<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[174764] trunk/Websites/bugs.webkit.org</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/174764">174764</a></dd>
<dt>Author</dt> <dd>ddkilzer@apple.com</dd>
<dt>Date</dt> <dd>2014-10-16 09:00:58 -0700 (Thu, 16 Oct 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>Upgrade bugs.webkit.org to Bugzilla 4.2
&lt;http://webkit.org/b/55882&gt;

Upgrade to Bugzilla 4.2.1.

Conflicts:
    .htaccess
    Bugzilla.pm
    Bugzilla/Auth.pm
    Bugzilla/Auth/Login/CGI.pm
    Bugzilla/Auth/Persist/Cookie.pm
    Bugzilla/Bug.pm
    Bugzilla/BugMail.pm
    Bugzilla/CGI.pm
    Bugzilla/Config/Attachment.pm
    Bugzilla/Config/Common.pm
    Bugzilla/Config/General.pm
    Bugzilla/Constants.pm
    Bugzilla/DB/Mysql.pm
    Bugzilla/DB/Oracle.pm
    Bugzilla/DB/Schema.pm
    Bugzilla/DB/Schema/Oracle.pm
    Bugzilla/Error.pm
    Bugzilla/Flag.pm
    Bugzilla/FlagType.pm
    Bugzilla/Hook.pm
    Bugzilla/Install/DB.pm
    Bugzilla/Install/Filesystem.pm
    Bugzilla/Install/Localconfig.pm
    Bugzilla/Install/Requirements.pm
    Bugzilla/Install/Util.pm
    Bugzilla/Mailer.pm
    Bugzilla/Product.pm
    Bugzilla/Search.pm
    Bugzilla/Search/Quicksearch.pm
    Bugzilla/Search/Saved.pm
    Bugzilla/Series.pm
    Bugzilla/Template.pm
    Bugzilla/Template/Plugin/Hook.pm
    Bugzilla/Token.pm
    Bugzilla/User.pm
    Bugzilla/Util.pm
    Bugzilla/WebService.pm
    Bugzilla/WebService/Bug.pm
    Bugzilla/WebService/Bugzilla.pm
    Bugzilla/WebService/Constants.pm
    Bugzilla/WebService/Product.pm
    Bugzilla/WebService/User.pm
    attachment.cgi
    buglist.cgi
    checksetup.pl
    colchange.cgi
    collectstats.pl
    contrib/bugzilla_ldapsync.rb
    contrib/bzdbcopy.pl
    contrib/gnats2bz.pl
    contrib/recode.pl
    contrib/sendbugmail.pl
    contrib/yp_nomail.sh
    docs/en/xml/Bugzilla-Guide.xml
    docs/en/xml/about.xml
    docs/en/xml/installation.xml
    docs/en/xml/security.xml
    docs/en/xml/troubleshooting.xml
    editflagtypes.cgi
    editparams.cgi
    editproducts.cgi
    editvalues.cgi
    editwhines.cgi
    email_in.pl
    enter_bug.cgi
    extensions/BmpConvert/Config.pm
    extensions/OldBugMove/template/en/default/admin/params/oldbugmove.html.tmpl
    extensions/Voting/template/en/default/hook/bug/process/header-title.html.tmpl
    extensions/Voting/template/en/default/hook/search/search-report-select-rep_fields.html.tmpl
    extensions/example/code/webservice-error_codes.pl
    extensions/example/version.pl
    images/favicon.ico
    importxml.pl
    index.cgi
    install-module.pl
    js/field.js
    js/util.js
    long_list.cgi
    mod_perl.pl
    post_bug.cgi
    process_bug.cgi
    quips.cgi
    sanitycheck.cgi
    show_bug.cgi
    showattachment.cgi
    sidebar.cgi
    skins/contrib/Dusk/global.css
    skins/contrib/Dusk/index.css
    skins/standard/global.css
    skins/standard/show_bug.css
    t/008filter.t
    template/en/custom/attachment/review.html.tmpl
    template/en/default/account/prefs/saved-searches.html.tmpl
    template/en/default/admin/classifications/delete.html.tmpl
    template/en/default/admin/classifications/edit-common.html.tmpl
    template/en/default/admin/classifications/footer.html.tmpl
    template/en/default/admin/components/create.html.tmpl
    template/en/default/admin/components/edit.html.tmpl
    template/en/default/admin/params/attachment.html.tmpl
    template/en/default/admin/sanitycheck/messages.html.tmpl
    template/en/default/admin/users/confirm-delete.html.tmpl
    template/en/default/admin/workflow/edit.html.tmpl
    template/en/default/attachment/created.html.tmpl
    template/en/default/attachment/diff-header.html.tmpl
    template/en/default/attachment/edit.html.tmpl
    template/en/default/attachment/list.html.tmpl
    template/en/default/attachment/updated.html.tmpl
    template/en/default/bug/comments.html.tmpl
    template/en/default/bug/create/create-guided.html.tmpl
    template/en/default/bug/create/create.html.tmpl
    template/en/default/bug/create/created.html.tmpl
    template/en/default/bug/edit.html.tmpl
    template/en/default/bug/field.html.tmpl
    template/en/default/bug/process/header.html.tmpl
    template/en/default/bug/show.html.tmpl
    template/en/default/bug/show.xml.tmpl
    template/en/default/config.rdf.tmpl
    template/en/default/email/whine.txt.tmpl
    template/en/default/filterexceptions.pl
    template/en/default/flag/list.html.tmpl
    template/en/default/global/common-links.html.tmpl
    template/en/default/global/confirm-action.html.tmpl
    template/en/default/global/field-descs.none.tmpl
    template/en/default/global/footer.html.tmpl
    template/en/default/global/header.html.tmpl
    template/en/default/global/user-error.html.tmpl
    template/en/default/global/userselect.html.tmpl
    template/en/default/list/edit-multiple.html.tmpl
    template/en/default/list/list.html.tmpl
    template/en/default/pages/fields.html.tmpl
    template/en/default/pages/release-notes.html.tmpl
    template/en/default/search/boolean-charts.html.tmpl
    template/en/default/search/form.html.tmpl
    template/en/default/search/search-report-graph.html.tmpl
    template/en/default/search/search-report-table.html.tmpl
    template/en/default/setup/strings.txt.pl
    token.cgi
    userprefs.cgi
    xml.cgi
    xmlrpc.cgi</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkWebsitesbugswebkitorghtaccess">trunk/Websites/bugs.webkit.org/.htaccess</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaAttachmentPatchReaderpm">trunk/Websites/bugs.webkit.org/Bugzilla/Attachment/PatchReader.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaAttachmentpm">trunk/Websites/bugs.webkit.org/Bugzilla/Attachment.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaAuthLoginCGIpm">trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Login/CGI.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaAuthLoginCookiepm">trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Login/Cookie.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaAuthLoginEnvpm">trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Login/Env.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaAuthLoginStackpm">trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Login/Stack.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaAuthLoginpm">trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Login.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaAuthPersistCookiepm">trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Persist/Cookie.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaAuthVerifyDBpm">trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Verify/DB.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaAuthVerifyLDAPpm">trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Verify/LDAP.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaAuthVerifyStackpm">trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Verify/Stack.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaAuthVerifypm">trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Verify.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaAuthpm">trunk/Websites/bugs.webkit.org/Bugzilla/Auth.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaBugpm">trunk/Websites/bugs.webkit.org/Bugzilla/Bug.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaBugMailpm">trunk/Websites/bugs.webkit.org/Bugzilla/BugMail.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaCGIpm">trunk/Websites/bugs.webkit.org/Bugzilla/CGI.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaChartpm">trunk/Websites/bugs.webkit.org/Bugzilla/Chart.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaClassificationpm">trunk/Websites/bugs.webkit.org/Bugzilla/Classification.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaComponentpm">trunk/Websites/bugs.webkit.org/Bugzilla/Component.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaConfigAdminpm">trunk/Websites/bugs.webkit.org/Bugzilla/Config/Admin.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaConfigAttachmentpm">trunk/Websites/bugs.webkit.org/Bugzilla/Config/Attachment.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaConfigAuthpm">trunk/Websites/bugs.webkit.org/Bugzilla/Config/Auth.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaConfigBugChangepm">trunk/Websites/bugs.webkit.org/Bugzilla/Config/BugChange.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaConfigBugFieldspm">trunk/Websites/bugs.webkit.org/Bugzilla/Config/BugFields.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaConfigCommonpm">trunk/Websites/bugs.webkit.org/Bugzilla/Config/Common.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaConfigCorepm">trunk/Websites/bugs.webkit.org/Bugzilla/Config/Core.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaConfigDependencyGraphpm">trunk/Websites/bugs.webkit.org/Bugzilla/Config/DependencyGraph.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaConfigGroupSecuritypm">trunk/Websites/bugs.webkit.org/Bugzilla/Config/GroupSecurity.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaConfigLDAPpm">trunk/Websites/bugs.webkit.org/Bugzilla/Config/LDAP.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaConfigMTApm">trunk/Websites/bugs.webkit.org/Bugzilla/Config/MTA.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaConfigPatchViewerpm">trunk/Websites/bugs.webkit.org/Bugzilla/Config/PatchViewer.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaConfigQuerypm">trunk/Websites/bugs.webkit.org/Bugzilla/Config/Query.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaConfigRADIUSpm">trunk/Websites/bugs.webkit.org/Bugzilla/Config/RADIUS.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaConfigShadowDBpm">trunk/Websites/bugs.webkit.org/Bugzilla/Config/ShadowDB.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaConfigUserMatchpm">trunk/Websites/bugs.webkit.org/Bugzilla/Config/UserMatch.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaConfigpm">trunk/Websites/bugs.webkit.org/Bugzilla/Config.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaConstantspm">trunk/Websites/bugs.webkit.org/Bugzilla/Constants.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaDBMysqlpm">trunk/Websites/bugs.webkit.org/Bugzilla/DB/Mysql.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaDBOraclepm">trunk/Websites/bugs.webkit.org/Bugzilla/DB/Oracle.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaDBPgpm">trunk/Websites/bugs.webkit.org/Bugzilla/DB/Pg.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaDBSchemaMysqlpm">trunk/Websites/bugs.webkit.org/Bugzilla/DB/Schema/Mysql.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaDBSchemaOraclepm">trunk/Websites/bugs.webkit.org/Bugzilla/DB/Schema/Oracle.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaDBSchemaPgpm">trunk/Websites/bugs.webkit.org/Bugzilla/DB/Schema/Pg.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaDBSchemapm">trunk/Websites/bugs.webkit.org/Bugzilla/DB/Schema.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaDBpm">trunk/Websites/bugs.webkit.org/Bugzilla/DB.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaErrorpm">trunk/Websites/bugs.webkit.org/Bugzilla/Error.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaFieldpm">trunk/Websites/bugs.webkit.org/Bugzilla/Field.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaFlagpm">trunk/Websites/bugs.webkit.org/Bugzilla/Flag.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaFlagTypepm">trunk/Websites/bugs.webkit.org/Bugzilla/FlagType.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaGrouppm">trunk/Websites/bugs.webkit.org/Bugzilla/Group.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaHookpm">trunk/Websites/bugs.webkit.org/Bugzilla/Hook.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaInstallCPANpm">trunk/Websites/bugs.webkit.org/Bugzilla/Install/CPAN.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaInstallDBpm">trunk/Websites/bugs.webkit.org/Bugzilla/Install/DB.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaInstallFilesystempm">trunk/Websites/bugs.webkit.org/Bugzilla/Install/Filesystem.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaInstallLocalconfigpm">trunk/Websites/bugs.webkit.org/Bugzilla/Install/Localconfig.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaInstallRequirementspm">trunk/Websites/bugs.webkit.org/Bugzilla/Install/Requirements.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaInstallUtilpm">trunk/Websites/bugs.webkit.org/Bugzilla/Install/Util.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaInstallpm">trunk/Websites/bugs.webkit.org/Bugzilla/Install.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaKeywordpm">trunk/Websites/bugs.webkit.org/Bugzilla/Keyword.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaMailerpm">trunk/Websites/bugs.webkit.org/Bugzilla/Mailer.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaMilestonepm">trunk/Websites/bugs.webkit.org/Bugzilla/Milestone.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaObjectpm">trunk/Websites/bugs.webkit.org/Bugzilla/Object.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaProductpm">trunk/Websites/bugs.webkit.org/Bugzilla/Product.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaSearchQuicksearchpm">trunk/Websites/bugs.webkit.org/Bugzilla/Search/Quicksearch.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaSearchSavedpm">trunk/Websites/bugs.webkit.org/Bugzilla/Search/Saved.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaSearchpm">trunk/Websites/bugs.webkit.org/Bugzilla/Search.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaSeriespm">trunk/Websites/bugs.webkit.org/Bugzilla/Series.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaStatuspm">trunk/Websites/bugs.webkit.org/Bugzilla/Status.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaTemplatePluginHookpm">trunk/Websites/bugs.webkit.org/Bugzilla/Template/Plugin/Hook.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaTemplatepm">trunk/Websites/bugs.webkit.org/Bugzilla/Template.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaTokenpm">trunk/Websites/bugs.webkit.org/Bugzilla/Token.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaUpdatepm">trunk/Websites/bugs.webkit.org/Bugzilla/Update.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaUserSettingpm">trunk/Websites/bugs.webkit.org/Bugzilla/User/Setting.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaUserpm">trunk/Websites/bugs.webkit.org/Bugzilla/User.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaUtilpm">trunk/Websites/bugs.webkit.org/Bugzilla/Util.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaVersionpm">trunk/Websites/bugs.webkit.org/Bugzilla/Version.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaWebServiceBugpm">trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Bug.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaWebServiceBugzillapm">trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Bugzilla.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaWebServiceConstantspm">trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Constants.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaWebServiceProductpm">trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Product.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaWebServiceUserpm">trunk/Websites/bugs.webkit.org/Bugzilla/WebService/User.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaWebServicepm">trunk/Websites/bugs.webkit.org/Bugzilla/WebService.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillapm">trunk/Websites/bugs.webkit.org/Bugzilla.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgREADME">trunk/Websites/bugs.webkit.org/README</a></li>
<li><a href="#trunkWebsitesbugswebkitorgattachmentcgi">trunk/Websites/bugs.webkit.org/attachment.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgbuglistcgi">trunk/Websites/bugs.webkit.org/buglist.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgbugzilladtd">trunk/Websites/bugs.webkit.org/bugzilla.dtd</a></li>
<li><a href="#trunkWebsitesbugswebkitorgchartcgi">trunk/Websites/bugs.webkit.org/chart.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgchecksetuppl">trunk/Websites/bugs.webkit.org/checksetup.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcolchangecgi">trunk/Websites/bugs.webkit.org/colchange.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcollectstatspl">trunk/Websites/bugs.webkit.org/collectstats.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgconfigcgi">trunk/Websites/bugs.webkit.org/config.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcontribREADME">trunk/Websites/bugs.webkit.org/contrib/README</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcontribbugzillasubmitbugdatatxt">trunk/Websites/bugs.webkit.org/contrib/bugzilla-submit/bugdata.txt</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcontribbugzillasubmitbugzillasubmit">trunk/Websites/bugs.webkit.org/contrib/bugzilla-submit/bugzilla-submit</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcontribbugzillasubmitbugzillasubmitxml">trunk/Websites/bugs.webkit.org/contrib/bugzilla-submit/bugzilla-submit.xml</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcontribbz_webservice_demopl">trunk/Websites/bugs.webkit.org/contrib/bz_webservice_demo.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcontribbzdbcopypl">trunk/Websites/bugs.webkit.org/contrib/bzdbcopy.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcontribcmdlinequeryconf">trunk/Websites/bugs.webkit.org/contrib/cmdline/query.conf</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcontribcvsupdatepl">trunk/Websites/bugs.webkit.org/contrib/cvs-update.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcontribjb2bzpy">trunk/Websites/bugs.webkit.org/contrib/jb2bz.py</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcontribmergeuserspl">trunk/Websites/bugs.webkit.org/contrib/merge-users.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcontribrecodepl">trunk/Websites/bugs.webkit.org/contrib/recode.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcontribsendbugmailpl">trunk/Websites/bugs.webkit.org/contrib/sendbugmail.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcontribsendunsentbugmailpl">trunk/Websites/bugs.webkit.org/contrib/sendunsentbugmail.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcreateaccountcgi">trunk/Websites/bugs.webkit.org/createaccount.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgdescribecomponentscgi">trunk/Websites/bugs.webkit.org/describecomponents.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgdescribekeywordscgi">trunk/Websites/bugs.webkit.org/describekeywords.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgdocsenREADMEdocs">trunk/Websites/bugs.webkit.org/docs/en/README.docs</a></li>
<li><a href="#trunkWebsitesbugswebkitorgdocsenimagesbzLifecyclepng">trunk/Websites/bugs.webkit.org/docs/en/images/bzLifecycle.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgdocsenimagesbzLifecyclexml">trunk/Websites/bugs.webkit.org/docs/en/images/bzLifecycle.xml</a></li>
<li><a href="#trunkWebsitesbugswebkitorgdocsenimagescautiongif">trunk/Websites/bugs.webkit.org/docs/en/images/caution.gif</a></li>
<li><a href="#trunkWebsitesbugswebkitorgdocsenimagestipgif">trunk/Websites/bugs.webkit.org/docs/en/images/tip.gif</a></li>
<li><a href="#trunkWebsitesbugswebkitorgdocsenimageswarninggif">trunk/Websites/bugs.webkit.org/docs/en/images/warning.gif</a></li>
<li><a href="#trunkWebsitesbugswebkitorgdocsenrel_notestxt">trunk/Websites/bugs.webkit.org/docs/en/rel_notes.txt</a></li>
<li><a href="#trunkWebsitesbugswebkitorgdocsenxmlBugzillaGuidexml">trunk/Websites/bugs.webkit.org/docs/en/xml/Bugzilla-Guide.xml</a></li>
<li><a href="#trunkWebsitesbugswebkitorgdocsenxmlaboutxml">trunk/Websites/bugs.webkit.org/docs/en/xml/about.xml</a></li>
<li><a href="#trunkWebsitesbugswebkitorgdocsenxmladministrationxml">trunk/Websites/bugs.webkit.org/docs/en/xml/administration.xml</a></li>
<li><a href="#trunkWebsitesbugswebkitorgdocsenxmlcustomizationxml">trunk/Websites/bugs.webkit.org/docs/en/xml/customization.xml</a></li>
<li><a href="#trunkWebsitesbugswebkitorgdocsenxmlgfdlxml">trunk/Websites/bugs.webkit.org/docs/en/xml/gfdl.xml</a></li>
<li><a href="#trunkWebsitesbugswebkitorgdocsenxmlglossaryxml">trunk/Websites/bugs.webkit.org/docs/en/xml/glossary.xml</a></li>
<li><a href="#trunkWebsitesbugswebkitorgdocsenxmlinstallationxml">trunk/Websites/bugs.webkit.org/docs/en/xml/installation.xml</a></li>
<li><a href="#trunkWebsitesbugswebkitorgdocsenxmlmodulesxml">trunk/Websites/bugs.webkit.org/docs/en/xml/modules.xml</a></li>
<li><a href="#trunkWebsitesbugswebkitorgdocsenxmlpatchesxml">trunk/Websites/bugs.webkit.org/docs/en/xml/patches.xml</a></li>
<li><a href="#trunkWebsitesbugswebkitorgdocsenxmlsecurityxml">trunk/Websites/bugs.webkit.org/docs/en/xml/security.xml</a></li>
<li><a href="#trunkWebsitesbugswebkitorgdocsenxmltroubleshootingxml">trunk/Websites/bugs.webkit.org/docs/en/xml/troubleshooting.xml</a></li>
<li><a href="#trunkWebsitesbugswebkitorgdocsenxmlusingxml">trunk/Websites/bugs.webkit.org/docs/en/xml/using.xml</a></li>
<li><a href="#trunkWebsitesbugswebkitorgdocslibPodSimpleHTMLBatchBugzillapm">trunk/Websites/bugs.webkit.org/docs/lib/Pod/Simple/HTMLBatch/Bugzilla.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgdocsmakedocspl">trunk/Websites/bugs.webkit.org/docs/makedocs.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgduplicatescgi">trunk/Websites/bugs.webkit.org/duplicates.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgeditclassificationscgi">trunk/Websites/bugs.webkit.org/editclassifications.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgeditcomponentscgi">trunk/Websites/bugs.webkit.org/editcomponents.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgeditfieldscgi">trunk/Websites/bugs.webkit.org/editfields.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgeditflagtypescgi">trunk/Websites/bugs.webkit.org/editflagtypes.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgeditgroupscgi">trunk/Websites/bugs.webkit.org/editgroups.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgeditkeywordscgi">trunk/Websites/bugs.webkit.org/editkeywords.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgeditmilestonescgi">trunk/Websites/bugs.webkit.org/editmilestones.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgeditparamscgi">trunk/Websites/bugs.webkit.org/editparams.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgeditproductscgi">trunk/Websites/bugs.webkit.org/editproducts.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgedituserscgi">trunk/Websites/bugs.webkit.org/editusers.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgeditvaluescgi">trunk/Websites/bugs.webkit.org/editvalues.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgeditversionscgi">trunk/Websites/bugs.webkit.org/editversions.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgeditwhinescgi">trunk/Websites/bugs.webkit.org/editwhines.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgeditworkflowcgi">trunk/Websites/bugs.webkit.org/editworkflow.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgemail_inpl">trunk/Websites/bugs.webkit.org/email_in.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgenter_bugcgi">trunk/Websites/bugs.webkit.org/enter_bug.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgimportxmlpl">trunk/Websites/bugs.webkit.org/importxml.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgindexcgi">trunk/Websites/bugs.webkit.org/index.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorginstallmodulepl">trunk/Websites/bugs.webkit.org/install-module.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsTUIjs">trunk/Websites/bugs.webkit.org/js/TUI.js</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsattachmentjs">trunk/Websites/bugs.webkit.org/js/attachment.js</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsfieldjs">trunk/Websites/bugs.webkit.org/js/field.js</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsutiljs">trunk/Websites/bugs.webkit.org/js/util.js</a></li>
<li><a href="#trunkWebsitesbugswebkitorgmod_perlpl">trunk/Websites/bugs.webkit.org/mod_perl.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgpagecgi">trunk/Websites/bugs.webkit.org/page.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgpost_bugcgi">trunk/Websites/bugs.webkit.org/post_bug.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgprocess_bugcgi">trunk/Websites/bugs.webkit.org/process_bug.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgquerycgi">trunk/Websites/bugs.webkit.org/query.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgquipscgi">trunk/Websites/bugs.webkit.org/quips.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgrelogincgi">trunk/Websites/bugs.webkit.org/relogin.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgreportcgi">trunk/Websites/bugs.webkit.org/report.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgreportscgi">trunk/Websites/bugs.webkit.org/reports.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgrequestcgi">trunk/Websites/bugs.webkit.org/request.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgsanitycheckcgi">trunk/Websites/bugs.webkit.org/sanitycheck.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgsanitycheckpl">trunk/Websites/bugs.webkit.org/sanitycheck.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgsearch_plugincgi">trunk/Websites/bugs.webkit.org/search_plugin.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgshow_activitycgi">trunk/Websites/bugs.webkit.org/show_activity.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgshow_bugcgi">trunk/Websites/bugs.webkit.org/show_bug.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgshowdependencygraphcgi">trunk/Websites/bugs.webkit.org/showdependencygraph.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgshowdependencytreecgi">trunk/Websites/bugs.webkit.org/showdependencytree.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscontribDuskglobalcss">trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/global.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscontribDuskindexcss">trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/index.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinsstandardIEfixescss">trunk/Websites/bugs.webkit.org/skins/standard/IE-fixes.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinsstandardadmincss">trunk/Websites/bugs.webkit.org/skins/standard/admin.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinsstandardbuglistcss">trunk/Websites/bugs.webkit.org/skins/standard/buglist.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinsstandardduplicatescss">trunk/Websites/bugs.webkit.org/skins/standard/duplicates.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinsstandardglobalcss">trunk/Websites/bugs.webkit.org/skins/standard/global.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinsstandardindexcss">trunk/Websites/bugs.webkit.org/skins/standard/index.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinsstandardshow_bugcss">trunk/Websites/bugs.webkit.org/skins/standard/show_bug.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgsummarize_timecgi">trunk/Websites/bugs.webkit.org/summarize_time.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgt001compilet">trunk/Websites/bugs.webkit.org/t/001compile.t</a></li>
<li><a href="#trunkWebsitesbugswebkitorgt002goodperlt">trunk/Websites/bugs.webkit.org/t/002goodperl.t</a></li>
<li><a href="#trunkWebsitesbugswebkitorgt004templatet">trunk/Websites/bugs.webkit.org/t/004template.t</a></li>
<li><a href="#trunkWebsitesbugswebkitorgt007utilt">trunk/Websites/bugs.webkit.org/t/007util.t</a></li>
<li><a href="#trunkWebsitesbugswebkitorgt008filtert">trunk/Websites/bugs.webkit.org/t/008filter.t</a></li>
<li><a href="#trunkWebsitesbugswebkitorgt009bugwordst">trunk/Websites/bugs.webkit.org/t/009bugwords.t</a></li>
<li><a href="#trunkWebsitesbugswebkitorgt010dependenciest">trunk/Websites/bugs.webkit.org/t/010dependencies.t</a></li>
<li><a href="#trunkWebsitesbugswebkitorgt012throwablest">trunk/Websites/bugs.webkit.org/t/012throwables.t</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtSupportFilespm">trunk/Websites/bugs.webkit.org/t/Support/Files.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtSupportTemplatespm">trunk/Websites/bugs.webkit.org/t/Support/Templates.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateencustomattachmentcreatehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/custom/attachment/create.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateencustomattachmentcreatedhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/custom/attachment/created.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateencustomattachmentedithtmltmpl">trunk/Websites/bugs.webkit.org/template/en/custom/attachment/edit.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateencustomattachmentlisthtmltmpl">trunk/Websites/bugs.webkit.org/template/en/custom/attachment/list.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateencustombugedithtmltmpl">trunk/Websites/bugs.webkit.org/template/en/custom/bug/edit.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateencustombugnavigatehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/custom/bug/navigate.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateencustomflaglisthtmltmpl">trunk/Websites/bugs.webkit.org/template/en/custom/flag/list.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateencustomglobalchooseproducthtmltmpl">trunk/Websites/bugs.webkit.org/template/en/custom/global/choose-product.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateencustomglobalheaderhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/custom/global/header.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateencustomlistlisthtmltmpl">trunk/Websites/bugs.webkit.org/template/en/custom/list/list.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateencustomrequestemailtxttmpl">trunk/Websites/bugs.webkit.org/template/en/custom/request/email.txt.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateencustomrequestqueuehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/custom/request/queue.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultaccountauthloginsmallhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/account/auth/login-small.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultaccountauthloginhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/account/auth/login.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultaccountcanceltokentxttmpl">trunk/Websites/bugs.webkit.org/template/en/default/account/cancel-token.txt.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultaccountcreatehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/account/create.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultaccountemailchangenewtxttmpl">trunk/Websites/bugs.webkit.org/template/en/default/account/email/change-new.txt.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultaccountemailchangeoldtxttmpl">trunk/Websites/bugs.webkit.org/template/en/default/account/email/change-old.txt.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultaccountemailconfirmnewhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/account/email/confirm-new.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultaccountemailrequestnewtxttmpl">trunk/Websites/bugs.webkit.org/template/en/default/account/email/request-new.txt.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultaccountpasswordforgottenpasswordtxttmpl">trunk/Websites/bugs.webkit.org/template/en/default/account/password/forgotten-password.txt.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultaccountpasswordsetforgottenpasswordhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/account/password/set-forgotten-password.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultaccountprefsaccounthtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/account/prefs/account.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultaccountprefsemailhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/account/prefs/email.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultaccountprefspermissionshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/account/prefs/permissions.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultaccountprefsprefshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/account/prefs/prefs.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultaccountprefssavedsearcheshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/account/prefs/saved-searches.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultaccountprofileactivityhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/account/profile-activity.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminadminhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/admin.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminclassificationsaddhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/classifications/add.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminclassificationsdelhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/classifications/del.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminclassificationsedithtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/classifications/edit.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminclassificationsreclassifyhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/classifications/reclassify.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminclassificationsselecthtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/classifications/select.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadmincomponentsconfirmdeletehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/components/confirm-delete.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadmincomponentscreatehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/components/create.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadmincomponentsedithtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/components/edit.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadmincomponentsfooterhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/components/footer.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadmincomponentslisthtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/components/list.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadmincustom_fieldscreatehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/custom_fields/create.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadmincustom_fieldsedithtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/custom_fields/edit.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadmincustom_fieldslisthtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/custom_fields/list.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminfieldvaluesconfirmdeletehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/fieldvalues/confirm-delete.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminfieldvaluescreatehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/fieldvalues/create.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminfieldvaluesedithtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/fieldvalues/edit.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminfieldvaluesfooterhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/fieldvalues/footer.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminfieldvalueslisthtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/fieldvalues/list.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminflagtypeedithtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/flag-type/edit.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminflagtypelisthtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/flag-type/list.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadmingroupsconfirmremovehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/groups/confirm-remove.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadmingroupsdeletehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/groups/delete.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadmingroupsedithtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/groups/edit.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadmingroupslisthtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/groups/list.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminkeywordsedithtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/keywords/edit.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminmilestonesconfirmdeletehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/milestones/confirm-delete.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminmilestonesedithtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/milestones/edit.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminmilestonesfooterhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/milestones/footer.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminmilestoneslisthtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/milestones/list.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminparamsadminhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/params/admin.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminparamsattachmenthtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/params/attachment.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminparamsauthhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/params/auth.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminparamsbugchangehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/params/bugchange.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminparamsbugfieldshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/params/bugfields.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminparamscommonhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/params/common.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminparamscorehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/params/core.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminparamsdependencygraphhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/params/dependencygraph.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminparamseditparamshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/params/editparams.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminparamsgroupsecurityhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/params/groupsecurity.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminparamsindexhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/params/index.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminparamsmtahtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/params/mta.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminparamsqueryhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/params/query.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminparamsradiushtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/params/radius.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminparamsusermatchhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/params/usermatch.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminproductsconfirmdeletehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/products/confirm-delete.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminproductscreatehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/products/create.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminproductseditcommonhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/products/edit-common.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminproductsedithtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/products/edit.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminproductsfooterhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/products/footer.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminproductsgroupcontroledithtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/products/groupcontrol/edit.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminproductsgroupcontrolupdatedhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/products/groupcontrol/updated.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminproductslistclassificationshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/products/list-classifications.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminproductslisthtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/products/list.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminproductsupdatedhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/products/updated.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminsanitycheckmessageshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/sanitycheck/messages.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminsudohtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/sudo.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadmintablehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/table.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminusersconfirmdeletehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/users/confirm-delete.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminuserslisthtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/users/list.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminuserslistselectvarshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/users/listselectvars.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminusersresponsibilitieshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/users/responsibilities.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminuserssearchhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/users/search.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminusersuserdatahtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/users/userdata.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminversionsconfirmdeletehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/versions/confirm-delete.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminversionsedithtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/versions/edit.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminversionsfooterhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/versions/footer.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminversionslisthtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/versions/list.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminworkflowcommenthtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/workflow/comment.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminworkflowedithtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/workflow/edit.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultattachmentcreatehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/attachment/create.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultattachmentcreatedhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/attachment/created.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultattachmentcreateformcontentshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/attachment/createformcontents.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultattachmentdifffilehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/attachment/diff-file.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultattachmentdifffooterhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/attachment/diff-footer.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultattachmentdiffheaderhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/attachment/diff-header.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultattachmentedithtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/attachment/edit.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultattachmentlisthtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/attachment/list.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultattachmentmidairhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/attachment/midair.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultattachmentshowmultiplehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/attachment/show-multiple.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultattachmentupdatedhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/attachment/updated.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultbugactivityshowhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/bug/activity/show.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultbugactivitytablehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/bug/activity/table.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultbugcommentshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/bug/comments.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultbugcreatecreateguidedhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/bug/create/create-guided.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultbugcreatecreatehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/bug/create/create.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultbugcreatecreatedhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/bug/create/created.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultbugdependencygraphhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/bug/dependency-graph.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultbugdependencytreehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/bug/dependency-tree.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultbugedithtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/bug/edit.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultbugfieldhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/bug/field.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultbugknobhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/bug/knob.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultbugnavigatehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/bug/navigate.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultbugprocessbugmailhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/bug/process/bugmail.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultbugprocessheaderhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/bug/process/header.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultbugprocessmidairhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/bug/process/midair.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultbugprocessresultshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/bug/process/results.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultbugprocessverifynewproducthtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/bug/process/verify-new-product.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultbugshowmultiplehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/bug/show-multiple.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultbugshowhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/bug/show.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultbugshowxmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/bug/show.xml.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultbugsummarizetimehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/bug/summarize-time.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultconfigjstmpl">trunk/Websites/bugs.webkit.org/template/en/default/config.js.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultconfigrdftmpl">trunk/Websites/bugs.webkit.org/template/en/default/config.rdf.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultemailsanitychecktxttmpl">trunk/Websites/bugs.webkit.org/template/en/default/email/sanitycheck.txt.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultemailwhinetxttmpl">trunk/Websites/bugs.webkit.org/template/en/default/email/whine.txt.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultfilterexceptionspl">trunk/Websites/bugs.webkit.org/template/en/default/filterexceptions.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultflaglisthtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/flag/list.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultglobalchooseclassificationhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/global/choose-classification.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultglobalchooseproducthtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/global/choose-product.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultglobalcodeerrorhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/global/code-error.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultglobalcommonlinkshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/global/common-links.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultglobalconfirmactionhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/global/confirm-action.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultglobalconfirmusermatchhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/global/confirm-user-match.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultglobalfielddescsnonetmpl">trunk/Websites/bugs.webkit.org/template/en/default/global/field-descs.none.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultglobalfooterhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/global/footer.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultglobalheaderhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/global/header.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultglobalhelphtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/global/help.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultglobalhiddenfieldshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/global/hidden-fields.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultglobalmessageshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/global/messages.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultglobalperbugquerieshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/global/per-bug-queries.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultglobalsettingdescsnonetmpl">trunk/Websites/bugs.webkit.org/template/en/default/global/setting-descs.none.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultglobalsitenavigationhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/global/site-navigation.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultglobaltabshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/global/tabs.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultglobaltextareahtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/global/textarea.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultglobalusefullinkshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/global/useful-links.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultglobalusererrorhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/global/user-error.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultglobaluserselecthtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/global/userselect.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultglobalvariablesnonetmpl">trunk/Websites/bugs.webkit.org/template/en/default/global/variables.none.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultindexhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/index.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultlistchangecolumnshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/list/change-columns.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultlisteditmultiplehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/list/edit-multiple.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultlistlistsimplehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/list/list-simple.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultlistlistatomtmpl">trunk/Websites/bugs.webkit.org/template/en/default/list/list.atom.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultlistlistcsvtmpl">trunk/Websites/bugs.webkit.org/template/en/default/list/list.csv.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultlistlisthtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/list/list.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultlistlisticstmpl">trunk/Websites/bugs.webkit.org/template/en/default/list/list.ics.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultlistlistrdftmpl">trunk/Websites/bugs.webkit.org/template/en/default/list/list.rdf.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultlistquipshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/list/quips.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultlisttablehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/list/table.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultpagesbugwritinghtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/pages/bug-writing.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultpagesfieldshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/pages/fields.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultpageslinkedhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/pages/linked.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultpagesquicksearchhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/pages/quicksearch.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultpagesreleasenoteshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/pages/release-notes.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultpagessudohtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/pages/sudo.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultreportscharthtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/reports/chart.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultreportscomponentshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/reports/components.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultreportscreatecharthtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/reports/create-chart.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultreportsduplicatessimplehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/reports/duplicates-simple.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultreportsduplicatestablehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/reports/duplicates-table.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultreportsduplicateshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/reports/duplicates.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultreportseditserieshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/reports/edit-series.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultreportskeywordshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/reports/keywords.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultreportsmenuhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/reports/menu.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultreportsoldchartshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/reports/old-charts.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultreportsreportbarpngtmpl">trunk/Websites/bugs.webkit.org/template/en/default/reports/report-bar.png.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultreportsreportlinepngtmpl">trunk/Websites/bugs.webkit.org/template/en/default/reports/report-line.png.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultreportsreportpiepngtmpl">trunk/Websites/bugs.webkit.org/template/en/default/reports/report-pie.png.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultreportsreporttablecsvtmpl">trunk/Websites/bugs.webkit.org/template/en/default/reports/report-table.csv.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultreportsreporttablehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/reports/report-table.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultreportsreporthtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/reports/report.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultreportsseriescommonhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/reports/series-common.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultrequestemailtxttmpl">trunk/Websites/bugs.webkit.org/template/en/default/request/email.txt.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultrequestqueuehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/request/queue.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultsearchbooleanchartshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/search/boolean-charts.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultsearchformhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/search/form.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultsearchknobhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/search/knob.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultsearchsearchadvancedhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/search/search-advanced.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultsearchsearchcreateserieshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/search/search-create-series.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultsearchsearchpluginxmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/search/search-plugin.xml.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultsearchsearchreportgraphhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/search/search-report-graph.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultsearchsearchreportselecthtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/search/search-report-select.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultsearchsearchreporttablehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/search/search-report-table.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultsearchsearchspecifichtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/search/search-specific.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultsearchtabshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/search/tabs.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultsetupstringstxtpl">trunk/Websites/bugs.webkit.org/template/en/default/setup/strings.txt.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultwelcomeadminhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/welcome-admin.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultwhinemailhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/whine/mail.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultwhinemailtxttmpl">trunk/Websites/bugs.webkit.org/template/en/default/whine/mail.txt.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultwhinemultipartmimetxttmpl">trunk/Websites/bugs.webkit.org/template/en/default/whine/multipart-mime.txt.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultwhineschedulehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/whine/schedule.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtestserverpl">trunk/Websites/bugs.webkit.org/testserver.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtokencgi">trunk/Websites/bugs.webkit.org/token.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorguserprefscgi">trunk/Websites/bugs.webkit.org/userprefs.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgvotescgi">trunk/Websites/bugs.webkit.org/votes.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgwhinepl">trunk/Websites/bugs.webkit.org/whine.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgwhineatnewspl">trunk/Websites/bugs.webkit.org/whineatnews.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgxmlrpccgi">trunk/Websites/bugs.webkit.org/xmlrpc.cgi</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkWebsitesbugswebkitorgbzrignore">trunk/Websites/bugs.webkit.org/.bzrignore</a></li>
<li>trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/</li>
<li>trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/Bugzilla/</li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaBugUrlBugzillaLocalpm">trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/Bugzilla/Local.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaBugUrlBugzillapm">trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/Bugzilla.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaBugUrlDebianpm">trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/Debian.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaBugUrlGooglepm">trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/Google.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaBugUrlJIRApm">trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/JIRA.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaBugUrlLaunchpadpm">trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/Launchpad.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaBugUrlMantisBTpm">trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/MantisBT.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaBugUrlSourceForgepm">trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/SourceForge.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaBugUrlTracpm">trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/Trac.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaBugUrlpm">trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaCommentpm">trunk/Websites/bugs.webkit.org/Bugzilla/Comment.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaConfigAdvancedpm">trunk/Websites/bugs.webkit.org/Bugzilla/Config/Advanced.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaConfigGeneralpm">trunk/Websites/bugs.webkit.org/Bugzilla/Config/General.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaDBSchemaSqlitepm">trunk/Websites/bugs.webkit.org/Bugzilla/DB/Schema/Sqlite.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaDBSqlitepm">trunk/Websites/bugs.webkit.org/Bugzilla/DB/Sqlite.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaExtensionpm">trunk/Websites/bugs.webkit.org/Bugzilla/Extension.pm</a></li>
<li>trunk/Websites/bugs.webkit.org/Bugzilla/Field/</li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaFieldChoicepm">trunk/Websites/bugs.webkit.org/Bugzilla/Field/Choice.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaFieldChoiceInterfacepm">trunk/Websites/bugs.webkit.org/Bugzilla/Field/ChoiceInterface.pm</a></li>
<li>trunk/Websites/bugs.webkit.org/Bugzilla/Job/</li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaJobMailerpm">trunk/Websites/bugs.webkit.org/Bugzilla/Job/Mailer.pm</a></li>
<li>trunk/Websites/bugs.webkit.org/Bugzilla/JobQueue/</li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaJobQueueRunnerpm">trunk/Websites/bugs.webkit.org/Bugzilla/JobQueue/Runner.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaJobQueuepm">trunk/Websites/bugs.webkit.org/Bugzilla/JobQueue.pm</a></li>
<li>trunk/Websites/bugs.webkit.org/Bugzilla/Migrate/</li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaMigrateGnatspm">trunk/Websites/bugs.webkit.org/Bugzilla/Migrate/Gnats.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaMigratepm">trunk/Websites/bugs.webkit.org/Bugzilla/Migrate.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaRNGpm">trunk/Websites/bugs.webkit.org/Bugzilla/RNG.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaSearchClausepm">trunk/Websites/bugs.webkit.org/Bugzilla/Search/Clause.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaSearchConditionpm">trunk/Websites/bugs.webkit.org/Bugzilla/Search/Condition.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaSearchRecentpm">trunk/Websites/bugs.webkit.org/Bugzilla/Search/Recent.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaTemplateContextpm">trunk/Websites/bugs.webkit.org/Bugzilla/Template/Context.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaUserSettingTimezonepm">trunk/Websites/bugs.webkit.org/Bugzilla/User/Setting/Timezone.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaWebServiceGrouppm">trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Group.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaWebServiceREADME">trunk/Websites/bugs.webkit.org/Bugzilla/WebService/README</a></li>
<li>trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Server/</li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaWebServiceServerJSONRPCpm">trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Server/JSONRPC.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaWebServiceServerXMLRPCpm">trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Server/XMLRPC.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaWebServiceServerpm">trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Server.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaWebServiceUtilpm">trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Util.pm</a></li>
<li>trunk/Websites/bugs.webkit.org/Bugzilla/Whine/</li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaWhineQuerypm">trunk/Websites/bugs.webkit.org/Bugzilla/Whine/Query.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaWhineSchedulepm">trunk/Websites/bugs.webkit.org/Bugzilla/Whine/Schedule.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaWhinepm">trunk/Websites/bugs.webkit.org/Bugzilla/Whine.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcontribbugzillaqueuerhel">trunk/Websites/bugs.webkit.org/contrib/bugzilla-queue.rhel</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcontribbugzillaqueuesuse">trunk/Websites/bugs.webkit.org/contrib/bugzilla-queue.suse</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcontribconsolepl">trunk/Websites/bugs.webkit.org/contrib/console.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcontribconvertworkflowpl">trunk/Websites/bugs.webkit.org/contrib/convert-workflow.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcontribextensionconvertpl">trunk/Websites/bugs.webkit.org/contrib/extension-convert.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcontribfixpermspl">trunk/Websites/bugs.webkit.org/contrib/fixperms.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcontribnewyuish">trunk/Websites/bugs.webkit.org/contrib/new-yui.sh</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/BmpConvert/</li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsBmpConvertConfigpm">trunk/Websites/bugs.webkit.org/extensions/BmpConvert/Config.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsBmpConvertExtensionpm">trunk/Websites/bugs.webkit.org/extensions/BmpConvert/Extension.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsBmpConvertdisabled">trunk/Websites/bugs.webkit.org/extensions/BmpConvert/disabled</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/Example/</li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsExampleConfigpm">trunk/Websites/bugs.webkit.org/extensions/Example/Config.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsExampleExtensionpm">trunk/Websites/bugs.webkit.org/extensions/Example/Extension.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsExampledisabled">trunk/Websites/bugs.webkit.org/extensions/Example/disabled</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/Example/lib/</li>
<li>trunk/Websites/bugs.webkit.org/extensions/Example/lib/Auth/</li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsExamplelibAuthLoginpm">trunk/Websites/bugs.webkit.org/extensions/Example/lib/Auth/Login.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsExamplelibAuthVerifypm">trunk/Websites/bugs.webkit.org/extensions/Example/lib/Auth/Verify.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsExamplelibConfigpm">trunk/Websites/bugs.webkit.org/extensions/Example/lib/Config.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsExamplelibUtilpm">trunk/Websites/bugs.webkit.org/extensions/Example/lib/Util.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsExamplelibWebServicepm">trunk/Websites/bugs.webkit.org/extensions/Example/lib/WebService.pm</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/Example/template/</li>
<li>trunk/Websites/bugs.webkit.org/extensions/Example/template/en/</li>
<li>trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/</li>
<li>trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/account/</li>
<li>trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/account/prefs/</li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsExampletemplateendefaultaccountprefsmy_tabhtmltmpl">trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/account/prefs/my_tab.html.tmpl</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/admin/</li>
<li>trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/admin/params/</li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsExampletemplateendefaultadminparamsexamplehtmltmpl">trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/admin/params/example.html.tmpl</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/hook/</li>
<li>trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/hook/account/</li>
<li>trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/hook/account/prefs/</li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsExampletemplateendefaulthookaccountprefsprefstabshtmltmpl">trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/hook/account/prefs/prefs-tabs.html.tmpl</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/hook/admin/</li>
<li>trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/hook/admin/params/</li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsExampletemplateendefaulthookadminparamseditparamscurrent_panelhtmltmpl">trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/hook/admin/params/editparams-current_panel.html.tmpl</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/hook/admin/sanitycheck/</li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsExampletemplateendefaulthookadminsanitycheckmessagesstatuseshtmltmpl">trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/hook/admin/sanitycheck/messages-statuses.html.tmpl</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/hook/global/</li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsExampletemplateendefaulthookglobalsettingdescssettingsnonetmpl">trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/hook/global/setting-descs-settings.none.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsExampletemplateendefaulthookglobalusererrorerrorshtmltmpl">trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/hook/global/user-error-errors.html.tmpl</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/pages/</li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsExampletemplateendefaultpagesexamplehtmltmpl">trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/pages/example.html.tmpl</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/setup/</li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsExampletemplateendefaultsetupstringstxtpl">trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/setup/strings.txt.pl</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/OldBugMove/</li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsOldBugMoveConfigpm">trunk/Websites/bugs.webkit.org/extensions/OldBugMove/Config.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsOldBugMoveExtensionpm">trunk/Websites/bugs.webkit.org/extensions/OldBugMove/Extension.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsOldBugMovedisabled">trunk/Websites/bugs.webkit.org/extensions/OldBugMove/disabled</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/OldBugMove/lib/</li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsOldBugMovelibParamspm">trunk/Websites/bugs.webkit.org/extensions/OldBugMove/lib/Params.pm</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/</li>
<li>trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/</li>
<li>trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/</li>
<li>trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/admin/</li>
<li>trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/admin/params/</li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsOldBugMovetemplateendefaultadminparamsoldbugmovehtmltmpl">trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/admin/params/oldbugmove.html.tmpl</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/hook/</li>
<li>trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/hook/bug/</li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsOldBugMovetemplateendefaulthookbugeditafter_comment_textareahtmltmpl">trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/hook/bug/edit-after_comment_textarea.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsOldBugMovetemplateendefaulthookbugformat_commenttypetxttmpl">trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/hook/bug/format_comment-type.txt.tmpl</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/hook/global/</li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsOldBugMovetemplateendefaulthookglobalusererrorauth_failure_actionhtmltmpl">trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/hook/global/user-error-auth_failure_action.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsOldBugMovetemplateendefaulthookglobalusererrorerrorshtmltmpl">trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/hook/global/user-error-errors.html.tmpl</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/hook/list/</li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsOldBugMovetemplateendefaulthooklisteditmultipleafter_groupshtmltmpl">trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/hook/list/edit-multiple-after_groups.html.tmpl</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/Voting/</li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsVotingExtensionpm">trunk/Websites/bugs.webkit.org/extensions/Voting/Extension.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsVotingdisabled">trunk/Websites/bugs.webkit.org/extensions/Voting/disabled</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/Voting/template/</li>
<li>trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/</li>
<li>trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/</li>
<li>trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/</li>
<li>trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/account/</li>
<li>trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/account/prefs/</li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthookaccountprefsemailrelationshipshtmltmpl">trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/account/prefs/email-relationships.html.tmpl</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/admin/</li>
<li>trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/admin/products/</li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthookadminproductseditcommonrowshtmltmpl">trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/admin/products/edit-common-rows.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthookadminproductsupdatedchangeshtmltmpl">trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/admin/products/updated-changes.html.tmpl</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/admin/sanitycheck/</li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthookadminsanitycheckmessagesstatuseshtmltmpl">trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/admin/sanitycheck/messages-statuses.html.tmpl</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/admin/users/</li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthookadminusersconfirmdeletewarn_safehtmltmpl">trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/admin/users/confirm-delete-warn_safe.html.tmpl</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/bug/</li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthookbugeditafter_importancehtmltmpl">trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/bug/edit-after_importance.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthookbugformat_commenttypetxttmpl">trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/bug/format_comment-type.txt.tmpl</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/bug/process/</li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthookbugprocessheadertitlehtmltmpl">trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/bug/process/header-title.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthookbugprocessresultstitlehtmltmpl">trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/bug/process/results-title.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthookbugshowheaderendhtmltmpl">trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/bug/show-header-end.html.tmpl</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/global/</li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthookglobalcodeerrorerrorshtmltmpl">trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/global/code-error-errors.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthookglobalfielddescsendnonetmpl">trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/global/field-descs-end.none.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthookglobalreasondescsendnonetmpl">trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/global/reason-descs-end.none.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthookglobalusererrorerrorshtmltmpl">trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/global/user-error-errors.html.tmpl</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/search/</li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthooksearchformafter_freetext_fieldshtmltmpl">trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/search/form-after_freetext_fields.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthooksearchsearchreportselectrep_fieldshtmltmpl">trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/search/search-report-select-rep_fields.html.tmpl</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/pages/</li>
<li>trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/pages/voting/</li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaultpagesvotingbughtmltmpl">trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/pages/voting/bug.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaultpagesvotinguserhtmltmpl">trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/pages/voting/user.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaultpagesvotinghtmltmpl">trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/pages/voting.html.tmpl</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/voting/</li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaultvotingdeleteallhtmltmpl">trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/voting/delete-all.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaultvotingvotesremovedtxttmpl">trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/voting/votes-removed.txt.tmpl</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/Voting/web/</li>
<li><a href="#trunkWebsitesbugswebkitorgextensionsVotingwebstylecss">trunk/Websites/bugs.webkit.org/extensions/Voting/web/style.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgextensionscreatepl">trunk/Websites/bugs.webkit.org/extensions/create.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjobqueuepl">trunk/Websites/bugs.webkit.org/jobqueue.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsbugjs">trunk/Websites/bugs.webkit.org/js/bug.js</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjschangecolumnsjs">trunk/Websites/bugs.webkit.org/js/change-columns.js</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjscommentsjs">trunk/Websites/bugs.webkit.org/js/comments.js</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjscustomsearchjs">trunk/Websites/bugs.webkit.org/js/custom-search.js</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsflagjs">trunk/Websites/bugs.webkit.org/js/flag.js</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsglobaljs">trunk/Websites/bugs.webkit.org/js/global.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/history.js/</li>
<li><a href="#trunkWebsitesbugswebkitorgjshistoryjslicensetxt">trunk/Websites/bugs.webkit.org/js/history.js/license.txt</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjshistoryjsnativehistoryjs">trunk/Websites/bugs.webkit.org/js/history.js/native.history.js</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjshistoryjsreadmetxt">trunk/Websites/bugs.webkit.org/js/history.js/readme.txt</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/animation/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuianimationanimationminjs">trunk/Websites/bugs.webkit.org/js/yui/animation/animation-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/assets/</li>
<li>trunk/Websites/bugs.webkit.org/js/yui/assets/skins/</li>
<li>trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamajaxloadergif">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/ajax-loader.gif</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamascgif">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/asc.gif</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamautocompletecss">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/autocomplete.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssambackhpng">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/back-h.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssambackvpng">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/back-v.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssambarhpng">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/bar-h.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssambarvpng">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/bar-v.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssambghgif">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/bg-h.gif</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssambgvgif">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/bg-v.gif</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamblankimagepng">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/blankimage.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssambuttoncss">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/button.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamcalendarcss">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/calendar.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamcarouselcss">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/carousel.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamcheck0gif">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/check0.gif</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamcheck1gif">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/check1.gif</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamcheck2gif">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/check2.gif</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamcolorpickercss">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/colorpicker.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamcontainercss">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/container.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamdatatablecss">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/datatable.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamdescgif">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/desc.gif</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamdtarrowdnpng">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/dt-arrow-dn.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamdtarrowuppng">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/dt-arrow-up.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssameditorknobgif">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/editor-knob.gif</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssameditorspriteactivegif">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/editor-sprite-active.gif</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssameditorspritegif">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/editor-sprite.gif</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssameditorcss">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/editor.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamheader_backgroundpng">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/header_background.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamhue_bgpng">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/hue_bg.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamimagecroppercss">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/imagecropper.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamlayoutcss">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/layout.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamlayout_spritepng">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/layout_sprite.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamloadinggif">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/loading.gif</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamloggercss">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/logger.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssammenubuttonarrowdisabledpng">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menu-button-arrow-disabled.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssammenubuttonarrowpng">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menu-button-arrow.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssammenucss">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menu.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssammenubaritem_submenuindicatorpng">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menubaritem_submenuindicator.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssammenubaritem_submenuindicator_disabledpng">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menubaritem_submenuindicator_disabled.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssammenuitem_checkboxpng">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menuitem_checkbox.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssammenuitem_checkbox_disabledpng">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menuitem_checkbox_disabled.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssammenuitem_submenuindicatorpng">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menuitem_submenuindicator.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssammenuitem_submenuindicator_disabledpng">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menuitem_submenuindicator_disabled.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssampaginatorcss">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/paginator.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssampicker_maskpng">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/picker_mask.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamprofilerviewercss">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/profilerviewer.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamprogressbarcss">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/progressbar.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamresizecss">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/resize.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamsimpleeditorcss">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/simpleeditor.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamslidercss">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/slider.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamsplitbuttonarrowactivepng">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/split-button-arrow-active.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamsplitbuttonarrowdisabledpng">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/split-button-arrow-disabled.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamsplitbuttonarrowfocuspng">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/split-button-arrow-focus.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamsplitbuttonarrowhoverpng">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/split-button-arrow-hover.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamsplitbuttonarrowpng">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/split-button-arrow.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamspritepng">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/sprite.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamtabviewcss">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/tabview.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamtreeviewloadinggif">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/treeview-loading.gif</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamtreeviewspritegif">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/treeview-sprite.gif</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamtreeviewcss">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/treeview.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamwaitgif">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/wait.gif</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiassetsskinssamyuitestcss">trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/yuitest.css</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/autocomplete/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiautocompleteautocompleteminjs">trunk/Websites/bugs.webkit.org/js/yui/autocomplete/autocomplete-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/base/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuibasebasemincss">trunk/Websites/bugs.webkit.org/js/yui/base/base-min.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuibasebasecss">trunk/Websites/bugs.webkit.org/js/yui/base/base.css</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/button/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuibuttonbuttonminjs">trunk/Websites/bugs.webkit.org/js/yui/button/button-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/calendar/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuicalendarcalendarminjs">trunk/Websites/bugs.webkit.org/js/yui/calendar/calendar-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/carousel/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuicarouselcarouselminjs">trunk/Websites/bugs.webkit.org/js/yui/carousel/carousel-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/charts/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuichartschartsminjs">trunk/Websites/bugs.webkit.org/js/yui/charts/charts-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/colorpicker/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuicolorpickercolorpickerminjs">trunk/Websites/bugs.webkit.org/js/yui/colorpicker/colorpicker-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/connection/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiconnectionconnectionminjs">trunk/Websites/bugs.webkit.org/js/yui/connection/connection-min.js</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiconnectionconnectionswf">trunk/Websites/bugs.webkit.org/js/yui/connection/connection.swf</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiconnectionconnection_coreminjs">trunk/Websites/bugs.webkit.org/js/yui/connection/connection_core-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/container/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuicontainercontainerminjs">trunk/Websites/bugs.webkit.org/js/yui/container/container-min.js</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuicontainercontainer_coreminjs">trunk/Websites/bugs.webkit.org/js/yui/container/container_core-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/cookie/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuicookiecookieminjs">trunk/Websites/bugs.webkit.org/js/yui/cookie/cookie-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/datasource/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuidatasourcedatasourceminjs">trunk/Websites/bugs.webkit.org/js/yui/datasource/datasource-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/datatable/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuidatatabledatatableminjs">trunk/Websites/bugs.webkit.org/js/yui/datatable/datatable-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/datemath/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuidatemathdatemathminjs">trunk/Websites/bugs.webkit.org/js/yui/datemath/datemath-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/dom/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuidomdomminjs">trunk/Websites/bugs.webkit.org/js/yui/dom/dom-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/dragdrop/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuidragdropdragdropminjs">trunk/Websites/bugs.webkit.org/js/yui/dragdrop/dragdrop-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/element/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuielementelementminjs">trunk/Websites/bugs.webkit.org/js/yui/element/element-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/element-delegate/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuielementdelegateelementdelegateminjs">trunk/Websites/bugs.webkit.org/js/yui/element-delegate/element-delegate-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/event/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuieventeventminjs">trunk/Websites/bugs.webkit.org/js/yui/event/event-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/event-delegate/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuieventdelegateeventdelegateminjs">trunk/Websites/bugs.webkit.org/js/yui/event-delegate/event-delegate-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/event-mouseenter/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuieventmouseentereventmouseenterminjs">trunk/Websites/bugs.webkit.org/js/yui/event-mouseenter/event-mouseenter-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/event-simulate/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuieventsimulateeventsimulateminjs">trunk/Websites/bugs.webkit.org/js/yui/event-simulate/event-simulate-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/fonts/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuifontsfontsmincss">trunk/Websites/bugs.webkit.org/js/yui/fonts/fonts-min.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuifontsfontscss">trunk/Websites/bugs.webkit.org/js/yui/fonts/fonts.css</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/get/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuigetgetminjs">trunk/Websites/bugs.webkit.org/js/yui/get/get-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/grids/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuigridsgridsmincss">trunk/Websites/bugs.webkit.org/js/yui/grids/grids-min.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuigridsgridscss">trunk/Websites/bugs.webkit.org/js/yui/grids/grids.css</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/history/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuihistoryhistoryminjs">trunk/Websites/bugs.webkit.org/js/yui/history/history-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/imagecropper/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiimagecropperimagecropperminjs">trunk/Websites/bugs.webkit.org/js/yui/imagecropper/imagecropper-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/imageloader/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiimageloaderimageloaderminjs">trunk/Websites/bugs.webkit.org/js/yui/imageloader/imageloader-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/json/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuijsonjsonminjs">trunk/Websites/bugs.webkit.org/js/yui/json/json-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/layout/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuilayoutlayoutminjs">trunk/Websites/bugs.webkit.org/js/yui/layout/layout-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/logger/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiloggerloggerminjs">trunk/Websites/bugs.webkit.org/js/yui/logger/logger-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/menu/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuimenumenuminjs">trunk/Websites/bugs.webkit.org/js/yui/menu/menu-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/paginator/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuipaginatorpaginatorminjs">trunk/Websites/bugs.webkit.org/js/yui/paginator/paginator-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/profiler/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiprofilerprofilerminjs">trunk/Websites/bugs.webkit.org/js/yui/profiler/profiler-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/profilerviewer/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiprofilerviewerprofilerviewerminjs">trunk/Websites/bugs.webkit.org/js/yui/profilerviewer/profilerviewer-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/progressbar/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiprogressbarprogressbarminjs">trunk/Websites/bugs.webkit.org/js/yui/progressbar/progressbar-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/reset/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiresetresetmincss">trunk/Websites/bugs.webkit.org/js/yui/reset/reset-min.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiresetresetcss">trunk/Websites/bugs.webkit.org/js/yui/reset/reset.css</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/reset-fonts/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiresetfontsresetfontscss">trunk/Websites/bugs.webkit.org/js/yui/reset-fonts/reset-fonts.css</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/reset-fonts-grids/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiresetfontsgridsresetfontsgridscss">trunk/Websites/bugs.webkit.org/js/yui/reset-fonts-grids/reset-fonts-grids.css</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/resize/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiresizeresizeminjs">trunk/Websites/bugs.webkit.org/js/yui/resize/resize-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/selector/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiselectorselectorminjs">trunk/Websites/bugs.webkit.org/js/yui/selector/selector-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/slider/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuislidersliderminjs">trunk/Websites/bugs.webkit.org/js/yui/slider/slider-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/storage/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuistoragestorageminjs">trunk/Websites/bugs.webkit.org/js/yui/storage/storage-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/stylesheet/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuistylesheetstylesheetminjs">trunk/Websites/bugs.webkit.org/js/yui/stylesheet/stylesheet-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/swf/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiswfswfminjs">trunk/Websites/bugs.webkit.org/js/yui/swf/swf-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/swfdetect/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiswfdetectswfdetectminjs">trunk/Websites/bugs.webkit.org/js/yui/swfdetect/swfdetect-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/swfstore/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiswfstoreswfstoreminjs">trunk/Websites/bugs.webkit.org/js/yui/swfstore/swfstore-min.js</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiswfstoreswfstoreswf">trunk/Websites/bugs.webkit.org/js/yui/swfstore/swfstore.swf</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/tabview/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuitabviewtabviewminjs">trunk/Websites/bugs.webkit.org/js/yui/tabview/tabview-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/treeview/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuitreeviewtreeviewminjs">trunk/Websites/bugs.webkit.org/js/yui/treeview/treeview-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/uploader/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiuploaderuploaderminjs">trunk/Websites/bugs.webkit.org/js/yui/uploader/uploader-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/yahoo/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiyahooyahoominjs">trunk/Websites/bugs.webkit.org/js/yui/yahoo/yahoo-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/yahoo-dom-event/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiyahoodomeventyahoodomeventjs">trunk/Websites/bugs.webkit.org/js/yui/yahoo-dom-event/yahoo-dom-event.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/yuiloader/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiyuiloaderyuiloaderminjs">trunk/Websites/bugs.webkit.org/js/yui/yuiloader/yuiloader-min.js</a></li>
<li>trunk/Websites/bugs.webkit.org/js/yui/yuitest/</li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiyuitestyuitestminjs">trunk/Websites/bugs.webkit.org/js/yui/yuitest/yuitest-min.js</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiyuitestyuitest_coreminjs">trunk/Websites/bugs.webkit.org/js/yui/yuitest/yuitest_core-min.js</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsonrpccgi">trunk/Websites/bugs.webkit.org/jsonrpc.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgmigratepl">trunk/Websites/bugs.webkit.org/migrate.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinsREADME">trunk/Websites/bugs.webkit.org/skins/README</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinsstandardattachmentcss">trunk/Websites/bugs.webkit.org/skins/standard/attachment.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinsstandardenter_bugcss">trunk/Websites/bugs.webkit.org/skins/standard/enter_bug.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinsstandardindexfileabugpng">trunk/Websites/bugs.webkit.org/skins/standard/index/file-a-bug.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinsstandardindexhelppng">trunk/Websites/bugs.webkit.org/skins/standard/index/help.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinsstandardindexnewaccountpng">trunk/Websites/bugs.webkit.org/skins/standard/index/new-account.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinsstandardindexsearchpng">trunk/Websites/bugs.webkit.org/skins/standard/index/search.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinsstandardpagecss">trunk/Websites/bugs.webkit.org/skins/standard/page.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinsstandardreportscss">trunk/Websites/bugs.webkit.org/skins/standard/reports.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinsstandardsearch_formcss">trunk/Websites/bugs.webkit.org/skins/standard/search_form.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgt005whitespacet">trunk/Websites/bugs.webkit.org/t/005whitespace.t</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateencustomattachmentcreateformcontentshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/custom/attachment/createformcontents.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateencustombugfieldhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/custom/bug/field.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateencustombugformat_commenttxttmpl">trunk/Websites/bugs.webkit.org/template/en/custom/bug/format_comment.txt.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminclassificationseditcommonhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/classifications/edit-common.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminclassificationsfooterhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/classifications/footer.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadmincomponentseditcommonhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/components/edit-common.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadmincustom_fieldscfjsjstmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/custom_fields/cf-js.js.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminparamsadvancedhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/params/advanced.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminparamsgeneralhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/params/general.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultbugfieldeventsjstmpl">trunk/Websites/bugs.webkit.org/template/en/default/bug/field-events.js.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultbugfieldhelpnonetmpl">trunk/Websites/bugs.webkit.org/template/en/default/bug/field-help.none.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultbugfieldlabelhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/bug/field-label.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultbugformat_commenttxttmpl">trunk/Websites/bugs.webkit.org/template/en/default/bug/format_comment.txt.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultbuglinkhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/bug/link.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultbugshowheaderhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/bug/show-header.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultemailbugmailcommontxttmpl">trunk/Websites/bugs.webkit.org/template/en/default/email/bugmail-common.txt.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultemailbugmailheadertxttmpl">trunk/Websites/bugs.webkit.org/template/en/default/email/bugmail-header.txt.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultemailbugmailhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/email/bugmail.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultemailbugmailtxttmpl">trunk/Websites/bugs.webkit.org/template/en/default/email/bugmail.txt.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultemaillockouttxttmpl">trunk/Websites/bugs.webkit.org/template/en/default/email/lockout.txt.tmpl</a></li>
<li>trunk/Websites/bugs.webkit.org/template/en/default/extensions/</li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultextensionsconfigpmtmpl">trunk/Websites/bugs.webkit.org/template/en/default/extensions/config.pm.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultextensionsextensionpmtmpl">trunk/Websites/bugs.webkit.org/template/en/default/extensions/extension.pm.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultextensionshookreadmetxttmpl">trunk/Websites/bugs.webkit.org/template/en/default/extensions/hook-readme.txt.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultextensionslicensetxttmpl">trunk/Websites/bugs.webkit.org/template/en/default/extensions/license.txt.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultextensionsnamereadmetxttmpl">trunk/Websites/bugs.webkit.org/template/en/default/extensions/name-readme.txt.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultextensionsutilpmtmpl">trunk/Websites/bugs.webkit.org/template/en/default/extensions/util.pm.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultextensionswebreadmetxttmpl">trunk/Websites/bugs.webkit.org/template/en/default/extensions/web-readme.txt.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultglobalreasondescsnonetmpl">trunk/Websites/bugs.webkit.org/template/en/default/global/reason-descs.none.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultglobaluserhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/global/user.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultglobalvaluedescsjstmpl">trunk/Websites/bugs.webkit.org/template/en/default/global/value-descs.js.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultglobalvaluedescsnonetmpl">trunk/Websites/bugs.webkit.org/template/en/default/global/value-descs.none.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultpagesreleasenotes3htmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/pages/release-notes3.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultreportsdeleteserieshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/reports/delete-series.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultsearchfieldhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/search/field.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultsearchtypeselecthtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/search/type-select.html.tmpl</a></li>
<li>trunk/Websites/bugs.webkit.org/xt/</li>
<li><a href="#trunkWebsitesbugswebkitorgxtREADME">trunk/Websites/bugs.webkit.org/xt/README</a></li>
<li>trunk/Websites/bugs.webkit.org/xt/lib/</li>
<li>trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/</li>
<li>trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/</li>
<li>trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/</li>
<li><a href="#trunkWebsitesbugswebkitorgxtlibBugzillaTestSearchAndTestpm">trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/AndTest.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgxtlibBugzillaTestSearchConstantspm">trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/Constants.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgxtlibBugzillaTestSearchCustomTestpm">trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/CustomTest.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgxtlibBugzillaTestSearchFieldTestpm">trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/FieldTest.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgxtlibBugzillaTestSearchFieldTestNormalpm">trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/FieldTestNormal.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgxtlibBugzillaTestSearchInjectionTestpm">trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/InjectionTest.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgxtlibBugzillaTestSearchNotTestpm">trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/NotTest.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgxtlibBugzillaTestSearchOperatorTestpm">trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/OperatorTest.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgxtlibBugzillaTestSearchOrTestpm">trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/OrTest.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgxtlibBugzillaTestSearchpm">trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgxtsearcht">trunk/Websites/bugs.webkit.org/xt/search.t</a></li>
</ul>

<h3>Removed Paths</h3>
<ul>
<li><a href="#trunkWebsitesbugswebkitorgcvsignore">trunk/Websites/bugs.webkit.org/.cvsignore</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillacvsignore">trunk/Websites/bugs.webkit.org/Bugzilla/.cvsignore</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaConfigBugMovepm">trunk/Websites/bugs.webkit.org/Bugzilla/Config/BugMove.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgBugzillaTemplateParserpm">trunk/Websites/bugs.webkit.org/Bugzilla/Template/Parser.pm</a></li>
<li><a href="#trunkWebsitesbugswebkitorgQUICKSTART">trunk/Websites/bugs.webkit.org/QUICKSTART</a></li>
<li><a href="#trunkWebsitesbugswebkitorgUPGRADING">trunk/Websites/bugs.webkit.org/UPGRADING</a></li>
<li><a href="#trunkWebsitesbugswebkitorgUPGRADINGpre28">trunk/Websites/bugs.webkit.org/UPGRADING-pre-2.8</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcontribbugzilla_ldapsyncrb">trunk/Websites/bugs.webkit.org/contrib/bugzilla_ldapsync.rb</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcontribgnats2bzpl">trunk/Websites/bugs.webkit.org/contrib/gnats2bz.pl</a></li>
<li>trunk/Websites/bugs.webkit.org/contrib/gnatsparse/</li>
<li><a href="#trunkWebsitesbugswebkitorgcontribyp_nomailsh">trunk/Websites/bugs.webkit.org/contrib/yp_nomail.sh</a></li>
<li><a href="#trunkWebsitesbugswebkitorgdocsencvsignore">trunk/Websites/bugs.webkit.org/docs/en/.cvsignore</a></li>
<li><a href="#trunkWebsitesbugswebkitorgdocsenxmlcvsignore">trunk/Websites/bugs.webkit.org/docs/en/xml/.cvsignore</a></li>
<li><a href="#trunkWebsitesbugswebkitorgdocsenxmlintegrationxml">trunk/Websites/bugs.webkit.org/docs/en/xml/integration.xml</a></li>
<li><a href="#trunkWebsitesbugswebkitorgdocsenxmlintroductionxml">trunk/Websites/bugs.webkit.org/docs/en/xml/introduction.xml</a></li>
<li><a href="#trunkWebsitesbugswebkitorgdocsenxmlrequiredsoftwarexml">trunk/Websites/bugs.webkit.org/docs/en/xml/requiredsoftware.xml</a></li>
<li>trunk/Websites/bugs.webkit.org/extensions/example/</li>
<li><a href="#trunkWebsitesbugswebkitorgjshelpjs">trunk/Websites/bugs.webkit.org/js/help.js</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuicalendarjs">trunk/Websites/bugs.webkit.org/js/yui/calendar.js</a></li>
<li><a href="#trunkWebsitesbugswebkitorgjsyuiyahoodomeventjs">trunk/Websites/bugs.webkit.org/js/yui/yahoo-dom-event.js</a></li>
<li><a href="#trunkWebsitesbugswebkitorglong_listcgi">trunk/Websites/bugs.webkit.org/long_list.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgshowattachmentcgi">trunk/Websites/bugs.webkit.org/showattachment.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgsidebarcgi">trunk/Websites/bugs.webkit.org/sidebar.cgi</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscvsignore">trunk/Websites/bugs.webkit.org/skins/.cvsignore</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscontribDuskcvsignore">trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/.cvsignore</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscontribDuskIEfixescss">trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/IE-fixes.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscontribDuskadmincss">trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/admin.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscontribDuskcreate_attachmentcss">trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/create_attachment.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscontribDuskdependencytreecss">trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/dependency-tree.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscontribDuskduplicatescss">trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/duplicates.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscontribDuskedituserscss">trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/editusers.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscontribDuskhelpcss">trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/help.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscontribDuskpanelcss">trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/panel.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscontribDuskparamscss">trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/params.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscontribDuskreleasenotescss">trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/release-notes.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscontribDuskshow_bugcss">trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/show_bug.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscontribDuskshow_multiplecss">trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/show_multiple.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscontribDusksummarizetimecss">trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/summarize-time.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscontribDuskvotingcss">trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/voting.css</a></li>
<li>trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/yui/</li>
<li><a href="#trunkWebsitesbugswebkitorgskinscustomIEfixescss">trunk/Websites/bugs.webkit.org/skins/custom/IE-fixes.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscustomadmincss">trunk/Websites/bugs.webkit.org/skins/custom/admin.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscustombuglistcss">trunk/Websites/bugs.webkit.org/skins/custom/buglist.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscustomcreate_attachmentcss">trunk/Websites/bugs.webkit.org/skins/custom/create_attachment.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscustomdependencytreecss">trunk/Websites/bugs.webkit.org/skins/custom/dependency-tree.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscustomduplicatescss">trunk/Websites/bugs.webkit.org/skins/custom/duplicates.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscustomedituserscss">trunk/Websites/bugs.webkit.org/skins/custom/editusers.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscustomhelpcss">trunk/Websites/bugs.webkit.org/skins/custom/help.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscustomopendarwingif">trunk/Websites/bugs.webkit.org/skins/custom/opendarwin.gif</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscustompanelcss">trunk/Websites/bugs.webkit.org/skins/custom/panel.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscustomparamscss">trunk/Websites/bugs.webkit.org/skins/custom/params.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscustomreleasenotescss">trunk/Websites/bugs.webkit.org/skins/custom/release-notes.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscustomshow_bugcss">trunk/Websites/bugs.webkit.org/skins/custom/show_bug.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscustomshow_multiplecss">trunk/Websites/bugs.webkit.org/skins/custom/show_multiple.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscustomsummarizetimecss">trunk/Websites/bugs.webkit.org/skins/custom/summarize-time.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinscustomvotingcss">trunk/Websites/bugs.webkit.org/skins/custom/voting.css</a></li>
<li>trunk/Websites/bugs.webkit.org/skins/custom/yui/</li>
<li><a href="#trunkWebsitesbugswebkitorgskinsstandardcreate_attachmentcss">trunk/Websites/bugs.webkit.org/skins/standard/create_attachment.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinsstandardhelpcss">trunk/Websites/bugs.webkit.org/skins/standard/help.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinsstandardindexfrontpng">trunk/Websites/bugs.webkit.org/skins/standard/index/front.png</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinsstandardpanelcss">trunk/Websites/bugs.webkit.org/skins/standard/panel.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinsstandardreleasenotescss">trunk/Websites/bugs.webkit.org/skins/standard/release-notes.css</a></li>
<li><a href="#trunkWebsitesbugswebkitorgskinsstandardvotingcss">trunk/Websites/bugs.webkit.org/skins/standard/voting.css</a></li>
<li>trunk/Websites/bugs.webkit.org/skins/standard/yui/</li>
<li><a href="#trunkWebsitesbugswebkitorgt005no_tabst">trunk/Websites/bugs.webkit.org/t/005no_tabs.t</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplatecvsignore">trunk/Websites/bugs.webkit.org/template/.cvsignore</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateencvsignore">trunk/Websites/bugs.webkit.org/template/en/.cvsignore</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateencustomattachmentcontenttypeshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/custom/attachment/content-types.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultadminparamsbugmovehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/admin/params/bugmove.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultattachmentcancelcreatedupehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/attachment/cancel-create-dupe.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultattachmentcontenttypeshtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/attachment/content-types.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultbugcreateconfirmcreatedupehtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/bug/create/confirm-create-dupe.html.tmpl</a></li>
<li>trunk/Websites/bugs.webkit.org/template/en/default/bug/votes/</li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultemailnewchangedmailtxttmpl">trunk/Websites/bugs.webkit.org/template/en/default/email/newchangedmail.txt.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultemailvotesremovedtxttmpl">trunk/Websites/bugs.webkit.org/template/en/default/email/votes-removed.txt.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultlistlistjstmpl">trunk/Websites/bugs.webkit.org/template/en/default/list/list.js.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultpagesquicksearchhackhtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/pages/quicksearchhack.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultpagesvotinghtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/pages/voting.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultsearchsearchhelphtmltmpl">trunk/Websites/bugs.webkit.org/template/en/default/search/search-help.html.tmpl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgtemplateendefaultsidebarxultmpl">trunk/Websites/bugs.webkit.org/template/en/default/sidebar.xul.tmpl</a></li>
<li>trunk/Websites/bugs.webkit.org/template/en/extension/</li>
<li><a href="#trunkWebsitesbugswebkitorgxmlcgi">trunk/Websites/bugs.webkit.org/xml.cgi</a></li>
</ul>

<h3>Property Changed</h3>
<ul>
<li><a href="#trunkWebsitesbugswebkitorgcontribbugzillasubmitbugdatatxt">trunk/Websites/bugs.webkit.org/contrib/bugzilla-submit/bugdata.txt</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcontribbugzillasubmitbugzillasubmitxml">trunk/Websites/bugs.webkit.org/contrib/bugzilla-submit/bugzilla-submit.xml</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcontribcmdlinequeryconf">trunk/Websites/bugs.webkit.org/contrib/cmdline/query.conf</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcontribcvsupdatepl">trunk/Websites/bugs.webkit.org/contrib/cvs-update.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcontribjb2bzpy">trunk/Websites/bugs.webkit.org/contrib/jb2bz.py</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcontribmergeuserspl">trunk/Websites/bugs.webkit.org/contrib/merge-users.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcontribsendbugmailpl">trunk/Websites/bugs.webkit.org/contrib/sendbugmail.pl</a></li>
<li><a href="#trunkWebsitesbugswebkitorgcontribsendunsentbugmailpl">trunk/Websites/bugs.webkit.org/contrib/sendunsentbugmail.pl</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkWebsitesbugswebkitorgbzrignore"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/.bzrignore (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/.bzrignore                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/.bzrignore        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,32 @@
</span><ins>+.htaccess
+/lib/*
+/template/en/custom
+/docs/bugzilla.ent
+/docs/en/xml/bugzilla.ent
+/docs/en/txt
+/docs/en/html
+/docs/en/pdf
+/skins/custom
+/graphs
+/data
+/localconfig
+/index.html
+
+/skins/contrib/Dusk/IE-fixes.css
+/skins/contrib/Dusk/admin.css
+/skins/contrib/Dusk/attachment.css
+/skins/contrib/Dusk/create_attachment.css
+/skins/contrib/Dusk/dependency-tree.css
+/skins/contrib/Dusk/duplicates.css
+/skins/contrib/Dusk/editusers.css
+/skins/contrib/Dusk/enter_bug.css
+/skins/contrib/Dusk/help.css
+/skins/contrib/Dusk/panel.css
+/skins/contrib/Dusk/page.css
+/skins/contrib/Dusk/params.css
+/skins/contrib/Dusk/reports.css
+/skins/contrib/Dusk/show_bug.css
+/skins/contrib/Dusk/search_form.css
+/skins/contrib/Dusk/show_multiple.css
+/skins/contrib/Dusk/summarize-time.css
+.DS_Store
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgcvsignore"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/.cvsignore (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/.cvsignore        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/.cvsignore        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,6 +0,0 @@
</span><del>-.htaccess
-graphs
-data
-localconfig
-index.html
-old-params.txt
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorghtaccess"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/.htaccess (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/.htaccess        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/.htaccess        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,10 +1,33 @@
</span><del>-# don't allow people to retrieve non-cgi executable files or our private data
</del><ins>+# Don't allow people to retrieve non-cgi executable files or our private data
</ins><span class="cx"> &lt;FilesMatch ^(.*\.pm|.*\.pl|.*localconfig.*)$&gt;
</span><span class="cx">   deny from all
</span><span class="cx"> &lt;/FilesMatch&gt;
</span><span class="cx"> &lt;FilesMatch ^(localconfig.js|localconfig.rdf)$&gt;
</span><span class="cx">   allow from all
</span><span class="cx"> &lt;/FilesMatch&gt;
</span><ins>+&lt;IfModule mod_expires.c&gt;
+&lt;IfModule mod_headers.c&gt;
+&lt;IfModule mod_env.c&gt;
+  &lt;FilesMatch (\.js|\.css)$&gt;
+    ExpiresActive On
+    # According to RFC 2616, &quot;1 year in the future&quot; means &quot;never expire&quot;.
+    # We change the name of the file's URL whenever its modification date
+    # changes, so browsers can cache any individual JS or CSS URL forever.
+    # However, since all JS and CSS URLs involve a ? in them (for the changing
+    # name) we have to explicitly set an Expires header or browsers won't
+    # *ever* cache them.
+    ExpiresDefault &quot;now plus 1 years&quot;
+    Header append Cache-Control &quot;public&quot;
+  &lt;/FilesMatch&gt;
</ins><span class="cx"> 
</span><ins>+  # This lets Bugzilla know that we are properly sending Cache-Control
+  # and Expires headers for CSS and JS files.
+  SetEnv BZ_CACHE_CONTROL 1
+&lt;/IfModule&gt;
+&lt;/IfModule&gt;
+&lt;/IfModule&gt;
+
</ins><span class="cx"> # Force all connections to HTTPS for 90 days at a time.
</span><del>-Header set Strict-Transport-Security &quot;max-age=7776000&quot;
</del><ins>+&lt;IfModule mod_headers.c&gt;
+  Header set Strict-Transport-Security &quot;max-age=7776000&quot;
+&lt;/IfModule&gt;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillacvsignore"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/Bugzilla/.cvsignore (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/.cvsignore        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/.cvsignore        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1 +0,0 @@
</span><del>-.htaccess
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaAttachmentPatchReaderpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Attachment/PatchReader.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Attachment/PatchReader.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Attachment/PatchReader.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -37,6 +37,7 @@
</span><span class="cx">         $last_reader-&gt;sends_data_to(new PatchReader::DiffPrinter::raw());
</span><span class="cx">         # Actually print out the patch.
</span><span class="cx">         print $cgi-&gt;header(-type =&gt; 'text/plain',
</span><ins>+                           -x_content_type_options =&gt; &quot;nosniff&quot;,
</ins><span class="cx">                            -expires =&gt; '+3M');
</span><span class="cx">         disable_utf8();
</span><span class="cx">         $reader-&gt;iterate_string('Attachment ' . $attachment-&gt;id, $attachment-&gt;data);
</span><span class="lines">@@ -118,6 +119,7 @@
</span><span class="cx">         $last_reader-&gt;sends_data_to(new PatchReader::DiffPrinter::raw());
</span><span class="cx">         # Actually print out the patch.
</span><span class="cx">         print $cgi-&gt;header(-type =&gt; 'text/plain',
</span><ins>+                           -x_content_type_options =&gt; &quot;nosniff&quot;,
</ins><span class="cx">                            -expires =&gt; '+3M');
</span><span class="cx">         disable_utf8();
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaAttachmentpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Attachment.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Attachment.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Attachment.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -28,24 +28,27 @@
</span><span class="cx"> 
</span><span class="cx"> =head1 NAME
</span><span class="cx"> 
</span><del>-Bugzilla::Attachment - a file related to a bug that a user has uploaded
-                       to the Bugzilla server
</del><ins>+Bugzilla::Attachment - Bugzilla attachment class.
</ins><span class="cx"> 
</span><span class="cx"> =head1 SYNOPSIS
</span><span class="cx"> 
</span><span class="cx">   use Bugzilla::Attachment;
</span><span class="cx"> 
</span><span class="cx">   # Get the attachment with the given ID.
</span><del>-  my $attachment = Bugzilla::Attachment-&gt;get($attach_id);
</del><ins>+  my $attachment = new Bugzilla::Attachment($attach_id);
</ins><span class="cx"> 
</span><span class="cx">   # Get the attachments with the given IDs.
</span><del>-  my $attachments = Bugzilla::Attachment-&gt;get_list($attach_ids);
</del><ins>+  my $attachments = Bugzilla::Attachment-&gt;new_from_list($attach_ids);
</ins><span class="cx"> 
</span><span class="cx"> =head1 DESCRIPTION
</span><span class="cx"> 
</span><del>-This module defines attachment objects, which represent files related to bugs
-that users upload to the Bugzilla server.
</del><ins>+Attachment.pm represents an attachment object. It is an implementation
+of L&lt;Bugzilla::Object&gt;, and thus provides all methods that
+L&lt;Bugzilla::Object&gt; provides.
</ins><span class="cx"> 
</span><ins>+The methods that are specific to C&lt;Bugzilla::Attachment&gt; are listed
+below.
+
</ins><span class="cx"> =cut
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla::Constants;
</span><span class="lines">@@ -54,96 +57,111 @@
</span><span class="cx"> use Bugzilla::User;
</span><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> use Bugzilla::Field;
</span><ins>+use Bugzilla::Hook;
</ins><span class="cx"> 
</span><del>-sub get {
-    my $invocant = shift;
-    my $id = shift;
</del><ins>+use File::Copy;
+use List::Util qw(max);
</ins><span class="cx"> 
</span><del>-    my $attachments = _retrieve([$id]);
-    my $self = $attachments-&gt;[0];
-    bless($self, ref($invocant) || $invocant) if $self;
</del><ins>+use base qw(Bugzilla::Object);
</ins><span class="cx"> 
</span><del>-    return $self;
-}
</del><ins>+###############################
+####    Initialization     ####
+###############################
</ins><span class="cx"> 
</span><del>-sub get_list {
-    my $invocant = shift;
-    my $ids = shift;
</del><ins>+use constant DB_TABLE   =&gt; 'attachments';
+use constant ID_FIELD   =&gt; 'attach_id';
+use constant LIST_ORDER =&gt; ID_FIELD;
+# Attachments are tracked in bugs_activity.
+use constant AUDIT_CREATES =&gt; 0;
+use constant AUDIT_UPDATES =&gt; 0;
</ins><span class="cx"> 
</span><del>-    my $attachments = _retrieve($ids);
-    foreach my $attachment (@$attachments) {
-        bless($attachment, ref($invocant) || $invocant);
-    }
</del><ins>+sub DB_COLUMNS {
+    my $dbh = Bugzilla-&gt;dbh;
</ins><span class="cx"> 
</span><del>-    return $attachments;
</del><ins>+    return qw(
+        attach_id
+        bug_id
+        description
+        filename
+        isobsolete
+        ispatch
+        isprivate
+        mimetype
+        modification_time
+        submitter_id),
+        $dbh-&gt;sql_date_format('attachments.creation_ts', '%Y.%m.%d %H:%i') . ' AS creation_ts';
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _retrieve {
-    my ($ids) = @_;
</del><ins>+use constant REQUIRED_FIELD_MAP =&gt; {
+    bug_id =&gt; 'bug',
+};
+use constant EXTRA_REQUIRED_FIELDS =&gt; qw(data);
</ins><span class="cx"> 
</span><del>-    return [] if scalar(@$ids) == 0;
</del><ins>+use constant UPDATE_COLUMNS =&gt; qw(
+    description
+    filename
+    isobsolete
+    ispatch
+    isprivate
+    mimetype
+);
</ins><span class="cx"> 
</span><del>-    my @columns = (
-        'attachments.attach_id AS id',
-        'attachments.bug_id AS bug_id',
-        'attachments.description AS description',
-        'attachments.mimetype AS contenttype',
-        'attachments.submitter_id AS attacher_id',
-        Bugzilla-&gt;dbh-&gt;sql_date_format('attachments.creation_ts',
-                                       '%Y.%m.%d %H:%i') . &quot; AS attached&quot;,
-        'attachments.modification_time',
-        'attachments.filename AS filename',
-        'attachments.ispatch AS ispatch',
-        'attachments.isurl AS isurl',
-        'attachments.isobsolete AS isobsolete',
-        'attachments.isprivate AS isprivate'
-    );
-    my $columns = join(&quot;, &quot;, @columns);
-    my $dbh = Bugzilla-&gt;dbh;
-    my $records = $dbh-&gt;selectall_arrayref(
-                      &quot;SELECT $columns
-                         FROM attachments
-                        WHERE &quot; 
-                       . Bugzilla-&gt;dbh-&gt;sql_in('attach_id', $ids) 
-                 . &quot; ORDER BY attach_id&quot;,
-                       { Slice =&gt; {} });
-    return $records;
-}
</del><ins>+use constant VALIDATORS =&gt; {
+    bug           =&gt; \&amp;_check_bug,
+    description   =&gt; \&amp;_check_description,
+    filename      =&gt; \&amp;_check_filename,
+    ispatch       =&gt; \&amp;Bugzilla::Object::check_boolean,
+    isprivate     =&gt; \&amp;_check_is_private,
+    mimetype      =&gt; \&amp;_check_content_type,
+};
</ins><span class="cx"> 
</span><ins>+use constant VALIDATOR_DEPENDENCIES =&gt; {
+    mimetype =&gt; ['ispatch'],
+};
+
+use constant UPDATE_VALIDATORS =&gt; {
+    isobsolete =&gt; \&amp;Bugzilla::Object::check_boolean,
+};
+
+###############################
+####      Accessors      ######
+###############################
+
</ins><span class="cx"> =pod
</span><span class="cx"> 
</span><span class="cx"> =head2 Instance Properties
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><del>-=item C&lt;id&gt;
</del><ins>+=item C&lt;bug_id&gt;
</ins><span class="cx"> 
</span><del>-the unique identifier for the attachment
</del><ins>+the ID of the bug to which the attachment is attached
</ins><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><span class="cx"> =cut
</span><span class="cx"> 
</span><del>-sub id {
</del><ins>+sub bug_id {
</ins><span class="cx">     my $self = shift;
</span><del>-    return $self-&gt;{id};
</del><ins>+    return $self-&gt;{bug_id};
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><del>-=item C&lt;bug_id&gt;
</del><ins>+=item C&lt;bug&gt;
</ins><span class="cx"> 
</span><del>-the ID of the bug to which the attachment is attached
</del><ins>+the bug object to which the attachment is attached
</ins><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><span class="cx"> =cut
</span><span class="cx"> 
</span><del>-# XXX Once Bug.pm slims down sufficiently this should become a reference
-# to a bug object.
-sub bug_id {
</del><ins>+sub bug {
</ins><span class="cx">     my $self = shift;
</span><del>-    return $self-&gt;{bug_id};
</del><ins>+
+    require Bugzilla::Bug;
+    $self-&gt;{bug} ||= Bugzilla::Bug-&gt;new($self-&gt;bug_id);
+    return $self-&gt;{bug};
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="lines">@@ -173,7 +191,7 @@
</span><span class="cx"> 
</span><span class="cx"> sub contenttype {
</span><span class="cx">     my $self = shift;
</span><del>-    return $self-&gt;{contenttype};
</del><ins>+    return $self-&gt;{mimetype};
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="lines">@@ -189,7 +207,7 @@
</span><span class="cx"> sub attacher {
</span><span class="cx">     my $self = shift;
</span><span class="cx">     return $self-&gt;{attacher} if exists $self-&gt;{attacher};
</span><del>-    $self-&gt;{attacher} = new Bugzilla::User($self-&gt;{attacher_id});
</del><ins>+    $self-&gt;{attacher} = new Bugzilla::User($self-&gt;{submitter_id});
</ins><span class="cx">     return $self-&gt;{attacher};
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -205,7 +223,7 @@
</span><span class="cx"> 
</span><span class="cx"> sub attached {
</span><span class="cx">     my $self = shift;
</span><del>-    return $self-&gt;{attached};
</del><ins>+    return $self-&gt;{creation_ts};
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="lines">@@ -255,21 +273,6 @@
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><del>-=item C&lt;isurl&gt;
-
-whether or not the attachment is a URL
-
-=back
-
-=cut
-
-sub isurl {
-    my $self = shift;
-    return $self-&gt;{isurl};
-}
-
-=over
-
</del><span class="cx"> =item C&lt;isobsolete&gt;
</span><span class="cx"> 
</span><span class="cx"> whether or not the attachment is obsolete
</span><span class="lines">@@ -351,7 +354,7 @@
</span><span class="cx">                                                       FROM attach_data
</span><span class="cx">                                                       WHERE id = ?&quot;,
</span><span class="cx">                                                      undef,
</span><del>-                                                     $self-&gt;{id});
</del><ins>+                                                     $self-&gt;id);
</ins><span class="cx"> 
</span><span class="cx">     # If there's no attachment data in the database, the attachment is stored
</span><span class="cx">     # in a local file, so retrieve it from there.
</span><span class="lines">@@ -396,7 +399,7 @@
</span><span class="cx">         Bugzilla-&gt;dbh-&gt;selectrow_array(&quot;SELECT LENGTH(thedata)
</span><span class="cx">                                         FROM attach_data
</span><span class="cx">                                         WHERE id = ?&quot;,
</span><del>-                                       undef, $self-&gt;{id}) || 0;
</del><ins>+                                       undef, $self-&gt;id) || 0;
</ins><span class="cx"> 
</span><span class="cx">     # If there's no attachment data in the database, either the attachment
</span><span class="cx">     # is stored in a local file, and so retrieve its size from the file,
</span><span class="lines">@@ -412,6 +415,13 @@
</span><span class="cx">     return $self-&gt;{datasize};
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub _get_local_filename {
+    my $self = shift;
+    my $hash = ($self-&gt;id % 100) + 100;
+    $hash =~ s/.*(\d\d)$/group.$1/;
+    return bz_locations()-&gt;{'attachdir'} . &quot;/$hash/attachment.&quot; . $self-&gt;id;
+}
+
</ins><span class="cx"> =over
</span><span class="cx"> 
</span><span class="cx"> =item C&lt;flags&gt;
</span><span class="lines">@@ -424,30 +434,147 @@
</span><span class="cx"> 
</span><span class="cx"> sub flags {
</span><span class="cx">     my $self = shift;
</span><del>-    return $self-&gt;{flags} if exists $self-&gt;{flags};
</del><span class="cx"> 
</span><del>-    $self-&gt;{flags} = Bugzilla::Flag-&gt;match({ 'attach_id' =&gt; $self-&gt;id });
</del><ins>+    # Don't cache it as it must be in sync with -&gt;flag_types.
+    $self-&gt;{flags} = [map { @{$_-&gt;{flags}} } @{$self-&gt;flag_types}];
</ins><span class="cx">     return $self-&gt;{flags};
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-# Instance methods; no POD documentation here yet because the only ones so far
-# are private.
</del><ins>+=over
</ins><span class="cx"> 
</span><del>-sub _get_local_filename {
</del><ins>+=item C&lt;flag_types&gt;
+
+Return all flag types available for this attachment as well as flags
+already set, grouped by flag type.
+
+=back
+
+=cut
+
+sub flag_types {
</ins><span class="cx">     my $self = shift;
</span><del>-    my $hash = ($self-&gt;id % 100) + 100;
-    $hash =~ s/.*(\d\d)$/group.$1/;
-    return bz_locations()-&gt;{'attachdir'} . &quot;/$hash/attachment.&quot; . $self-&gt;id;
</del><ins>+    return $self-&gt;{flag_types} if exists $self-&gt;{flag_types};
+
+    my $vars = { target_type  =&gt; 'attachment',
+                 product_id   =&gt; $self-&gt;bug-&gt;product_id,
+                 component_id =&gt; $self-&gt;bug-&gt;component_id,
+                 attach_id    =&gt; $self-&gt;id };
+
+    $self-&gt;{flag_types} = Bugzilla::Flag-&gt;_flag_types($vars);
+    return $self-&gt;{flag_types};
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _validate_filename {
-    my ($throw_error) = @_;
-    my $cgi = Bugzilla-&gt;cgi;
-    defined $cgi-&gt;upload('data')
-        || ($throw_error ? ThrowUserError(&quot;file_not_specified&quot;) : return 0);
</del><ins>+###############################
+####      Validators     ######
+###############################
</ins><span class="cx"> 
</span><del>-    my $filename = $cgi-&gt;upload('data');
</del><ins>+sub set_content_type { $_[0]-&gt;set('mimetype', $_[1]); }
+sub set_description  { $_[0]-&gt;set('description', $_[1]); }
+sub set_filename     { $_[0]-&gt;set('filename', $_[1]); }
+sub set_is_patch     { $_[0]-&gt;set('ispatch', $_[1]); }
+sub set_is_private   { $_[0]-&gt;set('isprivate', $_[1]); }
</ins><span class="cx"> 
</span><ins>+sub set_is_obsolete  {
+    my ($self, $obsolete) = @_;
+
+    my $old = $self-&gt;isobsolete;
+    $self-&gt;set('isobsolete', $obsolete);
+    my $new = $self-&gt;isobsolete;
+
+    # If the attachment is being marked as obsolete, cancel pending requests.
+    if ($new &amp;&amp; $old != $new) {
+        my @requests = grep { $_-&gt;status eq '?' } @{$self-&gt;flags};
+        return unless scalar @requests;
+
+        my %flag_ids = map { $_-&gt;id =&gt; 1 } @requests;
+        foreach my $flagtype (@{$self-&gt;flag_types}) {
+            @{$flagtype-&gt;{flags}} = grep { !$flag_ids{$_-&gt;id} } @{$flagtype-&gt;{flags}};
+        }
+    }
+}
+
+sub set_flags {
+    my ($self, $flags, $new_flags) = @_;
+
+    Bugzilla::Flag-&gt;set_flag($self, $_) foreach (@$flags, @$new_flags);
+}
+
+sub _check_bug {
+    my ($invocant, $bug) = @_;
+    my $user = Bugzilla-&gt;user;
+
+    $bug = ref $invocant ? $invocant-&gt;bug : $bug;
+
+    $bug || ThrowCodeError('param_required', 
+                           { function =&gt; &quot;$invocant-&gt;create&quot;, param =&gt; 'bug' });
+
+    ($user-&gt;can_see_bug($bug-&gt;id) &amp;&amp; $user-&gt;can_edit_product($bug-&gt;product_id))
+      || ThrowUserError(&quot;illegal_attachment_edit_bug&quot;, { bug_id =&gt; $bug-&gt;id });
+
+    return $bug;
+}
+
+sub _check_content_type {
+    my ($invocant, $content_type, undef, $params) = @_;

+    my $is_patch = ref($invocant) ? $invocant-&gt;ispatch : $params-&gt;{ispatch};
+    $content_type = 'text/plain' if $is_patch;
+    $content_type = clean_text($content_type);
+    # The subsets below cover all existing MIME types and charsets registered by IANA.
+    # (MIME type: RFC 2045 section 5.1; charset: RFC 2278 section 3.3)
+    my $legal_types = join('|', LEGAL_CONTENT_TYPES);
+    if (!$content_type
+        || $content_type !~ /^($legal_types)\/[a-z0-9_\-\+\.]+(;\s*charset=[a-z0-9_\-\+]+)?$/i)
+    {
+        ThrowUserError(&quot;invalid_content_type&quot;, { contenttype =&gt; $content_type });
+    }
+    trick_taint($content_type);
+
+    return $content_type;
+}
+
+sub _check_data {
+    my ($invocant, $params) = @_;
+
+    my $data = $params-&gt;{data};
+    $params-&gt;{filesize} = ref $data ? -s $data : length($data);
+
+    Bugzilla::Hook::process('attachment_process_data', { data       =&gt; \$data,
+                                                         attributes =&gt; $params });
+
+    $params-&gt;{filesize} || ThrowUserError('zero_length_file');
+    # Make sure the attachment does not exceed the maximum permitted size.
+    my $max_size = max(Bugzilla-&gt;params-&gt;{'maxlocalattachment'} * 1048576,
+                       Bugzilla-&gt;params-&gt;{'maxattachmentsize'} * 1024);
+
+    if ($params-&gt;{filesize} &gt; $max_size) {
+        my $vars = { filesize =&gt; sprintf(&quot;%.0f&quot;, $params-&gt;{filesize}/1024) };
+        ThrowUserError('file_too_large', $vars);
+    }
+    return $data;
+}
+
+sub _check_description {
+    my ($invocant, $description) = @_;
+
+    $description = trim($description);
+    $description || ThrowUserError('missing_attachment_description');
+    return $description;
+}
+
+sub _check_filename {
+    my ($invocant, $filename) = @_;
+
+    $filename = clean_text($filename);
+    if (!$filename) {
+        if (ref $invocant) {
+            ThrowUserError('filename_not_specified');
+        }
+        else {
+            ThrowUserError('file_not_specified');
+        }
+    }
+
</ins><span class="cx">     # Remove path info (if any) from the file name.  The browser should do this
</span><span class="cx">     # for us, but some are buggy.  This may not work on Mac file names and could
</span><span class="cx">     # mess up file names with slashes in them, but them's the breaks.  We only
</span><span class="lines">@@ -458,65 +585,21 @@
</span><span class="cx">     # Truncate the filename to 100 characters, counting from the end of the
</span><span class="cx">     # string to make sure we keep the filename extension.
</span><span class="cx">     $filename = substr($filename, -100, 100);
</span><ins>+    trick_taint($filename);
</ins><span class="cx"> 
</span><span class="cx">     return $filename;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _validate_data {
-    my ($throw_error, $hr_vars) = @_;
-    my $cgi = Bugzilla-&gt;cgi;
-    my $maxsize = $cgi-&gt;param('ispatch') ? Bugzilla-&gt;params-&gt;{'maxpatchsize'} 
-                  : Bugzilla-&gt;params-&gt;{'maxattachmentsize'};
-    $maxsize *= 1024; # Convert from K
-    my $fh;
-    # Skip uploading into a local variable if the user wants to upload huge
-    # attachments into local files.
-    if (!$cgi-&gt;param('bigfile')) {
-        $fh = $cgi-&gt;upload('data');
-    }
-    my $data;
</del><ins>+sub _check_is_private {
+    my ($invocant, $is_private) = @_;
</ins><span class="cx"> 
</span><del>-    # We could get away with reading only as much as required, except that then
-    # we wouldn't have a size to print to the error handler below.
-    if (!$cgi-&gt;param('bigfile')) {
-        # enable 'slurp' mode
-        local $/;
-        $data = &lt;$fh&gt;;
</del><ins>+    $is_private = $is_private ? 1 : 0;
+    if (((!ref $invocant &amp;&amp; $is_private)
+         || (ref $invocant &amp;&amp; $invocant-&gt;isprivate != $is_private))
+        &amp;&amp; !Bugzilla-&gt;user-&gt;is_insider) {
+        ThrowUserError('user_not_insider');
</ins><span class="cx">     }
</span><del>-
-    $data
-        || ($cgi-&gt;param('bigfile'))
-        || ($throw_error ? ThrowUserError(&quot;zero_length_file&quot;) : return 0);
-
-    # Windows screenshots are usually uncompressed BMP files which
-    # makes for a quick way to eat up disk space. Let's compress them.
-    # We do this before we check the size since the uncompressed version
-    # could easily be greater than maxattachmentsize.
-    if (Bugzilla-&gt;params-&gt;{'convert_uncompressed_images'}
-        &amp;&amp; $cgi-&gt;param('contenttype') eq 'image/bmp') {
-        require Image::Magick;
-        my $img = Image::Magick-&gt;new(magick=&gt;'bmp');
-        $img-&gt;BlobToImage($data);
-        $img-&gt;set(magick=&gt;'png');
-        my $imgdata = $img-&gt;ImageToBlob();
-        $data = $imgdata;
-        $cgi-&gt;param('contenttype', 'image/png');
-        $hr_vars-&gt;{'convertedbmp'} = 1;
-    }
-
-    # Make sure the attachment does not exceed the maximum permitted size
-    my $len = $data ? length($data) : 0;
-    if ($maxsize &amp;&amp; $len &gt; $maxsize) {
-        my $vars = { filesize =&gt; sprintf(&quot;%.0f&quot;, $len/1024) };
-        if ($cgi-&gt;param('ispatch')) {
-            $throw_error ? ThrowUserError(&quot;patch_too_large&quot;, $vars) : return 0;
-        }
-        else {
-            $throw_error ? ThrowUserError(&quot;file_too_large&quot;, $vars) : return 0;
-        }
-    }
-
-    return $data || '';
</del><ins>+    return $is_private;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> =pod
</span><span class="lines">@@ -538,7 +621,7 @@
</span><span class="cx"> =cut
</span><span class="cx"> 
</span><span class="cx"> sub get_attachments_by_bug {
</span><del>-    my ($class, $bug_id) = @_;
</del><ins>+    my ($class, $bug_id, $vars) = @_;
</ins><span class="cx">     my $user = Bugzilla-&gt;user;
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx"> 
</span><span class="lines">@@ -555,107 +638,26 @@
</span><span class="cx">     my $attach_ids = $dbh-&gt;selectcol_arrayref(&quot;SELECT attach_id FROM attachments
</span><span class="cx">                                                WHERE bug_id = ? $and_restriction&quot;,
</span><span class="cx">                                                undef, @values);
</span><del>-    my $attachments = Bugzilla::Attachment-&gt;get_list($attach_ids);
-    return $attachments;
-}
</del><span class="cx"> 
</span><del>-=pod
</del><ins>+    my $attachments = Bugzilla::Attachment-&gt;new_from_list($attach_ids);
</ins><span class="cx"> 
</span><del>-=item C&lt;validate_is_patch()&gt;
</del><ins>+    # To avoid $attachment-&gt;flags to run SQL queries itself for each
+    # attachment listed here, we collect all the data at once and
+    # populate $attachment-&gt;{flags} ourselves.
+    if ($vars-&gt;{preload}) {
+        $_-&gt;{flags} = [] foreach @$attachments;
+        my %att = map { $_-&gt;id =&gt; $_ } @$attachments;
</ins><span class="cx"> 
</span><del>-Description: validates the &quot;patch&quot; flag passed in by CGI.
</del><ins>+        my $flags = Bugzilla::Flag-&gt;match({ bug_id      =&gt; $bug_id,
+                                            target_type =&gt; 'attachment' });
</ins><span class="cx"> 
</span><del>-Returns:    1 on success.
</del><ins>+        # Exclude flags for private attachments you cannot see.
+        @$flags = grep {exists $att{$_-&gt;attach_id}} @$flags;
</ins><span class="cx"> 
</span><del>-=cut
-
-sub validate_is_patch {
-    my ($class, $throw_error) = @_;
-    my $cgi = Bugzilla-&gt;cgi;
-
-    # Set the ispatch flag to zero if it is undefined, since the UI uses
-    # an HTML checkbox to represent this flag, and unchecked HTML checkboxes
-    # do not get sent in HTML requests.
-    $cgi-&gt;param('ispatch', $cgi-&gt;param('ispatch') ? 1 : 0);
-
-    # Set the content type to text/plain if the attachment is a patch.
-    $cgi-&gt;param('contenttype', 'text/plain') if $cgi-&gt;param('ispatch');
-
-    return 1;
-}
-
-=pod
-
-=item C&lt;validate_description()&gt;
-
-Description: validates the description passed in by CGI.
-
-Returns:    1 on success.
-
-=cut
-
-sub validate_description {
-    my ($class, $throw_error) = @_;
-    my $cgi = Bugzilla-&gt;cgi;
-
-    $cgi-&gt;param('description')
-        || ($throw_error ? ThrowUserError(&quot;missing_attachment_description&quot;) : return 0);
-
-    return 1;
-}
-
-=pod
-
-=item C&lt;validate_content_type()&gt;
-
-Description: validates the content type passed in by CGI.
-
-Returns:    1 on success.
-
-=cut
-
-sub validate_content_type {
-    my ($class, $throw_error) = @_;
-    my $cgi = Bugzilla-&gt;cgi;
-
-    if (!defined $cgi-&gt;param('contenttypemethod')) {
-        $throw_error ? ThrowUserError(&quot;missing_content_type_method&quot;) : return 0;
</del><ins>+        push(@{$att{$_-&gt;attach_id}-&gt;{flags}}, $_) foreach @$flags;
+        $attachments = [sort {$a-&gt;id &lt;=&gt; $b-&gt;id} values %att];
</ins><span class="cx">     }
</span><del>-    elsif ($cgi-&gt;param('contenttypemethod') eq 'autodetect') {
-        my $contenttype =
-            $cgi-&gt;uploadInfo($cgi-&gt;param('data'))-&gt;{'Content-Type'};
-        # The user asked us to auto-detect the content type, so use the type
-        # specified in the HTTP request headers.
-        if ( !$contenttype ) {
-            $throw_error ? ThrowUserError(&quot;missing_content_type&quot;) : return 0;
-        }
-        $cgi-&gt;param('contenttype', $contenttype);
-    }
-    elsif ($cgi-&gt;param('contenttypemethod') eq 'list') {
-        # The user selected a content type from the list, so use their
-        # selection.
-        $cgi-&gt;param('contenttype', $cgi-&gt;param('contenttypeselection'));
-    }
-    elsif ($cgi-&gt;param('contenttypemethod') eq 'manual') {
-        # The user entered a content type manually, so use their entry.
-        $cgi-&gt;param('contenttype', $cgi-&gt;param('contenttypeentry'));
-    }
-    else {
-        $throw_error ?
-            ThrowCodeError(&quot;illegal_content_type_method&quot;,
-                           { contenttypemethod =&gt; $cgi-&gt;param('contenttypemethod') }) :
-            return 0;
-    }
-
-    if ( $cgi-&gt;param('contenttype') !~
-           /^(application|audio|image|message|model|multipart|text|video)\/.+$/ ) {
-        $throw_error ?
-            ThrowUserError(&quot;invalid_content_type&quot;,
-                           { contenttype =&gt; $cgi-&gt;param('contenttype') }) :
-            return 0;
-    }
-
-    return 1;
</del><ins>+    return $attachments;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> =pod
</span><span class="lines">@@ -670,7 +672,7 @@
</span><span class="cx"> Params:      $attachment - the attachment object being edited.
</span><span class="cx">              $product_id - the product ID the attachment belongs to.
</span><span class="cx"> 
</span><del>-Returns:     1 on success. Else an error is thrown.
</del><ins>+Returns:     1 on success, 0 otherwise.
</ins><span class="cx"> 
</span><span class="cx"> =cut
</span><span class="cx"> 
</span><span class="lines">@@ -679,15 +681,12 @@
</span><span class="cx">     my $user = Bugzilla-&gt;user;
</span><span class="cx"> 
</span><span class="cx">     # The submitter can edit their attachments.
</span><del>-    return 1 if ($attachment-&gt;attacher-&gt;id == $user-&gt;id
-                 || ((!$attachment-&gt;isprivate || $user-&gt;is_insider)
-                      &amp;&amp; $user-&gt;in_group('editbugs', $product_id)));
-
-    # If we come here, then this attachment cannot be seen by the user.
-    ThrowUserError('illegal_attachment_edit', { attach_id =&gt; $attachment-&gt;id });
</del><ins>+    return ($attachment-&gt;attacher-&gt;id == $user-&gt;id
+            || ((!$attachment-&gt;isprivate || $user-&gt;is_insider)
+                 &amp;&amp; $user-&gt;in_group('editbugs', $product_id))) ? 1 : 0;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-=item C&lt;validate_obsolete($bug)&gt;
</del><ins>+=item C&lt;validate_obsolete($bug, $attach_ids)&gt;
</ins><span class="cx"> 
</span><span class="cx"> Description: validates if attachments the user wants to mark as obsolete
</span><span class="cx">              really belong to the given bug and are not already obsolete.
</span><span class="lines">@@ -695,33 +694,34 @@
</span><span class="cx">              he cannot view it (due to restrictions on it).
</span><span class="cx"> 
</span><span class="cx"> Params:      $bug - The bug object obsolete attachments should belong to.
</span><ins>+             $attach_ids - The list of attachments to mark as obsolete.
</ins><span class="cx"> 
</span><del>-Returns:     1 on success. Else an error is thrown.
</del><ins>+Returns:     The list of attachment objects to mark as obsolete.
+             Else an error is thrown.
</ins><span class="cx"> 
</span><span class="cx"> =cut
</span><span class="cx"> 
</span><span class="cx"> sub validate_obsolete {
</span><del>-    my ($class, $bug) = @_;
-    my $cgi = Bugzilla-&gt;cgi;
</del><ins>+    my ($class, $bug, $list) = @_;
</ins><span class="cx"> 
</span><span class="cx">     # Make sure the attachment id is valid and the user has permissions to view
</span><span class="cx">     # the bug to which it is attached. Make sure also that the user can view
</span><span class="cx">     # the attachment itself.
</span><span class="cx">     my @obsolete_attachments;
</span><del>-    foreach my $attachid ($cgi-&gt;param('obsolete')) {
</del><ins>+    foreach my $attachid (@$list) {
</ins><span class="cx">         my $vars = {};
</span><span class="cx">         $vars-&gt;{'attach_id'} = $attachid;
</span><span class="cx"> 
</span><span class="cx">         detaint_natural($attachid)
</span><span class="cx">           || ThrowCodeError('invalid_attach_id_to_obsolete', $vars);
</span><span class="cx"> 
</span><del>-        my $attachment = Bugzilla::Attachment-&gt;get($attachid);
-
</del><span class="cx">         # Make sure the attachment exists in the database.
</span><del>-        ThrowUserError('invalid_attach_id', $vars) unless $attachment;
</del><ins>+        my $attachment = new Bugzilla::Attachment($attachid)
+          || ThrowUserError('invalid_attach_id', $vars);
</ins><span class="cx"> 
</span><span class="cx">         # Check that the user can view and edit this attachment.
</span><del>-        $attachment-&gt;validate_can_edit($bug-&gt;product_id);
</del><ins>+        $attachment-&gt;validate_can_edit($bug-&gt;product_id)
+          || ThrowUserError('illegal_attachment_edit', { attach_id =&gt; $attachment-&gt;id });
</ins><span class="cx"> 
</span><span class="cx">         $vars-&gt;{'description'} = $attachment-&gt;description;
</span><span class="cx"> 
</span><span class="lines">@@ -731,203 +731,150 @@
</span><span class="cx">             ThrowCodeError('mismatched_bug_ids_on_obsolete', $vars);
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if ($attachment-&gt;isobsolete) {
-          ThrowCodeError('attachment_already_obsolete', $vars);
-        }
</del><ins>+        next if $attachment-&gt;isobsolete;
</ins><span class="cx"> 
</span><span class="cx">         push(@obsolete_attachments, $attachment);
</span><span class="cx">     }
</span><span class="cx">     return @obsolete_attachments;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+###############################
+####     Constructors     #####
+###############################
</ins><span class="cx"> 
</span><span class="cx"> =pod
</span><span class="cx"> 
</span><del>-=item C&lt;insert_attachment_for_bug($throw_error, $bug, $user, $timestamp, $hr_vars)&gt;
</del><ins>+=item C&lt;create&gt;
</ins><span class="cx"> 
</span><del>-Description: inserts an attachment from CGI input for the given bug.
</del><ins>+Description: inserts an attachment into the given bug.
</ins><span class="cx"> 
</span><del>-Params:     C&lt;$bug&gt; - Bugzilla::Bug object - the bug for which to insert
</del><ins>+Params:     takes a hashref with the following keys:
+            C&lt;bug&gt; - Bugzilla::Bug object - the bug for which to insert
</ins><span class="cx">             the attachment.
</span><del>-            C&lt;$user&gt; - Bugzilla::User object - the user we're inserting an
-            attachment for.
-            C&lt;$timestamp&gt; - scalar - timestamp of the insert as returned
-            by SELECT NOW().
-            C&lt;$hr_vars&gt; - hash reference - reference to a hash of template
-            variables.
</del><ins>+            C&lt;data&gt; - Either a filehandle pointing to the content of the
+            attachment, or the content of the attachment itself.
+            C&lt;description&gt; - string - describe what the attachment is about.
+            C&lt;filename&gt; - string - the name of the attachment (used by the
+            browser when downloading it). If the attachment is a URL, this
+            parameter has no effect.
+            C&lt;mimetype&gt; - string - a valid MIME type.
+            C&lt;creation_ts&gt; - string (optional) - timestamp of the insert
+            as returned by SELECT LOCALTIMESTAMP(0).
+            C&lt;ispatch&gt; - boolean (optional, default false) - true if the
+            attachment is a patch.
+            C&lt;isprivate&gt; - boolean (optional, default false) - true if
+            the attachment is private.
</ins><span class="cx"> 
</span><del>-Returns:    the ID of the new attachment.
</del><ins>+Returns:    The new attachment object.
</ins><span class="cx"> 
</span><span class="cx"> =cut
</span><span class="cx"> 
</span><del>-sub insert_attachment_for_bug {
-    my ($class, $throw_error, $bug, $user, $timestamp, $hr_vars) = @_;
-
-    my $cgi = Bugzilla-&gt;cgi;
</del><ins>+sub create {
+    my $class = shift;
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><del>-    my $attachurl = $cgi-&gt;param('attachurl') || '';
-    my $data;
-    my $filename;
-    my $contenttype;
-    my $isurl;
-    $class-&gt;validate_is_patch($throw_error) || return;
-    $class-&gt;validate_description($throw_error) || return;
</del><span class="cx"> 
</span><del>-    if (Bugzilla-&gt;params-&gt;{'allow_attach_url'}
-        &amp;&amp; ($attachurl =~ /^(http|https|ftp):\/\/\S+/)
-        &amp;&amp; !defined $cgi-&gt;upload('data'))
-    {
-        $filename = '';
-        $data = $attachurl;
-        $isurl = 1;
-        $contenttype = 'text/plain';
-        $cgi-&gt;param('ispatch', 0);
-        $cgi-&gt;delete('bigfile');
-    }
-    else {
-        $filename = _validate_filename($throw_error) || return;
-        # need to validate content type before data as
-        # we now check the content type for image/bmp in _validate_data()
-        unless ($cgi-&gt;param('ispatch')) {
-            $class-&gt;validate_content_type($throw_error) || return;
</del><ins>+    $class-&gt;check_required_create_fields(@_);
+    my $params = $class-&gt;run_create_validators(@_);
</ins><span class="cx"> 
</span><del>-            # Set the ispatch flag to 1 if we're set to autodetect
-            # and the content type is text/x-diff or text/x-patch
-            if ($cgi-&gt;param('contenttypemethod') eq 'autodetect'
-                &amp;&amp; $cgi-&gt;param('contenttype') =~ m{text/x-(?:diff|patch)})
-            {
-                $cgi-&gt;param('ispatch', 1);
-                $cgi-&gt;param('contenttype', 'text/plain');
-            }
-        }
-        $data = _validate_data($throw_error, $hr_vars);
-        # If the attachment is stored locally, $data eq ''.
-        # If an error is thrown, $data eq '0'.
-        ($data ne '0') || return;
-        $contenttype = $cgi-&gt;param('contenttype');
</del><ins>+    # Extract everything which is not a valid column name.
+    my $bug = delete $params-&gt;{bug};
+    $params-&gt;{bug_id} = $bug-&gt;id;
+    my $data = delete $params-&gt;{data};
+    my $size = delete $params-&gt;{filesize};
</ins><span class="cx"> 
</span><del>-        # These are inserted using placeholders so no need to panic
-        trick_taint($filename);
-        trick_taint($contenttype);
-        $isurl = 0;
-    }
</del><ins>+    my $attachment = $class-&gt;insert_create_data($params);
+    my $attachid = $attachment-&gt;id;
</ins><span class="cx"> 
</span><del>-    # Check attachments the user tries to mark as obsolete.
-    my @obsolete_attachments;
-    if ($cgi-&gt;param('obsolete')) {
-        @obsolete_attachments = $class-&gt;validate_obsolete($bug);
</del><ins>+    # The file is too large to be stored in the DB, so we store it locally.
+    if ($size &gt; Bugzilla-&gt;params-&gt;{'maxattachmentsize'} * 1024) {
+        my $attachdir = bz_locations()-&gt;{'attachdir'};
+        my $hash = ($attachid % 100) + 100;
+        $hash =~ s/.*(\d\d)$/group.$1/;
+        mkdir &quot;$attachdir/$hash&quot;, 0770;
+        chmod 0770, &quot;$attachdir/$hash&quot;;
+        if (ref $data) {
+            copy($data, &quot;$attachdir/$hash/attachment.$attachid&quot;);
+            close $data;
+        }
+        else {
+            open(AH, '&gt;', &quot;$attachdir/$hash/attachment.$attachid&quot;);
+            binmode AH;
+            print AH $data;
+            close AH;
+        }
+        $data = ''; # Will be stored in the DB.
</ins><span class="cx">     }
</span><del>-
-    # The order of these function calls is important, as Flag::validate
-    # assumes User::match_field has ensured that the
-    # values in the requestee fields are legitimate user email addresses.
-    my $match_status = Bugzilla::User::match_field($cgi, {
-        '^requestee(_type)?-(\d+)$' =&gt; { 'type' =&gt; 'multi' },
-    }, MATCH_SKIP_CONFIRM);
-
-    $hr_vars-&gt;{'match_field'} = 'requestee';
-    if ($match_status == USER_MATCH_FAILED) {
-        $hr_vars-&gt;{'message'} = 'user_match_failed';
</del><ins>+    # If we have a filehandle, we need its content to store it in the DB.
+    elsif (ref $data) {
+        local $/;
+        # Store the content in a temp variable while we close the FH.
+        my $tmp = &lt;$data&gt;;
+        close $data;
+        $data = $tmp;
</ins><span class="cx">     }
</span><del>-    elsif ($match_status == USER_MATCH_MULTIPLE) {
-        $hr_vars-&gt;{'message'} = 'user_match_multiple';
-    }
</del><span class="cx"> 
</span><del>-    # Escape characters in strings that will be used in SQL statements.
-    my $description = $cgi-&gt;param('description');
-    trick_taint($description);
-    my $isprivate = $cgi-&gt;param('isprivate') ? 1 : 0;
</del><ins>+    my $sth = $dbh-&gt;prepare(&quot;INSERT INTO attach_data
+                             (id, thedata) VALUES ($attachid, ?)&quot;);
</ins><span class="cx"> 
</span><del>-    # Insert the attachment into the database.
-    my $sth = $dbh-&gt;do(
-        &quot;INSERT INTO attachments
-            (bug_id, creation_ts, modification_time, filename, description,
-             mimetype, ispatch, isurl, isprivate, submitter_id)
-         VALUES (?,?,?,?,?,?,?,?,?,?)&quot;, undef, ($bug-&gt;bug_id, $timestamp, $timestamp,
-              $filename, $description, $contenttype, $cgi-&gt;param('ispatch'),
-              $isurl, $isprivate, $user-&gt;id));
-    # Retrieve the ID of the newly created attachment record.
-    my $attachid = $dbh-&gt;bz_last_key('attachments', 'attach_id');
-
-    # We only use $data here in this INSERT with a placeholder,
-    # so it's safe.
-    $sth = $dbh-&gt;prepare(&quot;INSERT INTO attach_data
-                         (id, thedata) VALUES ($attachid, ?)&quot;);
</del><span class="cx">     trick_taint($data);
</span><span class="cx">     $sth-&gt;bind_param(1, $data, $dbh-&gt;BLOB_TYPE);
</span><span class="cx">     $sth-&gt;execute();
</span><span class="cx"> 
</span><del>-    # If the file is to be stored locally, stream the file from the web server
-    # to the local file without reading it into a local variable.
-    if ($cgi-&gt;param('bigfile')) {
-        my $attachdir = bz_locations()-&gt;{'attachdir'};
-        my $fh = $cgi-&gt;upload('data');
-        my $hash = ($attachid % 100) + 100;
-        $hash =~ s/.*(\d\d)$/group.$1/;
-        mkdir &quot;$attachdir/$hash&quot;, 0770;
-        chmod 0770, &quot;$attachdir/$hash&quot;;
-        open(AH, &quot;&gt;$attachdir/$hash/attachment.$attachid&quot;);
-        binmode AH;
-        my $sizecount = 0;
-        my $limit = (Bugzilla-&gt;params-&gt;{&quot;maxlocalattachment&quot;} * 1048576);
-        while (&lt;$fh&gt;) {
-            print AH $_;
-            $sizecount += length($_);
-            if ($sizecount &gt; $limit) {
-                close AH;
-                close $fh;
-                unlink &quot;$attachdir/$hash/attachment.$attachid&quot;;
-                $throw_error ? ThrowUserError(&quot;local_file_too_large&quot;) : return;
-            }
-        }
-        close AH;
-        close $fh;
-    }
</del><ins>+    $attachment-&gt;{bug} = $bug;
</ins><span class="cx"> 
</span><del>-    # Make existing attachments obsolete.
-    my $fieldid = get_field_id('attachments.isobsolete');
</del><ins>+    # Return the new attachment object.
+    return $attachment;
+}
</ins><span class="cx"> 
</span><del>-    foreach my $obsolete_attachment (@obsolete_attachments) {
-        # If the obsolete attachment has request flags, cancel them.
-        # This call must be done before updating the 'attachments' table.
-        Bugzilla::Flag-&gt;CancelRequests($bug, $obsolete_attachment, $timestamp);
</del><ins>+sub run_create_validators {
+    my ($class, $params) = @_;
</ins><span class="cx"> 
</span><del>-        $dbh-&gt;do('UPDATE attachments SET isobsolete = 1, modification_time = ?
-                  WHERE attach_id = ?',
-                 undef, ($timestamp, $obsolete_attachment-&gt;id));
</del><ins>+    # Let's validate the attachment content first as it may
+    # alter some other attachment attributes.
+    $params-&gt;{data} = $class-&gt;_check_data($params);
+    $params = $class-&gt;SUPER::run_create_validators($params);
</ins><span class="cx"> 
</span><del>-        $dbh-&gt;do('INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when,
-                                             fieldid, removed, added)
-                       VALUES (?,?,?,?,?,?,?)',
-                  undef, ($bug-&gt;bug_id, $obsolete_attachment-&gt;id, $user-&gt;id,
-                          $timestamp, $fieldid, 0, 1));
</del><ins>+    $params-&gt;{creation_ts} ||= Bugzilla-&gt;dbh-&gt;selectrow_array('SELECT LOCALTIMESTAMP(0)');
+    $params-&gt;{modification_time} = $params-&gt;{creation_ts};
+    $params-&gt;{submitter_id} = Bugzilla-&gt;user-&gt;id || ThrowCodeError('invalid_user');
+
+    return $params;
+}
+
+sub update {
+    my $self = shift;
+    my $dbh = Bugzilla-&gt;dbh;
+    my $user = Bugzilla-&gt;user;
+    my $timestamp = shift || $dbh-&gt;selectrow_array('SELECT LOCALTIMESTAMP(0)');
+
+    my ($changes, $old_self) = $self-&gt;SUPER::update(@_);
+
+    my ($removed, $added) = Bugzilla::Flag-&gt;update_flags($self, $old_self, $timestamp);
+    if ($removed || $added) {
+        $changes-&gt;{'flagtypes.name'} = [$removed, $added];
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    my $attachment = Bugzilla::Attachment-&gt;get($attachid);
</del><ins>+    # Record changes in the activity table.
+    my $sth = $dbh-&gt;prepare('INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when,
+                                                        fieldid, removed, added)
+                             VALUES (?, ?, ?, ?, ?, ?, ?)');
</ins><span class="cx"> 
</span><del>-    # 1. Add flags, if any. To avoid dying if something goes wrong
-    # while processing flags, we will eval() flag validation.
-    # This requires errors to die().
-    # XXX: this can go away as soon as flag validation is able to
-    #      fail without dying.
-    #
-    # 2. Flag::validate() should not detect any reference to existing flags
-    # when creating a new attachment. Setting the third param to -1 will
-    # force this function to check this point.
-    my $error_mode_cache = Bugzilla-&gt;error_mode;
-    Bugzilla-&gt;error_mode(ERROR_MODE_DIE);
-    eval {
-        Bugzilla::Flag::validate($bug-&gt;bug_id, -1, SKIP_REQUESTEE_ON_ERROR);
-        Bugzilla::Flag-&gt;process($bug, $attachment, $timestamp, $hr_vars);
-    };
-    Bugzilla-&gt;error_mode($error_mode_cache);
-    if ($@) {
-        $hr_vars-&gt;{'message'} = 'flag_creation_failed';
-        $hr_vars-&gt;{'flag_creation_error'} = $@;
</del><ins>+    foreach my $field (keys %$changes) {
+        my $change = $changes-&gt;{$field};
+        $field = &quot;attachments.$field&quot; unless $field eq &quot;flagtypes.name&quot;;
+        my $fieldid = get_field_id($field);
+        $sth-&gt;execute($self-&gt;bug_id, $self-&gt;id, $user-&gt;id, $timestamp,
+                      $fieldid, $change-&gt;[0], $change-&gt;[1]);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    # Return the new attachment object.
-    return $attachment;
</del><ins>+    if (scalar(keys %$changes)) {
+      $dbh-&gt;do('UPDATE attachments SET modification_time = ? WHERE attach_id = ?',
+               undef, ($timestamp, $self-&gt;id));
+      $dbh-&gt;do('UPDATE bugs SET delta_ts = ? WHERE bug_id = ?',
+               undef, ($timestamp, $self-&gt;bug_id));
+    }
+
+    return $changes;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> =pod
</span><span class="lines">@@ -951,9 +898,61 @@
</span><span class="cx">     $dbh-&gt;bz_start_transaction();
</span><span class="cx">     $dbh-&gt;do('DELETE FROM flags WHERE attach_id = ?', undef, $self-&gt;id);
</span><span class="cx">     $dbh-&gt;do('DELETE FROM attach_data WHERE id = ?', undef, $self-&gt;id);
</span><del>-    $dbh-&gt;do('UPDATE attachments SET mimetype = ?, ispatch = ?, isurl = ?, isobsolete = ?
-              WHERE attach_id = ?', undef, ('text/plain', 0, 0, 1, $self-&gt;id));
</del><ins>+    $dbh-&gt;do('UPDATE attachments SET mimetype = ?, ispatch = ?, isobsolete = ?
+              WHERE attach_id = ?', undef, ('text/plain', 0, 1, $self-&gt;id));
</ins><span class="cx">     $dbh-&gt;bz_commit_transaction();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+###############################
+####       Helpers        #####
+###############################
+
+# Extract the content type from the attachment form.
+sub get_content_type {
+    my $cgi = Bugzilla-&gt;cgi;
+
+    return 'text/plain' if ($cgi-&gt;param('ispatch') || $cgi-&gt;param('attach_text'));
+
+    my $content_type;
+    if (!defined $cgi-&gt;param('contenttypemethod')) {
+        ThrowUserError(&quot;missing_content_type_method&quot;);
+    }
+    elsif ($cgi-&gt;param('contenttypemethod') eq 'autodetect') {
+        defined $cgi-&gt;upload('data') || ThrowUserError('file_not_specified');
+        # The user asked us to auto-detect the content type, so use the type
+        # specified in the HTTP request headers.
+        $content_type =
+            $cgi-&gt;uploadInfo($cgi-&gt;param('data'))-&gt;{'Content-Type'};
+        $content_type || ThrowUserError(&quot;missing_content_type&quot;);
+
+        # Set the ispatch flag to 1 if the content type
+        # is text/x-diff or text/x-patch
+        if ($content_type =~ m{text/x-(?:diff|patch)}) {
+            $cgi-&gt;param('ispatch', 1);
+            $content_type = 'text/plain';
+        }
+
+        # Internet Explorer sends image/x-png for PNG images,
+        # so convert that to image/png to match other browsers.
+        if ($content_type eq 'image/x-png') {
+            $content_type = 'image/png';
+        }
+    }
+    elsif ($cgi-&gt;param('contenttypemethod') eq 'list') {
+        # The user selected a content type from the list, so use their
+        # selection.
+        $content_type = $cgi-&gt;param('contenttypeselection');
+    }
+    elsif ($cgi-&gt;param('contenttypemethod') eq 'manual') {
+        # The user entered a content type manually, so use their entry.
+        $content_type = $cgi-&gt;param('contenttypeentry');
+    }
+    else {
+        ThrowCodeError(&quot;illegal_content_type_method&quot;,
+                       { contenttypemethod =&gt; $cgi-&gt;param('contenttypemethod') });
+    }
+    return $content_type;
+}
+
+
</ins><span class="cx"> 1;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaAuthLoginCGIpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Login/CGI.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Login/CGI.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Login/CGI.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -40,13 +40,11 @@
</span><span class="cx"> 
</span><span class="cx"> sub get_login_info {
</span><span class="cx">     my ($self) = @_;
</span><del>-    my $cgi = Bugzilla-&gt;cgi;
</del><ins>+    my $params = Bugzilla-&gt;input_params;
</ins><span class="cx"> 
</span><del>-    my $username = trim($cgi-&gt;param(&quot;Bugzilla_login&quot;));
-    my $password = $cgi-&gt;param(&quot;Bugzilla_password&quot;);
</del><ins>+    my $username = trim(delete $params-&gt;{&quot;Bugzilla_login&quot;});
+    my $password = delete $params-&gt;{&quot;Bugzilla_password&quot;};
</ins><span class="cx"> 
</span><del>-    $cgi-&gt;delete('Bugzilla_login', 'Bugzilla_password');
-
</del><span class="cx">     if (!defined $username || !defined $password) {
</span><span class="cx">         return { failure =&gt; AUTH_NODATA };
</span><span class="cx">     }
</span><span class="lines">@@ -59,23 +57,10 @@
</span><span class="cx">     my $cgi = Bugzilla-&gt;cgi;
</span><span class="cx">     my $template = Bugzilla-&gt;template;
</span><span class="cx"> 
</span><del>-    if (Bugzilla-&gt;error_mode == Bugzilla::Constants::ERROR_MODE_DIE_SOAP_FAULT) {
-        die SOAP::Fault
-            -&gt;faultcode(ERROR_AUTH_NODATA)
-            -&gt;faultstring('Login Required');
</del><ins>+    if (Bugzilla-&gt;usage_mode != USAGE_MODE_BROWSER) {
+        ThrowUserError('login_required');
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    # If system is not configured to never require SSL connections
-    # we want to always redirect to SSL since passing usernames and
-    # passwords over an unprotected connection is a bad idea. If we 
-    # get here then a login form will be provided to the user so we
-    # want this to be protected if possible.
-    if ($cgi-&gt;protocol ne 'https' &amp;&amp; Bugzilla-&gt;params-&gt;{'sslbase'} ne ''
-        &amp;&amp; Bugzilla-&gt;params-&gt;{'ssl'} ne 'never')
-    {
-        $cgi-&gt;require_https(Bugzilla-&gt;params-&gt;{'sslbase'});
-    }
-
</del><span class="cx">     print $cgi-&gt;header();
</span><span class="cx">     $template-&gt;process(&quot;account/auth/login.html.tmpl&quot;,
</span><span class="cx">                        { 'target' =&gt; $cgi-&gt;url(-relative=&gt;1) }) 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaAuthLoginCookiepm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Login/Cookie.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Login/Cookie.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Login/Cookie.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -27,6 +27,7 @@
</span><span class="cx"> use constant requires_persistence  =&gt; 0;
</span><span class="cx"> use constant requires_verification =&gt; 0;
</span><span class="cx"> use constant can_login =&gt; 0;
</span><ins>+use constant is_automatic =&gt; 1;
</ins><span class="cx"> 
</span><span class="cx"> # Note that Cookie never consults the Verifier, it always assumes
</span><span class="cx"> # it has a valid DB account or it fails.
</span><span class="lines">@@ -35,8 +36,7 @@
</span><span class="cx">     my $cgi = Bugzilla-&gt;cgi;
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx"> 
</span><del>-    my $ip_addr      = $cgi-&gt;remote_addr();
-    my $net_addr     = get_netaddr($ip_addr);
</del><ins>+    my $ip_addr      = remote_ip();
</ins><span class="cx">     my $login_cookie = $cgi-&gt;cookie(&quot;Bugzilla_logincookie&quot;);
</span><span class="cx">     my $user_id      = $cgi-&gt;cookie(&quot;Bugzilla_login&quot;);
</span><span class="cx"> 
</span><span class="lines">@@ -60,24 +60,16 @@
</span><span class="cx">         trick_taint($login_cookie);
</span><span class="cx">         detaint_natural($user_id);
</span><span class="cx"> 
</span><del>-        my $query = &quot;SELECT userid
-                       FROM logincookies
-                      WHERE logincookies.cookie = ?
-                            AND logincookies.userid = ?
-                            AND (logincookies.ipaddr = ?&quot;;
</del><ins>+        my $is_valid =
+          $dbh-&gt;selectrow_array('SELECT 1
+                                   FROM logincookies
+                                  WHERE cookie = ?
+                                        AND userid = ?
+                                        AND (ipaddr = ? OR ipaddr IS NULL)',
+                                 undef, ($login_cookie, $user_id, $ip_addr));
</ins><span class="cx"> 
</span><del>-        # If we have a network block that's allowed to use this cookie,
-        # as opposed to just a single IP.
-        my @params = ($login_cookie, $user_id, $ip_addr);
-        if (defined $net_addr) {
-            trick_taint($net_addr);
-            $query .= &quot; OR logincookies.ipaddr = ?&quot;;
-            push(@params, $net_addr);
-        }
-        $query .= &quot;)&quot;;
-
</del><span class="cx">         # If the cookie is valid, return a valid username.
</span><del>-        if ($dbh-&gt;selectrow_array($query, undef, @params)) {
</del><ins>+        if ($is_valid) {
</ins><span class="cx">             # If we logged in successfully, then update the lastused 
</span><span class="cx">             # time on the login cookie
</span><span class="cx">             $dbh-&gt;do(&quot;UPDATE logincookies SET lastused = NOW() 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaAuthLoginEnvpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Login/Env.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Login/Env.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Login/Env.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -29,7 +29,10 @@
</span><span class="cx"> 
</span><span class="cx"> use constant can_logout =&gt; 0;
</span><span class="cx"> use constant can_login  =&gt; 0;
</span><ins>+use constant requires_persistence  =&gt; 0;
</ins><span class="cx"> use constant requires_verification =&gt; 0;
</span><ins>+use constant is_automatic =&gt; 1;
+use constant extern_id_used =&gt; 1;
</ins><span class="cx"> 
</span><span class="cx"> sub get_login_info {
</span><span class="cx">     my ($self) = @_;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaAuthLoginStackpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Login/Stack.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Login/Stack.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Login/Stack.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -26,16 +26,26 @@
</span><span class="cx">     _stack
</span><span class="cx">     successful
</span><span class="cx"> );
</span><ins>+use Hash::Util qw(lock_keys);
+use Bugzilla::Hook;
+use Bugzilla::Constants;
+use List::MoreUtils qw(any);
</ins><span class="cx"> 
</span><span class="cx"> sub new {
</span><span class="cx">     my $class = shift;
</span><span class="cx">     my $self = $class-&gt;SUPER::new(@_);
</span><span class="cx">     my $list = shift;
</span><ins>+    my %methods = map { $_ =&gt; &quot;Bugzilla/Auth/Login/$_.pm&quot; } split(',', $list);
+    lock_keys(%methods);
+    Bugzilla::Hook::process('auth_login_methods', { modules =&gt; \%methods });
+
</ins><span class="cx">     $self-&gt;{_stack} = [];
</span><span class="cx">     foreach my $login_method (split(',', $list)) {
</span><del>-        require &quot;Bugzilla/Auth/Login/${login_method}.pm&quot;;
-        push(@{$self-&gt;{_stack}}, 
-             &quot;Bugzilla::Auth::Login::$login_method&quot;-&gt;new(@_));
</del><ins>+        my $module = $methods{$login_method};
+        require $module;
+        $module =~ s|/|::|g;
+        $module =~ s/.pm$//;
+        push(@{$self-&gt;{_stack}}, $module-&gt;new(@_));
</ins><span class="cx">     }
</span><span class="cx">     return $self;
</span><span class="cx"> }
</span><span class="lines">@@ -44,10 +54,20 @@
</span><span class="cx">     my $self = shift;
</span><span class="cx">     my $result;
</span><span class="cx">     foreach my $object (@{$self-&gt;{_stack}}) {
</span><ins>+        # See Bugzilla::WebService::Server::JSONRPC for where and why
+        # auth_no_automatic_login is used.
+        if (Bugzilla-&gt;request_cache-&gt;{auth_no_automatic_login}) {
+            next if $object-&gt;is_automatic;
+        }
</ins><span class="cx">         $result = $object-&gt;get_login_info(@_);
</span><span class="cx">         $self-&gt;{successful} = $object;
</span><del>-        last if !$result-&gt;{failure};
-        # So that if none of them succeed, it's undef.
</del><ins>+        
+        # We only carry on down the stack if this method denied all knowledge.
+        last unless ($result-&gt;{failure}
+                    &amp;&amp; ($result-&gt;{failure} eq AUTH_NODATA 
+                       || $result-&gt;{failure} eq AUTH_NO_SUCH_USER));
+        
+        # If none of the methods succeed, it's undef.
</ins><span class="cx">         $self-&gt;{successful} = undef;
</span><span class="cx">     }
</span><span class="cx">     return $result;
</span><span class="lines">@@ -84,4 +104,9 @@
</span><span class="cx">     return 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub extern_id_used {
+    my ($self) = @_;
+    return any { $_-&gt;extern_id_used } @{ $self-&gt;{_stack} };
+}
+
</ins><span class="cx"> 1;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaAuthLoginpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Login.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Login.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Login.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -27,6 +27,8 @@
</span><span class="cx"> use constant requires_persistence  =&gt; 1;
</span><span class="cx"> use constant requires_verification =&gt; 1;
</span><span class="cx"> use constant user_can_create_account =&gt; 0;
</span><ins>+use constant is_automatic =&gt; 0;
+use constant extern_id_used =&gt; 0; 
</ins><span class="cx"> 
</span><span class="cx"> sub new {
</span><span class="cx">     my ($class) = @_;
</span><span class="lines">@@ -122,4 +124,20 @@
</span><span class="cx"> Whether or not users can create accounts, if this login method is
</span><span class="cx"> currently being used by the system. Defaults to C&lt;false&gt;.
</span><span class="cx"> 
</span><ins>+=item C&lt;is_automatic&gt;
+
+True if this login method requires no interaction from the user within
+Bugzilla. (For example, C&lt;Env&gt; auth is &quot;automatic&quot; because the webserver
+just passes us an environment variable on most page requests, and does not
+ask the user for authentication information directly in Bugzilla.) Defaults
+to C&lt;false&gt;.
+
+=item C&lt;extern_id_used&gt;
+
+Whether or not this login method uses the extern_id field. If
+used, users with editusers permission will be be allowed to
+edit the extern_id for all users.
+
+The default value is C&lt;0&gt;.
+
</ins><span class="cx"> =back
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaAuthPersistCookiepm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Persist/Cookie.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Persist/Cookie.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Persist/Cookie.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -48,18 +48,16 @@
</span><span class="cx">     my ($self, $user) = @_;
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx">     my $cgi = Bugzilla-&gt;cgi;
</span><ins>+    my $input_params = Bugzilla-&gt;input_params;
</ins><span class="cx"> 
</span><del>-    my $ip_addr = $cgi-&gt;remote_addr;
-    unless ($cgi-&gt;param('Bugzilla_restrictlogin') ||
-            Bugzilla-&gt;params-&gt;{'loginnetmask'} == 32) 
-    {
-        $ip_addr = get_netaddr($ip_addr);
</del><ins>+    my $ip_addr;
+    if ($input_params-&gt;{'Bugzilla_restrictlogin'}) {
+        $ip_addr = remote_ip();
+        # The IP address is valid, at least for comparing with itself in a
+        # subsequent login
+        trick_taint($ip_addr);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    # The IP address is valid, at least for comparing with itself in a
-    # subsequent login
-    trick_taint($ip_addr);
-
</del><span class="cx">     $dbh-&gt;bz_start_transaction();
</span><span class="cx"> 
</span><span class="cx">     my $login_cookie = 
</span><span class="lines">@@ -71,8 +69,9 @@
</span><span class="cx"> 
</span><span class="cx">     # Issuing a new cookie is a good time to clean up the old
</span><span class="cx">     # cookies.
</span><del>-    $dbh-&gt;do(&quot;DELETE FROM logincookies WHERE lastused &lt; LOCALTIMESTAMP(0) - &quot;
-             . $dbh-&gt;sql_interval(MAX_LOGINCOOKIE_AGE, 'DAY'));
</del><ins>+    $dbh-&gt;do(&quot;DELETE FROM logincookies WHERE lastused &lt; &quot;
+             . $dbh-&gt;sql_date_math('LOCALTIMESTAMP(0)', '-',
+                                   MAX_LOGINCOOKIE_AGE, 'DAY'));
</ins><span class="cx"> 
</span><span class="cx">     $dbh-&gt;bz_commit_transaction();
</span><span class="cx"> 
</span><span class="lines">@@ -83,17 +82,15 @@
</span><span class="cx">     # or admin didn't forbid it and user told to remember.
</span><span class="cx">     if ( Bugzilla-&gt;params-&gt;{'rememberlogin'} eq 'on' ||
</span><span class="cx">          (Bugzilla-&gt;params-&gt;{'rememberlogin'} ne 'off' &amp;&amp;
</span><del>-          $cgi-&gt;param('Bugzilla_remember') &amp;&amp;
-          $cgi-&gt;param('Bugzilla_remember') eq 'on') ) 
</del><ins>+          $input_params-&gt;{'Bugzilla_remember'} &amp;&amp;
+          $input_params-&gt;{'Bugzilla_remember'} eq 'on') ) 
</ins><span class="cx">     {
</span><span class="cx">         # Not a session cookie, so set an infinite expiry
</span><span class="cx">         $cookieargs{'-expires'} = 'Fri, 01-Jan-2038 00:00:00 GMT';
</span><span class="cx">     }
</span><del>-    if (Bugzilla-&gt;params-&gt;{'ssl'} ne 'never'
-        &amp;&amp; Bugzilla-&gt;params-&gt;{'sslbase'} ne '')
-    {
-        # Bugzilla-&gt;login will automatically redirect to https://,
-        # so it's safe to turn on the 'secure' bit.
</del><ins>+    if (Bugzilla-&gt;params-&gt;{'ssl_redirect'}) {
+        # Make these cookies only be sent to us by the browser during 
+        # HTTPS sessions, if we're using SSL.
</ins><span class="cx">         $cookieargs{'-secure'} = 1;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -161,6 +158,7 @@
</span><span class="cx">     my $cgi = Bugzilla-&gt;cgi;
</span><span class="cx">     $cgi-&gt;remove_cookie('Bugzilla_login');
</span><span class="cx">     $cgi-&gt;remove_cookie('Bugzilla_logincookie');
</span><ins>+    $cgi-&gt;remove_cookie('sudo');
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> 1;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaAuthVerifyDBpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Verify/DB.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Verify/DB.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Verify/DB.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -41,34 +41,59 @@
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx"> 
</span><span class="cx">     my $username = $login_data-&gt;{username};
</span><del>-    my $user_id  = login_to_id($username);
</del><ins>+    my $user = new Bugzilla::User({ name =&gt; $username });
</ins><span class="cx"> 
</span><del>-    return { failure =&gt; AUTH_NO_SUCH_USER } unless $user_id;
</del><ins>+    return { failure =&gt; AUTH_NO_SUCH_USER } unless $user;
</ins><span class="cx"> 
</span><del>-    $login_data-&gt;{bz_username} = $username;
-    my $password = $login_data-&gt;{password};
</del><ins>+    $login_data-&gt;{user} = $user;
+    $login_data-&gt;{bz_username} = $user-&gt;login;
</ins><span class="cx"> 
</span><del>-    trick_taint($username);
-    my ($real_password_crypted) = $dbh-&gt;selectrow_array(
-        &quot;SELECT cryptpassword FROM profiles WHERE userid = ?&quot;,
-        undef, $user_id);
-
-    # Wide characters cause crypt to die
-    if (Bugzilla-&gt;params-&gt;{'utf8'}) {
-        utf8::encode($password) if utf8::is_utf8($password);
</del><ins>+    if ($user-&gt;account_is_locked_out) {
+        return { failure =&gt; AUTH_LOCKOUT, user =&gt; $user };
</ins><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    my $password = $login_data-&gt;{password};
+    my $real_password_crypted = $user-&gt;cryptpassword;
+
</ins><span class="cx">     # Using the internal crypted password as the salt,
</span><span class="cx">     # crypt the password the user entered.
</span><del>-    my $entered_password_crypted = crypt($password, $real_password_crypted);

-    return { failure =&gt; AUTH_LOGINFAILED }
-        if $entered_password_crypted ne $real_password_crypted;
</del><ins>+    my $entered_password_crypted = bz_crypt($password, $real_password_crypted);
</ins><span class="cx"> 
</span><ins>+    if ($entered_password_crypted ne $real_password_crypted) {
+        # Record the login failure
+        $user-&gt;note_login_failure();
+
+        # Immediately check if we are locked out
+        if ($user-&gt;account_is_locked_out) {
+            return { failure =&gt; AUTH_LOCKOUT, user =&gt; $user,
+                     just_locked_out =&gt; 1 };
+        }
+
+        return { failure =&gt; AUTH_LOGINFAILED,
+                 failure_count =&gt; scalar(@{ $user-&gt;account_ip_login_failures }),
+               };
+    } 
+
+    # Force the user to type a longer password if it's too short.
+    if (length($password) &lt; USER_PASSWORD_MIN_LENGTH) {
+        return { failure =&gt; AUTH_ERROR, user_error =&gt; 'password_current_too_short',
+                 details =&gt; { locked_user =&gt; $user } };
+    }
+
</ins><span class="cx">     # The user's credentials are okay, so delete any outstanding
</span><del>-    # password tokens they may have generated.
-    Bugzilla::Token::DeletePasswordTokens($user_id, &quot;user_logged_in&quot;);
</del><ins>+    # password tokens or login failures they may have generated.
+    Bugzilla::Token::DeletePasswordTokens($user-&gt;id, &quot;user_logged_in&quot;);
+    $user-&gt;clear_login_failures();
</ins><span class="cx"> 
</span><ins>+    # If their old password was using crypt() or some different hash
+    # than we're using now, convert the stored password to using
+    # whatever hashing system we're using now.
+    my $current_algorithm = PASSWORD_DIGEST_ALGORITHM;
+    if ($real_password_crypted !~ /{\Q$current_algorithm\E}$/) {
+        $user-&gt;set_password($password);
+        $user-&gt;update();
+    }
+
</ins><span class="cx">     return $login_data;
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaAuthVerifyLDAPpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Verify/LDAP.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Verify/LDAP.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Verify/LDAP.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -56,7 +56,7 @@
</span><span class="cx">     # just appending the Base DN to the uid isn't sufficient to get the
</span><span class="cx">     # user's DN.  For servers which don't work this way, there will still
</span><span class="cx">     # be no harm done.
</span><del>-    $self-&gt;_bind_ldap_anonymously();
</del><ins>+    $self-&gt;_bind_ldap_for_search();
</ins><span class="cx"> 
</span><span class="cx">     # Now, we verify that the user exists, and get a LDAP Distinguished
</span><span class="cx">     # Name for the user.
</span><span class="lines">@@ -76,12 +76,35 @@
</span><span class="cx">     return { failure =&gt; AUTH_LOGINFAILED } if $pw_result-&gt;code;
</span><span class="cx"> 
</span><span class="cx">     # And now we fill in the user's details.
</span><ins>+
+    # First try the search as the (already bound) user in question.
+    my $user_entry;
+    my $error_string;
</ins><span class="cx">     my $detail_result = $self-&gt;ldap-&gt;search(_bz_search_params($username));
</span><ins>+    if ($detail_result-&gt;code) {
+        # Stash away the original error, just in case
+        $error_string = $detail_result-&gt;error;
+    } else {
+        $user_entry = $detail_result-&gt;shift_entry;
+    }
+
+    # If that failed (either because the search failed, or returned no
+    # results) then try re-binding as the initial search user, but only
+    # if the LDAPbinddn parameter is set.
+    if (!$user_entry &amp;&amp; Bugzilla-&gt;params-&gt;{&quot;LDAPbinddn&quot;}) {
+        $self-&gt;_bind_ldap_for_search();
+
+        $detail_result = $self-&gt;ldap-&gt;search(_bz_search_params($username));
+        if (!$detail_result-&gt;code) {
+            $user_entry = $detail_result-&gt;shift_entry;
+        }
+    }
+
+    # If we *still* don't have anything in $user_entry then give up.
</ins><span class="cx">     return { failure =&gt; AUTH_ERROR, error =&gt; &quot;ldap_search_error&quot;,
</span><del>-             details =&gt; {errstr =&gt; $detail_result-&gt;error, username =&gt; $username}
-    } if $detail_result-&gt;code;
</del><ins>+             details =&gt; {errstr =&gt; $error_string, username =&gt; $username}
+    } if !$user_entry;
</ins><span class="cx"> 
</span><del>-    my $user_entry = $detail_result-&gt;shift_entry;
</del><span class="cx"> 
</span><span class="cx">     my $mail_attr = Bugzilla-&gt;params-&gt;{&quot;LDAPmailattribute&quot;};
</span><span class="cx">     if ($mail_attr) {
</span><span class="lines">@@ -128,7 +151,7 @@
</span><span class="cx">                       . Bugzilla-&gt;params-&gt;{&quot;LDAPfilter&quot;} . ')');
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _bind_ldap_anonymously {
</del><ins>+sub _bind_ldap_for_search {
</ins><span class="cx">     my ($self) = @_;
</span><span class="cx">     my $bind_result;
</span><span class="cx">     if (Bugzilla-&gt;params-&gt;{&quot;LDAPbinddn&quot;}) {
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaAuthVerifyStackpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Verify/Stack.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Verify/Stack.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Verify/Stack.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -22,15 +22,26 @@
</span><span class="cx">     successful
</span><span class="cx"> );
</span><span class="cx"> 
</span><ins>+use Bugzilla::Hook;
+
+use Hash::Util qw(lock_keys);
+use List::MoreUtils qw(any);
+
</ins><span class="cx"> sub new {
</span><span class="cx">     my $class = shift;
</span><span class="cx">     my $list = shift;
</span><span class="cx">     my $self = $class-&gt;SUPER::new(@_);
</span><ins>+    my %methods = map { $_ =&gt; &quot;Bugzilla/Auth/Verify/$_.pm&quot; } split(',', $list);
+    lock_keys(%methods);
+    Bugzilla::Hook::process('auth_verify_methods', { modules =&gt; \%methods });
+
</ins><span class="cx">     $self-&gt;{_stack} = [];
</span><span class="cx">     foreach my $verify_method (split(',', $list)) {
</span><del>-        require &quot;Bugzilla/Auth/Verify/${verify_method}.pm&quot;;
-        push(@{$self-&gt;{_stack}}, 
-             &quot;Bugzilla::Auth::Verify::$verify_method&quot;-&gt;new(@_));
</del><ins>+        my $module = $methods{$verify_method};
+        require $module;
+        $module =~ s|/|::|g;
+        $module =~ s/.pm$//;
+        push(@{$self-&gt;{_stack}}, $module-&gt;new(@_));
</ins><span class="cx">     }
</span><span class="cx">     return $self;
</span><span class="cx"> }
</span><span class="lines">@@ -78,4 +89,9 @@
</span><span class="cx">     return 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub extern_id_used {
+    my ($self) = @_;
+    return any { $_-&gt;extern_id_used } @{ $self-&gt;{_stack} };
+}
+
</ins><span class="cx"> 1;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaAuthVerifypm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Verify.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Verify.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Auth/Verify.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -25,6 +25,7 @@
</span><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> 
</span><span class="cx"> use constant user_can_create_account =&gt; 1;
</span><ins>+use constant extern_id_used =&gt; 0;
</ins><span class="cx"> 
</span><span class="cx"> sub new {
</span><span class="cx">     my ($class, $login_type) = @_;
</span><span class="lines">@@ -232,4 +233,12 @@
</span><span class="cx"> Whether or not users can manually create accounts in this type of
</span><span class="cx"> account source. Defaults to C&lt;true&gt;.
</span><span class="cx"> 
</span><ins>+=item C&lt;extern_id_used&gt;
+
+Whether or not this verifier method uses the extern_id field. If
+used, users with editusers permission will be be allowed to
+edit the extern_id for all users.
+
+The default value is C&lt;false&gt;.
+
</ins><span class="cx"> =back
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaAuthpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Auth.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Auth.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Auth.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -32,6 +32,9 @@
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla::Constants;
</span><span class="cx"> use Bugzilla::Error;
</span><ins>+use Bugzilla::Mailer;
+use Bugzilla::Util qw(datetime_from);
+use Bugzilla::User::Setting ();
</ins><span class="cx"> use Bugzilla::Auth::Login::Stack;
</span><span class="cx"> use Bugzilla::Auth::Verify::Stack;
</span><span class="cx"> use Bugzilla::Auth::Persist::Cookie;
</span><span class="lines">@@ -83,7 +86,7 @@
</span><span class="cx"> 
</span><span class="cx">     # Make sure the user isn't disabled.
</span><span class="cx">     my $user = $login_info-&gt;{user};
</span><del>-    if ($user-&gt;disabledtext) {
</del><ins>+    if (!$user-&gt;is_enabled) {
</ins><span class="cx">         return $self-&gt;_handle_login_result({ failure =&gt; AUTH_DISABLED,
</span><span class="cx">                                               user    =&gt; $user }, $type);
</span><span class="cx">     }
</span><span class="lines">@@ -131,6 +134,12 @@
</span><span class="cx">            &amp;&amp; $getter-&gt;user_can_create_account;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub extern_id_used {
+    my ($self) = @_;
+    return $self-&gt;{_info_getter}-&gt;extern_id_used
+           ||  $self-&gt;{_verifier}-&gt;extern_id_used;
+}
+
</ins><span class="cx"> sub can_change_email {
</span><span class="cx">     return $_[0]-&gt;user_can_create_account;
</span><span class="cx"> }
</span><span class="lines">@@ -143,12 +152,22 @@
</span><span class="cx">     my $fail_code = $result-&gt;{failure};
</span><span class="cx"> 
</span><span class="cx">     if (!$fail_code) {
</span><del>-        if ($self-&gt;{_info_getter}-&gt;{successful}-&gt;requires_persistence) {
</del><ins>+        # We don't persist logins over GET requests in the WebService,
+        # because the persistance information can't be re-used again.
+        # (See Bugzilla::WebService::Server::JSONRPC for more info.)
+        if ($self-&gt;{_info_getter}-&gt;{successful}-&gt;requires_persistence
+            and !Bugzilla-&gt;request_cache-&gt;{auth_no_automatic_login}) 
+        {
</ins><span class="cx">             $self-&gt;{_persister}-&gt;persist_login($user);
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     elsif ($fail_code == AUTH_ERROR) {
</span><del>-        ThrowCodeError($result-&gt;{error}, $result-&gt;{details});
</del><ins>+        if ($result-&gt;{user_error}) {
+            ThrowUserError($result-&gt;{user_error}, $result-&gt;{details});
+        }
+        else {
+            ThrowCodeError($result-&gt;{error}, $result-&gt;{details});
+        }
</ins><span class="cx">     }
</span><span class="cx">     elsif ($fail_code == AUTH_NODATA) {
</span><span class="cx">         $self-&gt;{_info_getter}-&gt;fail_nodata($self) 
</span><span class="lines">@@ -162,7 +181,10 @@
</span><span class="cx">     # the password was just wrong. (This makes it harder for a cracker
</span><span class="cx">     # to find account names by brute force)
</span><span class="cx">     elsif ($fail_code == AUTH_LOGINFAILED or $fail_code == AUTH_NO_SUCH_USER) {
</span><del>-        ThrowUserError(&quot;invalid_username_or_password&quot;);
</del><ins>+        my $remaining_attempts = MAX_LOGIN_ATTEMPTS 
+                                 - ($result-&gt;{failure_count} || 0);
+        ThrowUserError(&quot;invalid_username_or_password&quot;, 
+                       { remaining =&gt; $remaining_attempts });
</ins><span class="cx">     }
</span><span class="cx">     # The account may be disabled
</span><span class="cx">     elsif ($fail_code == AUTH_DISABLED) {
</span><span class="lines">@@ -173,6 +195,41 @@
</span><span class="cx">         ThrowUserError(&quot;account_disabled&quot;,
</span><span class="cx">             {'disabled_reason' =&gt; $result-&gt;{user}-&gt;disabledtext});
</span><span class="cx">     }
</span><ins>+    elsif ($fail_code == AUTH_LOCKOUT) {
+        my $attempts = $user-&gt;account_ip_login_failures;
+
+        # We want to know when the account will be unlocked. This is 
+        # determined by the 5th-from-last login failure (or more/less than
+        # 5th, if MAX_LOGIN_ATTEMPTS is not 5).
+        my $determiner = $attempts-&gt;[scalar(@$attempts) - MAX_LOGIN_ATTEMPTS];
+        my $unlock_at = datetime_from($determiner-&gt;{login_time}, 
+                                      Bugzilla-&gt;local_timezone);
+        $unlock_at-&gt;add(minutes =&gt; LOGIN_LOCKOUT_INTERVAL);
+
+        # If we were *just* locked out, notify the maintainer about the
+        # lockout.
+        if ($result-&gt;{just_locked_out}) {
+            # We're sending to the maintainer, who may be not a Bugzilla 
+            # account, but just an email address. So we use the
+            # installation's default language for sending the email.
+            my $default_settings = Bugzilla::User::Setting::get_defaults();
+            my $template = Bugzilla-&gt;template_inner(
+                               $default_settings-&gt;{lang}-&gt;{default_value});
+            my $vars = {
+                locked_user =&gt; $user,
+                attempts    =&gt; $attempts,
+                unlock_at   =&gt; $unlock_at,
+            };
+            my $message;
+            $template-&gt;process('email/lockout.txt.tmpl', $vars, \$message)
+                || ThrowTemplateError($template-&gt;error);
+            MessageToMTA($message);
+        }
+
+        $unlock_at-&gt;set_time_zone($user-&gt;timezone);
+        ThrowUserError('account_locked', 
+            { ip_addr =&gt; $determiner-&gt;{ip_addr}, unlock_at =&gt; $unlock_at });
+    }
</ins><span class="cx">     # If we get here, then we've run out of options, which shouldn't happen.
</span><span class="cx">     else {
</span><span class="cx">         ThrowCodeError(&quot;authres_unhandled&quot;, { value =&gt; $fail_code });
</span><span class="lines">@@ -234,6 +291,11 @@
</span><span class="cx"> 
</span><span class="cx"> An incorrect username or password was given.
</span><span class="cx"> 
</span><ins>+The hashref may also contain a C&lt;failure_count&gt; element, which specifies
+how many times the account has failed to log in within the lockout
+period (see L&lt;/AUTH_LOCKOUT&gt;). This is used to warn the user when
+he is getting close to being locked out.
+
</ins><span class="cx"> =head2 C&lt;AUTH_NO_SUCH_USER&gt;
</span><span class="cx"> 
</span><span class="cx"> This is an optional more-specific version of C&lt;AUTH_LOGINFAILED&gt;.
</span><span class="lines">@@ -251,6 +313,15 @@
</span><span class="cx"> The user successfully logged in, but their account has been disabled.
</span><span class="cx"> Usually this is throw only by C&lt;Bugzilla::Auth::login&gt;.
</span><span class="cx"> 
</span><ins>+=head2 C&lt;AUTH_LOCKOUT&gt;
+
+The user's account is locked out after having failed to log in too many
+times within a certain period of time (as specified by
+L&lt;Bugzilla::Constants/LOGIN_LOCKOUT_INTERVAL&gt;).
+
+The hashref will also contain a C&lt;user&gt; element, representing the
+L&lt;Bugzilla::User&gt; whose account is locked out.
+
</ins><span class="cx"> =head1 LOGIN TYPES
</span><span class="cx"> 
</span><span class="cx"> The C&lt;login&gt; function (below) can do different types of login, depending
</span><span class="lines">@@ -333,6 +404,10 @@
</span><span class="cx"> Returns:     C&lt;true&gt; if users are allowed to create new Bugzilla accounts,
</span><span class="cx">              C&lt;false&gt; otherwise.
</span><span class="cx"> 
</span><ins>+=item C&lt;extern_id_used&gt;
+
+Description: Whether or not current login system uses extern_id.
+
</ins><span class="cx"> =item C&lt;can_change_email&gt;
</span><span class="cx"> 
</span><span class="cx"> Description: Whether or not the current login system allows users to
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaBugpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Bug.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Bug.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Bug.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -25,6 +25,8 @@
</span><span class="cx"> #                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
</span><span class="cx"> #                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
</span><span class="cx"> #                 Lance Larsh &lt;lance.larsh@oracle.com&gt;
</span><ins>+#                 Elliotte Martin &lt;elliotte_martin@yahoo.com&gt;
+#                 Christian Legnitto &lt;clegnitto@mozilla.com&gt;
</ins><span class="cx"> 
</span><span class="cx"> package Bugzilla::Bug;
</span><span class="cx"> 
</span><span class="lines">@@ -37,24 +39,30 @@
</span><span class="cx"> use Bugzilla::FlagType;
</span><span class="cx"> use Bugzilla::Hook;
</span><span class="cx"> use Bugzilla::Keyword;
</span><ins>+use Bugzilla::Milestone;
</ins><span class="cx"> use Bugzilla::User;
</span><span class="cx"> use Bugzilla::Util;
</span><ins>+use Bugzilla::Version;
</ins><span class="cx"> use Bugzilla::Error;
</span><span class="cx"> use Bugzilla::Product;
</span><span class="cx"> use Bugzilla::Component;
</span><span class="cx"> use Bugzilla::Group;
</span><span class="cx"> use Bugzilla::Status;
</span><ins>+use Bugzilla::Comment;
+use Bugzilla::BugUrl;
</ins><span class="cx"> 
</span><del>-use List::Util qw(min);
</del><ins>+use List::MoreUtils qw(firstidx uniq part);
+use List::Util qw(min max first);
</ins><span class="cx"> use Storable qw(dclone);
</span><ins>+use URI;
+use URI::QueryParam;
+use Scalar::Util qw(blessed);
</ins><span class="cx"> 
</span><span class="cx"> use base qw(Bugzilla::Object Exporter);
</span><span class="cx"> @Bugzilla::Bug::EXPORT = qw(
</span><del>-    bug_alias_to_id ValidateBugID
-    RemoveVotes CheckIfVotedConfirmed
</del><ins>+    bug_alias_to_id
</ins><span class="cx">     LogActivityEntry
</span><span class="cx">     editable_bug_fields
</span><del>-    SPECIAL_STATUS_WORKFLOW_ACTIONS
</del><span class="cx"> );
</span><span class="cx"> 
</span><span class="cx"> #####################################################################
</span><span class="lines">@@ -65,6 +73,9 @@
</span><span class="cx"> use constant ID_FIELD   =&gt; 'bug_id';
</span><span class="cx"> use constant NAME_FIELD =&gt; 'alias';
</span><span class="cx"> use constant LIST_ORDER =&gt; ID_FIELD;
</span><ins>+# Bugs have their own auditing table, bugs_activity.
+use constant AUDIT_CREATES =&gt; 0;
+use constant AUDIT_UPDATES =&gt; 0;
</ins><span class="cx"> 
</span><span class="cx"> # This is a sub because it needs to call other subroutines.
</span><span class="cx"> sub DB_COLUMNS {
</span><span class="lines">@@ -72,7 +83,8 @@
</span><span class="cx">     my @custom = grep {$_-&gt;type != FIELD_TYPE_MULTI_SELECT}
</span><span class="cx">                       Bugzilla-&gt;active_custom_fields;
</span><span class="cx">     my @custom_names = map {$_-&gt;name} @custom;
</span><del>-    return qw(
</del><ins>+
+    my @columns = (qw(
</ins><span class="cx">         alias
</span><span class="cx">         assigned_to
</span><span class="cx">         bug_file_loc
</span><span class="lines">@@ -84,6 +96,7 @@
</span><span class="cx">         delta_ts
</span><span class="cx">         estimated_time
</span><span class="cx">         everconfirmed
</span><ins>+        lastdiffed
</ins><span class="cx">         op_sys
</span><span class="cx">         priority
</span><span class="cx">         product_id
</span><span class="lines">@@ -100,34 +113,45 @@
</span><span class="cx">     'reporter    AS reporter_id',
</span><span class="cx">     $dbh-&gt;sql_date_format('creation_ts', '%Y.%m.%d %H:%i') . ' AS creation_ts',
</span><span class="cx">     $dbh-&gt;sql_date_format('deadline', '%Y-%m-%d') . ' AS deadline',
</span><del>-    @custom_names;
</del><ins>+    @custom_names);
+    
+    Bugzilla::Hook::process(&quot;bug_columns&quot;, { columns =&gt; \@columns });
+    
+    return @columns;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-use constant REQUIRED_CREATE_FIELDS =&gt; qw(
-    component
-    product
-    short_desc
-    version
-);
</del><ins>+sub VALIDATORS {
</ins><span class="cx"> 
</span><del>-# There are also other, more complex validators that are called
-# from run_create_validators.
-sub VALIDATORS {
</del><span class="cx">     my $validators = {
</span><span class="cx">         alias          =&gt; \&amp;_check_alias,
</span><ins>+        assigned_to    =&gt; \&amp;_check_assigned_to,
</ins><span class="cx">         bug_file_loc   =&gt; \&amp;_check_bug_file_loc,
</span><del>-        bug_severity   =&gt; \&amp;_check_bug_severity,
</del><ins>+        bug_severity   =&gt; \&amp;_check_select_field,
+        bug_status     =&gt; \&amp;_check_bug_status,
+        cc             =&gt; \&amp;_check_cc,
</ins><span class="cx">         comment        =&gt; \&amp;_check_comment,
</span><del>-        commentprivacy =&gt; \&amp;_check_commentprivacy,
</del><ins>+        component      =&gt; \&amp;_check_component,
+        creation_ts    =&gt; \&amp;_check_creation_ts,
</ins><span class="cx">         deadline       =&gt; \&amp;_check_deadline,
</span><del>-        estimated_time =&gt; \&amp;_check_estimated_time,
-        op_sys         =&gt; \&amp;_check_op_sys,
</del><ins>+        dup_id         =&gt; \&amp;_check_dup_id,
+        estimated_time =&gt; \&amp;_check_time_field,
+        everconfirmed  =&gt; \&amp;Bugzilla::Object::check_boolean,
+        groups         =&gt; \&amp;_check_groups,
+        keywords       =&gt; \&amp;_check_keywords,
+        op_sys         =&gt; \&amp;_check_select_field,
</ins><span class="cx">         priority       =&gt; \&amp;_check_priority,
</span><span class="cx">         product        =&gt; \&amp;_check_product,
</span><del>-        remaining_time =&gt; \&amp;_check_remaining_time,
-        rep_platform   =&gt; \&amp;_check_rep_platform,
</del><ins>+        qa_contact     =&gt; \&amp;_check_qa_contact,
+        remaining_time =&gt; \&amp;_check_time_field,
+        rep_platform   =&gt; \&amp;_check_select_field,
+        resolution     =&gt; \&amp;_check_resolution,
</ins><span class="cx">         short_desc     =&gt; \&amp;_check_short_desc,
</span><span class="cx">         status_whiteboard =&gt; \&amp;_check_status_whiteboard,
</span><ins>+        target_milestone  =&gt; \&amp;_check_target_milestone,
+        version           =&gt; \&amp;_check_version,
+
+        cclist_accessible   =&gt; \&amp;Bugzilla::Object::check_boolean,
+        reporter_accessible =&gt; \&amp;Bugzilla::Object::check_boolean,
</ins><span class="cx">     };
</span><span class="cx"> 
</span><span class="cx">     # Set up validators for custom fields.    
</span><span class="lines">@@ -145,6 +169,9 @@
</span><span class="cx">         elsif ($field-&gt;type == FIELD_TYPE_FREETEXT) {
</span><span class="cx">             $validator = \&amp;_check_freetext_field;
</span><span class="cx">         }
</span><ins>+        elsif ($field-&gt;type == FIELD_TYPE_BUG_ID) {
+            $validator = \&amp;_check_bugid_field;
+        }
</ins><span class="cx">         else {
</span><span class="cx">             $validator = \&amp;_check_default_field;
</span><span class="cx">         }
</span><span class="lines">@@ -154,16 +181,33 @@
</span><span class="cx">     return $validators;
</span><span class="cx"> };
</span><span class="cx"> 
</span><del>-use constant UPDATE_VALIDATORS =&gt; {
-    assigned_to         =&gt; \&amp;_check_assigned_to,
-    bug_status          =&gt; \&amp;_check_bug_status,
-    cclist_accessible   =&gt; \&amp;Bugzilla::Object::check_boolean,
-    dup_id              =&gt; \&amp;_check_dup_id,
-    qa_contact          =&gt; \&amp;_check_qa_contact,
-    reporter_accessible =&gt; \&amp;Bugzilla::Object::check_boolean,
-    resolution          =&gt; \&amp;_check_resolution,
-    target_milestone    =&gt; \&amp;_check_target_milestone,
-    version             =&gt; \&amp;_check_version,
</del><ins>+sub VALIDATOR_DEPENDENCIES {
+    my $cache = Bugzilla-&gt;request_cache;
+    return $cache-&gt;{bug_validator_dependencies} 
+        if $cache-&gt;{bug_validator_dependencies};
+
+    my %deps = (
+        assigned_to      =&gt; ['component'],
+        bug_status       =&gt; ['product', 'comment', 'target_milestone'],
+        cc               =&gt; ['component'],
+        comment          =&gt; ['creation_ts'],
+        component        =&gt; ['product'],
+        dup_id           =&gt; ['bug_status', 'resolution'],
+        groups           =&gt; ['product'],
+        keywords         =&gt; ['product'],
+        resolution       =&gt; ['bug_status'],
+        qa_contact       =&gt; ['component'],
+        target_milestone =&gt; ['product'],
+        version          =&gt; ['product'],
+    );
+
+    foreach my $field (@{ Bugzilla-&gt;fields }) {
+        $deps{$field-&gt;name} = [ $field-&gt;visibility_field-&gt;name ]
+            if $field-&gt;{visibility_field_id};
+    }
+
+    $cache-&gt;{bug_validator_dependencies} = \%deps;
+    return \%deps;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> sub UPDATE_COLUMNS {
</span><span class="lines">@@ -204,39 +248,89 @@
</span><span class="cx"> );
</span><span class="cx"> 
</span><span class="cx"> sub DATE_COLUMNS {
</span><del>-    my @fields = Bugzilla-&gt;get_fields(
-        { custom =&gt; 1, type =&gt; FIELD_TYPE_DATETIME });
</del><ins>+    my @fields = @{ Bugzilla-&gt;fields({ type =&gt; FIELD_TYPE_DATETIME }) };
</ins><span class="cx">     return map { $_-&gt;name } @fields;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-# This is used by add_comment to know what we validate before putting in
-# the DB.
-use constant UPDATE_COMMENT_COLUMNS =&gt; qw(
-    thetext
-    work_time
-    type
-    extra_data
-    isprivate
-);
-
</del><span class="cx"> # Used in LogActivityEntry(). Gives the max length of lines in the
</span><span class="cx"> # activity table.
</span><span class="cx"> use constant MAX_LINE_LENGTH =&gt; 254;
</span><span class="cx"> 
</span><del>-use constant SPECIAL_STATUS_WORKFLOW_ACTIONS =&gt; qw(
-    none
-    duplicate
-    change_resolution
-    clearresolution
-);
</del><ins>+# This maps the names of internal Bugzilla bug fields to things that would
+# make sense to somebody who's not intimately familiar with the inner workings
+# of Bugzilla. (These are the field names that the WebService and email_in.pl
+# use.)
+use constant FIELD_MAP =&gt; {
+    blocks           =&gt; 'blocked',
+    cc_accessible    =&gt; 'cclist_accessible',
+    commentprivacy   =&gt; 'comment_is_private',
+    creation_time    =&gt; 'creation_ts',
+    creator          =&gt; 'reporter',
+    description      =&gt; 'comment',
+    depends_on       =&gt; 'dependson',
+    dupe_of          =&gt; 'dup_id',
+    id               =&gt; 'bug_id',
+    is_confirmed     =&gt; 'everconfirmed',
+    is_cc_accessible =&gt; 'cclist_accessible',
+    is_creator_accessible =&gt; 'reporter_accessible',
+    last_change_time =&gt; 'delta_ts',
+    platform         =&gt; 'rep_platform',
+    severity         =&gt; 'bug_severity',
+    status           =&gt; 'bug_status',
+    summary          =&gt; 'short_desc',
+    url              =&gt; 'bug_file_loc',
+    whiteboard       =&gt; 'status_whiteboard',
</ins><span class="cx"> 
</span><ins>+    # These are special values for the WebService Bug.search method.
+    limit            =&gt; 'LIMIT',
+    offset           =&gt; 'OFFSET',
+};
+
+use constant REQUIRED_FIELD_MAP =&gt; {
+    product_id   =&gt; 'product',
+    component_id =&gt; 'component',
+};
+
+# Creation timestamp is here because it needs to be validated
+# but it can be NULL in the database (see comments in create above)
+#
+# Target Milestone is here because it has a default that the validator
+# creates (product.defaultmilestone) that is different from the database
+# default.
+#
+# CC is here because it is a separate table, and has a validator-created
+# default of the component initialcc.
+#
+# QA Contact is allowed to be NULL in the database, so it wouldn't normally
+# be caught by _required_create_fields. However, it always has to be validated,
+# because it has a default of the component.defaultqacontact.
+#
+# Groups are in a separate table, but must always be validated so that
+# mandatory groups get set on bugs.
+use constant EXTRA_REQUIRED_FIELDS =&gt; qw(creation_ts target_milestone cc qa_contact groups);
+
</ins><span class="cx"> #####################################################################
</span><span class="cx"> 
</span><ins>+# This and &quot;new&quot; catch every single way of creating a bug, so that we
+# can call _create_cf_accessors.
+sub _do_list_select {
+    my $invocant = shift;
+    $invocant-&gt;_create_cf_accessors();
+    return $invocant-&gt;SUPER::_do_list_select(@_);
+}
+
</ins><span class="cx"> sub new {
</span><span class="cx">     my $invocant = shift;
</span><span class="cx">     my $class = ref($invocant) || $invocant;
</span><span class="cx">     my $param = shift;
</span><span class="cx"> 
</span><ins>+    $class-&gt;_create_cf_accessors();
+
+    # Remove leading &quot;#&quot; mark if we've just been passed an id.
+    if (!ref $param &amp;&amp; $param =~ /^#(\d+)$/) {
+        $param = $1;
+    }
+
</ins><span class="cx">     # If we get something that looks like a word (not a number),
</span><span class="cx">     # make it the &quot;name&quot; param.
</span><span class="cx">     if (!defined $param || (!ref($param) &amp;&amp; $param !~ /^\d+$/)) {
</span><span class="lines">@@ -261,15 +355,227 @@
</span><span class="cx">     # if the bug wasn't found in the database.
</span><span class="cx">     if (!$self) {
</span><span class="cx">         my $error_self = {};
</span><ins>+        if (ref $param) {
+            $error_self-&gt;{bug_id} = $param-&gt;{name};
+            $error_self-&gt;{error}  = 'InvalidBugId';
+        }
+        else {
+            $error_self-&gt;{bug_id} = $param;
+            $error_self-&gt;{error}  = 'NotFound';
+        }
</ins><span class="cx">         bless $error_self, $class;
</span><del>-        $error_self-&gt;{'bug_id'} = ref($param) ? $param-&gt;{name} : $param;
-        $error_self-&gt;{'error'}  = 'NotFound';
</del><span class="cx">         return $error_self;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     return $self;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub check {
+    my $class = shift;
+    my ($id, $field) = @_;
+
+    ThrowUserError('improper_bug_id_field_value', { field =&gt; $field }) unless defined $id;
+
+    # Bugzilla::Bug throws lots of special errors, so we don't call
+    # SUPER::check, we just call our new and do our own checks.
+    my $self = $class-&gt;new(trim($id));
+    # For error messages, use the id that was returned by new(), because
+    # it's cleaned up.
+    $id = $self-&gt;id;
+
+    if ($self-&gt;{error}) {
+        if ($self-&gt;{error} eq 'NotFound') {
+             ThrowUserError(&quot;bug_id_does_not_exist&quot;, { bug_id =&gt; $id });
+        }
+        if ($self-&gt;{error} eq 'InvalidBugId') {
+            ThrowUserError(&quot;improper_bug_id_field_value&quot;,
+                              { bug_id =&gt; $id,
+                                field  =&gt; $field });
+        }
+    }
+
+    unless ($field &amp;&amp; $field =~ /^(dependson|blocked|dup_id)$/) {
+        $self-&gt;check_is_visible;
+    }
+    return $self;
+}
+
+sub check_is_visible {
+    my $self = shift;
+    my $user = Bugzilla-&gt;user;
+
+    if (!$user-&gt;can_see_bug($self-&gt;id)) {
+        # The error the user sees depends on whether or not they are
+        # logged in (i.e. $user-&gt;id contains the user's positive integer ID).
+        if ($user-&gt;id) {
+            ThrowUserError(&quot;bug_access_denied&quot;, { bug_id =&gt; $self-&gt;id });
+        } else {
+            ThrowUserError(&quot;bug_access_query&quot;, { bug_id =&gt; $self-&gt;id });
+        }
+    }
+}
+
+sub match {
+    my $class = shift;
+    my ($params) = @_;
+
+    # Allow matching certain fields by name (in addition to matching by ID).
+    my %translate_fields = (
+        assigned_to =&gt; 'Bugzilla::User',
+        qa_contact  =&gt; 'Bugzilla::User',
+        reporter    =&gt; 'Bugzilla::User',
+        product     =&gt; 'Bugzilla::Product',
+        component   =&gt; 'Bugzilla::Component',
+    );
+    my %translated;
+
+    foreach my $field (keys %translate_fields) {
+        my @ids;
+        # Convert names to ids. We use &quot;exists&quot; everywhere since people can
+        # legally specify &quot;undef&quot; to mean IS NULL (even though most of these
+        # fields can't be NULL, people can still specify it...).
+        if (exists $params-&gt;{$field}) {
+            my $names = $params-&gt;{$field};
+            my $type = $translate_fields{$field};
+            my $param = $type eq 'Bugzilla::User' ? 'login_name' : 'name';
+            # We call Bugzilla::Object::match directly to avoid the
+            # Bugzilla::User::match implementation which is different.
+            my $objects = Bugzilla::Object::match($type, { $param =&gt; $names });
+            push(@ids, map { $_-&gt;id } @$objects);
+        }
+        # You can also specify ids directly as arguments to this function,
+        # so include them in the list if they have been specified.
+        if (exists $params-&gt;{&quot;${field}_id&quot;}) {
+            my $current_ids = $params-&gt;{&quot;${field}_id&quot;};
+            my @id_array = ref $current_ids ? @$current_ids : ($current_ids);
+            push(@ids, @id_array);
+        }
+        # We do this &quot;or&quot; instead of a &quot;scalar(@ids)&quot; to handle the case
+        # when people passed only invalid object names. Otherwise we'd
+        # end up with a SUPER::match call with zero criteria (which dies).
+        if (exists $params-&gt;{$field} or exists $params-&gt;{&quot;${field}_id&quot;}) {
+            $translated{$field} = scalar(@ids) == 1 ? $ids[0] : \@ids;
+        }
+    }
+
+    # The user fields don't have an _id on the end of them in the database,
+    # but the product &amp; component fields do, so we have to have separate
+    # code to deal with the different sets of fields here.
+    foreach my $field (qw(assigned_to qa_contact reporter)) {
+        delete $params-&gt;{&quot;${field}_id&quot;};
+        $params-&gt;{$field} = $translated{$field} 
+            if exists $translated{$field};
+    }
+    foreach my $field (qw(product component)) {
+        delete $params-&gt;{$field};
+        $params-&gt;{&quot;${field}_id&quot;} = $translated{$field} 
+            if exists $translated{$field};
+    }
+
+    return $class-&gt;SUPER::match(@_);
+}
+
+# Helps load up information for bugs for show_bug.cgi and other situations
+# that will need to access info on lots of bugs.
+sub preload {
+    my ($class, $bugs) = @_;
+    my $user = Bugzilla-&gt;user;
+
+    # It would be faster but MUCH more complicated to select all the
+    # deps for the entire list in one SQL statement. If we ever have
+    # a profile that proves that that's necessary, we can switch over
+    # to the more complex method.
+    my @all_dep_ids;
+    foreach my $bug (@$bugs) {
+        push(@all_dep_ids, @{ $bug-&gt;blocked }, @{ $bug-&gt;dependson });
+    }
+    @all_dep_ids = uniq @all_dep_ids;
+    # If we don't do this, can_see_bug will do one call per bug in
+    # the dependency lists, during get_bug_link in Bugzilla::Template.
+    $user-&gt;visible_bugs(\@all_dep_ids);
+}
+
+sub possible_duplicates {
+    my ($class, $params) = @_;
+    my $short_desc = $params-&gt;{summary};
+    my $products = $params-&gt;{products} || [];
+    my $limit = $params-&gt;{limit} || MAX_POSSIBLE_DUPLICATES;
+    $limit = MAX_POSSIBLE_DUPLICATES if $limit &gt; MAX_POSSIBLE_DUPLICATES;
+    $products = [$products] if !ref($products) eq 'ARRAY';
+
+    my $orig_limit = $limit;
+    detaint_natural($limit) 
+        || ThrowCodeError('param_must_be_numeric', 
+                          { function =&gt; 'possible_duplicates',
+                            param    =&gt; $orig_limit });
+
+    my $dbh = Bugzilla-&gt;dbh;
+    my $user = Bugzilla-&gt;user;
+    my @words = split(/[\b\s]+/, $short_desc || '');
+    # Exclude punctuation from the array.
+    @words = map { /(\w+)/; $1 } @words;
+    # And make sure that each word is longer than 2 characters.
+    @words = grep { defined $_ and length($_) &gt; 2 } @words;
+
+    return [] if !@words;
+
+    my ($where_sql, $relevance_sql);
+    if ($dbh-&gt;FULLTEXT_OR) {
+        my $joined_terms = join($dbh-&gt;FULLTEXT_OR, @words);
+        ($where_sql, $relevance_sql) = 
+            $dbh-&gt;sql_fulltext_search('bugs_fulltext.short_desc', 
+                                      $joined_terms, 1);
+        $relevance_sql ||= $where_sql;
+    }
+    else {
+        my (@where, @relevance);
+        my $count = 0;
+        foreach my $word (@words) {
+            $count++;
+            my ($term, $rel_term) = $dbh-&gt;sql_fulltext_search(
+                'bugs_fulltext.short_desc', $word, $count);
+            push(@where, $term);
+            push(@relevance, $rel_term || $term);
+        }
+
+        $where_sql = join(' OR ', @where);
+        $relevance_sql = join(' + ', @relevance);
+    }
+
+    my $product_ids = join(',', map { $_-&gt;id } @$products);
+    my $product_sql = $product_ids ? &quot;AND product_id IN ($product_ids)&quot; : &quot;&quot;;
+
+    # Because we collapse duplicates, we want to get slightly more bugs
+    # than were actually asked for.
+    my $sql_limit = $limit + 5;
+
+    my $possible_dupes = $dbh-&gt;selectall_arrayref(
+        &quot;SELECT bugs.bug_id AS bug_id, bugs.resolution AS resolution,
+                ($relevance_sql) AS relevance
+           FROM bugs
+                INNER JOIN bugs_fulltext ON bugs.bug_id = bugs_fulltext.bug_id
+          WHERE ($where_sql) $product_sql
+       ORDER BY relevance DESC, bug_id DESC &quot; .
+          $dbh-&gt;sql_limit($sql_limit), {Slice=&gt;{}});
+
+    my @actual_dupe_ids;
+    # Resolve duplicates into their ultimate target duplicates.
+    foreach my $bug (@$possible_dupes) {
+        my $push_id = $bug-&gt;{bug_id};
+        if ($bug-&gt;{resolution} &amp;&amp; $bug-&gt;{resolution} eq 'DUPLICATE') {
+            $push_id = _resolve_ultimate_dup_id($bug-&gt;{bug_id});
+        }
+        push(@actual_dupe_ids, $push_id);
+    }
+    @actual_dupe_ids = uniq @actual_dupe_ids;
+    if (scalar @actual_dupe_ids &gt; $limit) {
+        @actual_dupe_ids = @actual_dupe_ids[0..($limit-1)];
+    }
+
+    my $visible = $user-&gt;visible_bugs(\@actual_dupe_ids);
+    return $class-&gt;new_from_list($visible);
+}
+
</ins><span class="cx"> # Docs for create() (there's no POD in this file yet, but we very
</span><span class="cx"> # much need this documented right now):
</span><span class="cx"> #
</span><span class="lines">@@ -331,19 +637,13 @@
</span><span class="cx"> 
</span><span class="cx">     # These are not a fields in the bugs table, so we don't pass them to
</span><span class="cx">     # insert_create_data.
</span><del>-    my $cc_ids     = delete $params-&gt;{cc};
-    my $groups     = delete $params-&gt;{groups};
-    my $depends_on = delete $params-&gt;{dependson};
-    my $blocked    = delete $params-&gt;{blocked};
-    my ($comment, $privacy) = ($params-&gt;{comment}, $params-&gt;{commentprivacy});
-    delete $params-&gt;{comment};
-    delete $params-&gt;{commentprivacy};
</del><ins>+    my $cc_ids           = delete $params-&gt;{cc};
+    my $groups           = delete $params-&gt;{groups};
+    my $depends_on       = delete $params-&gt;{dependson};
+    my $blocked          = delete $params-&gt;{blocked};
+    my $keywords         = delete $params-&gt;{keywords};
+    my $creation_comment = delete $params-&gt;{comment};
</ins><span class="cx"> 
</span><del>-    # Set up the keyword cache for bug creation.
-    my $keywords = $params-&gt;{keywords};
-    $params-&gt;{keywords} = join(', ', sort {lc($a) cmp lc($b)} 
-                                          map($_-&gt;name, @$keywords));
-
</del><span class="cx">     # We don't want the bug to appear in the system until it's correctly
</span><span class="cx">     # protected by groups.
</span><span class="cx">     my $timestamp = delete $params-&gt;{creation_ts}; 
</span><span class="lines">@@ -354,8 +654,8 @@
</span><span class="cx">     # Add the group restrictions
</span><span class="cx">     my $sth_group = $dbh-&gt;prepare(
</span><span class="cx">         'INSERT INTO bug_group_map (bug_id, group_id) VALUES (?, ?)');
</span><del>-    foreach my $group_id (@$groups) {
-        $sth_group-&gt;execute($bug-&gt;bug_id, $group_id);
</del><ins>+    foreach my $group (@$groups) {
+        $sth_group-&gt;execute($bug-&gt;bug_id, $group-&gt;id);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     $dbh-&gt;do('UPDATE bugs SET creation_ts = ? WHERE bug_id = ?', undef,
</span><span class="lines">@@ -406,21 +706,19 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    # And insert the comment. We always insert a comment on bug creation,
</del><ins>+    # Comment #0 handling...
+
+    # We now have a bug id so we can fill this out
+    $creation_comment-&gt;{'bug_id'} = $bug-&gt;id;
+
+    # Insert the comment. We always insert a comment on bug creation,
</ins><span class="cx">     # but sometimes it's blank.
</span><del>-    my @columns = qw(bug_id who bug_when thetext);
-    my @values  = ($bug-&gt;bug_id, $bug-&gt;{reporter_id}, $timestamp, $comment);
-    # We don't include the &quot;isprivate&quot; column unless it was specified. 
-    # This allows it to fall back to its database default.
-    if (defined $privacy) {
-        push(@columns, 'isprivate');
-        push(@values, $privacy);
-    }
-    my $qmarks = &quot;?,&quot; x @columns;
-    chop($qmarks);
-    $dbh-&gt;do('INSERT INTO longdescs (' . join(',', @columns)  . &quot;)
-                   VALUES ($qmarks)&quot;, undef, @values);
</del><ins>+    Bugzilla::Comment-&gt;insert_create_data($creation_comment);
</ins><span class="cx"> 
</span><ins>+    Bugzilla::Hook::process('bug_end_of_create', { bug =&gt; $bug,
+                                                   timestamp =&gt; $timestamp,
+                                                 });
+
</ins><span class="cx">     $dbh-&gt;bz_commit_transaction();
</span><span class="cx"> 
</span><span class="cx">     # Because MySQL doesn't support transactions on the fulltext table,
</span><span class="lines">@@ -431,43 +729,17 @@
</span><span class="cx">     return $bug;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-
</del><span class="cx"> sub run_create_validators {
</span><span class="cx">     my $class  = shift;
</span><span class="cx">     my $params = $class-&gt;SUPER::run_create_validators(@_);
</span><span class="cx"> 
</span><del>-    my $product = $params-&gt;{product};
</del><ins>+    my $product = delete $params-&gt;{product};
</ins><span class="cx">     $params-&gt;{product_id} = $product-&gt;id;
</span><del>-    delete $params-&gt;{product};
-
-    ($params-&gt;{bug_status}, $params-&gt;{everconfirmed})
-        = $class-&gt;_check_bug_status($params-&gt;{bug_status}, $product,
-                                    $params-&gt;{comment});
-
-    $params-&gt;{target_milestone} = $class-&gt;_check_target_milestone(
-        $params-&gt;{target_milestone}, $product);
-
-    $params-&gt;{version} = $class-&gt;_check_version($params-&gt;{version}, $product);
-
-    $params-&gt;{keywords} = $class-&gt;_check_keywords($params-&gt;{keywords}, $product);
-
-    $params-&gt;{groups} = $class-&gt;_check_groups($product,
-        $params-&gt;{groups});
-
-    my $component = $class-&gt;_check_component($params-&gt;{component}, $product);
</del><ins>+    my $component = delete $params-&gt;{component};
</ins><span class="cx">     $params-&gt;{component_id} = $component-&gt;id;
</span><del>-    delete $params-&gt;{component};
</del><span class="cx"> 
</span><del>-    $params-&gt;{assigned_to} = 
-        $class-&gt;_check_assigned_to($params-&gt;{assigned_to}, $component);
-    $params-&gt;{qa_contact} =
-        $class-&gt;_check_qa_contact($params-&gt;{qa_contact}, $component);
-    $params-&gt;{cc} = $class-&gt;_check_cc($component, $params-&gt;{cc});
-
-    # Callers cannot set Reporter, currently.
</del><ins>+    # Callers cannot set reporter, creation_ts, or delta_ts.
</ins><span class="cx">     $params-&gt;{reporter} = $class-&gt;_check_reporter();
</span><del>-
-    $params-&gt;{creation_ts} ||= Bugzilla-&gt;dbh-&gt;selectrow_array('SELECT NOW()');
</del><span class="cx">     $params-&gt;{delta_ts} = $params-&gt;{creation_ts};
</span><span class="cx"> 
</span><span class="cx">     if ($params-&gt;{estimated_time}) {
</span><span class="lines">@@ -483,10 +755,20 @@
</span><span class="cx"> 
</span><span class="cx">     # You can't set these fields on bug creation (or sometimes ever).
</span><span class="cx">     delete $params-&gt;{resolution};
</span><del>-    delete $params-&gt;{votes};
</del><span class="cx">     delete $params-&gt;{lastdiffed};
</span><span class="cx">     delete $params-&gt;{bug_id};
</span><span class="cx"> 
</span><ins>+    Bugzilla::Hook::process('bug_end_of_create_validators',
+                            { params =&gt; $params });
+
+    my @mandatory_fields = @{ Bugzilla-&gt;fields({ is_mandatory =&gt; 1,
+                                                 enter_bug    =&gt; 1,
+                                                 obsolete     =&gt; 0 }) };
+    foreach my $field (@mandatory_fields) {
+        $class-&gt;_check_field_is_mandatory($params-&gt;{$field-&gt;name}, $field,
+                                          $params);
+    }
+
</ins><span class="cx">     return $params;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -496,11 +778,12 @@
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx">     # XXX This is just a temporary hack until all updating happens
</span><span class="cx">     # inside this function.
</span><del>-    my $delta_ts = shift || $dbh-&gt;selectrow_array(&quot;SELECT NOW()&quot;);
</del><ins>+    my $delta_ts = shift || $dbh-&gt;selectrow_array('SELECT LOCALTIMESTAMP(0)');
</ins><span class="cx"> 
</span><del>-    my $old_bug = $self-&gt;new($self-&gt;id);
-    my $changes = $self-&gt;SUPER::update(@_);
</del><ins>+    $dbh-&gt;bz_start_transaction();
</ins><span class="cx"> 
</span><ins>+    my ($changes, $old_bug) = $self-&gt;SUPER::update(@_);
+
</ins><span class="cx">     # Certain items in $changes have to be fixed so that they hold
</span><span class="cx">     # a name instead of an ID.
</span><span class="cx">     foreach my $field (qw(product_id component_id)) {
</span><span class="lines">@@ -557,8 +840,6 @@
</span><span class="cx">         $dbh-&gt;do('INSERT INTO keywords (bug_id, keywordid) VALUES (?,?)',
</span><span class="cx">                  undef, $self-&gt;id, $keyword_id);
</span><span class="cx">     }
</span><del>-    $dbh-&gt;do('UPDATE bugs SET keywords = ? WHERE bug_id = ?', undef,
-             $self-&gt;keywords, $self-&gt;id);
</del><span class="cx">     # If any changes were found, record it in the activity log
</span><span class="cx">     if (scalar @$removed_kw || scalar @$added_kw) {
</span><span class="cx">         my $removed_keywords = Bugzilla::Keyword-&gt;new_from_list($removed_kw);
</span><span class="lines">@@ -625,25 +906,33 @@
</span><span class="cx">         $changes-&gt;{'bug_group'} = [join(', ', @removed_names),
</span><span class="cx">                                    join(', ', @added_names)];
</span><span class="cx">     }
</span><del>-    
</del><ins>+
+    # Flags
+    my ($removed, $added) = Bugzilla::Flag-&gt;update_flags($self, $old_bug, $delta_ts);
+    if ($removed || $added) {
+        $changes-&gt;{'flagtypes.name'} = [$removed, $added];
+    }
+
</ins><span class="cx">     # Comments
</span><span class="cx">     foreach my $comment (@{$self-&gt;{added_comments} || []}) {
</span><del>-        my $columns = join(',', keys %$comment);
-        my @values  = values %$comment;
-        my $qmarks  = join(',', ('?') x @values);
-        $dbh-&gt;do(&quot;INSERT INTO longdescs (bug_id, who, bug_when, $columns)
-                       VALUES (?,?,?,$qmarks)&quot;, undef,
-                 $self-&gt;bug_id, Bugzilla-&gt;user-&gt;id, $delta_ts, @values);
-        if ($comment-&gt;{work_time}) {
-            LogActivityEntry($self-&gt;id, &quot;work_time&quot;, &quot;&quot;, $comment-&gt;{work_time},
</del><ins>+        # Override the Comment's timestamp to be identical to the update
+        # timestamp.
+        $comment-&gt;{bug_when} = $delta_ts;
+        $comment = Bugzilla::Comment-&gt;insert_create_data($comment);
+        if ($comment-&gt;work_time) {
+            LogActivityEntry($self-&gt;id, &quot;work_time&quot;, &quot;&quot;, $comment-&gt;work_time,
</ins><span class="cx">                 Bugzilla-&gt;user-&gt;id, $delta_ts);
</span><span class="cx">         }
</span><span class="cx">     }
</span><del>-    
-    foreach my $comment_id (keys %{$self-&gt;{comment_isprivate} || {}}) {
-        $dbh-&gt;do(&quot;UPDATE longdescs SET isprivate = ? WHERE comment_id = ?&quot;,
-                 undef, $self-&gt;{comment_isprivate}-&gt;{$comment_id}, $comment_id);
-        # XXX It'd be nice to track this in the bug activity.
</del><ins>+
+    # Comment Privacy 
+    foreach my $comment (@{$self-&gt;{comment_isprivate} || []}) {
+        $comment-&gt;update();
+        
+        my ($from, $to) 
+            = $comment-&gt;is_private ? (0, 1) : (1, 0);
+        LogActivityEntry($self-&gt;id, &quot;longdescs.isprivate&quot;, $from, $to, 
+                         Bugzilla-&gt;user-&gt;id, $delta_ts, $comment-&gt;id);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # Insert the values into the multiselect value tables
</span><span class="lines">@@ -664,6 +953,23 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    # See Also
+
+    my ($removed_see, $added_see) =
+        diff_arrays($old_bug-&gt;see_also, $self-&gt;see_also, 'name');
+
+    $_-&gt;remove_from_db foreach @$removed_see;
+    $_-&gt;insert_create_data($_) foreach @$added_see;
+
+    # If any changes were found, record it in the activity log
+    if (scalar @$removed_see || scalar @$added_see) {
+        $changes-&gt;{see_also} = [join(', ', map { $_-&gt;name } @$removed_see),
+                                join(', ', map { $_-&gt;name } @$added_see)];
+    }
+
+    $_-&gt;update foreach @{ $self-&gt;{_update_ref_bugs} || [] };
+    delete $self-&gt;{_update_ref_bugs};
+
</ins><span class="cx">     # Log bugs_activity items
</span><span class="cx">     # XXX Eventually, when bugs_activity is able to track the dupe_id,
</span><span class="cx">     # this code should go below the duplicates-table-updating code below.
</span><span class="lines">@@ -690,29 +996,37 @@
</span><span class="cx">         $changes-&gt;{'dup_id'} = [$old_dup || undef, $cur_dup || undef];
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    Bugzilla::Hook::process('bug-end_of_update', { bug       =&gt; $self,
-                                                   timestamp =&gt; $delta_ts,
-                                                   changes   =&gt; $changes,
-                                                 });
</del><ins>+    Bugzilla::Hook::process('bug_end_of_update', 
+        { bug =&gt; $self, timestamp =&gt; $delta_ts, changes =&gt; $changes,
+          old_bug =&gt; $old_bug });
</ins><span class="cx"> 
</span><span class="cx">     # If any change occurred, refresh the timestamp of the bug.
</span><del>-    if (scalar(keys %$changes) || $self-&gt;{added_comments}) {
</del><ins>+    if (scalar(keys %$changes) || $self-&gt;{added_comments}
+        || $self-&gt;{comment_isprivate})
+    {
</ins><span class="cx">         $dbh-&gt;do('UPDATE bugs SET delta_ts = ? WHERE bug_id = ?',
</span><span class="cx">                  undef, ($delta_ts, $self-&gt;id));
</span><span class="cx">         $self-&gt;{delta_ts} = $delta_ts;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    $dbh-&gt;bz_commit_transaction();
+
</ins><span class="cx">     # The only problem with this here is that update() is often called
</span><span class="cx">     # in the middle of a transaction, and if that transaction is rolled
</span><span class="cx">     # back, this change will *not* be rolled back. As we expect rollbacks
</span><span class="cx">     # to be extremely rare, that is OK for us.
</span><span class="cx">     $self-&gt;_sync_fulltext()
</span><del>-        if $self-&gt;{added_comments} || $changes-&gt;{short_desc};
</del><ins>+        if $self-&gt;{added_comments} || $changes-&gt;{short_desc}
+           || $self-&gt;{comment_isprivate};
</ins><span class="cx"> 
</span><span class="cx">     # Remove obsolete internal variables.
</span><span class="cx">     delete $self-&gt;{'_old_assigned_to'};
</span><span class="cx">     delete $self-&gt;{'_old_qa_contact'};
</span><span class="cx"> 
</span><ins>+    # Also flush the visible_bugs cache for this bug as the user's
+    # relationship with this bug may have changed.
+    delete Bugzilla-&gt;user-&gt;{_visible_bugs_cache}-&gt;{$self-&gt;id};
+
</ins><span class="cx">     return $changes;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -784,8 +1098,6 @@
</span><span class="cx">     # - flags
</span><span class="cx">     # - keywords
</span><span class="cx">     # - longdescs
</span><del>-    # - votes
-    # Also included are custom multi-select fields.
</del><span class="cx"> 
</span><span class="cx">     # Also, the attach_data table uses attachments.attach_id as a foreign
</span><span class="cx">     # key, and so indirectly depends on a bug deletion too.
</span><span class="lines">@@ -801,7 +1113,6 @@
</span><span class="cx">              undef, ($bug_id, $bug_id));
</span><span class="cx">     $dbh-&gt;do(&quot;DELETE FROM flags WHERE bug_id = ?&quot;, undef, $bug_id);
</span><span class="cx">     $dbh-&gt;do(&quot;DELETE FROM keywords WHERE bug_id = ?&quot;, undef, $bug_id);
</span><del>-    $dbh-&gt;do(&quot;DELETE FROM votes WHERE bug_id = ?&quot;, undef, $bug_id);
</del><span class="cx"> 
</span><span class="cx">     # The attach_data table doesn't depend on bugs.bug_id directly.
</span><span class="cx">     my $attach_ids =
</span><span class="lines">@@ -818,24 +1129,112 @@
</span><span class="cx">     $dbh-&gt;do(&quot;DELETE FROM bugs WHERE bug_id = ?&quot;, undef, $bug_id);
</span><span class="cx">     $dbh-&gt;do(&quot;DELETE FROM longdescs WHERE bug_id = ?&quot;, undef, $bug_id);
</span><span class="cx"> 
</span><del>-    # Delete entries from custom multi-select fields.
-    my @multi_selects = Bugzilla-&gt;get_fields({custom =&gt; 1, type =&gt; FIELD_TYPE_MULTI_SELECT});
-
-    foreach my $field (@multi_selects) {
-        $dbh-&gt;do(&quot;DELETE FROM bug_&quot; . $field-&gt;name . &quot; WHERE bug_id = ?&quot;, undef, $bug_id);
-    }
-
</del><span class="cx">     $dbh-&gt;bz_commit_transaction();
</span><span class="cx"> 
</span><span class="cx">     # The bugs_fulltext table doesn't support transactions.
</span><span class="cx">     $dbh-&gt;do(&quot;DELETE FROM bugs_fulltext WHERE bug_id = ?&quot;, undef, $bug_id);
</span><span class="cx"> 
</span><del>-    # Now this bug no longer exists
-    $self-&gt;DESTROY;
-    return $self;
</del><ins>+    undef $self;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #####################################################################
</span><ins>+# Sending Email After Bug Update
+#####################################################################
+
+sub send_changes {
+    my ($self, $changes, $vars) = @_;
+
+    my $user = Bugzilla-&gt;user;
+
+    my $old_qa  = $changes-&gt;{'qa_contact'}  
+                  ? $changes-&gt;{'qa_contact'}-&gt;[0] : '';
+    my $old_own = $changes-&gt;{'assigned_to'} 
+                  ? $changes-&gt;{'assigned_to'}-&gt;[0] : '';
+    my $old_cc  = $changes-&gt;{cc}
+                  ? $changes-&gt;{cc}-&gt;[0] : '';
+
+    my %forced = (
+        cc        =&gt; [split(/[,;]+/, $old_cc)],
+        owner     =&gt; $old_own,
+        qacontact =&gt; $old_qa,
+        changer   =&gt; $user,
+    );
+
+    _send_bugmail({ id =&gt; $self-&gt;id, type =&gt; 'bug', forced =&gt; \%forced }, 
+                  $vars);
+
+    # If the bug was marked as a duplicate, we need to notify users on the
+    # other bug of any changes to that bug.
+    my $new_dup_id = $changes-&gt;{'dup_id'} ? $changes-&gt;{'dup_id'}-&gt;[1] : undef;
+    if ($new_dup_id) {
+        _send_bugmail({ forced =&gt; { changer =&gt; $user }, type =&gt; &quot;dupe&quot;,
+                        id =&gt; $new_dup_id }, $vars);
+    }
+
+    # If there were changes in dependencies, we need to notify those
+    # dependencies.
+    if ($changes-&gt;{'bug_status'}) {
+        my ($old_status, $new_status) = @{ $changes-&gt;{'bug_status'} };
+
+        # If this bug has changed from opened to closed or vice-versa,
+        # then all of the bugs we block need to be notified.
+        if (is_open_state($old_status) ne is_open_state($new_status)) {
+            my $params = { forced   =&gt; { changer =&gt; $user },
+                           type     =&gt; 'dep',
+                           dep_only =&gt; 1,
+                           blocker  =&gt; $self,
+                           changes  =&gt; $changes };
+
+            foreach my $id (@{ $self-&gt;blocked }) {
+                $params-&gt;{id} = $id;
+                _send_bugmail($params, $vars);
+            }
+        }
+    }
+
+    # To get a list of all changed dependencies, convert the &quot;changes&quot; arrays
+    # into a long string, then collapse that string into unique numbers in
+    # a hash.
+    my $all_changed_deps = join(', ', @{ $changes-&gt;{'dependson'} || [] });
+    $all_changed_deps = join(', ', @{ $changes-&gt;{'blocked'} || [] },
+                                   $all_changed_deps);
+    my %changed_deps = map { $_ =&gt; 1 } split(', ', $all_changed_deps);
+    # When clearning one field (say, blocks) and filling in the other
+    # (say, dependson), an empty string can get into the hash and cause
+    # an error later.
+    delete $changed_deps{''};
+
+    foreach my $id (sort { $a &lt;=&gt; $b } (keys %changed_deps)) {
+        _send_bugmail({ forced =&gt; { changer =&gt; $user }, type =&gt; &quot;dep&quot;,
+                         id =&gt; $id }, $vars);
+    }
+
+    # Sending emails for the referenced bugs.
+    foreach my $ref_bug_id (uniq @{ $self-&gt;{see_also_changes} || [] }) {
+        _send_bugmail({ forced =&gt; { changer =&gt; $user },
+                        id =&gt; $ref_bug_id }, $vars);
+    }
+}
+
+sub _send_bugmail {
+    my ($params, $vars) = @_;
+
+    require Bugzilla::BugMail;
+
+    my $results = 
+        Bugzilla::BugMail::Send($params-&gt;{'id'}, $params-&gt;{'forced'}, $params);
+
+    if (Bugzilla-&gt;usage_mode == USAGE_MODE_BROWSER) {
+        my $template = Bugzilla-&gt;template;
+        $vars-&gt;{$_} = $params-&gt;{$_} foreach keys %$params;
+        $vars-&gt;{'sent_bugmail'} = $results;
+        $template-&gt;process(&quot;bug/process/results.html.tmpl&quot;, $vars)
+            || ThrowTemplateError($template-&gt;error());
+        $vars-&gt;{'header_done'} = 1;
+    }
+}
+
+#####################################################################
</ins><span class="cx"> # Validators
</span><span class="cx"> #####################################################################
</span><span class="cx"> 
</span><span class="lines">@@ -869,8 +1268,10 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _check_assigned_to {
</span><del>-    my ($invocant, $assignee, $component) = @_;
</del><ins>+    my ($invocant, $assignee, undef, $params) = @_;
</ins><span class="cx">     my $user = Bugzilla-&gt;user;
</span><ins>+    my $component = blessed($invocant) ? $invocant-&gt;component_obj
+                                       : $params-&gt;{component};
</ins><span class="cx"> 
</span><span class="cx">     # Default assignee is the component owner.
</span><span class="cx">     my $id;
</span><span class="lines">@@ -907,36 +1308,29 @@
</span><span class="cx">     return $url;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _check_bug_severity {
-    my ($invocant, $severity) = @_;
-    $severity = trim($severity);
-    check_field('bug_severity', $severity);
-    return $severity;
-}
-
</del><span class="cx"> sub _check_bug_status {
</span><del>-    my ($invocant, $new_status, $product, $comment) = @_;
</del><ins>+    my ($invocant, $new_status, undef, $params) = @_;
</ins><span class="cx">     my $user = Bugzilla-&gt;user;
</span><span class="cx">     my @valid_statuses;
</span><span class="cx">     my $old_status; # Note that this is undef for new bugs.
</span><span class="cx"> 
</span><ins>+    my ($product, $comment);
</ins><span class="cx">     if (ref $invocant) {
</span><del>-        @valid_statuses = @{$invocant-&gt;status-&gt;can_change_to};
</del><ins>+        @valid_statuses = @{$invocant-&gt;statuses_available};
</ins><span class="cx">         $product = $invocant-&gt;product_obj;
</span><span class="cx">         $old_status = $invocant-&gt;status;
</span><span class="cx">         my $comments = $invocant-&gt;{added_comments} || [];
</span><span class="cx">         $comment = $comments-&gt;[-1];
</span><span class="cx">     }
</span><span class="cx">     else {
</span><ins>+        $product = $params-&gt;{product};
+        $comment = $params-&gt;{comment};
</ins><span class="cx">         @valid_statuses = @{Bugzilla::Status-&gt;can_change_to()};
</span><ins>+        if (!$product-&gt;allows_unconfirmed) {
+            @valid_statuses = grep {$_-&gt;name ne 'UNCONFIRMED'} @valid_statuses;
+        }
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (!$product-&gt;votes_to_confirm) {
-        # UNCONFIRMED becomes an invalid status if votes_to_confirm is 0,
-        # even if you are in editbugs.
-        @valid_statuses = grep {$_-&gt;name ne 'UNCONFIRMED'} @valid_statuses;
-    }
-
</del><span class="cx">     # Check permissions for users filing new bugs.
</span><span class="cx">     if (!ref $invocant) {
</span><span class="cx">         if ($user-&gt;in_group('editbugs', $product-&gt;id)
</span><span class="lines">@@ -965,9 +1359,13 @@
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">     }
</span><ins>+
</ins><span class="cx">     # Time to validate the bug status.
</span><span class="cx">     $new_status = Bugzilla::Status-&gt;check($new_status) unless ref($new_status);
</span><del>-    if (!grep {$_-&gt;name eq $new_status-&gt;name} @valid_statuses) {
</del><ins>+    # We skip this check if we are changing from a status to itself.
+    if ( (!$old_status || $old_status-&gt;id != $new_status-&gt;id)
+          &amp;&amp; !grep {$_-&gt;name eq $new_status-&gt;name} @valid_statuses) 
+    {
</ins><span class="cx">         ThrowUserError('illegal_bug_status_transition',
</span><span class="cx">                        { old =&gt; $old_status, new =&gt; $new_status });
</span><span class="cx">     }
</span><span class="lines">@@ -980,7 +1378,10 @@
</span><span class="cx">         
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    if (ref $invocant &amp;&amp; $new_status-&gt;name eq 'ASSIGNED'
</del><ins>+    if (ref $invocant 
+        &amp;&amp; ($new_status-&gt;name eq 'IN_PROGRESS'
+            # Backwards-compat for the old default workflow.
+            or $new_status-&gt;name eq 'ASSIGNED')
</ins><span class="cx">         &amp;&amp; Bugzilla-&gt;params-&gt;{&quot;usetargetmilestone&quot;}
</span><span class="cx">         &amp;&amp; Bugzilla-&gt;params-&gt;{&quot;musthavemilestoneonaccept&quot;}
</span><span class="cx">         # musthavemilestoneonaccept applies only if at least two
</span><span class="lines">@@ -991,16 +1392,25 @@
</span><span class="cx">         ThrowUserError(&quot;milestone_required&quot;, { bug =&gt; $invocant });
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    return $new_status-&gt;name if ref $invocant;
-    return ($new_status-&gt;name, $new_status-&gt;name eq 'UNCONFIRMED' ? 0 : 1);
</del><ins>+    if (!blessed $invocant) {
+        $params-&gt;{everconfirmed} = $new_status-&gt;name eq 'UNCONFIRMED' ? 0 : 1;
+    }
+
+    return $new_status-&gt;name;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _check_cc {
</span><del>-    my ($invocant, $component, $ccs) = @_;
</del><ins>+    my ($invocant, $ccs, undef, $params) = @_;
+    my $component = blessed($invocant) ? $invocant-&gt;component_obj
+                                       : $params-&gt;{component};
</ins><span class="cx">     return [map {$_-&gt;id} @{$component-&gt;initial_cc}] unless $ccs;
</span><span class="cx"> 
</span><ins>+    # Allow comma-separated input as well as arrayrefs.
+    $ccs = [split(/[,;]+/, $ccs)] if !ref $ccs;
+
</ins><span class="cx">     my %cc_ids;
</span><span class="cx">     foreach my $person (@$ccs) {
</span><ins>+        $person = trim($person);
</ins><span class="cx">         next unless $person;
</span><span class="cx">         my $id = login_to_id($person, THROW_ERROR);
</span><span class="cx">         $cc_ids{$id} = 1;
</span><span class="lines">@@ -1013,52 +1423,66 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _check_comment {
</span><del>-    my ($invocant, $comment) = @_;
</del><ins>+    my ($invocant, $comment_txt, undef, $params) = @_;
</ins><span class="cx"> 
</span><del>-    $comment = '' unless defined $comment;
</del><ins>+    # Comment can be empty. We should force it to be empty if the text is undef
+    if (!defined $comment_txt) {
+        $comment_txt = '';
+    }
</ins><span class="cx"> 
</span><del>-    # Remove any trailing whitespace. Leading whitespace could be
-    # a valid part of the comment.
-    $comment =~ s/\s*$//s;
-    $comment =~ s/\r\n?/\n/g; # Get rid of \r.
</del><ins>+    # Load up some data
+    my $isprivate = delete $params-&gt;{comment_is_private};
+    my $timestamp = $params-&gt;{creation_ts};
</ins><span class="cx"> 
</span><del>-    ThrowUserError('comment_too_long') if length($comment) &gt; MAX_COMMENT_LENGTH;
-    return $comment;
-}
</del><ins>+    # Create the new comment so we can check it
+    my $comment = {
+        thetext  =&gt; $comment_txt,
+        bug_when =&gt; $timestamp,
+    };
</ins><span class="cx"> 
</span><del>-sub _check_commentprivacy {
-    my ($invocant, $comment_privacy) = @_;
-    my $insider_group = Bugzilla-&gt;params-&gt;{&quot;insidergroup&quot;};
-    return ($insider_group &amp;&amp; Bugzilla-&gt;user-&gt;in_group($insider_group) 
-            &amp;&amp; $comment_privacy) ? 1 : 0;
-}
</del><ins>+    # We don't include the &quot;isprivate&quot; column unless it was specified. 
+    # This allows it to fall back to its database default.
+    if (defined $isprivate) {
+        $comment-&gt;{isprivate} = $isprivate;
+    }
</ins><span class="cx"> 
</span><del>-sub _check_comment_type {
-    my ($invocant, $type) = @_;
-    detaint_natural($type)
-      || ThrowCodeError('bad_arg', { argument =&gt; 'type', 
-                                     function =&gt; caller });
-    return $type;
</del><ins>+    # Validate comment. We have to do this special as a comment normally
+    # requires a bug to be already created. For a new bug, the first comment
+    # obviously can't get the bug if the bug is created after this
+    # (see bug 590334)
+    Bugzilla::Comment-&gt;check_required_create_fields($comment);
+    $comment = Bugzilla::Comment-&gt;run_create_validators($comment,
+                                                        { skip =&gt; ['bug_id'] }
+    );
+
+    return $comment; 
+
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _check_component {
</span><del>-    my ($invocant, $name, $product) = @_;
</del><ins>+    my ($invocant, $name, undef, $params) = @_;
</ins><span class="cx">     $name = trim($name);
</span><span class="cx">     $name || ThrowUserError(&quot;require_component&quot;);
</span><del>-    ($product = $invocant-&gt;product_obj) if ref $invocant;
</del><ins>+    my $product = blessed($invocant) ? $invocant-&gt;product_obj 
+                                     : $params-&gt;{product};
</ins><span class="cx">     my $obj = Bugzilla::Component-&gt;check({ product =&gt; $product, name =&gt; $name });
</span><span class="cx">     return $obj;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub _check_creation_ts {
+    return Bugzilla-&gt;dbh-&gt;selectrow_array('SELECT LOCALTIMESTAMP(0)');
+}
+
</ins><span class="cx"> sub _check_deadline {
</span><span class="cx">     my ($invocant, $date) = @_;
</span><del>-    
-    # Check time-tracking permissions.
-    my $tt_group = Bugzilla-&gt;params-&gt;{&quot;timetrackinggroup&quot;};
-    # deadline() returns '' instead of undef if no deadline is set.
-    my $current = ref $invocant ? ($invocant-&gt;deadline || undef) : undef;
-    return $current unless $tt_group &amp;&amp; Bugzilla-&gt;user-&gt;in_group($tt_group);
-    
</del><ins>+
+    # When filing bugs, we're forgiving and just return undef if
+    # the user isn't a timetracker. When updating bugs, check_can_change_field
+    # controls permissions, so we don't want to check them here.
+    if (!ref $invocant and !Bugzilla-&gt;user-&gt;is_timetracker) {
+        return undef;
+    }
+
</ins><span class="cx">     # Validate entered deadline
</span><span class="cx">     $date = trim($date);
</span><span class="cx">     return undef if !$date;
</span><span class="lines">@@ -1081,12 +1505,14 @@
</span><span class="cx"> 
</span><span class="cx">     my %deps_in = (dependson =&gt; $depends_on || '', blocked =&gt; $blocks || '');
</span><span class="cx"> 
</span><del>-    foreach my $type qw(dependson blocked) {
-        my @bug_ids = split(/[\s,]+/, $deps_in{$type});
</del><ins>+    foreach my $type (qw(dependson blocked)) {
+        my @bug_ids = ref($deps_in{$type}) 
+            ? @{$deps_in{$type}} 
+            : split(/[\s,]+/, $deps_in{$type});
</ins><span class="cx">         # Eliminate nulls.
</span><span class="cx">         @bug_ids = grep {$_} @bug_ids;
</span><del>-        # We do Validate up here to make sure all aliases are converted to IDs.
-        ValidateBugID($_, $type) foreach @bug_ids;
</del><ins>+        # We do this up here to make sure all aliases are converted to IDs.
+        @bug_ids = map { $invocant-&gt;check($_, $type)-&gt;id } @bug_ids;
</ins><span class="cx">        
</span><span class="cx">         my @check_access = @bug_ids;
</span><span class="cx">         # When we're updating a bug, only added or removed bug_ids are 
</span><span class="lines">@@ -1108,11 +1534,10 @@
</span><span class="cx"> 
</span><span class="cx">         my $user = Bugzilla-&gt;user;
</span><span class="cx">         foreach my $modified_id (@check_access) {
</span><del>-            ValidateBugID($modified_id);
</del><ins>+            my $delta_bug = $invocant-&gt;check($modified_id);
</ins><span class="cx">             # Under strict isolation, you can't modify a bug if you can't
</span><span class="cx">             # edit it, even if you can see it.
</span><span class="cx">             if (Bugzilla-&gt;params-&gt;{&quot;strict_isolation&quot;}) {
</span><del>-                my $delta_bug = new Bugzilla::Bug($modified_id);
</del><span class="cx">                 if (!$user-&gt;can_edit_product($delta_bug-&gt;{'product_id'})) {
</span><span class="cx">                     ThrowUserError(&quot;illegal_change_deps&quot;, {field =&gt; $type});
</span><span class="cx">                 }
</span><span class="lines">@@ -1135,38 +1560,23 @@
</span><span class="cx">     
</span><span class="cx">     $dupe_of = trim($dupe_of);
</span><span class="cx">     $dupe_of || ThrowCodeError('undefined_field', { field =&gt; 'dup_id' });
</span><del>-    # Validate the bug ID. The second argument will force ValidateBugID() to
-    # only make sure that the bug exists, and convert the alias to the bug ID
</del><ins>+    # Validate the bug ID. The second argument will force check() to only
+    # make sure that the bug exists, and convert the alias to the bug ID
</ins><span class="cx">     # if a string is passed. Group restrictions are checked below.
</span><del>-    ValidateBugID($dupe_of, 'dup_id');
</del><ins>+    my $dupe_of_bug = $self-&gt;check($dupe_of, 'dup_id');
+    $dupe_of = $dupe_of_bug-&gt;id;
</ins><span class="cx"> 
</span><span class="cx">     # If the dupe is unchanged, we have nothing more to check.
</span><span class="cx">     return $dupe_of if ($self-&gt;dup_id &amp;&amp; $self-&gt;dup_id == $dupe_of);
</span><span class="cx"> 
</span><span class="cx">     # If we come here, then the duplicate is new. We have to make sure
</span><span class="cx">     # that we can view/change it (issue A on bug 96085).
</span><del>-    check_is_visible($dupe_of);
</del><ins>+    $dupe_of_bug-&gt;check_is_visible;
</ins><span class="cx"> 
</span><span class="cx">     # Make sure a loop isn't created when marking this bug
</span><span class="cx">     # as duplicate.
</span><del>-    my %dupes;
-    my $this_dup = $dupe_of;
-    my $sth = $dbh-&gt;prepare('SELECT dupe_of FROM duplicates WHERE dupe = ?');
</del><ins>+   _resolve_ultimate_dup_id($self-&gt;id, $dupe_of, 1);
</ins><span class="cx"> 
</span><del>-    while ($this_dup) {
-        if ($this_dup == $self-&gt;id) {
-            ThrowUserError('dupe_loop_detected', { bug_id  =&gt; $self-&gt;id,
-                                                   dupe_of =&gt; $dupe_of });
-        }
-        # If $dupes{$this_dup} is already set to 1, then a loop
-        # already exists which does not involve this bug.
-        # As the user is not responsible for this loop, do not
-        # prevent him from marking this bug as a duplicate.
-        last if exists $dupes{$this_dup};
-        $dupes{$this_dup} = 1;
-        $this_dup = $dbh-&gt;selectrow_array($sth, undef, $this_dup);
-    }
-
</del><span class="cx">     my $cur_dup = $self-&gt;dup_id || 0;
</span><span class="cx">     if ($cur_dup != $dupe_of &amp;&amp; Bugzilla-&gt;params-&gt;{'commentonduplicate'}
</span><span class="cx">         &amp;&amp; !$self-&gt;{added_comments})
</span><span class="lines">@@ -1177,7 +1587,6 @@
</span><span class="cx">     # Should we add the reporter to the CC list of the new bug?
</span><span class="cx">     # If he can see the bug...
</span><span class="cx">     if ($self-&gt;reporter-&gt;can_see_bug($dupe_of)) {
</span><del>-        my $dupe_of_bug = new Bugzilla::Bug($dupe_of);
</del><span class="cx">         # We only add him if he's not the reporter of the other bug.
</span><span class="cx">         $self-&gt;{_add_dup_cc} = 1
</span><span class="cx">             if $dupe_of_bug-&gt;reporter-&gt;id != $self-&gt;reporter-&gt;id;
</span><span class="lines">@@ -1202,9 +1611,7 @@
</span><span class="cx">             my $vars = {};
</span><span class="cx">             my $template = Bugzilla-&gt;template;
</span><span class="cx">             # Ask the user what they want to do about the reporter.
</span><del>-            $vars-&gt;{'cclist_accessible'} = $dbh-&gt;selectrow_array(
-                q{SELECT cclist_accessible FROM bugs WHERE bug_id = ?},
-                undef, $dupe_of);
</del><ins>+            $vars-&gt;{'cclist_accessible'} = $dupe_of_bug-&gt;cclist_accessible;
</ins><span class="cx">             $vars-&gt;{'original_bug_id'} = $dupe_of;
</span><span class="cx">             $vars-&gt;{'duplicate_bug_id'} = $self-&gt;id;
</span><span class="cx">             print $cgi-&gt;header();
</span><span class="lines">@@ -1217,71 +1624,67 @@
</span><span class="cx">     return $dupe_of;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _check_estimated_time {
-    return $_[0]-&gt;_check_time($_[1], 'estimated_time');
-}
-
</del><span class="cx"> sub _check_groups {
</span><del>-    my ($invocant, $product, $group_ids) = @_;
</del><ins>+    my ($invocant, $group_names, undef, $params) = @_;
</ins><span class="cx"> 
</span><del>-    my $user = Bugzilla-&gt;user;
-
</del><ins>+    my $bug_id = blessed($invocant) ? $invocant-&gt;id : undef;
+    my $product = blessed($invocant) ? $invocant-&gt;product_obj 
+                                     : $params-&gt;{product};
</ins><span class="cx">     my %add_groups;
</span><del>-    my $controls = $product-&gt;group_controls;
</del><span class="cx"> 
</span><del>-    foreach my $id (@$group_ids) {
-        my $group = new Bugzilla::Group($id)
-            || ThrowUserError(&quot;invalid_group_ID&quot;);
-
-        # This can only happen if somebody hacked the enter_bug form.
-        ThrowCodeError(&quot;inactive_group&quot;, { name =&gt; $group-&gt;name })
-            unless $group-&gt;is_active;
-
-        my $membercontrol = $controls-&gt;{$id}
-                            &amp;&amp; $controls-&gt;{$id}-&gt;{membercontrol};
-        my $othercontrol  = $controls-&gt;{$id} 
-                            &amp;&amp; $controls-&gt;{$id}-&gt;{othercontrol};
-        
-        my $permit = ($membercontrol &amp;&amp; $user-&gt;in_group($group-&gt;name))
-                     || $othercontrol;
-
-        $add_groups{$id} = 1 if $permit;
</del><ins>+    # In email or WebServices, when the &quot;groups&quot; item actually 
+    # isn't specified, then just add the default groups.
+    if (!defined $group_names) {
+        my $available = $product-&gt;groups_available;
+        foreach my $group (@$available) {
+            $add_groups{$group-&gt;id} = $group if $group-&gt;{is_default};
+        }
</ins><span class="cx">     }
</span><ins>+    else {
+        # Allow a comma-separated list, for email_in.pl.
+        $group_names = [map { trim($_) } split(',', $group_names)]
+            if !ref $group_names;
</ins><span class="cx"> 
</span><del>-    foreach my $id (keys %$controls) {
-        next unless $controls-&gt;{$id}-&gt;{'group'}-&gt;is_active;
-        my $membercontrol = $controls-&gt;{$id}-&gt;{membercontrol} || 0;
-        my $othercontrol  = $controls-&gt;{$id}-&gt;{othercontrol}  || 0;
</del><ins>+        # First check all the groups they chose to set.
+        my %args = ( product =&gt; $product-&gt;name, bug_id =&gt; $bug_id, action =&gt; 'add' );
+        foreach my $name (@$group_names) {
+            my $group = Bugzilla::Group-&gt;check_no_disclose({ %args, name =&gt; $name });
</ins><span class="cx"> 
</span><del>-        # Add groups required
-        if ($membercontrol == CONTROLMAPMANDATORY
-            || ($othercontrol == CONTROLMAPMANDATORY
-                &amp;&amp; !$user-&gt;in_group_id($id))) 
-        {
-            # User had no option, bug needs to be in this group.
-            $add_groups{$id} = 1;
</del><ins>+            if (!$product-&gt;group_is_settable($group)) {
+                ThrowUserError('group_restriction_not_allowed', { %args, name =&gt; $name });
+            }
+            $add_groups{$group-&gt;id} = $group;
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    my @add_groups = keys %add_groups;
</del><ins>+    # Now enforce mandatory groups.
+    $add_groups{$_-&gt;id} = $_ foreach @{ $product-&gt;groups_mandatory };
+
+    my @add_groups = values %add_groups;
</ins><span class="cx">     return \@add_groups;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _check_keywords {
</span><del>-    my ($invocant, $keyword_string, $product) = @_;
-    $keyword_string = trim($keyword_string);
-    return [] if !$keyword_string;
</del><ins>+    my ($invocant, $keywords_in, undef, $params) = @_;
+
+    return [] if !defined $keywords_in;
+
+    my $keyword_array = $keywords_in;
+    if (!ref $keyword_array) {
+        $keywords_in = trim($keywords_in);
+        $keyword_array = [split(/[\s,]+/, $keywords_in)];
+    }
</ins><span class="cx">     
</span><span class="cx">     # On creation, only editbugs users can set keywords.
</span><span class="cx">     if (!ref $invocant) {
</span><ins>+        my $product = $params-&gt;{product};
</ins><span class="cx">         return [] if !Bugzilla-&gt;user-&gt;in_group('editbugs', $product-&gt;id);
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     my %keywords;
</span><del>-    foreach my $keyword (split(/[\s,]+/, $keyword_string)) {
</del><ins>+    foreach my $keyword (@$keyword_array) {
</ins><span class="cx">         next unless $keyword;
</span><del>-        my $obj = new Bugzilla::Keyword({ name =&gt; $keyword });
-        ThrowUserError(&quot;unknown_keyword&quot;, { keyword =&gt; $keyword }) if !$obj;
</del><ins>+        my $obj = Bugzilla::Keyword-&gt;check($keyword);
</ins><span class="cx">         $keywords{$obj-&gt;id} = $obj;
</span><span class="cx">     }
</span><span class="cx">     return [values %keywords];
</span><span class="lines">@@ -1297,34 +1700,23 @@
</span><span class="cx">     }
</span><span class="cx">     # Check that the product exists and that the user
</span><span class="cx">     # is allowed to enter bugs into this product.
</span><del>-    Bugzilla-&gt;user-&gt;can_enter_product($name, THROW_ERROR);
-    # can_enter_product already does everything that check_product
-    # would do for us, so we don't need to use it.
-    return new Bugzilla::Product({ name =&gt; $name });
</del><ins>+    my $product = Bugzilla-&gt;user-&gt;can_enter_product($name, THROW_ERROR);
+    return $product;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _check_op_sys {
-    my ($invocant, $op_sys) = @_;
-    $op_sys = trim($op_sys);
-    check_field('op_sys', $op_sys);
-    return $op_sys;
-}
-
</del><span class="cx"> sub _check_priority {
</span><span class="cx">     my ($invocant, $priority) = @_;
</span><span class="cx">     if (!ref $invocant &amp;&amp; !Bugzilla-&gt;params-&gt;{'letsubmitterchoosepriority'}) {
</span><span class="cx">         $priority = Bugzilla-&gt;params-&gt;{'defaultpriority'};
</span><span class="cx">     }
</span><del>-    $priority = trim($priority);
-    check_field('priority', $priority);
-
-    return $priority;
</del><ins>+    return $invocant-&gt;_check_select_field($priority, 'priority');
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _check_qa_contact {
</span><del>-    my ($invocant, $qa_contact, $component) = @_;
</del><ins>+    my ($invocant, $qa_contact, undef, $params) = @_;
</ins><span class="cx">     $qa_contact = trim($qa_contact) if !ref $qa_contact;
</span><del>-    
</del><ins>+    my $component = blessed($invocant) ? $invocant-&gt;component_obj
+                                       : $params-&gt;{component};
</ins><span class="cx">     my $id;
</span><span class="cx">     if (!ref $invocant) {
</span><span class="cx">         # Bugs get no QA Contact on creation if useqacontact is off.
</span><span class="lines">@@ -1354,17 +1746,6 @@
</span><span class="cx">     return $id || undef;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _check_remaining_time {
-    return $_[0]-&gt;_check_time($_[1], 'remaining_time');
-}
-
-sub _check_rep_platform {
-    my ($invocant, $platform) = @_;
-    $platform = trim($platform);
-    check_field('rep_platform', $platform);
-    return $platform;
-}
-
</del><span class="cx"> sub _check_reporter {
</span><span class="cx">     my $invocant = shift;
</span><span class="cx">     my $reporter;
</span><span class="lines">@@ -1375,8 +1756,8 @@
</span><span class="cx">     else {
</span><span class="cx">         # On bug creation, the reporter is the logged in user
</span><span class="cx">         # (meaning that he must be logged in first!).
</span><ins>+        Bugzilla-&gt;login(LOGIN_REQUIRED);
</ins><span class="cx">         $reporter = Bugzilla-&gt;user-&gt;id;
</span><del>-        $reporter || ThrowCodeError('invalid_user');
</del><span class="cx">     }
</span><span class="cx">     return $reporter;
</span><span class="cx"> }
</span><span class="lines">@@ -1392,19 +1773,22 @@
</span><span class="cx">         if !$resolution &amp;&amp; !$self-&gt;status-&gt;is_open;
</span><span class="cx">     
</span><span class="cx">     # Make sure this is a valid resolution.
</span><del>-    check_field('resolution', $resolution);
</del><ins>+    $resolution = $self-&gt;_check_select_field($resolution, 'resolution');
</ins><span class="cx"> 
</span><span class="cx">     # Don't allow open bugs to have resolutions.
</span><span class="cx">     ThrowUserError('resolution_not_allowed') if $self-&gt;status-&gt;is_open;
</span><span class="cx">     
</span><span class="cx">     # Check noresolveonopenblockers.
</span><del>-    if (Bugzilla-&gt;params-&gt;{&quot;noresolveonopenblockers&quot;} &amp;&amp; $resolution eq 'FIXED')
</del><ins>+    if (Bugzilla-&gt;params-&gt;{&quot;noresolveonopenblockers&quot;}
+        &amp;&amp; $resolution eq 'FIXED'
+        &amp;&amp; (!$self-&gt;resolution || $resolution ne $self-&gt;resolution)
+        &amp;&amp; scalar @{$self-&gt;dependson})
</ins><span class="cx">     {
</span><del>-        my @dependencies = CountOpenDependencies($self-&gt;id);
-        if (@dependencies) {
</del><ins>+        my $dep_bugs = Bugzilla::Bug-&gt;new_from_list($self-&gt;dependson);
+        my $count_open = grep { $_-&gt;isopened } @$dep_bugs;
+        if ($count_open) {
</ins><span class="cx">             ThrowUserError(&quot;still_unresolved_bugs&quot;,
</span><del>-                           { dependencies     =&gt; \@dependencies,
-                             dependency_count =&gt; scalar @dependencies });
</del><ins>+                           { bug_id =&gt; $self-&gt;id, dep_count =&gt; $count_open });
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -1427,6 +1811,10 @@
</span><span class="cx">     if (!defined $short_desc || $short_desc eq '') {
</span><span class="cx">         ThrowUserError(&quot;require_summary&quot;);
</span><span class="cx">     }
</span><ins>+    if (length($short_desc) &gt; MAX_FREETEXT_LENGTH) {
+        ThrowUserError('freetext_too_long', 
+                       { field =&gt; 'short_desc', text =&gt; $short_desc });
+    }
</ins><span class="cx">     return $short_desc;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1505,46 +1893,81 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub _check_tag_name {
+    my ($invocant, $tag) = @_;
+
+    $tag = clean_text($tag);
+    $tag || ThrowUserError('no_tag_to_edit');
+    ThrowUserError('tag_name_too_long') if length($tag) &gt; MAX_LEN_QUERY_NAME;
+    trick_taint($tag);
+    # Tags are all lowercase.
+    return lc($tag);
+}
+
</ins><span class="cx"> sub _check_target_milestone {
</span><del>-    my ($invocant, $target, $product) = @_;
-    $product = $invocant-&gt;product_obj if ref $invocant;
-
</del><ins>+    my ($invocant, $target, undef, $params) = @_;
+    my $product = blessed($invocant) ? $invocant-&gt;product_obj 
+                                     : $params-&gt;{product};
</ins><span class="cx">     $target = trim($target);
</span><span class="cx">     $target = $product-&gt;default_milestone if !defined $target;
</span><del>-    check_field('target_milestone', $target,
-            [map($_-&gt;name, @{$product-&gt;milestones})]);
-    return $target;
</del><ins>+    my $object = Bugzilla::Milestone-&gt;check(
+        { product =&gt; $product, name =&gt; $target });
+    return $object-&gt;name;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _check_time {
-    my ($invocant, $time, $field) = @_;
</del><ins>+sub _check_time_field {
+    my ($invocant, $value, $field, $params) = @_;
</ins><span class="cx"> 
</span><del>-    my $current = 0;
-    if (ref $invocant &amp;&amp; $field ne 'work_time') {
-        $current = $invocant-&gt;$field;
</del><ins>+    # When filing bugs, we're forgiving and just return 0 if
+    # the user isn't a timetracker. When updating bugs, check_can_change_field
+    # controls permissions, so we don't want to check them here.
+    if (!ref $invocant and !Bugzilla-&gt;user-&gt;is_timetracker) {
+        return 0;
</ins><span class="cx">     }
</span><del>-    my $tt_group = Bugzilla-&gt;params-&gt;{&quot;timetrackinggroup&quot;};
-    return $current unless $tt_group &amp;&amp; Bugzilla-&gt;user-&gt;in_group($tt_group);
-    
-    $time = trim($time) || 0;
-    ValidateTime($time, $field);
-    return $time;
</del><ins>+
+    # check_time is in Bugzilla::Object.
+    return $invocant-&gt;check_time($value, $field, $params);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _check_version {
</span><del>-    my ($invocant, $version, $product) = @_;
</del><ins>+    my ($invocant, $version, undef, $params) = @_;
</ins><span class="cx">     $version = trim($version);
</span><del>-    ($product = $invocant-&gt;product_obj) if ref $invocant;
-    check_field('version', $version, [map($_-&gt;name, @{$product-&gt;versions})]);
-    return $version;
</del><ins>+    my $product = blessed($invocant) ? $invocant-&gt;product_obj 
+                                     : $params-&gt;{product};
+    my $object = 
+        Bugzilla::Version-&gt;check({ product =&gt; $product, name =&gt; $version });
+    return $object-&gt;name;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _check_work_time {
-    return $_[0]-&gt;_check_time($_[1], 'work_time');
</del><ins>+# Custom Field Validators
+
+sub _check_field_is_mandatory {
+    my ($invocant, $value, $field, $params) = @_;
+
+    if (!blessed($field)) {
+        $field = Bugzilla::Field-&gt;new({ name =&gt; $field });
+        return if !$field;
+    }
+
+    return if !$field-&gt;is_mandatory;
+
+    return if !$field-&gt;is_visible_on_bug($params || $invocant);
+
+    if (ref($value) eq 'ARRAY') {
+        $value = join('', @$value);
+    }
+
+    $value = trim($value);
+    if (!defined($value)
+        or $value eq &quot;&quot;
+        or ($value eq '---' and $field-&gt;type == FIELD_TYPE_SINGLE_SELECT)
+        or ($value =~ EMPTY_DATETIME_REGEX
+            and $field-&gt;type == FIELD_TYPE_DATETIME))
+    {
+        ThrowUserError('required_field', { field =&gt; $field });
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-# Custom Field Validators
-
</del><span class="cx"> sub _check_datetime_field {
</span><span class="cx">     my ($invocant, $date_time) = @_;
</span><span class="cx"> 
</span><span class="lines">@@ -1570,33 +1993,84 @@
</span><span class="cx"> sub _check_default_field { return defined $_[1] ? trim($_[1]) : ''; }
</span><span class="cx"> 
</span><span class="cx"> sub _check_freetext_field {
</span><del>-    my ($invocant, $text) = @_;
</del><ins>+    my ($invocant, $text, $field) = @_;
</ins><span class="cx"> 
</span><span class="cx">     $text = (defined $text) ? trim($text) : '';
</span><span class="cx">     if (length($text) &gt; MAX_FREETEXT_LENGTH) {
</span><del>-        ThrowUserError('freetext_too_long', { text =&gt; $text });
</del><ins>+        ThrowUserError('freetext_too_long', 
+                       { field =&gt; $field, text =&gt; $text });
</ins><span class="cx">     }
</span><span class="cx">     return $text;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _check_multi_select_field {
</span><span class="cx">     my ($invocant, $values, $field) = @_;
</span><ins>+
+    # Allow users (mostly email_in.pl) to specify multi-selects as
+    # comma-separated values.
+    if (defined $values and !ref $values) {
+        # We don't split on spaces because multi-select values can and often
+        # do have spaces in them. (Theoretically they can have commas in them
+        # too, but that's much less common and people should be able to work
+        # around it pretty cleanly, if they want to use email_in.pl.)
+        $values = [split(',', $values)];
+    }
+
</ins><span class="cx">     return [] if !$values;
</span><ins>+    my @checked_values;
</ins><span class="cx">     foreach my $value (@$values) {
</span><del>-        $value = trim($value);
-        check_field($field, $value);
-        trick_taint($value);
</del><ins>+        push(@checked_values, $invocant-&gt;_check_select_field($value, $field));
</ins><span class="cx">     }
</span><del>-    return $values;
</del><ins>+    return \@checked_values;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _check_select_field {
</span><span class="cx">     my ($invocant, $value, $field) = @_;
</span><del>-    $value = trim($value);
-    check_field($field, $value);
-    return $value;
</del><ins>+    my $object = Bugzilla::Field::Choice-&gt;type($field)-&gt;check($value);
+    return $object-&gt;name;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub _check_bugid_field {
+    my ($invocant, $value, $field) = @_;
+    return undef if !$value;
+    
+    # check that the value is a valid, visible bug id
+    my $checked_id = $invocant-&gt;check($value, $field)-&gt;id;
+    
+    # check for loop (can't have a loop if this is a new bug)
+    if (ref $invocant) {
+        _check_relationship_loop($field, $invocant-&gt;bug_id, $checked_id);
+    }
+
+    return $checked_id;
+}
+
+sub _check_relationship_loop {
+    # Generates a dependency tree for a given bug.  Calls itself recursively
+    # to generate sub-trees for the bug's dependencies.
+    my ($field, $bug_id, $dep_id, $ids) = @_;
+
+    # Don't do anything if this bug doesn't have any dependencies.
+    return unless defined($dep_id);
+
+    # Check whether we have seen this bug yet
+    $ids = {} unless defined $ids;
+    $ids-&gt;{$bug_id} = 1;
+    if ($ids-&gt;{$dep_id}) {
+        ThrowUserError(&quot;relationship_loop_single&quot;, {
+            'bug_id' =&gt; $bug_id,
+            'dep_id' =&gt; $dep_id,
+            'field_name' =&gt; $field});
+    }
+    
+    # Get this dependency's record from the database
+    my $dbh = Bugzilla-&gt;dbh;
+    my $next_dep_id = $dbh-&gt;selectrow_array(
+        &quot;SELECT $field FROM bugs WHERE bug_id = ?&quot;, undef, $dep_id);
+
+    _check_relationship_loop($field, $dep_id, $next_dep_id, $ids);
+}
+
</ins><span class="cx"> #####################################################################
</span><span class="cx"> # Class Accessors
</span><span class="cx"> #####################################################################
</span><span class="lines">@@ -1604,17 +2078,18 @@
</span><span class="cx"> sub fields {
</span><span class="cx">     my $class = shift;
</span><span class="cx"> 
</span><del>-    return (
</del><ins>+   my @fields =
+   (
</ins><span class="cx">         # Standard Fields
</span><span class="cx">         # Keep this ordering in sync with bugzilla.dtd.
</span><span class="cx">         qw(bug_id alias creation_ts short_desc delta_ts
</span><span class="cx">            reporter_accessible cclist_accessible
</span><span class="cx">            classification_id classification
</span><span class="cx">            product component version rep_platform op_sys
</span><del>-           bug_status resolution dup_id
</del><ins>+           bug_status resolution dup_id see_also
</ins><span class="cx">            bug_file_loc status_whiteboard keywords
</span><span class="cx">            priority bug_severity target_milestone
</span><del>-           dependson blocked votes everconfirmed
</del><ins>+           dependson blocked everconfirmed
</ins><span class="cx">            reporter assigned_to cc estimated_time
</span><span class="cx">            remaining_time actual_time deadline),
</span><span class="cx"> 
</span><span class="lines">@@ -1623,6 +2098,9 @@
</span><span class="cx">         # Custom Fields
</span><span class="cx">         map { $_-&gt;name } Bugzilla-&gt;active_custom_fields
</span><span class="cx">     );
</span><ins>+    Bugzilla::Hook::process('bug_fields', {'fields' =&gt; \@fields} );
+    
+    return @fields;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #####################################################################
</span><span class="lines">@@ -1654,6 +2132,7 @@
</span><span class="cx">                                            newvalue =&gt; $value,
</span><span class="cx">                                            privs    =&gt; $privs });
</span><span class="cx">     }
</span><ins>+    $self-&gt;_check_field_is_mandatory($value, $field);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -1661,6 +2140,131 @@
</span><span class="cx"> # &quot;Set&quot; Methods #
</span><span class="cx"> #################
</span><span class="cx"> 
</span><ins>+# Note that if you are changing multiple bugs at once, you must pass
+# other_bugs to set_all in order for it to behave properly.
+sub set_all {
+    my $self = shift;
+    my ($input_params) = @_;
+    
+    # Clone the data as we are going to alter it, and this would affect
+    # subsequent bugs when calling set_all() again, as some fields would
+    # be modified or no longer defined.
+    my $params = {};
+    %$params = %$input_params;
+
+    # You cannot mark bugs as duplicate when changing several bugs at once
+    # (because currently there is no way to check for duplicate loops in that
+    # situation). You also cannot set the alias of several bugs at once.
+    if ($params-&gt;{other_bugs} and scalar @{ $params-&gt;{other_bugs} } &gt; 1) {
+        ThrowUserError('dupe_not_allowed') if exists $params-&gt;{dup_id};
+        ThrowUserError('multiple_alias_not_allowed') 
+            if defined $params-&gt;{alias};
+    }
+
+    # For security purposes, and because lots of other checks depend on it,
+    # we set the product first before anything else.
+    my $product_changed; # Used only for strict_isolation checks.
+    if (exists $params-&gt;{'product'}) {
+        $product_changed = $self-&gt;_set_product($params-&gt;{'product'}, $params);
+    }
+
+    # strict_isolation checks mean that we should set the groups
+    # immediately after changing the product.
+    $self-&gt;_add_remove($params, 'groups');
+
+    if (exists $params-&gt;{'dependson'} or exists $params-&gt;{'blocked'}) {
+        my %set_deps;
+        foreach my $name (qw(dependson blocked)) {
+            my @dep_ids = @{ $self-&gt;$name };
+            # If only one of the two fields was passed in, then we need to
+            # retain the current value for the other one.
+            if (!exists $params-&gt;{$name}) {
+                $set_deps{$name} = \@dep_ids;
+                next;
+            }
+
+            # Explicitly setting them to a particular value overrides
+            # add/remove.
+            if (exists $params-&gt;{$name}-&gt;{set}) {
+                $set_deps{$name} = $params-&gt;{$name}-&gt;{set};
+                next;
+            }
+
+            foreach my $add (@{ $params-&gt;{$name}-&gt;{add} || [] }) {
+                push(@dep_ids, $add) if !grep($_ == $add, @dep_ids);
+            }
+            foreach my $remove (@{ $params-&gt;{$name}-&gt;{remove} || [] }) {
+                @dep_ids = grep($_ != $remove, @dep_ids);
+            }
+            $set_deps{$name} = \@dep_ids;
+        }
+
+        $self-&gt;set_dependencies($set_deps{'dependson'}, $set_deps{'blocked'});
+    }
+
+    if (exists $params-&gt;{'keywords'}) {
+        # Sorting makes the order &quot;add, remove, set&quot;, just like for other
+        # fields.
+        foreach my $action (sort keys %{ $params-&gt;{'keywords'} }) {
+            $self-&gt;modify_keywords($params-&gt;{'keywords'}-&gt;{$action}, $action);
+        }
+    }
+
+    if (exists $params-&gt;{'comment'} or exists $params-&gt;{'work_time'}) {
+        # Add a comment as needed to each bug. This is done early because
+        # there are lots of things that want to check if we added a comment.
+        $self-&gt;add_comment($params-&gt;{'comment'}-&gt;{'body'},
+            { isprivate =&gt; $params-&gt;{'comment'}-&gt;{'is_private'},
+              work_time =&gt; $params-&gt;{'work_time'} });
+    }
+
+    my %normal_set_all;
+    foreach my $name (keys %$params) {
+        # These are handled separately below.
+        if ($self-&gt;can(&quot;set_$name&quot;)) {
+            $normal_set_all{$name} = $params-&gt;{$name};
+        }
+    }
+    $self-&gt;SUPER::set_all(\%normal_set_all);
+
+    $self-&gt;reset_assigned_to if $params-&gt;{'reset_assigned_to'};
+    $self-&gt;reset_qa_contact  if $params-&gt;{'reset_qa_contact'};
+
+    $self-&gt;_add_remove($params, 'see_also');
+
+    # And set custom fields.
+    my @custom_fields = Bugzilla-&gt;active_custom_fields;
+    foreach my $field (@custom_fields) {
+        my $fname = $field-&gt;name;
+        if (exists $params-&gt;{$fname}) {
+            $self-&gt;set_custom_field($field, $params-&gt;{$fname});
+        }
+    }
+
+    $self-&gt;_add_remove($params, 'cc');
+
+    # Theoretically you could move a product without ever specifying
+    # a new assignee or qa_contact, or adding/removing any CCs. So,
+    # we have to check that the current assignee, qa, and CCs are still
+    # valid if we've switched products, under strict_isolation. We can only
+    # do that here, because if they *did* change the assignee, qa, or CC,
+    # then we don't want to check the original ones, only the new ones. 
+    $self-&gt;_check_strict_isolation() if $product_changed;
+}
+
+# Helper for set_all that helps with fields that have an &quot;add/remove&quot;
+# pattern instead of a &quot;set_&quot; pattern.
+sub _add_remove {
+    my ($self, $params, $name) = @_;
+    my @add    = @{ $params-&gt;{$name}-&gt;{add}    || [] };
+    my @remove = @{ $params-&gt;{$name}-&gt;{remove} || [] };
+    $name =~ s/s$//;
+    my $add_method = &quot;add_$name&quot;;
+    my $remove_method = &quot;remove_$name&quot;;
+    $self-&gt;$add_method($_) foreach @add;
+    $self-&gt;$remove_method($_) foreach @remove;
+}
+
</ins><span class="cx"> sub set_alias { $_[0]-&gt;set('alias', $_[1]); }
</span><span class="cx"> sub set_assigned_to {
</span><span class="cx">     my ($self, $value) = @_;
</span><span class="lines">@@ -1671,26 +2275,31 @@
</span><span class="cx"> }
</span><span class="cx"> sub reset_assigned_to {
</span><span class="cx">     my $self = shift;
</span><del>-    if (Bugzilla-&gt;params-&gt;{'commentonreassignbycomponent'} 
-        &amp;&amp; !$self-&gt;{added_comments})
-    {
-        ThrowUserError('comment_required');
-    }
</del><span class="cx">     my $comp = $self-&gt;component_obj;
</span><span class="cx">     $self-&gt;set_assigned_to($comp-&gt;default_assignee);
</span><span class="cx"> }
</span><span class="cx"> sub set_cclist_accessible { $_[0]-&gt;set('cclist_accessible', $_[1]); }
</span><span class="cx"> sub set_comment_is_private {
</span><span class="cx">     my ($self, $comment_id, $isprivate) = @_;
</span><del>-    return unless Bugzilla-&gt;user-&gt;is_insider;
-    my ($comment) = grep($comment_id eq $_-&gt;{id}, @{$self-&gt;longdescs});
</del><ins>+
+    # We also allow people to pass in a hash of comment ids to update.
+    if (ref $comment_id) {
+        while (my ($id, $is) = each %$comment_id) {
+            $self-&gt;set_comment_is_private($id, $is);
+        }
+        return;
+    }
+
+    my ($comment) = grep($comment_id == $_-&gt;id, @{ $self-&gt;comments });
</ins><span class="cx">     ThrowUserError('comment_invalid_isprivate', { id =&gt; $comment_id }) 
</span><span class="cx">         if !$comment;
</span><span class="cx"> 
</span><span class="cx">     $isprivate = $isprivate ? 1 : 0;
</span><del>-    if ($isprivate != $comment-&gt;{isprivate}) {
-        $self-&gt;{comment_isprivate} ||= {};
-        $self-&gt;{comment_isprivate}-&gt;{$comment_id} = $isprivate;
</del><ins>+    if ($isprivate != $comment-&gt;is_private) {
+        ThrowUserError('user_not_insider') if !Bugzilla-&gt;user-&gt;is_insider;
+        $self-&gt;{comment_isprivate} ||= [];
+        $comment-&gt;set_is_private($isprivate);
+        push @{$self-&gt;{comment_isprivate}}, $comment;
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> sub set_component  {
</span><span class="lines">@@ -1711,6 +2320,7 @@
</span><span class="cx"> }
</span><span class="cx"> sub set_custom_field {
</span><span class="cx">     my ($self, $field, $value) = @_;
</span><ins>+
</ins><span class="cx">     if (ref $value eq 'ARRAY' &amp;&amp; $field-&gt;type != FIELD_TYPE_MULTI_SELECT) {
</span><span class="cx">         $value = $value-&gt;[0];
</span><span class="cx">     }
</span><span class="lines">@@ -1727,6 +2337,8 @@
</span><span class="cx">     detaint_natural($_) foreach (@$dependson, @$blocked);
</span><span class="cx">     $self-&gt;{'dependson'} = $dependson;
</span><span class="cx">     $self-&gt;{'blocked'}   = $blocked;
</span><ins>+    delete $self-&gt;{depends_on_obj};
+    delete $self-&gt;{blocks_obj};
</ins><span class="cx"> }
</span><span class="cx"> sub _clear_dup_id { $_[0]-&gt;{dup_id} = undef; }
</span><span class="cx"> sub set_dup_id {
</span><span class="lines">@@ -1735,6 +2347,21 @@
</span><span class="cx">     $self-&gt;set('dup_id', $dup_id);
</span><span class="cx">     my $new = $self-&gt;dup_id;
</span><span class="cx">     return if $old == $new;
</span><ins>+
+    # Make sure that we have the DUPLICATE resolution. This is needed
+    # if somebody calls set_dup_id without calling set_bug_status or
+    # set_resolution.
+    if ($self-&gt;resolution ne 'DUPLICATE') {
+        # Even if the current status is VERIFIED, we change it back to
+        # RESOLVED (or whatever the duplicate_or_move_bug_status is) here,
+        # because that's the same thing the UI does when you click on the
+        # &quot;Mark as Duplicate&quot; link. If people really want to retain their
+        # current status, they can use set_bug_status and set the DUPLICATE
+        # resolution before getting here.
+        $self-&gt;set_bug_status(
+            Bugzilla-&gt;params-&gt;{'duplicate_or_move_bug_status'},
+            { resolution =&gt; 'DUPLICATE' });
+    }
</ins><span class="cx">     
</span><span class="cx">     # Update the other bug.
</span><span class="cx">     my $dupe_of = new Bugzilla::Bug($self-&gt;dup_id);
</span><span class="lines">@@ -1762,10 +2389,17 @@
</span><span class="cx"> }
</span><span class="cx"> sub set_estimated_time { $_[0]-&gt;set('estimated_time', $_[1]); }
</span><span class="cx"> sub _set_everconfirmed { $_[0]-&gt;set('everconfirmed', $_[1]); }
</span><ins>+sub set_flags {
+    my ($self, $flags, $new_flags) = @_;
+
+    Bugzilla::Flag-&gt;set_flag($self, $_) foreach (@$flags, @$new_flags);
+}
</ins><span class="cx"> sub set_op_sys         { $_[0]-&gt;set('op_sys',        $_[1]); }
</span><span class="cx"> sub set_platform       { $_[0]-&gt;set('rep_platform',  $_[1]); }
</span><span class="cx"> sub set_priority       { $_[0]-&gt;set('priority',      $_[1]); }
</span><del>-sub set_product {
</del><ins>+# For security reasons, you have to use set_all to change the product.
+# See the strict_isolation check in set_all for an explanation.
+sub _set_product {
</ins><span class="cx">     my ($self, $name, $params) = @_;
</span><span class="cx">     my $old_product = $self-&gt;product_obj;
</span><span class="cx">     my $product = $self-&gt;_check_product($name);
</span><span class="lines">@@ -1779,14 +2413,14 @@
</span><span class="cx">         $self-&gt;{_old_product_name} = $old_product-&gt;name;
</span><span class="cx">         # Delete fields that depend upon the old Product value.
</span><span class="cx">         delete $self-&gt;{choices};
</span><del>-        delete $self-&gt;{milestoneurl};
</del><span class="cx">         $product_changed = 1;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     $params ||= {};
</span><del>-    my $comp_name = $params-&gt;{component} || $self-&gt;component;
-    my $vers_name = $params-&gt;{version}   || $self-&gt;version;
-    my $tm_name   = $params-&gt;{target_milestone};
</del><ins>+    # We delete these so that they're not set again later in set_all.
+    my $comp_name = delete $params-&gt;{component} || $self-&gt;component;
+    my $vers_name = delete $params-&gt;{version}   || $self-&gt;version;
+    my $tm_name   = delete $params-&gt;{target_milestone};
</ins><span class="cx">     # This way, if usetargetmilestone is off and we've changed products,
</span><span class="cx">     # set_target_milestone will reset our target_milestone to
</span><span class="cx">     # $product-&gt;default_milestone. But if we haven't changed products,
</span><span class="lines">@@ -1818,7 +2452,7 @@
</span><span class="cx">         undef $@;
</span><span class="cx">         Bugzilla-&gt;error_mode($old_error_mode);
</span><span class="cx">         
</span><del>-        my $verified = $params-&gt;{change_confirmed};
</del><ins>+        my $verified = $params-&gt;{product_change_confirmed};
</ins><span class="cx">         my %vars;
</span><span class="cx">         if (!$verified || !$component_ok || !$version_ok || !$milestone_ok) {
</span><span class="cx">             $vars{defaults} = {
</span><span class="lines">@@ -1872,7 +2506,9 @@
</span><span class="cx">         # just die if any of these are invalid.
</span><span class="cx">         $self-&gt;set_component($comp_name);
</span><span class="cx">         $self-&gt;set_version($vers_name);
</span><del>-        if ($product_changed &amp;&amp; !$self-&gt;check_can_change_field('target_milestone', 0, 1)) {
</del><ins>+        if ($product_changed 
+            and !$self-&gt;check_can_change_field('target_milestone', 0, 1)) 
+        {
</ins><span class="cx">             # Have to set this directly to bypass the validators.
</span><span class="cx">             $self-&gt;{target_milestone} = $product-&gt;default_milestone;
</span><span class="cx">         }
</span><span class="lines">@@ -1880,28 +2516,24 @@
</span><span class="cx">             $self-&gt;set_target_milestone($tm_name);
</span><span class="cx">         }
</span><span class="cx">     }
</span><del>-    
</del><ins>+
</ins><span class="cx">     if ($product_changed) {
</span><del>-        # Remove groups that aren't valid in the new product. This will also
-        # have the side effect of removing the bug from groups that aren't
-        # active anymore.
-        #
</del><ins>+        # Remove groups that can't be set in the new product.
</ins><span class="cx">         # We copy this array because the original array is modified while we're
</span><span class="cx">         # working, and that confuses &quot;foreach&quot;.
</span><span class="cx">         my @current_groups = @{$self-&gt;groups_in};
</span><span class="cx">         foreach my $group (@current_groups) {
</span><del>-            if (!grep($group-&gt;id == $_-&gt;id, @{$product-&gt;groups_valid})) {
</del><ins>+            if (!$product-&gt;group_is_valid($group)) {
</ins><span class="cx">                 $self-&gt;remove_group($group);
</span><span class="cx">             }
</span><span class="cx">         }
</span><del>-    
</del><ins>+
</ins><span class="cx">         # Make sure the bug is in all the mandatory groups for the new product.
</span><del>-        foreach my $group (@{$product-&gt;groups_mandatory_for(Bugzilla-&gt;user)}) {
</del><ins>+        foreach my $group (@{$product-&gt;groups_mandatory}) {
</ins><span class="cx">             $self-&gt;add_group($group);
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    # XXX This is temporary until all of process_bug uses update();
</del><span class="cx">     return $product_changed;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1916,11 +2548,6 @@
</span><span class="cx"> }
</span><span class="cx"> sub reset_qa_contact {
</span><span class="cx">     my $self = shift;
</span><del>-    if (Bugzilla-&gt;params-&gt;{'commentonreassignbycomponent'}
-        &amp;&amp; !$self-&gt;{added_comments})
-    {
-        ThrowUserError('comment_required');
-    }
</del><span class="cx">     my $comp = $self-&gt;component_obj;
</span><span class="cx">     $self-&gt;set_qa_contact($comp-&gt;default_qa_contact);
</span><span class="cx"> }
</span><span class="lines">@@ -1933,13 +2560,10 @@
</span><span class="cx">     
</span><span class="cx">     my $old_res = $self-&gt;resolution;
</span><span class="cx">     $self-&gt;set('resolution', $value);
</span><ins>+    delete $self-&gt;{choices};
</ins><span class="cx">     my $new_res = $self-&gt;resolution;
</span><span class="cx"> 
</span><span class="cx">     if ($new_res ne $old_res) {
</span><del>-        # MOVED has a special meaning and can only be used when
-        # really moving bugs to another installation.
-        ThrowCodeError('no_manual_moved') if ($new_res eq 'MOVED' &amp;&amp; !$params-&gt;{moving});
-
</del><span class="cx">         # Clear the dup_id if we're leaving the dup resolution.
</span><span class="cx">         if ($old_res eq 'DUPLICATE') {
</span><span class="cx">             $self-&gt;_clear_dup_id();
</span><span class="lines">@@ -1955,44 +2579,55 @@
</span><span class="cx">     # of another, theoretically. Note that this code block will also run
</span><span class="cx">     # when going between different closed states.
</span><span class="cx">     if ($self-&gt;resolution eq 'DUPLICATE') {
</span><del>-        if ($params-&gt;{dupe_of}) {
-            $self-&gt;set_dup_id($params-&gt;{dupe_of});
</del><ins>+        if (my $dup_id = $params-&gt;{dup_id}) {
+            $self-&gt;set_dup_id($dup_id);
</ins><span class="cx">         }
</span><span class="cx">         elsif (!$self-&gt;dup_id) {
</span><span class="cx">             ThrowUserError('dupe_id_required');
</span><span class="cx">         }
</span><span class="cx">     }
</span><ins>+
+    # This method has handled dup_id, so set_all doesn't have to worry
+    # about it now.
+    delete $params-&gt;{dup_id};
</ins><span class="cx"> }
</span><span class="cx"> sub clear_resolution {
</span><span class="cx">     my $self = shift;
</span><span class="cx">     if (!$self-&gt;status-&gt;is_open) {
</span><span class="cx">         ThrowUserError('resolution_cant_clear', { bug_id =&gt; $self-&gt;id });
</span><span class="cx">     }
</span><del>-    if (Bugzilla-&gt;params-&gt;{'commentonclearresolution'}
-        &amp;&amp; $self-&gt;resolution &amp;&amp; !$self-&gt;{added_comments})
-    {
-        ThrowUserError('comment_required');
-    }
</del><span class="cx">     $self-&gt;{'resolution'} = ''; 
</span><span class="cx">     $self-&gt;_clear_dup_id; 
</span><span class="cx"> }
</span><span class="cx"> sub set_severity       { $_[0]-&gt;set('bug_severity',  $_[1]); }
</span><del>-sub set_status {
</del><ins>+sub set_bug_status {
</ins><span class="cx">     my ($self, $status, $params) = @_;
</span><span class="cx">     my $old_status = $self-&gt;status;
</span><span class="cx">     $self-&gt;set('bug_status', $status);
</span><span class="cx">     delete $self-&gt;{'status'};
</span><ins>+    delete $self-&gt;{'statuses_available'};
+    delete $self-&gt;{'choices'};
</ins><span class="cx">     my $new_status = $self-&gt;status;
</span><del>-    
</del><ins>+   
</ins><span class="cx">     if ($new_status-&gt;is_open) {
</span><span class="cx">         # Check for the everconfirmed transition
</span><del>-        $self-&gt;_set_everconfirmed(1) if $new_status-&gt;name ne 'UNCONFIRMED';
</del><ins>+        $self-&gt;_set_everconfirmed($new_status-&gt;name eq 'UNCONFIRMED' ? 0 : 1);
</ins><span class="cx">         $self-&gt;clear_resolution();
</span><ins>+        # Calling clear_resolution handled the &quot;resolution&quot; and &quot;dup_id&quot;
+        # setting, so set_all doesn't have to worry about them.
+        delete $params-&gt;{resolution};
+        delete $params-&gt;{dup_id};
</ins><span class="cx">     }
</span><span class="cx">     else {
</span><span class="cx">         # We do this here so that we can make sure closed statuses have
</span><span class="cx">         # resolutions.
</span><del>-        my $resolution = delete $params-&gt;{resolution} || $self-&gt;resolution;
</del><ins>+        my $resolution = $self-&gt;resolution;
+        # We need to check &quot;defined&quot; to prevent people from passing
+        # a blank resolution in the WebService, which would otherwise fail
+        # silently.
+        if (defined $params-&gt;{resolution}) {
+            $resolution = delete $params-&gt;{resolution};
+        }
</ins><span class="cx">         $self-&gt;set_resolution($resolution, $params);
</span><span class="cx"> 
</span><span class="cx">         # Changing between closed statuses zeros the remaining time.
</span><span class="lines">@@ -2031,6 +2666,10 @@
</span><span class="cx">     my ($self, $user_or_name) = @_;
</span><span class="cx">     my $user = ref $user_or_name ? $user_or_name
</span><span class="cx">                                  : Bugzilla::User-&gt;check($user_or_name);
</span><ins>+    my $currentUser = Bugzilla-&gt;user;
+    if (!$self-&gt;user-&gt;{'canedit'} &amp;&amp; $user-&gt;id != $currentUser-&gt;id) {
+        ThrowUserError('cc_remove_denied');
+    }
</ins><span class="cx">     my $cc_users = $self-&gt;cc_users;
</span><span class="cx">     @$cc_users = grep { $_-&gt;id != $user-&gt;id } @$cc_users;
</span><span class="cx"> }
</span><span class="lines">@@ -2040,44 +2679,34 @@
</span><span class="cx"> sub add_comment {
</span><span class="cx">     my ($self, $comment, $params) = @_;
</span><span class="cx"> 
</span><del>-    $comment = $self-&gt;_check_comment($comment);
-
</del><span class="cx">     $params ||= {};
</span><del>-    if (exists $params-&gt;{work_time}) {
-        $params-&gt;{work_time} = $self-&gt;_check_work_time($params-&gt;{work_time});
-        ThrowUserError('comment_required')
-            if $comment eq '' &amp;&amp; $params-&gt;{work_time} != 0;
-    }
-    if (exists $params-&gt;{type}) {
-        $params-&gt;{type} = $self-&gt;_check_comment_type($params-&gt;{type});
-    }
-    if (exists $params-&gt;{isprivate}) {
-        $params-&gt;{isprivate} = 
-            $self-&gt;_check_commentprivacy($params-&gt;{isprivate});
-    }
-    # XXX We really should check extra_data, too.
</del><span class="cx"> 
</span><del>-    if ($comment eq '' &amp;&amp; !($params-&gt;{type} || $params-&gt;{work_time})) {
</del><ins>+    # Fill out info that doesn't change and callers may not pass in
+    $params-&gt;{'bug_id'}  = $self;
+    $params-&gt;{'thetext'} = defined($comment) ? $comment : '';
+
+    # Validate all the entered data
+    Bugzilla::Comment-&gt;check_required_create_fields($params);
+    $params = Bugzilla::Comment-&gt;run_create_validators($params);
+
+    # This makes it so we won't create new comments when there is nothing
+    # to add 
+    if ($params-&gt;{'thetext'} eq ''
+        &amp;&amp; !($params-&gt;{type} || abs($params-&gt;{work_time} || 0)))
+    {
</ins><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    # So we really want to comment. Make sure we are allowed to do so.
-    my $privs;
-    $self-&gt;check_can_change_field('longdesc', 0, 1, \$privs)
-        || ThrowUserError('illegal_change', { field =&gt; 'longdesc', privs =&gt; $privs });
</del><ins>+    # If the user has explicitly set remaining_time, this will be overridden
+    # later in set_all. But if they haven't, this keeps remaining_time
+    # up-to-date.
+    if ($params-&gt;{work_time}) {
+        $self-&gt;set_remaining_time(max($self-&gt;remaining_time - $params-&gt;{work_time}, 0));
+    }
</ins><span class="cx"> 
</span><span class="cx">     $self-&gt;{added_comments} ||= [];
</span><del>-    my $add_comment = dclone($params);
-    $add_comment-&gt;{thetext} = $comment;
</del><span class="cx"> 
</span><del>-    # We only want to trick_taint fields that we know about--we don't
-    # want to accidentally let somebody set some field that's not OK
-    # to set!
-    foreach my $field (UPDATE_COMMENT_COLUMNS) {
-        trick_taint($add_comment-&gt;{$field}) if defined $add_comment-&gt;{$field};
-    }
-
-    push(@{$self-&gt;{added_comments}}, $add_comment);
</del><ins>+    push(@{$self-&gt;{added_comments}}, $params);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> # There was a lot of duplicate code when I wrote this as three separate
</span><span class="lines">@@ -2086,15 +2715,15 @@
</span><span class="cx"> sub modify_keywords {
</span><span class="cx">     my ($self, $keywords, $action) = @_;
</span><span class="cx">     
</span><del>-    $action ||= &quot;makeexact&quot;;
-    if (!grep($action eq $_, qw(add delete makeexact))) {
-        $action = &quot;makeexact&quot;;
</del><ins>+    $action ||= 'set';
+    if (!grep($action eq $_, qw(add remove set))) {
+        $action = 'set';
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     $keywords = $self-&gt;_check_keywords($keywords);
</span><span class="cx"> 
</span><span class="cx">     my (@result, $any_changes);
</span><del>-    if ($action eq 'makeexact') {
</del><ins>+    if ($action eq 'set') {
</ins><span class="cx">         @result = @$keywords;
</span><span class="cx">         # Check if anything was added or removed.
</span><span class="cx">         my @old_ids = map { $_-&gt;id } @{$self-&gt;keyword_objects};
</span><span class="lines">@@ -2128,21 +2757,29 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     $self-&gt;{'keyword_objects'} = \@result;
</span><del>-    return $any_changes;
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub add_group {
</span><span class="cx">     my ($self, $group) = @_;
</span><del>-    # Invalid ids are silently ignored. (We can't tell people whether
-    # or not a group exists.)
-    $group = new Bugzilla::Group($group) unless ref $group;
-    return unless $group;
</del><span class="cx"> 
</span><ins>+    # If the user enters &quot;FoO&quot; but the DB has &quot;Foo&quot;, $group-&gt;name would
+    # return &quot;Foo&quot; and thus revealing the existence of the group name.
+    # So we have to store and pass the name as entered by the user to
+    # the error message, if we have it.
+    my $group_name = blessed($group) ? $group-&gt;name : $group;
+    my $args = { name =&gt; $group_name, product =&gt; $self-&gt;product,
+                 bug_id =&gt; $self-&gt;id, action =&gt; 'add' };
+
+    $group = Bugzilla::Group-&gt;check_no_disclose($args) if !blessed $group;
+
+    # If the bug is already in this group, then there is nothing to do.
+    return if $self-&gt;in_group($group);
+
+
</ins><span class="cx">     # Make sure that bugs in this product can actually be restricted
</span><del>-    # to this group.
-    grep($group-&gt;id == $_-&gt;id, @{$self-&gt;product_obj-&gt;groups_valid})
-         || ThrowUserError('group_invalid_restriction',
-                { product =&gt; $self-&gt;product, group_id =&gt; $group-&gt;id });
</del><ins>+    # to this group by the current user.
+    $self-&gt;product_obj-&gt;group_is_settable($group)
+         || ThrowUserError('group_restriction_not_allowed', $args);
</ins><span class="cx"> 
</span><span class="cx">     # OtherControl people can add groups only during a product change,
</span><span class="cx">     # and only when the group is not NA for them.
</span><span class="lines">@@ -2151,36 +2788,38 @@
</span><span class="cx">         if (!$self-&gt;{_old_product_name}
</span><span class="cx">             || $controls-&gt;{othercontrol} == CONTROLMAPNA)
</span><span class="cx">         {
</span><del>-            ThrowUserError('group_change_denied',
-                           { bug =&gt; $self, group_id =&gt; $group-&gt;id });
</del><ins>+            ThrowUserError('group_restriction_not_allowed', $args);
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     my $current_groups = $self-&gt;groups_in;
</span><del>-    if (!grep($group-&gt;id == $_-&gt;id, @$current_groups)) {
-        push(@$current_groups, $group);
-    }
</del><ins>+    push(@$current_groups, $group);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub remove_group {
</span><span class="cx">     my ($self, $group) = @_;
</span><del>-    $group = new Bugzilla::Group($group) unless ref $group;
-    return unless $group;
-    
-    # First, check if this is a valid group for this product.
-    # You can *always* remove a group that is not valid for this product, so
-    # we don't do any other checks if that's the case. (set_product does this.)
-    #
-    # This particularly happens when isbuggroup is no longer 1, and we're
-    # moving a bug to a new product.
-    if (grep($_-&gt;id == $group-&gt;id, @{$self-&gt;product_obj-&gt;groups_valid})) {   
</del><ins>+
+    # See add_group() for the reason why we store the user input.
+    my $group_name = blessed($group) ? $group-&gt;name : $group;
+    my $args = { name =&gt; $group_name, product =&gt; $self-&gt;product,
+                 bug_id =&gt; $self-&gt;id, action =&gt; 'remove' };
+
+    $group = Bugzilla::Group-&gt;check_no_disclose($args) if !blessed $group;
+
+    # If the bug isn't in this group, then either the name is misspelled,
+    # or the group really doesn't exist. Let the user know about this problem.
+    $self-&gt;in_group($group) || ThrowUserError('group_invalid_removal', $args);
+
+    # Check if this is a valid group for this product. You can *always*
+    # remove a group that is not valid for this product (set_product does this).
+    # This particularly happens when we're moving a bug to a new product.
+    # You still have to be a member of an inactive group to remove it.
+    if ($self-&gt;product_obj-&gt;group_is_valid($group)) {
</ins><span class="cx">         my $controls = $self-&gt;product_obj-&gt;group_controls-&gt;{$group-&gt;id};
</span><span class="cx"> 
</span><del>-        # Nobody can ever remove a Mandatory group.
-        if ($controls-&gt;{membercontrol} == CONTROLMAPMANDATORY) {
-            ThrowUserError('group_invalid_removal',
-                { product =&gt; $self-&gt;product, group_id =&gt; $group-&gt;id,
-                  bug =&gt; $self });
</del><ins>+        # Nobody can ever remove a Mandatory group, unless it became inactive.
+        if ($controls-&gt;{membercontrol} == CONTROLMAPMANDATORY &amp;&amp; $group-&gt;is_active) {
+            ThrowUserError('group_invalid_removal', $args);
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         # OtherControl people can remove groups only during a product change,
</span><span class="lines">@@ -2190,20 +2829,209 @@
</span><span class="cx">                 || $controls-&gt;{othercontrol} == CONTROLMAPMANDATORY
</span><span class="cx">                 || $controls-&gt;{othercontrol} == CONTROLMAPNA)
</span><span class="cx">             {
</span><del>-                ThrowUserError('group_change_denied',
-                               { bug =&gt; $self, group_id =&gt; $group-&gt;id });
</del><ins>+                ThrowUserError('group_invalid_removal', $args);
</ins><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">     }
</span><del>-    
</del><ins>+
</ins><span class="cx">     my $current_groups = $self-&gt;groups_in;
</span><span class="cx">     @$current_groups = grep { $_-&gt;id != $group-&gt;id } @$current_groups;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub add_see_also {
+    my ($self, $input, $skip_recursion) = @_;
+
+    # This is needed by xt/search.t.
+    $input = $input-&gt;name if blessed($input);
+
+    $input = trim($input);
+    return if !$input;
+
+    my ($class, $uri) = Bugzilla::BugUrl-&gt;class_for($input);
+
+    my $params = { value =&gt; $uri, bug_id =&gt; $self, class =&gt; $class };
+    $class-&gt;check_required_create_fields($params);
+
+    my $field_values = $class-&gt;run_create_validators($params);
+    my $value = $field_values-&gt;{value}-&gt;as_string;
+    trick_taint($value);
+    $field_values-&gt;{value} = $value;
+
+    # We only add the new URI if it hasn't been added yet. URIs are
+    # case-sensitive, but most of our DBs are case-insensitive, so we do
+    # this check case-insensitively.
+    if (!grep { lc($_-&gt;name) eq lc($value) } @{ $self-&gt;see_also }) {
+        my $privs;
+        my $can = $self-&gt;check_can_change_field('see_also', '', $value, \$privs);
+        if (!$can) {
+            ThrowUserError('illegal_change', { field    =&gt; 'see_also',
+                                               newvalue =&gt; $value,
+                                               privs    =&gt; $privs });
+        }
+        # If this is a link to a local bug then save the
+        # ref bug id for sending changes email.
+        my $ref_bug = delete $field_values-&gt;{ref_bug};
+        if ($class-&gt;isa('Bugzilla::BugUrl::Bugzilla::Local')
+            and !$skip_recursion)
+        {
+            $ref_bug-&gt;add_see_also($self-&gt;id, 'skip_recursion');
+            push @{ $self-&gt;{_update_ref_bugs} }, $ref_bug;
+            push @{ $self-&gt;{see_also_changes} }, $ref_bug-&gt;id;
+        }
+        push @{ $self-&gt;{see_also} }, bless ($field_values, $class);
+    }
+}
+
+sub remove_see_also {
+    my ($self, $url, $skip_recursion) = @_;
+    my $see_also = $self-&gt;see_also;
+
+    # This is needed by xt/search.t.
+    $url = $url-&gt;name if blessed($url);
+
+    my ($removed_bug_url, $new_see_also) =
+        part { lc($_-&gt;name) ne lc($url) } @$see_also;
+
+    my $privs;
+    my $can = $self-&gt;check_can_change_field('see_also', $see_also, $new_see_also, \$privs);
+    if (!$can) {
+        ThrowUserError('illegal_change', { field    =&gt; 'see_also',
+                                           oldvalue =&gt; $url,
+                                           privs    =&gt; $privs });
+    }
+
+    # Since we remove also the url from the referenced bug,
+    # we need to notify changes for that bug too.
+    $removed_bug_url = $removed_bug_url-&gt;[0];
+    if (!$skip_recursion and $removed_bug_url
+        and $removed_bug_url-&gt;isa('Bugzilla::BugUrl::Bugzilla::Local'))
+    {
+        my $ref_bug
+            = Bugzilla::Bug-&gt;check($removed_bug_url-&gt;ref_bug_url-&gt;bug_id);
+
+        if (Bugzilla-&gt;user-&gt;can_edit_product($ref_bug-&gt;product_id)) {
+            my $self_url = $removed_bug_url-&gt;local_uri($self-&gt;id);
+            $ref_bug-&gt;remove_see_also($self_url, 'skip_recursion');
+            push @{ $self-&gt;{_update_ref_bugs} }, $ref_bug;
+            push @{ $self-&gt;{see_also_changes} }, $ref_bug-&gt;id;
+        }
+    }
+
+    $self-&gt;{see_also} = $new_see_also || [];
+}
+
+sub add_tag {
+    my ($self, $tag) = @_;
+    my $dbh = Bugzilla-&gt;dbh;
+    my $user = Bugzilla-&gt;user;
+    $tag = $self-&gt;_check_tag_name($tag);
+
+    my $tag_id = $user-&gt;tags-&gt;{$tag}-&gt;{id};
+    # If this tag doesn't exist for this user yet, create it.
+    if (!$tag_id) {
+        $dbh-&gt;do('INSERT INTO tag (user_id, name) VALUES (?, ?)',
+                  undef, ($user-&gt;id, $tag));
+
+        $tag_id = $dbh-&gt;selectrow_array('SELECT id FROM tag
+                                         WHERE name = ? AND user_id = ?',
+                                         undef, ($tag, $user-&gt;id));
+        # The list has changed.
+        delete $user-&gt;{tags};
+    }
+    # Do nothing if this tag is already set for this bug.
+    return if grep { $_ eq $tag } @{$self-&gt;tags};
+
+    # Increment the counter. Do it before the SQL call below,
+    # to not count the tag twice.
+    $user-&gt;tags-&gt;{$tag}-&gt;{bug_count}++;
+
+    $dbh-&gt;do('INSERT INTO bug_tag (bug_id, tag_id) VALUES (?, ?)',
+              undef, ($self-&gt;id, $tag_id));
+
+    push(@{$self-&gt;{tags}}, $tag);
+}
+
+sub remove_tag {
+    my ($self, $tag) = @_;
+    my $dbh = Bugzilla-&gt;dbh;
+    my $user = Bugzilla-&gt;user;
+    $tag = $self-&gt;_check_tag_name($tag);
+
+    my $tag_id = exists $user-&gt;tags-&gt;{$tag} ? $user-&gt;tags-&gt;{$tag}-&gt;{id} : undef;
+    # Do nothing if the user doesn't use this tag, or didn't set it for this bug.
+    return unless ($tag_id &amp;&amp; grep { $_ eq $tag } @{$self-&gt;tags});
+
+    $dbh-&gt;do('DELETE FROM bug_tag WHERE bug_id = ? AND tag_id = ?',
+              undef, ($self-&gt;id, $tag_id));
+
+    $self-&gt;{tags} = [grep { $_ ne $tag } @{$self-&gt;tags}];
+
+    # Decrement the counter, and delete the tag if no bugs are using it anymore.
+    if (!--$user-&gt;tags-&gt;{$tag}-&gt;{bug_count}) {
+        $dbh-&gt;do('DELETE FROM tag WHERE name = ? AND user_id = ?',
+                  undef, ($tag, $user-&gt;id));
+
+        # The list has changed.
+        delete $user-&gt;{tags};
+    }
+}
+
+sub tags {
+    my $self = shift;
+    my $dbh = Bugzilla-&gt;dbh;
+    my $user = Bugzilla-&gt;user;
+
+    # This method doesn't support several users using the same bug object.
+    if (!exists $self-&gt;{tags}) {
+        $self-&gt;{tags} = $dbh-&gt;selectcol_arrayref(
+            'SELECT name FROM bug_tag
+             INNER JOIN tag ON tag.id = bug_tag.tag_id
+             WHERE bug_id = ? AND user_id = ?',
+             undef, ($self-&gt;id, $user-&gt;id));
+    }
+    return $self-&gt;{tags};
+}
+
</ins><span class="cx"> #####################################################################
</span><del>-# Instance Accessors
</del><ins>+# Simple Accessors
</ins><span class="cx"> #####################################################################
</span><span class="cx"> 
</span><ins>+# These are accessors that don't need to access the database.
+# Keep them in alphabetical order.
+
+sub alias               { return $_[0]-&gt;{alias}               }
+sub bug_file_loc        { return $_[0]-&gt;{bug_file_loc}        }
+sub bug_id              { return $_[0]-&gt;{bug_id}              }
+sub bug_severity        { return $_[0]-&gt;{bug_severity}        }
+sub bug_status          { return $_[0]-&gt;{bug_status}          }
+sub cclist_accessible   { return $_[0]-&gt;{cclist_accessible}   }
+sub component_id        { return $_[0]-&gt;{component_id}        }
+sub creation_ts         { return $_[0]-&gt;{creation_ts}         }
+sub estimated_time      { return $_[0]-&gt;{estimated_time}      }
+sub deadline            { return $_[0]-&gt;{deadline}            }
+sub delta_ts            { return $_[0]-&gt;{delta_ts}            }
+sub error               { return $_[0]-&gt;{error}               }
+sub everconfirmed       { return $_[0]-&gt;{everconfirmed}       }
+sub lastdiffed          { return $_[0]-&gt;{lastdiffed}          }
+sub op_sys              { return $_[0]-&gt;{op_sys}              }
+sub priority            { return $_[0]-&gt;{priority}            }
+sub product_id          { return $_[0]-&gt;{product_id}          }
+sub remaining_time      { return $_[0]-&gt;{remaining_time}      }
+sub reporter_accessible { return $_[0]-&gt;{reporter_accessible} }
+sub rep_platform        { return $_[0]-&gt;{rep_platform}        }
+sub resolution          { return $_[0]-&gt;{resolution}          }
+sub short_desc          { return $_[0]-&gt;{short_desc}          }
+sub status_whiteboard   { return $_[0]-&gt;{status_whiteboard}   }
+sub target_milestone    { return $_[0]-&gt;{target_milestone}    }
+sub version             { return $_[0]-&gt;{version}             }
+
+#####################################################################
+# Complex Accessors
+#####################################################################
+
+# These are accessors that have to access the database for additional
+# information about a bug.
+
</ins><span class="cx"> # These subs are in alphabetical order, as much as possible.
</span><span class="cx"> # If you add a new sub, please try to keep it in alphabetical order
</span><span class="cx"> # with the other ones.
</span><span class="lines">@@ -2232,12 +3060,43 @@
</span><span class="cx">     return $self-&gt;{'dup_id'};
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub _resolve_ultimate_dup_id {
+    my ($bug_id, $dupe_of, $loops_are_an_error) = @_;
+    my $dbh = Bugzilla-&gt;dbh;
+    my $sth = $dbh-&gt;prepare('SELECT dupe_of FROM duplicates WHERE dupe = ?');
+
+    my $this_dup = $dupe_of || $dbh-&gt;selectrow_array($sth, undef, $bug_id);
+    my $last_dup = $bug_id;
+
+    my %dupes;
+    while ($this_dup) {
+        if ($this_dup == $bug_id) {
+            if ($loops_are_an_error) {
+                ThrowUserError('dupe_loop_detected', { bug_id  =&gt; $bug_id,
+                                                       dupe_of =&gt; $dupe_of });
+            }
+            else {
+                return $last_dup;
+            }
+        }
+        # If $dupes{$this_dup} is already set to 1, then a loop
+        # already exists which does not involve this bug.
+        # As the user is not responsible for this loop, do not
+        # prevent him from marking this bug as a duplicate.
+        return $last_dup if exists $dupes{$this_dup};
+        $dupes{$this_dup} = 1;
+        $last_dup = $this_dup;
+        $this_dup = $dbh-&gt;selectrow_array($sth, undef, $this_dup);
+    }
+
+    return $last_dup;
+}
+
</ins><span class="cx"> sub actual_time {
</span><span class="cx">     my ($self) = @_;
</span><span class="cx">     return $self-&gt;{'actual_time'} if exists $self-&gt;{'actual_time'};
</span><span class="cx"> 
</span><del>-    if ( $self-&gt;{'error'} || 
-         !Bugzilla-&gt;user-&gt;in_group(Bugzilla-&gt;params-&gt;{&quot;timetrackinggroup&quot;}) ) {
</del><ins>+    if ( $self-&gt;{'error'} || !Bugzilla-&gt;user-&gt;is_timetracker ) {
</ins><span class="cx">         $self-&gt;{'actual_time'} = undef;
</span><span class="cx">         return $self-&gt;{'actual_time'};
</span><span class="cx">     }
</span><span class="lines">@@ -2256,8 +3115,12 @@
</span><span class="cx">         if exists $self-&gt;{'any_flags_requesteeble'};
</span><span class="cx">     return 0 if $self-&gt;{'error'};
</span><span class="cx"> 
</span><del>-    $self-&gt;{'any_flags_requesteeble'} = 
-        grep($_-&gt;{'is_requesteeble'}, @{$self-&gt;flag_types});
</del><ins>+    my $any_flags_requesteeble =
+      grep { $_-&gt;is_requestable &amp;&amp; $_-&gt;is_requesteeble } @{$self-&gt;flag_types};
+    # Useful in case a flagtype is no longer requestable but a requestee
+    # has been set before we turned off that bit.
+    $any_flags_requesteeble ||= grep { $_-&gt;requestee_id } @{$self-&gt;flags};
+    $self-&gt;{'any_flags_requesteeble'} = $any_flags_requesteeble;
</ins><span class="cx"> 
</span><span class="cx">     return $self-&gt;{'any_flags_requesteeble'};
</span><span class="cx"> }
</span><span class="lines">@@ -2267,22 +3130,8 @@
</span><span class="cx">     return $self-&gt;{'attachments'} if exists $self-&gt;{'attachments'};
</span><span class="cx">     return [] if $self-&gt;{'error'};
</span><span class="cx"> 
</span><del>-    my $attachments = Bugzilla::Attachment-&gt;get_attachments_by_bug($self-&gt;bug_id);
-    $_-&gt;{'flags'} = [] foreach @$attachments;
-    my %att = map { $_-&gt;id =&gt; $_ } @$attachments;
-
-    # Retrieve all attachment flags at once for this bug, and group them
-    # by attachment. We populate attachment flags here to avoid querying
-    # the DB for each attachment individually later.
-    my $flags = Bugzilla::Flag-&gt;match({ 'bug_id'      =&gt; $self-&gt;bug_id,
-                                        'target_type' =&gt; 'attachment' });
-
-    # Exclude flags for private attachments you cannot see.
-    @$flags = grep {exists $att{$_-&gt;attach_id}} @$flags;
-
-    push(@{$att{$_-&gt;attach_id}-&gt;{'flags'}}, $_) foreach @$flags;
-
-    $self-&gt;{'attachments'} = [sort {$a-&gt;id &lt;=&gt; $b-&gt;id} values %att];
</del><ins>+    $self-&gt;{'attachments'} =
+        Bugzilla::Attachment-&gt;get_attachments_by_bug($self-&gt;bug_id, {preload =&gt; 1});
</ins><span class="cx">     return $self-&gt;{'attachments'};
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -2302,9 +3151,26 @@
</span><span class="cx">     return $self-&gt;{'blocked'};
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-# Even bugs in an error state always have a bug_id.
-sub bug_id { $_[0]-&gt;{'bug_id'}; }
</del><ins>+sub blocks_obj {
+    my ($self) = @_;
+    $self-&gt;{blocks_obj} ||= $self-&gt;_bugs_in_order($self-&gt;blocked);
+    return $self-&gt;{blocks_obj};
+}
</ins><span class="cx"> 
</span><ins>+sub bug_group {
+    my ($self) = @_;
+    return join(', ', (map { $_-&gt;name } @{$self-&gt;groups_in}));
+}
+
+sub related_bugs {
+    my ($self, $relationship) = @_;
+    return [] if $self-&gt;{'error'};
+
+    my $field_name = $relationship-&gt;name;
+    $self-&gt;{'related_bugs'}-&gt;{$field_name} ||= $self-&gt;match({$field_name =&gt; $self-&gt;id});
+    return $self-&gt;{'related_bugs'}-&gt;{$field_name}; 
+}
+
</ins><span class="cx"> sub cc {
</span><span class="cx">     my ($self) = @_;
</span><span class="cx">     return $self-&gt;{'cc'} if exists $self-&gt;{'cc'};
</span><span class="lines">@@ -2384,34 +3250,32 @@
</span><span class="cx">     return $self-&gt;{'dependson'};
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub depends_on_obj {
+    my ($self) = @_;
+    $self-&gt;{depends_on_obj} ||= $self-&gt;_bugs_in_order($self-&gt;dependson);
+    return $self-&gt;{depends_on_obj};
+}
+
</ins><span class="cx"> sub flag_types {
</span><span class="cx">     my ($self) = @_;
</span><span class="cx">     return $self-&gt;{'flag_types'} if exists $self-&gt;{'flag_types'};
</span><span class="cx">     return [] if $self-&gt;{'error'};
</span><span class="cx"> 
</span><del>-    # The types of flags that can be set on this bug.
-    # If none, no UI for setting flags will be displayed.
-    my $flag_types = Bugzilla::FlagType::match(
-        {'target_type'  =&gt; 'bug',
-         'product_id'   =&gt; $self-&gt;{'product_id'}, 
-         'component_id' =&gt; $self-&gt;{'component_id'} });
</del><ins>+    my $vars = { target_type  =&gt; 'bug',
+                 product_id   =&gt; $self-&gt;{product_id},
+                 component_id =&gt; $self-&gt;{component_id},
+                 bug_id       =&gt; $self-&gt;bug_id };
</ins><span class="cx"> 
</span><del>-    $_-&gt;{'flags'} = [] foreach @$flag_types;
-    my %flagtypes = map { $_-&gt;id =&gt; $_ } @$flag_types;
</del><ins>+    $self-&gt;{'flag_types'} = Bugzilla::Flag-&gt;_flag_types($vars);
+    return $self-&gt;{'flag_types'};
+}
</ins><span class="cx"> 
</span><del>-    # Retrieve all bug flags at once for this bug and group them
-    # by flag types.
-    my $flags = Bugzilla::Flag-&gt;match({ 'bug_id'      =&gt; $self-&gt;bug_id,
-                                        'target_type' =&gt; 'bug' });
</del><ins>+sub flags {
+    my $self = shift;
</ins><span class="cx"> 
</span><del>-    # Call the internal 'type_id' variable instead of the method
-    # to not create a flagtype object.
-    push(@{$flagtypes{$_-&gt;{'type_id'}}-&gt;{'flags'}}, $_) foreach @$flags;
-
-    $self-&gt;{'flag_types'} =
-      [sort {$a-&gt;sortkey &lt;=&gt; $b-&gt;sortkey || $a-&gt;name cmp $b-&gt;name} values %flagtypes];
-
-    return $self-&gt;{'flag_types'};
</del><ins>+    # Don't cache it as it must be in sync with -&gt;flag_types.
+    $self-&gt;{flags} = [map { @{$_-&gt;{flags}} } @{$self-&gt;flag_types}];
+    return $self-&gt;{flags};
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub isopened {
</span><span class="lines">@@ -2419,11 +3283,6 @@
</span><span class="cx">     return is_open_state($self-&gt;{bug_status}) ? 1 : 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub isunconfirmed {
-    my $self = shift;
-    return ($self-&gt;bug_status eq 'UNCONFIRMED') ? 1 : 0;
-}
-
</del><span class="cx"> sub keywords {
</span><span class="cx">     my ($self) = @_;
</span><span class="cx">     return join(', ', (map { $_-&gt;name } @{$self-&gt;keyword_objects}));
</span><span class="lines">@@ -2442,23 +3301,56 @@
</span><span class="cx">     return $self-&gt;{'keyword_objects'};
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub longdescs {
-    my ($self) = @_;
-    return $self-&gt;{'longdescs'} if exists $self-&gt;{'longdescs'};
</del><ins>+sub comments {
+    my ($self, $params) = @_;
</ins><span class="cx">     return [] if $self-&gt;{'error'};
</span><del>-    $self-&gt;{'longdescs'} = GetComments($self-&gt;{bug_id});
-    return $self-&gt;{'longdescs'};
-}
</del><ins>+    $params ||= {};
</ins><span class="cx"> 
</span><del>-sub milestoneurl {
-    my ($self) = @_;
-    return $self-&gt;{'milestoneurl'} if exists $self-&gt;{'milestoneurl'};
-    return '' if $self-&gt;{'error'};
</del><ins>+    if (!defined $self-&gt;{'comments'}) {
+        $self-&gt;{'comments'} = Bugzilla::Comment-&gt;match({ bug_id =&gt; $self-&gt;id });
+        my $count = 0;
+        foreach my $comment (@{ $self-&gt;{'comments'} }) {
+            $comment-&gt;{count} = $count++;
+            $comment-&gt;{bug} = $self;
+        }
+        Bugzilla::Comment-&gt;preload($self-&gt;{'comments'});
+    }
+    my @comments = @{ $self-&gt;{'comments'} };
</ins><span class="cx"> 
</span><del>-    $self-&gt;{'milestoneurl'} = $self-&gt;product_obj-&gt;milestone_url;
-    return $self-&gt;{'milestoneurl'};
</del><ins>+    my $order = $params-&gt;{order} 
+        || Bugzilla-&gt;user-&gt;setting('comment_sort_order');
+    if ($order ne 'oldest_to_newest') {
+        @comments = reverse @comments;
+        if ($order eq 'newest_to_oldest_desc_first') {
+            unshift(@comments, pop @comments);
+        }
+    }
+
+    if ($params-&gt;{after}) {
+        my $from = datetime_from($params-&gt;{after});
+        @comments = grep { datetime_from($_-&gt;creation_ts) &gt; $from } @comments;
+    }
+    if ($params-&gt;{to}) {
+        my $to = datetime_from($params-&gt;{to});
+        @comments = grep { datetime_from($_-&gt;creation_ts) &lt;= $to } @comments;
+    }
+    return \@comments;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# This is needed by xt/search.t.
+sub percentage_complete {
+    my $self = shift;
+    return undef if $self-&gt;{'error'} || !Bugzilla-&gt;user-&gt;is_timetracker;
+    my $remaining = $self-&gt;remaining_time;
+    my $actual    = $self-&gt;actual_time;
+    my $total = $remaining + $actual;
+    return undef if $total == 0;
+    # Search.pm truncates this value to an integer, so we want to as well,
+    # since this is mostly used in a test where its value needs to be
+    # identical to what the database will return.
+    return int(100 * ($actual / $total));
+}
+
</ins><span class="cx"> sub product {
</span><span class="cx">     my ($self) = @_;
</span><span class="cx">     return $self-&gt;{product} if exists $self-&gt;{product};
</span><span class="lines">@@ -2501,6 +3393,21 @@
</span><span class="cx">     return $self-&gt;{'reporter'};
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub see_also {
+    my ($self) = @_;
+    return [] if $self-&gt;{'error'};
+    if (!exists $self-&gt;{see_also}) {
+        my $ids = Bugzilla-&gt;dbh-&gt;selectcol_arrayref(
+            'SELECT id FROM bug_see_also WHERE bug_id = ?',
+            undef, $self-&gt;id);
+
+        my $bug_urls = Bugzilla::BugUrl-&gt;new_from_list($ids);
+
+        $self-&gt;{see_also} = $bug_urls;
+    }
+    return $self-&gt;{see_also};
+}
+
</ins><span class="cx"> sub status {
</span><span class="cx">     my $self = shift;
</span><span class="cx">     return undef if $self-&gt;{'error'};
</span><span class="lines">@@ -2509,6 +3416,36 @@
</span><span class="cx">     return $self-&gt;{'status'};
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub statuses_available {
+    my $self = shift;
+    return [] if $self-&gt;{'error'};
+    return $self-&gt;{'statuses_available'}
+        if defined $self-&gt;{'statuses_available'};
+
+    my @statuses = @{ $self-&gt;status-&gt;can_change_to };
+
+    # UNCONFIRMED is only a valid status if it is enabled in this product.
+    if (!$self-&gt;product_obj-&gt;allows_unconfirmed) {
+        @statuses = grep { $_-&gt;name ne 'UNCONFIRMED' } @statuses;
+    }
+
+    my @available;
+    foreach my $status (@statuses) {
+        # Make sure this is a legal status transition
+        next if !$self-&gt;check_can_change_field(
+                     'bug_status', $self-&gt;status-&gt;name, $status-&gt;name);
+        push(@available, $status);
+    }
+
+    # If this bug has an inactive status set, it should still be in the list.
+    if (!grep($_-&gt;name eq $self-&gt;status-&gt;name, @available)) {
+        unshift(@available, $self-&gt;status);
+    }
+
+    $self-&gt;{'statuses_available'} = \@available;
+    return $self-&gt;{'statuses_available'};
+}
+
</ins><span class="cx"> sub show_attachment_flags {
</span><span class="cx">     my ($self) = @_;
</span><span class="cx">     return $self-&gt;{'show_attachment_flags'} 
</span><span class="lines">@@ -2533,14 +3470,6 @@
</span><span class="cx">     return $self-&gt;{'show_attachment_flags'};
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub use_votes {
-    my ($self) = @_;
-    return 0 if $self-&gt;{'error'};
-
-    return Bugzilla-&gt;params-&gt;{'usevotes'} 
-           &amp;&amp; $self-&gt;product_obj-&gt;votes_per_user &gt; 0;
-}
-
</del><span class="cx"> sub groups {
</span><span class="cx">     my $self = shift;
</span><span class="cx">     return $self-&gt;{'groups'} if exists $self-&gt;{'groups'};
</span><span class="lines">@@ -2618,13 +3547,17 @@
</span><span class="cx">     return $self-&gt;{'groups_in'};
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub in_group {
+    my ($self, $group) = @_;
+    return grep($_-&gt;id == $group-&gt;id, @{$self-&gt;groups_in}) ? 1 : 0;
+}
+
</ins><span class="cx"> sub user {
</span><span class="cx">     my $self = shift;
</span><span class="cx">     return $self-&gt;{'user'} if exists $self-&gt;{'user'};
</span><span class="cx">     return {} if $self-&gt;{'error'};
</span><span class="cx"> 
</span><span class="cx">     my $user = Bugzilla-&gt;user;
</span><del>-    my $canmove = Bugzilla-&gt;params-&gt;{'move-enabled'} &amp;&amp; $user-&gt;is_mover;
</del><span class="cx"> 
</span><span class="cx">     my $prod_id = $self-&gt;{'product_id'};
</span><span class="cx"> 
</span><span class="lines">@@ -2639,62 +3572,48 @@
</span><span class="cx">     my $isreporter = $user-&gt;id
</span><span class="cx">                      &amp;&amp; $user-&gt;id == $self-&gt;{reporter_id};
</span><span class="cx"> 
</span><del>-    $self-&gt;{'user'} = {canmove    =&gt; $canmove,
-                       canconfirm =&gt; $canconfirm,
</del><ins>+    $self-&gt;{'user'} = {canconfirm =&gt; $canconfirm,
</ins><span class="cx">                        canedit    =&gt; $canedit,
</span><span class="cx">                        isreporter =&gt; $isreporter};
</span><span class="cx">     return $self-&gt;{'user'};
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# This is intended to get values that can be selected by the user in the
+# UI. It should not be used for security or validation purposes.
</ins><span class="cx"> sub choices {
</span><span class="cx">     my $self = shift;
</span><span class="cx">     return $self-&gt;{'choices'} if exists $self-&gt;{'choices'};
</span><span class="cx">     return {} if $self-&gt;{'error'};
</span><ins>+    my $user = Bugzilla-&gt;user;
</ins><span class="cx"> 
</span><del>-    $self-&gt;{'choices'} = {};
-
-    my @prodlist = map {$_-&gt;name} @{Bugzilla-&gt;user-&gt;get_enterable_products};
</del><ins>+    my @products = @{ $user-&gt;get_enterable_products };
</ins><span class="cx">     # The current product is part of the popup, even if new bugs are no longer
</span><span class="cx">     # allowed for that product
</span><del>-    if (lsearch(\@prodlist, $self-&gt;product) &lt; 0) {
-        push(@prodlist, $self-&gt;product);
-        @prodlist = sort @prodlist;
</del><ins>+    if (!grep($_-&gt;name eq $self-&gt;product_obj-&gt;name, @products)) {
+        unshift(@products, $self-&gt;product_obj);
</ins><span class="cx">     }
</span><ins>+    my %class_ids = map { $_-&gt;classification_id =&gt; 1 } @products;
+    my $classifications = 
+        Bugzilla::Classification-&gt;new_from_list([keys %class_ids]);
</ins><span class="cx"> 
</span><del>-    # Hack - this array contains &quot;&quot;. See bug 106589.
-    my @res = grep ($_, @{get_legal_field_values('resolution')});
</del><ins>+    my %choices = (
+        bug_status =&gt; $self-&gt;statuses_available,
+        classification =&gt; $classifications,
+        product    =&gt; \@products,
+        component  =&gt; $self-&gt;product_obj-&gt;components,
+        version    =&gt; $self-&gt;product_obj-&gt;versions,
+        target_milestone =&gt; $self-&gt;product_obj-&gt;milestones,
+    );
</ins><span class="cx"> 
</span><del>-    $self-&gt;{'choices'} =
-      {
-       'product' =&gt; \@prodlist,
-       'rep_platform' =&gt; get_legal_field_values('rep_platform'),
-       'priority'     =&gt; get_legal_field_values('priority'),
-       'bug_severity' =&gt; get_legal_field_values('bug_severity'),
-       'op_sys'       =&gt; get_legal_field_values('op_sys'),
-       'bug_status'   =&gt; get_legal_field_values('bug_status'),
-       'resolution'   =&gt; \@res,
-       'component'    =&gt; [map($_-&gt;name, @{$self-&gt;product_obj-&gt;components})],
-       'version'      =&gt; [map($_-&gt;name, @{$self-&gt;product_obj-&gt;versions})],
-       'target_milestone' =&gt; [map($_-&gt;name, @{$self-&gt;product_obj-&gt;milestones})],
-      };
</del><ins>+    my $resolution_field = new Bugzilla::Field({ name =&gt; 'resolution' });
+    # Don't include the empty resolution in drop-downs.
+    my @resolutions = grep($_-&gt;name, @{ $resolution_field-&gt;legal_values });
+    $choices{'resolution'} = \@resolutions;
</ins><span class="cx"> 
</span><ins>+    $self-&gt;{'choices'} = \%choices;
</ins><span class="cx">     return $self-&gt;{'choices'};
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub votes {
-    my ($self) = @_;
-    return 0 if $self-&gt;{error};
-    return $self-&gt;{votes} if defined $self-&gt;{votes};
-
-    my $dbh = Bugzilla-&gt;dbh;
-    $self-&gt;{votes} = $dbh-&gt;selectrow_array(
-        'SELECT SUM(vote_count) FROM votes
-          WHERE bug_id = ? ' . $dbh-&gt;sql_group_by('bug_id'),
-        undef, $self-&gt;bug_id);
-    $self-&gt;{votes} ||= 0;
-    return $self-&gt;{votes};
-}
-
</del><span class="cx"> # Convenience Function. If you need speed, use this. If you need
</span><span class="cx"> # other Bug fields in addition to this, just create a new Bug with
</span><span class="cx"> # the alias.
</span><span class="lines">@@ -2713,45 +3632,16 @@
</span><span class="cx"> # Subroutines
</span><span class="cx"> #####################################################################
</span><span class="cx"> 
</span><del>-sub update_comment {
-    my ($self, $comment_id, $new_comment) = @_;
-
-    # Some validation checks.
-    if ($self-&gt;{'error'}) {
-        ThrowCodeError(&quot;bug_error&quot;, { bug =&gt; $self });
-    }
-    detaint_natural($comment_id)
-      || ThrowCodeError('bad_arg', {argument =&gt; 'comment_id', function =&gt; 'update_comment'});
-
-    # The comment ID must belong to this bug.
-    my @current_comment_obj = grep {$_-&gt;{'id'} == $comment_id} @{$self-&gt;longdescs};
-    scalar(@current_comment_obj)
-      || ThrowCodeError('bad_arg', {argument =&gt; 'comment_id', function =&gt; 'update_comment'});
-
-    # If the new comment is undefined, then there is nothing to update.
-    # To delete a comment, an empty string should be passed.
-    return unless defined $new_comment;
-    $new_comment =~ s/\s*$//s;    # Remove trailing whitespaces.
-    $new_comment =~ s/\r\n?/\n/g; # Handle Windows and Mac-style line endings.
-    trick_taint($new_comment);
-
-    # We assume _check_comment() has already been called earlier.
-    Bugzilla-&gt;dbh-&gt;do('UPDATE longdescs SET thetext = ? WHERE comment_id = ?',
-                       undef, ($new_comment, $comment_id));
-    $self-&gt;_sync_fulltext();
-
-    # Update the comment object with this new text.
-    $current_comment_obj[0]-&gt;{'body'} = $new_comment;
-}
-
</del><span class="cx"> # Represents which fields from the bugs table are handled by process_bug.cgi.
</span><span class="cx"> sub editable_bug_fields {
</span><span class="cx">     my @fields = Bugzilla-&gt;dbh-&gt;bz_table_columns('bugs');
</span><span class="cx">     # Obsolete custom fields are not editable.
</span><del>-    my @obsolete_fields = Bugzilla-&gt;get_fields({obsolete =&gt; 1, custom =&gt; 1});
</del><ins>+    my @obsolete_fields = @{ Bugzilla-&gt;fields({obsolete =&gt; 1, custom =&gt; 1}) };
</ins><span class="cx">     @obsolete_fields = map { $_-&gt;name } @obsolete_fields;
</span><del>-    foreach my $remove (&quot;bug_id&quot;, &quot;reporter&quot;, &quot;creation_ts&quot;, &quot;delta_ts&quot;, &quot;lastdiffed&quot;, @obsolete_fields) {
-        my $location = lsearch(\@fields, $remove);
</del><ins>+    foreach my $remove (&quot;bug_id&quot;, &quot;reporter&quot;, &quot;creation_ts&quot;, &quot;delta_ts&quot;, 
+                        &quot;lastdiffed&quot;, @obsolete_fields) 
+    {
+        my $location = firstidx { $_ eq $remove } @fields;
</ins><span class="cx">         # Custom multi-select fields are not stored in the bugs table.
</span><span class="cx">         splice(@fields, $location, 1) if ($location &gt; -1);
</span><span class="cx">     }
</span><span class="lines">@@ -2762,113 +3652,33 @@
</span><span class="cx"> 
</span><span class="cx"> # XXX - When Bug::update() will be implemented, we should make this routine
</span><span class="cx"> #       a private method.
</span><ins>+# Join with bug_status and bugs tables to show bugs with open statuses first,
+# and then the others
</ins><span class="cx"> sub EmitDependList {
</span><span class="cx">     my ($myfield, $targetfield, $bug_id) = (@_);
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx">     my $list_ref = $dbh-&gt;selectcol_arrayref(
</span><del>-          &quot;SELECT $targetfield FROM dependencies
-            WHERE $myfield = ? ORDER BY $targetfield&quot;,
</del><ins>+          &quot;SELECT $targetfield
+             FROM dependencies
+                  INNER JOIN bugs ON dependencies.$targetfield = bugs.bug_id
+                  INNER JOIN bug_status ON bugs.bug_status = bug_status.value
+            WHERE $myfield = ?
+            ORDER BY is_open DESC, $targetfield&quot;,
</ins><span class="cx">             undef, $bug_id);
</span><span class="cx">     return $list_ref;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub ValidateTime {
-    my ($time, $field) = @_;
-
-    # regexp verifies one or more digits, optionally followed by a period and
-    # zero or more digits, OR we have a period followed by one or more digits
-    # (allow negatives, though, so people can back out errors in time reporting)
-    if ($time !~ /^-?(?:\d+(?:\.\d*)?|\.\d+)$/) {
-        ThrowUserError(&quot;number_not_numeric&quot;,
-                       {field =&gt; &quot;$field&quot;, num =&gt; &quot;$time&quot;});
-    }
-
-    # Only the &quot;work_time&quot; field is allowed to contain a negative value.
-    if ( ($time &lt; 0) &amp;&amp; ($field ne &quot;work_time&quot;) ) {
-        ThrowUserError(&quot;number_too_small&quot;,
-                       {field =&gt; &quot;$field&quot;, num =&gt; &quot;$time&quot;, min_num =&gt; &quot;0&quot;});
-    }
-
-    if ($time &gt; 99999.99) {
-        ThrowUserError(&quot;number_too_large&quot;,
-                       {field =&gt; &quot;$field&quot;, num =&gt; &quot;$time&quot;, max_num =&gt; &quot;99999.99&quot;});
-    }
</del><ins>+# Creates a lot of bug objects in the same order as the input array.
+sub _bugs_in_order {
+    my ($self, $bug_ids) = @_;
+    my $bugs = $self-&gt;new_from_list($bug_ids);
+    my %bug_map = map { $_-&gt;id =&gt; $_ } @$bugs;
+    my @result = map { $bug_map{$_} } @$bug_ids;
+    return \@result;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub GetComments {
-    my ($id, $comment_sort_order, $start, $end, $raw) = @_;
-    my $dbh = Bugzilla-&gt;dbh;
-
-    $comment_sort_order = $comment_sort_order ||
-        Bugzilla-&gt;user-&gt;settings-&gt;{'comment_sort_order'}-&gt;{'value'};
-
-    my $sort_order = ($comment_sort_order eq &quot;oldest_to_newest&quot;) ? 'asc' : 'desc';
-
-    my @comments;
-    my @args = ($id);
-
-    my $query = 'SELECT longdescs.comment_id AS id, profiles.userid, ' .
-                        $dbh-&gt;sql_date_format('longdescs.bug_when', '%Y.%m.%d %H:%i:%s') .
-                      ' AS time, longdescs.thetext AS body, longdescs.work_time,
-                        isprivate, already_wrapped, type, extra_data
-                   FROM longdescs
-             INNER JOIN profiles
-                     ON profiles.userid = longdescs.who
-                  WHERE longdescs.bug_id = ?';
-    if ($start) {
-        $query .= ' AND longdescs.bug_when &gt; ?
-                    AND longdescs.bug_when &lt;= ?';
-        push(@args, ($start, $end));
-    }
-    $query .= &quot; ORDER BY longdescs.bug_when $sort_order&quot;;
-    my $sth = $dbh-&gt;prepare($query);
-    $sth-&gt;execute(@args);
-
-    while (my $comment_ref = $sth-&gt;fetchrow_hashref()) {
-        my %comment = %$comment_ref;
-        $comment{'author'} = new Bugzilla::User($comment{'userid'});
-
-        # If raw data is requested, do not format 'special' comments.
-        $comment{'body'} = format_comment(\%comment) unless $raw;
-
-        push (@comments, \%comment);
-    }
-   
-    if ($comment_sort_order eq &quot;newest_to_oldest_desc_first&quot;) {
-        unshift(@comments, pop @comments);
-    }
-
-    return \@comments;
-}
-
-# Format language specific comments. This routine must not update
-# $comment{'body'} itself, see BugMail::prepare_comments().
-sub format_comment {
-    my $comment = shift;
-    my $body;
-
-    if ($comment-&gt;{'type'} == CMT_DUPE_OF) {
-        $body = $comment-&gt;{'body'} . &quot;\n\n&quot; .
-                get_text('bug_duplicate_of', { dupe_of =&gt; $comment-&gt;{'extra_data'} });
-    }
-    elsif ($comment-&gt;{'type'} == CMT_HAS_DUPE) {
-        $body = get_text('bug_has_duplicate', { dupe =&gt; $comment-&gt;{'extra_data'} });
-    }
-    elsif ($comment-&gt;{'type'} == CMT_POPULAR_VOTES) {
-        $body = get_text('bug_confirmed_by_votes');
-    }
-    elsif ($comment-&gt;{'type'} == CMT_MOVED_TO) {
-        $body = $comment-&gt;{'body'} . &quot;\n\n&quot; .
-                get_text('bug_moved_to', { login =&gt; $comment-&gt;{'extra_data'} });
-    }
-    else {
-        $body = $comment-&gt;{'body'};
-    }
-    return $body;
-}
-
</del><span class="cx"> # Get the activity of a bug, starting from $starttime (if given).
</span><del>-# This routine assumes ValidateBugID has been previously called.
</del><ins>+# This routine assumes Bugzilla::Bug-&gt;check has been previously called.
</ins><span class="cx"> sub GetBugActivity {
</span><span class="cx">     my ($bug_id, $attach_id, $starttime) = @_;
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="lines">@@ -2893,24 +3703,17 @@
</span><span class="cx">     # Only includes attachments the user is allowed to see.
</span><span class="cx">     my $suppjoins = &quot;&quot;;
</span><span class="cx">     my $suppwhere = &quot;&quot;;
</span><del>-    if (Bugzilla-&gt;params-&gt;{&quot;insidergroup&quot;} 
-        &amp;&amp; !Bugzilla-&gt;user-&gt;in_group(Bugzilla-&gt;params-&gt;{'insidergroup'})) 
</del><ins>+    if (!Bugzilla-&gt;user-&gt;is_insider) 
</ins><span class="cx">     {
</span><span class="cx">         $suppjoins = &quot;LEFT JOIN attachments 
</span><span class="cx">                    ON attachments.attach_id = bugs_activity.attach_id&quot;;
</span><span class="cx">         $suppwhere = &quot;AND COALESCE(attachments.isprivate, 0) = 0&quot;;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    my $query = &quot;
-        SELECT COALESCE(fielddefs.description, &quot; 
-               # This is a hack - PostgreSQL requires both COALESCE
-               # arguments to be of the same type, and this is the only
-               # way supported by both MySQL 3 and PostgreSQL to convert
-               # an integer to a string. MySQL 4 supports CAST.
-               . $dbh-&gt;sql_string_concat('bugs_activity.fieldid', q{''}) .
-               &quot;), fielddefs.name, bugs_activity.attach_id, &quot; .
</del><ins>+    my $query = &quot;SELECT fielddefs.name, bugs_activity.attach_id, &quot; .
</ins><span class="cx">         $dbh-&gt;sql_date_format('bugs_activity.bug_when', '%Y.%m.%d %H:%i:%s') .
</span><del>-            &quot;, bugs_activity.removed, bugs_activity.added, profiles.login_name
</del><ins>+            &quot;, bugs_activity.removed, bugs_activity.added, profiles.login_name, 
+               bugs_activity.comment_id
</ins><span class="cx">           FROM bugs_activity
</span><span class="cx">                $suppjoins
</span><span class="cx">      LEFT JOIN fielddefs
</span><span class="lines">@@ -2931,7 +3734,7 @@
</span><span class="cx">     my $incomplete_data = 0;
</span><span class="cx"> 
</span><span class="cx">     foreach my $entry (@$list) {
</span><del>-        my ($field, $fieldname, $attachid, $when, $removed, $added, $who) = @$entry;
</del><ins>+        my ($fieldname, $attachid, $when, $removed, $added, $who, $comment_id) = @$entry;
</ins><span class="cx">         my %change;
</span><span class="cx">         my $activity_visible = 1;
</span><span class="cx"> 
</span><span class="lines">@@ -2941,18 +3744,24 @@
</span><span class="cx">             || $fieldname eq 'work_time'
</span><span class="cx">             || $fieldname eq 'deadline')
</span><span class="cx">         {
</span><del>-            $activity_visible = 
-                Bugzilla-&gt;user-&gt;in_group(Bugzilla-&gt;params-&gt;{'timetrackinggroup'}) ? 1 : 0;
-        } else {
</del><ins>+            $activity_visible = Bugzilla-&gt;user-&gt;is_timetracker;
+        }
+        elsif ($fieldname eq 'longdescs.isprivate'
+                &amp;&amp; !Bugzilla-&gt;user-&gt;is_insider 
+                &amp;&amp; $added) 
+        { 
+            $activity_visible = 0;
+        } 
+        else {
</ins><span class="cx">             $activity_visible = 1;
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         if ($activity_visible) {
</span><del>-            # This gets replaced with a hyperlink in the template.
-            $field =~ s/^Attachment\s*// if $attachid;
-
</del><span class="cx">             # Check for the results of an old Bugzilla data corruption bug
</span><del>-            $incomplete_data = 1 if ($added =~ /^\?/ || $removed =~ /^\?/);
</del><ins>+            if (($added eq '?' &amp;&amp; $removed eq '?')
+                || ($added =~ /^\? / || $removed =~ /^\? /)) {
+                $incomplete_data = 1;
+            }
</ins><span class="cx"> 
</span><span class="cx">             # An operation, done by 'who' at time 'when', has a number of
</span><span class="cx">             # 'changes' associated with it.
</span><span class="lines">@@ -2973,11 +3782,15 @@
</span><span class="cx">             $operation-&gt;{'who'} = $who;
</span><span class="cx">             $operation-&gt;{'when'} = $when;
</span><span class="cx"> 
</span><del>-            $change{'field'} = $field;
</del><span class="cx">             $change{'fieldname'} = $fieldname;
</span><span class="cx">             $change{'attachid'} = $attachid;
</span><span class="cx">             $change{'removed'} = $removed;
</span><span class="cx">             $change{'added'} = $added;
</span><ins>+            
+            if ($comment_id) {
+                $change{'comment'} = Bugzilla::Comment-&gt;new($comment_id);
+            }
+
</ins><span class="cx">             push (@$changes, \%change);
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -2992,7 +3805,7 @@
</span><span class="cx"> 
</span><span class="cx"> # Update the bugs_activity table to reflect changes made in bugs.
</span><span class="cx"> sub LogActivityEntry {
</span><del>-    my ($i, $col, $removed, $added, $whoid, $timestamp) = @_;
</del><ins>+    my ($i, $col, $removed, $added, $whoid, $timestamp, $comment_id) = @_;
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx">     # in the case of CCs, deps, and keywords, there's a possibility that someone
</span><span class="cx">     # might try to add or remove a lot of them at once, which might take more
</span><span class="lines">@@ -3020,171 +3833,29 @@
</span><span class="cx">         trick_taint($removestr);
</span><span class="cx">         my $fieldid = get_field_id($col);
</span><span class="cx">         $dbh-&gt;do(&quot;INSERT INTO bugs_activity
</span><del>-                  (bug_id, who, bug_when, fieldid, removed, added)
-                  VALUES (?, ?, ?, ?, ?, ?)&quot;,
-                  undef, ($i, $whoid, $timestamp, $fieldid, $removestr, $addstr));
</del><ins>+                  (bug_id, who, bug_when, fieldid, removed, added, comment_id)
+                  VALUES (?, ?, ?, ?, ?, ?, ?)&quot;,
+                  undef, ($i, $whoid, $timestamp, $fieldid, $removestr, $addstr, $comment_id));
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-# CountOpenDependencies counts the number of open dependent bugs for a
-# list of bugs and returns a list of bug_id's and their dependency count
-# It takes one parameter:
-#  - A list of bug numbers whose dependencies are to be checked
-sub CountOpenDependencies {
-    my (@bug_list) = @_;
-    my @dependencies;
-    my $dbh = Bugzilla-&gt;dbh;
</del><ins>+# Convert WebService API and email_in.pl field names to internal DB field
+# names.
+sub map_fields {
+    my ($params, $except) = @_; 
</ins><span class="cx"> 
</span><del>-    my $sth = $dbh-&gt;prepare(
-          &quot;SELECT blocked, COUNT(bug_status) &quot; .
-            &quot;FROM bugs, dependencies &quot; .
-           &quot;WHERE &quot; . $dbh-&gt;sql_in('blocked', \@bug_list) .
-             &quot;AND bug_id = dependson &quot; .
-             &quot;AND bug_status IN (&quot; . join(', ', map {$dbh-&gt;quote($_)} BUG_STATE_OPEN)  . &quot;) &quot; .
-          $dbh-&gt;sql_group_by('blocked'));
-    $sth-&gt;execute();
-
-    while (my ($bug_id, $dependencies) = $sth-&gt;fetchrow_array()) {
-        push(@dependencies, { bug_id       =&gt; $bug_id,
-                              dependencies =&gt; $dependencies });
-    }
-
-    return @dependencies;
-}
-
-# If a bug is moved to a product which allows less votes per bug
-# compared to the previous product, extra votes need to be removed.
-sub RemoveVotes {
-    my ($id, $who, $reason) = (@_);
-    my $dbh = Bugzilla-&gt;dbh;
-
-    my $whopart = ($who) ? &quot; AND votes.who = $who&quot; : &quot;&quot;;
-
-    my $sth = $dbh-&gt;prepare(&quot;SELECT profiles.login_name, &quot; .
-                            &quot;profiles.userid, votes.vote_count, &quot; .
-                            &quot;products.votesperuser, products.maxvotesperbug &quot; .
-                            &quot;FROM profiles &quot; . 
-                            &quot;LEFT JOIN votes ON profiles.userid = votes.who &quot; .
-                            &quot;LEFT JOIN bugs ON votes.bug_id = bugs.bug_id &quot; .
-                            &quot;LEFT JOIN products ON products.id = bugs.product_id &quot; .
-                            &quot;WHERE votes.bug_id = ? &quot; . $whopart);
-    $sth-&gt;execute($id);
-    my @list;
-    while (my ($name, $userid, $oldvotes, $votesperuser, $maxvotesperbug) = $sth-&gt;fetchrow_array()) {
-        push(@list, [$name, $userid, $oldvotes, $votesperuser, $maxvotesperbug]);
-    }
-
-    # @messages stores all emails which have to be sent, if any.
-    # This array is passed to the caller which will send these emails itself.
-    my @messages = ();
-
-    if (scalar(@list)) {
-        foreach my $ref (@list) {
-            my ($name, $userid, $oldvotes, $votesperuser, $maxvotesperbug) = (@$ref);
-
-            $maxvotesperbug = min($votesperuser, $maxvotesperbug);
-
-            # If this product allows voting and the user's votes are in
-            # the acceptable range, then don't do anything.
-            next if $votesperuser &amp;&amp; $oldvotes &lt;= $maxvotesperbug;
-
-            # If the user has more votes on this bug than this product
-            # allows, then reduce the number of votes so it fits
-            my $newvotes = $maxvotesperbug;
-
-            my $removedvotes = $oldvotes - $newvotes;
-
-            if ($newvotes) {
-                $dbh-&gt;do(&quot;UPDATE votes SET vote_count = ? &quot; .
-                         &quot;WHERE bug_id = ? AND who = ?&quot;,
-                         undef, ($newvotes, $id, $userid));
-            } else {
-                $dbh-&gt;do(&quot;DELETE FROM votes WHERE bug_id = ? AND who = ?&quot;,
-                         undef, ($id, $userid));
-            }
-
-            # Notice that we did not make sure that the user fit within the $votesperuser
-            # range.  This is considered to be an acceptable alternative to losing votes
-            # during product moves.  Then next time the user attempts to change their votes,
-            # they will be forced to fit within the $votesperuser limit.
-
-            # Now lets send the e-mail to alert the user to the fact that their votes have
-            # been reduced or removed.
-            my $vars = {
-                'to' =&gt; $name . Bugzilla-&gt;params-&gt;{'emailsuffix'},
-                'bugid' =&gt; $id,
-                'reason' =&gt; $reason,
-
-                'votesremoved' =&gt; $removedvotes,
-                'votesold' =&gt; $oldvotes,
-                'votesnew' =&gt; $newvotes,
-            };
-
-            my $voter = new Bugzilla::User($userid);
-            my $template = Bugzilla-&gt;template_inner($voter-&gt;settings-&gt;{'lang'}-&gt;{'value'});
-
-            my $msg;
-            $template-&gt;process(&quot;email/votes-removed.txt.tmpl&quot;, $vars, \$msg);
-            push(@messages, $msg);
</del><ins>+    my %field_values;
+    foreach my $field (keys %$params) {
+        my $field_name;
+        if ($except-&gt;{$field}) {
+           $field_name = $field;
</ins><span class="cx">         }
</span><del>-        Bugzilla-&gt;template_inner(&quot;&quot;);
-
-        my $votes = $dbh-&gt;selectrow_array(&quot;SELECT SUM(vote_count) &quot; .
-                                          &quot;FROM votes WHERE bug_id = ?&quot;,
-                                          undef, $id) || 0;
-        $dbh-&gt;do(&quot;UPDATE bugs SET votes = ? WHERE bug_id = ?&quot;,
-                 undef, ($votes, $id));
-    }
-    # Now return the array containing emails to be sent.
-    return \@messages;
-}
-
-# If a user votes for a bug, or the number of votes required to
-# confirm a bug has been reduced, check if the bug is now confirmed.
-sub CheckIfVotedConfirmed {
-    my ($id, $who) = (@_);
-    my $dbh = Bugzilla-&gt;dbh;
-
-    # XXX - Use bug methods to update the bug status and everconfirmed.
-    my $bug = new Bugzilla::Bug($id);
-
-    my ($votes, $status, $everconfirmed, $votestoconfirm, $timestamp) =
-        $dbh-&gt;selectrow_array(&quot;SELECT votes, bug_status, everconfirmed, &quot; .
-                              &quot;       votestoconfirm, NOW() &quot; .
-                              &quot;FROM bugs INNER JOIN products &quot; .
-                              &quot;                  ON products.id = bugs.product_id &quot; .
-                              &quot;WHERE bugs.bug_id = ?&quot;,
-                              undef, $id);
-
-    my $ret = 0;
-    if ($votes &gt;= $votestoconfirm &amp;&amp; !$everconfirmed) {
-        $bug-&gt;add_comment('', { type =&gt; CMT_POPULAR_VOTES });
-        $bug-&gt;update();
-
-        if ($status eq 'UNCONFIRMED') {
-            my $fieldid = get_field_id(&quot;bug_status&quot;);
-            $dbh-&gt;do(&quot;UPDATE bugs SET bug_status = 'NEW', everconfirmed = 1, &quot; .
-                     &quot;delta_ts = ? WHERE bug_id = ?&quot;,
-                     undef, ($timestamp, $id));
-            $dbh-&gt;do(&quot;INSERT INTO bugs_activity &quot; .
-                     &quot;(bug_id, who, bug_when, fieldid, removed, added) &quot; .
-                     &quot;VALUES (?, ?, ?, ?, ?, ?)&quot;,
-                     undef, ($id, $who, $timestamp, $fieldid, 'UNCONFIRMED', 'NEW'));
-        }
</del><span class="cx">         else {
</span><del>-            $dbh-&gt;do(&quot;UPDATE bugs SET everconfirmed = 1, delta_ts = ? &quot; .
-                     &quot;WHERE bug_id = ?&quot;, undef, ($timestamp, $id));
</del><ins>+            $field_name = FIELD_MAP-&gt;{$field} || $field;
</ins><span class="cx">         }
</span><del>-
-        my $fieldid = get_field_id(&quot;everconfirmed&quot;);
-        $dbh-&gt;do(&quot;INSERT INTO bugs_activity &quot; .
-                 &quot;(bug_id, who, bug_when, fieldid, removed, added) &quot; .
-                 &quot;VALUES (?, ?, ?, ?, ?, ?)&quot;,
-                 undef, ($id, $who, $timestamp, $fieldid, '0', '1'));
-
-        $ret = 1;
</del><ins>+        $field_values{$field_name} = $params-&gt;{$field};
</ins><span class="cx">     }
</span><del>-    return $ret;
</del><ins>+    return \%field_values;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ################################################################################
</span><span class="lines">@@ -3220,12 +3891,27 @@
</span><span class="cx">     } elsif (trim($oldvalue) eq trim($newvalue)) {
</span><span class="cx">         return 1;
</span><span class="cx">     # numeric fields need to be compared using ==
</span><del>-    } elsif (($field eq 'estimated_time' || $field eq 'remaining_time')
</del><ins>+    } elsif (($field eq 'estimated_time' || $field eq 'remaining_time' 
+              || $field eq 'work_time')
</ins><span class="cx">              &amp;&amp; $oldvalue == $newvalue)
</span><span class="cx">     {
</span><span class="cx">         return 1;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    my @priv_results;
+    Bugzilla::Hook::process('bug_check_can_change_field',
+        { bug =&gt; $self, field =&gt; $field, 
+          new_value =&gt; $newvalue, old_value =&gt; $oldvalue, 
+          priv_results =&gt; \@priv_results });
+    if (my $priv_required = first { $_ &gt; 0 } @priv_results) {
+        $$PrivilegesRequired = $priv_required;
+        return 0;
+    }
+    my $allow_found = first { $_ == 0 } @priv_results;
+    if (defined $allow_found) {
+        return 1;
+    }
+
</ins><span class="cx">     # Allow anyone to change comments.
</span><span class="cx">     if ($field =~ /^longdesc/) {
</span><span class="cx">         return 1;
</span><span class="lines">@@ -3235,16 +3921,15 @@
</span><span class="cx">     # We store the required permission set into the $PrivilegesRequired
</span><span class="cx">     # variable which gets passed to the error template.
</span><span class="cx">     #
</span><del>-    # $PrivilegesRequired = 0 : no privileges required;
-    # $PrivilegesRequired = 1 : the reporter, assignee or an empowered user;
-    # $PrivilegesRequired = 2 : the assignee or an empowered user;
-    # $PrivilegesRequired = 3 : an empowered user.
</del><ins>+    # $PrivilegesRequired = PRIVILEGES_REQUIRED_NONE : no privileges required;
+    # $PrivilegesRequired = PRIVILEGES_REQUIRED_REPORTER : the reporter, assignee or an empowered user;
+    # $PrivilegesRequired = PRIVILEGES_REQUIRED_ASSIGNEE : the assignee or an empowered user;
+    # $PrivilegesRequired = PRIVILEGES_REQUIRED_EMPOWERED : an empowered user.
</ins><span class="cx">     
</span><span class="cx">     # Only users in the time-tracking group can change time-tracking fields.
</span><del>-    if ( grep($_ eq $field, qw(deadline estimated_time remaining_time)) ) {
-        my $tt_group = Bugzilla-&gt;params-&gt;{timetrackinggroup};
-        if (!$tt_group || !$user-&gt;in_group($tt_group)) {
-            $$PrivilegesRequired = 3;
</del><ins>+    if ( grep($_ eq $field, TIMETRACKING_FIELDS) ) {
+        if (!$user-&gt;is_timetracker) {
+            $$PrivilegesRequired = PRIVILEGES_REQUIRED_EMPOWERED;
</ins><span class="cx">             return 0;
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -3255,12 +3940,8 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # *Only* users with (product-specific) &quot;canconfirm&quot; privs can confirm bugs.
</span><del>-    if ($field eq 'canconfirm'
-        || ($field eq 'bug_status'
-            &amp;&amp; $oldvalue eq 'UNCONFIRMED'
-            &amp;&amp; is_open_state($newvalue)))
-    {
-        $$PrivilegesRequired = 3;
</del><ins>+    if ($self-&gt;_changes_everconfirmed($field, $oldvalue, $newvalue)) {
+        $$PrivilegesRequired = PRIVILEGES_REQUIRED_EMPOWERED;
</ins><span class="cx">         return $user-&gt;in_group('canconfirm', $self-&gt;{'product_id'});
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -3291,26 +3972,38 @@
</span><span class="cx">     #   in that case we will have already returned 1 above
</span><span class="cx">     #   when checking for the assignee of the bug.
</span><span class="cx">     if ($field eq 'assigned_to') {
</span><del>-        $$PrivilegesRequired = 2;
</del><ins>+        $$PrivilegesRequired = PRIVILEGES_REQUIRED_ASSIGNEE;
</ins><span class="cx">         return 0;
</span><span class="cx">     }
</span><span class="cx">     # - change the QA contact
</span><span class="cx">     if ($field eq 'qa_contact') {
</span><del>-        $$PrivilegesRequired = 2;
</del><ins>+        $$PrivilegesRequired = PRIVILEGES_REQUIRED_ASSIGNEE;
</ins><span class="cx">         return 0;
</span><span class="cx">     }
</span><span class="cx">     # - change the target milestone
</span><span class="cx">     if ($field eq 'target_milestone') {
</span><del>-        $$PrivilegesRequired = 2;
</del><ins>+        $$PrivilegesRequired = PRIVILEGES_REQUIRED_ASSIGNEE;
</ins><span class="cx">         return 0;
</span><span class="cx">     }
</span><span class="cx">     # - change the priority (unless he could have set it originally)
</span><span class="cx">     if ($field eq 'priority'
</span><span class="cx">         &amp;&amp; !Bugzilla-&gt;params-&gt;{'letsubmitterchoosepriority'})
</span><span class="cx">     {
</span><del>-        $$PrivilegesRequired = 2;
</del><ins>+        $$PrivilegesRequired = PRIVILEGES_REQUIRED_ASSIGNEE;
</ins><span class="cx">         return 0;
</span><span class="cx">     }
</span><ins>+    # - unconfirm bugs (confirming them is handled above)
+    if ($field eq 'everconfirmed') {
+        $$PrivilegesRequired = PRIVILEGES_REQUIRED_ASSIGNEE;
+        return 0;
+    }
+    # - change the status from one open state to another
+    if ($field eq 'bug_status'
+        &amp;&amp; is_open_state($oldvalue) &amp;&amp; is_open_state($newvalue)) 
+    {
+       $$PrivilegesRequired = PRIVILEGES_REQUIRED_ASSIGNEE;
+       return 0;
+    }
</ins><span class="cx"> 
</span><span class="cx">     # The reporter is allowed to change anything else.
</span><span class="cx">     if (!$self-&gt;{'error'} &amp;&amp; $self-&gt;{'reporter_id'} == $user-&gt;id) {
</span><span class="lines">@@ -3319,67 +4012,32 @@
</span><span class="cx"> 
</span><span class="cx">     # If we haven't returned by this point, then the user doesn't
</span><span class="cx">     # have the necessary permissions to change this field.
</span><del>-    $$PrivilegesRequired = 1;
</del><ins>+    $$PrivilegesRequired = PRIVILEGES_REQUIRED_REPORTER;
</ins><span class="cx">     return 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# A helper for check_can_change_field
+sub _changes_everconfirmed {
+    my ($self, $field, $old, $new) = @_;
+    return 1 if $field eq 'everconfirmed';
+    if ($field eq 'bug_status') {
+        if ($self-&gt;everconfirmed) {
+            # Moving a confirmed bug to UNCONFIRMED will change everconfirmed.
+            return 1 if $new eq 'UNCONFIRMED';
+        }
+        else {
+            # Moving an unconfirmed bug to an open state that isn't 
+            # UNCONFIRMED will confirm the bug.
+            return 1 if (is_open_state($new) and $new ne 'UNCONFIRMED');
+        }
+    }
+    return 0;
+}
+
</ins><span class="cx"> #
</span><span class="cx"> # Field Validation
</span><span class="cx"> #
</span><span class="cx"> 
</span><del>-# Validates and verifies a bug ID, making sure the number is a 
-# positive integer, that it represents an existing bug in the
-# database, and that the user is authorized to access that bug.
-# We detaint the number here, too.
-sub ValidateBugID {
-    my ($id, $field) = @_;
-    my $dbh = Bugzilla-&gt;dbh;
-    my $user = Bugzilla-&gt;user;
-
-    ThrowUserError('improper_bug_id_field_value', { field =&gt; $field }) unless defined $id;
-
-    # Get rid of leading '#' (number) mark, if present.
-    $id =~ s/^\s*#//;
-    # Remove whitespace
-    $id = trim($id);
-
-    # If the ID isn't a number, it might be an alias, so try to convert it.
-    my $alias = $id;
-    if (!detaint_natural($id)) {
-        $id = bug_alias_to_id($alias);
-        $id || ThrowUserError(&quot;improper_bug_id_field_value&quot;,
-                              {'bug_id' =&gt; $alias,
-                               'field'  =&gt; $field });
-    }
-    
-    # Modify the calling code's original variable to contain the trimmed,
-    # converted-from-alias ID.
-    $_[0] = $id;
-    
-    # First check that the bug exists
-    $dbh-&gt;selectrow_array(&quot;SELECT bug_id FROM bugs WHERE bug_id = ?&quot;, undef, $id)
-      || ThrowUserError(&quot;bug_id_does_not_exist&quot;, {'bug_id' =&gt; $id});
-
-    unless ($field &amp;&amp; $field =~ /^(dependson|blocked|dup_id)$/) {
-        check_is_visible($id);
-    }
-}
-
-sub check_is_visible {
-    my $id = shift;
-    my $user = Bugzilla-&gt;user;
-
-    return if $user-&gt;can_see_bug($id);
-
-    # The error the user sees depends on whether or not they are logged in
-    # (i.e. $user-&gt;id contains the user's positive integer ID).
-    if ($user-&gt;id) {
-        ThrowUserError(&quot;bug_access_denied&quot;, {'bug_id' =&gt; $id});
-    } else {
-        ThrowUserError(&quot;bug_access_query&quot;, {'bug_id' =&gt; $id});
-    }
-}
-
</del><span class="cx"> # Validate and return a hash of dependencies
</span><span class="cx"> sub ValidateDependencies {
</span><span class="cx">     my $fields = {};
</span><span class="lines">@@ -3451,67 +4109,55 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> #####################################################################
</span><del>-# Autoloaded Accessors
</del><ins>+# Custom Field Accessors
</ins><span class="cx"> #####################################################################
</span><span class="cx"> 
</span><del>-# Determines whether an attribute access trapped by the AUTOLOAD function
-# is for a valid bug attribute.  Bug attributes are properties and methods
-# predefined by this module as well as bug fields for which an accessor
-# can be defined by AUTOLOAD at runtime when the accessor is first accessed.
-#
-# XXX Strangely, some predefined attributes are on the list, but others aren't,
-# and the original code didn't specify why that is.  Presumably the only
-# attributes that need to be on this list are those that aren't predefined;
-# we should verify that and update the list accordingly.
-#
-sub _validate_attribute {
-    my ($attribute) = @_;
</del><ins>+sub _create_cf_accessors {
+    my ($invocant) = @_;
+    my $class = ref($invocant) || $invocant;
+    return if Bugzilla-&gt;request_cache-&gt;{&quot;${class}_cf_accessors_created&quot;};
</ins><span class="cx"> 
</span><del>-    my @valid_attributes = (
-        # Miscellaneous properties and methods.
-        qw(error groups product_id component_id
-           longdescs milestoneurl attachments
-           isopened isunconfirmed
-           flag_types num_attachment_flag_types
-           show_attachment_flags any_flags_requesteeble),
</del><ins>+    my $fields = Bugzilla-&gt;fields({ custom =&gt; 1 });
+    foreach my $field (@$fields) {
+        my $accessor = $class-&gt;_accessor_for($field);
+        my $name = &quot;${class}::&quot; . $field-&gt;name;
+        {
+            no strict 'refs';
+            next if defined *{$name};
+            *{$name} = $accessor;
+        }
+    }
</ins><span class="cx"> 
</span><del>-        # Bug fields.
-        Bugzilla::Bug-&gt;fields
-    );
</del><ins>+    Bugzilla-&gt;request_cache-&gt;{&quot;${class}_cf_accessors_created&quot;} = 1;
+}
</ins><span class="cx"> 
</span><del>-    return grep($attribute eq $_, @valid_attributes) ? 1 : 0;
</del><ins>+sub _accessor_for {
+    my ($class, $field) = @_;
+    if ($field-&gt;type == FIELD_TYPE_MULTI_SELECT) {
+        return $class-&gt;_multi_select_accessor($field-&gt;name);
+    }
+    return $class-&gt;_cf_accessor($field-&gt;name);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub AUTOLOAD {
-  use vars qw($AUTOLOAD);
-  my $attr = $AUTOLOAD;
</del><ins>+sub _cf_accessor {
+    my ($class, $field) = @_;
+    my $accessor = sub {
+        my ($self) = @_;
+        return $self-&gt;{$field};
+    };
+    return $accessor;
+}
</ins><span class="cx"> 
</span><del>-  $attr =~ s/.*:://;
-  return unless $attr=~ /[^A-Z]/;
-  if (!_validate_attribute($attr)) {
-      require Carp;
-      Carp::confess(&quot;invalid bug attribute $attr&quot;);
-  }
-
-  no strict 'refs';
-  *$AUTOLOAD = sub {
-      my $self = shift;
-
-      return $self-&gt;{$attr} if defined $self-&gt;{$attr};
-
-      $self-&gt;{_multi_selects} ||= [Bugzilla-&gt;get_fields(
-          {custom =&gt; 1, type =&gt; FIELD_TYPE_MULTI_SELECT })];
-      if ( grep($_-&gt;name eq $attr, @{$self-&gt;{_multi_selects}}) ) {
-          $self-&gt;{$attr} ||= Bugzilla-&gt;dbh-&gt;selectcol_arrayref(
-              &quot;SELECT value FROM bug_$attr WHERE bug_id = ? ORDER BY value&quot;,
-              undef, $self-&gt;id);
-          return $self-&gt;{$attr};
-      }
-
-      return '';
-  };
-
-  goto &amp;$AUTOLOAD;
</del><ins>+sub _multi_select_accessor {
+    my ($class, $field) = @_;
+    my $accessor = sub {
+        my ($self) = @_;
+        $self-&gt;{$field} ||= Bugzilla-&gt;dbh-&gt;selectcol_arrayref(
+            &quot;SELECT value FROM bug_$field WHERE bug_id = ? ORDER BY value&quot;,
+            undef, $self-&gt;id);
+        return $self-&gt;{$field};
+    };
+    return $accessor;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> 1;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaBugMailpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/BugMail.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/BugMail.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/BugMail.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -27,6 +27,9 @@
</span><span class="cx"> #                 J. Paul Reed &lt;preed@sigkill.com&gt;
</span><span class="cx"> #                 Gervase Markham &lt;gerv@gerv.net&gt;
</span><span class="cx"> #                 Byron Jones &lt;bugzilla@glob.com.au&gt;
</span><ins>+#                 Reed Loden &lt;reed@reedloden.com&gt;
+#                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
+#                 Guy Pyrzak &lt;guy.pyrzak@gmail.com&gt;
</ins><span class="cx"> 
</span><span class="cx"> use strict;
</span><span class="cx"> 
</span><span class="lines">@@ -37,68 +40,27 @@
</span><span class="cx"> use Bugzilla::Constants;
</span><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> use Bugzilla::Bug;
</span><del>-use Bugzilla::Classification;
-use Bugzilla::Product;
-use Bugzilla::Component;
-use Bugzilla::Status;
</del><ins>+use Bugzilla::Comment;
</ins><span class="cx"> use Bugzilla::Mailer;
</span><ins>+use Bugzilla::Hook;
</ins><span class="cx"> 
</span><span class="cx"> use Date::Parse;
</span><span class="cx"> use Date::Format;
</span><ins>+use Scalar::Util qw(blessed);
+use List::MoreUtils qw(uniq);
</ins><span class="cx"> 
</span><del>-use constant FORMAT_TRIPLE =&gt; &quot;%19s|%-28s|%-28s&quot;;
-use constant FORMAT_3_SIZE =&gt; [19,28,28];
-use constant FORMAT_DOUBLE =&gt; &quot;%19s %-55s&quot;;
-use constant FORMAT_2_SIZE =&gt; [19,55];
-
</del><span class="cx"> use constant BIT_DIRECT    =&gt; 1;
</span><span class="cx"> use constant BIT_WATCHING  =&gt; 2;
</span><span class="cx"> 
</span><del>-# We need these strings for the X-Bugzilla-Reasons header
-# Note: this hash uses &quot;,&quot; rather than &quot;=&gt;&quot; to avoid auto-quoting of the LHS.
-use constant REL_NAMES =&gt; {
-    REL_ASSIGNEE      , &quot;AssignedTo&quot;, 
-    REL_REPORTER      , &quot;Reporter&quot;,
-    REL_QA            , &quot;QAcontact&quot;,
-    REL_CC            , &quot;CC&quot;,
-    REL_VOTER         , &quot;Voter&quot;,
-    REL_GLOBAL_WATCHER, &quot;GlobalWatcher&quot;
-};
-
-# We use this instead of format because format doesn't deal well with
-# multi-byte languages.
-sub multiline_sprintf {
-    my ($format, $args, $sizes) = @_;
-    my @parts;
-    my @my_sizes = @$sizes; # Copy this so we don't modify the input array.
-    foreach my $string (@$args) {
-        my $size = shift @my_sizes;
-        my @pieces = split(&quot;\n&quot;, wrap_hard($string, $size));
-        push(@parts, \@pieces);
-    }
-
-    my $formatted;
-    while (1) {
-        # Get the first item of each part.
-        my @line = map { shift @$_ } @parts;
-        # If they're all undef, we're done.
-        last if !grep { defined $_ } @line;
-        # Make any single undef item into ''
-        @line = map { defined $_ ? $_ : '' } @line;
-        # And append a formatted line
-        $formatted .= sprintf($format, @line);
-        # Remove trailing spaces, or they become lots of =20's in 
-        # quoted-printable emails.
-        $formatted =~ s/\s+$//;
-        $formatted .= &quot;\n&quot;;
-    }
-    return $formatted;
</del><ins>+sub relationships {
+    my $ref = RELATIONSHIPS;
+    # Clone it so that we don't modify the constant;
+    my %relationships = %$ref;
+    Bugzilla::Hook::process('bugmail_relationships', 
+                            { relationships =&gt; \%relationships });
+    return %relationships;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub three_columns {
-    return multiline_sprintf(FORMAT_TRIPLE, \@_, FORMAT_3_SIZE);
-}
-
</del><span class="cx"> # This is a bit of a hack, basically keeping the old system()
</span><span class="cx"> # cmd line interface. Should clean this up at some point.
</span><span class="cx"> #
</span><span class="lines">@@ -108,248 +70,67 @@
</span><span class="cx"> # roles when the email is sent.
</span><span class="cx"> # All the names are email addresses, not userids
</span><span class="cx"> # values are scalars, except for cc, which is a list
</span><del>-# This hash usually comes from the &quot;mailrecipients&quot; var in a template call.
</del><span class="cx"> sub Send {
</span><del>-    my ($id, $forced) = (@_);
</del><ins>+    my ($id, $forced, $params) = @_;
+    $params ||= {};
</ins><span class="cx"> 
</span><del>-    my @headerlist;
-    my %defmailhead;
-    my %fielddescription;
-
-    my $msg = &quot;&quot;;
-
</del><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><ins>+    my $bug = new Bugzilla::Bug($id);
</ins><span class="cx"> 
</span><del>-    # XXX - These variables below are useless. We could use field object
-    # methods directly. But we first have to implement a cache in
-    # Bugzilla-&gt;get_fields to avoid querying the DB all the time.
-    foreach my $field (Bugzilla-&gt;get_fields({obsolete =&gt; 0})) {
-        push(@headerlist, $field-&gt;name);
-        $defmailhead{$field-&gt;name} = $field-&gt;in_new_bugmail;
-        $fielddescription{$field-&gt;name} = $field-&gt;description;
-    }
</del><ins>+    my $start = $bug-&gt;lastdiffed;
+    my $end   = $dbh-&gt;selectrow_array('SELECT LOCALTIMESTAMP(0)');
</ins><span class="cx"> 
</span><del>-    my %values = %{$dbh-&gt;selectrow_hashref(
-        'SELECT ' . join(',', editable_bug_fields()) . ', reporter,
-                lastdiffed AS start_time, LOCALTIMESTAMP(0) AS end_time
-           FROM bugs WHERE bug_id = ?',
-        undef, $id)};
</del><ins>+    # Bugzilla::User objects of people in various roles. More than one person
+    # can 'have' a role, if the person in that role has changed, or people are
+    # watching.
+    my @assignees = ($bug-&gt;assigned_to);
+    my @qa_contacts = $bug-&gt;qa_contact || ();
</ins><span class="cx"> 
</span><del>-    my $product = new Bugzilla::Product($values{product_id});
-    $values{product} = $product-&gt;name;
-    if (Bugzilla-&gt;params-&gt;{'useclassification'}) {
-        $values{classification} = Bugzilla::Classification-&gt;new($product-&gt;classification_id)-&gt;name;
-    }
-    my $component = new Bugzilla::Component($values{component_id});
-    $values{component} = $component-&gt;name;
-
-    my ($start, $end) = ($values{start_time}, $values{end_time});
-
-    # User IDs of people in various roles. More than one person can 'have' a 
-    # role, if the person in that role has changed, or people are watching.
-    my $reporter = $values{'reporter'};
-    my @assignees = ($values{'assigned_to'});
-    my @qa_contacts = ($values{'qa_contact'});
-
-    my $cc_users = $dbh-&gt;selectall_arrayref(
-           &quot;SELECT cc.who, profiles.login_name
-              FROM cc
-        INNER JOIN profiles
-                ON cc.who = profiles.userid
-             WHERE bug_id = ?&quot;,
-           undef, $id);
-
-    my (@ccs, @cc_login_names);
-    foreach my $cc_user (@$cc_users) {
-        my ($user_id, $user_login) = @$cc_user;
-        push (@ccs, $user_id);
-        push (@cc_login_names, $user_login);
-    }
-
</del><ins>+    my @ccs = @{ $bug-&gt;cc_users };
</ins><span class="cx">     # Include the people passed in as being in particular roles.
</span><span class="cx">     # This can include people who used to hold those roles.
</span><span class="cx">     # At this point, we don't care if there are duplicates in these arrays.
</span><span class="cx">     my $changer = $forced-&gt;{'changer'};
</span><span class="cx">     if ($forced-&gt;{'owner'}) {
</span><del>-        push (@assignees, login_to_id($forced-&gt;{'owner'}, THROW_ERROR));
</del><ins>+        push (@assignees, Bugzilla::User-&gt;check($forced-&gt;{'owner'}));
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     if ($forced-&gt;{'qacontact'}) {
</span><del>-        push (@qa_contacts, login_to_id($forced-&gt;{'qacontact'}, THROW_ERROR));
</del><ins>+        push (@qa_contacts, Bugzilla::User-&gt;check($forced-&gt;{'qacontact'}));
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     if ($forced-&gt;{'cc'}) {
</span><span class="cx">         foreach my $cc (@{$forced-&gt;{'cc'}}) {
</span><del>-            push(@ccs, login_to_id($cc, THROW_ERROR));
</del><ins>+            push(@ccs, Bugzilla::User-&gt;check($cc));
</ins><span class="cx">         }
</span><span class="cx">     }
</span><del>-    
-    # Convert to names, for later display
-    $values{'changer'} = $changer;
-    # If no changer is specified, then it has no name.
-    if ($changer) {
-        $values{'changername'} = Bugzilla::User-&gt;new({name =&gt; $changer})-&gt;name;
-    }
-    $values{'assigned_to'} = user_id_to_login($values{'assigned_to'});
-    $values{'reporter'} = user_id_to_login($values{'reporter'});
-    if ($values{'qa_contact'}) {
-        $values{'qa_contact'} = user_id_to_login($values{'qa_contact'});
-    }
-    $values{'cc'} = join(', ', @cc_login_names);
-    $values{'estimated_time'} = format_time_decimal($values{'estimated_time'});
</del><ins>+    my %user_cache = map { $_-&gt;id =&gt; $_ } (@assignees, @qa_contacts, @ccs);
</ins><span class="cx"> 
</span><del>-    if ($values{'deadline'}) {
-        $values{'deadline'} = time2str(&quot;%Y-%m-%d&quot;, str2time($values{'deadline'}));
</del><ins>+    my @diffs;
+    if (!$start) {
+        @diffs = _get_new_bugmail_fields($bug);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    my $dependslist = $dbh-&gt;selectcol_arrayref(
-        'SELECT dependson FROM dependencies
-         WHERE blocked = ? ORDER BY dependson',
-        undef, ($id));
-
-    $values{'dependson'} = join(&quot;,&quot;, @$dependslist);
-
-    my $blockedlist = $dbh-&gt;selectcol_arrayref(
-        'SELECT blocked FROM dependencies
-         WHERE dependson = ? ORDER BY blocked',
-        undef, ($id));
-
-    $values{'blocked'} = join(&quot;,&quot;, @$blockedlist);
-
-    my @args = ($id);
-
-    # If lastdiffed is NULL, then we don't limit the search on time.
-    my $when_restriction = '';
-    if ($start) {
-        $when_restriction = ' AND bug_when &gt; ? AND bug_when &lt;= ?';
-        push @args, ($start, $end);
</del><ins>+    if ($params-&gt;{dep_only}) {
+        push(@diffs, { field_name =&gt; 'bug_status',
+                       old =&gt; $params-&gt;{changes}-&gt;{bug_status}-&gt;[0],
+                       new =&gt; $params-&gt;{changes}-&gt;{bug_status}-&gt;[1],
+                       login_name =&gt; $changer-&gt;login,
+                       blocker =&gt; $params-&gt;{blocker} },
+                     { field_name =&gt; 'resolution',
+                       old =&gt; $params-&gt;{changes}-&gt;{resolution}-&gt;[0],
+                       new =&gt; $params-&gt;{changes}-&gt;{resolution}-&gt;[1],
+                       login_name =&gt; $changer-&gt;login,
+                       blocker =&gt; $params-&gt;{blocker} });
</ins><span class="cx">     }
</span><del>-    
-    my $diffs = $dbh-&gt;selectall_arrayref(
-           &quot;SELECT profiles.login_name, profiles.realname, fielddefs.description,
-                   bugs_activity.bug_when, bugs_activity.removed, 
-                   bugs_activity.added, bugs_activity.attach_id, fielddefs.name
-              FROM bugs_activity
-        INNER JOIN fielddefs
-                ON fielddefs.id = bugs_activity.fieldid
-        INNER JOIN profiles
-                ON profiles.userid = bugs_activity.who
-             WHERE bugs_activity.bug_id = ?
-                   $when_restriction
-          ORDER BY bugs_activity.bug_when&quot;, undef, @args);
-
-    my @new_depbugs;
-    my $difftext = &quot;&quot;;
-    my $diffheader = &quot;&quot;;
-    my @diffparts;
-    my $lastwho = &quot;&quot;;
-    my $fullwho;
-    my @changedfields;
-    foreach my $ref (@$diffs) {
-        my ($who, $whoname, $what, $when, $old, $new, $attachid, $fieldname) = (@$ref);
-        my $diffpart = {};
-        if ($who ne $lastwho) {
-            $lastwho = $who;
-            $fullwho = $whoname ? &quot;$whoname &lt;$who&gt;&quot; : $who;
-            $diffheader = &quot;\n$fullwho changed:\n\n&quot;;
-            $diffheader .= three_columns(&quot;What    &quot;, &quot;Removed&quot;, &quot;Added&quot;);
-            $diffheader .= ('-' x 76) . &quot;\n&quot;;
-        }
-        $what =~ s/^(Attachment )?/Attachment #$attachid / if $attachid;
-        if( $fieldname eq 'estimated_time' ||
-            $fieldname eq 'remaining_time' ) {
-            $old = format_time_decimal($old);
-            $new = format_time_decimal($new);
-        }
-        if ($fieldname eq 'dependson') {
-            push(@new_depbugs, grep {$_ =~ /^\d+$/} split(/[\s,]+/, $new));
-        }
-        if ($attachid) {
-            ($diffpart-&gt;{'isprivate'}) = $dbh-&gt;selectrow_array(
-                'SELECT isprivate FROM attachments WHERE attach_id = ?',
-                undef, ($attachid));
-        }
-        $difftext = three_columns($what, $old, $new);
-        $diffpart-&gt;{'header'} = $diffheader;
-        $diffpart-&gt;{'fieldname'} = $fieldname;
-        $diffpart-&gt;{'text'} = $difftext;
-        push(@diffparts, $diffpart);
-        push(@changedfields, $what);
</del><ins>+    else {
+        push(@diffs, _get_diffs($bug, $end, \%user_cache));
</ins><span class="cx">     }
</span><del>-    $values{'changed_fields'} = join(' ', @changedfields);
</del><span class="cx"> 
</span><del>-    my @depbugs;
-    my $deptext = &quot;&quot;;
-    # Do not include data about dependent bugs when they have just been added.
-    # Completely skip checking for dependent bugs on bug creation as all
-    # dependencies bugs will just have been added.
-    if ($start) {
-        my $dep_restriction = &quot;&quot;;
-        if (scalar @new_depbugs) {
-            $dep_restriction = &quot;AND bugs_activity.bug_id NOT IN (&quot; .
-                               join(&quot;, &quot;, @new_depbugs) . &quot;)&quot;;
-        }
</del><ins>+    my $comments = $bug-&gt;comments({ after =&gt; $start, to =&gt; $end });
+    # Skip empty comments.
+    @$comments = grep { $_-&gt;type || $_-&gt;body =~ /\S/ } @$comments;
</ins><span class="cx"> 
</span><del>-        my $dependency_diffs = $dbh-&gt;selectall_arrayref(
-           &quot;SELECT bugs_activity.bug_id, bugs.short_desc, fielddefs.name, 
-                   bugs_activity.removed, bugs_activity.added
-              FROM bugs_activity
-        INNER JOIN bugs
-                ON bugs.bug_id = bugs_activity.bug_id
-        INNER JOIN dependencies
-                ON bugs_activity.bug_id = dependencies.dependson
-        INNER JOIN fielddefs
-                ON fielddefs.id = bugs_activity.fieldid
-             WHERE dependencies.blocked = ?
-               AND (fielddefs.name = 'bug_status'
-                    OR fielddefs.name = 'resolution')
-                   $when_restriction
-                   $dep_restriction
-          ORDER BY bugs_activity.bug_when, bugs.bug_id&quot;, undef, @args);
-
-        my $thisdiff = &quot;&quot;;
-        my $lastbug = &quot;&quot;;
-        my $interestingchange = 0;
-        foreach my $dependency_diff (@$dependency_diffs) {
-            my ($depbug, $summary, $what, $old, $new) = @$dependency_diff;
-
-            if ($depbug ne $lastbug) {
-                if ($interestingchange) {
-                    $deptext .= $thisdiff;
-                }
-                $lastbug = $depbug;
-                my $urlbase = Bugzilla-&gt;params-&gt;{&quot;urlbase&quot;};
-                $thisdiff =
-                  &quot;\nBug $id depends on bug $depbug, which changed state.\n\n&quot; .
-                  &quot;Bug $depbug Summary: $summary\n&quot; .
-                  &quot;${urlbase}show_bug.cgi?id=$depbug\n\n&quot;;
-                $thisdiff .= three_columns(&quot;What    &quot;, &quot;Old Value&quot;, &quot;New Value&quot;);
-                $thisdiff .= ('-' x 76) . &quot;\n&quot;;
-                $interestingchange = 0;
-            }
-            $thisdiff .= three_columns($fielddescription{$what}, $old, $new);
-            if ($what eq 'bug_status'
-                &amp;&amp; is_open_state($old) ne is_open_state($new))
-            {
-                $interestingchange = 1;
-            }
-            push(@depbugs, $depbug);
-        }
-
-        if ($interestingchange) {
-            $deptext .= $thisdiff;
-        }
-        $deptext = trim($deptext);
-
-        if ($deptext) {
-            my $diffpart = {};
-            $diffpart-&gt;{'text'} = &quot;\n&quot; . trim(&quot;\n\n&quot; . $deptext);
-            push(@diffparts, $diffpart);
-        }
-    }
-
-    my ($raw_comments, $anyprivate, $count) = get_comments_by_bug($id, $start, $end);
-
</del><span class="cx">     ###########################################################################
</span><span class="cx">     # Start of email filtering code
</span><span class="cx">     ###########################################################################
</span><span class="lines">@@ -362,71 +143,71 @@
</span><span class="cx">     # the relationships in a hash. The keys are userids, the values are an
</span><span class="cx">     # array of role constants.
</span><span class="cx">     
</span><del>-    # Voters
-    my $voters = $dbh-&gt;selectcol_arrayref(
-        &quot;SELECT who FROM votes WHERE bug_id = ?&quot;, undef, ($id));
-        
-    $recipients{$_}-&gt;{+REL_VOTER} = BIT_DIRECT foreach (@$voters);
-
</del><span class="cx">     # CCs
</span><del>-    $recipients{$_}-&gt;{+REL_CC} = BIT_DIRECT foreach (@ccs);
</del><ins>+    $recipients{$_-&gt;id}-&gt;{+REL_CC} = BIT_DIRECT foreach (@ccs);
</ins><span class="cx">     
</span><span class="cx">     # Reporter (there's only ever one)
</span><del>-    $recipients{$reporter}-&gt;{+REL_REPORTER} = BIT_DIRECT;
</del><ins>+    $recipients{$bug-&gt;reporter-&gt;id}-&gt;{+REL_REPORTER} = BIT_DIRECT;
</ins><span class="cx">     
</span><span class="cx">     # QA Contact
</span><span class="cx">     if (Bugzilla-&gt;params-&gt;{'useqacontact'}) {
</span><span class="cx">         foreach (@qa_contacts) {
</span><span class="cx">             # QA Contact can be blank; ignore it if so.
</span><del>-            $recipients{$_}-&gt;{+REL_QA} = BIT_DIRECT if $_;
</del><ins>+            $recipients{$_-&gt;id}-&gt;{+REL_QA} = BIT_DIRECT if $_;
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # Assignee
</span><del>-    $recipients{$_}-&gt;{+REL_ASSIGNEE} = BIT_DIRECT foreach (@assignees);
</del><ins>+    $recipients{$_-&gt;id}-&gt;{+REL_ASSIGNEE} = BIT_DIRECT foreach (@assignees);
</ins><span class="cx"> 
</span><span class="cx">     # The last relevant set of people are those who are being removed from 
</span><span class="cx">     # their roles in this change. We get their names out of the diffs.
</span><del>-    foreach my $ref (@$diffs) {
-        my ($who, $whoname, $what, $when, $old, $new) = (@$ref);
-        if ($old) {
-            # You can't stop being the reporter, and mail isn't sent if you
-            # remove your vote.
</del><ins>+    foreach my $change (@diffs) {
+        if ($change-&gt;{old}) {
+            # You can't stop being the reporter, so we don't check that
+            # relationship here.
</ins><span class="cx">             # Ignore people whose user account has been deleted or renamed.
</span><del>-            if ($what eq &quot;CC&quot;) {
-                foreach my $cc_user (split(/[\s,]+/, $old)) {
</del><ins>+            if ($change-&gt;{field_name} eq 'cc') {
+                foreach my $cc_user (split(/[\s,]+/, $change-&gt;{old})) {
</ins><span class="cx">                     my $uid = login_to_id($cc_user);
</span><span class="cx">                     $recipients{$uid}-&gt;{+REL_CC} = BIT_DIRECT if $uid;
</span><span class="cx">                 }
</span><span class="cx">             }
</span><del>-            elsif ($what eq &quot;QAContact&quot;) {
-                my $uid = login_to_id($old);
</del><ins>+            elsif ($change-&gt;{field_name} eq 'qa_contact') {
+                my $uid = login_to_id($change-&gt;{old});
</ins><span class="cx">                 $recipients{$uid}-&gt;{+REL_QA} = BIT_DIRECT if $uid;
</span><span class="cx">             }
</span><del>-            elsif ($what eq &quot;AssignedTo&quot;) {
-                my $uid = login_to_id($old);
</del><ins>+            elsif ($change-&gt;{field_name} eq 'assigned_to') {
+                my $uid = login_to_id($change-&gt;{old});
</ins><span class="cx">                 $recipients{$uid}-&gt;{+REL_ASSIGNEE} = BIT_DIRECT if $uid;
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">     }
</span><ins>+
+    # Make sure %user_cache has every user in it so far referenced
+    foreach my $user_id (keys %recipients) {
+        $user_cache{$user_id} ||= new Bugzilla::User($user_id);
+    }
</ins><span class="cx">     
</span><del>-    if (Bugzilla-&gt;params-&gt;{&quot;supportwatchers&quot;}) {
-        # Find all those user-watching anyone on the current list, who is not 
-        # on it already themselves.
-        my $involved = join(&quot;,&quot;, keys %recipients);
</del><ins>+    Bugzilla::Hook::process('bugmail_recipients',
+                            { bug =&gt; $bug, recipients =&gt; \%recipients,
+                              users =&gt; \%user_cache, diffs =&gt; \@diffs });
</ins><span class="cx"> 
</span><del>-        my $userwatchers = 
-            $dbh-&gt;selectall_arrayref(&quot;SELECT watcher, watched FROM watch 
-                                      WHERE watched IN ($involved)&quot;);
</del><ins>+    # Find all those user-watching anyone on the current list, who is not
+    # on it already themselves.
+    my $involved = join(&quot;,&quot;, keys %recipients);
</ins><span class="cx"> 
</span><del>-        # Mark these people as having the role of the person they are watching
-        foreach my $watch (@$userwatchers) {
-            while (my ($role, $bits) = each %{$recipients{$watch-&gt;[1]}}) {
-                $recipients{$watch-&gt;[0]}-&gt;{$role} |= BIT_WATCHING
-                    if $bits &amp; BIT_DIRECT;
-            }
-            push (@{$watching{$watch-&gt;[0]}}, $watch-&gt;[1]);
</del><ins>+    my $userwatchers =
+        $dbh-&gt;selectall_arrayref(&quot;SELECT watcher, watched FROM watch
+                                  WHERE watched IN ($involved)&quot;);
+
+    # Mark these people as having the role of the person they are watching
+    foreach my $watch (@$userwatchers) {
+        while (my ($role, $bits) = each %{$recipients{$watch-&gt;[1]}}) {
+            $recipients{$watch-&gt;[0]}-&gt;{$role} |= BIT_WATCHING
+                if $bits &amp; BIT_DIRECT;
</ins><span class="cx">         }
</span><ins>+        push(@{$watching{$watch-&gt;[0]}}, $watch-&gt;[1]);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # Global watcher
</span><span class="lines">@@ -443,38 +224,29 @@
</span><span class="cx">     my @sent;
</span><span class="cx">     my @excluded;
</span><span class="cx"> 
</span><del>-    # Some comments are language specific. We cache them here.
-    my %comments;
</del><ins>+    # The email client will display the Date: header in the desired timezone,
+    # so we can always use UTC here.
+    my $date = $params-&gt;{dep_only} ? $end : $bug-&gt;delta_ts;
+    $date = format_time($date, '%a, %d %b %Y %T %z', 'UTC');
</ins><span class="cx"> 
</span><span class="cx">     foreach my $user_id (keys %recipients) {
</span><span class="cx">         my %rels_which_want;
</span><span class="cx">         my $sent_mail = 0;
</span><del>-
-        my $user = new Bugzilla::User($user_id);
</del><ins>+        $user_cache{$user_id} ||= new Bugzilla::User($user_id);
+        my $user = $user_cache{$user_id};
</ins><span class="cx">         # Deleted users must be excluded.
</span><span class="cx">         next unless $user;
</span><span class="cx"> 
</span><del>-        # What's the language chosen by this user for email?
-        my $lang = $user-&gt;settings-&gt;{'lang'}-&gt;{'value'};
-
</del><span class="cx">         if ($user-&gt;can_see_bug($id)) {
</span><del>-            # It's time to format language specific comments.
-            unless (exists $comments{$lang}) {
-                Bugzilla-&gt;template_inner($lang);
-                $comments{$lang} = prepare_comments($raw_comments, $count);
-                Bugzilla-&gt;template_inner(&quot;&quot;);
-            }
-
</del><span class="cx">             # Go through each role the user has and see if they want mail in
</span><span class="cx">             # that role.
</span><span class="cx">             foreach my $relationship (keys %{$recipients{$user_id}}) {
</span><del>-                if ($user-&gt;wants_bug_mail($id,
</del><ins>+                if ($user-&gt;wants_bug_mail($bug,
</ins><span class="cx">                                           $relationship, 
</span><del>-                                          $diffs, 
-                                          $comments{$lang},
-                                          $deptext,
-                                          $changer,
-                                          !$start))
</del><ins>+                                          $start ? \@diffs : [],
+                                          $comments,
+                                          $params-&gt;{dep_only},
+                                          $changer))
</ins><span class="cx">                 {
</span><span class="cx">                     $rels_which_want{$relationship} = 
</span><span class="cx">                         $recipients{$user_id}-&gt;{$relationship};
</span><span class="lines">@@ -486,48 +258,31 @@
</span><span class="cx">             # So the user exists, can see the bug, and wants mail in at least
</span><span class="cx">             # one role. But do we want to send it to them?
</span><span class="cx"> 
</span><del>-            # If we are using insiders, and the comment is private, only send 
-            # to insiders
-            my $insider_ok = 1;
-            $insider_ok = 0 if (Bugzilla-&gt;params-&gt;{&quot;insidergroup&quot;} &amp;&amp; 
-                                ($anyprivate != 0) &amp;&amp; 
-                                (!$user-&gt;groups-&gt;{Bugzilla-&gt;params-&gt;{&quot;insidergroup&quot;}}));
-
-            # We shouldn't send mail if this is a dependency mail (i.e. there 
-            # is something in @depbugs), and any of the depending bugs are not 
-            # visible to the user. This is to avoid leaking the summaries of 
-            # confidential bugs.
</del><ins>+            # We shouldn't send mail if this is a dependency mail and the
+            # depending bug is not visible to the user.
+            # This is to avoid leaking the summary of a confidential bug.
</ins><span class="cx">             my $dep_ok = 1;
</span><del>-            foreach my $dep_id (@depbugs) {
-                if (!$user-&gt;can_see_bug($dep_id)) {
-                   $dep_ok = 0;
-                   last;
-                }
</del><ins>+            if ($params-&gt;{dep_only}) {
+                $dep_ok = $user-&gt;can_see_bug($params-&gt;{blocker}-&gt;id) ? 1 : 0;
</ins><span class="cx">             }
</span><span class="cx"> 
</span><del>-            # Make sure the user isn't in the nomail list, and the insider and 
-            # dep checks passed.
-            if ($user-&gt;email_enabled &amp;&amp;
-                $insider_ok &amp;&amp;
-                $dep_ok)
-            {
</del><ins>+            # Make sure the user isn't in the nomail list, and the dep check passed.
+            if ($user-&gt;email_enabled &amp;&amp; $dep_ok) {
</ins><span class="cx">                 # OK, OK, if we must. Email the user.
</span><del>-                $sent_mail = sendMail($user, 
-                                      \@headerlist,
-                                      \%rels_which_want, 
-                                      \%values,
-                                      \%defmailhead, 
-                                      \%fielddescription, 
-                                      \@diffparts,
-                                      $comments{$lang},
-                                      $anyprivate, 
-                                      ! $start, 
-                                      $id,
-                                      exists $watching{$user_id} ?
-                                             $watching{$user_id} : undef);
</del><ins>+                $sent_mail = sendMail(
+                    { to       =&gt; $user, 
+                      bug      =&gt; $bug,
+                      comments =&gt; $comments,
+                      date     =&gt; $date,
+                      changer  =&gt; $changer,
+                      watchers =&gt; exists $watching{$user_id} ?
+                                  $watching{$user_id} : undef,
+                      diffs    =&gt; \@diffs,
+                      rels_which_want =&gt; \%rels_which_want,
+                    });
</ins><span class="cx">             }
</span><span class="cx">         }
</span><del>-       
</del><ins>+
</ins><span class="cx">         if ($sent_mail) {
</span><span class="cx">             push(@sent, $user-&gt;login); 
</span><span class="cx">         } 
</span><span class="lines">@@ -535,203 +290,204 @@
</span><span class="cx">             push(@excluded, $user-&gt;login); 
</span><span class="cx">         } 
</span><span class="cx">     }
</span><del>-    
-    $dbh-&gt;do('UPDATE bugs SET lastdiffed = ? WHERE bug_id = ?',
-             undef, ($end, $id));
</del><span class="cx"> 
</span><ins>+    # When sending bugmail about a blocker being reopened or resolved,
+    # we say nothing about changes in the bug being blocked, so we must
+    # not update lastdiffed in this case.
+    if (!$params-&gt;{dep_only}) {
+        $dbh-&gt;do('UPDATE bugs SET lastdiffed = ? WHERE bug_id = ?',
+                 undef, ($end, $id));
+        $bug-&gt;{lastdiffed} = $end;
+    }
+
</ins><span class="cx">     return {'sent' =&gt; \@sent, 'excluded' =&gt; \@excluded};
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub sendMail {
</span><del>-    my ($user, $hlRef, $relRef, $valueRef, $dmhRef, $fdRef,
-        $diffRef, $newcomments, $anyprivate, $isnew,
-        $id, $watchingRef) = @_;
-
-    my %values = %$valueRef;
-    my @headerlist = @$hlRef;
-    my %mailhead = %$dmhRef;
-    my %fielddescription = %$fdRef;
-    my @diffparts = @$diffRef;    
</del><ins>+    my $params = shift;
</ins><span class="cx">     
</span><del>-    # Build difftext (the actions) by verifying the user should see them
-    my $difftext = &quot;&quot;;
-    my $diffheader = &quot;&quot;;
-    my $add_diff;
</del><ins>+    my $user   = $params-&gt;{to};
+    my $bug    = $params-&gt;{bug};
+    my @send_comments = @{ $params-&gt;{comments} };
+    my $date = $params-&gt;{date};
+    my $changer = $params-&gt;{changer};
+    my $watchingRef = $params-&gt;{watchers};
+    my @diffs = @{ $params-&gt;{diffs} };
+    my $relRef      = $params-&gt;{rels_which_want};
</ins><span class="cx"> 
</span><del>-    foreach my $diff (@diffparts) {
-        $add_diff = 0;
</del><ins>+    # Only display changes the user is allowed see.
+    my @display_diffs;
+
+    foreach my $diff (@diffs) {
+        my $add_diff = 0;
</ins><span class="cx">         
</span><del>-        if (exists($diff-&gt;{'fieldname'}) &amp;&amp; 
-            ($diff-&gt;{'fieldname'} eq 'estimated_time' ||
-             $diff-&gt;{'fieldname'} eq 'remaining_time' ||
-             $diff-&gt;{'fieldname'} eq 'work_time' ||
-             $diff-&gt;{'fieldname'} eq 'deadline')){
-            if ($user-&gt;groups-&gt;{Bugzilla-&gt;params-&gt;{&quot;timetrackinggroup&quot;}}) {
-                $add_diff = 1;
-            }
-        } elsif (($diff-&gt;{'isprivate'}) 
-                 &amp;&amp; Bugzilla-&gt;params-&gt;{'insidergroup'}
-                 &amp;&amp; !($user-&gt;groups-&gt;{Bugzilla-&gt;params-&gt;{'insidergroup'}})
-                ) {
-            $add_diff = 0;
-#if WEBKIT_CHANGES
-        # If the only thing we are modifying is the in-rietveld flag, don't
-        # include this diff.  If multiple flags are being modified,
-        # the diff text will have a comma seperating it.
-        # This will prevent mail from being sent.
-        } elsif ($diff-&gt;{'text'} =~ /in-rietveld/ &amp;&amp; !($diff-&gt;{'text'} =~ /,/)) {
-            $add_diff = 0;
-#endif // WEBKIT_CHANGES
-        } else {
</del><ins>+        if (grep { $_ eq $diff-&gt;{field_name} } TIMETRACKING_FIELDS) {
+            $add_diff = 1 if $user-&gt;is_timetracker;
+        }
+        elsif (!$diff-&gt;{isprivate} || $user-&gt;is_insider) {
</ins><span class="cx">             $add_diff = 1;
</span><span class="cx">         }
</span><ins>+        push(@display_diffs, $diff) if $add_diff;
+    }
</ins><span class="cx"> 
</span><del>-        if ($add_diff) {
-            if (exists($diff-&gt;{'header'}) &amp;&amp; 
-             ($diffheader ne $diff-&gt;{'header'})) {
-                $diffheader = $diff-&gt;{'header'};
-                $difftext .= $diffheader;
-            }
-            $difftext .= $diff-&gt;{'text'};
-        }
</del><ins>+    if (!$user-&gt;is_insider) {
+        @send_comments = grep { !$_-&gt;is_private } @send_comments;
</ins><span class="cx">     }
</span><del>- 
-    if ($difftext eq &quot;&quot; &amp;&amp; $newcomments eq &quot;&quot; &amp;&amp; !$isnew) {
</del><ins>+
+    if (!scalar(@display_diffs) &amp;&amp; !scalar(@send_comments)) {
</ins><span class="cx">       # Whoops, no differences!
</span><span class="cx">       return 0;
</span><span class="cx">     }
</span><del>-    
-    # If an attachment was created, then add an URL. (Note: the 'g'lobal
-    # replace should work with comments with multiple attachments.)
</del><span class="cx"> 
</span><del>-    if ( $newcomments =~ /Created an attachment \(/ ) {
-
-        my $showattachurlbase =
-            Bugzilla-&gt;params-&gt;{'urlbase'} . &quot;attachment.cgi?id=&quot;;
-
-        $newcomments =~ s/(Created an attachment \(id=([0-9]+)\))/$1\n --&gt; \(${showattachurlbase}$2&amp;action=review\)/g;
-    }
-
-    my $diffs = $difftext . &quot;\n\n&quot; . $newcomments;
-    if ($isnew) {
-        my $head = &quot;&quot;;
-        foreach my $f (@headerlist) {
-            next unless $mailhead{$f};
-            my $value = $values{$f};
-            # If there isn't anything to show, don't include this header.
-            next unless $value;
-            # Only send estimated_time if it is enabled and the user is in the group.
-            if (($f ne 'estimated_time' &amp;&amp; $f ne 'deadline')
-                || $user-&gt;groups-&gt;{Bugzilla-&gt;params-&gt;{'timetrackinggroup'}})
-            {
-                my $desc = $fielddescription{$f};
-                $head .= multiline_sprintf(FORMAT_DOUBLE, [&quot;$desc:&quot;, $value],
-                                           FORMAT_2_SIZE);
-            }
-        }
-        $diffs = $head . ($difftext ? &quot;\n\n&quot; : &quot;&quot;) . $diffs;
-    }
-
</del><span class="cx">     my (@reasons, @reasons_watch);
</span><span class="cx">     while (my ($relationship, $bits) = each %{$relRef}) {
</span><span class="cx">         push(@reasons, $relationship) if ($bits &amp; BIT_DIRECT);
</span><span class="cx">         push(@reasons_watch, $relationship) if ($bits &amp; BIT_WATCHING);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    my @headerrel   = map { REL_NAMES-&gt;{$_} } @reasons;
-    my @watchingrel = map { REL_NAMES-&gt;{$_} } @reasons_watch;
</del><ins>+    my %relationships = relationships();
+    my @headerrel   = map { $relationships{$_} } @reasons;
+    my @watchingrel = map { $relationships{$_} } @reasons_watch;
</ins><span class="cx">     push(@headerrel,   'None') unless @headerrel;
</span><span class="cx">     push(@watchingrel, 'None') unless @watchingrel;
</span><span class="cx">     push @watchingrel, map { user_id_to_login($_) } @$watchingRef;
</span><span class="cx"> 
</span><del>-    my $threadingmarker = build_thread_marker($id, $user-&gt;id, $isnew);
-
</del><span class="cx">     my $vars = {
</span><del>-        isnew =&gt; $isnew,
-        to =&gt; $user-&gt;email,
-        bugid =&gt; $id,
-        alias =&gt; Bugzilla-&gt;params-&gt;{'usebugaliases'} ? $values{'alias'} : &quot;&quot;,
-        classification =&gt; $values{'classification'},
-        product =&gt; $values{'product'},
-        comp =&gt; $values{'component'},
-        keywords =&gt; $values{'keywords'},
-        severity =&gt; $values{'bug_severity'},
-        status =&gt; $values{'bug_status'},
-        priority =&gt; $values{'priority'},
-        assignedto =&gt; $values{'assigned_to'},
-        assignedtoname =&gt; Bugzilla::User-&gt;new({name =&gt; $values{'assigned_to'}})-&gt;name,
-        targetmilestone =&gt; $values{'target_milestone'},
-        changedfields =&gt; $values{'changed_fields'},
-        summary =&gt; $values{'short_desc'},
</del><ins>+        date =&gt; $date,
+        to_user =&gt; $user,
+        bug =&gt; $bug,
</ins><span class="cx">         reasons =&gt; \@reasons,
</span><span class="cx">         reasons_watch =&gt; \@reasons_watch,
</span><span class="cx">         reasonsheader =&gt; join(&quot; &quot;, @headerrel),
</span><span class="cx">         reasonswatchheader =&gt; join(&quot; &quot;, @watchingrel),
</span><del>-        changer =&gt; $values{'changer'},
-        changername =&gt; $values{'changername'},
-        reporter =&gt; $values{'reporter'},
-        reportername =&gt; Bugzilla::User-&gt;new({name =&gt; $values{'reporter'}})-&gt;name,
-        diffs =&gt; $diffs,
-        threadingmarker =&gt; $threadingmarker
</del><ins>+        changer =&gt; $changer,
+        diffs =&gt; \@display_diffs,
+        changedfields =&gt; [uniq map { $_-&gt;{field_name} } @display_diffs],
+        new_comments =&gt; \@send_comments,
+        threadingmarker =&gt; build_thread_marker($bug-&gt;id, $user-&gt;id, !$bug-&gt;lastdiffed),
</ins><span class="cx">     };
</span><del>-
-    my $msg;
-    my $template = Bugzilla-&gt;template_inner($user-&gt;settings-&gt;{'lang'}-&gt;{'value'});
-    $template-&gt;process(&quot;email/newchangedmail.txt.tmpl&quot;, $vars, \$msg)
-      || ThrowTemplateError($template-&gt;error());
-    Bugzilla-&gt;template_inner(&quot;&quot;);
-
</del><ins>+    my $msg =  _generate_bugmail($user, $vars);
</ins><span class="cx">     MessageToMTA($msg);
</span><span class="cx"> 
</span><span class="cx">     return 1;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-# Get bug comments for the given period.
-sub get_comments_by_bug {
-    my ($id, $start, $end) = @_;
-    my $dbh = Bugzilla-&gt;dbh;
</del><ins>+sub _generate_bugmail {
+    my ($user, $vars) = @_;
+    my $template = Bugzilla-&gt;template_inner($user-&gt;setting('lang'));
+    my ($msg_text, $msg_html, $msg_header);
+  
+    $template-&gt;process(&quot;email/bugmail-header.txt.tmpl&quot;, $vars, \$msg_header)
+        || ThrowTemplateError($template-&gt;error());
+    $template-&gt;process(&quot;email/bugmail.txt.tmpl&quot;, $vars, \$msg_text)
+        || ThrowTemplateError($template-&gt;error());
</ins><span class="cx"> 
</span><del>-    my $result = &quot;&quot;;
-    my $count = 0;
-    my $anyprivate = 0;
</del><ins>+    my @parts = (
+        Email::MIME-&gt;create(
+            attributes =&gt; {
+                content_type =&gt; &quot;text/plain&quot;,
+            },
+            body =&gt; $msg_text,
+        )
+    );
+    if ($user-&gt;setting('email_format') eq 'html') {
+        $template-&gt;process(&quot;email/bugmail.html.tmpl&quot;, $vars, \$msg_html)
+            || ThrowTemplateError($template-&gt;error());
+        push @parts, Email::MIME-&gt;create(
+            attributes =&gt; {
+                content_type =&gt; &quot;text/html&quot;,         
+            },
+            body =&gt; $msg_html,
+        );
+    }
</ins><span class="cx"> 
</span><del>-    # $start will be undef for new bugs, and defined for pre-existing bugs.
-    if ($start) {
-        # If $start is not NULL, obtain the count-index
-        # of this comment for the leading &quot;Comment #xxx&quot; line.
-        $count = $dbh-&gt;selectrow_array('SELECT COUNT(*) FROM longdescs
-                                        WHERE bug_id = ? AND bug_when &lt;= ?',
-                                        undef, ($id, $start));
</del><ins>+    # TT trims the trailing newline, and threadingmarker may be ignored.
+    my $email = new Email::MIME(&quot;$msg_header\n&quot;);
+    if (scalar(@parts) == 1) {
+        $email-&gt;content_type_set($parts[0]-&gt;content_type);
+    } else {
+        $email-&gt;content_type_set('multipart/alternative');
</ins><span class="cx">     }
</span><ins>+    $email-&gt;parts_set(\@parts);
+    return $email;
+}
</ins><span class="cx"> 
</span><del>-    my $raw = 1; # Do not format comments which are not of type CMT_NORMAL.
-    my $comments = Bugzilla::Bug::GetComments($id, &quot;oldest_to_newest&quot;, $start, $end, $raw);
</del><ins>+sub _get_diffs {
+    my ($bug, $end, $user_cache) = @_;
+    my $dbh = Bugzilla-&gt;dbh;
</ins><span class="cx"> 
</span><del>-    if (Bugzilla-&gt;params-&gt;{'insidergroup'}) {
-        $anyprivate = 1 if scalar(grep {$_-&gt;{'isprivate'} &gt; 0} @$comments);
</del><ins>+    my @args = ($bug-&gt;id);
+    # If lastdiffed is NULL, then we don't limit the search on time.
+    my $when_restriction = '';
+    if ($bug-&gt;lastdiffed) {
+        $when_restriction = ' AND bug_when &gt; ? AND bug_when &lt;= ?';
+        push @args, ($bug-&gt;lastdiffed, $end);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    return ($comments, $anyprivate, $count);
</del><ins>+    my $diffs = $dbh-&gt;selectall_arrayref(
+           &quot;SELECT fielddefs.name AS field_name,
+                   bugs_activity.bug_when, bugs_activity.removed AS old,
+                   bugs_activity.added AS new, bugs_activity.attach_id,
+                   bugs_activity.comment_id, bugs_activity.who
+              FROM bugs_activity
+        INNER JOIN fielddefs
+                ON fielddefs.id = bugs_activity.fieldid
+             WHERE bugs_activity.bug_id = ?
+                   $when_restriction
+          ORDER BY bugs_activity.bug_when&quot;, {Slice=&gt;{}}, @args);
+
+    foreach my $diff (@$diffs) {
+        $user_cache-&gt;{$diff-&gt;{who}} ||= new Bugzilla::User($diff-&gt;{who}); 
+        $diff-&gt;{who} =  $user_cache-&gt;{$diff-&gt;{who}};
+        if ($diff-&gt;{attach_id}) {
+            $diff-&gt;{isprivate} = $dbh-&gt;selectrow_array(
+                'SELECT isprivate FROM attachments WHERE attach_id = ?',
+                undef, $diff-&gt;{attach_id});
+         }
+         if ($diff-&gt;{field_name} eq 'longdescs.isprivate') {
+             my $comment = Bugzilla::Comment-&gt;new($diff-&gt;{comment_id});
+             $diff-&gt;{num} = $comment-&gt;count;
+             $diff-&gt;{isprivate} = $diff-&gt;{new};
+         }
+    }
+
+    return @$diffs;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-# Prepare comments for the given language.
-sub prepare_comments {
-    my ($raw_comments, $count) = @_;
</del><ins>+sub _get_new_bugmail_fields {
+    my $bug = shift;
+    my @fields = @{ Bugzilla-&gt;fields({obsolete =&gt; 0, in_new_bugmail =&gt; 1}) };
+    my @diffs;
</ins><span class="cx"> 
</span><del>-    my $result = &quot;&quot;;
-    foreach my $comment (@$raw_comments) {
-        if ($count) {
-            $result .= &quot;\n\n--- Comment #$count from &quot; . $comment-&gt;{'author'}-&gt;identity .
-                       &quot;  &quot; . format_time($comment-&gt;{'time'}) . &quot; ---\n&quot;;
</del><ins>+    foreach my $field (@fields) {
+        my $name = $field-&gt;name;
+        my $value = $bug-&gt;$name;
+
+        if (ref $value eq 'ARRAY') {
+            $value = join(', ', @$value);
</ins><span class="cx">         }
</span><del>-        # Format language specific comments. We don't update $comment-&gt;{'body'}
-        # directly, otherwise it would grow everytime you call format_comment()
-        # with a different language as some text may be appended to the existing one.
-        my $body = Bugzilla::Bug::format_comment($comment);
-        $result .= ($comment-&gt;{'already_wrapped'} ? $body : wrap_comment($body));
-        $count++;
</del><ins>+        elsif (blessed($value) &amp;&amp; $value-&gt;isa('Bugzilla::User')) {
+            $value = $value-&gt;login;
+        }
+        elsif (blessed($value) &amp;&amp; $value-&gt;isa('Bugzilla::Object')) {
+            $value = $value-&gt;name;
+        }
+        elsif ($name eq 'estimated_time') {
+            # &quot;0.00&quot; (which is what we get from the DB) is true,
+            # so we explicitly do a numerical comparison with 0.
+            $value = 0 if $value == 0;
+        }
+        elsif ($name eq 'deadline') {
+            $value = time2str(&quot;%Y-%m-%d&quot;, str2time($value)) if $value;
+        }
+
+        # If there isn't anything to show, don't include this header.
+        next unless $value;
+
+        push(@diffs, {field_name =&gt; $name, new =&gt; $value});
</ins><span class="cx">     }
</span><del>-    return $result;
</del><ins>+
+    return @diffs;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> 1;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaBugUrlBugzillaLocalpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/Bugzilla/Local.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/Bugzilla/Local.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/Bugzilla/Local.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,111 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Tiago Mello.
+# Portions created by Tiago Mello are Copyright (C) 2010
+# Tiago Mello. All Rights Reserved.
+#
+# Contributor(s): Tiago Mello &lt;timello@linux.vnet.ibm.com&gt;
+
+package Bugzilla::BugUrl::Bugzilla::Local;
+use strict;
+use base qw(Bugzilla::BugUrl::Bugzilla);
+
+use Bugzilla::Error;
+use Bugzilla::Util;
+
+###############################
+####    Initialization     ####
+###############################
+
+use constant VALIDATOR_DEPENDENCIES =&gt; {
+    value =&gt; ['bug_id'],
+};
+
+###############################
+####        Methods        ####
+###############################
+
+sub ref_bug_url {
+    my $self = shift;
+
+    if (!exists $self-&gt;{ref_bug_url}) {
+        my $ref_bug_id = new URI($self-&gt;name)-&gt;query_param('id');
+        my $ref_bug = Bugzilla::Bug-&gt;check($ref_bug_id);
+        my $ref_value = $self-&gt;local_uri($self-&gt;bug_id);
+        $self-&gt;{ref_bug_url} =
+            new Bugzilla::BugUrl::Bugzilla::Local({ bug_id =&gt; $ref_bug-&gt;id,
+                                                    value =&gt; $ref_value });
+    }
+    return $self-&gt;{ref_bug_url};
+}
+
+sub should_handle {
+    my ($class, $uri) = @_;
+
+    # Check if it is either a bug id number or an alias.
+    return 1 if $uri-&gt;as_string =~ m/^\w+$/;
+
+    # Check if it is a local Bugzilla uri and call
+    # Bugzilla::BugUrl::Bugzilla to check if it's a valid Bugzilla
+    # see also url.
+    my $canonical_local = URI-&gt;new($class-&gt;local_uri)-&gt;canonical;
+    if ($canonical_local-&gt;authority eq $uri-&gt;canonical-&gt;authority
+        and $canonical_local-&gt;path eq $uri-&gt;canonical-&gt;path)
+    {
+        return $class-&gt;SUPER::should_handle($uri);
+    }
+
+    return 0;
+}
+
+sub _check_value {
+    my ($class, $uri, undef, $params) = @_;
+
+    # At this point we are going to treat any word as a
+    # bug id/alias to the local Bugzilla.
+    my $value = $uri-&gt;as_string;
+    if ($value =~ m/^\w+$/) {
+        $uri = new URI($class-&gt;local_uri($value));
+    } else {
+        # It's not a word, then we have to check
+        # if it's a valid Bugzilla url.
+        $uri = $class-&gt;SUPER::_check_value($uri);
+    }
+
+    my $ref_bug_id  = $uri-&gt;query_param('id');
+    my $ref_bug     = Bugzilla::Bug-&gt;check($ref_bug_id);
+    my $self_bug_id = $params-&gt;{bug_id};
+    $params-&gt;{ref_bug} = $ref_bug;
+
+    if ($ref_bug-&gt;id == $self_bug_id) {
+        ThrowUserError('see_also_self_reference');
+    }

+    my $product = $ref_bug-&gt;product_obj;
+    if (!Bugzilla-&gt;user-&gt;can_edit_product($product-&gt;id)) {
+        ThrowUserError(&quot;product_edit_denied&quot;,
+                       { product =&gt; $product-&gt;name });
+    }
+
+    return $uri;
+}
+
+sub local_uri {
+    my ($self, $bug_id) = @_;
+    $bug_id ||= '';
+    return correct_urlbase() . &quot;show_bug.cgi?id=$bug_id&quot;;
+}
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaBugUrlBugzillapm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/Bugzilla.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/Bugzilla.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/Bugzilla.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,67 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Tiago Mello.
+# Portions created by Tiago Mello are Copyright (C) 2010
+# Tiago Mello. All Rights Reserved.
+#
+# Contributor(s): Tiago Mello &lt;timello@linux.vnet.ibm.com&gt;
+#                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+package Bugzilla::BugUrl::Bugzilla;
+use strict;
+use base qw(Bugzilla::BugUrl);
+
+use Bugzilla::Error;
+use Bugzilla::Util;
+
+###############################
+####        Methods        ####
+###############################
+
+sub should_handle {
+    my ($class, $uri) = @_;
+    return ($uri-&gt;path =~ /show_bug\.cgi$/) ? 1 : 0;
+}
+
+sub _check_value {
+    my ($class, $uri) = @_;
+
+    $uri = $class-&gt;SUPER::_check_value($uri);
+
+    my $bug_id = $uri-&gt;query_param('id');
+    # We don't currently allow aliases, because we can't check to see
+    # if somebody's putting both an alias link and a numeric ID link.
+    # When we start validating the URL by accessing the other Bugzilla,
+    # we can allow aliases.
+    detaint_natural($bug_id);
+    if (!$bug_id) {
+        my $value = $uri-&gt;as_string;
+        ThrowUserError('bug_url_invalid', { url =&gt; $value, reason =&gt; 'id' });
+    }
+
+    # Make sure that &quot;id&quot; is the only query parameter.
+    $uri-&gt;query(&quot;id=$bug_id&quot;);
+    # And remove any # part if there is one.
+    $uri-&gt;fragment(undef);
+
+    return $uri;
+}
+
+sub target_bug_id {
+    my ($self) = @_;
+    return new URI($self-&gt;name)-&gt;query_param('id');
+}
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaBugUrlDebianpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/Debian.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/Debian.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/Debian.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,63 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Tiago Mello.
+# Portions created by Tiago Mello are Copyright (C) 2010
+# Tiago Mello. All Rights Reserved.
+#
+# Contributor(s): Tiago Mello &lt;timello@linux.vnet.ibm.com&gt;
+#                 Reed Loden &lt;reed@reedloden.com&gt;
+
+package Bugzilla::BugUrl::Debian;
+use strict;
+use base qw(Bugzilla::BugUrl);
+
+use Bugzilla::Error;
+use Bugzilla::Util;
+
+###############################
+####        Methods        ####
+###############################
+
+sub should_handle {
+    my ($class, $uri) = @_;
+    return ($uri-&gt;authority =~ /^bugs.debian.org$/i) ? 1 : 0;
+}
+
+sub _check_value {
+    my $class = shift;
+
+    my $uri = $class-&gt;SUPER::_check_value(@_);
+
+    # Debian BTS URLs can look like various things:
+    #   http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1234
+    #   http://bugs.debian.org/1234
+    my $bug_id;
+    if ($uri-&gt;path =~ m|^/(\d+)$|) {
+        $bug_id = $1;
+    }
+    elsif ($uri-&gt;path =~ /bugreport\.cgi$/) {
+        $bug_id = $uri-&gt;query_param('bug');
+        detaint_natural($bug_id);
+    }
+    if (!$bug_id) {
+        ThrowUserError('bug_url_invalid',
+                       { url =&gt; $uri-&gt;path, reason =&gt; 'id' });
+    }
+    # This is the shortest standard URL form for Debian BTS URLs,
+    # and so we reduce all URLs to this.
+    return new URI(&quot;http://bugs.debian.org/&quot; . $bug_id);
+}
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaBugUrlGooglepm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/Google.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/Google.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/Google.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,65 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Tiago Mello.
+# Portions created by Tiago Mello are Copyright (C) 2010
+# Tiago Mello. All Rights Reserved.
+#
+# Contributor(s): Tiago Mello &lt;timello@linux.vnet.ibm.com&gt;
+#                 Reed Loden &lt;reed@reedloden.com&gt;
+
+package Bugzilla::BugUrl::Google;
+use strict;
+use base qw(Bugzilla::BugUrl);
+
+use Bugzilla::Error;
+use Bugzilla::Util;
+
+###############################
+####        Methods        ####
+###############################
+
+sub should_handle {
+    my ($class, $uri) = @_;
+    return ($uri-&gt;authority =~ /^code.google.com$/i) ? 1 : 0;
+}
+
+sub _check_value {
+    my ($class, $uri) = @_;
+    
+    $uri = $class-&gt;SUPER::_check_value($uri);
+
+    my $value = $uri-&gt;as_string;
+    # Google Code URLs only have one form:
+    #   http(s)://code.google.com/p/PROJECT_NAME/issues/detail?id=1234
+    my $project_name;
+    if ($uri-&gt;path =~ m|^/p/([^/]+)/issues/detail$|) {
+        $project_name = $1;
+    } else {
+        ThrowUserError('bug_url_invalid', { url =&gt; $value });
+    }
+    my $bug_id = $uri-&gt;query_param('id');
+    detaint_natural($bug_id);
+    if (!$bug_id) {
+        ThrowUserError('bug_url_invalid', { url =&gt; $value, reason =&gt; 'id' });
+    }
+    # While Google Code URLs can be either HTTP or HTTPS,
+    # always go with the HTTP scheme, as that's the default.
+    $value = &quot;http://code.google.com/p/&quot; . $project_name .
+             &quot;/issues/detail?id=&quot; . $bug_id;
+
+    return new URI($value);
+}
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaBugUrlJIRApm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/JIRA.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/JIRA.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/JIRA.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,54 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Matt Selsky
+# Portions created by Matt Selsky are Copyright (C) 2010
+# Matt Selsky. All Rights Reserved.
+#
+# Contributor(s): Matt Selsky &lt;selsky@columbia.edu&gt;
+
+package Bugzilla::BugUrl::JIRA;
+use strict;
+use base qw(Bugzilla::BugUrl);
+
+use Bugzilla::Error;
+use Bugzilla::Util;
+
+###############################
+####        Methods        ####
+###############################
+
+sub should_handle {
+    my ($class, $uri) = @_;
+    return ($uri-&gt;path =~ m|/browse/[A-Z][A-Z]+-\d+$|) ? 1 : 0;
+}
+
+sub _check_value {
+    my $class = shift;
+
+    my $uri = $class-&gt;SUPER::_check_value(@_);
+
+    # JIRA URLs have only one basic form (but the jira is optional):
+    #   https://issues.apache.org/jira/browse/KEY-1234
+    #   http://issues.example.com/browse/KEY-1234
+
+    # Make sure there are no query parameters.
+    $uri-&gt;query(undef);
+    # And remove any # part if there is one.
+    $uri-&gt;fragment(undef);
+
+    return $uri;
+}
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaBugUrlLaunchpadpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/Launchpad.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/Launchpad.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/Launchpad.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,59 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Tiago Mello.
+# Portions created by Tiago Mello are Copyright (C) 2010
+# Tiago Mello. All Rights Reserved.
+#
+# Contributor(s): Tiago Mello &lt;timello@linux.vnet.ibm.com&gt;
+#                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+package Bugzilla::BugUrl::Launchpad;
+use strict;
+use base qw(Bugzilla::BugUrl);
+
+use Bugzilla::Error;
+
+###############################
+####        Methods        ####
+###############################
+
+sub should_handle {
+    my ($class, $uri) = @_;
+    return ($uri-&gt;authority =~ /launchpad.net$/) ? 1 : 0;
+}
+
+sub _check_value {
+    my ($class, $uri) = @_;
+
+    $uri = $class-&gt;SUPER::_check_value($uri);
+
+    my $value = $uri-&gt;as_string;
+    # Launchpad bug URLs can look like various things:
+    #   https://bugs.launchpad.net/ubuntu/+bug/1234
+    #   https://launchpad.net/bugs/1234
+    # All variations end with either &quot;/bugs/1234&quot; or &quot;/+bug/1234&quot;
+    if ($uri-&gt;path =~ m|bugs?/(\d+)$|) {
+        # This is the shortest standard URL form for Launchpad bugs,
+        # and so we reduce all URLs to this.
+        $value = &quot;https://launchpad.net/bugs/$1&quot;;
+    }
+    else {
+        ThrowUserError('bug_url_invalid', { url =&gt; $value, reason =&gt; 'id' });
+    }
+
+    return new URI($value);
+}
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaBugUrlMantisBTpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/MantisBT.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/MantisBT.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/MantisBT.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,51 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Reed Loden.
+# Portions created by Reed Loden are Copyright (C) 2010
+# Reed Loden. All Rights Reserved.
+#
+# Contributor(s): Reed Loden &lt;reed@reedloden.com&gt;
+
+package Bugzilla::BugUrl::MantisBT;
+use strict;
+use base qw(Bugzilla::BugUrl);
+
+use Bugzilla::Error;
+use Bugzilla::Util;
+
+###############################
+####        Methods        ####
+###############################
+
+sub should_handle {
+    my ($class, $uri) = @_;
+    return ($uri-&gt;path_query =~ m|view\.php\?id=\d+$|) ? 1 : 0;
+}
+
+sub _check_value {
+    my $class = shift;
+
+    my $uri = $class-&gt;SUPER::_check_value(@_);
+
+    # MantisBT URLs look like the following ('bugs' directory is optional):
+    #   http://www.mantisbt.org/bugs/view.php?id=1234
+
+    # Remove any # part if there is one.
+    $uri-&gt;fragment(undef);
+
+    return $uri;
+}
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaBugUrlSourceForgepm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/SourceForge.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/SourceForge.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/SourceForge.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,58 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Tiago Mello
+# Portions created by Tiago Mello are Copyright (C) 2011
+# Tiago Mello. All Rights Reserved.
+#
+# Contributor(s): Tiago Mello &lt;timello@linux.vnet.ibm.com&gt;
+
+package Bugzilla::BugUrl::SourceForge;
+use strict;
+use base qw(Bugzilla::BugUrl);
+
+use Bugzilla::Error;
+use Bugzilla::Util;
+
+###############################
+####        Methods        ####
+###############################
+
+sub should_handle {
+    my ($class, $uri) = @_;
+    return ($uri-&gt;authority =~ /^sourceforge.net$/i
+            and $uri-&gt;path =~ m|/tracker/|) ? 1 : 0;
+}
+
+sub _check_value {
+    my $class = shift;
+
+    my $uri = $class-&gt;SUPER::_check_value(@_);
+
+    # SourceForge tracker URLs have only one form:
+    #  http://sourceforge.net/tracker/?func=detail&amp;aid=111&amp;group_id=111&amp;atid=111
+    if ($uri-&gt;query_param('func') eq 'detail' and $uri-&gt;query_param('aid')
+        and $uri-&gt;query_param('group_id') and $uri-&gt;query_param('atid'))
+    {
+        # Remove any # part if there is one.
+        $uri-&gt;fragment(undef);
+        return $uri;
+    }
+    else {
+        my $value = $uri-&gt;as_string;
+        ThrowUserError('bug_url_invalid', { url =&gt; $value });
+    }
+}
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaBugUrlTracpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/Trac.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/Trac.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl/Trac.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,54 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Matt Selsky
+# Portions created by Matt Selsky are Copyright (C) 2010
+# Matt Selsky. All Rights Reserved.
+#
+# Contributor(s): Matt Selsky &lt;selsky@columbia.edu&gt;
+
+package Bugzilla::BugUrl::Trac;
+use strict;
+use base qw(Bugzilla::BugUrl);
+
+use Bugzilla::Error;
+use Bugzilla::Util;
+
+###############################
+####        Methods        ####
+###############################
+
+sub should_handle {
+    my ($class, $uri) = @_;
+    return ($uri-&gt;path =~ m|/ticket/\d+$|) ? 1 : 0;
+}
+
+sub _check_value {
+    my $class = shift;
+
+    my $uri = $class-&gt;SUPER::_check_value(@_);
+
+    # Trac URLs can look like various things:
+    #   http://dev.mutt.org/trac/ticket/1234
+    #   http://trac.roundcube.net/ticket/1484130
+
+    # Make sure there are no query parameters.
+    $uri-&gt;query(undef);
+    # And remove any # part if there is one.
+    $uri-&gt;fragment(undef);
+
+    return $uri;
+}
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaBugUrlpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/BugUrl.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,208 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Tiago Mello
+# Portions created by Tiago Mello are Copyright (C) 2010
+# Tiago Mello. All Rights Reserved.
+#
+# Contributor(s): Tiago Mello &lt;timello@linux.vnet.ibm.com&gt;
+
+package Bugzilla::BugUrl;
+use strict;
+use base qw(Bugzilla::Object);
+
+use Bugzilla::Util;
+use Bugzilla::Error;
+use Bugzilla::Constants;
+
+use URI::QueryParam;
+
+###############################
+####    Initialization     ####
+###############################
+
+use constant DB_TABLE   =&gt; 'bug_see_also';
+use constant NAME_FIELD =&gt; 'value';
+use constant LIST_ORDER =&gt; 'id';
+# See Also is tracked in bugs_activity.
+use constant AUDIT_CREATES =&gt; 0;
+use constant AUDIT_UPDATES =&gt; 0;
+use constant AUDIT_REMOVES =&gt; 0;
+
+use constant DB_COLUMNS =&gt; qw(
+    id
+    bug_id
+    value
+    class
+);
+
+# This must be strings with the names of the validations,
+# instead of coderefs, because subclasses override these
+# validators with their own.
+use constant VALIDATORS =&gt; {
+    value  =&gt; '_check_value',
+    bug_id =&gt; '_check_bug_id',
+    class  =&gt; \&amp;_check_class,
+};
+
+# This is the order we go through all of subclasses and
+# pick the first one that should handle the url. New
+# subclasses should be added at the end of the list.
+use constant SUB_CLASSES =&gt; qw(
+    Bugzilla::BugUrl::Bugzilla::Local
+    Bugzilla::BugUrl::Bugzilla
+    Bugzilla::BugUrl::Launchpad
+    Bugzilla::BugUrl::Google
+    Bugzilla::BugUrl::Debian
+    Bugzilla::BugUrl::JIRA
+    Bugzilla::BugUrl::Trac
+    Bugzilla::BugUrl::MantisBT
+    Bugzilla::BugUrl::SourceForge
+);
+
+###############################
+####      Accessors      ######
+###############################
+
+sub class  { return $_[0]-&gt;{class}  }
+sub bug_id { return $_[0]-&gt;{bug_id} }
+
+###############################
+####        Methods        ####
+###############################
+
+sub new {
+    my $class = shift;
+    my $param = shift;
+
+    if (ref $param) {
+        my $bug_id = $param-&gt;{bug_id};
+        my $name   = $param-&gt;{name} || $param-&gt;{value};
+        if (!defined $bug_id) {
+            ThrowCodeError('bad_arg',
+                { argument =&gt; 'bug_id',
+                  function =&gt; &quot;${class}::new&quot; });
+        }
+        if (!defined $name) {
+            ThrowCodeError('bad_arg',
+                { argument =&gt; 'name',
+                  function =&gt; &quot;${class}::new&quot; });
+        }
+
+        my $condition = 'bug_id = ? AND value = ?';
+        my @values = ($bug_id, $name);
+        $param = { condition =&gt; $condition, values =&gt; \@values };
+    }
+
+    unshift @_, $param;
+    return $class-&gt;SUPER::new(@_);
+}
+
+sub _do_list_select {
+    my $class = shift;
+    my $objects = $class-&gt;SUPER::_do_list_select(@_);
+
+    foreach my $object (@$objects) {
+        eval &quot;use &quot; . $object-&gt;class; die $@ if $@;
+        bless $object, $object-&gt;class;
+    }
+
+    return $objects
+}
+
+# This is an abstract method. It must be overridden
+# in every subclass.
+sub should_handle {
+    my ($class, $input) = @_;
+    ThrowCodeError('unknown_method',
+        { method =&gt; &quot;${class}::should_handle&quot; });
+}
+
+sub class_for {
+    my ($class, $value) = @_;
+
+    my $uri = URI-&gt;new($value);
+    foreach my $subclass ($class-&gt;SUB_CLASSES) {
+        eval &quot;use $subclass&quot;;
+        die $@ if $@;
+        return wantarray ? ($subclass, $uri) : $subclass
+            if $subclass-&gt;should_handle($uri);
+    }
+
+    ThrowUserError('bug_url_invalid', { url    =&gt; $value,
+                                        reason =&gt; 'show_bug' });
+}
+
+sub _check_class {
+    my ($class, $subclass) = @_;
+    eval &quot;use $subclass&quot;; die $@ if $@;
+    return $subclass;
+}
+
+sub _check_bug_id {
+    my ($class, $bug_id) = @_;
+
+    my $bug;
+    if (blessed $bug_id) {
+        # We got a bug object passed in, use it
+        $bug = $bug_id;
+        $bug-&gt;check_is_visible;
+    }
+    else {
+        # We got a bug id passed in, check it and get the bug object
+        $bug = Bugzilla::Bug-&gt;check({ id =&gt; $bug_id });
+    }
+
+    return $bug-&gt;id;
+}
+
+sub _check_value {
+    my ($class, $uri) = @_;
+
+    my $value = $uri-&gt;as_string;
+
+    if (!$value) {
+        ThrowCodeError('param_required',
+                       { function =&gt; 'add_see_also', param =&gt; '$value' });
+    }
+
+    # We assume that the URL is an HTTP URL if there is no (something):// 
+    # in front.
+    if (!$uri-&gt;scheme) {
+        # This works better than setting $uri-&gt;scheme('http'), because
+        # that creates URLs like &quot;http:domain.com&quot; and doesn't properly
+        # differentiate the path from the domain.
+        $uri = new URI(&quot;http://$value&quot;);
+    }
+    elsif ($uri-&gt;scheme ne 'http' &amp;&amp; $uri-&gt;scheme ne 'https') {
+        ThrowUserError('bug_url_invalid', { url =&gt; $value, reason =&gt; 'http' });
+    }
+
+    # This stops the following edge cases from being accepted:
+    # * show_bug.cgi?id=1
+    # * /show_bug.cgi?id=1
+    # * http:///show_bug.cgi?id=1
+    if (!$uri-&gt;authority or $uri-&gt;path !~ m{/}) {
+        ThrowUserError('bug_url_invalid',
+                       { url =&gt; $value, reason =&gt; 'path_only' });
+    }
+
+    if (length($uri-&gt;path) &gt; MAX_BUG_URL_LENGTH) {
+        ThrowUserError('bug_url_too_long', { url =&gt; $uri-&gt;path });
+    }
+
+    return $uri;
+}
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaCGIpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/CGI.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/CGI.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/CGI.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -21,48 +21,53 @@
</span><span class="cx"> #                 Byron Jones &lt;bugzilla@glob.com.au&gt;
</span><span class="cx"> #                 Marc Schumann &lt;wurblzap@gmail.com&gt;
</span><span class="cx"> 
</span><ins>+package Bugzilla::CGI;
</ins><span class="cx"> use strict;
</span><ins>+use base qw(CGI);
</ins><span class="cx"> 
</span><del>-package Bugzilla::CGI;
</del><ins>+use Bugzilla::Constants;
+use Bugzilla::Error;
+use Bugzilla::Util;
+use Bugzilla::Search::Recent;
</ins><span class="cx"> 
</span><ins>+use File::Basename;
+
</ins><span class="cx"> BEGIN {
</span><del>-    if ($^O =~ /MSWin32/i) {
</del><ins>+    if (ON_WINDOWS) {
</ins><span class="cx">         # Help CGI find the correct temp directory as the default list
</span><span class="cx">         # isn't Windows friendly (Bug 248988)
</span><span class="cx">         $ENV{'TMPDIR'} = $ENV{'TEMP'} || $ENV{'TMP'} || &quot;$ENV{'WINDIR'}\\TEMP&quot;;
</span><span class="cx">     }
</span><ins>+    *AUTOLOAD = \&amp;CGI::AUTOLOAD;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-use CGI qw(-no_xhtml -oldstyle_urls :private_tempfiles :unique_headers SERVER_PUSH);
</del><ins>+sub _init_bz_cgi_globals {
+    my $invocant = shift;
+    # We need to disable output buffering - see bug 179174
+    $| = 1;
</ins><span class="cx"> 
</span><del>-use base qw(CGI);
</del><ins>+    # Ignore SIGTERM and SIGPIPE - this prevents DB corruption. If the user closes
+    # their browser window while a script is running, the web server sends these
+    # signals, and we don't want to die half way through a write.
+    $SIG{TERM} = 'IGNORE';
+    $SIG{PIPE} = 'IGNORE';
</ins><span class="cx"> 
</span><del>-use Bugzilla::Constants;
-use Bugzilla::Error;
-use Bugzilla::Util;
</del><ins>+    # We don't precompile any functions here, that's done specially in
+    # mod_perl code.
+    $invocant-&gt;_setup_symbols(qw(:no_xhtml :oldstyle_urls :private_tempfiles
+                                 :unique_headers));
+}
</ins><span class="cx"> 
</span><del>-# We need to disable output buffering - see bug 179174
-$| = 1;
</del><ins>+BEGIN { __PACKAGE__-&gt;_init_bz_cgi_globals() if i_am_cgi(); }
</ins><span class="cx"> 
</span><del>-# Ignore SIGTERM and SIGPIPE - this prevents DB corruption. If the user closes
-# their browser window while a script is running, the web server sends these
-# signals, and we don't want to die half way through a write.
-$::SIG{TERM} = 'IGNORE';
-$::SIG{PIPE} = 'IGNORE';
-
-# CGI.pm uses AUTOLOAD, but explicitly defines a DESTROY sub.
-# We need to do so, too, otherwise perl dies when the object is destroyed
-# and we don't have a DESTROY method (because CGI.pm's AUTOLOAD will |die|
-# on getting an unknown sub to try to call)
-sub DESTROY {
-    my $self = shift;
-    $self-&gt;SUPER::DESTROY(@_);
-};
-
</del><span class="cx"> sub new {
</span><span class="cx">     my ($invocant, @args) = @_;
</span><span class="cx">     my $class = ref($invocant) || $invocant;
</span><span class="cx"> 
</span><ins>+    # Under mod_perl, CGI's global variables get reset on each request,
+    # so we need to set them up again every time.
+    $class-&gt;_init_bz_cgi_globals() if $ENV{MOD_PERL};
+
</ins><span class="cx">     my $self = $class-&gt;SUPER::new(@args);
</span><span class="cx"> 
</span><span class="cx">     # Make sure our outgoing cookie list is empty on each invocation
</span><span class="lines">@@ -72,15 +77,9 @@
</span><span class="cx">     $self-&gt;charset(Bugzilla-&gt;params-&gt;{'utf8'} ? 'UTF-8' : '');
</span><span class="cx"> 
</span><span class="cx">     # Redirect to urlbase/sslbase if we are not viewing an attachment.
</span><del>-    if (use_attachbase() &amp;&amp; i_am_cgi()) {
-        my $cgi_file = $self-&gt;url('-path_info' =&gt; 0, '-query' =&gt; 0, '-relative' =&gt; 1);
-        $cgi_file =~ s/\?$//;
-        my $urlbase = Bugzilla-&gt;params-&gt;{'urlbase'};
-        my $sslbase = Bugzilla-&gt;params-&gt;{'sslbase'};
-        my $path_regexp = $sslbase ? qr/^(\Q$urlbase\E|\Q$sslbase\E)/ : qr/^\Q$urlbase\E/;
-        if ($cgi_file ne 'attachment.cgi' &amp;&amp; $self-&gt;self_url !~ /$path_regexp/) {
-            $self-&gt;redirect_to_urlbase;
-        }
</del><ins>+    my $script = basename($0);
+    if ($self-&gt;url_is_attachment_base and $script ne 'attachment.cgi') {
+        $self-&gt;redirect_to_urlbase();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # Check for errors
</span><span class="lines">@@ -119,8 +118,12 @@
</span><span class="cx">     my @parameters;
</span><span class="cx">     foreach my $key (sort($self-&gt;param())) {
</span><span class="cx">         # Leave this key out if it's in the exclude list
</span><del>-        next if lsearch(\@exclude, $key) != -1;
</del><ins>+        next if grep { $_ eq $key } @exclude;
</ins><span class="cx"> 
</span><ins>+        # Remove the Boolean Charts for standard query.cgi fields
+        # They are listed in the query URL already
+        next if $key =~ /^(field|type|value)(-\d+){3}$/;
+
</ins><span class="cx">         my $esc_key = url_quote($key);
</span><span class="cx"> 
</span><span class="cx">         foreach my $value ($self-&gt;param($key)) {
</span><span class="lines">@@ -137,7 +140,7 @@
</span><span class="cx"> 
</span><span class="cx"> sub clean_search_url {
</span><span class="cx">     my $self = shift;
</span><del>-    # Delete any empty URL parameter
</del><ins>+    # Delete any empty URL parameter.
</ins><span class="cx">     my @cgi_params = $self-&gt;param;
</span><span class="cx"> 
</span><span class="cx">     foreach my $param (@cgi_params) {
</span><span class="lines">@@ -146,18 +149,69 @@
</span><span class="cx">             $self-&gt;delete(&quot;${param}_type&quot;);
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        # Boolean Chart stuff is empty if it's &quot;noop&quot;
-        if ($param =~ /\d-\d-\d/ &amp;&amp; defined $self-&gt;param($param)
-            &amp;&amp; $self-&gt;param($param) eq 'noop')
</del><ins>+        # Custom Search stuff is empty if it's &quot;noop&quot;. We also keep around
+        # the old Boolean Chart syntax for backwards-compatibility.
+        if (($param =~ /\d-\d-\d/ || $param =~ /^[[:alpha:]]\d+$/)
+            &amp;&amp; defined $self-&gt;param($param) &amp;&amp; $self-&gt;param($param) eq 'noop')
</ins><span class="cx">         {
</span><span class="cx">             $self-&gt;delete($param);
</span><span class="cx">         }
</span><ins>+        
+        # Any &quot;join&quot; for custom search that's an AND can be removed, because
+        # that's the default.
+        if (($param =~ /^j\d+$/ || $param eq 'j_top')
+            &amp;&amp; $self-&gt;param($param) eq 'AND')
+        {
+            $self-&gt;delete($param);
+        }
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    # Delete certain parameters if the associated parameter is empty.
-    $self-&gt;delete('bugidtype')  if !$self-&gt;param('bug_id');
-    $self-&gt;delete('emailtype1') if !$self-&gt;param('email1');
-    $self-&gt;delete('emailtype2') if !$self-&gt;param('email2');
</del><ins>+    # Delete leftovers from the login form
+    $self-&gt;delete('Bugzilla_remember', 'GoAheadAndLogIn');
+
+    foreach my $num (1,2,3) {
+        # If there's no value in the email field, delete the related fields.
+        if (!$self-&gt;param(&quot;email$num&quot;)) {
+            foreach my $field (qw(type assigned_to reporter qa_contact cc longdesc)) {
+                $self-&gt;delete(&quot;email$field$num&quot;);
+            }
+        }
+    }
+
+    # chfieldto is set to &quot;Now&quot; by default in query.cgi. But if none
+    # of the other chfield parameters are set, it's meaningless.
+    if (!defined $self-&gt;param('chfieldfrom') &amp;&amp; !$self-&gt;param('chfield')
+        &amp;&amp; !defined $self-&gt;param('chfieldvalue') &amp;&amp; $self-&gt;param('chfieldto')
+        &amp;&amp; lc($self-&gt;param('chfieldto')) eq 'now')
+    {
+        $self-&gt;delete('chfieldto');
+    }
+
+    # cmdtype &quot;doit&quot; is the default from query.cgi, but it's only meaningful
+    # if there's a remtype parameter.
+    if (defined $self-&gt;param('cmdtype') &amp;&amp; $self-&gt;param('cmdtype') eq 'doit'
+        &amp;&amp; !defined $self-&gt;param('remtype'))
+    {
+        $self-&gt;delete('cmdtype');
+    }
+
+    # &quot;Reuse same sort as last time&quot; is actually the default, so we don't
+    # need it in the URL.
+    if ($self-&gt;param('order') 
+        &amp;&amp; $self-&gt;param('order') eq 'Reuse same sort as last time')
+    {
+        $self-&gt;delete('order');
+    }
+
+    # list_id is added in buglist.cgi after calling clean_search_url,
+    # and doesn't need to be saved in saved searches.
+    $self-&gt;delete('list_id'); 
+
+    # And now finally, if query_format is our only parameter, that
+    # really means we have no parameters, so we should delete query_format.
+    if ($self-&gt;param('query_format') &amp;&amp; scalar($self-&gt;param()) == 1) {
+        $self-&gt;delete('query_format');
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> # Overwrite to ensure nph doesn't get set, and unset HEADERS_ONCE
</span><span class="lines">@@ -172,7 +226,8 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # Set the MIME boundary and content-type
</span><del>-    my $boundary = $param{'-boundary'} || '------- =_aaaaaaaaaa0';
</del><ins>+    my $boundary = $param{'-boundary'}
+        || '------- =_' . generate_random_password(16);
</ins><span class="cx">     delete $param{'-boundary'};
</span><span class="cx">     $self-&gt;{'separator'} = &quot;\r\n--$boundary\r\n&quot;;
</span><span class="cx">     $self-&gt;{'final_separator'} = &quot;\r\n--$boundary--\r\n&quot;;
</span><span class="lines">@@ -220,30 +275,78 @@
</span><span class="cx"> sub header {
</span><span class="cx">     my $self = shift;
</span><span class="cx"> 
</span><ins>+    # If there's only one parameter, then it's a Content-Type.
+    if (scalar(@_) == 1) {
+        # Since we're adding parameters below, we have to name it.
+        unshift(@_, '-type' =&gt; shift(@_));
+    }
+
</ins><span class="cx">     # Add the cookies in if we have any
</span><span class="cx">     if (scalar(@{$self-&gt;{Bugzilla_cookie_list}})) {
</span><del>-        if (scalar(@_) == 1) {
-            # if there's only one parameter, then it's a Content-Type.
-            # Since we're adding parameters we have to name it.
-            unshift(@_, '-type' =&gt; shift(@_));
-        }
</del><span class="cx">         unshift(@_, '-cookie' =&gt; $self-&gt;{Bugzilla_cookie_list});
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    # Add Strict-Transport-Security (STS) header if this response
+    # is over SSL and the strict_transport_security param is turned on.
+    if ($self-&gt;https &amp;&amp; !$self-&gt;url_is_attachment_base
+        &amp;&amp; Bugzilla-&gt;params-&gt;{'strict_transport_security'} ne 'off') 
+    {
+        my $sts_opts = 'max-age=' . MAX_STS_AGE;
+        if (Bugzilla-&gt;params-&gt;{'strict_transport_security'} 
+            eq 'include_subdomains')
+        {
+            $sts_opts .= '; includeSubDomains';
+        }
+        unshift(@_, '-strict_transport_security' =&gt; $sts_opts);
+    }
+
+    # Add X-Frame-Options header to prevent framing and subsequent
+    # possible clickjacking problems.
+    unless ($self-&gt;url_is_attachment_base) {
+        unshift(@_, '-x_frame_options' =&gt; 'SAMEORIGIN');
+    }
+
</ins><span class="cx">     return $self-&gt;SUPER::header(@_) || &quot;&quot;;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-# CGI.pm is not utf8-aware and passes data as bytes instead of UTF-8 strings.
</del><span class="cx"> sub param {
</span><span class="cx">     my $self = shift;
</span><del>-    if (Bugzilla-&gt;params-&gt;{'utf8'} &amp;&amp; scalar(@_) == 1) {
-        if (wantarray) {
-            return map { _fix_utf8($_) } $self-&gt;SUPER::param(@_);
</del><ins>+
+    # When we are just requesting the value of a parameter...
+    if (scalar(@_) == 1) {
+        my @result = $self-&gt;SUPER::param(@_); 
+
+        # Also look at the URL parameters, after we look at the POST 
+        # parameters. This is to allow things like login-form submissions
+        # with URL parameters in the form's &quot;target&quot; attribute.
+        if (!scalar(@result)
+            &amp;&amp; $self-&gt;request_method &amp;&amp; $self-&gt;request_method eq 'POST')
+        {
+            # Some servers fail to set the QUERY_STRING parameter, which
+            # causes undef issues
+            $ENV{'QUERY_STRING'} = '' unless exists $ENV{'QUERY_STRING'};
+            @result = $self-&gt;SUPER::url_param(@_);
</ins><span class="cx">         }
</span><del>-        else {
-            return _fix_utf8(scalar $self-&gt;SUPER::param(@_));
</del><ins>+
+        # Fix UTF-8-ness of input parameters.
+        if (Bugzilla-&gt;params-&gt;{'utf8'}) {
+            @result = map { _fix_utf8($_) } @result;
</ins><span class="cx">         }
</span><ins>+
+        return wantarray ? @result : $result[0];
</ins><span class="cx">     }
</span><ins>+    # And for various other functions in CGI.pm, we need to correctly
+    # return the URL parameters in addition to the POST parameters when
+    # asked for the list of parameters.
+    elsif (!scalar(@_) &amp;&amp; $self-&gt;request_method 
+           &amp;&amp; $self-&gt;request_method eq 'POST') 
+    {
+        my @post_params = $self-&gt;SUPER::param;
+        my @url_params  = $self-&gt;url_param;
+        my %params = map { $_ =&gt; 1 } (@post_params, @url_params);
+        return keys %params;
+    }
+
</ins><span class="cx">     return $self-&gt;SUPER::param(@_);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -254,6 +357,14 @@
</span><span class="cx">     return $input;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub should_set {
+    my ($self, $param) = @_;
+    my $set = (defined $self-&gt;param($param) 
+               or defined $self-&gt;param(&quot;defined_$param&quot;))
+              ? 1 : 0;
+    return $set;
+}
+
</ins><span class="cx"> # The various parts of Bugzilla which create cookies don't want to have to
</span><span class="cx"> # pass them around to all of the callers. Instead, store them locally here,
</span><span class="cx"> # and then output as required from |header|.
</span><span class="lines">@@ -299,27 +410,77 @@
</span><span class="cx">                        '-value'   =&gt; 'X');
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-# Redirect to https if required
-sub require_https {
-     my ($self, $url) = @_;
-     # Do not create query string if data submitted via XMLRPC
-     # since we want the data to be resubmitted over POST method.
-     my $query = Bugzilla-&gt;usage_mode == USAGE_MODE_WEBSERVICE ? 0 : 1;
-     # XMLRPC clients (SOAP::Lite at least) requires 301 to redirect properly
-     # and do not work with 302.
-     my $status = Bugzilla-&gt;usage_mode == USAGE_MODE_WEBSERVICE ? 301 : 302;
-     if (defined $url) {
-         $url .= $self-&gt;url('-path_info' =&gt; 1, '-query' =&gt; $query, '-relative' =&gt; 1);
-     } else {
-         $url = $self-&gt;self_url;
-         $url =~ s/^http:/https:/i;
-     }
-     print $self-&gt;redirect(-location =&gt; $url, -status =&gt; $status);
-     # When using XML-RPC with mod_perl, we need the headers sent immediately.
-     $self-&gt;r-&gt;rflush if $ENV{MOD_PERL};
-     exit;
</del><ins>+# This helps implement Bugzilla::Search::Recent, and also shortens search
+# URLs that get POSTed to buglist.cgi.
+sub redirect_search_url {
+    my $self = shift;
+    # If we're retreiving an old list, we never need to redirect or
+    # do anything related to Bugzilla::Search::Recent.
+    return if $self-&gt;param('regetlastlist');
+
+    my $user = Bugzilla-&gt;user;
+
+    if ($user-&gt;id) {
+        # There are two conditions that could happen here--we could get a URL
+        # with no list id, and we could get a URL with a list_id that isn't
+        # ours.
+        my $list_id = $self-&gt;param('list_id');
+        if ($list_id) {
+            # If we have a valid list_id, no need to redirect or clean.
+            return if Bugzilla::Search::Recent-&gt;check_quietly(
+                { id =&gt; $list_id });
+        }
+    }
+    elsif ($self-&gt;request_method ne 'POST') {
+        # Logged-out users who do a GET don't get a list_id, don't get
+        # their URLs cleaned, and don't get redirected.
+        return;
+    }
+
+    $self-&gt;clean_search_url();
+
+    # Make sure we still have params still after cleaning otherwise we 
+    # do not want to store a list_id for an empty search.
+    if ($user-&gt;id &amp;&amp; $self-&gt;param) {
+        # Insert a placeholder Bugzilla::Search::Recent, so that we know what
+        # the id of the resulting search will be. This is then pulled out
+        # of the Referer header when viewing show_bug.cgi to know what
+        # bug list we came from.
+        my $recent_search = Bugzilla::Search::Recent-&gt;create_placeholder;
+        $self-&gt;param('list_id', $recent_search-&gt;id);
+    }
+
+    # GET requests that lacked a list_id are always redirected. POST requests
+    # are only redirected if they're under the CGI_URI_LIMIT though.
+    my $uri_length = length($self-&gt;self_url());
+    if ($self-&gt;request_method() ne 'POST' or $uri_length &lt; CGI_URI_LIMIT) {
+        print $self-&gt;redirect(-url =&gt; $self-&gt;self_url());
+        exit;
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub redirect_to_https {
+    my $self = shift;
+    my $sslbase = Bugzilla-&gt;params-&gt;{'sslbase'};
+    # If this is a POST, we don't want ?POSTDATA in the query string.
+    # We expect the client to re-POST, which may be a violation of
+    # the HTTP spec, but the only time we're expecting it often is
+    # in the WebService, and WebService clients usually handle this
+    # correctly.
+    $self-&gt;delete('POSTDATA');
+    my $url = $sslbase . $self-&gt;url('-path_info' =&gt; 1, '-query' =&gt; 1, 
+                                    '-relative' =&gt; 1);
+
+    # XML-RPC clients (SOAP::Lite at least) require a 301 to redirect properly
+    # and do not work with 302. Our redirect really is permanent anyhow, so
+    # it doesn't hurt to make it a 301.
+    print $self-&gt;redirect(-location =&gt; $url, -status =&gt; 301);
+
+    # When using XML-RPC with mod_perl, we need the headers sent immediately.
+    $self-&gt;r-&gt;rflush if $ENV{MOD_PERL};
+    exit;
+}
+
</ins><span class="cx"> # Redirect to the urlbase version of the current URL.
</span><span class="cx"> sub redirect_to_urlbase {
</span><span class="cx">     my $self = shift;
</span><span class="lines">@@ -328,6 +489,61 @@
</span><span class="cx">     exit;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub url_is_attachment_base {
+    my ($self, $id) = @_;
+    return 0 if !use_attachbase() or !i_am_cgi();
+    my $attach_base = Bugzilla-&gt;params-&gt;{'attachment_base'};
+    # If we're passed an id, we only want one specific attachment base
+    # for a particular bug. If we're not passed an ID, we just want to
+    # know if our current URL matches the attachment_base *pattern*.
+    my $regex;
+    if ($id) {
+        $attach_base =~ s/\%bugid\%/$id/;
+        $regex = quotemeta($attach_base);
+    }
+    else {
+        # In this circumstance we run quotemeta first because we need to
+        # insert an active regex meta-character afterward.
+        $regex = quotemeta($attach_base);
+        $regex =~ s/\\\%bugid\\\%/\\d+/;
+    }
+    $regex = &quot;^$regex&quot;;
+    return ($self-&gt;self_url =~ $regex) ? 1 : 0;
+}
+
+##########################
+# Vars TIEHASH Interface #
+##########################
+
+# Fix the TIEHASH interface (scalar $cgi-&gt;Vars) to return and accept 
+# arrayrefs.
+sub STORE {
+    my $self = shift;
+    my ($param, $value) = @_;
+    if (defined $value and ref $value eq 'ARRAY') {
+        return $self-&gt;param(-name =&gt; $param, -value =&gt; $value);
+    }
+    return $self-&gt;SUPER::STORE(@_);
+}
+
+sub FETCH {
+    my ($self, $param) = @_;
+    return $self if $param eq 'CGI'; # CGI.pm did this, so we do too.
+    my @result = $self-&gt;param($param);
+    return undef if !scalar(@result);
+    return $result[0] if scalar(@result) == 1;
+    return \@result;
+}
+
+# For the Vars TIEHASH interface: the normal CGI.pm DELETE doesn't return 
+# the value deleted, but Perl's &quot;delete&quot; expects that value.
+sub DELETE {
+    my ($self, $param) = @_;
+    my $value = $self-&gt;FETCH($param);
+    $self-&gt;delete($param);
+    return $value;
+}
+
</ins><span class="cx"> 1;
</span><span class="cx"> 
</span><span class="cx"> __END__
</span><span class="lines">@@ -390,13 +606,13 @@
</span><span class="cx"> 
</span><span class="cx"> As its only argument, it takes the name of the cookie to expire.
</span><span class="cx"> 
</span><del>-=item C&lt;require_https($baseurl)&gt;
</del><ins>+=item C&lt;redirect_to_https&gt;
</ins><span class="cx"> 
</span><del>-This routine redirects the client to a different location using the https protocol. 
-If the client is using XMLRPC, it will not retain the QUERY_STRING since XMLRPC uses POST.
</del><ins>+This routine redirects the client to the https version of the page that
+they're looking at, using the C&lt;sslbase&gt; parameter for the redirection.
</ins><span class="cx"> 
</span><del>-It takes an optional argument which will be used as the base URL.  If $baseurl
-is not provided, the current URL is used.
</del><ins>+Generally you should use L&lt;Bugzilla::Util/do_ssl_redirect_if_required&gt;
+instead of calling this directly.
</ins><span class="cx"> 
</span><span class="cx"> =item C&lt;redirect_to_urlbase&gt;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaChartpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Chart.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Chart.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Chart.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -67,7 +67,7 @@
</span><span class="cx">     #
</span><span class="cx">     # The URL encoding is:
</span><span class="cx">     # line0=67&amp;line0=73&amp;line1=81&amp;line2=67...
</span><del>-    # &amp;label0=B+/+R+/+NEW&amp;label1=...
</del><ins>+    # &amp;label0=B+/+R+/+CONFIRMED&amp;label1=...
</ins><span class="cx">     # &amp;select0=1&amp;select3=1...    
</span><span class="cx">     # &amp;cumulate=1&amp;datefrom=2002-02-03&amp;dateto=2002-04-04&amp;ctype=html...
</span><span class="cx">     # &amp;gt=1&amp;labelgt=Grand+Total    
</span><span class="lines">@@ -382,8 +382,7 @@
</span><span class="cx"> sub getVisibleSeries {
</span><span class="cx">     my %cats;
</span><span class="cx"> 
</span><del>-    # List of groups the user is in; use -1 to make sure it's not empty.
-    my $grouplist = join(&quot;, &quot;, (-1, values(%{Bugzilla-&gt;user-&gt;groups})));
</del><ins>+    my $grouplist = Bugzilla-&gt;user-&gt;groups_as_string;
</ins><span class="cx">     
</span><span class="cx">     # Get all visible series
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="lines">@@ -397,10 +396,10 @@
</span><span class="cx">                         &quot;LEFT JOIN category_group_map AS cgm &quot; .
</span><span class="cx">                         &quot;    ON series.category = cgm.category_id &quot; .
</span><span class="cx">                         &quot;    AND cgm.group_id NOT IN($grouplist) &quot; .
</span><del>-                        &quot;WHERE creator = &quot; . Bugzilla-&gt;user-&gt;id . &quot; OR &quot; .
-                        &quot;      cgm.category_id IS NULL &quot; . 
</del><ins>+                        &quot;WHERE creator = ? OR (is_public = 1 AND cgm.category_id IS NULL) &quot; .
</ins><span class="cx">                    $dbh-&gt;sql_group_by('series.series_id', 'cc1.name, cc2.name, ' .
</span><del>-                                      'series.name'));
</del><ins>+                                      'series.name'),
+                        undef, Bugzilla-&gt;user-&gt;id);
</ins><span class="cx">     foreach my $series (@$serieses) {
</span><span class="cx">         my ($cat, $subcat, $name, $series_id) = @$series;
</span><span class="cx">         $cats{$cat}{$subcat}{$name} = $series_id;
</span><span class="lines">@@ -439,7 +438,7 @@
</span><span class="cx">     
</span><span class="cx">     require Data::Dumper;
</span><span class="cx">     print &quot;&lt;pre&gt;Bugzilla::Chart object:\n&quot;;
</span><del>-    print Data::Dumper::Dumper($self);
</del><ins>+    print html_quote(Data::Dumper::Dumper($self));
</ins><span class="cx">     print &quot;&lt;/pre&gt;&quot;;
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaClassificationpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Classification.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Classification.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Classification.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -13,78 +13,121 @@
</span><span class="cx"> # The Original Code is the Bugzilla Bug Tracking System.
</span><span class="cx"> #
</span><span class="cx"> # Contributor(s): Tiago R. Mello &lt;timello@async.com.br&gt;
</span><del>-#
</del><ins>+#                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
</ins><span class="cx"> 
</span><span class="cx"> use strict;
</span><span class="cx"> 
</span><span class="cx"> package Bugzilla::Classification;
</span><span class="cx"> 
</span><ins>+use Bugzilla::Constants;
+use Bugzilla::Field;
</ins><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> use Bugzilla::Error;
</span><span class="cx"> use Bugzilla::Product;
</span><span class="cx"> 
</span><ins>+use base qw(Bugzilla::Field::ChoiceInterface Bugzilla::Object);
+
</ins><span class="cx"> ###############################
</span><span class="cx"> ####    Initialization     ####
</span><span class="cx"> ###############################
</span><span class="cx"> 
</span><ins>+use constant DB_TABLE =&gt; 'classifications';
+use constant LIST_ORDER =&gt; 'sortkey, name';
+
</ins><span class="cx"> use constant DB_COLUMNS =&gt; qw(
</span><del>-    classifications.id
-    classifications.name
-    classifications.description
-    classifications.sortkey
</del><ins>+    id
+    name
+    description
+    sortkey
</ins><span class="cx"> );
</span><span class="cx"> 
</span><del>-our $columns = join(&quot;, &quot;, DB_COLUMNS);
</del><ins>+use constant UPDATE_COLUMNS =&gt; qw(
+    name
+    description
+    sortkey
+);
</ins><span class="cx"> 
</span><ins>+use constant VALIDATORS =&gt; {
+    name        =&gt; \&amp;_check_name,
+    description =&gt; \&amp;_check_description,
+    sortkey     =&gt; \&amp;_check_sortkey,
+};
+
</ins><span class="cx"> ###############################
</span><del>-####       Methods         ####
</del><ins>+####     Constructors     #####
</ins><span class="cx"> ###############################
</span><del>-
-sub new {
-    my $invocant = shift;
-    my $class = ref($invocant) || $invocant;
-    my $self = {};
-    bless($self, $class);
-    return $self-&gt;_init(@_);
-}
-
-sub _init {
</del><ins>+sub remove_from_db {
</ins><span class="cx">     my $self = shift;
</span><del>-    my ($param) = @_;
</del><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx"> 
</span><del>-    my $id = $param unless (ref $param eq 'HASH');
-    my $classification;
</del><ins>+    ThrowUserError(&quot;classification_not_deletable&quot;) if ($self-&gt;id == 1);
</ins><span class="cx"> 
</span><del>-    if (defined $id) {
-        detaint_natural($id)
-          || ThrowCodeError('param_must_be_numeric',
-                            {function =&gt; 'Bugzilla::Classification::_init'});
</del><ins>+    $dbh-&gt;bz_start_transaction();
+    # Reclassify products to the default classification, if needed.
+    $dbh-&gt;do(&quot;UPDATE products SET classification_id = 1
+              WHERE classification_id = ?&quot;, undef, $self-&gt;id);
</ins><span class="cx"> 
</span><del>-        $classification = $dbh-&gt;selectrow_hashref(qq{
-            SELECT $columns FROM classifications
-            WHERE id = ?}, undef, $id);
</del><ins>+    $self-&gt;SUPER::remove_from_db();
</ins><span class="cx"> 
</span><del>-    } elsif (defined $param-&gt;{'name'}) {
</del><ins>+    $dbh-&gt;bz_commit_transaction();
</ins><span class="cx"> 
</span><del>-        trick_taint($param-&gt;{'name'});
-        $classification = $dbh-&gt;selectrow_hashref(qq{
-            SELECT $columns FROM classifications
-            WHERE name = ?}, undef, $param-&gt;{'name'});
-    } else {
-        ThrowCodeError('bad_arg',
-            {argument =&gt; 'param',
-             function =&gt; 'Bugzilla::Classification::_init'});
</del><ins>+}
+
+###############################
+####      Validators       ####
+###############################
+
+sub _check_name {
+    my ($invocant, $name) = @_;
+
+    $name = trim($name);
+    $name || ThrowUserError('classification_not_specified');
+
+    if (length($name) &gt; MAX_CLASSIFICATION_SIZE) {
+        ThrowUserError('classification_name_too_long', {'name' =&gt; $name});
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    return undef unless (defined $classification);
</del><ins>+    my $classification = new Bugzilla::Classification({name =&gt; $name});
+    if ($classification &amp;&amp; (!ref $invocant || $classification-&gt;id != $invocant-&gt;id)) {
+        ThrowUserError(&quot;classification_already_exists&quot;, { name =&gt; $classification-&gt;name });
+    }
+    return $name;
+}
</ins><span class="cx"> 
</span><del>-    foreach my $field (keys %$classification) {
-        $self-&gt;{$field} = $classification-&gt;{$field};
</del><ins>+sub _check_description {
+    my ($invocant, $description) = @_;
+
+    $description  = trim($description || '');
+    return $description;
+}
+
+sub _check_sortkey {
+    my ($invocant, $sortkey) = @_;
+
+    $sortkey ||= 0;
+    my $stored_sortkey = $sortkey;
+    if (!detaint_natural($sortkey) || $sortkey &gt; MAX_SMALLINT) {
+        ThrowUserError('classification_invalid_sortkey', { 'sortkey' =&gt; $stored_sortkey });
</ins><span class="cx">     }
</span><del>-    return $self;
</del><ins>+    return $sortkey;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#####################################
+# Implement Bugzilla::Field::Choice #
+#####################################
+
+use constant FIELD_NAME =&gt; 'classification';
+use constant is_default =&gt; 0;
+use constant is_active =&gt; 1;
+
+###############################
+####       Methods         ####
+###############################
+
+sub set_name        { $_[0]-&gt;set('name', $_[1]); }
+sub set_description { $_[0]-&gt;set('description', $_[1]); }
+sub set_sortkey     { $_[0]-&gt;set('sortkey', $_[1]); }
+
</ins><span class="cx"> sub product_count {
</span><span class="cx">     my $self = shift;
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="lines">@@ -116,46 +159,9 @@
</span><span class="cx"> ####      Accessors        ####
</span><span class="cx"> ###############################
</span><span class="cx"> 
</span><del>-sub id          { return $_[0]-&gt;{'id'};          }
-sub name        { return $_[0]-&gt;{'name'};        }
</del><span class="cx"> sub description { return $_[0]-&gt;{'description'}; }
</span><span class="cx"> sub sortkey     { return $_[0]-&gt;{'sortkey'};     }
</span><span class="cx"> 
</span><del>-###############################
-####      Subroutines      ####
-###############################
-
-sub get_all_classifications {
-    my $dbh = Bugzilla-&gt;dbh;
-
-    my $ids = $dbh-&gt;selectcol_arrayref(q{
-        SELECT id FROM classifications ORDER BY sortkey, name});
-
-    my @classifications;
-    foreach my $id (@$ids) {
-        push @classifications, new Bugzilla::Classification($id);
-    }
-    return @classifications;
-}
-
-sub check_classification {
-    my ($class_name) = @_;
-
-    unless ($class_name) {
-        ThrowUserError(&quot;classification_not_specified&quot;);
-    }
-
-    my $classification =
-        new Bugzilla::Classification({name =&gt; $class_name});
-
-    unless ($classification) {
-        ThrowUserError(&quot;classification_doesnt_exist&quot;,
-                       { name =&gt; $class_name });
-    }
-    
-    return $classification;
-}
-
</del><span class="cx"> 1;
</span><span class="cx"> 
</span><span class="cx"> __END__
</span><span class="lines">@@ -174,39 +180,25 @@
</span><span class="cx">     my $id = $classification-&gt;id;
</span><span class="cx">     my $name = $classification-&gt;name;
</span><span class="cx">     my $description = $classification-&gt;description;
</span><ins>+    my $sortkey = $classification-&gt;sortkey;
</ins><span class="cx">     my $product_count = $classification-&gt;product_count;
</span><span class="cx">     my $products = $classification-&gt;products;
</span><span class="cx"> 
</span><del>-    my $hash_ref = Bugzilla::Classification::get_all_classifications();
-    my $classification = $hash_ref-&gt;{1};
-
-    my $classification =
-        Bugzilla::Classification::check_classification('AcmeClass');
-
</del><span class="cx"> =head1 DESCRIPTION
</span><span class="cx"> 
</span><del>-Classification.pm represents a Classification object.
</del><ins>+Classification.pm represents a classification object. It is an
+implementation of L&lt;Bugzilla::Object&gt;, and thus provides all methods
+that L&lt;Bugzilla::Object&gt; provides.
</ins><span class="cx"> 
</span><ins>+The methods that are specific to C&lt;Bugzilla::Classification&gt; are listed
+below.
+
</ins><span class="cx"> A Classification is a higher-level grouping of Products.
</span><span class="cx"> 
</span><span class="cx"> =head1 METHODS
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><del>-=item C&lt;new($param)&gt;
-
- Description: The constructor is used to load an existing
-              classification by passing a classification
-              id or classification name using a hash.
-
- Params:      $param - If you pass an integer, the integer is the
-                      classification_id from the database that we
-                      want to read in. If you pass in a hash with
-                      'name' key, then the value of the name key
-                      is the name of a classification from the DB.
-
- Returns:     A Bugzilla::Classification object.
-
</del><span class="cx"> =item C&lt;product_count()&gt;
</span><span class="cx"> 
</span><span class="cx">  Description: Returns the total number of products that belong to
</span><span class="lines">@@ -226,27 +218,4 @@
</span><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><del>-=head1 SUBROUTINES
-
-=over
-
-=item C&lt;get_all_classifications()&gt;
-
- Description: Returns all classifications.
-
- Params:      none.
-
- Returns:     Bugzilla::Classification object list.
-
-=item C&lt;check_classification($classification_name)&gt;
-
- Description: Checks if the classification name passed in is a
-              valid classification.
-
- Params:      $classification_name - String with a classification name.
-
- Returns:     Bugzilla::Classification object.
-
-=back
-
</del><span class="cx"> =cut
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaCommentpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/Comment.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Comment.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Comment.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,433 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is James Robson.
+# Portions created by James Robson are Copyright (c) 2009 James Robson.
+# All rights reserved.
+#
+# Contributor(s): James Robson &lt;arbingersys@gmail.com&gt; 
+#                 Christian Legnitto &lt;clegnitto@mozilla.com&gt; 
+
+use strict;
+
+package Bugzilla::Comment;
+
+use base qw(Bugzilla::Object);
+
+use Bugzilla::Attachment;
+use Bugzilla::Constants;
+use Bugzilla::Error;
+use Bugzilla::User;
+use Bugzilla::Util;
+
+use Scalar::Util qw(blessed);
+
+###############################
+####    Initialization     ####
+###############################
+
+# Creation and updating of comments are audited in longdescs
+# and bugs_activity respectively instead of audit_log.
+use constant AUDIT_CREATES =&gt; 0;
+use constant AUDIT_UPDATES =&gt; 0;
+
+use constant DB_COLUMNS =&gt; qw(
+    comment_id
+    bug_id
+    who
+    bug_when
+    work_time
+    thetext
+    isprivate
+    already_wrapped
+    type
+    extra_data
+);
+
+use constant UPDATE_COLUMNS =&gt; qw(
+    isprivate
+    type
+    extra_data
+);
+
+use constant DB_TABLE =&gt; 'longdescs';
+use constant ID_FIELD =&gt; 'comment_id';
+# In some rare cases, two comments can have identical timestamps. If
+# this happens, we want to be sure that the comment added later shows up
+# later in the sequence.
+use constant LIST_ORDER =&gt; 'bug_when, comment_id';
+
+use constant VALIDATORS =&gt; {
+    bug_id      =&gt; \&amp;_check_bug_id,
+    who         =&gt; \&amp;_check_who,
+    bug_when    =&gt; \&amp;_check_bug_when,
+    work_time   =&gt; \&amp;_check_work_time,
+    thetext     =&gt; \&amp;_check_thetext,
+    isprivate   =&gt; \&amp;_check_isprivate,
+    extra_data  =&gt; \&amp;_check_extra_data,
+    type        =&gt; \&amp;_check_type,
+};
+
+use constant VALIDATOR_DEPENDENCIES =&gt; {
+    extra_data =&gt; ['type'],
+    bug_id     =&gt; ['who'],
+    work_time  =&gt; ['who', 'bug_id'],
+    isprivate  =&gt; ['who'],
+};
+
+#########################
+# Database Manipulation #
+#########################
+
+sub update {
+    my $self = shift;
+    my $changes = $self-&gt;SUPER::update(@_);
+    $self-&gt;bug-&gt;_sync_fulltext();
+    return $changes;
+}
+
+# Speeds up displays of comment lists by loading all -&gt;author objects
+# at once for a whole list.
+sub preload {
+    my ($class, $comments) = @_;
+    my %user_ids = map { $_-&gt;{who} =&gt; 1 } @$comments;
+    my $users = Bugzilla::User-&gt;new_from_list([keys %user_ids]);
+    my %user_map = map { $_-&gt;id =&gt; $_ } @$users;
+    foreach my $comment (@$comments) {
+        $comment-&gt;{author} = $user_map{$comment-&gt;{who}};
+    }
+}
+
+###############################
+####      Accessors      ######
+###############################
+
+sub already_wrapped { return $_[0]-&gt;{'already_wrapped'}; }
+sub body        { return $_[0]-&gt;{'thetext'};   }
+sub bug_id      { return $_[0]-&gt;{'bug_id'};    }
+sub creation_ts { return $_[0]-&gt;{'bug_when'};  }
+sub is_private  { return $_[0]-&gt;{'isprivate'}; }
+sub work_time   {
+    # Work time is returned as a string (see bug 607909)
+    return 0 if $_[0]-&gt;{'work_time'} + 0 == 0;
+    return $_[0]-&gt;{'work_time'};
+}
+sub type        { return $_[0]-&gt;{'type'};      }
+sub extra_data  { return $_[0]-&gt;{'extra_data'} }
+
+sub bug {
+    my $self = shift;
+    require Bugzilla::Bug;
+    $self-&gt;{bug} ||= new Bugzilla::Bug($self-&gt;bug_id);
+    return $self-&gt;{bug};
+}
+
+sub is_about_attachment {
+    my ($self) = @_;
+    return 1 if ($self-&gt;type == CMT_ATTACHMENT_CREATED
+                 or $self-&gt;type == CMT_ATTACHMENT_UPDATED);
+    return 0;
+}
+
+sub attachment {
+    my ($self) = @_;
+    return undef if not $self-&gt;is_about_attachment;
+    $self-&gt;{attachment} ||= new Bugzilla::Attachment($self-&gt;extra_data);
+    return $self-&gt;{attachment};
+}
+
+sub author { 
+    my $self = shift;
+    $self-&gt;{'author'} ||= new Bugzilla::User($self-&gt;{'who'});
+    return $self-&gt;{'author'};
+}
+
+sub body_full {
+    my ($self, $params) = @_;
+    $params ||= {};
+    my $template = Bugzilla-&gt;template_inner;
+    my $body;
+    if ($self-&gt;type) {
+        $template-&gt;process(&quot;bug/format_comment.txt.tmpl&quot;, 
+                           { comment =&gt; $self, %$params }, \$body)
+            || ThrowTemplateError($template-&gt;error());
+        $body =~ s/^X//;
+    }
+    else {
+        $body = $self-&gt;body;
+    }
+    if ($params-&gt;{wrap} and !$self-&gt;already_wrapped) {
+        $body = wrap_comment($body);
+    }
+    return $body;
+}
+
+############
+# Mutators #
+############
+
+sub set_is_private  { $_[0]-&gt;set('isprivate',  $_[1]); }
+sub set_type        { $_[0]-&gt;set('type',       $_[1]); }
+sub set_extra_data  { $_[0]-&gt;set('extra_data', $_[1]); }
+
+##############
+# Validators #
+##############
+
+sub run_create_validators {
+    my $self = shift;
+    my $params = $self-&gt;SUPER::run_create_validators(@_);
+    # Sometimes this run_create_validators is called with parameters that
+    # skip bug_id validation, so it might not exist in the resulting hash.
+    if (defined $params-&gt;{bug_id}) {
+        $params-&gt;{bug_id} = $params-&gt;{bug_id}-&gt;id;
+    }
+    return $params;
+}
+
+sub _check_extra_data {
+    my ($invocant, $extra_data, undef, $params) = @_;
+    my $type = blessed($invocant) ? $invocant-&gt;type : $params-&gt;{type};
+
+    if ($type == CMT_NORMAL) {
+        if (defined $extra_data) {
+            ThrowCodeError('comment_extra_data_not_allowed',
+                           { type =&gt; $type, extra_data =&gt; $extra_data });
+        }
+    }
+    else {
+        if (!defined $extra_data) {
+            ThrowCodeError('comment_extra_data_required', { type =&gt; $type });
+        }
+        elsif ($type == CMT_ATTACHMENT_CREATED 
+               or $type == CMT_ATTACHMENT_UPDATED) 
+        {
+             my $attachment = Bugzilla::Attachment-&gt;check({ 
+                 id =&gt; $extra_data });
+             $extra_data = $attachment-&gt;id;
+        }
+        else {
+            my $original = $extra_data;
+            detaint_natural($extra_data) 
+              or ThrowCodeError('comment_extra_data_not_numeric',
+                                { type =&gt; $type, extra_data =&gt; $original });
+        }
+    }
+
+    return $extra_data;
+}
+
+sub _check_type {
+    my ($invocant, $type) = @_;
+    $type ||= CMT_NORMAL;
+    my $original = $type;
+    detaint_natural($type)
+        or ThrowCodeError('comment_type_invalid', { type =&gt; $original });
+    return $type;
+}
+
+sub _check_bug_id {
+    my ($invocant, $bug_id) = @_;
+
+    ThrowCodeError('param_required', {function =&gt; 'Bugzilla::Comment-&gt;create',
+                                      param =&gt; 'bug_id'}) unless $bug_id;
+
+    my $bug;
+    if (blessed $bug_id) {
+        # We got a bug object passed in, use it
+        $bug = $bug_id;
+        $bug-&gt;check_is_visible;
+    }
+    else {
+        # We got a bug id passed in, check it and get the bug object
+        $bug = Bugzilla::Bug-&gt;check({ id =&gt; $bug_id });
+    }
+
+    # Make sure the user can edit the product
+    Bugzilla-&gt;user-&gt;can_edit_product($bug-&gt;{product_id});
+
+    # Make sure the user can comment
+    my $privs;
+    $bug-&gt;check_can_change_field('longdesc', 0, 1, \$privs)
+        || ThrowUserError('illegal_change', 
+                          { field =&gt; 'longdesc', privs =&gt; $privs });
+    return $bug;
+}
+
+sub _check_who {
+    my ($invocant, $who) = @_;
+    Bugzilla-&gt;login(LOGIN_REQUIRED);
+    return Bugzilla-&gt;user-&gt;id;
+}
+
+sub _check_bug_when {
+    my ($invocant, $when) = @_;
+
+    # Make sure the timestamp is defined, default to a timestamp from the db
+    if (!defined $when) {
+        $when = Bugzilla-&gt;dbh-&gt;selectrow_array('SELECT LOCALTIMESTAMP(0)');
+    }
+
+    # Make sure the timestamp parses
+    if (!datetime_from($when)) {
+        ThrowCodeError('invalid_timestamp', { timestamp =&gt; $when });
+    }
+
+    return $when;
+}
+
+sub _check_work_time {
+    my ($invocant, $value_in, $field, $params) = @_;
+
+    # Call down to Bugzilla::Object, letting it know negative
+    # values are ok
+    my $time = $invocant-&gt;check_time($value_in, $field, $params, 1);
+    my $privs;
+    $params-&gt;{bug_id}-&gt;check_can_change_field('work_time', 0, $time, \$privs)
+        || ThrowUserError('illegal_change',
+                          { field =&gt; 'work_time', privs =&gt; $privs });
+    return $time;
+}
+
+sub _check_thetext {
+    my ($invocant, $thetext) = @_;
+
+    ThrowCodeError('param_required',{function =&gt; 'Bugzilla::Comment-&gt;create',
+                                     param =&gt; 'thetext'}) unless defined $thetext;
+
+    # Remove any trailing whitespace. Leading whitespace could be
+    # a valid part of the comment.
+    $thetext =~ s/\s*$//s;
+    $thetext =~ s/\r\n?/\n/g; # Get rid of \r.
+
+    ThrowUserError('comment_too_long') if length($thetext) &gt; MAX_COMMENT_LENGTH;
+    return $thetext;
+}
+
+sub _check_isprivate {
+    my ($invocant, $isprivate) = @_;
+    if ($isprivate &amp;&amp; !Bugzilla-&gt;user-&gt;is_insider) {
+        ThrowUserError('user_not_insider');
+    }
+    return $isprivate ? 1 : 0;
+}
+
+sub count {
+    my ($self) = @_;
+
+    return $self-&gt;{'count'} if defined $self-&gt;{'count'};
+
+    my $dbh = Bugzilla-&gt;dbh;
+    ($self-&gt;{'count'}) = $dbh-&gt;selectrow_array(
+        &quot;SELECT COUNT(*)
+           FROM longdescs 
+          WHERE bug_id = ? 
+                AND bug_when &lt;= ?&quot;,
+        undef, $self-&gt;bug_id, $self-&gt;creation_ts);
+
+    return --$self-&gt;{'count'};
+}   
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::Comment - A Comment for a given bug 
+
+=head1 SYNOPSIS
+
+ use Bugzilla::Comment;
+
+ my $comment = Bugzilla::Comment-&gt;new($comment_id);
+ my $comments = Bugzilla::Comment-&gt;new_from_list($comment_ids);
+
+=head1 DESCRIPTION
+
+Bugzilla::Comment represents a comment attached to a bug.
+
+This implements all standard C&lt;Bugzilla::Object&gt; methods. See 
+L&lt;Bugzilla::Object&gt; for more details.
+
+=head2 Accessors
+
+=over
+
+=item C&lt;bug_id&gt;
+
+C&lt;int&gt; The ID of the bug to which the comment belongs.
+
+=item C&lt;creation_ts&gt;
+
+C&lt;string&gt; The comment creation timestamp.
+
+=item C&lt;body&gt;
+
+C&lt;string&gt; The body without any special additional text.
+
+=item C&lt;work_time&gt;
+
+C&lt;string&gt; Time spent as related to this comment.
+
+=item C&lt;is_private&gt;
+
+C&lt;boolean&gt; Comment is marked as private
+
+=item C&lt;already_wrapped&gt;
+
+If this comment is stored in the database word-wrapped, this will be C&lt;1&gt;.
+C&lt;0&gt; otherwise.
+
+=item C&lt;author&gt;
+
+L&lt;Bugzilla::User&gt; who created the comment.
+
+=item C&lt;count&gt;
+
+C&lt;int&gt; The position this comment is located in the full list of comments for a bug starting from 0.
+
+=item C&lt;body_full&gt;
+
+=over
+
+=item B&lt;Description&gt;
+
+C&lt;string&gt; Body of the comment, including any special text (such as
+&quot;this bug was marked as a duplicate of...&quot;).
+
+=item B&lt;Params&gt;
+
+=over
+
+=item C&lt;is_bugmail&gt;
+
+C&lt;boolean&gt;. C&lt;1&gt; if this comment should be formatted specifically for
+bugmail.
+
+=item C&lt;wrap&gt;
+
+C&lt;boolean&gt;. C&lt;1&gt; if the comment should be returned word-wrapped.
+
+=back
+
+=item B&lt;Returns&gt;
+
+A string, the full text of the comment as it would be displayed to an end-user.
+
+=back
+
+=back
+
+=cut
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaComponentpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Component.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Component.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Component.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -17,12 +17,10 @@
</span><span class="cx"> #                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
</span><span class="cx"> #                 Akamai Technologies &lt;bugzilla-dev@akamai.com&gt;
</span><span class="cx"> 
</span><ins>+package Bugzilla::Component;
</ins><span class="cx"> use strict;
</span><ins>+use base qw(Bugzilla::Field::ChoiceInterface Bugzilla::Object);
</ins><span class="cx"> 
</span><del>-package Bugzilla::Component;
-
-use base qw(Bugzilla::Object);
-
</del><span class="cx"> use Bugzilla::Constants;
</span><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> use Bugzilla::Error;
</span><span class="lines">@@ -30,11 +28,15 @@
</span><span class="cx"> use Bugzilla::FlagType;
</span><span class="cx"> use Bugzilla::Series;
</span><span class="cx"> 
</span><ins>+use Scalar::Util qw(blessed);
+
</ins><span class="cx"> ###############################
</span><span class="cx"> ####    Initialization     ####
</span><span class="cx"> ###############################
</span><span class="cx"> 
</span><span class="cx"> use constant DB_TABLE =&gt; 'components';
</span><ins>+# This is mostly for the editfields.cgi case where -&gt;get_all is called.
+use constant LIST_ORDER =&gt; 'product_id, name';
</ins><span class="cx"> 
</span><span class="cx"> use constant DB_COLUMNS =&gt; qw(
</span><span class="cx">     id
</span><span class="lines">@@ -43,32 +45,34 @@
</span><span class="cx">     initialowner
</span><span class="cx">     initialqacontact
</span><span class="cx">     description
</span><ins>+    isactive
</ins><span class="cx"> );
</span><span class="cx"> 
</span><del>-use constant REQUIRED_CREATE_FIELDS =&gt; qw(
-    name
-    product
-    initialowner
-    description
-);
-
</del><span class="cx"> use constant UPDATE_COLUMNS =&gt; qw(
</span><span class="cx">     name
</span><span class="cx">     initialowner
</span><span class="cx">     initialqacontact
</span><span class="cx">     description
</span><ins>+    isactive
</ins><span class="cx"> );
</span><span class="cx"> 
</span><ins>+use constant REQUIRED_FIELD_MAP =&gt; {
+    product_id =&gt; 'product',
+};
+
</ins><span class="cx"> use constant VALIDATORS =&gt; {
</span><ins>+    create_series    =&gt; \&amp;Bugzilla::Object::check_boolean,
</ins><span class="cx">     product          =&gt; \&amp;_check_product,
</span><span class="cx">     initialowner     =&gt; \&amp;_check_initialowner,
</span><span class="cx">     initialqacontact =&gt; \&amp;_check_initialqacontact,
</span><span class="cx">     description      =&gt; \&amp;_check_description,
</span><span class="cx">     initial_cc       =&gt; \&amp;_check_cc_list,
</span><ins>+    name             =&gt; \&amp;_check_name,
+    isactive         =&gt; \&amp;Bugzilla::Object::check_boolean,
</ins><span class="cx"> };
</span><span class="cx"> 
</span><del>-use constant UPDATE_VALIDATORS =&gt; {
-    name =&gt; \&amp;_check_name,
</del><ins>+use constant VALIDATOR_DEPENDENCIES =&gt; {
+    name =&gt; ['product'],
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> ###############################
</span><span class="lines">@@ -79,7 +83,7 @@
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx"> 
</span><span class="cx">     my $product;
</span><del>-    if (ref $param) {
</del><ins>+    if (ref $param and !defined $param-&gt;{id}) {
</ins><span class="cx">         $product = $param-&gt;{product};
</span><span class="cx">         my $name = $param-&gt;{name};
</span><span class="cx">         if (!defined $product) {
</span><span class="lines">@@ -114,30 +118,23 @@
</span><span class="cx">     $class-&gt;check_required_create_fields(@_);
</span><span class="cx">     my $params = $class-&gt;run_create_validators(@_);
</span><span class="cx">     my $cc_list = delete $params-&gt;{initial_cc};
</span><ins>+    my $create_series = delete $params-&gt;{create_series};
+    my $product = delete $params-&gt;{product};
+    $params-&gt;{product_id} = $product-&gt;id;
</ins><span class="cx"> 
</span><span class="cx">     my $component = $class-&gt;insert_create_data($params);
</span><ins>+    $component-&gt;{product} = $product;
</ins><span class="cx"> 
</span><span class="cx">     # We still have to fill the component_cc table.
</span><del>-    $component-&gt;_update_cc_list($cc_list);
</del><ins>+    $component-&gt;_update_cc_list($cc_list) if $cc_list;
</ins><span class="cx"> 
</span><span class="cx">     # Create series for the new component.
</span><del>-    $component-&gt;_create_series();
</del><ins>+    $component-&gt;_create_series() if $create_series;
</ins><span class="cx"> 
</span><span class="cx">     $dbh-&gt;bz_commit_transaction();
</span><span class="cx">     return $component;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub run_create_validators {
-    my $class  = shift;
-    my $params = $class-&gt;SUPER::run_create_validators(@_);
-
-    my $product = delete $params-&gt;{product};
-    $params-&gt;{product_id} = $product-&gt;id;
-    $params-&gt;{name} = $class-&gt;_check_name($params-&gt;{name}, $product);
-
-    return $params;
-}
-
</del><span class="cx"> sub update {
</span><span class="cx">     my $self = shift;
</span><span class="cx">     my $changes = $self-&gt;SUPER::update(@_);
</span><span class="lines">@@ -154,6 +151,8 @@
</span><span class="cx">     my $self = shift;
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx"> 
</span><ins>+    $self-&gt;_check_if_controller(); # From ChoiceInterface
+
</ins><span class="cx">     $dbh-&gt;bz_start_transaction();
</span><span class="cx"> 
</span><span class="cx">     if ($self-&gt;bug_count) {
</span><span class="lines">@@ -186,7 +185,8 @@
</span><span class="cx"> ################################
</span><span class="cx"> 
</span><span class="cx"> sub _check_name {
</span><del>-    my ($invocant, $name, $product) = @_;
</del><ins>+    my ($invocant, $name, undef, $params) = @_;
+    my $product = blessed($invocant) ? $invocant-&gt;product : $params-&gt;{product};
</ins><span class="cx"> 
</span><span class="cx">     $name = trim($name);
</span><span class="cx">     $name || ThrowUserError('component_blank_name');
</span><span class="lines">@@ -195,7 +195,6 @@
</span><span class="cx">         ThrowUserError('component_name_too_long', {'name' =&gt; $name});
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    $product = $invocant-&gt;product if (ref $invocant);
</del><span class="cx">     my $component = new Bugzilla::Component({product =&gt; $product, name =&gt; $name});
</span><span class="cx">     if ($component &amp;&amp; (!ref $invocant || $component-&gt;id != $invocant-&gt;id)) {
</span><span class="cx">         ThrowUserError('component_already_exists', { name    =&gt; $component-&gt;name,
</span><span class="lines">@@ -235,6 +234,8 @@
</span><span class="cx"> 
</span><span class="cx"> sub _check_product {
</span><span class="cx">     my ($invocant, $product) = @_;
</span><ins>+    $product || ThrowCodeError('param_required', 
+                    { function =&gt; &quot;$invocant-&gt;create&quot;, param =&gt; 'product' });
</ins><span class="cx">     return Bugzilla-&gt;user-&gt;check_can_admin_product($product-&gt;name);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -302,6 +303,7 @@
</span><span class="cx"> 
</span><span class="cx"> sub set_name { $_[0]-&gt;set('name', $_[1]); }
</span><span class="cx"> sub set_description { $_[0]-&gt;set('description', $_[1]); }
</span><ins>+sub set_is_active { $_[0]-&gt;set('isactive', $_[1]); }
</ins><span class="cx"> sub set_default_assignee {
</span><span class="cx">     my ($self, $owner) = @_;
</span><span class="cx"> 
</span><span class="lines">@@ -372,16 +374,14 @@
</span><span class="cx">     my $self = shift;
</span><span class="cx"> 
</span><span class="cx">     if (!defined $self-&gt;{'flag_types'}) {
</span><ins>+        my $flagtypes = Bugzilla::FlagType::match({ product_id   =&gt; $self-&gt;product_id,
+                                                    component_id =&gt; $self-&gt;id });
+
</ins><span class="cx">         $self-&gt;{'flag_types'} = {};
</span><span class="cx">         $self-&gt;{'flag_types'}-&gt;{'bug'} =
</span><del>-          Bugzilla::FlagType::match({ 'target_type'  =&gt; 'bug',
-                                      'product_id'   =&gt; $self-&gt;product_id,
-                                      'component_id' =&gt; $self-&gt;id });
-
</del><ins>+          [grep { $_-&gt;target_type eq 'bug' } @$flagtypes];
</ins><span class="cx">         $self-&gt;{'flag_types'}-&gt;{'attachment'} =
</span><del>-          Bugzilla::FlagType::match({ 'target_type'  =&gt; 'attachment',
-                                      'product_id'   =&gt; $self-&gt;product_id,
-                                      'component_id' =&gt; $self-&gt;id });
</del><ins>+          [grep { $_-&gt;target_type eq 'attachment' } @$flagtypes];
</ins><span class="cx">     }
</span><span class="cx">     return $self-&gt;{'flag_types'};
</span><span class="cx"> }
</span><span class="lines">@@ -416,11 +416,25 @@
</span><span class="cx"> ####      Accessors        ####
</span><span class="cx"> ###############################
</span><span class="cx"> 
</span><del>-sub id          { return $_[0]-&gt;{'id'};          }
-sub name        { return $_[0]-&gt;{'name'};        }
</del><span class="cx"> sub description { return $_[0]-&gt;{'description'}; }
</span><span class="cx"> sub product_id  { return $_[0]-&gt;{'product_id'};  }
</span><ins>+sub is_active   { return $_[0]-&gt;{'isactive'};    }
</ins><span class="cx"> 
</span><ins>+##############################################
+# Implement Bugzilla::Field::ChoiceInterface #
+##############################################
+
+use constant FIELD_NAME =&gt; 'component';
+use constant is_default =&gt; 0;
+
+sub is_set_on_bug {
+    my ($self, $bug) = @_;
+    # We treat it like a hash always, so that we don't have to check if it's
+    # a hash or an object.
+    return 0 if !defined $bug-&gt;{component_id};
+    $bug-&gt;{component_id} == $self-&gt;id ? 1 : 0;
+}
+
</ins><span class="cx"> ###############################
</span><span class="cx"> ####      Subroutines      ####
</span><span class="cx"> ###############################
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaConfigAdminpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Config/Admin.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Config/Admin.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Config/Admin.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -35,7 +35,7 @@
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla::Config::Common;
</span><span class="cx"> 
</span><del>-$Bugzilla::Config::Admin::sortkey = &quot;01&quot;;
</del><ins>+our $sortkey = 200;
</ins><span class="cx"> 
</span><span class="cx"> sub get_param_list {
</span><span class="cx">   my $class = shift;
</span><span class="lines">@@ -49,20 +49,14 @@
</span><span class="cx">   {
</span><span class="cx">    name =&gt; 'allowemailchange',
</span><span class="cx">    type =&gt; 'b',
</span><del>-   default =&gt; 0
</del><ins>+   default =&gt; 1
</ins><span class="cx">   },
</span><span class="cx"> 
</span><span class="cx">   {
</span><span class="cx">    name =&gt; 'allowuserdeletion',
</span><span class="cx">    type =&gt; 'b',
</span><span class="cx">    default =&gt; 0
</span><del>-  },
-
-  {
-   name =&gt; 'supportwatchers',
-   type =&gt; 'b',
-   default =&gt; 0
-  } );
</del><ins>+  });
</ins><span class="cx">   return @param_list;
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaConfigAdvancedpmfromrev173253trunkWebsitesbugswebkitorgBugzillaConfigPatchViewerpm"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/Bugzilla/Config/Advanced.pm (from rev 173253, trunk/Websites/bugs.webkit.org/Bugzilla/Config/PatchViewer.pm) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Config/Advanced.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Config/Advanced.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,68 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Netscape Communications
+# Corporation. Portions created by Netscape are
+# Copyright (C) 1998 Netscape Communications Corporation. All
+# Rights Reserved.
+#
+# Contributor(s): Terry Weissman &lt;terry@mozilla.org&gt;
+#                 Dawn Endico &lt;endico@mozilla.org&gt;
+#                 Dan Mosedale &lt;dmose@mozilla.org&gt;
+#                 Joe Robins &lt;jmrobins@tgix.com&gt;
+#                 Jacob Steenhagen &lt;jake@bugzilla.org&gt;
+#                 J. Paul Reed &lt;preed@sigkill.com&gt;
+#                 Bradley Baetz &lt;bbaetz@student.usyd.edu.au&gt;
+#                 Joseph Heenan &lt;joseph@heenan.me.uk&gt;
+#                 Erik Stambaugh &lt;erik@dasbistro.com&gt;
+#                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
+#                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+package Bugzilla::Config::Advanced;
+use strict;
+
+use Bugzilla::Config::Common;
+
+our $sortkey = 1700;
+
+use constant get_param_list =&gt; (
+  {
+   name =&gt; 'cookiedomain',
+   type =&gt; 't',
+   default =&gt; ''
+  },
+
+  {
+   name =&gt; 'inbound_proxies',
+   type =&gt; 't',
+   default =&gt; '',
+   checker =&gt; \&amp;check_ip
+  },
+
+  {
+   name =&gt; 'proxy_url',
+   type =&gt; 't',
+   default =&gt; ''
+  },
+
+  {
+   name =&gt; 'strict_transport_security',
+   type =&gt; 's',
+   choices =&gt; ['off', 'this_domain_only', 'include_subdomains'],
+   default =&gt; 'off',
+   checker =&gt; \&amp;check_multi
+  },
+);
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaConfigAttachmentpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Config/Attachment.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Config/Attachment.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Config/Attachment.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -35,7 +35,7 @@
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla::Config::Common;
</span><span class="cx"> 
</span><del>-$Bugzilla::Config::Attachment::sortkey = &quot;025&quot;;
</del><ins>+our $sortkey = 400;
</ins><span class="cx"> 
</span><span class="cx"> sub get_param_list {
</span><span class="cx">   my $class = shift;
</span><span class="lines">@@ -58,17 +58,6 @@
</span><span class="cx">   type =&gt; 'b',
</span><span class="cx">   default =&gt; 0
</span><span class="cx">   },
</span><del>-  {
-  name =&gt; 'allow_attach_url',
-  type =&gt; 'b',
-  default =&gt; 0
-  },
-  {
-   name =&gt; 'maxpatchsize',
-   type =&gt; 't',
-   default =&gt; '1000',
-   checker =&gt; \&amp;check_numeric
-  },
</del><span class="cx"> 
</span><span class="cx">   {
</span><span class="cx">    name =&gt; 'maxattachmentsize',
</span><span class="lines">@@ -90,13 +79,6 @@
</span><span class="cx">    type =&gt; 't',
</span><span class="cx">    default =&gt; '0',
</span><span class="cx">    checker =&gt; \&amp;check_numeric
</span><del>-  },
-  
-  {
-   name =&gt; 'convert_uncompressed_images',
-   type =&gt; 'b',
-   default =&gt; 0,
-   checker =&gt; \&amp;check_image_converter
</del><span class="cx">   } );
</span><span class="cx">   return @param_list;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaConfigAuthpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Config/Auth.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Config/Auth.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Config/Auth.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -35,7 +35,7 @@
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla::Config::Common;
</span><span class="cx"> 
</span><del>-$Bugzilla::Config::Auth::sortkey = &quot;02&quot;;
</del><ins>+our $sortkey = 300;
</ins><span class="cx"> 
</span><span class="cx"> sub get_param_list {
</span><span class="cx">   my $class = shift;
</span><span class="lines">@@ -91,13 +91,6 @@
</span><span class="cx">   },
</span><span class="cx"> 
</span><span class="cx">   {
</span><del>-   name =&gt; 'loginnetmask',
-   type =&gt; 't',
-   default =&gt; '0',
-   checker =&gt; \&amp;check_netmask
-  },
-
-  {
</del><span class="cx">    name =&gt; 'requirelogin',
</span><span class="cx">    type =&gt; 'b',
</span><span class="cx">    default =&gt; '0'
</span><span class="lines">@@ -128,6 +121,15 @@
</span><span class="cx">    type =&gt; 't',
</span><span class="cx">    default =&gt; q:.*:,
</span><span class="cx">    checker =&gt; \&amp;check_regexp
</span><ins>+  },
+
+  {
+   name =&gt; 'password_complexity',
+   type =&gt; 's',
+   choices =&gt; [ 'no_constraints', 'mixed_letters', 'letters_numbers',
+                'letters_numbers_specialchars' ],
+   default =&gt; 'no_constraints',
+   checker =&gt; \&amp;check_multi
</ins><span class="cx">   } );
</span><span class="cx">   return @param_list;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaConfigBugChangepm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Config/BugChange.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Config/BugChange.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Config/BugChange.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -36,7 +36,7 @@
</span><span class="cx"> use Bugzilla::Config::Common;
</span><span class="cx"> use Bugzilla::Status;
</span><span class="cx"> 
</span><del>-$Bugzilla::Config::BugChange::sortkey = &quot;03&quot;;
</del><ins>+our $sortkey = 500;
</ins><span class="cx"> 
</span><span class="cx"> sub get_param_list {
</span><span class="cx">   my $class = shift;
</span><span class="lines">@@ -81,24 +81,12 @@
</span><span class="cx">   },
</span><span class="cx"> 
</span><span class="cx">   {
</span><del>-   name =&gt; 'commentonclearresolution',
-   type =&gt; 'b',
-   default =&gt; 0
-  },
-
-  {
</del><span class="cx">    name =&gt; 'commentonchange_resolution',
</span><span class="cx">    type =&gt; 'b',
</span><span class="cx">    default =&gt; 0
</span><span class="cx">   },
</span><span class="cx"> 
</span><span class="cx">   {
</span><del>-   name =&gt; 'commentonreassignbycomponent',
-   type =&gt; 'b',
-   default =&gt; 0
-  },
-
-  {
</del><span class="cx">    name =&gt; 'commentonduplicate',
</span><span class="cx">    type =&gt; 'b',
</span><span class="cx">    default =&gt; 0
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaConfigBugFieldspm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Config/BugFields.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Config/BugFields.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Config/BugFields.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -36,7 +36,7 @@
</span><span class="cx"> use Bugzilla::Config::Common;
</span><span class="cx"> use Bugzilla::Field;
</span><span class="cx"> 
</span><del>-$Bugzilla::Config::BugFields::sortkey = &quot;04&quot;;
</del><ins>+our $sortkey = 600;
</ins><span class="cx"> 
</span><span class="cx"> sub get_param_list {
</span><span class="cx">   my $class = shift;
</span><span class="lines">@@ -54,12 +54,6 @@
</span><span class="cx">   },
</span><span class="cx"> 
</span><span class="cx">   {
</span><del>-   name =&gt; 'showallproducts',
-   type =&gt; 'b',
-   default =&gt; 0
-  },
-
-  {
</del><span class="cx">    name =&gt; 'usetargetmilestone',
</span><span class="cx">    type =&gt; 'b',
</span><span class="cx">    default =&gt; 0
</span><span class="lines">@@ -78,15 +72,15 @@
</span><span class="cx">   },
</span><span class="cx"> 
</span><span class="cx">   {
</span><del>-   name =&gt; 'usevotes',
</del><ins>+   name =&gt; 'usebugaliases',
</ins><span class="cx">    type =&gt; 'b',
</span><span class="cx">    default =&gt; 0
</span><span class="cx">   },
</span><span class="cx"> 
</span><span class="cx">   {
</span><del>-   name =&gt; 'usebugaliases',
</del><ins>+   name =&gt; 'use_see_also',
</ins><span class="cx">    type =&gt; 'b',
</span><del>-   default =&gt; 0
</del><ins>+   default =&gt; 1
</ins><span class="cx">   },
</span><span class="cx"> 
</span><span class="cx">   {
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaConfigBugMovepm"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/Bugzilla/Config/BugMove.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Config/BugMove.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Config/BugMove.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,93 +0,0 @@
</span><del>-# -*- Mode: perl; indent-tabs-mode: nil -*-
-#
-# The contents of this file are subject to the Mozilla Public
-# License Version 1.1 (the &quot;License&quot;); you may not use this file
-# except in compliance with the License. You may obtain a copy of
-# the License at http://www.mozilla.org/MPL/
-#
-# Software distributed under the License is distributed on an &quot;AS
-# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
-# implied. See the License for the specific language governing
-# rights and limitations under the License.
-#
-# The Original Code is the Bugzilla Bug Tracking System.
-#
-# The Initial Developer of the Original Code is Netscape Communications
-# Corporation. Portions created by Netscape are
-# Copyright (C) 1998 Netscape Communications Corporation. All
-# Rights Reserved.
-#
-# Contributor(s): Terry Weissman &lt;terry@mozilla.org&gt;
-#                 Dawn Endico &lt;endico@mozilla.org&gt;
-#                 Dan Mosedale &lt;dmose@mozilla.org&gt;
-#                 Joe Robins &lt;jmrobins@tgix.com&gt;
-#                 Jacob Steenhagen &lt;jake@bugzilla.org&gt;
-#                 J. Paul Reed &lt;preed@sigkill.com&gt;
-#                 Bradley Baetz &lt;bbaetz@student.usyd.edu.au&gt;
-#                 Joseph Heenan &lt;joseph@heenan.me.uk&gt;
-#                 Erik Stambaugh &lt;erik@dasbistro.com&gt;
-#                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
-#
-
-package Bugzilla::Config::BugMove;
-
-use strict;
-
-use Bugzilla::Config::Common;
-
-$Bugzilla::Config::BugMove::sortkey = &quot;05&quot;;
-
-sub get_param_list {
-  my $class = shift;
-  my @param_list = (
-  {
-   name =&gt; 'move-enabled',
-   type =&gt; 'b',
-   default =&gt; 0
-  },
-
-  {
-   name =&gt; 'move-button-text',
-   type =&gt; 't',
-   default =&gt; 'Move To Bugscape'
-  },
-
-  {
-   name =&gt; 'move-to-url',
-   type =&gt; 't',
-   default =&gt; ''
-  },
-
-  {
-   name =&gt; 'move-to-address',
-   type =&gt; 't',
-   default =&gt; 'bugzilla-import'
-  },
-
-  {
-   name =&gt; 'moved-from-address',
-   type =&gt; 't',
-   default =&gt; 'bugzilla-admin'
-  },
-
-  {
-   name =&gt; 'movers',
-   type =&gt; 't',
-   default =&gt; ''
-  },
-
-  {
-   name =&gt; 'moved-default-product',
-   type =&gt; 't',
-   default =&gt; ''
-  },
-
-  {
-   name =&gt; 'moved-default-component',
-   type =&gt; 't',
-   default =&gt; ''
-  } );
-  return @param_list;
-}
-
-1;
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaConfigCommonpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Config/Common.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Config/Common.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Config/Common.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -34,8 +34,8 @@
</span><span class="cx"> 
</span><span class="cx"> use strict;
</span><span class="cx"> 
</span><ins>+use Email::Address;
</ins><span class="cx"> use Socket;
</span><del>-use Time::Zone;
</del><span class="cx"> 
</span><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> use Bugzilla::Constants;
</span><span class="lines">@@ -48,10 +48,10 @@
</span><span class="cx">     qw(check_multi check_numeric check_regexp check_url check_group
</span><span class="cx">        check_sslbase check_priority check_severity check_platform
</span><span class="cx">        check_opsys check_shadowdb check_urlbase check_webdotbase
</span><del>-       check_netmask check_user_verify_class check_image_converter
-       check_mail_delivery_method check_notification check_timezone check_utf8
-       check_bug_status check_smtp_auth 
-       check_maxattachmentsize
</del><ins>+       check_user_verify_class check_ip
+       check_mail_delivery_method check_notification check_utf8
+       check_bug_status check_smtp_auth check_theschwartz_available
+       check_maxattachmentsize check_email
</ins><span class="cx"> );
</span><span class="cx"> 
</span><span class="cx"> # Checking functions for the various values
</span><span class="lines">@@ -95,6 +95,14 @@
</span><span class="cx">     return $@;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub check_email {
+    my ($value) = @_;
+    if ($value !~ $Email::Address::mailbox) {
+        return &quot;must be a valid email address.&quot;;
+    }
+    return &quot;&quot;;
+}
+
</ins><span class="cx"> sub check_sslbase {
</span><span class="cx">     my $url = shift;
</span><span class="cx">     if ($url ne '') {
</span><span class="lines">@@ -121,6 +129,15 @@
</span><span class="cx">     return &quot;&quot;;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub check_ip {
+    my $inbound_proxies = shift;
+    my @proxies = split(/[\s,]+/, $inbound_proxies);
+    foreach my $proxy (@proxies) {
+        validate_ip($proxy) || return &quot;$proxy is not a valid IPv4 or IPv6 address&quot;;
+    }
+    return &quot;&quot;;
+}
+
</ins><span class="cx"> sub check_utf8 {
</span><span class="cx">     my $utf8 = shift;
</span><span class="cx">     # You cannot turn off the UTF-8 parameter if you've already converted
</span><span class="lines">@@ -136,7 +153,7 @@
</span><span class="cx"> sub check_priority {
</span><span class="cx">     my ($value) = (@_);
</span><span class="cx">     my $legal_priorities = get_legal_field_values('priority');
</span><del>-    if (lsearch($legal_priorities, $value) &lt; 0) {
</del><ins>+    if (!grep($_ eq $value, @$legal_priorities)) {
</ins><span class="cx">         return &quot;Must be a legal priority value: one of &quot; .
</span><span class="cx">             join(&quot;, &quot;, @$legal_priorities);
</span><span class="cx">     }
</span><span class="lines">@@ -146,7 +163,7 @@
</span><span class="cx"> sub check_severity {
</span><span class="cx">     my ($value) = (@_);
</span><span class="cx">     my $legal_severities = get_legal_field_values('bug_severity');
</span><del>-    if (lsearch($legal_severities, $value) &lt; 0) {
</del><ins>+    if (!grep($_ eq $value, @$legal_severities)) {
</ins><span class="cx">         return &quot;Must be a legal severity value: one of &quot; .
</span><span class="cx">             join(&quot;, &quot;, @$legal_severities);
</span><span class="cx">     }
</span><span class="lines">@@ -156,7 +173,7 @@
</span><span class="cx"> sub check_platform {
</span><span class="cx">     my ($value) = (@_);
</span><span class="cx">     my $legal_platforms = get_legal_field_values('rep_platform');
</span><del>-    if (lsearch(['', @$legal_platforms], $value) &lt; 0) {
</del><ins>+    if (!grep($_ eq $value, '', @$legal_platforms)) {
</ins><span class="cx">         return &quot;Must be empty or a legal platform value: one of &quot; .
</span><span class="cx">             join(&quot;, &quot;, @$legal_platforms);
</span><span class="cx">     }
</span><span class="lines">@@ -166,7 +183,7 @@
</span><span class="cx"> sub check_opsys {
</span><span class="cx">     my ($value) = (@_);
</span><span class="cx">     my $legal_OS = get_legal_field_values('op_sys');
</span><del>-    if (lsearch(['', @$legal_OS], $value) &lt; 0) {
</del><ins>+    if (!grep($_ eq $value, '', @$legal_OS)) {
</ins><span class="cx">         return &quot;Must be empty or a legal operating system value: one of &quot; .
</span><span class="cx">             join(&quot;, &quot;, @$legal_OS);
</span><span class="cx">     }
</span><span class="lines">@@ -176,7 +193,7 @@
</span><span class="cx"> sub check_bug_status {
</span><span class="cx">     my $bug_status = shift;
</span><span class="cx">     my @closed_bug_statuses = map {$_-&gt;name} closed_bug_statuses();
</span><del>-    if (lsearch(\@closed_bug_statuses, $bug_status) &lt; 0) {
</del><ins>+    if (!grep($_ eq $bug_status, @closed_bug_statuses)) {
</ins><span class="cx">         return &quot;Must be a valid closed status: one of &quot; . join(', ', @closed_bug_statuses);
</span><span class="cx">     }
</span><span class="cx">     return &quot;&quot;;
</span><span class="lines">@@ -249,21 +266,6 @@
</span><span class="cx">     return &quot;&quot;;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub check_netmask {
-    my ($mask) = @_;
-    my $res = check_numeric($mask);
-    return $res if $res;
-    if ($mask &lt; 0 || $mask &gt; 32) {
-        return &quot;an IPv4 netmask must be between 0 and 32 bits&quot;;
-    }
-    # Note that if we changed the netmask from anything apart from 32, then
-    # existing logincookies which aren't for a single IP won't work
-    # any more. We can't know which ones they are, though, so they'll just
-    # take space until they're periodically cleared, later.
-
-    return &quot;&quot;;
-}
-
</del><span class="cx"> sub check_user_verify_class {
</span><span class="cx">     # doeditparams traverses the list of params, and for each one it checks,
</span><span class="cx">     # then updates. This means that if one param checker wants to look at 
</span><span class="lines">@@ -273,47 +275,39 @@
</span><span class="cx">     # the login method as LDAP, we won't notice, but all logins will fail.
</span><span class="cx">     # So don't do that.
</span><span class="cx"> 
</span><ins>+    my $params = Bugzilla-&gt;params;
</ins><span class="cx">     my ($list, $entry) = @_;
</span><span class="cx">     $list || return 'You need to specify at least one authentication mechanism';
</span><span class="cx">     for my $class (split /,\s*/, $list) {
</span><span class="cx">         my $res = check_multi($class, $entry);
</span><span class="cx">         return $res if $res;
</span><del>-        if ($class eq 'DB') {
-            # No params
</del><ins>+        if ($class eq 'RADIUS') {
+            if (!Bugzilla-&gt;feature('auth_radius')) {
+                return &quot;RADIUS support is not available. Run checksetup.pl&quot;
+                       . &quot; for more details&quot;;
+            }
+            return &quot;RADIUS servername (RADIUS_server) is missing&quot;
+                if !$params-&gt;{&quot;RADIUS_server&quot;};
+            return &quot;RADIUS_secret is empty&quot; if !$params-&gt;{&quot;RADIUS_secret&quot;};
</ins><span class="cx">         }
</span><del>-        elsif ($class eq 'RADIUS') {
-            eval &quot;require Authen::Radius&quot;;
-            return &quot;Error requiring Authen::Radius: '$@'&quot; if $@;
-            return &quot;RADIUS servername (RADIUS_server) is missing&quot; unless Bugzilla-&gt;params-&gt;{&quot;RADIUS_server&quot;};
-            return &quot;RADIUS_secret is empty&quot; unless Bugzilla-&gt;params-&gt;{&quot;RADIUS_secret&quot;};
-        }
</del><span class="cx">         elsif ($class eq 'LDAP') {
</span><del>-            eval &quot;require Net::LDAP&quot;;
-            return &quot;Error requiring Net::LDAP: '$@'&quot; if $@;
-            return &quot;LDAP servername (LDAPserver) is missing&quot; unless Bugzilla-&gt;params-&gt;{&quot;LDAPserver&quot;};
-            return &quot;LDAPBaseDN is empty&quot; unless Bugzilla-&gt;params-&gt;{&quot;LDAPBaseDN&quot;};
</del><ins>+            if (!Bugzilla-&gt;feature('auth_ldap')) {
+                return &quot;LDAP support is not available. Run checksetup.pl&quot;
+                       . &quot; for more details&quot;;
+            }
+            return &quot;LDAP servername (LDAPserver) is missing&quot; 
+                if !$params-&gt;{&quot;LDAPserver&quot;};
+            return &quot;LDAPBaseDN is empty&quot; if !$params-&gt;{&quot;LDAPBaseDN&quot;};
</ins><span class="cx">         }
</span><del>-        else {
-            return &quot;Unknown user_verify_class '$class' in check_user_verify_class&quot;;
-        }
</del><span class="cx">     }
</span><span class="cx">     return &quot;&quot;;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub check_image_converter {
-    my ($value, $hash) = @_;
-    if ($value == 1){
-       eval &quot;require Image::Magick&quot;;
-       return &quot;Error requiring Image::Magick: '$@'&quot; if $@;
-    } 
-    return &quot;&quot;;
-}
-
</del><span class="cx"> sub check_mail_delivery_method {
</span><span class="cx">     my $check = check_multi(@_);
</span><span class="cx">     return $check if $check;
</span><span class="cx">     my $mailer = shift;
</span><del>-    if ($mailer eq 'sendmail' &amp;&amp; $^O =~ /MSWin32/i) {
</del><ins>+    if ($mailer eq 'sendmail' and ON_WINDOWS) {
</ins><span class="cx">         # look for sendmail.exe 
</span><span class="cx">         return &quot;Failed to locate &quot; . SENDMAIL_EXE
</span><span class="cx">             unless -e SENDMAIL_EXE;
</span><span class="lines">@@ -349,22 +343,28 @@
</span><span class="cx">                &quot;about the next stable release, you should select &quot; .
</span><span class="cx">                &quot;'latest_stable_release' instead&quot;;
</span><span class="cx">     }
</span><ins>+    if ($option ne 'disabled' &amp;&amp; !Bugzilla-&gt;feature('updates')) {
+        return &quot;Some Perl modules are missing to get notifications about &quot; .
+               &quot;new releases. See the output of checksetup.pl for more information&quot;;
+    }
</ins><span class="cx">     return &quot;&quot;;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub check_timezone {
-    my $tz = shift;
-    unless (defined(tz_offset($tz))) {
-        return &quot;must be empty or a legal timezone name, such as PDT or JST&quot;;
</del><ins>+sub check_smtp_auth {
+    my $username = shift;
+    if ($username and !Bugzilla-&gt;feature('smtp_auth')) {
+        return &quot;SMTP Authentication is not available. Run checksetup.pl for&quot;
+               . &quot; more details&quot;;
</ins><span class="cx">     }
</span><span class="cx">     return &quot;&quot;;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub check_smtp_auth {
-    my $username = shift;
-    if ($username) {
-        eval &quot;require Authen::SASL&quot;;
-        return &quot;Error requiring Authen::SASL: '$@'&quot; if $@;
</del><ins>+sub check_theschwartz_available {
+    my $use_queue = shift;
+    if ($use_queue &amp;&amp; !Bugzilla-&gt;feature('jobqueue')) {
+        return &quot;Using the job queue requires that you have certain Perl&quot;
+               . &quot; modules installed. See the output of checksetup.pl&quot;
+               . &quot; for more information&quot;;
</ins><span class="cx">     }
</span><span class="cx">     return &quot;&quot;;
</span><span class="cx"> }
</span><span class="lines">@@ -446,7 +446,9 @@
</span><span class="cx"> 
</span><span class="cx"> =head1 DESCRIPTION
</span><span class="cx"> 
</span><del>-All parameter checking functions are called with two parameters:
</del><ins>+All parameter checking functions are called with two parameters: the value to 
+check, and a hash with the details of the param (type, default etc.) as defined
+in the relevant F&lt;Bugzilla::Config::*&gt; package.
</ins><span class="cx"> 
</span><span class="cx"> =head2 Functions
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaConfigCorepm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Config/Core.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Config/Core.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Config/Core.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -35,18 +35,10 @@
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla::Config::Common;
</span><span class="cx"> 
</span><del>-$Bugzilla::Config::Core::sortkey = &quot;00&quot;;
</del><ins>+our $sortkey = 100;
</ins><span class="cx"> 
</span><del>-sub get_param_list {
-  my $class = shift;
-  my @param_list = (
</del><ins>+use constant get_param_list =&gt; (
</ins><span class="cx">   {
</span><del>-   name =&gt; 'maintainer',
-   type =&gt; 't',
-   default =&gt; 'THE MAINTAINER HAS NOT YET BEEN SET'
-  },
-
-  {
</del><span class="cx">    name =&gt; 'urlbase',
</span><span class="cx">    type =&gt; 't',
</span><span class="cx">    default =&gt; '',
</span><span class="lines">@@ -54,10 +46,9 @@
</span><span class="cx">   },
</span><span class="cx"> 
</span><span class="cx">   {
</span><del>-   name =&gt; 'docs_urlbase',
-   type =&gt; 't',
-   default =&gt; 'docs/%lang%/html/',
-   checker =&gt; \&amp;check_url
</del><ins>+   name =&gt; 'ssl_redirect',
+   type =&gt; 'b',
+   default =&gt; 0
</ins><span class="cx">   },
</span><span class="cx"> 
</span><span class="cx">   {
</span><span class="lines">@@ -68,66 +59,10 @@
</span><span class="cx">   },
</span><span class="cx"> 
</span><span class="cx">   {
</span><del>-   name =&gt; 'ssl',
-   type =&gt; 's',
-   choices =&gt; ['never', 'authenticated sessions', 'always'],
-   default =&gt; 'never'
-  },
-
-
-  {
-   name =&gt; 'cookiedomain',
-   type =&gt; 't',
-   default =&gt; ''
-  },
-
-  {
</del><span class="cx">    name =&gt; 'cookiepath',
</span><span class="cx">    type =&gt; 't',
</span><span class="cx">    default =&gt; '/'
</span><span class="cx">   },
</span><ins>+);
</ins><span class="cx"> 
</span><del>-  {
-   name =&gt; 'timezone',
-   type =&gt; 't',
-   default =&gt; '',
-   checker =&gt; \&amp;check_timezone
-  },
-
-  {
-   name =&gt; 'utf8',
-   type =&gt; 'b',
-   default =&gt; '0',
-   checker =&gt; \&amp;check_utf8
-  },
-
-  {
-   name =&gt; 'shutdownhtml',
-   type =&gt; 'l',
-   default =&gt; ''
-  },
-
-  {
-   name =&gt; 'announcehtml',
-   type =&gt; 'l',
-   default =&gt; ''
-  },
-
-  {
-   name =&gt; 'proxy_url',
-   type =&gt; 't',
-   default =&gt; ''
-  },
-
-  {
-   name =&gt; 'upgrade_notification',
-   type =&gt; 's',
-   choices =&gt; ['development_snapshot', 'latest_stable_release',
-               'stable_branch_release', 'disabled'],
-   default =&gt; 'latest_stable_release',
-   checker =&gt; \&amp;check_notification
-  } );
-  return @param_list;
-}
-
</del><span class="cx"> 1;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaConfigDependencyGraphpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Config/DependencyGraph.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Config/DependencyGraph.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Config/DependencyGraph.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -35,7 +35,7 @@
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla::Config::Common;
</span><span class="cx"> 
</span><del>-$Bugzilla::Config::DependencyGraph::sortkey = &quot;06&quot;;
</del><ins>+our $sortkey = 800;
</ins><span class="cx"> 
</span><span class="cx"> sub get_param_list {
</span><span class="cx">   my $class = shift;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaConfigGeneralpmfromrev173253trunkWebsitesbugswebkitorgBugzillaConfigCorepm"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/Bugzilla/Config/General.pm (from rev 173253, trunk/Websites/bugs.webkit.org/Bugzilla/Config/Core.pm) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Config/General.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Config/General.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,83 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Netscape Communications
+# Corporation. Portions created by Netscape are
+# Copyright (C) 1998 Netscape Communications Corporation. All
+# Rights Reserved.
+#
+# Contributor(s): Terry Weissman &lt;terry@mozilla.org&gt;
+#                 Dawn Endico &lt;endico@mozilla.org&gt;
+#                 Dan Mosedale &lt;dmose@mozilla.org&gt;
+#                 Joe Robins &lt;jmrobins@tgix.com&gt;
+#                 Jacob Steenhagen &lt;jake@bugzilla.org&gt;
+#                 J. Paul Reed &lt;preed@sigkill.com&gt;
+#                 Bradley Baetz &lt;bbaetz@student.usyd.edu.au&gt;
+#                 Joseph Heenan &lt;joseph@heenan.me.uk&gt;
+#                 Erik Stambaugh &lt;erik@dasbistro.com&gt;
+#                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
+#                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+package Bugzilla::Config::General;
+use strict;
+use Bugzilla::Config::Common;
+
+our $sortkey = 150;
+
+use constant get_param_list =&gt; (
+  {
+   name =&gt; 'maintainer',
+   type =&gt; 't',
+   no_reset =&gt; '1',
+   default =&gt; '',
+   checker =&gt; \&amp;check_email
+  },
+
+  {
+   name =&gt; 'docs_urlbase',
+   type =&gt; 't',
+   default =&gt; 'docs/%lang%/html/',
+   checker =&gt; \&amp;check_url
+  },
+
+  {
+   name =&gt; 'utf8',
+   type =&gt; 'b',
+   default =&gt; '0',
+   checker =&gt; \&amp;check_utf8
+  },
+
+  {
+   name =&gt; 'shutdownhtml',
+   type =&gt; 'l',
+   default =&gt; ''
+  },
+
+  {
+   name =&gt; 'announcehtml',
+   type =&gt; 'l',
+   default =&gt; ''
+  },
+
+  {
+   name =&gt; 'upgrade_notification',
+   type =&gt; 's',
+   choices =&gt; ['development_snapshot', 'latest_stable_release',
+               'stable_branch_release', 'disabled'],
+   default =&gt; 'latest_stable_release',
+   checker =&gt; \&amp;check_notification
+  },
+);
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaConfigGroupSecuritypm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Config/GroupSecurity.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Config/GroupSecurity.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Config/GroupSecurity.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -36,7 +36,7 @@
</span><span class="cx"> use Bugzilla::Config::Common;
</span><span class="cx"> use Bugzilla::Group;
</span><span class="cx"> 
</span><del>-$Bugzilla::Config::GroupSecurity::sortkey = &quot;07&quot;;
</del><ins>+our $sortkey = 900;
</ins><span class="cx"> 
</span><span class="cx"> sub get_param_list {
</span><span class="cx">   my $class = shift;
</span><span class="lines">@@ -49,12 +49,6 @@
</span><span class="cx">   },
</span><span class="cx"> 
</span><span class="cx">   {
</span><del>-   name =&gt; 'useentrygroupdefault',
-   type =&gt; 'b',
-   default =&gt; 0
-  },
-
-  {
</del><span class="cx">    name =&gt; 'chartgroup',
</span><span class="cx">    type =&gt; 's',
</span><span class="cx">    choices =&gt; \&amp;_get_all_group_names,
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaConfigLDAPpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Config/LDAP.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Config/LDAP.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Config/LDAP.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -35,7 +35,7 @@
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla::Config::Common;
</span><span class="cx"> 
</span><del>-$Bugzilla::Config::LDAP::sortkey = &quot;09&quot;;
</del><ins>+our $sortkey = 1000;
</ins><span class="cx"> 
</span><span class="cx"> sub get_param_list {
</span><span class="cx">   my $class = shift;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaConfigMTApm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Config/MTA.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Config/MTA.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Config/MTA.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -36,7 +36,7 @@
</span><span class="cx"> use Bugzilla::Config::Common;
</span><span class="cx"> use Email::Send;
</span><span class="cx"> 
</span><del>-$Bugzilla::Config::MTA::sortkey = &quot;10&quot;;
</del><ins>+our $sortkey = 1200;
</ins><span class="cx"> 
</span><span class="cx"> sub get_param_list {
</span><span class="cx">   my $class = shift;
</span><span class="lines">@@ -58,9 +58,10 @@
</span><span class="cx">   },
</span><span class="cx"> 
</span><span class="cx">   {
</span><del>-   name =&gt; 'sendmailnow',
</del><ins>+   name =&gt; 'use_mailer_queue',
</ins><span class="cx">    type =&gt; 'b',
</span><del>-   default =&gt; 1
</del><ins>+   default =&gt; 0,
+   checker =&gt; \&amp;check_theschwartz_available,
</ins><span class="cx">   },
</span><span class="cx"> 
</span><span class="cx">   {
</span><span class="lines">@@ -90,7 +91,6 @@
</span><span class="cx">    default =&gt; 7,
</span><span class="cx">    checker =&gt; \&amp;check_numeric
</span><span class="cx">   },
</span><del>-  
</del><span class="cx">   {
</span><span class="cx">    name =&gt; 'globalwatchers',
</span><span class="cx">    type =&gt; 't',
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaConfigPatchViewerpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Config/PatchViewer.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Config/PatchViewer.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Config/PatchViewer.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -35,7 +35,7 @@
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla::Config::Common;
</span><span class="cx"> 
</span><del>-$Bugzilla::Config::PatchViewer::sortkey = &quot;11&quot;;
</del><ins>+our $sortkey = 1300;
</ins><span class="cx"> 
</span><span class="cx"> sub get_param_list {
</span><span class="cx">   my $class = shift;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaConfigQuerypm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Config/Query.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Config/Query.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Config/Query.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -35,7 +35,7 @@
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla::Config::Common;
</span><span class="cx"> 
</span><del>-$Bugzilla::Config::Query::sortkey = &quot;12&quot;;
</del><ins>+our $sortkey = 1400;
</ins><span class="cx"> 
</span><span class="cx"> sub get_param_list {
</span><span class="cx">   my $class = shift;
</span><span class="lines">@@ -58,28 +58,34 @@
</span><span class="cx">   {
</span><span class="cx">    name =&gt; 'mybugstemplate',
</span><span class="cx">    type =&gt; 't',
</span><del>-   default =&gt; 'buglist.cgi?bug_status=UNCONFIRMED&amp;amp;bug_status=NEW&amp;amp;bug_status=ASSIGNED&amp;amp;bug_status=REOPENED&amp;amp;emailassigned_to1=1&amp;amp;emailreporter1=1&amp;amp;emailtype1=exact&amp;amp;email1=%userid%&amp;amp;field0-0-0=bug_status&amp;amp;type0-0-0=notequals&amp;amp;value0-0-0=UNCONFIRMED&amp;amp;field0-0-1=reporter&amp;amp;type0-0-1=equals&amp;amp;value0-0-1=%userid%'
</del><ins>+   default =&gt; 'buglist.cgi?resolution=---&amp;amp;emailassigned_to1=1&amp;amp;emailreporter1=1&amp;amp;emailtype1=exact&amp;amp;email1=%userid%'
</ins><span class="cx">   },
</span><span class="cx"> 
</span><span class="cx">   {
</span><span class="cx">    name =&gt; 'defaultquery',
</span><span class="cx">    type =&gt; 't',
</span><del>-   default =&gt; 'bug_status=NEW&amp;bug_status=ASSIGNED&amp;bug_status=REOPENED&amp;emailassigned_to1=1&amp;emailassigned_to2=1&amp;emailreporter2=1&amp;emailcc2=1&amp;emailqa_contact2=1&amp;order=Importance&amp;long_desc_type=substring'
</del><ins>+   default =&gt; 'resolution=---&amp;emailassigned_to1=1&amp;emailassigned_to2=1&amp;emailreporter2=1&amp;emailcc2=1&amp;emailqa_contact2=1&amp;emaillongdesc3=1&amp;order=Importance&amp;long_desc_type=substring'
</ins><span class="cx">   },
</span><span class="cx"> 
</span><span class="cx">   {
</span><del>-   name    =&gt; 'quicksearch_comment_cutoff',
-   type    =&gt; 't',
-   default =&gt; '4',
-   checker =&gt; \&amp;check_numeric
</del><ins>+   name =&gt; 'search_allow_no_criteria',
+   type =&gt; 'b',
+   default =&gt; 1
</ins><span class="cx">   },
</span><del>-  
</del><ins>+
</ins><span class="cx">   {
</span><del>-   name =&gt; 'specific_search_allow_empty_words',
-   type =&gt; 'b',
-   default =&gt; 0
-  }
-  
</del><ins>+    name =&gt; 'default_search_limit',
+    type =&gt; 't',
+    default =&gt; '500',
+    checker =&gt; \&amp;check_numeric
+  },
+
+  {
+    name =&gt; 'max_search_results',
+    type =&gt; 't',
+    default =&gt; '10000',
+    checker =&gt; \&amp;check_numeric
+  },
</ins><span class="cx">   );
</span><span class="cx">   return @param_list;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaConfigRADIUSpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Config/RADIUS.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Config/RADIUS.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Config/RADIUS.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -25,7 +25,7 @@
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla::Config::Common;
</span><span class="cx"> 
</span><del>-$Bugzilla::Config::RADIUS::sortkey = &quot;09&quot;;
</del><ins>+our $sortkey = 1100;
</ins><span class="cx"> 
</span><span class="cx"> sub get_param_list {
</span><span class="cx">   my $class = shift;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaConfigShadowDBpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Config/ShadowDB.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Config/ShadowDB.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Config/ShadowDB.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -35,7 +35,7 @@
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla::Config::Common;
</span><span class="cx"> 
</span><del>-$Bugzilla::Config::ShadowDB::sortkey = &quot;13&quot;;
</del><ins>+our $sortkey = 1500;
</ins><span class="cx"> 
</span><span class="cx"> sub get_param_list {
</span><span class="cx">   my $class = shift;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaConfigUserMatchpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Config/UserMatch.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Config/UserMatch.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Config/UserMatch.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -35,7 +35,7 @@
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla::Config::Common;
</span><span class="cx"> 
</span><del>-$Bugzilla::Config::UserMatch::sortkey = &quot;14&quot;;
</del><ins>+our $sortkey = 1600;
</ins><span class="cx"> 
</span><span class="cx"> sub get_param_list {
</span><span class="cx">   my $class = shift;
</span><span class="lines">@@ -47,10 +47,9 @@
</span><span class="cx">   },
</span><span class="cx"> 
</span><span class="cx">   {
</span><del>-   name =&gt; 'usermatchmode',
-   type =&gt; 's',
-   choices =&gt; ['off', 'wildcard', 'search'],
-   default =&gt; 'off'
</del><ins>+   name    =&gt; 'ajax_user_autocompletion', 
+   type    =&gt; 'b', 
+   default =&gt; '1', 
</ins><span class="cx">   },
</span><span class="cx"> 
</span><span class="cx">   {
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaConfigpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Config.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Config.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Config.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -34,6 +34,8 @@
</span><span class="cx"> 
</span><span class="cx"> use base qw(Exporter);
</span><span class="cx"> use Bugzilla::Constants;
</span><ins>+use Bugzilla::Hook;
+use Bugzilla::Install::Filesystem qw(fix_file_permissions);
</ins><span class="cx"> use Data::Dumper;
</span><span class="cx"> use File::Temp;
</span><span class="cx"> 
</span><span class="lines">@@ -46,22 +48,28 @@
</span><span class="cx">   );
</span><span class="cx"> Exporter::export_ok_tags('admin');
</span><span class="cx"> 
</span><del>-use vars qw(@param_list);
-
</del><span class="cx"> # INITIALISATION CODE
</span><span class="cx"> # Perl throws a warning if we use bz_locations() directly after do.
</span><span class="cx"> our %params;
</span><span class="cx"> # Load in the param definitions
</span><span class="cx"> sub _load_params {
</span><span class="cx">     my $panels = param_panels();
</span><ins>+    my %hook_panels;
</ins><span class="cx">     foreach my $panel (keys %$panels) {
</span><span class="cx">         my $module = $panels-&gt;{$panel};
</span><span class="cx">         eval(&quot;require $module&quot;) || die $@;
</span><del>-        my @new_param_list = &quot;$module&quot;-&gt;get_param_list();
-        foreach my $item (@new_param_list) {
</del><ins>+        my @new_param_list = $module-&gt;get_param_list();
+        $hook_panels{lc($panel)} = { params =&gt; \@new_param_list };
+    }
+    # This hook is also called in editparams.cgi. This call here is required
+    # to make SetParam work.
+    Bugzilla::Hook::process('config_modify_panels', 
+                            { panels =&gt; \%hook_panels });
+
+    foreach my $panel (keys %hook_panels) {
+        foreach my $item (@{$hook_panels{$panel}-&gt;{params}}) {
</ins><span class="cx">             $params{$item-&gt;{'name'}} = $item;
</span><span class="cx">         }
</span><del>-        push(@param_list, @new_param_list);
</del><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> # END INIT CODE
</span><span class="lines">@@ -77,7 +85,8 @@
</span><span class="cx">         $param_panels-&gt;{$module} = &quot;Bugzilla::Config::$module&quot; unless $module eq 'Common';
</span><span class="cx">     }
</span><span class="cx">     # Now check for any hooked params
</span><del>-    Bugzilla::Hook::process('config', { config =&gt; $param_panels });
</del><ins>+    Bugzilla::Hook::process('config_add_panels', 
+                            { panel_modules =&gt; $param_panels });
</ins><span class="cx">     return $param_panels;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -107,33 +116,28 @@
</span><span class="cx">     my $answer = Bugzilla-&gt;installation_answers;
</span><span class="cx"> 
</span><span class="cx">     my $param = read_param_file();
</span><ins>+    my %new_params;
</ins><span class="cx"> 
</span><span class="cx">     # If we didn't return any param values, then this is a new installation.
</span><span class="cx">     my $new_install = !(keys %$param);
</span><span class="cx"> 
</span><span class="cx">     # --- UPDATE OLD PARAMS ---
</span><span class="cx"> 
</span><del>-    # Old Bugzilla versions stored the version number in the params file
-    # We don't want it, so get rid of it
-    delete $param-&gt;{'version'};
-
</del><span class="cx">     # Change from usebrowserinfo to defaultplatform/defaultopsys combo
</span><span class="cx">     if (exists $param-&gt;{'usebrowserinfo'}) {
</span><span class="cx">         if (!$param-&gt;{'usebrowserinfo'}) {
</span><span class="cx">             if (!exists $param-&gt;{'defaultplatform'}) {
</span><del>-                $param-&gt;{'defaultplatform'} = 'Other';
</del><ins>+                $new_params{'defaultplatform'} = 'Other';
</ins><span class="cx">             }
</span><span class="cx">             if (!exists $param-&gt;{'defaultopsys'}) {
</span><del>-                $param-&gt;{'defaultopsys'} = 'Other';
</del><ins>+                $new_params{'defaultopsys'} = 'Other';
</ins><span class="cx">             }
</span><span class="cx">         }
</span><del>-        delete $param-&gt;{'usebrowserinfo'};
</del><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # Change from a boolean for quips to multi-state
</span><span class="cx">     if (exists $param-&gt;{'usequip'} &amp;&amp; !exists $param-&gt;{'enablequips'}) {
</span><del>-        $param-&gt;{'enablequips'} = $param-&gt;{'usequip'} ? 'on' : 'off';
-        delete $param-&gt;{'usequip'};
</del><ins>+        $new_params{'enablequips'} = $param-&gt;{'usequip'} ? 'on' : 'off';
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # Change from old product groups to controls for group_control_map
</span><span class="lines">@@ -141,24 +145,19 @@
</span><span class="cx">     if (exists $param-&gt;{'usebuggroups'} &amp;&amp; 
</span><span class="cx">         !exists $param-&gt;{'makeproductgroups'}) 
</span><span class="cx">     {
</span><del>-        $param-&gt;{'makeproductgroups'} = $param-&gt;{'usebuggroups'};
</del><ins>+        $new_params{'makeproductgroups'} = $param-&gt;{'usebuggroups'};
</ins><span class="cx">     }
</span><del>-    if (exists $param-&gt;{'usebuggroupsentry'} 
-       &amp;&amp; !exists $param-&gt;{'useentrygroupdefault'}) {
-        $param-&gt;{'useentrygroupdefault'} = $param-&gt;{'usebuggroupsentry'};
-    }
</del><span class="cx"> 
</span><span class="cx">     # Modularise auth code
</span><span class="cx">     if (exists $param-&gt;{'useLDAP'} &amp;&amp; !exists $param-&gt;{'loginmethod'}) {
</span><del>-        $param-&gt;{'loginmethod'} = $param-&gt;{'useLDAP'} ? &quot;LDAP&quot; : &quot;DB&quot;;
</del><ins>+        $new_params{'loginmethod'} = $param-&gt;{'useLDAP'} ? &quot;LDAP&quot; : &quot;DB&quot;;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # set verify method to whatever loginmethod was
</span><span class="cx">     if (exists $param-&gt;{'loginmethod'} 
</span><span class="cx">         &amp;&amp; !exists $param-&gt;{'user_verify_class'}) 
</span><span class="cx">     {
</span><del>-        $param-&gt;{'user_verify_class'} = $param-&gt;{'loginmethod'};
-        delete $param-&gt;{'loginmethod'};
</del><ins>+        $new_params{'user_verify_class'} = $param-&gt;{'loginmethod'};
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # Remove quip-display control from parameters
</span><span class="lines">@@ -171,8 +170,7 @@
</span><span class="cx">         ($param-&gt;{'enablequips'} eq 'approved') &amp;&amp; do {$new_value = 'moderated';};
</span><span class="cx">         ($param-&gt;{'enablequips'} eq 'frozen')   &amp;&amp; do {$new_value = 'closed';};
</span><span class="cx">         ($param-&gt;{'enablequips'} eq 'off')      &amp;&amp; do {$new_value = 'closed';};
</span><del>-        $param-&gt;{'quip_list_entry_control'} = $new_value;
-        delete $param-&gt;{'enablequips'};
</del><ins>+        $new_params{'quip_list_entry_control'} = $new_value;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # Old mail_delivery_method choices contained no uppercase characters
</span><span class="lines">@@ -188,14 +186,34 @@
</span><span class="cx">         $param-&gt;{'mail_delivery_method'} = $translation{$method};
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    # Convert the old &quot;ssl&quot; parameter to the new &quot;ssl_redirect&quot; parameter.
+    # Both &quot;authenticated sessions&quot; and &quot;always&quot; turn on &quot;ssl_redirect&quot;
+    # when upgrading.
+    if (exists $param-&gt;{'ssl'} and $param-&gt;{'ssl'} ne 'never') {
+        $new_params{'ssl_redirect'} = 1;
+    }
+
+    # &quot;specific_search_allow_empty_words&quot; has been renamed to &quot;search_allow_no_criteria&quot;.
+    if (exists $param-&gt;{'specific_search_allow_empty_words'}) {
+        $new_params{'search_allow_no_criteria'} = $param-&gt;{'specific_search_allow_empty_words'};
+    }
+
</ins><span class="cx">     # --- DEFAULTS FOR NEW PARAMS ---
</span><span class="cx"> 
</span><span class="cx">     _load_params unless %params;
</span><del>-    foreach my $item (@param_list) {
-        my $name = $item-&gt;{'name'};
</del><ins>+    foreach my $name (keys %params) {
+        my $item = $params{$name};
</ins><span class="cx">         unless (exists $param-&gt;{$name}) {
</span><span class="cx">             print &quot;New parameter: $name\n&quot; unless $new_install;
</span><del>-            $param-&gt;{$name} = $answer-&gt;{$name} || $item-&gt;{'default'};
</del><ins>+            if (exists $new_params{$name}) {
+                $param-&gt;{$name} = $new_params{$name};
+            }
+            elsif (exists $answer-&gt;{$name}) {
+                $param-&gt;{$name} = $answer-&gt;{$name};
+            }
+            else {
+                $param-&gt;{$name} = $item-&gt;{'default'};
+            }
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -204,21 +222,23 @@
</span><span class="cx">     # --- REMOVE OLD PARAMS ---
</span><span class="cx"> 
</span><span class="cx">     my %oldparams;
</span><del>-    # Remove any old params, put them in old-params.txt
</del><ins>+    # Remove any old params
</ins><span class="cx">     foreach my $item (keys %$param) {
</span><del>-        if (!grep($_ eq $item, map ($_-&gt;{'name'}, @param_list))) {
-            $oldparams{$item} = $param-&gt;{$item};
-            delete $param-&gt;{$item};
</del><ins>+        if (!exists $params{$item}) {
+            $oldparams{$item} = delete $param-&gt;{$item};
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    # Write any old parameters to old-params.txt
+    my $datadir = bz_locations()-&gt;{'datadir'};
+    my $old_param_file = &quot;$datadir/old-params.txt&quot;;
</ins><span class="cx">     if (scalar(keys %oldparams)) {
</span><del>-        my $op_file = new IO::File('old-params.txt', '&gt;&gt;', 0600)
-          || die &quot;old-params.txt: $!&quot;;
</del><ins>+        my $op_file = new IO::File($old_param_file, '&gt;&gt;', 0600)
+          || die &quot;Couldn't create $old_param_file: $!&quot;;
</ins><span class="cx"> 
</span><span class="cx">         print &quot;The following parameters are no longer used in Bugzilla,&quot;,
</span><span class="cx">               &quot; and so have been\nmoved from your parameters file into&quot;,
</span><del>-              &quot; old-params.txt:\n&quot;;
</del><ins>+              &quot; $old_param_file:\n&quot;;
</ins><span class="cx"> 
</span><span class="cx">         local $Data::Dumper::Terse  = 1;
</span><span class="cx">         local $Data::Dumper::Indent = 0;
</span><span class="lines">@@ -281,29 +301,13 @@
</span><span class="cx">     rename $tmpname, $param_file
</span><span class="cx">       or die &quot;Can't rename $tmpname to $param_file: $!&quot;;
</span><span class="cx"> 
</span><del>-    ChmodDataFile($param_file, 0666);
</del><ins>+    fix_file_permissions($param_file);
</ins><span class="cx"> 
</span><span class="cx">     # And now we have to reset the params cache so that Bugzilla will re-read
</span><span class="cx">     # them.
</span><span class="cx">     delete Bugzilla-&gt;request_cache-&gt;{params};
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-# Some files in the data directory must be world readable if and only if
-# we don't have a webserver group. Call this function to do this.
-# This will become a private function once all the datafile handling stuff
-# moves into this package
-
-# This sub is not perldoc'd for that reason - noone should know about it
-sub ChmodDataFile {
-    my ($file, $mask) = @_;
-    my $perm = 0770;
-    if ((stat(bz_locations()-&gt;{'datadir'}))[2] &amp; 0002) {
-        $perm = 0777;
-    }
-    $perm = $perm &amp; $mask;
-    chmod $perm,$file;
-}
-
</del><span class="cx"> sub read_param_file {
</span><span class="cx">     my %params;
</span><span class="cx">     my $datadir = bz_locations()-&gt;{'datadir'};
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaConstantspm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Constants.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Constants.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Constants.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -35,10 +35,14 @@
</span><span class="cx"> 
</span><span class="cx"> # For bz_locations
</span><span class="cx"> use File::Basename;
</span><ins>+use Memoize;
</ins><span class="cx"> 
</span><span class="cx"> @Bugzilla::Constants::EXPORT = qw(
</span><span class="cx">     BUGZILLA_VERSION
</span><span class="cx"> 
</span><ins>+    REMOTE_FILE
+    LOCAL_FILE
+
</ins><span class="cx">     bz_locations
</span><span class="cx"> 
</span><span class="cx">     IS_NULL
</span><span class="lines">@@ -55,9 +59,9 @@
</span><span class="cx">     AUTH_LOGINFAILED
</span><span class="cx">     AUTH_DISABLED
</span><span class="cx">     AUTH_NO_SUCH_USER
</span><ins>+    AUTH_LOCKOUT
</ins><span class="cx"> 
</span><span class="cx">     USER_PASSWORD_MIN_LENGTH
</span><del>-    USER_PASSWORD_MAX_LENGTH
</del><span class="cx"> 
</span><span class="cx">     LOGIN_OPTIONAL
</span><span class="cx">     LOGIN_NORMAL
</span><span class="lines">@@ -79,9 +83,9 @@
</span><span class="cx"> 
</span><span class="cx">     DEFAULT_COLUMN_LIST
</span><span class="cx">     DEFAULT_QUERY_NAME
</span><ins>+    DEFAULT_MILESTONE
</ins><span class="cx"> 
</span><del>-    QUERY_LIST
-    LIST_OF_BUGS
</del><ins>+    SAVE_NUM_SEARCHES
</ins><span class="cx"> 
</span><span class="cx">     COMMENT_COLS
</span><span class="cx">     COMMENT_COLS_WRAP
</span><span class="lines">@@ -90,27 +94,26 @@
</span><span class="cx">     CMT_NORMAL
</span><span class="cx">     CMT_DUPE_OF
</span><span class="cx">     CMT_HAS_DUPE
</span><del>-    CMT_POPULAR_VOTES
-    CMT_MOVED_TO
</del><ins>+    CMT_ATTACHMENT_CREATED
+    CMT_ATTACHMENT_UPDATED
</ins><span class="cx"> 
</span><span class="cx">     THROW_ERROR
</span><span class="cx">     
</span><span class="cx">     RELATIONSHIPS
</span><del>-    REL_ASSIGNEE REL_QA REL_REPORTER REL_CC REL_VOTER REL_GLOBAL_WATCHER
</del><ins>+    REL_ASSIGNEE REL_QA REL_REPORTER REL_CC REL_GLOBAL_WATCHER
</ins><span class="cx">     REL_ANY
</span><span class="cx">     
</span><span class="cx">     POS_EVENTS
</span><span class="cx">     EVT_OTHER EVT_ADDED_REMOVED EVT_COMMENT EVT_ATTACHMENT EVT_ATTACHMENT_DATA
</span><span class="cx">     EVT_PROJ_MANAGEMENT EVT_OPENED_CLOSED EVT_KEYWORD EVT_CC EVT_DEPEND_BLOCK
</span><del>-    
</del><ins>+    EVT_BUG_CREATED
+
</ins><span class="cx">     NEG_EVENTS
</span><span class="cx">     EVT_UNCONFIRMED EVT_CHANGED_BY_ME 
</span><span class="cx">         
</span><span class="cx">     GLOBAL_EVENTS
</span><span class="cx">     EVT_FLAG_REQUESTED EVT_REQUESTED_FLAG
</span><span class="cx"> 
</span><del>-    FULLTEXT_BUGLIST_LIMIT
-
</del><span class="cx">     ADMIN_GROUP_NAME
</span><span class="cx">     PER_PRODUCT_PRIVILEGES
</span><span class="cx"> 
</span><span class="lines">@@ -123,35 +126,76 @@
</span><span class="cx">     FIELD_TYPE_MULTI_SELECT
</span><span class="cx">     FIELD_TYPE_TEXTAREA
</span><span class="cx">     FIELD_TYPE_DATETIME
</span><ins>+    FIELD_TYPE_BUG_ID
+    FIELD_TYPE_BUG_URLS
+    FIELD_TYPE_KEYWORDS
</ins><span class="cx"> 
</span><ins>+    EMPTY_DATETIME_REGEX
+
+    ABNORMAL_SELECTS
+
+    TIMETRACKING_FIELDS
+
</ins><span class="cx">     USAGE_MODE_BROWSER
</span><span class="cx">     USAGE_MODE_CMDLINE
</span><del>-    USAGE_MODE_WEBSERVICE
</del><ins>+    USAGE_MODE_XMLRPC
</ins><span class="cx">     USAGE_MODE_EMAIL
</span><ins>+    USAGE_MODE_JSON
+    USAGE_MODE_TEST
</ins><span class="cx"> 
</span><span class="cx">     ERROR_MODE_WEBPAGE
</span><span class="cx">     ERROR_MODE_DIE
</span><span class="cx">     ERROR_MODE_DIE_SOAP_FAULT
</span><ins>+    ERROR_MODE_JSON_RPC
+    ERROR_MODE_TEST
</ins><span class="cx"> 
</span><ins>+    COLOR_ERROR
+    COLOR_SUCCESS
+
</ins><span class="cx">     INSTALLATION_MODE_INTERACTIVE
</span><span class="cx">     INSTALLATION_MODE_NON_INTERACTIVE
</span><span class="cx"> 
</span><span class="cx">     DB_MODULE
</span><span class="cx">     ROOT_USER
</span><span class="cx">     ON_WINDOWS
</span><ins>+    ON_ACTIVESTATE
</ins><span class="cx"> 
</span><span class="cx">     MAX_TOKEN_AGE
</span><span class="cx">     MAX_LOGINCOOKIE_AGE
</span><ins>+    MAX_SUDO_TOKEN_AGE
+    MAX_LOGIN_ATTEMPTS
+    LOGIN_LOCKOUT_INTERVAL
+    MAX_STS_AGE
</ins><span class="cx"> 
</span><span class="cx">     SAFE_PROTOCOLS
</span><ins>+    LEGAL_CONTENT_TYPES
</ins><span class="cx"> 
</span><span class="cx">     MIN_SMALLINT
</span><span class="cx">     MAX_SMALLINT
</span><ins>+    MAX_INT_32
</ins><span class="cx"> 
</span><span class="cx">     MAX_LEN_QUERY_NAME
</span><ins>+    MAX_CLASSIFICATION_SIZE
+    MAX_PRODUCT_SIZE
</ins><span class="cx">     MAX_MILESTONE_SIZE
</span><span class="cx">     MAX_COMPONENT_SIZE
</span><ins>+    MAX_FIELD_VALUE_SIZE
</ins><span class="cx">     MAX_FREETEXT_LENGTH
</span><ins>+    MAX_BUG_URL_LENGTH
+    MAX_POSSIBLE_DUPLICATES
+
+    PASSWORD_DIGEST_ALGORITHM
+    PASSWORD_SALT_LENGTH
+    
+    CGI_URI_LIMIT
+
+    PRIVILEGES_REQUIRED_NONE
+    PRIVILEGES_REQUIRED_REPORTER
+    PRIVILEGES_REQUIRED_ASSIGNEE
+    PRIVILEGES_REQUIRED_EMPOWERED
+
+    AUDIT_CREATE
+    AUDIT_REMOVE
</ins><span class="cx"> );
</span><span class="cx"> 
</span><span class="cx"> @Bugzilla::Constants::EXPORT_OK = qw(contenttypes);
</span><span class="lines">@@ -159,8 +203,12 @@
</span><span class="cx"> # CONSTANTS
</span><span class="cx"> #
</span><span class="cx"> # Bugzilla version
</span><del>-use constant BUGZILLA_VERSION =&gt; &quot;3.2.3&quot;;
</del><ins>+use constant BUGZILLA_VERSION =&gt; &quot;4.2.1&quot;;
</ins><span class="cx"> 
</span><ins>+# Location of the remote and local XML files to track new releases.
+use constant REMOTE_FILE =&gt; 'http://updates.bugzilla.org/bugzilla-update.xml';
+use constant LOCAL_FILE  =&gt; 'bugzilla-update.xml'; # Relative to datadir.
+
</ins><span class="cx"> # These are unique values that are unlikely to match a string or a number,
</span><span class="cx"> # to be used in criteria for match() functions and other things. They start
</span><span class="cx"> # and end with spaces because most Bugzilla stuff has trim() called on it,
</span><span class="lines">@@ -212,10 +260,10 @@
</span><span class="cx"> use constant AUTH_LOGINFAILED =&gt; 3;
</span><span class="cx"> use constant AUTH_DISABLED =&gt; 4;
</span><span class="cx"> use constant AUTH_NO_SUCH_USER  =&gt; 5;
</span><ins>+use constant AUTH_LOCKOUT =&gt; 6;
</ins><span class="cx"> 
</span><del>-# The minimum and maximum lengths a password must have.
-use constant USER_PASSWORD_MIN_LENGTH =&gt; 3;
-use constant USER_PASSWORD_MAX_LENGTH =&gt; 16;
</del><ins>+# The minimum length a password must have.
+use constant USER_PASSWORD_MIN_LENGTH =&gt; 6;
</ins><span class="cx"> 
</span><span class="cx"> use constant LOGIN_OPTIONAL =&gt; 0;
</span><span class="cx"> use constant LOGIN_NORMAL =&gt; 1;
</span><span class="lines">@@ -225,18 +273,6 @@
</span><span class="cx"> use constant LOGOUT_CURRENT =&gt; 1;
</span><span class="cx"> use constant LOGOUT_KEEP_CURRENT =&gt; 2;
</span><span class="cx"> 
</span><del>-use constant contenttypes =&gt;
-  {
-   &quot;html&quot;=&gt; &quot;text/html&quot; , 
-   &quot;rdf&quot; =&gt; &quot;application/rdf+xml&quot; , 
-   &quot;atom&quot;=&gt; &quot;application/atom+xml&quot; ,
-   &quot;xml&quot; =&gt; &quot;application/xml&quot; , 
-   &quot;js&quot;  =&gt; &quot;application/x-javascript&quot; , 
-   &quot;csv&quot; =&gt; &quot;text/csv&quot; ,
-   &quot;png&quot; =&gt; &quot;image/png&quot; ,
-   &quot;ics&quot; =&gt; &quot;text/calendar&quot; ,
-  };
-
</del><span class="cx"> use constant GRANT_DIRECT =&gt; 0;
</span><span class="cx"> use constant GRANT_REGEXP =&gt; 2;
</span><span class="cx"> 
</span><span class="lines">@@ -249,20 +285,23 @@
</span><span class="cx"> 
</span><span class="cx"> # The default list of columns for buglist.cgi
</span><span class="cx"> use constant DEFAULT_COLUMN_LIST =&gt; (
</span><del>-    &quot;bug_severity&quot;, &quot;priority&quot;, &quot;op_sys&quot;,&quot;assigned_to&quot;,
-    &quot;bug_status&quot;, &quot;resolution&quot;, &quot;short_desc&quot;
</del><ins>+    &quot;product&quot;, &quot;component&quot;, &quot;assigned_to&quot;,
+    &quot;bug_status&quot;, &quot;resolution&quot;, &quot;short_desc&quot;, &quot;changeddate&quot;
</ins><span class="cx"> );
</span><span class="cx"> 
</span><span class="cx"> # Used by query.cgi and buglist.cgi as the named-query name
</span><span class="cx"> # for the default settings.
</span><span class="cx"> use constant DEFAULT_QUERY_NAME =&gt; '(Default query)';
</span><span class="cx"> 
</span><del>-# The possible types for saved searches.
-use constant QUERY_LIST =&gt; 0;
-use constant LIST_OF_BUGS =&gt; 1;
</del><ins>+# The default &quot;defaultmilestone&quot; created for products.
+use constant DEFAULT_MILESTONE =&gt; '---';
</ins><span class="cx"> 
</span><del>-# The column width (cols attribute) of HTML textareas for inputting comments.
</del><ins>+# How many of the user's most recent searches to save.
+use constant SAVE_NUM_SEARCHES =&gt; 10;
+
+# The column width for comment textareas and comments in bugmails.
</ins><span class="cx"> use constant COMMENT_COLS =&gt; 80;
</span><ins>+#if WEBKIT_CHANGES
</ins><span class="cx"> # The column width at which to wrap comments prior to display -- using
</span><span class="cx"> # Perl's Text::Wrap::wrap().  Only Bugzilla/Util.pm's wrap_comment() method
</span><span class="cx"> # uses this constant.
</span><span class="lines">@@ -273,6 +312,7 @@
</span><span class="cx"> # &quot;white-space: pre-wrap&quot; in the CSS to do line-wrapping instead.  We
</span><span class="cx"> # arbitrarily choose 8000, which is enough for a 100-line paragraph.
</span><span class="cx"> use constant COMMENT_COLS_WRAP =&gt; 8000;
</span><ins>+#endif // WEBKIT_CHANGES
</ins><span class="cx"> # Used in _check_comment(). Gives the max length allowed for a comment.
</span><span class="cx"> use constant MAX_COMMENT_LENGTH =&gt; 65535;
</span><span class="cx"> 
</span><span class="lines">@@ -280,8 +320,10 @@
</span><span class="cx"> use constant CMT_NORMAL =&gt; 0;
</span><span class="cx"> use constant CMT_DUPE_OF =&gt; 1;
</span><span class="cx"> use constant CMT_HAS_DUPE =&gt; 2;
</span><del>-use constant CMT_POPULAR_VOTES =&gt; 3;
-use constant CMT_MOVED_TO =&gt; 4;
</del><ins>+# Type 3 was CMT_POPULAR_VOTES, which moved to the Voting extension.
+# Type 4 was CMT_MOVED_TO, which moved to the OldBugMove extension.
+use constant CMT_ATTACHMENT_CREATED =&gt; 5;
+use constant CMT_ATTACHMENT_UPDATED =&gt; 6;
</ins><span class="cx"> 
</span><span class="cx"> # Determine whether a validation routine should return 0 or throw
</span><span class="cx"> # an error when the validation fails.
</span><span class="lines">@@ -291,11 +333,20 @@
</span><span class="cx"> use constant REL_QA                 =&gt; 1;
</span><span class="cx"> use constant REL_REPORTER           =&gt; 2;
</span><span class="cx"> use constant REL_CC                 =&gt; 3;
</span><del>-use constant REL_VOTER              =&gt; 4;
</del><ins>+# REL 4 was REL_VOTER, before it was moved ino an extension.
</ins><span class="cx"> use constant REL_GLOBAL_WATCHER     =&gt; 5;
</span><span class="cx"> 
</span><del>-use constant RELATIONSHIPS =&gt; REL_ASSIGNEE, REL_QA, REL_REPORTER, REL_CC, 
-                              REL_VOTER, REL_GLOBAL_WATCHER;
</del><ins>+# We need these strings for the X-Bugzilla-Reasons header
+# Note: this hash uses &quot;,&quot; rather than &quot;=&gt;&quot; to avoid auto-quoting of the LHS.
+# This should be accessed through Bugzilla::BugMail::relationships() instead
+# of being accessed directly.
+use constant RELATIONSHIPS =&gt; {
+    REL_ASSIGNEE      , &quot;AssignedTo&quot;,
+    REL_REPORTER      , &quot;Reporter&quot;,
+    REL_QA            , &quot;QAcontact&quot;,
+    REL_CC            , &quot;CC&quot;,
+    REL_GLOBAL_WATCHER, &quot;GlobalWatcher&quot;
+};
</ins><span class="cx">                               
</span><span class="cx"> # Used for global events like EVT_FLAG_REQUESTED
</span><span class="cx"> use constant REL_ANY                =&gt; 100;
</span><span class="lines">@@ -316,11 +367,12 @@
</span><span class="cx"> use constant EVT_KEYWORD            =&gt; 7;
</span><span class="cx"> use constant EVT_CC                 =&gt; 8;
</span><span class="cx"> use constant EVT_DEPEND_BLOCK       =&gt; 9;
</span><ins>+use constant EVT_BUG_CREATED        =&gt; 10;
</ins><span class="cx"> 
</span><span class="cx"> use constant POS_EVENTS =&gt; EVT_OTHER, EVT_ADDED_REMOVED, EVT_COMMENT, 
</span><span class="cx">                            EVT_ATTACHMENT, EVT_ATTACHMENT_DATA, 
</span><span class="cx">                            EVT_PROJ_MANAGEMENT, EVT_OPENED_CLOSED, EVT_KEYWORD,
</span><del>-                           EVT_CC, EVT_DEPEND_BLOCK;
</del><ins>+                           EVT_CC, EVT_DEPEND_BLOCK, EVT_BUG_CREATED;
</ins><span class="cx"> 
</span><span class="cx"> use constant EVT_UNCONFIRMED        =&gt; 50;
</span><span class="cx"> use constant EVT_CHANGED_BY_ME      =&gt; 51;
</span><span class="lines">@@ -334,10 +386,6 @@
</span><span class="cx"> 
</span><span class="cx"> use constant GLOBAL_EVENTS =&gt; EVT_FLAG_REQUESTED, EVT_REQUESTED_FLAG;
</span><span class="cx"> 
</span><del>-#  Number of bugs to return in a buglist when performing
-#  a fulltext search.
-use constant FULLTEXT_BUGLIST_LIMIT =&gt; 200;
-
</del><span class="cx"> # Default administration group name.
</span><span class="cx"> use constant ADMIN_GROUP_NAME =&gt; 'admin';
</span><span class="cx"> 
</span><span class="lines">@@ -362,46 +410,106 @@
</span><span class="cx"> use constant FIELD_TYPE_MULTI_SELECT =&gt; 3;
</span><span class="cx"> use constant FIELD_TYPE_TEXTAREA  =&gt; 4;
</span><span class="cx"> use constant FIELD_TYPE_DATETIME  =&gt; 5;
</span><ins>+use constant FIELD_TYPE_BUG_ID  =&gt; 6;
+use constant FIELD_TYPE_BUG_URLS =&gt; 7;
+use constant FIELD_TYPE_KEYWORDS =&gt; 8;
</ins><span class="cx"> 
</span><ins>+use constant EMPTY_DATETIME_REGEX =&gt; qr/^[0\-:\sA-Za-z]+$/; 
+
+# See the POD for Bugzilla::Field/is_abnormal to see why these are listed
+# here.
+use constant ABNORMAL_SELECTS =&gt; {
+    classification =&gt; 1,
+    component      =&gt; 1,
+    product        =&gt; 1,
+};
+
+# The fields from fielddefs that are blocked from non-timetracking users.
+# work_time is sometimes called actual_time.
+use constant TIMETRACKING_FIELDS =&gt;
+    qw(estimated_time remaining_time work_time actual_time
+       percentage_complete deadline);
+
</ins><span class="cx"> # The maximum number of days a token will remain valid.
</span><span class="cx"> use constant MAX_TOKEN_AGE =&gt; 3;
</span><span class="cx"> # How many days a logincookie will remain valid if not used.
</span><span class="cx"> use constant MAX_LOGINCOOKIE_AGE =&gt; 30;
</span><ins>+# How many seconds (default is 6 hours) a sudo cookie remains valid.
+use constant MAX_SUDO_TOKEN_AGE =&gt; 21600;
</ins><span class="cx"> 
</span><ins>+# Maximum failed logins to lock account for this IP
+use constant MAX_LOGIN_ATTEMPTS =&gt; 5;
+# If the maximum login attempts occur during this many minutes, the
+# account is locked.
+use constant LOGIN_LOCKOUT_INTERVAL =&gt; 30;
+
+# The maximum number of seconds the Strict-Transport-Security header
+# will remain valid. Default is one week.
+use constant MAX_STS_AGE =&gt; 604800;
+
</ins><span class="cx"> # Protocols which are considered as safe.
</span><span class="cx"> use constant SAFE_PROTOCOLS =&gt; ('afs', 'cid', 'ftp', 'gopher', 'http', 'https',
</span><del>-                                'irc', 'mid', 'news', 'nntp', 'prospero', 'telnet',
-                                'view-source', 'wais');
</del><ins>+                                'irc', 'ircs', 'mid', 'news', 'nntp', 'prospero',
+                                'telnet', 'view-source', 'wais');
</ins><span class="cx"> 
</span><ins>+# Valid MIME types for attachments.
+use constant LEGAL_CONTENT_TYPES =&gt; ('application', 'audio', 'image', 'message',
+                                     'model', 'multipart', 'text', 'video');
+
+use constant contenttypes =&gt;
+  {
+   &quot;html&quot;=&gt; &quot;text/html&quot; ,
+   &quot;rdf&quot; =&gt; &quot;application/rdf+xml&quot; ,
+   &quot;atom&quot;=&gt; &quot;application/atom+xml&quot; ,
+   &quot;xml&quot; =&gt; &quot;application/xml&quot; ,
+   &quot;js&quot;  =&gt; &quot;application/x-javascript&quot; ,
+   &quot;json&quot;=&gt; &quot;application/json&quot; ,
+   &quot;csv&quot; =&gt; &quot;text/csv&quot; ,
+   &quot;png&quot; =&gt; &quot;image/png&quot; ,
+   &quot;ics&quot; =&gt; &quot;text/calendar&quot; ,
+  };
+
</ins><span class="cx"> # Usage modes. Default USAGE_MODE_BROWSER. Use with Bugzilla-&gt;usage_mode.
</span><span class="cx"> use constant USAGE_MODE_BROWSER    =&gt; 0;
</span><span class="cx"> use constant USAGE_MODE_CMDLINE    =&gt; 1;
</span><del>-use constant USAGE_MODE_WEBSERVICE =&gt; 2;
</del><ins>+use constant USAGE_MODE_XMLRPC     =&gt; 2;
</ins><span class="cx"> use constant USAGE_MODE_EMAIL      =&gt; 3;
</span><ins>+use constant USAGE_MODE_JSON       =&gt; 4;
+use constant USAGE_MODE_TEST       =&gt; 5;
</ins><span class="cx"> 
</span><span class="cx"> # Error modes. Default set by Bugzilla-&gt;usage_mode (so ERROR_MODE_WEBPAGE
</span><span class="cx"> # usually). Use with Bugzilla-&gt;error_mode.
</span><span class="cx"> use constant ERROR_MODE_WEBPAGE        =&gt; 0;
</span><span class="cx"> use constant ERROR_MODE_DIE            =&gt; 1;
</span><span class="cx"> use constant ERROR_MODE_DIE_SOAP_FAULT =&gt; 2;
</span><ins>+use constant ERROR_MODE_JSON_RPC       =&gt; 3;
+use constant ERROR_MODE_TEST           =&gt; 4;
</ins><span class="cx"> 
</span><ins>+# The ANSI colors of messages that command-line scripts use
+use constant COLOR_ERROR =&gt; 'red';
+use constant COLOR_SUCCESS =&gt; 'green';
+
</ins><span class="cx"> # The various modes that checksetup.pl can run in.
</span><span class="cx"> use constant INSTALLATION_MODE_INTERACTIVE =&gt; 0;
</span><span class="cx"> use constant INSTALLATION_MODE_NON_INTERACTIVE =&gt; 1;
</span><span class="cx"> 
</span><span class="cx"> # Data about what we require for different databases.
</span><span class="cx"> use constant DB_MODULE =&gt; {
</span><del>-    'mysql' =&gt; {db =&gt; 'Bugzilla::DB::Mysql', db_version =&gt; '4.1.2',
</del><ins>+    # MySQL 5.0.15 was the first production 5.0.x release.
+    'mysql' =&gt; {db =&gt; 'Bugzilla::DB::Mysql', db_version =&gt; '5.0.15',
</ins><span class="cx">                 dbd =&gt; { 
</span><span class="cx">                     package =&gt; 'DBD-mysql',
</span><span class="cx">                     module  =&gt; 'DBD::mysql',
</span><span class="cx">                     # Disallow development versions
</span><span class="cx">                     blacklist =&gt; ['_'],
</span><del>-                    # For UTF-8 support
-                    version =&gt; '4.00',
</del><ins>+                    # For UTF-8 support. 4.001 makes sure that blobs aren't
+                    # marked as UTF-8.
+                    version =&gt; '4.001',
</ins><span class="cx">                 },
</span><span class="cx">                 name =&gt; 'MySQL'},
</span><del>-    'pg'    =&gt; {db =&gt; 'Bugzilla::DB::Pg', db_version =&gt; '8.00.0000',
</del><ins>+    # Also see Bugzilla::DB::Pg::bz_check_server_version, which has special
+    # code to require DBD::Pg 2.17.2 for PostgreSQL 9 and above.
+    'pg'    =&gt; {db =&gt; 'Bugzilla::DB::Pg', db_version =&gt; '8.03.0000',
</ins><span class="cx">                 dbd =&gt; {
</span><span class="cx">                     package =&gt; 'DBD-Pg',
</span><span class="cx">                     module  =&gt; 'DBD::Pg',
</span><span class="lines">@@ -415,30 +523,86 @@
</span><span class="cx">                      version =&gt; '1.19',
</span><span class="cx">                 },
</span><span class="cx">                 name =&gt; 'Oracle'},
</span><ins>+     # SQLite 3.6.22 fixes a WHERE clause problem that may affect us.
+    sqlite =&gt; {db =&gt; 'Bugzilla::DB::Sqlite', db_version =&gt; '3.6.22',
+               dbd =&gt; {
+                   package =&gt; 'DBD-SQLite',
+                   module  =&gt; 'DBD::SQLite',
+                   # 1.29 is the version that contains 3.6.22.
+                   version =&gt; '1.29',
+               },
+               name =&gt; 'SQLite'},
</ins><span class="cx"> };
</span><span class="cx"> 
</span><ins>+# True if we're on Win32.
+use constant ON_WINDOWS =&gt; ($^O =~ /MSWin32/i) ? 1 : 0;
+# True if we're using ActiveState Perl (as opposed to Strawberry) on Windows.
+use constant ON_ACTIVESTATE =&gt; eval { &amp;Win32::BuildNumber };
+
</ins><span class="cx"> # The user who should be considered &quot;root&quot; when we're giving
</span><span class="cx"> # instructions to Bugzilla administrators.
</span><del>-use constant ROOT_USER =&gt; $^O =~ /MSWin32/i ? 'Administrator' : 'root';
</del><ins>+use constant ROOT_USER =&gt; ON_WINDOWS ? 'Administrator' : 'root';
</ins><span class="cx"> 
</span><del>-# True if we're on Win32.
-use constant ON_WINDOWS =&gt; ($^O =~ /MSWin32/i);
-
</del><span class="cx"> use constant MIN_SMALLINT =&gt; -32768;
</span><span class="cx"> use constant MAX_SMALLINT =&gt; 32767;
</span><ins>+use constant MAX_INT_32 =&gt; 2147483647;
</ins><span class="cx"> 
</span><span class="cx"> # The longest that a saved search name can be.
</span><span class="cx"> use constant MAX_LEN_QUERY_NAME =&gt; 64;
</span><span class="cx"> 
</span><ins>+# The longest classification name allowed.
+use constant MAX_CLASSIFICATION_SIZE =&gt; 64;
+
+# The longest product name allowed.
+use constant MAX_PRODUCT_SIZE =&gt; 64;
+
</ins><span class="cx"> # The longest milestone name allowed.
</span><span class="cx"> use constant MAX_MILESTONE_SIZE =&gt; 20;
</span><span class="cx"> 
</span><span class="cx"> # The longest component name allowed.
</span><span class="cx"> use constant MAX_COMPONENT_SIZE =&gt; 64;
</span><span class="cx"> 
</span><ins>+# The maximum length for values of &lt;select&gt; fields.
+use constant MAX_FIELD_VALUE_SIZE =&gt; 64;
+
</ins><span class="cx"> # Maximum length allowed for free text fields.
</span><span class="cx"> use constant MAX_FREETEXT_LENGTH =&gt; 255;
</span><span class="cx"> 
</span><ins>+# The longest a bug URL in a BUG_URLS field can be.
+use constant MAX_BUG_URL_LENGTH =&gt; 255;
+
+# The largest number of possible duplicates that Bug::possible_duplicates
+# will return.
+use constant MAX_POSSIBLE_DUPLICATES =&gt; 25;
+
+# This is the name of the algorithm used to hash passwords before storing
+# them in the database. This can be any string that is valid to pass to
+# Perl's &quot;Digest&quot; module. Note that if you change this, it won't take
+# effect until a user changes his password.
+use constant PASSWORD_DIGEST_ALGORITHM =&gt; 'SHA-256';
+# How long of a salt should we use? Note that if you change this, none
+# of your users will be able to log in until they reset their passwords.
+use constant PASSWORD_SALT_LENGTH =&gt; 8;
+
+# Certain scripts redirect to GET even if the form was submitted originally
+# via POST such as buglist.cgi. This value determines whether the redirect
+# can be safely done or not based on the web server's URI length setting.
+use constant CGI_URI_LIMIT =&gt; 8000;
+
+# If the user isn't allowed to change a field, we must tell him who can.
+# We store the required permission set into the $PrivilegesRequired
+# variable which gets passed to the error template.
+
+use constant PRIVILEGES_REQUIRED_NONE      =&gt; 0;
+use constant PRIVILEGES_REQUIRED_REPORTER  =&gt; 1;
+use constant PRIVILEGES_REQUIRED_ASSIGNEE  =&gt; 2;
+use constant PRIVILEGES_REQUIRED_EMPOWERED =&gt; 3;
+
+# Special field values used in the audit_log table to mean either
+# &quot;we just created this object&quot; or &quot;we just deleted this object&quot;.
+use constant AUDIT_CREATE =&gt; '__create__';
+use constant AUDIT_REMOVE =&gt; '__remove__';
+
</ins><span class="cx"> sub bz_locations {
</span><span class="cx">     # We know that Bugzilla/Constants.pm must be in %INC at this point.
</span><span class="cx">     # So the only question is, what's the name of the directory
</span><span class="lines">@@ -466,6 +630,7 @@
</span><span class="cx">         $datadir = &quot;data&quot;;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    $datadir = &quot;$libpath/$datadir&quot;;
</ins><span class="cx">     # We have to return absolute paths for mod_perl. 
</span><span class="cx">     # That means that if you modify these paths, they must be absolute paths.
</span><span class="cx">     return {
</span><span class="lines">@@ -475,20 +640,26 @@
</span><span class="cx">         # make sure this still points to the CGIs.
</span><span class="cx">         'cgi_path'    =&gt; $libpath,
</span><span class="cx">         'templatedir' =&gt; &quot;$libpath/template&quot;,
</span><ins>+        'template_cache' =&gt; &quot;$datadir/template&quot;,
</ins><span class="cx">         'project'     =&gt; $project,
</span><span class="cx">         'localconfig' =&gt; &quot;$libpath/$localconfig&quot;,
</span><del>-        'datadir'     =&gt; &quot;$libpath/$datadir&quot;,
-        'attachdir'   =&gt; &quot;$libpath/$datadir/attachments&quot;,
</del><ins>+        'datadir'     =&gt; $datadir,
+        'attachdir'   =&gt; &quot;$datadir/attachments&quot;,
</ins><span class="cx">         'skinsdir'    =&gt; &quot;$libpath/skins&quot;,
</span><ins>+        'graphsdir'   =&gt; &quot;$libpath/graphs&quot;,
</ins><span class="cx">         # $webdotdir must be in the web server's tree somewhere. Even if you use a 
</span><span class="cx">         # local dot, we output images to there. Also, if $webdotdir is 
</span><span class="cx">         # not relative to the bugzilla root directory, you'll need to 
</span><span class="cx">         # change showdependencygraph.cgi to set image_url to the correct 
</span><span class="cx">         # location.
</span><span class="cx">         # The script should really generate these graphs directly...
</span><del>-        'webdotdir'   =&gt; &quot;$libpath/$datadir/webdot&quot;,
</del><ins>+        'webdotdir'   =&gt; &quot;$datadir/webdot&quot;,
</ins><span class="cx">         'extensionsdir' =&gt; &quot;$libpath/extensions&quot;,
</span><span class="cx">     };
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# This makes us not re-compute all the bz_locations data every time it's
+# called.
+BEGIN { memoize('bz_locations') };
+
</ins><span class="cx"> 1;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaDBMysqlpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/DB/Mysql.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/DB/Mysql.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/DB/Mysql.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -40,8 +40,8 @@
</span><span class="cx"> =cut
</span><span class="cx"> 
</span><span class="cx"> package Bugzilla::DB::Mysql;
</span><del>-
</del><span class="cx"> use strict;
</span><ins>+use base qw(Bugzilla::DB);
</ins><span class="cx"> 
</span><span class="cx"> use Bugzilla::Constants;
</span><span class="cx"> use Bugzilla::Install::Util qw(install_string);
</span><span class="lines">@@ -50,26 +50,33 @@
</span><span class="cx"> use Bugzilla::DB::Schema::Mysql;
</span><span class="cx"> 
</span><span class="cx"> use List::Util qw(max);
</span><ins>+use Text::ParseWords;
</ins><span class="cx"> 
</span><span class="cx"> # This is how many comments of MAX_COMMENT_LENGTH we expect on a single bug.
</span><span class="cx"> # In reality, you could have a LOT more comments than this, because 
</span><span class="cx"> # MAX_COMMENT_LENGTH is big.
</span><span class="cx"> use constant MAX_COMMENTS =&gt; 50;
</span><span class="cx"> 
</span><del>-# This module extends the DB interface via inheritance
-use base qw(Bugzilla::DB);
</del><ins>+use constant FULLTEXT_OR =&gt; '|';
</ins><span class="cx"> 
</span><span class="cx"> sub new {
</span><del>-    my ($class, $user, $pass, $host, $dbname, $port, $sock) = @_;
</del><ins>+    my ($class, $params) = @_;
+    my ($user, $pass, $host, $dbname, $port, $sock) =
+        @$params{qw(db_user db_pass db_host db_name db_port db_sock)};
</ins><span class="cx"> 
</span><span class="cx">     # construct the DSN from the parameters we got
</span><del>-    my $dsn = &quot;DBI:mysql:host=$host;database=$dbname&quot;;
</del><ins>+    my $dsn = &quot;dbi:mysql:host=$host;database=$dbname&quot;;
</ins><span class="cx">     $dsn .= &quot;;port=$port&quot; if $port;
</span><span class="cx">     $dsn .= &quot;;mysql_socket=$sock&quot; if $sock;
</span><span class="cx"> 
</span><del>-    my $attrs = { mysql_enable_utf8 =&gt; Bugzilla-&gt;params-&gt;{'utf8'} };
</del><ins>+    my %attrs = (
+        mysql_enable_utf8 =&gt; Bugzilla-&gt;params-&gt;{'utf8'},
+        # Needs to be explicitly specified for command-line processes.
+        mysql_auto_reconnect =&gt; 1,
+    );
</ins><span class="cx">     
</span><del>-    my $self = $class-&gt;db_new($dsn, $user, $pass, $attrs);
</del><ins>+    my $self = $class-&gt;db_new({ dsn =&gt; $dsn, user =&gt; $user, 
+                                pass =&gt; $pass, attrs =&gt; \%attrs });
</ins><span class="cx"> 
</span><span class="cx">     # This makes sure that if the tables are encoded as UTF-8, we
</span><span class="cx">     # return their data correctly.
</span><span class="lines">@@ -79,6 +86,9 @@
</span><span class="cx">     # a prefix 'private_'. See DBI documentation.
</span><span class="cx">     $self-&gt;{private_bz_tables_locked} = &quot;&quot;;
</span><span class="cx"> 
</span><ins>+    # Needed by TheSchwartz
+    $self-&gt;{private_bz_dsn} = $dsn;
+
</ins><span class="cx">     bless ($self, $class);
</span><span class="cx">     
</span><span class="cx">     # Bug 321645 - disable MySQL strict mode, if set
</span><span class="lines">@@ -116,23 +126,32 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub sql_group_concat {
</span><del>-    my ($self, $column, $separator) = @_;
-    my $sep_sql;
-    if ($separator) {
-        $sep_sql = &quot; SEPARATOR $separator&quot;;
</del><ins>+    my ($self, $column, $separator, $sort) = @_;
+    $separator = $self-&gt;quote(', ') if !defined $separator;
+    $sort = 1 if !defined $sort;
+    if ($sort) {
+        my $sort_order = $column;
+        $sort_order =~ s/^DISTINCT\s+//i;
+        $column = &quot;$column ORDER BY $sort_order&quot;;
</ins><span class="cx">     }
</span><del>-    return &quot;GROUP_CONCAT($column$sep_sql)&quot;;
</del><ins>+    return &quot;GROUP_CONCAT($column SEPARATOR $separator)&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub sql_regexp {
</span><del>-    my ($self, $expr, $pattern) = @_;
</del><ins>+    my ($self, $expr, $pattern, $nocheck, $real_pattern) = @_;
+    $real_pattern ||= $pattern;
</ins><span class="cx"> 
</span><ins>+    $self-&gt;bz_check_regexp($real_pattern) if !$nocheck;
+
</ins><span class="cx">     return &quot;$expr REGEXP $pattern&quot;;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub sql_not_regexp {
</span><del>-    my ($self, $expr, $pattern) = @_;
</del><ins>+    my ($self, $expr, $pattern, $nocheck, $real_pattern) = @_;
+    $real_pattern ||= $pattern;
</ins><span class="cx"> 
</span><ins>+    $self-&gt;bz_check_regexp($real_pattern) if !$nocheck;
+
</ins><span class="cx">     return &quot;$expr NOT REGEXP $pattern&quot;;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -156,9 +175,22 @@
</span><span class="cx">     my ($self, $column, $text) = @_;
</span><span class="cx"> 
</span><span class="cx">     # Add the boolean mode modifier if the search string contains
</span><del>-    # boolean operators.
-    my $mode = ($text =~ /[+\-&lt;&gt;()~*&quot;]/ ? &quot;IN BOOLEAN MODE&quot; : &quot;&quot;);
</del><ins>+    # boolean operators at the start or end of a word.
+    my $mode = '';
+    if ($text =~ /(?:^|\W)[+\-&lt;&gt;~&quot;()]/ || $text =~ /[()&quot;*](?:$|\W)/) {
+        $mode = 'IN BOOLEAN MODE';
</ins><span class="cx"> 
</span><ins>+        # quote un-quoted compound words
+        my @words = quotewords('[\s()]+', 'delimiters', $text);
+        foreach my $word (@words) {
+            # match words that have non-word chars in the middle of them
+            if ($word =~ /\w\W+\w/ &amp;&amp; $word !~ m/&quot;/) {
+                $word = '&quot;' . $word . '&quot;';
+            }
+        }
+        $text = join('', @words);
+    }
+
</ins><span class="cx">     # quote the text for use in the MATCH AGAINST expression
</span><span class="cx">     $text = $self-&gt;quote($text);
</span><span class="cx"> 
</span><span class="lines">@@ -194,10 +226,10 @@
</span><span class="cx">     return &quot;DATE_FORMAT($date, &quot; . $self-&gt;quote($format) . &quot;)&quot;;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub sql_interval {
-    my ($self, $interval, $units) = @_;
</del><ins>+sub sql_date_math {
+    my ($self, $date, $operator, $interval, $units) = @_;
</ins><span class="cx">     
</span><del>-    return &quot;INTERVAL $interval $units&quot;;
</del><ins>+    return &quot;$date $operator INTERVAL $interval $units&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub sql_iposition {
</span><span class="lines">@@ -221,7 +253,31 @@
</span><span class="cx">     return &quot;GROUP BY $needed_columns&quot;;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub bz_explain {
+    my ($self, $sql) = @_;
+    my $sth  = $self-&gt;prepare(&quot;EXPLAIN $sql&quot;);
+    $sth-&gt;execute();
+    my $columns = $sth-&gt;{'NAME'};
+    my $lengths = $sth-&gt;{'mysql_max_length'};
+    my $format_string = '|';
+    my $i = 0;
+    foreach my $column (@$columns) {
+        # Sometimes the column name is longer than the contents.
+        my $length = max($lengths-&gt;[$i], length($column));
+        $format_string .= ' %-' . $length . 's |';
+        $i++;
+    }
</ins><span class="cx"> 
</span><ins>+    my $first_row = sprintf($format_string, @$columns);
+    my @explain_rows = ($first_row, '-' x length($first_row));
+    while (my $row = $sth-&gt;fetchrow_arrayref) {
+        my @fixed = map { defined $_ ? $_ : 'NULL' } @$row;
+        push(@explain_rows, sprintf($format_string, @fixed));
+    }
+
+    return join(&quot;\n&quot;, @explain_rows);
+}
+
</ins><span class="cx"> sub _bz_get_initial_schema {
</span><span class="cx">     my ($self) = @_;
</span><span class="cx">     return $self-&gt;_bz_build_schema_from_disk();
</span><span class="lines">@@ -231,6 +287,18 @@
</span><span class="cx"> # Database Setup
</span><span class="cx"> #####################################################################
</span><span class="cx"> 
</span><ins>+sub bz_check_server_version {
+    my $self = shift;
+
+    my $lc = Bugzilla-&gt;localconfig;
+    if (lc(Bugzilla-&gt;localconfig-&gt;{db_name}) eq 'mysql') {
+        die &quot;It is not safe to run Bugzilla inside a database named 'mysql'.\n&quot;
+            . &quot; Please pick a different value for \$db_name in localconfig.\n&quot;;
+    }
+
+    $self-&gt;SUPER::bz_check_server_version(@_);
+}
+
</ins><span class="cx"> sub bz_setup_database {
</span><span class="cx">     my ($self) = @_;
</span><span class="cx"> 
</span><span class="lines">@@ -260,47 +328,18 @@
</span><span class="cx">     my ($innodb_on) = @{$self-&gt;selectcol_arrayref(
</span><span class="cx">         q{SHOW VARIABLES LIKE '%have_innodb%'}, {Columns=&gt;[2]})};
</span><span class="cx">     if ($innodb_on ne 'YES') {
</span><del>-        print &lt;&lt;EOT;
-InnoDB is disabled in your MySQL installation. 
-Bugzilla requires InnoDB to be enabled. 
-Please enable it and then re-run checksetup.pl.
-
-EOT
-        exit 3;
</del><ins>+        die install_string('mysql_innodb_disabled');
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-    # Figure out if any existing tables are of type ISAM and convert them
-    # to type MyISAM if so.  ISAM tables are deprecated in MySQL 3.23,
-    # which Bugzilla now requires, and they don't support more than 16
-    # indexes per table, which Bugzilla needs.
-    my $table_status = $self-&gt;selectall_arrayref(&quot;SHOW TABLE STATUS&quot;);
-    my @isam_tables;
-    foreach my $row (@$table_status) {
-        my ($name, $type) = @$row;
-        push(@isam_tables, $name) if $type eq &quot;ISAM&quot;;
-    }
-
-    if(scalar(@isam_tables)) {
-        print &quot;One or more of the tables in your existing MySQL database are\n&quot;
-              . &quot;of type ISAM. ISAM tables are deprecated in MySQL 3.23 and\n&quot;
-              . &quot;don't support more than 16 indexes per table, which \n&quot;
-              . &quot;Bugzilla needs.\n  Converting your ISAM tables to type&quot;
-              . &quot; MyISAM:\n\n&quot;;
-        foreach my $table (@isam_tables) {
-            print &quot;Converting table $table... &quot;;
-            $self-&gt;do(&quot;ALTER TABLE $table TYPE = MYISAM&quot;);
-            print &quot;done.\n&quot;;
-        }
-        print &quot;\nISAM-&gt;MyISAM table conversion done.\n\n&quot;;
-    }
-
</del><span class="cx">     my ($sd_index_deleted, $longdescs_index_deleted);
</span><span class="cx">     my @tables = $self-&gt;bz_table_list_real();
</span><span class="cx">     # We want to convert tables to InnoDB, but it's possible that they have 
</span><span class="cx">     # fulltext indexes on them, and conversion will fail unless we remove
</span><span class="cx">     # the indexes.
</span><del>-    if (grep($_ eq 'bugs', @tables)) {
</del><ins>+    if (grep($_ eq 'bugs', @tables)
+        and !grep($_ eq 'bugs_fulltext', @tables))
+    {
</ins><span class="cx">         if ($self-&gt;bz_index_info_real('bugs', 'short_desc')) {
</span><span class="cx">             $self-&gt;bz_drop_index_raw('bugs', 'short_desc');
</span><span class="cx">         }
</span><span class="lines">@@ -309,7 +348,9 @@
</span><span class="cx">             $sd_index_deleted = 1; # Used for later schema cleanup.
</span><span class="cx">         }
</span><span class="cx">     }
</span><del>-    if (grep($_ eq 'longdescs', @tables)) {
</del><ins>+    if (grep($_ eq 'longdescs', @tables)
+        and !grep($_ eq 'bugs_fulltext', @tables))
+    {
</ins><span class="cx">         if ($self-&gt;bz_index_info_real('longdescs', 'thetext')) {
</span><span class="cx">             $self-&gt;bz_drop_index_raw('longdescs', 'thetext');
</span><span class="cx">         }
</span><span class="lines">@@ -320,27 +361,25 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # Upgrade tables from MyISAM to InnoDB
</span><del>-    my @myisam_tables;
-    foreach my $row (@$table_status) {
-        my ($name, $type) = @$row;
-        if ($type =~ /^MYISAM$/i 
-            &amp;&amp; !grep($_ eq $name, Bugzilla::DB::Schema::Mysql::MYISAM_TABLES))
-        {
-            push(@myisam_tables, $name) ;
-        }
</del><ins>+    my $db_name = Bugzilla-&gt;localconfig-&gt;{db_name};
+    my $myisam_tables = $self-&gt;selectcol_arrayref(
+        'SELECT TABLE_NAME FROM information_schema.TABLES 
+          WHERE TABLE_SCHEMA = ? AND ENGINE = ?',
+        undef, $db_name, 'MyISAM');
+    foreach my $should_be_myisam (Bugzilla::DB::Schema::Mysql::MYISAM_TABLES) {
+        @$myisam_tables = grep { $_ ne $should_be_myisam } @$myisam_tables;
</ins><span class="cx">     }
</span><del>-    if (scalar @myisam_tables) {
</del><ins>+
+    if (scalar @$myisam_tables) {
</ins><span class="cx">         print &quot;Bugzilla now uses the InnoDB storage engine in MySQL for&quot;,
</span><span class="cx">               &quot; most tables.\nConverting tables to InnoDB:\n&quot;;
</span><del>-        foreach my $table (@myisam_tables) {
</del><ins>+        foreach my $table (@$myisam_tables) {
</ins><span class="cx">             print &quot;Converting table $table... &quot;;
</span><del>-            $self-&gt;do(&quot;ALTER TABLE $table TYPE = InnoDB&quot;);
</del><ins>+            $self-&gt;do(&quot;ALTER TABLE $table ENGINE = InnoDB&quot;);
</ins><span class="cx">             print &quot;done.\n&quot;;
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     
</span><del>-    $self-&gt;_after_table_status(\@tables);
-    
</del><span class="cx">     # Versions of Bugzilla before the existence of Bugzilla::DB::Schema did 
</span><span class="cx">     # not provide explicit names for the table indexes. This means
</span><span class="cx">     # that our upgrades will not be reliable, because we look for the name
</span><span class="lines">@@ -368,17 +407,7 @@
</span><span class="cx">         # We just do the check here since this check is a reliable way
</span><span class="cx">         # of telling that we are upgrading from a version pre-2.20.
</span><span class="cx">         if (grep($_ eq 'bz_schema', $self-&gt;bz_table_list_real())) {
</span><del>-            die(&quot;\nYou are upgrading from a version before 2.20, but the&quot;
-              . &quot; bz_schema\ntable already exists. This means that you&quot;
-              . &quot; restored a mysqldump into\nthe Bugzilla database without&quot;
-              . &quot; first dropping the already-existing\nBugzilla database,&quot;
-              . &quot; at some point. Whenever you restore a Bugzilla\ndatabase&quot;
-              . &quot; backup, you must always drop the entire database first.\n\n&quot;
-              . &quot;Please drop your Bugzilla database and restore it from a&quot;
-              . &quot; backup that\ndoes not contain the bz_schema table. If for&quot;
-              . &quot; some reason you cannot\ndo this, you can connect to your&quot;
-              . &quot; MySQL database and drop the bz_schema\ntable, as a last&quot;
-              . &quot; resort.\n&quot;);
</del><ins>+            die install_string('bz_schema_exists_before_220');
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         my $bug_count = $self-&gt;selectrow_array(&quot;SELECT COUNT(*) FROM bugs&quot;);
</span><span class="lines">@@ -392,12 +421,8 @@
</span><span class="cx">         # If we're going to take longer than 5 minutes, we let the user know
</span><span class="cx">         # and allow them to abort.
</span><span class="cx">         if ($rename_time &gt; 5) {
</span><del>-            print &quot;\nWe are about to rename old indexes.\n&quot;
-                  . &quot;The estimated time to complete renaming is &quot;
-                  . &quot;$rename_time minutes.\n&quot;
-                  . &quot;You cannot interrupt this action once it has begun.\n&quot;
-                  . &quot;If you would like to cancel, press Ctrl-C now...&quot;
-                  . &quot; (Waiting 45 seconds...)\n\n&quot;;
</del><ins>+            print &quot;\n&quot;, install_string('mysql_index_renaming',
+                                       { minutes =&gt; $rename_time });
</ins><span class="cx">             # Wait 45 seconds for them to respond.
</span><span class="cx">             sleep(45) unless Bugzilla-&gt;installation_answers-&gt;{NO_PAUSE};
</span><span class="cx">         }
</span><span class="lines">@@ -611,8 +636,11 @@
</span><span class="cx"> 
</span><span class="cx">     # 2005-09-24 - bugreport@peshkin.net, bug 307602
</span><span class="cx">     # Make sure that default 4G table limit is overridden
</span><del>-    my $row = $self-&gt;selectrow_hashref(&quot;SHOW TABLE STATUS LIKE 'attach_data'&quot;);
-    if ($$row{'Create_options'} !~ /MAX_ROWS/i) {
</del><ins>+    my $attach_data_create = $self-&gt;selectrow_array(
+        'SELECT CREATE_OPTIONS FROM information_schema.TABLES 
+          WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?',
+        undef, $db_name, 'attach_data');
+    if ($attach_data_create !~ /MAX_ROWS/i) {
</ins><span class="cx">         print &quot;Converting attach_data maximum size to 100G...\n&quot;;
</span><span class="cx">         $self-&gt;do(&quot;ALTER TABLE attach_data
</span><span class="cx">                    AVG_ROW_LENGTH=1000000,
</span><span class="lines">@@ -624,42 +652,25 @@
</span><span class="cx">     # partial-conversion situations can happen, and this handles anything
</span><span class="cx">     # that could come up (including having the DB charset be utf8 but not
</span><span class="cx">     # the table charsets.
</span><del>-    my $utf_table_status =
-        $self-&gt;selectall_arrayref(&quot;SHOW TABLE STATUS&quot;, {Slice=&gt;{}});
-    $self-&gt;_after_table_status([map($_-&gt;{Name}, @$utf_table_status)]);
-    my @non_utf8_tables = grep($_-&gt;{Collation} !~ /^utf8/, @$utf_table_status);
</del><ins>+    #
+    # TABLE_COLLATION IS NOT NULL prevents us from trying to convert views.
+    my $non_utf8_tables = $self-&gt;selectrow_array(
+        &quot;SELECT 1 FROM information_schema.TABLES 
+          WHERE TABLE_SCHEMA = ? AND TABLE_COLLATION IS NOT NULL 
+                AND TABLE_COLLATION NOT LIKE 'utf8%' 
+          LIMIT 1&quot;, undef, $db_name);
</ins><span class="cx">     
</span><del>-    if (Bugzilla-&gt;params-&gt;{'utf8'} &amp;&amp; scalar @non_utf8_tables) {
-        print &lt;&lt;EOT;
</del><ins>+    if (Bugzilla-&gt;params-&gt;{'utf8'} &amp;&amp; $non_utf8_tables) {
+        print &quot;\n&quot;, install_string('mysql_utf8_conversion');
</ins><span class="cx"> 
</span><del>-WARNING: We are about to convert your table storage format to UTF8. This
-         allows Bugzilla to correctly store and sort international characters.
-         However, if you have any non-UTF-8 data in your database,
-         it ***WILL BE DELETED*** by this process. So, before
-         you continue with checksetup.pl, if you have any non-UTF-8
-         data (or even if you're not sure) you should press Ctrl-C now
-         to interrupt checksetup.pl, and run contrib/recode.pl to make all 
-         the data in your database into UTF-8. You should also back up your
-         database before continuing. This will affect every single table
-         in the database, even non-Bugzilla tables.
-
-         If you ever used a version of Bugzilla before 2.22, we STRONGLY
-         recommend that you stop checksetup.pl NOW and run contrib/recode.pl.
-
-EOT
-
</del><span class="cx">         if (!Bugzilla-&gt;installation_answers-&gt;{NO_PAUSE}) {
</span><span class="cx">             if (Bugzilla-&gt;installation_mode == 
</span><span class="cx">                 INSTALLATION_MODE_NON_INTERACTIVE) 
</span><span class="cx">             {
</span><del>-                print &lt;&lt;EOT;
-         Re-run checksetup.pl in interactive mode (without an 'answers' file)
-         to continue.
-EOT
-                exit;
</del><ins>+                die install_string('continue_without_answers'), &quot;\n&quot;;
</ins><span class="cx">             }
</span><span class="cx">             else {
</span><del>-                print &quot;         Press Enter to continue or Ctrl-C to exit...&quot;;
</del><ins>+                print &quot;\n         &quot; . install_string('enter_or_ctrl_c');
</ins><span class="cx">                 getc;
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="lines">@@ -669,6 +680,7 @@
</span><span class="cx">         foreach my $table ($self-&gt;bz_table_list_real) {
</span><span class="cx">             my $info_sth = $self-&gt;prepare(&quot;SHOW FULL COLUMNS FROM $table&quot;);
</span><span class="cx">             $info_sth-&gt;execute();
</span><ins>+            my (@binary_sql, @utf8_sql);
</ins><span class="cx">             while (my $column = $info_sth-&gt;fetchrow_hashref) {
</span><span class="cx">                 # Our conversion code doesn't work on enum fields, but they
</span><span class="cx">                 # all go away later in checksetup anyway.
</span><span class="lines">@@ -681,31 +693,16 @@
</span><span class="cx">                 {
</span><span class="cx">                     my $name = $column-&gt;{Field};
</span><span class="cx"> 
</span><del>-                    # The code below doesn't work on a field with a FULLTEXT
-                    # index. So we drop it, which we'd do later anyway.
-                    if ($table eq 'longdescs' &amp;&amp; $name eq 'thetext') {
-                        $self-&gt;bz_drop_index('longdescs', 
-                                             'longdescs_thetext_idx');
-                    }
-                    if ($table eq 'bugs' &amp;&amp; $name eq 'short_desc') {
-                        $self-&gt;bz_drop_index('bugs', 'bugs_short_desc_idx');
-                    }
-                    my %ft_indexes;
-                    if ($table eq 'bugs_fulltext') {
-                        %ft_indexes = $self-&gt;_bz_real_schema-&gt;get_indexes_on_column_abstract(
-                            'bugs_fulltext', $name);
-                        foreach my $index (keys %ft_indexes) {
-                            $self-&gt;bz_drop_index('bugs_fulltext', $index);
-                        }
-                    }
</del><ins>+                    print &quot;$table.$name needs to be converted to UTF-8...\n&quot;;
</ins><span class="cx"> 
</span><del>-                    print &quot;Converting $table.$name to be stored as UTF-8...\n&quot;;
-                    my $col_info = 
</del><ins>+                    # These will be automatically re-created at the end
+                    # of checksetup.
+                    $self-&gt;bz_drop_related_fks($table, $name);
+
+                    my $col_info =
</ins><span class="cx">                         $self-&gt;bz_column_info_real($table, $name);
</span><del>-
</del><span class="cx">                     # CHANGE COLUMN doesn't take PRIMARY KEY
</span><span class="cx">                     delete $col_info-&gt;{PRIMARYKEY};
</span><del>-
</del><span class="cx">                     my $sql_def = $self-&gt;_bz_schema-&gt;get_type_ddl($col_info);
</span><span class="cx">                     # We don't want MySQL to actually try to *convert*
</span><span class="cx">                     # from our current charset to UTF-8, we just want to
</span><span class="lines">@@ -717,21 +714,39 @@
</span><span class="cx">                     my $type = $self-&gt;_bz_schema-&gt;convert_type($col_info-&gt;{TYPE});
</span><span class="cx">                     $binary =~ s/(\Q$type\E)/$1 CHARACTER SET binary/;
</span><span class="cx">                     $utf8   =~ s/(\Q$type\E)/$1 CHARACTER SET utf8/;
</span><del>-                    $self-&gt;do(&quot;ALTER TABLE $table CHANGE COLUMN $name $name 
-                              $binary&quot;);
-                    $self-&gt;do(&quot;ALTER TABLE $table CHANGE COLUMN $name $name 
-                              $utf8&quot;);
</del><ins>+                    push(@binary_sql, &quot;MODIFY COLUMN $name $binary&quot;);
+                    push(@utf8_sql, &quot;MODIFY COLUMN $name $utf8&quot;);
+                }
+            } # foreach column
</ins><span class="cx"> 
</span><del>-                    if ($table eq 'bugs_fulltext') {
-                        foreach my $index (keys %ft_indexes) {
-                            $self-&gt;bz_add_index('bugs_fulltext', $index,
-                                                $ft_indexes{$index});
-                        }
</del><ins>+            if (@binary_sql) {
+                my %indexes = %{ $self-&gt;bz_table_indexes($table) };
+                foreach my $index_name (keys %indexes) {
+                    my $index = $indexes{$index_name};
+                    if ($index-&gt;{TYPE} and $index-&gt;{TYPE} eq 'FULLTEXT') {
+                        $self-&gt;bz_drop_index($table, $index_name);
</ins><span class="cx">                     }
</span><ins>+                    else {
+                        delete $indexes{$index_name};
+                    }
</ins><span class="cx">                 }
</span><ins>+
+                print &quot;Converting the $table table to UTF-8...\n&quot;;
+                my $bin = &quot;ALTER TABLE $table &quot; . join(', ', @binary_sql);
+                my $utf = &quot;ALTER TABLE $table &quot; . join(', ', @utf8_sql,
+                          'DEFAULT CHARACTER SET utf8');
+                $self-&gt;do($bin);
+                $self-&gt;do($utf);
+
+                # Re-add any removed FULLTEXT indexes.
+                foreach my $index (keys %indexes) {
+                    $self-&gt;bz_add_index($table, $index, $indexes{$index});
+                }
</ins><span class="cx">             }
</span><ins>+            else {
+                $self-&gt;do(&quot;ALTER TABLE $table DEFAULT CHARACTER SET utf8&quot;);
+            }
</ins><span class="cx"> 
</span><del>-            $self-&gt;do(&quot;ALTER TABLE $table DEFAULT CHARACTER SET utf8&quot;);
</del><span class="cx">         } # foreach my $table (@tables)
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -743,18 +758,79 @@
</span><span class="cx">     if (Bugzilla-&gt;params-&gt;{'utf8'} &amp;&amp; !$self-&gt;bz_db_is_utf8) {
</span><span class="cx">         $self-&gt;_alter_db_charset_to_utf8();
</span><span class="cx">     }
</span><ins>+
+     $self-&gt;_fix_defaults();
+
+    # Bug 451735 highlighted a bug in bz_drop_index() which didn't
+    # check for FKs before trying to delete an index. Consequently,
+    # the series_creator_idx index was considered to be deleted
+    # despite it was still present in the DB. That's why we have to
+    # force the deletion, bypassing the DB schema.
+    if (!$self-&gt;bz_index_info('series', 'series_category_idx')) {
+        if (!$self-&gt;bz_index_info('series', 'series_creator_idx')
+            &amp;&amp; $self-&gt;bz_index_info_real('series', 'series_creator_idx'))
+        {
+            foreach my $column (qw(creator category subcategory name)) {
+                $self-&gt;bz_drop_related_fks('series', $column);
+            }
+            $self-&gt;bz_drop_index_raw('series', 'series_creator_idx');
+        }
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-# There is a bug in MySQL 4.1.0 - 4.1.15 that makes certain SELECT
-# statements fail after a SHOW TABLE STATUS: 
-# http://bugs.mysql.com/bug.php?id=13535
-# This is a workaround, a dummy SELECT to reset the LAST_INSERT_ID.
-sub _after_table_status {
-    my ($self, $tables) = @_;
-    if (grep($_ eq 'bugs', @$tables)
-        &amp;&amp; $self-&gt;bz_column_info_real(&quot;bugs&quot;, &quot;bug_id&quot;))
-    {
-        $self-&gt;do('SELECT 1 FROM bugs WHERE bug_id IS NULL');
</del><ins>+# When you import a MySQL 3/4 mysqldump into MySQL 5, columns that
+# aren't supposed to have defaults will have defaults. This is only
+# a minor issue, but it makes our tests fail, and it's good to keep
+# the DB actually consistent with what DB::Schema thinks the database
+# looks like. So we remove defaults from columns that aren't supposed
+# to have them
+sub _fix_defaults {
+    my $self = shift;
+    my $maj_version = substr($self-&gt;bz_server_version, 0, 1);
+    return if $maj_version &lt; 5;
+
+    # The oldest column that could have this problem is bugs.assigned_to,
+    # so if it doesn't have the problem, we just skip doing this entirely.
+    my $assi_def = $self-&gt;_bz_raw_column_info('bugs', 'assigned_to');
+    my $assi_default = $assi_def-&gt;{COLUMN_DEF};
+    # This &quot;ne ''&quot; thing is necessary because _raw_column_info seems to
+    # return COLUMN_DEF as an empty string for columns that don't have
+    # a default.
+    return unless (defined $assi_default &amp;&amp; $assi_default ne '');
+
+    my %fix_columns;
+    foreach my $table ($self-&gt;_bz_real_schema-&gt;get_table_list()) {
+        foreach my $column ($self-&gt;bz_table_columns($table)) {
+            my $abs_def = $self-&gt;bz_column_info($table, $column);
+            # BLOB/TEXT columns never have defaults
+            next if $abs_def-&gt;{TYPE} =~ /BLOB|TEXT/i;
+            if (!defined $abs_def-&gt;{DEFAULT}) {
+                # Get the exact default from the database without any
+                # &quot;fixing&quot; by bz_column_info_real.
+                my $raw_info = $self-&gt;_bz_raw_column_info($table, $column);
+                my $raw_default = $raw_info-&gt;{COLUMN_DEF};
+                if (defined $raw_default) {
+                    if ($raw_default eq '') {
+                        # Only (var)char columns can have empty strings as 
+                        # defaults, so if we got an empty string for some
+                        # other default type, then it's bogus.
+                        next unless $abs_def-&gt;{TYPE} =~ /char/i;
+                        $raw_default = &quot;''&quot;;
+                    }
+                    $fix_columns{$table} ||= [];
+                    push(@{ $fix_columns{$table} }, $column);
+                    print &quot;$table.$column has incorrect DB default: $raw_default\n&quot;;
+                }
+            }
+        } # foreach $column
+    } # foreach $table
+
+    print &quot;Fixing defaults...\n&quot;;
+    foreach my $table (reverse sort keys %fix_columns) {
+        my @alters = map(&quot;ALTER COLUMN $_ DROP DEFAULT&quot;, 
+                         @{ $fix_columns{$table} });
+        my $sql = &quot;ALTER TABLE $table &quot; . join(',', @alters);
+        $self-&gt;do($sql);
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -834,7 +910,13 @@
</span><span class="cx"> 
</span><span class="cx"> sub bz_column_info_real {
</span><span class="cx">     my ($self, $table, $column) = @_;
</span><ins>+    my $col_data = $self-&gt;_bz_raw_column_info($table, $column);
+    return $self-&gt;_bz_schema-&gt;column_info_to_column($col_data);
+}
</ins><span class="cx"> 
</span><ins>+sub _bz_raw_column_info {
+    my ($self, $table, $column) = @_;
+
</ins><span class="cx">     # DBD::mysql does not support selecting a specific column,
</span><span class="cx">     # so we have to get all the columns on the table and find 
</span><span class="cx">     # the one we want.
</span><span class="lines">@@ -849,7 +931,7 @@
</span><span class="cx">     if (!defined $col_data) {
</span><span class="cx">         return undef;
</span><span class="cx">     }
</span><del>-    return $self-&gt;_bz_schema-&gt;column_info_to_column($col_data);
</del><ins>+    return $col_data;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> =item C&lt;bz_index_info_real($table, $index)&gt;
</span><span class="lines">@@ -938,11 +1020,12 @@
</span><span class="cx"> sub _bz_build_schema_from_disk {
</span><span class="cx">     my ($self) = @_;
</span><span class="cx"> 
</span><del>-    print &quot;Building Schema object from database...\n&quot;;
-
</del><span class="cx">     my $schema = $self-&gt;_bz_schema-&gt;get_empty_schema();
</span><span class="cx"> 
</span><span class="cx">     my @tables = $self-&gt;bz_table_list_real();
</span><ins>+    if (@tables) {
+        print &quot;Building Schema object from database...\n&quot;; 
+    }
</ins><span class="cx">     foreach my $table (@tables) {
</span><span class="cx">         $schema-&gt;add_table($table);
</span><span class="cx">         my @columns = $self-&gt;bz_table_columns_real($table);
</span><span class="lines">@@ -964,4 +1047,5 @@
</span><span class="cx"> 
</span><span class="cx">     return $schema;
</span><span class="cx"> }
</span><ins>+
</ins><span class="cx"> 1;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaDBOraclepm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/DB/Oracle.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/DB/Oracle.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/DB/Oracle.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -35,16 +35,16 @@
</span><span class="cx"> =cut
</span><span class="cx"> 
</span><span class="cx"> package Bugzilla::DB::Oracle;
</span><del>-
</del><span class="cx"> use strict;
</span><ins>+use base qw(Bugzilla::DB);
</ins><span class="cx"> 
</span><span class="cx"> use DBD::Oracle;
</span><span class="cx"> use DBD::Oracle qw(:ora_types);
</span><ins>+use List::Util qw(max);
+
</ins><span class="cx"> use Bugzilla::Constants;
</span><span class="cx"> use Bugzilla::Error;
</span><span class="cx"> use Bugzilla::Util;
</span><del>-# This module extends the DB interface via inheritance
-use base qw(Bugzilla::DB);
</del><span class="cx"> 
</span><span class="cx"> #####################################################################
</span><span class="cx"> # Constants
</span><span class="lines">@@ -52,10 +52,14 @@
</span><span class="cx"> use constant EMPTY_STRING  =&gt; '__BZ_EMPTY_STR__';
</span><span class="cx"> use constant ISOLATION_LEVEL =&gt; 'READ COMMITTED';
</span><span class="cx"> use constant BLOB_TYPE =&gt; { ora_type =&gt; ORA_BLOB };
</span><del>-use constant GROUPBY_REGEXP =&gt; '((CASE\s+WHEN.+END)|(TO_CHAR\(.+\))|(\(SCORE.+\))|(\(MATCH.+\))|(\w+(\.\w+)?))(\s+AS\s+)?(.*)?$';
</del><ins>+# The max size allowed for LOB fields, in kilobytes.
+use constant MIN_LONG_READ_LEN =&gt; 32 * 1024;
+use constant FULLTEXT_OR =&gt; ' OR ';
</ins><span class="cx"> 
</span><span class="cx"> sub new {
</span><del>-    my ($class, $user, $pass, $host, $dbname, $port) = @_;
</del><ins>+    my ($class, $params) = @_;
+    my ($user, $pass, $host, $dbname, $port) = 
+        @$params{qw(db_user db_pass db_host db_name db_port)};
</ins><span class="cx"> 
</span><span class="cx">     # You can never connect to Oracle without a DB name,
</span><span class="cx">     # and there is no default DB.
</span><span class="lines">@@ -65,13 +69,16 @@
</span><span class="cx">     $ENV{'NLS_LANG'} = '.AL32UTF8' if Bugzilla-&gt;params-&gt;{'utf8'};
</span><span class="cx"> 
</span><span class="cx">     # construct the DSN from the parameters we got
</span><del>-    my $dsn = &quot;DBI:Oracle:host=$host;sid=$dbname&quot;;
</del><ins>+    my $dsn = &quot;dbi:Oracle:host=$host;sid=$dbname&quot;;
</ins><span class="cx">     $dsn .= &quot;;port=$port&quot; if $port;
</span><span class="cx">     my $attrs = { FetchHashKeyName =&gt; 'NAME_lc',  
</span><del>-                  LongReadLen =&gt; ( Bugzilla-&gt;params-&gt;{'maxattachmentsize'}
-                                     || 1000 ) * 1024, 
</del><ins>+                  LongReadLen =&gt; max(Bugzilla-&gt;params-&gt;{'maxattachmentsize'},
+                                     MIN_LONG_READ_LEN) * 1024,
</ins><span class="cx">                 };
</span><del>-    my $self = $class-&gt;db_new($dsn, $user, $pass, $attrs);
</del><ins>+    my $self = $class-&gt;db_new({ dsn =&gt; $dsn, user =&gt; $user, 
+                                pass =&gt; $pass, attrs =&gt; $attrs });
+    # Needed by TheSchwartz
+    $self-&gt;{private_bz_dsn} = $dsn;
</ins><span class="cx"> 
</span><span class="cx">     bless ($self, $class);
</span><span class="cx"> 
</span><span class="lines">@@ -95,15 +102,46 @@
</span><span class="cx">     return $last_insert_id;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub bz_check_regexp {
+    my ($self, $pattern) = @_;
+
+    eval { $self-&gt;do(&quot;SELECT 1 FROM DUAL WHERE &quot;
+          . $self-&gt;sql_regexp($self-&gt;quote(&quot;a&quot;), $pattern, 1)) };
+
+    $@ &amp;&amp; ThrowUserError('illegal_regexp',
+        { value =&gt; $pattern, dberror =&gt; $self-&gt;errstr });
+}
+
+sub bz_explain { 
+     my ($self, $sql) = @_; 
+     my $sth = $self-&gt;prepare(&quot;EXPLAIN PLAN FOR $sql&quot;); 
+     $sth-&gt;execute();
+     my $explain = $self-&gt;selectcol_arrayref(
+         &quot;SELECT PLAN_TABLE_OUTPUT FROM TABLE(DBMS_XPLAN.DISPLAY)&quot;);
+     return join(&quot;\n&quot;, @$explain); 
+} 
+
+sub sql_group_concat {
+    my ($self, $text, $separator) = @_;
+    $separator = $self-&gt;quote(', ') if !defined $separator;
+    return &quot;group_concat(T_CLOB_DELIM($text, $separator))&quot;;
+}
+
</ins><span class="cx"> sub sql_regexp {
</span><del>-    my ($self, $expr, $pattern) = @_;
</del><ins>+    my ($self, $expr, $pattern, $nocheck, $real_pattern) = @_;
+    $real_pattern ||= $pattern;
</ins><span class="cx"> 
</span><ins>+    $self-&gt;bz_check_regexp($real_pattern) if !$nocheck;
+
</ins><span class="cx">     return &quot;REGEXP_LIKE($expr, $pattern)&quot;;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub sql_not_regexp {
</span><del>-    my ($self, $expr, $pattern) = @_;
</del><ins>+    my ($self, $expr, $pattern, $nocheck, $real_pattern) = @_;
+    $real_pattern ||= $pattern;
</ins><span class="cx"> 
</span><ins>+    $self-&gt;bz_check_regexp($real_pattern) if !$nocheck;
+
</ins><span class="cx">     return &quot;NOT REGEXP_LIKE($expr, $pattern)&quot; 
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -136,7 +174,7 @@
</span><span class="cx">     my ($self, $column, $text, $label) = @_;
</span><span class="cx">     $text = $self-&gt;quote($text);
</span><span class="cx">     trick_taint($text);
</span><del>-    return &quot;CONTAINS($column,$text,$label)&quot;, &quot;SCORE($label)&quot;;
</del><ins>+    return &quot;CONTAINS($column,$text,$label) &gt; 0&quot;, &quot;SCORE($label)&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub sql_date_format {
</span><span class="lines">@@ -156,13 +194,15 @@
</span><span class="cx">     return &quot;TO_CHAR($date, &quot; . $self-&gt;quote($format) . &quot;)&quot;;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub sql_interval {
-    my ($self, $interval, $units) = @_;
</del><ins>+sub sql_date_math {
+    my ($self, $date, $operator, $interval, $units) = @_;
+    my $time_sql;
</ins><span class="cx">     if ($units =~ /YEAR|MONTH/i) {
</span><del>-        return &quot;NUMTOYMINTERVAL($interval,'$units')&quot;;
</del><ins>+        $time_sql = &quot;NUMTOYMINTERVAL($interval,'$units')&quot;;
</ins><span class="cx">     } else{
</span><del>-        return &quot;NUMTODSINTERVAL($interval,'$units')&quot;;
</del><ins>+        $time_sql = &quot;NUMTODSINTERVAL($interval,'$units')&quot;;
</ins><span class="cx">     }
</span><ins>+   return &quot;$date $operator $time_sql&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub sql_position {
</span><span class="lines">@@ -185,6 +225,15 @@
</span><span class="cx">     return &quot;( &quot; . join(&quot; OR &quot;, @in_str) . &quot; )&quot;;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub _bz_add_field_table {
+    my ($self, $name, $schema_ref, $type) = @_;
+    $self-&gt;SUPER::_bz_add_field_table($name, $schema_ref);
+    if (defined($type) &amp;&amp; $type == FIELD_TYPE_MULTI_SELECT) {
+        my $uk_name = &quot;UK_&quot; . $self-&gt;_bz_schema-&gt;_hash_identifier($name . '_value');
+        $self-&gt;do(&quot;ALTER TABLE $name ADD CONSTRAINT $uk_name UNIQUE(value)&quot;);
+    }
+}
+
</ins><span class="cx"> sub bz_drop_table {
</span><span class="cx">      my ($self, $name) = @_;
</span><span class="cx">      my $table_exists = $self-&gt;bz_table_info($name);
</span><span class="lines">@@ -197,7 +246,7 @@
</span><span class="cx"> # Dropping all FKs for a specified table. 
</span><span class="cx"> sub _bz_drop_fks {
</span><span class="cx">     my ($self, $table) = @_;
</span><del>-    my @columns = $self-&gt;_bz_real_schema-&gt;get_table_columns($table);
</del><ins>+    my @columns = $self-&gt;bz_table_columns($table);
</ins><span class="cx">     foreach my $column (@columns) {
</span><span class="cx">         $self-&gt;bz_drop_fk($table, $column);
</span><span class="cx">     }
</span><span class="lines">@@ -229,6 +278,10 @@
</span><span class="cx"> 
</span><span class="cx"> sub adjust_statement {
</span><span class="cx">     my ($sql) = @_;
</span><ins>+    
+    if ($sql =~ /^CREATE OR REPLACE.*/i){
+        return $sql;
+    } 
</ins><span class="cx"> 
</span><span class="cx">     # We can't just assume any occurrence of &quot;''&quot; in $sql is an empty
</span><span class="cx">     # string, since &quot;''&quot; can occur inside a string literal as a way of
</span><span class="lines">@@ -295,6 +348,10 @@
</span><span class="cx">         
</span><span class="cx">         # Oracle need no 'AS'
</span><span class="cx">         $nonstring =~ s/\bAS\b//ig;
</span><ins>+        
+        # Take the first 4000 chars for comparison  
+        $nonstring =~ s/\(\s*(longdescs_\d+\.thetext|attachdata_\d+\.thedata)/
+                      \(DBMS_LOB.SUBSTR\($1, 4000, 1\)/ig;
</ins><span class="cx"> 
</span><span class="cx">         # Look for a LIMIT clause
</span><span class="cx">         ($limit) = ($nonstring =~ m(/\* LIMIT (\d*) \*/)o);
</span><span class="lines">@@ -319,20 +376,17 @@
</span><span class="cx">         if ($new_sql !~ /\bWHERE\b/) {
</span><span class="cx">             $new_sql = $new_sql.&quot; WHERE 1=1&quot;;
</span><span class="cx">         }
</span><del>-         my ($before_where, $after_where) = split /\bWHERE\b/i,$new_sql;
-         if (defined($offset)) {
-             if ($new_sql =~ /(.*\s+)FROM(\s+.*)/i) { 
-                 my ($before_from,$after_from) = ($1,$2);
-                 $before_where = &quot;$before_from FROM ($before_from,&quot;
-                             . &quot; ROW_NUMBER() OVER (ORDER BY 1) R &quot;
-                             . &quot; FROM $after_from ) &quot;; 
-                 $after_where = &quot; R BETWEEN $offset+1 AND $limit+$offset&quot;;
-             }
-         } else {
-                 $after_where = &quot; rownum &lt;=$limit AND &quot;.$after_where;
-         }
-
-         $new_sql = $before_where.&quot; WHERE &quot;.$after_where;
</del><ins>+        my ($before_where, $after_where) = split(/\bWHERE\b/i, $new_sql, 2);
+        if (defined($offset)) {
+            my ($before_from, $after_from) = split(/\bFROM\b/i, $new_sql, 2);
+            $before_where = &quot;$before_from FROM ($before_from,&quot;
+                          . &quot; ROW_NUMBER() OVER (ORDER BY 1) R &quot;
+                          . &quot; FROM $after_from ) &quot;; 
+            $after_where = &quot; R BETWEEN $offset+1 AND $limit+$offset&quot;;
+        } else {
+            $after_where = &quot; rownum &lt;=$limit AND &quot;.$after_where;
+        }
+        $new_sql = $before_where.&quot; WHERE &quot;.$after_where;
</ins><span class="cx">     }
</span><span class="cx">     return $new_sql;
</span><span class="cx"> }
</span><span class="lines">@@ -487,6 +541,88 @@
</span><span class="cx">               . &quot; RETURN DATE IS BEGIN RETURN SYSDATE; END;&quot;);
</span><span class="cx">     $self-&gt;do(&quot;CREATE OR REPLACE FUNCTION CHAR_LENGTH(COLUMN_NAME VARCHAR2)&quot; 
</span><span class="cx">               . &quot; RETURN NUMBER IS BEGIN RETURN LENGTH(COLUMN_NAME); END;&quot;);
</span><ins>+    
+    # Create types for group_concat
+    my $t_clob_delim = $self-&gt;selectcol_arrayref(&quot;
+        SELECT TYPE_NAME FROM USER_TYPES WHERE TYPE_NAME=?&quot;,
+        undef, 'T_CLOB_DELIM'); 
+
+    if ( !@$t_clob_delim ) {
+        $self-&gt;do(&quot;CREATE OR REPLACE TYPE T_CLOB_DELIM AS OBJECT &quot;
+              . &quot;( p_CONTENT CLOB, p_DELIMITER VARCHAR2(256));&quot;);
+    }
+
+    $self-&gt;do(&quot;CREATE OR REPLACE TYPE T_GROUP_CONCAT AS OBJECT 
+               (  CLOB_CONTENT CLOB,
+                  DELIMITER    VARCHAR2(256),
+                  STATIC FUNCTION ODCIAGGREGATEINITIALIZE(
+                      SCTX IN OUT NOCOPY T_GROUP_CONCAT)
+                  RETURN NUMBER,
+                  MEMBER FUNCTION ODCIAGGREGATEITERATE(
+                      SELF IN OUT NOCOPY T_GROUP_CONCAT,
+                      VALUE IN T_CLOB_DELIM) 
+                  RETURN NUMBER,
+                  MEMBER FUNCTION ODCIAGGREGATETERMINATE(
+                      SELF IN T_GROUP_CONCAT,
+                      RETURNVALUE OUT NOCOPY CLOB,
+                      FLAGS       IN NUMBER)
+                  RETURN NUMBER,
+                  MEMBER FUNCTION ODCIAGGREGATEMERGE(
+                      SELF IN OUT NOCOPY T_GROUP_CONCAT,
+                      CTX2 IN T_GROUP_CONCAT) 
+                  RETURN NUMBER);&quot;);
+
+    $self-&gt;do(&quot;CREATE OR REPLACE TYPE BODY T_GROUP_CONCAT IS
+                  STATIC FUNCTION ODCIAGGREGATEINITIALIZE(
+                  SCTX IN OUT NOCOPY T_GROUP_CONCAT)
+                  RETURN NUMBER IS
+                  BEGIN
+                      SCTX := T_GROUP_CONCAT(EMPTY_CLOB(), NULL);
+                      DBMS_LOB.CREATETEMPORARY(SCTX.CLOB_CONTENT, TRUE);
+                      RETURN ODCICONST.SUCCESS;
+                  END;
+                  MEMBER FUNCTION ODCIAGGREGATEITERATE(
+                      SELF IN OUT NOCOPY T_GROUP_CONCAT,
+                      VALUE IN T_CLOB_DELIM) 
+                  RETURN NUMBER IS
+                  BEGIN
+                      SELF.DELIMITER := VALUE.P_DELIMITER;
+                      DBMS_LOB.WRITEAPPEND(SELF.CLOB_CONTENT, 
+                                           LENGTH(SELF.DELIMITER),
+                                           SELF.DELIMITER);
+                      DBMS_LOB.APPEND(SELF.CLOB_CONTENT, VALUE.P_CONTENT);
+  
+                      RETURN ODCICONST.SUCCESS;
+                  END;
+                  MEMBER FUNCTION ODCIAGGREGATETERMINATE(
+                      SELF IN T_GROUP_CONCAT,
+                      RETURNVALUE OUT NOCOPY CLOB,
+                      FLAGS IN NUMBER) 
+                  RETURN NUMBER IS
+                  BEGIN
+                      RETURNVALUE := RTRIM(LTRIM(SELF.CLOB_CONTENT, 
+                                     SELF.DELIMITER), 
+                                     SELF.DELIMITER);
+                      RETURN ODCICONST.SUCCESS;
+                  END;
+                  MEMBER FUNCTION ODCIAGGREGATEMERGE(
+                      SELF IN OUT NOCOPY T_GROUP_CONCAT,
+                      CTX2 IN T_GROUP_CONCAT) 
+                  RETURN NUMBER IS
+                  BEGIN
+                      DBMS_LOB.WRITEAPPEND(SELF.CLOB_CONTENT, 
+                                           LENGTH(SELF.DELIMITER), 
+                                           SELF.DELIMITER);
+                      DBMS_LOB.APPEND(SELF.CLOB_CONTENT, CTX2.CLOB_CONTENT);
+                      RETURN ODCICONST.SUCCESS;
+                  END;
+               END;&quot;);
+
+    # Create user-defined aggregate function group_concat
+    $self-&gt;do(&quot;CREATE OR REPLACE FUNCTION GROUP_CONCAT(P_INPUT T_CLOB_DELIM) 
+               RETURN CLOB 
+               DETERMINISTIC PARALLEL_ENABLE AGGREGATE USING T_GROUP_CONCAT;&quot;);
+
</ins><span class="cx">     # Create a WORLD_LEXER named BZ_LEX for multilingual fulltext search
</span><span class="cx">     my $lexer = $self-&gt;selectcol_arrayref(
</span><span class="cx">        &quot;SELECT pre_name FROM CTXSYS.CTX_PREFERENCES WHERE pre_name = ? AND
</span><span class="lines">@@ -512,6 +648,10 @@
</span><span class="cx">                 my $fk_name = $self-&gt;_bz_schema-&gt;_get_fk_name($table,
</span><span class="cx">                                                               $column,
</span><span class="cx">                                                               $references);
</span><ins>+                # bz_rename_table didn't rename the trigger correctly.
+                if ($table eq 'bug_tag' &amp;&amp; $to_table eq 'tags') {
+                    $to_table = 'tag';
+                }
</ins><span class="cx">                 if ( $update =~ /CASCADE/i ){
</span><span class="cx">                      my $trigger_name = uc($fk_name . &quot;_UC&quot;);
</span><span class="cx">                      my $exist_trigger = $self-&gt;selectcol_arrayref(
</span><span class="lines">@@ -522,7 +662,7 @@
</span><span class="cx">                     }
</span><span class="cx">   
</span><span class="cx">                      my $tr_str = &quot;CREATE OR REPLACE TRIGGER $trigger_name&quot;
</span><del>-                         . &quot; AFTER  UPDATE  ON &quot;. $to_table
</del><ins>+                         . &quot; AFTER UPDATE OF $to_column ON $to_table &quot;
</ins><span class="cx">                          . &quot; REFERENCING &quot;
</span><span class="cx">                          . &quot; NEW AS NEW &quot;
</span><span class="cx">                          . &quot; OLD AS OLD &quot;
</span><span class="lines">@@ -538,6 +678,14 @@
</span><span class="cx">      }
</span><span class="cx">    }
</span><span class="cx"> 
</span><ins>+   # Drop the trigger which causes bug 541553
+   my $trigger_name = &quot;PRODUCTS_MILESTONEURL&quot;;
+   my $exist_trigger = $self-&gt;selectcol_arrayref(
+       &quot;SELECT OBJECT_NAME FROM USER_OBJECTS
+        WHERE OBJECT_NAME = ?&quot;, undef, $trigger_name);
+   if(@$exist_trigger) {
+       $self-&gt;do(&quot;DROP TRIGGER $trigger_name&quot;);
+   }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> package Bugzilla::DB::Oracle::st;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaDBPgpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/DB/Pg.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/DB/Pg.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/DB/Pg.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -52,7 +52,9 @@
</span><span class="cx"> use constant BLOB_TYPE =&gt; { pg_type =&gt; DBD::Pg::PG_BYTEA };
</span><span class="cx"> 
</span><span class="cx"> sub new {
</span><del>-    my ($class, $user, $pass, $host, $dbname, $port) = @_;
</del><ins>+    my ($class, $params) = @_;
+    my ($user, $pass, $host, $dbname, $port) = 
+        @$params{qw(db_user db_pass db_host db_name db_port)};
</ins><span class="cx"> 
</span><span class="cx">     # The default database name for PostgreSQL. We have
</span><span class="cx">     # to connect to SOME database, even if we have
</span><span class="lines">@@ -60,7 +62,7 @@
</span><span class="cx">     $dbname ||= 'template1';
</span><span class="cx"> 
</span><span class="cx">     # construct the DSN from the parameters we got
</span><del>-    my $dsn = &quot;DBI:Pg:dbname=$dbname&quot;;
</del><ins>+    my $dsn = &quot;dbi:Pg:dbname=$dbname&quot;;
</ins><span class="cx">     $dsn .= &quot;;host=$host&quot; if $host;
</span><span class="cx">     $dsn .= &quot;;port=$port&quot; if $port;
</span><span class="cx"> 
</span><span class="lines">@@ -70,11 +72,14 @@
</span><span class="cx"> 
</span><span class="cx">     my $attrs = { pg_enable_utf8 =&gt; Bugzilla-&gt;params-&gt;{'utf8'} };
</span><span class="cx"> 
</span><del>-    my $self = $class-&gt;db_new($dsn, $user, $pass, $attrs);
</del><ins>+    my $self = $class-&gt;db_new({ dsn =&gt; $dsn, user =&gt; $user, 
+                                pass =&gt; $pass, attrs =&gt; $attrs });
</ins><span class="cx"> 
</span><span class="cx">     # all class local variables stored in DBI derived class needs to have
</span><span class="cx">     # a prefix 'private_'. See DBI documentation.
</span><span class="cx">     $self-&gt;{private_bz_tables_locked} = &quot;&quot;;
</span><ins>+    # Needed by TheSchwartz
+    $self-&gt;{private_bz_dsn} = $dsn;
</ins><span class="cx"> 
</span><span class="cx">     bless ($self, $class);
</span><span class="cx"> 
</span><span class="lines">@@ -92,16 +97,45 @@
</span><span class="cx">     return $last_insert_id;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub sql_group_concat {
+    my ($self, $text, $separator, $sort) = @_;
+    $sort = 1 if !defined $sort;
+    $separator = $self-&gt;quote(', ') if !defined $separator;
+    my $sql = &quot;array_accum($text)&quot;;
+    if ($sort) {
+        $sql = &quot;array_sort($sql)&quot;;
+    }
+    return &quot;array_to_string($sql, $separator)&quot;;
+}
+
+sub sql_istring {
+    my ($self, $string) = @_;
+
+    return &quot;LOWER(${string}::text)&quot;;
+}
+
+sub sql_position {
+    my ($self, $fragment, $text) = @_;
+
+    return &quot;POSITION(${fragment}::text IN ${text}::text)&quot;;
+}
+
</ins><span class="cx"> sub sql_regexp {
</span><del>-    my ($self, $expr, $pattern) = @_;
</del><ins>+    my ($self, $expr, $pattern, $nocheck, $real_pattern) = @_;
+    $real_pattern ||= $pattern;
</ins><span class="cx"> 
</span><del>-    return &quot;$expr ~* $pattern&quot;;
</del><ins>+    $self-&gt;bz_check_regexp($real_pattern) if !$nocheck;
+
+    return &quot;${expr}::text ~* $pattern&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub sql_not_regexp {
</span><del>-    my ($self, $expr, $pattern) = @_;
</del><ins>+    my ($self, $expr, $pattern, $nocheck, $real_pattern) = @_;
+    $real_pattern ||= $pattern;
</ins><span class="cx"> 
</span><del>-    return &quot;$expr !~* $pattern&quot; 
</del><ins>+    $self-&gt;bz_check_regexp($real_pattern) if !$nocheck;
+
+    return &quot;${expr}::text !~* $pattern&quot; 
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub sql_limit {
</span><span class="lines">@@ -117,7 +151,7 @@
</span><span class="cx"> sub sql_from_days {
</span><span class="cx">     my ($self, $days) = @_;
</span><span class="cx"> 
</span><del>-    return &quot;TO_TIMESTAMP(${days}::int, 'J')::date&quot;;
</del><ins>+    return &quot;TO_TIMESTAMP('$days', 'J')::date&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub sql_to_days {
</span><span class="lines">@@ -143,10 +177,10 @@
</span><span class="cx">     return &quot;TO_CHAR($date, &quot; . $self-&gt;quote($format) . &quot;)&quot;;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub sql_interval {
-    my ($self, $interval, $units) = @_;
</del><ins>+sub sql_date_math {
+    my ($self, $date, $operator, $interval, $units) = @_;
</ins><span class="cx">     
</span><del>-    return &quot;$interval * INTERVAL '1 $units'&quot;;
</del><ins>+    return &quot;$date $operator $interval * INTERVAL '1 $units'&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub sql_string_concat {
</span><span class="lines">@@ -167,14 +201,61 @@
</span><span class="cx">     return $exists || 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub bz_explain {
+    my ($self, $sql) = @_;
+    my $explain = $self-&gt;selectcol_arrayref(&quot;EXPLAIN ANALYZE $sql&quot;);
+    return join(&quot;\n&quot;, @$explain);
+}
+
</ins><span class="cx"> #####################################################################
</span><span class="cx"> # Custom Database Setup
</span><span class="cx"> #####################################################################
</span><span class="cx"> 
</span><ins>+sub bz_check_server_version {
+    my $self = shift;
+    my ($db) = @_;
+    my $server_version = $self-&gt;SUPER::bz_check_server_version(@_);
+    my ($major_version) = $server_version =~ /^(\d+)/;
+    # Pg 9 requires DBD::Pg 2.17.2 in order to properly read bytea values.
+    if ($major_version &gt;= 9) {
+        local $db-&gt;{dbd}-&gt;{version} = '2.17.2';
+        local $db-&gt;{name} = $db-&gt;{name} . ' 9+';
+        Bugzilla::DB::_bz_check_dbd(@_);
+    }
+}
+
</ins><span class="cx"> sub bz_setup_database {
</span><span class="cx">     my $self = shift;
</span><span class="cx">     $self-&gt;SUPER::bz_setup_database(@_);
</span><span class="cx"> 
</span><ins>+    # Custom Functions
+    my $function = 'array_accum';
+    my $array_accum = $self-&gt;selectrow_array(
+        'SELECT 1 FROM pg_proc WHERE proname = ?', undef, $function);
+    if (!$array_accum) {
+        print &quot;Creating function $function...\n&quot;;
+        $self-&gt;do(&quot;CREATE AGGREGATE array_accum (
+                       SFUNC = array_append,
+                       BASETYPE = anyelement,
+                       STYPE = anyarray,
+                       INITCOND = '{}' 
+                   )&quot;);
+    }
+
+   $self-&gt;do(&lt;&lt;'END');
+CREATE OR REPLACE FUNCTION array_sort(ANYARRAY)
+RETURNS ANYARRAY LANGUAGE SQL
+IMMUTABLE STRICT
+AS $$
+SELECT ARRAY(
+    SELECT $1[s.i] AS each_item
+    FROM
+        generate_series(array_lower($1,1), array_upper($1,1)) AS s(i)
+    ORDER BY each_item
+);
+$$;
+END
+
</ins><span class="cx">     # PostgreSQL doesn't like having *any* index on the thetext
</span><span class="cx">     # field, because it can't have index data longer than 2770
</span><span class="cx">     # characters on that field.
</span><span class="lines">@@ -201,15 +282,60 @@
</span><span class="cx">     $self-&gt;bz_add_index('products', 'products_name_lower_idx',
</span><span class="cx">         {FIELDS =&gt; ['LOWER(name)'], TYPE =&gt; 'UNIQUE'});
</span><span class="cx"> 
</span><del>-    # bz_rename_column didn't correctly rename the sequence.
-    if ($self-&gt;bz_column_info('fielddefs', 'id')
-        &amp;&amp; $self-&gt;bz_sequence_exists('fielddefs_fieldid_seq')) 
</del><ins>+    # bz_rename_column and bz_rename_table didn't correctly rename
+    # the sequence.
+    $self-&gt;_fix_bad_sequence('fielddefs', 'id', 'fielddefs_fieldid_seq', 'fielddefs_id_seq');
+    # If the 'tags' table still exists, then bz_rename_table()
+    # will fix the sequence for us.
+    if (!$self-&gt;bz_table_info('tags')) {
+        my $res = $self-&gt;_fix_bad_sequence('tag', 'id', 'tags_id_seq', 'tag_id_seq');
+        # If $res is true, then the sequence has been renamed, meaning that
+        # the primary key must be renamed too.
+        if ($res) {
+            $self-&gt;do('ALTER INDEX tags_pkey RENAME TO tag_pkey');
+        }
+    }
+
+    # Certain sequences got upgraded before we required Pg 8.3, and
+    # so they were not properly associated with their columns.
+    my @tables = $self-&gt;bz_table_list_real;
+    foreach my $table (@tables) {
+        my @columns = $self-&gt;bz_table_columns_real($table);
+        foreach my $column (@columns) {
+            # All our SERIAL pks have &quot;id&quot; in their name at the end.
+            next unless $column =~ /id$/;
+            my $sequence = &quot;${table}_${column}_seq&quot;;
+            if ($self-&gt;bz_sequence_exists($sequence)) {
+                my $is_associated = $self-&gt;selectrow_array(
+                    'SELECT pg_get_serial_sequence(?,?)',
+                    undef, $table, $column);
+                next if $is_associated;
+                print &quot;Fixing $sequence to be associated&quot;
+                      . &quot; with $table.$column...\n&quot;;
+                $self-&gt;do(&quot;ALTER SEQUENCE $sequence OWNED BY $table.$column&quot;);
+                # In order to produce an exactly identical schema to what
+                # a brand-new checksetup.pl run would produce, we also need
+                # to re-set the default on this column.
+                $self-&gt;do(&quot;ALTER TABLE $table
+                          ALTER COLUMN $column
+                           SET DEFAULT nextval('$sequence')&quot;);
+            }
+        }
+    }
+}
+
+sub _fix_bad_sequence {
+    my ($self, $table, $column, $old_seq, $new_seq) = @_;
+    if ($self-&gt;bz_column_info($table, $column)
+        &amp;&amp; $self-&gt;bz_sequence_exists($old_seq))
</ins><span class="cx">     {
</span><del>-        print &quot;Fixing fielddefs_fieldid_seq sequence...\n&quot;;
-        $self-&gt;do(&quot;ALTER TABLE fielddefs_fieldid_seq RENAME TO fielddefs_id_seq&quot;);
-        $self-&gt;do(&quot;ALTER TABLE fielddefs ALTER COLUMN id
-                    SET DEFAULT NEXTVAL('fielddefs_id_seq')&quot;);
</del><ins>+        print &quot;Fixing $old_seq sequence...\n&quot;;
+        $self-&gt;do(&quot;ALTER SEQUENCE $old_seq RENAME TO $new_seq&quot;);
+        $self-&gt;do(&quot;ALTER TABLE $table ALTER COLUMN $column
+                    SET DEFAULT NEXTVAL('$new_seq')&quot;);
+        return 1;
</ins><span class="cx">     }
</span><ins>+    return 0;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> # Renames things that differ only in case.
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaDBSchemaMysqlpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/DB/Schema/Mysql.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/DB/Schema/Mysql.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/DB/Schema/Mysql.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -43,6 +43,9 @@
</span><span class="cx"> # that should be interpreted as a BOOLEAN instead of as an INT1 when
</span><span class="cx"> # reading in the Schema from the disk. The values are discarded; I just
</span><span class="cx"> # used &quot;1&quot; for simplicity.
</span><ins>+# 
+# THIS CONSTANT IS ONLY USED FOR UPGRADES FROM 2.18 OR EARLIER. DON'T
+# UPDATE IT TO MODERN COLUMN NAMES OR DEFINITIONS.
</ins><span class="cx"> use constant BOOLEAN_MAP =&gt; {
</span><span class="cx">     bugs           =&gt; {everconfirmed =&gt; 1, reporter_accessible =&gt; 1,
</span><span class="cx">                        cclist_accessible =&gt; 1, qacontact_accessible =&gt; 1,
</span><span class="lines">@@ -178,13 +181,35 @@
</span><span class="cx">         delete $new_def_copy{PRIMARYKEY};
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    my $new_ddl = $self-&gt;get_type_ddl(\%new_def_copy);
</del><span class="cx">     my @statements;
</span><span class="cx"> 
</span><span class="cx">     push(@statements, &quot;UPDATE $table SET $column = $set_nulls_to
</span><span class="cx">                         WHERE $column IS NULL&quot;) if defined $set_nulls_to;
</span><del>-    push(@statements, &quot;ALTER TABLE $table CHANGE COLUMN 
</del><ins>+
+    # Calling SET DEFAULT or DROP DEFAULT is *way* faster than calling
+    # CHANGE COLUMN, so just do that if we're just changing the default.
+    my %old_defaultless = %$old_def;
+    my %new_defaultless = %$new_def;
+    delete $old_defaultless{DEFAULT};
+    delete $new_defaultless{DEFAULT};
+    if (!$self-&gt;columns_equal($old_def, $new_def)
+        &amp;&amp; $self-&gt;columns_equal(\%new_defaultless, \%old_defaultless)) 
+    {
+        if (!defined $new_def-&gt;{DEFAULT}) {
+            push(@statements,
+                 &quot;ALTER TABLE $table ALTER COLUMN $column DROP DEFAULT&quot;);
+        }
+        else {
+            push(@statements, &quot;ALTER TABLE $table ALTER COLUMN $column
+                               SET DEFAULT &quot; . $new_def-&gt;{DEFAULT});
+        }
+    }
+    else {
+        my $new_ddl = $self-&gt;get_type_ddl(\%new_def_copy);
+        push(@statements, &quot;ALTER TABLE $table CHANGE COLUMN 
</ins><span class="cx">                        $column $column $new_ddl&quot;);
</span><ins>+    }
+
</ins><span class="cx">     if ($old_def-&gt;{PRIMARYKEY} &amp;&amp; !$new_def-&gt;{PRIMARYKEY}) {
</span><span class="cx">         # Dropping a PRIMARY KEY needs an explicit DROP PRIMARY KEY
</span><span class="cx">         push(@statements, &quot;ALTER TABLE $table DROP PRIMARY KEY&quot;);
</span><span class="lines">@@ -241,6 +266,11 @@
</span><span class="cx">     return ($sql);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub get_set_serial_sql {
+    my ($self, $table, $column, $value) = @_;
+    return (&quot;ALTER TABLE $table AUTO_INCREMENT = $value&quot;);
+}
+
</ins><span class="cx"> # Converts a DBI column_info output to an abstract column definition.
</span><span class="cx"> # Expects to only be called by Bugzila::DB::Mysql::_bz_build_schema_from_disk,
</span><span class="cx"> # although there's a chance that it will also work properly if called
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaDBSchemaOraclepm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/DB/Schema/Oracle.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/DB/Schema/Oracle.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/DB/Schema/Oracle.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -35,6 +35,7 @@
</span><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> 
</span><span class="cx"> use constant ADD_COLUMN =&gt; 'ADD';
</span><ins>+use constant MULTIPLE_FKS_IN_ALTER =&gt; 0;
</ins><span class="cx"> # Whether this is true or not, this is what it needs to be in order for
</span><span class="cx"> # hash_identifier to maintain backwards compatibility with versions before
</span><span class="cx"> # 3.2rc2.
</span><span class="lines">@@ -136,37 +137,44 @@
</span><span class="cx"> # - Delete CASCADE
</span><span class="cx"> # - Delete SET NULL
</span><span class="cx"> sub get_fk_ddl {
</span><del>-    my ($self, $table, $column, $references) = @_;
-    return &quot;&quot; if !$references;
</del><ins>+    my $self = shift;
+    my $ddl = $self-&gt;SUPER::get_fk_ddl(@_);
</ins><span class="cx"> 
</span><del>-    my $update    = $references-&gt;{UPDATE} || 'CASCADE';
-    my $delete    = $references-&gt;{DELETE};
-    my $to_table  = $references-&gt;{TABLE}  || confess &quot;No table in reference&quot;;
-    my $to_column = $references-&gt;{COLUMN} || confess &quot;No column in reference&quot;;
-    my $fk_name   = $self-&gt;_get_fk_name($table, $column, $references);
</del><ins>+    # iThe Bugzilla Oracle driver implements UPDATE via a trigger.
+    $ddl =~ s/ON UPDATE \S+//i;
+    # RESTRICT is the default for DELETE on Oracle and may not be specified.
+    $ddl =~ s/ON DELETE RESTRICT//i;
</ins><span class="cx"> 
</span><del>-    my $fk_string = &quot;\n     CONSTRAINT $fk_name FOREIGN KEY ($column)\n&quot;
-                    . &quot;     REFERENCES $to_table($to_column)\n&quot;;
-   
-    $fk_string    = $fk_string . &quot;     ON DELETE $delete&quot; if $delete; 
-    
-    if ( $update =~ /CASCADE/i ){
-        my $tr_str = &quot;CREATE OR REPLACE TRIGGER ${fk_name}_UC&quot;
-                     . &quot; AFTER  UPDATE  ON &quot;. $to_table
-                     . &quot; REFERENCING &quot;
-                     . &quot; NEW AS NEW &quot;
-                     . &quot; OLD AS OLD &quot;
-                     . &quot; FOR EACH ROW &quot;
-                     . &quot; BEGIN &quot;
-                     . &quot;     UPDATE $table&quot;
-                     . &quot;        SET $column = :NEW.$to_column&quot;
-                     . &quot;      WHERE $column = :OLD.$to_column;&quot;
-                     . &quot; END ${fk_name}_UC;&quot;;
-        my $dbh = Bugzilla-&gt;dbh; 
-        $dbh-&gt;do($tr_str);      
</del><ins>+    return $ddl;
+}
+
+sub get_add_fks_sql {
+    my $self = shift;
+    my ($table, $column_fks) = @_;
+    my @sql = $self-&gt;SUPER::get_add_fks_sql(@_);
+
+    foreach my $column (keys %$column_fks) {
+        my $fk = $column_fks-&gt;{$column};
+        next if $fk-&gt;{UPDATE} &amp;&amp; uc($fk-&gt;{UPDATE}) ne 'CASCADE';
+        my $fk_name   = $self-&gt;_get_fk_name($table, $column, $fk);
+        my $to_column = $fk-&gt;{COLUMN};
+        my $to_table  = $fk-&gt;{TABLE};
+
+        my $trigger = &lt;&lt;END;
+CREATE OR REPLACE TRIGGER ${fk_name}_UC
+          AFTER UPDATE OF $to_column ON $to_table
+              REFERENCING NEW AS NEW OLD AS OLD
+             FOR EACH ROW
+                    BEGIN
+                   UPDATE $table
+                      SET $column = :NEW.$to_column
+                    WHERE $column = :OLD.$to_column;
+                      END ${fk_name}_UC;
+END
+        push(@sql, $trigger);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    return $fk_string;
</del><ins>+    return @sql;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub get_drop_fk_sql {
</span><span class="lines">@@ -206,6 +214,10 @@
</span><span class="cx"> 
</span><span class="cx">     my $default = $new_def-&gt;{DEFAULT};
</span><span class="cx">     my $default_old = $old_def-&gt;{DEFAULT};
</span><ins>+
+    if (defined $default) {
+        $default = $specific-&gt;{$default} if exists $specific-&gt;{$default};
+    }
</ins><span class="cx">     # This first condition prevents &quot;uninitialized value&quot; errors.
</span><span class="cx">     if (!defined $default &amp;&amp; !defined $default_old) {
</span><span class="cx">         # Do Nothing
</span><span class="lines">@@ -219,7 +231,6 @@
</span><span class="cx">     elsif ( (defined $default &amp;&amp; !defined $default_old) || 
</span><span class="cx">             ($default ne $default_old) ) 
</span><span class="cx">     {
</span><del>-        $default = $specific-&gt;{$default} if exists $specific-&gt;{$default};
</del><span class="cx">         push(@statements, &quot;ALTER TABLE $table MODIFY $column &quot;
</span><span class="cx">                          . &quot; DEFAULT $default&quot;);
</span><span class="cx">     }
</span><span class="lines">@@ -228,7 +239,7 @@
</span><span class="cx">     if (!$old_def-&gt;{NOTNULL} &amp;&amp; $new_def-&gt;{NOTNULL}) {
</span><span class="cx">         my $setdefault;
</span><span class="cx">         # Handle any fields that were NULL before, if we have a default,
</span><del>-        $setdefault = $new_def-&gt;{DEFAULT} if exists $new_def-&gt;{DEFAULT};
</del><ins>+        $setdefault = $default if defined $default;
</ins><span class="cx">         # But if we have a set_nulls_to, that overrides the DEFAULT 
</span><span class="cx">         # (although nobody would usually specify both a default and 
</span><span class="cx">         # a set_nulls_to.)
</span><span class="lines">@@ -340,17 +351,10 @@
</span><span class="cx">     my $def = $self-&gt;get_column_abstract($table, $old_name);
</span><span class="cx">     if ($def-&gt;{TYPE} =~ /SERIAL/i) {
</span><span class="cx">         # We have to rename the series also, and fix the default of the series.
</span><del>-        push(@sql, &quot;RENAME ${table}_${old_name}_SEQ TO 
-                      ${table}_${new_name}_seq&quot;);
-        my $serial_sql =
-                       &quot;CREATE OR REPLACE TRIGGER ${table}_${new_name}_TR &quot;
-                     . &quot; BEFORE INSERT ON ${table} &quot;
-                     . &quot; FOR EACH ROW &quot;
-                     . &quot; BEGIN &quot;
-                     . &quot;   SELECT ${table}_${new_name}_SEQ.NEXTVAL &quot;
-                     . &quot;   INTO :NEW.${new_name} FROM DUAL; &quot;
-                     . &quot; END;&quot;;
-        push(@sql, $serial_sql);
</del><ins>+        my $old_seq = &quot;${table}_${old_name}_SEQ&quot;;
+        my $new_seq = &quot;${table}_${new_name}_SEQ&quot;;
+        push(@sql, &quot;RENAME $old_seq TO $new_seq&quot;);
+        push(@sql, $self-&gt;_get_create_trigger_ddl($table, $new_name, $new_seq));
</ins><span class="cx">         push(@sql, &quot;DROP TRIGGER ${table}_${old_name}_TR&quot;);
</span><span class="cx">     }
</span><span class="cx">     if ($def-&gt;{TYPE} =~ /varchar|text/i &amp;&amp; $def-&gt;{NOTNULL} ) {
</span><span class="lines">@@ -360,6 +364,53 @@
</span><span class="cx">     return @sql;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub get_rename_table_sql {
+    my ($self, $old_name, $new_name) = @_;
+    if (lc($old_name) eq lc($new_name)) {
+        # if the only change is a case change, return an empty list.
+        return ();
+    }
+
+    my @sql = (&quot;ALTER TABLE $old_name RENAME TO $new_name&quot;);
+    my @columns = $self-&gt;get_table_columns($old_name);
+    foreach my $column (@columns) {
+        my $def = $self-&gt;get_column_abstract($old_name, $column);
+        if ($def-&gt;{TYPE} =~ /SERIAL/i) {
+            # If there's a SERIAL column on this table, we also need
+            # to rename the sequence.
+            my $old_seq = &quot;${old_name}_${column}_SEQ&quot;;
+            my $new_seq = &quot;${new_name}_${column}_SEQ&quot;;
+            push(@sql, &quot;RENAME $old_seq TO $new_seq&quot;);
+            push(@sql, $self-&gt;_get_create_trigger_ddl($new_name, $column, $new_seq));
+            push(@sql, &quot;DROP TRIGGER ${old_name}_${column}_TR&quot;);
+        }
+        if ($def-&gt;{TYPE} =~ /varchar|text/i &amp;&amp; $def-&gt;{NOTNULL}) {
+            push(@sql, _get_notnull_trigger_ddl($new_name, $column));
+            push(@sql, &quot;DROP TRIGGER ${old_name}_${column}&quot;);
+        }
+    }
+
+    return @sql;
+}
+
+sub get_drop_table_ddl {
+    my ($self, $name) = @_;
+    my @sql;
+
+    my @columns = $self-&gt;get_table_columns($name);
+    foreach my $column (@columns) {
+        my $def = $self-&gt;get_column_abstract($name, $column);
+        if ($def-&gt;{TYPE} =~ /SERIAL/i) {
+            # If there's a SERIAL column on this table, we also need
+            # to remove the sequence.
+            push(@sql, &quot;DROP SEQUENCE ${name}_${column}_SEQ&quot;);
+        }
+    }
+    push(@sql, &quot;DROP TABLE $name CASCADE CONSTRAINTS PURGE&quot;);
+
+    return @sql;
+}
+
</ins><span class="cx"> sub _get_notnull_trigger_ddl {
</span><span class="cx">       my ($table, $column) = @_;
</span><span class="cx"> 
</span><span class="lines">@@ -387,17 +438,47 @@
</span><span class="cx">                    . &quot; NOMAXVALUE &quot;
</span><span class="cx">                    . &quot; NOCYCLE &quot;
</span><span class="cx">                    . &quot; NOCACHE&quot;;
</span><del>-     my $serial_sql = &quot;CREATE OR REPLACE TRIGGER ${table}_${column}_TR &quot;
-                    . &quot; BEFORE INSERT ON ${table} &quot;
-                    . &quot; FOR EACH ROW &quot;
-                    . &quot; BEGIN &quot;
-                    . &quot;   SELECT ${seq_name}.NEXTVAL &quot;
-                    . &quot;   INTO :NEW.${column} FROM DUAL; &quot;
-                    . &quot; END;&quot;;
</del><span class="cx">     push (@ddl, $seq_sql);
</span><del>-    push (@ddl, $serial_sql);
</del><ins>+    push(@ddl, $self-&gt;_get_create_trigger_ddl($table, $column, $seq_name));
</ins><span class="cx"> 
</span><span class="cx">     return @ddl;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub _get_create_trigger_ddl {
+    my ($self, $table, $column, $seq_name) = @_;
+    my $serial_sql = &quot;CREATE OR REPLACE TRIGGER ${table}_${column}_TR &quot;
+                   . &quot; BEFORE INSERT ON $table &quot;
+                   . &quot; FOR EACH ROW &quot;
+                   . &quot; BEGIN &quot;
+                   . &quot;   SELECT ${seq_name}.NEXTVAL &quot;
+                   . &quot;   INTO :NEW.$column FROM DUAL; &quot;
+                   . &quot; END;&quot;;
+    return $serial_sql;
+}
+
+sub get_set_serial_sql { 
+    my ($self, $table, $column, $value) = @_; 
+    my @sql;
+    my $seq_name = &quot;${table}_${column}_SEQ&quot;;
+    push(@sql, &quot;DROP SEQUENCE ${seq_name}&quot;);
+    push(@sql, $self-&gt;_get_create_seq_ddl($table, $column, $value));       
+    return @sql;
+} 
+
+sub get_drop_column_ddl {
+    my $self = shift;
+    my ($table, $column) = @_;
+    my @sql;
+    push(@sql, $self-&gt;SUPER::get_drop_column_ddl(@_));
+    my $dbh=Bugzilla-&gt;dbh;
+    my $trigger_name = uc($table . &quot;_&quot; . $column);
+    my $exist_trigger = $dbh-&gt;selectcol_arrayref(
+        &quot;SELECT OBJECT_NAME FROM USER_OBJECTS
+         WHERE OBJECT_NAME = ?&quot;, undef, $trigger_name);
+    if(@$exist_trigger) {
+        push(@sql, &quot;DROP TRIGGER $trigger_name&quot;);
+    }
+    return @sql;
+}
+
</ins><span class="cx"> 1;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaDBSchemaPgpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/DB/Schema/Pg.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/DB/Schema/Pg.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/DB/Schema/Pg.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -100,11 +100,9 @@
</span><span class="cx">     my @sql = (&quot;ALTER TABLE $table RENAME COLUMN $old_name TO $new_name&quot;);
</span><span class="cx">     my $def = $self-&gt;get_column_abstract($table, $old_name);
</span><span class="cx">     if ($def-&gt;{TYPE} =~ /SERIAL/i) {
</span><del>-        # We have to rename the series also, and fix the default of the series.
-        push(@sql, &quot;ALTER TABLE ${table}_${old_name}_seq 
-                      RENAME TO ${table}_${new_name}_seq&quot;);
-        push(@sql, &quot;ALTER TABLE $table ALTER COLUMN $new_name 
-                    SET DEFAULT NEXTVAL('${table}_${new_name}_seq')&quot;);
</del><ins>+        # We have to rename the series also.
+        push(@sql, &quot;ALTER SEQUENCE ${table}_${old_name}_seq 
+                         RENAME TO ${table}_${new_name}_seq&quot;);
</ins><span class="cx">     }
</span><span class="cx">     return @sql;
</span><span class="cx"> }
</span><span class="lines">@@ -116,9 +114,38 @@
</span><span class="cx">         # is case-insensitive and will return an error about a duplicate name
</span><span class="cx">         return ();
</span><span class="cx">     }
</span><del>-    return (&quot;ALTER TABLE $old_name RENAME TO $new_name&quot;);
</del><ins>+
+    my @sql = (&quot;ALTER TABLE $old_name RENAME TO $new_name&quot;);
+
+    # If there's a SERIAL column on this table, we also need to rename the
+    # sequence.
+    # If there is a PRIMARY KEY, we need to rename it too.
+    my @columns = $self-&gt;get_table_columns($old_name);
+    foreach my $column (@columns) {
+        my $def = $self-&gt;get_column_abstract($old_name, $column);
+        if ($def-&gt;{TYPE} =~ /SERIAL/i) {
+            my $old_seq = &quot;${old_name}_${column}_seq&quot;;
+            my $new_seq = &quot;${new_name}_${column}_seq&quot;;
+            push(@sql, &quot;ALTER SEQUENCE $old_seq RENAME TO $new_seq&quot;);
+            push(@sql, &quot;ALTER TABLE $new_name ALTER COLUMN $column
+                             SET DEFAULT NEXTVAL('$new_seq')&quot;);
+        }
+        if ($def-&gt;{PRIMARYKEY}) {
+            my $old_pk = &quot;${old_name}_pkey&quot;;
+            my $new_pk = &quot;${new_name}_pkey&quot;;
+            push(@sql, &quot;ALTER INDEX $old_pk RENAME to $new_pk&quot;);
+        }
+    }
+
+    return @sql;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub get_set_serial_sql {
+    my ($self, $table, $column, $value) = @_;
+    return (&quot;SELECT setval('${table}_${column}_seq', $value, false)
+               FROM $table&quot;);
+}
+
</ins><span class="cx"> sub _get_alter_type_sql {
</span><span class="cx">     my ($self, $table, $column, $new_def, $old_def) = @_;
</span><span class="cx">     my @statements;
</span><span class="lines">@@ -130,9 +157,10 @@
</span><span class="cx">     if ($type =~ /serial/i &amp;&amp; $old_def-&gt;{TYPE} !~ /serial/i) {
</span><span class="cx">         die(&quot;You cannot specify a DEFAULT on a SERIAL-type column.&quot;) 
</span><span class="cx">             if $new_def-&gt;{DEFAULT};
</span><del>-        $type =~ s/serial/integer/i;
</del><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    $type =~ s/\bserial\b/integer/i;
+
</ins><span class="cx">     # On Pg, you don't need UNIQUE if you're a PK--it creates
</span><span class="cx">     # two identical indexes otherwise.
</span><span class="cx">     $type =~ s/unique//i if $new_def-&gt;{PRIMARYKEY};
</span><span class="lines">@@ -141,7 +169,8 @@
</span><span class="cx">                               TYPE $type&quot;);
</span><span class="cx"> 
</span><span class="cx">     if ($new_def-&gt;{TYPE} =~ /serial/i &amp;&amp; $old_def-&gt;{TYPE} !~ /serial/i) {
</span><del>-        push(@statements, &quot;CREATE SEQUENCE ${table}_${column}_seq&quot;);
</del><ins>+        push(@statements, &quot;CREATE SEQUENCE ${table}_${column}_seq
+                                  OWNED BY $table.$column&quot;);
</ins><span class="cx">         push(@statements, &quot;SELECT setval('${table}_${column}_seq',
</span><span class="cx">                                          MAX($table.$column))
</span><span class="cx">                              FROM $table&quot;);
</span><span class="lines">@@ -154,10 +183,9 @@
</span><span class="cx">     if ($old_def-&gt;{TYPE} =~ /serial/i &amp;&amp; $new_def-&gt;{TYPE} !~ /serial/i) {
</span><span class="cx">         push(@statements, &quot;ALTER TABLE $table ALTER COLUMN $column 
</span><span class="cx">                            DROP DEFAULT&quot;);
</span><del>-        # XXX Pg actually won't let us drop the sequence, even though it's
-        #     no longer in use. So we harmlessly leave behind a sequence
-        #     that does nothing.
-        #push(@statements, &quot;DROP SEQUENCE ${table}_${column}_seq&quot;);
</del><ins>+        push(@statements, &quot;ALTER SEQUENCE ${table}_${column}_seq 
+                           OWNED BY NONE&quot;);
+        push(@statements, &quot;DROP SEQUENCE ${table}_${column}_seq&quot;);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     return @statements;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaDBSchemaSqlitepm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/DB/Schema/Sqlite.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/DB/Schema/Sqlite.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/DB/Schema/Sqlite.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,312 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Everything Solved, Inc.
+# Portions created by the Initial Developer are Copyright (C) 2010 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+use strict;
+package Bugzilla::DB::Schema::Sqlite;
+use base qw(Bugzilla::DB::Schema);
+
+use Bugzilla::Error;
+use Bugzilla::Util qw(generate_random_password);
+
+use Storable qw(dclone);
+
+use constant FK_ON_CREATE =&gt; 1;
+
+sub _initialize {
+
+    my $self = shift;
+
+    $self = $self-&gt;SUPER::_initialize(@_);
+
+    $self-&gt;{db_specific} = {
+        BOOLEAN =&gt;      'integer',
+        FALSE =&gt;        '0', 
+        TRUE =&gt;         '1',
+
+        INT1 =&gt;         'integer',
+        INT2 =&gt;         'integer',
+        INT3 =&gt;         'integer',
+        INT4 =&gt;         'integer',
+
+        SMALLSERIAL =&gt;  'SERIAL',
+        MEDIUMSERIAL =&gt; 'SERIAL',
+        INTSERIAL =&gt;    'SERIAL',
+
+        TINYTEXT =&gt;     'text',
+        MEDIUMTEXT =&gt;   'text',
+        LONGTEXT =&gt;     'text',
+
+        LONGBLOB =&gt;     'blob',
+
+        DATETIME =&gt;     'DATETIME',
+    };
+
+    $self-&gt;_adjust_schema;
+
+    return $self;
+
+}
+
+#################################
+# General SQLite Schema Helpers #
+#################################
+
+sub _sqlite_create_table {
+    my ($self, $table) = @_;
+    return scalar Bugzilla-&gt;dbh-&gt;selectrow_array(
+        &quot;SELECT sql FROM sqlite_master WHERE name = ? AND type = 'table'&quot;,
+        undef, $table);
+}
+
+sub _sqlite_table_lines {
+    my $self = shift;
+    my $table_sql = $self-&gt;_sqlite_create_table(@_);
+    $table_sql =~ s/\n*\)$//s;
+    # The $ makes this work even if people some day add crazy stuff to their
+    # schema like multi-column foreign keys.
+    return split(/,\s*$/m, $table_sql);
+}
+
+# This does most of the &quot;heavy lifting&quot; of the schema-altering functions.
+sub _sqlite_alter_schema {
+    my ($self, $table, $create_table, $options) = @_;
+    
+    # $create_table is sometimes an array in the form that _sqlite_table_lines
+    # returns.
+    if (ref $create_table) {
+        $create_table = join(',', @$create_table) . &quot;\n)&quot;;
+    }
+    
+    my $dbh = Bugzilla-&gt;dbh;
+    
+    my $random = generate_random_password(5);
+    my $rename_to = &quot;${table}_$random&quot;;
+
+    my @columns = $dbh-&gt;bz_table_columns_real($table);
+    push(@columns, $options-&gt;{extra_column}) if $options-&gt;{extra_column};
+    if (my $exclude = $options-&gt;{exclude_column}) {
+        @columns = grep { $_ ne $exclude } @columns;
+    }
+    my @insert_cols = @columns;
+    my @select_cols = @columns;
+    if (my $rename = $options-&gt;{rename}) {
+        foreach my $from (keys %$rename) {
+            my $to = $rename-&gt;{$from};
+            @insert_cols = map { $_ eq $from ? $to : $_ } @insert_cols;
+        }
+    }
+    
+    my $insert_str = join(',', @insert_cols);
+    my $select_str = join(',', @select_cols);
+    my $copy_sql = &quot;INSERT INTO $table ($insert_str)&quot;
+                   . &quot; SELECT $select_str FROM $rename_to&quot;;
+                   
+    # We have to turn FKs off before doing this. Otherwise, when we rename
+    # the table, all of the FKs in the other tables will be automatically
+    # updated to point to the renamed table. Note that PRAGMA foreign_keys
+    # can only be set outside of a transaction--otherwise it is a no-op.
+    if ($dbh-&gt;bz_in_transaction) {
+        die &quot;can't alter the schema inside of a transaction&quot;;
+    }
+    my @sql = (
+        'PRAGMA foreign_keys = OFF',
+        'BEGIN EXCLUSIVE TRANSACTION',
+        @{ $options-&gt;{pre_sql} || [] },
+        &quot;ALTER TABLE $table RENAME TO $rename_to&quot;,
+        $create_table,
+        $copy_sql,
+        &quot;DROP TABLE $rename_to&quot;,
+        'COMMIT TRANSACTION',
+        'PRAGMA foreign_keys = ON',
+    );    
+}
+
+# For finding a particular column's definition in a CREATE TABLE statement.
+sub _sqlite_column_regex {
+    my ($column) = @_;
+    # 1 = Comma at start
+    # 2 = Column name + Space
+    # 3 = Definition
+    # 4 = Ending comma
+    return qr/(^|,)(\s\Q$column\E\s+)(.*?)(,|$)/m;
+}
+
+#############################
+# Schema Setup &amp; Alteration #
+#############################
+
+sub get_create_database_sql {
+    # If we get here, it means there was some error creating the
+    # database file during bz_create_database in Bugzilla::DB,
+    # and we just want to display that error instead of doing
+    # anything else.
+    Bugzilla-&gt;dbh;
+    die &quot;Reached an unreachable point&quot;;
+}
+
+sub _get_create_table_ddl {
+    my $self = shift;
+    my ($table) = @_;
+    my $ddl = $self-&gt;SUPER::_get_create_table_ddl(@_);
+
+    # TheSchwartz uses its own driver to access its tables, meaning
+    # that it doesn't understand &quot;COLLATE bugzilla&quot; and in fact
+    # SQLite throws an error when TheSchwartz tries to access its
+    # own tables, if COLLATE bugzilla is on them. We don't have
+    # to fix this elsewhere currently, because we only create
+    # TheSchwartz's tables, we never modify them.
+    if ($table =~ /^ts_/) {
+        $ddl =~ s/ COLLATE bugzilla//g;
+    }
+    return $ddl;
+}
+
+sub get_type_ddl {
+    my $self = shift;
+    my $def = dclone($_[0]);
+    
+    my $ddl = $self-&gt;SUPER::get_type_ddl(@_);
+    if ($def-&gt;{PRIMARYKEY} and $def-&gt;{TYPE} =~ /SERIAL/i) {
+        $ddl =~ s/\bSERIAL\b/integer/;
+        $ddl =~ s/\bPRIMARY KEY\b/PRIMARY KEY AUTOINCREMENT/;
+    }
+    if ($def-&gt;{TYPE} =~ /text/i or $def-&gt;{TYPE} =~ /char/i) {
+        $ddl .= &quot; COLLATE bugzilla&quot;;
+    }
+    # Don't collate DATETIME fields.
+    if ($def-&gt;{TYPE} eq 'DATETIME') {
+        $ddl =~ s/\bDATETIME\b/text COLLATE BINARY/;
+    }
+    return $ddl;
+}
+
+sub get_alter_column_ddl {
+    my $self = shift;
+    my ($table, $column, $new_def, $set_nulls_to) = @_;
+    my $dbh = Bugzilla-&gt;dbh;
+    
+    my $table_sql = $self-&gt;_sqlite_create_table($table);
+    my $new_ddl = $self-&gt;get_type_ddl($new_def);
+    # When we do ADD COLUMN, columns can show up all on one line separated
+    # by commas, so we have to account for that.
+    my $column_regex = _sqlite_column_regex($column);
+    $table_sql =~ s/$column_regex/$1$2$new_ddl$4/
+        || die &quot;couldn't find $column in $table:\n$table_sql&quot;;
+    my @pre_sql = $self-&gt;_set_nulls_sql(@_);
+    return $self-&gt;_sqlite_alter_schema($table, $table_sql,
+                                       { pre_sql =&gt; \@pre_sql });
+}
+
+sub get_add_column_ddl {
+    my $self = shift;
+    my ($table, $column, $definition, $init_value) = @_;
+    # SQLite can use the normal ADD COLUMN when:
+    # * The column isn't a PK
+    if ($definition-&gt;{PRIMARYKEY}) {
+        if ($definition-&gt;{NOTNULL} and $definition-&gt;{TYPE} !~ /SERIAL/i) {
+            die &quot;You can only add new SERIAL type PKs with SQLite&quot;;
+        }
+        my $table_sql = $self-&gt;_sqlite_new_column_sql(@_);
+        # This works because _sqlite_alter_schema will exclude the new column
+        # in its INSERT ... SELECT statement, meaning that when the &quot;new&quot;
+        # table is populated, it will have AUTOINCREMENT values generated
+        # for it.
+        return $self-&gt;_sqlite_alter_schema($table, $table_sql);
+    }
+    # * The column has a default one way or another. Either it
+    #   defaults to NULL (it lacks NOT NULL) or it has a DEFAULT
+    #   clause. Since we also require this when doing bz_add_column (in
+    #   the way of forcing an init_value for NOT NULL columns with no
+    #   default), we first set the init_value as the default and then
+    #   alter the column.
+    if ($definition-&gt;{NOTNULL} and !defined $definition-&gt;{DEFAULT}) {
+        my %with_default = %$definition;
+        $with_default{DEFAULT} = $init_value;
+        my @pre_sql =
+            $self-&gt;SUPER::get_add_column_ddl($table, $column, \%with_default);
+        my $table_sql = $self-&gt;_sqlite_new_column_sql(@_);
+        return $self-&gt;_sqlite_alter_schema($table, $table_sql,
+            { pre_sql =&gt; \@pre_sql, extra_column =&gt; $column });
+    }
+    
+    return $self-&gt;SUPER::get_add_column_ddl(@_);
+}
+
+sub _sqlite_new_column_sql {
+    my ($self, $table, $column, $def) = @_;
+    my $table_sql = $self-&gt;_sqlite_create_table($table);
+    my $new_ddl = $self-&gt;get_type_ddl($def);
+    my $new_line = &quot;\t$column\t$new_ddl&quot;;
+    $table_sql =~ s/^(CREATE TABLE \w+ \()/$1\n$new_line,/s
+        || die &quot;Can't find start of CREATE TABLE:\n$table_sql&quot;;
+    return $table_sql;
+}
+
+sub get_drop_column_ddl {
+    my ($self, $table, $column) = @_;
+    my $table_sql = $self-&gt;_sqlite_create_table($table);
+    my $column_regex = _sqlite_column_regex($column);
+    $table_sql =~ s/$column_regex/$1/
+        || die &quot;Can't find column $column: $table_sql&quot;;
+    # Make sure we don't end up with a comma at the end of the definition.
+    $table_sql =~ s/,\s+\)$/\n)/s;
+    return $self-&gt;_sqlite_alter_schema($table, $table_sql,
+                                       { exclude_column =&gt; $column });
+}
+
+sub get_rename_column_ddl {
+    my ($self, $table, $old_name, $new_name) = @_;
+    my $table_sql = $self-&gt;_sqlite_create_table($table);
+    my $column_regex = _sqlite_column_regex($old_name);
+    $table_sql =~ s/$column_regex/$1\t$new_name\t$3$4/
+        || die &quot;Can't find $old_name: $table_sql&quot;;
+    my %rename = ($old_name =&gt; $new_name);
+    return $self-&gt;_sqlite_alter_schema($table, $table_sql,
+                                       { rename =&gt; \%rename });
+}
+
+################
+# Foreign Keys #
+################
+
+sub get_add_fks_sql {
+    my ($self, $table, $column_fks) = @_;
+    my @clauses = $self-&gt;_sqlite_table_lines($table);
+    my @add = $self-&gt;_column_fks_to_ddl($table, $column_fks);
+    push(@clauses, @add);
+    return $self-&gt;_sqlite_alter_schema($table, \@clauses);
+}
+
+sub get_drop_fk_sql {
+    my ($self, $table, $column, $references) = @_;
+    my @clauses = $self-&gt;_sqlite_table_lines($table);
+    my $fk_name = $self-&gt;_get_fk_name($table, $column, $references);
+    
+    my $line_re = qr/^\s+CONSTRAINT $fk_name /s;
+    grep { $line_re } @clauses
+        or die &quot;Can't find $fk_name: &quot; . join(',', @clauses);
+    @clauses = grep { $_ !~ $line_re } @clauses;
+    
+    return $self-&gt;_sqlite_alter_schema($table, \@clauses);
+}
+
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaDBSchemapm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/DB/Schema.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/DB/Schema.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/DB/Schema.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -23,6 +23,7 @@
</span><span class="cx"> #                 Lance Larsh &lt;lance.larsh@oracle.com&gt;
</span><span class="cx"> #                 Dennis Melentyev &lt;dennis.melentyev@infopulse.com.ua&gt;
</span><span class="cx"> #                 Akamai Technologies &lt;bugzilla-dev@akamai.com&gt;
</span><ins>+#                 Elliotte Martin &lt;emartin@everythingsolved.com&gt;
</ins><span class="cx"> 
</span><span class="cx"> package Bugzilla::DB::Schema;
</span><span class="cx"> 
</span><span class="lines">@@ -43,13 +44,20 @@
</span><span class="cx"> use Carp qw(confess);
</span><span class="cx"> use Digest::MD5 qw(md5_hex);
</span><span class="cx"> use Hash::Util qw(lock_value unlock_hash lock_keys unlock_keys);
</span><ins>+use List::MoreUtils qw(firstidx natatime);
</ins><span class="cx"> use Safe;
</span><span class="cx"> # Historical, needed for SCHEMA_VERSION = '1.00'
</span><span class="cx"> use Storable qw(dclone freeze thaw);
</span><span class="cx"> 
</span><del>-# New SCHEMA_VERSION (2.00) use this
</del><ins>+# New SCHEMA_VERSIONs (2+) use this
</ins><span class="cx"> use Data::Dumper;
</span><span class="cx"> 
</span><ins>+# Whether or not this database can safely create FKs when doing a
+# CREATE TABLE statement. This is false for most DBs, because they
+# prevent you from creating FKs on tables and columns that don't
+# yet exist. (However, in SQLite it's 1 because SQLite allows that.)
+use constant FK_ON_CREATE =&gt; 0;
+
</ins><span class="cx"> =head1 NAME
</span><span class="cx"> 
</span><span class="cx"> Bugzilla::DB::Schema - Abstract database schema for Bugzilla
</span><span class="lines">@@ -206,10 +214,33 @@
</span><span class="cx"> 
</span><span class="cx"> =cut
</span><span class="cx"> 
</span><del>-use constant SCHEMA_VERSION  =&gt; '2.00';
</del><ins>+use constant SCHEMA_VERSION  =&gt; 3;
</ins><span class="cx"> use constant ADD_COLUMN      =&gt; 'ADD COLUMN';
</span><ins>+# Multiple FKs can be added using ALTER TABLE ADD CONSTRAINT in one
+# SQL statement. This isn't true for all databases.
+use constant MULTIPLE_FKS_IN_ALTER =&gt; 1;
</ins><span class="cx"> # This is a reasonable default that's true for both PostgreSQL and MySQL.
</span><span class="cx"> use constant MAX_IDENTIFIER_LEN =&gt; 63;
</span><ins>+
+use constant FIELD_TABLE_SCHEMA =&gt; {
+    FIELDS =&gt; [
+        id       =&gt; {TYPE =&gt; 'SMALLSERIAL', NOTNULL =&gt; 1,
+                     PRIMARYKEY =&gt; 1},
+        value    =&gt; {TYPE =&gt; 'varchar(64)', NOTNULL =&gt; 1},
+        sortkey  =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1, DEFAULT =&gt; 0},
+        isactive =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1,
+                     DEFAULT =&gt; 'TRUE'},
+        visibility_value_id =&gt; {TYPE =&gt; 'INT2'},
+    ],
+    # Note that bz_add_field_table should prepend the table name
+    # to these index names.
+    INDEXES =&gt; [
+        value_idx   =&gt; {FIELDS =&gt; ['value'], TYPE =&gt; 'UNIQUE'},
+        sortkey_idx =&gt; ['sortkey', 'value'],
+        visibility_value_id_idx =&gt; ['visibility_value_id'],
+    ],
+};
+
</ins><span class="cx"> use constant ABSTRACT_SCHEMA =&gt; {
</span><span class="cx"> 
</span><span class="cx">     # BUG-RELATED TABLES
</span><span class="lines">@@ -221,8 +252,11 @@
</span><span class="cx">         FIELDS =&gt; [
</span><span class="cx">             bug_id              =&gt; {TYPE =&gt; 'MEDIUMSERIAL', NOTNULL =&gt; 1,
</span><span class="cx">                                     PRIMARYKEY =&gt; 1},
</span><del>-            assigned_to         =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1},
-            bug_file_loc        =&gt; {TYPE =&gt; 'MEDIUMTEXT'},
</del><ins>+            assigned_to         =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                                    REFERENCES =&gt; {TABLE  =&gt; 'profiles',
+                                                   COLUMN =&gt; 'userid'}},
+            bug_file_loc        =&gt; {TYPE =&gt; 'MEDIUMTEXT', 
+                                    NOTNULL =&gt; 1, DEFAULT =&gt; &quot;''&quot;},
</ins><span class="cx">             bug_severity        =&gt; {TYPE =&gt; 'varchar(64)', NOTNULL =&gt; 1},
</span><span class="cx">             bug_status          =&gt; {TYPE =&gt; 'varchar(64)', NOTNULL =&gt; 1},
</span><span class="cx">             creation_ts         =&gt; {TYPE =&gt; 'DATETIME'},
</span><span class="lines">@@ -230,33 +264,35 @@
</span><span class="cx">             short_desc          =&gt; {TYPE =&gt; 'varchar(255)', NOTNULL =&gt; 1},
</span><span class="cx">             op_sys              =&gt; {TYPE =&gt; 'varchar(64)', NOTNULL =&gt; 1},
</span><span class="cx">             priority            =&gt; {TYPE =&gt; 'varchar(64)', NOTNULL =&gt; 1},
</span><del>-            product_id          =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1},
</del><ins>+            product_id          =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1,
+                                    REFERENCES =&gt; {TABLE  =&gt; 'products',
+                                                   COLUMN =&gt; 'id'}},
</ins><span class="cx">             rep_platform        =&gt; {TYPE =&gt; 'varchar(64)', NOTNULL =&gt; 1},
</span><del>-            reporter            =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1},
</del><ins>+            reporter            =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                                    REFERENCES =&gt; {TABLE  =&gt; 'profiles',
+                                                   COLUMN =&gt; 'userid'}},
</ins><span class="cx">             version             =&gt; {TYPE =&gt; 'varchar(64)', NOTNULL =&gt; 1},
</span><del>-            component_id        =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1},
</del><ins>+            component_id        =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1,
+                                    REFERENCES =&gt; {TABLE  =&gt; 'components',
+                                                   COLUMN =&gt; 'id'}},
</ins><span class="cx">             resolution          =&gt; {TYPE =&gt; 'varchar(64)',
</span><span class="cx">                                     NOTNULL =&gt; 1, DEFAULT =&gt; &quot;''&quot;},
</span><span class="cx">             target_milestone    =&gt; {TYPE =&gt; 'varchar(20)',
</span><span class="cx">                                     NOTNULL =&gt; 1, DEFAULT =&gt; &quot;'---'&quot;},
</span><del>-            qa_contact          =&gt; {TYPE =&gt; 'INT3'},
</del><ins>+            qa_contact          =&gt; {TYPE =&gt; 'INT3',
+                                    REFERENCES =&gt; {TABLE  =&gt; 'profiles',
+                                                   COLUMN =&gt; 'userid'}},
</ins><span class="cx">             status_whiteboard   =&gt; {TYPE =&gt; 'MEDIUMTEXT', NOTNULL =&gt; 1,
</span><span class="cx">                                     DEFAULT =&gt; &quot;''&quot;},
</span><del>-            votes               =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
-                                    DEFAULT =&gt; '0'},
-            # Note: keywords field is only a cache; the real data
-            # comes from the keywords table
-            keywords            =&gt; {TYPE =&gt; 'MEDIUMTEXT', NOTNULL =&gt; 1,
-                                    DEFAULT =&gt; &quot;''&quot;},
</del><span class="cx">             lastdiffed          =&gt; {TYPE =&gt; 'DATETIME'},
</span><span class="cx">             everconfirmed       =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1},
</span><span class="cx">             reporter_accessible =&gt; {TYPE =&gt; 'BOOLEAN',
</span><span class="cx">                                     NOTNULL =&gt; 1, DEFAULT =&gt; 'TRUE'},
</span><span class="cx">             cclist_accessible   =&gt; {TYPE =&gt; 'BOOLEAN',
</span><span class="cx">                                     NOTNULL =&gt; 1, DEFAULT =&gt; 'TRUE'},
</span><del>-            estimated_time      =&gt; {TYPE =&gt; 'decimal(5,2)',
</del><ins>+            estimated_time      =&gt; {TYPE =&gt; 'decimal(7,2)',
</ins><span class="cx">                                     NOTNULL =&gt; 1, DEFAULT =&gt; '0'},
</span><del>-            remaining_time      =&gt; {TYPE =&gt; 'decimal(5,2)',
</del><ins>+            remaining_time      =&gt; {TYPE =&gt; 'decimal(7,2)',
</ins><span class="cx">                                     NOTNULL =&gt; 1, DEFAULT =&gt; '0'},
</span><span class="cx">             deadline            =&gt; {TYPE =&gt; 'DATETIME'},
</span><span class="cx">             alias               =&gt; {TYPE =&gt; 'varchar(20)'},
</span><span class="lines">@@ -278,7 +314,6 @@
</span><span class="cx">             bugs_resolution_idx       =&gt; ['resolution'],
</span><span class="cx">             bugs_target_milestone_idx =&gt; ['target_milestone'],
</span><span class="cx">             bugs_qa_contact_idx       =&gt; ['qa_contact'],
</span><del>-            bugs_votes_idx            =&gt; ['votes'],
</del><span class="cx">         ],
</span><span class="cx">     },
</span><span class="cx"> 
</span><span class="lines">@@ -307,27 +342,43 @@
</span><span class="cx"> 
</span><span class="cx">     bugs_activity =&gt; {
</span><span class="cx">         FIELDS =&gt; [
</span><del>-            bug_id    =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1},
-            attach_id =&gt; {TYPE =&gt; 'INT3'},
</del><ins>+            bug_id    =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                          REFERENCES    =&gt;  {TABLE  =&gt;  'bugs',
+                                             COLUMN =&gt;  'bug_id',
+                                             DELETE =&gt; 'CASCADE'}},
+            attach_id =&gt; {TYPE =&gt; 'INT3',
+                          REFERENCES    =&gt;  {TABLE  =&gt;  'attachments',
+                                            COLUMN  =&gt;  'attach_id',
+                                            DELETE =&gt; 'CASCADE'}},
</ins><span class="cx">             who       =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
</span><span class="cx">                           REFERENCES =&gt; {TABLE  =&gt; 'profiles',
</span><span class="cx">                                          COLUMN =&gt; 'userid'}},
</span><span class="cx">             bug_when  =&gt; {TYPE =&gt; 'DATETIME', NOTNULL =&gt; 1},
</span><del>-            fieldid   =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1},
-            added     =&gt; {TYPE =&gt; 'TINYTEXT'},
</del><ins>+            fieldid   =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                          REFERENCES    =&gt;  {TABLE  =&gt;  'fielddefs',
+                                             COLUMN =&gt;  'id'}},
+            added     =&gt; {TYPE =&gt; 'varchar(255)'},
</ins><span class="cx">             removed   =&gt; {TYPE =&gt; 'TINYTEXT'},
</span><ins>+            comment_id =&gt; {TYPE =&gt; 'INT3', 
+                           REFERENCES =&gt; { TABLE  =&gt; 'longdescs',
+                                           COLUMN =&gt; 'comment_id',
+                                           DELETE =&gt; 'CASCADE'}},
</ins><span class="cx">         ],
</span><span class="cx">         INDEXES =&gt; [
</span><span class="cx">             bugs_activity_bug_id_idx  =&gt; ['bug_id'],
</span><span class="cx">             bugs_activity_who_idx     =&gt; ['who'],
</span><span class="cx">             bugs_activity_bug_when_idx =&gt; ['bug_when'],
</span><span class="cx">             bugs_activity_fieldid_idx =&gt; ['fieldid'],
</span><ins>+            bugs_activity_added_idx   =&gt; ['added'],
</ins><span class="cx">         ],
</span><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     cc =&gt; {
</span><span class="cx">         FIELDS =&gt; [
</span><del>-            bug_id =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1},
</del><ins>+            bug_id =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                       REFERENCES =&gt; {TABLE  =&gt; 'bugs',
+                                      COLUMN =&gt; 'bug_id',
+                                      DELETE =&gt; 'CASCADE'}},
</ins><span class="cx">             who    =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
</span><span class="cx">                        REFERENCES =&gt; {TABLE  =&gt; 'profiles',
</span><span class="cx">                                       COLUMN =&gt; 'userid',
</span><span class="lines">@@ -344,10 +395,15 @@
</span><span class="cx">         FIELDS =&gt; [
</span><span class="cx">             comment_id      =&gt; {TYPE =&gt; 'MEDIUMSERIAL',  NOTNULL =&gt; 1,
</span><span class="cx">                                 PRIMARYKEY =&gt; 1},
</span><del>-            bug_id          =&gt; {TYPE =&gt; 'INT3',  NOTNULL =&gt; 1},
-            who             =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1},
</del><ins>+            bug_id          =&gt; {TYPE =&gt; 'INT3',  NOTNULL =&gt; 1,
+                                REFERENCES =&gt; {TABLE =&gt; 'bugs',
+                                               COLUMN =&gt; 'bug_id',
+                                               DELETE =&gt; 'CASCADE'}},
+            who             =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                                REFERENCES =&gt; {TABLE =&gt; 'profiles',
+                                               COLUMN =&gt; 'userid'}},
</ins><span class="cx">             bug_when        =&gt; {TYPE =&gt; 'DATETIME', NOTNULL =&gt; 1},
</span><del>-            work_time       =&gt; {TYPE =&gt; 'decimal(5,2)', NOTNULL =&gt; 1,
</del><ins>+            work_time       =&gt; {TYPE =&gt; 'decimal(7,2)', NOTNULL =&gt; 1,
</ins><span class="cx">                                 DEFAULT =&gt; '0'},
</span><span class="cx">             thetext         =&gt; {TYPE =&gt; 'LONGTEXT', NOTNULL =&gt; 1},
</span><span class="cx">             isprivate       =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1,
</span><span class="lines">@@ -367,8 +423,14 @@
</span><span class="cx"> 
</span><span class="cx">     dependencies =&gt; {
</span><span class="cx">         FIELDS =&gt; [
</span><del>-            blocked   =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1},
-            dependson =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1},
</del><ins>+            blocked   =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                          REFERENCES    =&gt;  {TABLE  =&gt;   'bugs',
+                                            COLUMN  =&gt;  'bug_id',
+                                            DELETE =&gt; 'CASCADE'}},
+            dependson =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                          REFERENCES    =&gt;  {TABLE  =&gt;   'bugs',
+                                            COLUMN  =&gt;  'bug_id',
+                                            DELETE =&gt; 'CASCADE'}},
</ins><span class="cx">         ],
</span><span class="cx">         INDEXES =&gt; [
</span><span class="cx">             dependencies_blocked_idx   =&gt; ['blocked'],
</span><span class="lines">@@ -376,31 +438,20 @@
</span><span class="cx">         ],
</span><span class="cx">     },
</span><span class="cx"> 
</span><del>-    votes =&gt; {
-        FIELDS =&gt; [
-            who        =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
-                           REFERENCES =&gt; {TABLE  =&gt; 'profiles',
-                                          COLUMN =&gt; 'userid',
-                                          DELETE =&gt; 'CASCADE'}},
-            bug_id     =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1},
-            vote_count =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1},
-        ],
-        INDEXES =&gt; [
-            votes_who_idx    =&gt; ['who'],
-            votes_bug_id_idx =&gt; ['bug_id'],
-        ],
-    },
-
</del><span class="cx">     attachments =&gt; {
</span><span class="cx">         FIELDS =&gt; [
</span><span class="cx">             attach_id    =&gt; {TYPE =&gt; 'MEDIUMSERIAL', NOTNULL =&gt; 1,
</span><span class="cx">                              PRIMARYKEY =&gt; 1},
</span><del>-            bug_id       =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1},
</del><ins>+            bug_id       =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                             REFERENCES    =&gt;  {TABLE  =&gt; 'bugs',
+                                                COLUMN =&gt; 'bug_id',
+                                                DELETE =&gt; 'CASCADE'}},
</ins><span class="cx">             creation_ts  =&gt; {TYPE =&gt; 'DATETIME', NOTNULL =&gt; 1},
</span><span class="cx">             modification_time =&gt; {TYPE =&gt; 'DATETIME', NOTNULL =&gt; 1},
</span><span class="cx">             description  =&gt; {TYPE =&gt; 'TINYTEXT', NOTNULL =&gt; 1},
</span><span class="cx">             mimetype     =&gt; {TYPE =&gt; 'TINYTEXT', NOTNULL =&gt; 1},
</span><del>-            ispatch      =&gt; {TYPE =&gt; 'BOOLEAN'},
</del><ins>+            ispatch      =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1,
+                             DEFAULT =&gt; 'FALSE'},
</ins><span class="cx">             filename     =&gt; {TYPE =&gt; 'varchar(100)', NOTNULL =&gt; 1},
</span><span class="cx">             submitter_id =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
</span><span class="cx">                              REFERENCES =&gt; {TABLE =&gt; 'profiles',
</span><span class="lines">@@ -409,8 +460,6 @@
</span><span class="cx">                              DEFAULT =&gt; 'FALSE'},
</span><span class="cx">             isprivate    =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1,
</span><span class="cx">                              DEFAULT =&gt; 'FALSE'},
</span><del>-            isurl        =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1,
-                             DEFAULT =&gt; 'FALSE'},
</del><span class="cx">         ],
</span><span class="cx">         INDEXES =&gt; [
</span><span class="cx">             attachments_bug_id_idx =&gt; ['bug_id'],
</span><span class="lines">@@ -422,19 +471,63 @@
</span><span class="cx">     attach_data =&gt; {
</span><span class="cx">         FIELDS =&gt; [
</span><span class="cx">             id      =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
</span><del>-                        PRIMARYKEY =&gt; 1},
</del><ins>+                        PRIMARYKEY =&gt; 1,
+                        REFERENCES  =&gt;  {TABLE  =&gt; 'attachments',
+                                         COLUMN =&gt; 'attach_id',
+                                         DELETE =&gt; 'CASCADE'}},
</ins><span class="cx">             thedata =&gt; {TYPE =&gt; 'LONGBLOB', NOTNULL =&gt; 1},
</span><span class="cx">         ],
</span><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     duplicates =&gt; {
</span><span class="cx">         FIELDS =&gt; [
</span><del>-            dupe_of =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1},
</del><ins>+            dupe_of =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                        REFERENCES =&gt; {TABLE  =&gt;  'bugs',
+                                       COLUMN =&gt;  'bug_id',
+                                       DELETE =&gt;  'CASCADE'}},
</ins><span class="cx">             dupe    =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
</span><ins>+                        PRIMARYKEY =&gt; 1,
+                        REFERENCES =&gt; {TABLE  =&gt;  'bugs',
+                                       COLUMN =&gt;  'bug_id',
+                                       DELETE =&gt;  'CASCADE'}},
+        ],
+    },
+
+    bug_see_also =&gt; {
+        FIELDS =&gt; [
+            id     =&gt; {TYPE =&gt; 'MEDIUMSERIAL', NOTNULL =&gt; 1,
</ins><span class="cx">                        PRIMARYKEY =&gt; 1},
</span><ins>+            bug_id =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                       REFERENCES =&gt; {TABLE  =&gt; 'bugs',
+                                      COLUMN =&gt; 'bug_id',
+                                      DELETE =&gt; 'CASCADE'}},
+            value  =&gt; {TYPE =&gt; 'varchar(255)', NOTNULL =&gt; 1},
+            class  =&gt; {TYPE =&gt; 'varchar(255)', NOTNULL =&gt; 1, DEFAULT =&gt; &quot;''&quot;},
</ins><span class="cx">         ],
</span><ins>+        INDEXES =&gt; [
+            bug_see_also_bug_id_idx =&gt; {FIELDS =&gt; [qw(bug_id value)], 
+                                        TYPE   =&gt; 'UNIQUE'},
+        ],
</ins><span class="cx">     },
</span><span class="cx"> 
</span><ins>+    # Auditing
+    # --------
+
+    audit_log =&gt; {
+        FIELDS =&gt; [
+            user_id   =&gt; {TYPE =&gt; 'INT3',
+                          REFERENCES =&gt; {TABLE  =&gt; 'profiles',
+                                         COLUMN =&gt; 'userid',
+                                         DELETE =&gt; 'SET NULL'}},
+            class     =&gt; {TYPE =&gt; 'varchar(255)', NOTNULL =&gt; 1},
+            object_id =&gt; {TYPE =&gt; 'INT4', NOTNULL =&gt; 1},
+            field     =&gt; {TYPE =&gt; 'varchar(64)', NOTNULL =&gt; 1},
+            removed   =&gt; {TYPE =&gt; 'MEDIUMTEXT'},
+            added     =&gt; {TYPE =&gt; 'MEDIUMTEXT'},
+            at_time   =&gt; {TYPE =&gt; 'DATETIME', NOTNULL =&gt; 1},
+        ],
+    },
+
</ins><span class="cx">     # Keywords
</span><span class="cx">     # --------
</span><span class="cx"> 
</span><span class="lines">@@ -443,7 +536,7 @@
</span><span class="cx">             id          =&gt; {TYPE =&gt; 'SMALLSERIAL', NOTNULL =&gt; 1,
</span><span class="cx">                             PRIMARYKEY =&gt; 1},
</span><span class="cx">             name        =&gt; {TYPE =&gt; 'varchar(64)', NOTNULL =&gt; 1},
</span><del>-            description =&gt; {TYPE =&gt; 'MEDIUMTEXT'},
</del><ins>+            description =&gt; {TYPE =&gt; 'MEDIUMTEXT', NOTNULL =&gt; 1},
</ins><span class="cx">         ],
</span><span class="cx">         INDEXES =&gt; [
</span><span class="cx">             keyworddefs_name_idx   =&gt; {FIELDS =&gt; ['name'],
</span><span class="lines">@@ -453,8 +546,15 @@
</span><span class="cx"> 
</span><span class="cx">     keywords =&gt; {
</span><span class="cx">         FIELDS =&gt; [
</span><del>-            bug_id    =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1},
-            keywordid =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1},
</del><ins>+            bug_id    =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                          REFERENCES =&gt; {TABLE  =&gt; 'bugs',
+                                         COLUMN =&gt; 'bug_id',
+                                         DELETE =&gt; 'CASCADE'}},
+            keywordid =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1,
+                          REFERENCES =&gt; {TABLE  =&gt; 'keyworddefs',
+                                         COLUMN =&gt; 'id',
+                                         DELETE =&gt; 'CASCADE'}},
+
</ins><span class="cx">         ],
</span><span class="cx">         INDEXES =&gt; [
</span><span class="cx">             keywords_bug_id_idx    =&gt; {FIELDS =&gt; [qw(bug_id keywordid)],
</span><span class="lines">@@ -471,14 +571,27 @@
</span><span class="cx">         FIELDS =&gt; [
</span><span class="cx">             id                =&gt; {TYPE =&gt; 'MEDIUMSERIAL', NOTNULL =&gt; 1,
</span><span class="cx">                                   PRIMARYKEY =&gt; 1},
</span><del>-            type_id           =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1},
</del><ins>+            type_id           =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1,
+                                  REFERENCES =&gt; {TABLE  =&gt; 'flagtypes',
+                                                 COLUMN =&gt; 'id',
+                                                 DELETE =&gt; 'CASCADE'}},
</ins><span class="cx">             status            =&gt; {TYPE =&gt; 'char(1)', NOTNULL =&gt; 1},
</span><del>-            bug_id            =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1},
-            attach_id         =&gt; {TYPE =&gt; 'INT3'},
</del><ins>+            bug_id            =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                                  REFERENCES =&gt; {TABLE  =&gt; 'bugs',
+                                                 COLUMN =&gt; 'bug_id',
+                                                 DELETE =&gt; 'CASCADE'}},
+            attach_id         =&gt; {TYPE =&gt; 'INT3',
+                                  REFERENCES =&gt; {TABLE  =&gt; 'attachments',
+                                                 COLUMN =&gt; 'attach_id',
+                                                 DELETE =&gt; 'CASCADE'}},
</ins><span class="cx">             creation_date     =&gt; {TYPE =&gt; 'DATETIME', NOTNULL =&gt; 1},
</span><span class="cx">             modification_date =&gt; {TYPE =&gt; 'DATETIME'},
</span><del>-            setter_id         =&gt; {TYPE =&gt; 'INT3'},
-            requestee_id      =&gt; {TYPE =&gt; 'INT3'},
</del><ins>+            setter_id         =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                                  REFERENCES =&gt; {TABLE  =&gt; 'profiles',
+                                                 COLUMN =&gt; 'userid'}},
+            requestee_id      =&gt; {TYPE =&gt; 'INT3',
+                                  REFERENCES =&gt; {TABLE  =&gt; 'profiles',
+                                                 COLUMN =&gt; 'userid'}},
</ins><span class="cx">         ],
</span><span class="cx">         INDEXES =&gt; [
</span><span class="cx">             flags_bug_id_idx       =&gt; [qw(bug_id attach_id)],
</span><span class="lines">@@ -508,8 +621,14 @@
</span><span class="cx">                                  DEFAULT =&gt; 'FALSE'},
</span><span class="cx">             sortkey          =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1,
</span><span class="cx">                                  DEFAULT =&gt; '0'},
</span><del>-            grant_group_id   =&gt; {TYPE =&gt; 'INT3'},
-            request_group_id =&gt; {TYPE =&gt; 'INT3'},
</del><ins>+            grant_group_id   =&gt; {TYPE =&gt; 'INT3',
+                                 REFERENCES =&gt; {TABLE  =&gt; 'groups',
+                                                COLUMN =&gt; 'id',
+                                                DELETE =&gt; 'SET NULL'}},
+            request_group_id =&gt; {TYPE =&gt; 'INT3',
+                                 REFERENCES =&gt; {TABLE  =&gt; 'groups',
+                                                COLUMN =&gt; 'id',
+                                                DELETE =&gt; 'SET NULL'}},
</ins><span class="cx">         ],
</span><span class="cx">     },
</span><span class="cx"> 
</span><span class="lines">@@ -518,9 +637,18 @@
</span><span class="cx">     #     to be set for them.
</span><span class="cx">     flaginclusions =&gt; {
</span><span class="cx">         FIELDS =&gt; [
</span><del>-            type_id      =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1},
-            product_id   =&gt; {TYPE =&gt; 'INT2'},
-            component_id =&gt; {TYPE =&gt; 'INT2'},
</del><ins>+            type_id      =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1,
+                             REFERENCES =&gt; {TABLE  =&gt; 'flagtypes',
+                                            COLUMN =&gt; 'id',
+                                            DELETE =&gt; 'CASCADE'}},
+            product_id   =&gt; {TYPE =&gt; 'INT2',
+                             REFERENCES =&gt; {TABLE  =&gt; 'products',
+                                            COLUMN =&gt; 'id',
+                                            DELETE =&gt; 'CASCADE'}},
+            component_id =&gt; {TYPE =&gt; 'INT2',
+                             REFERENCES =&gt; {TABLE  =&gt; 'components',
+                                            COLUMN =&gt; 'id',
+                                            DELETE =&gt; 'CASCADE'}},
</ins><span class="cx">         ],
</span><span class="cx">         INDEXES =&gt; [
</span><span class="cx">             flaginclusions_type_id_idx =&gt;
</span><span class="lines">@@ -530,9 +658,18 @@
</span><span class="cx"> 
</span><span class="cx">     flagexclusions =&gt; {
</span><span class="cx">         FIELDS =&gt; [
</span><del>-            type_id      =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1},
-            product_id   =&gt; {TYPE =&gt; 'INT2'},
-            component_id =&gt; {TYPE =&gt; 'INT2'},
</del><ins>+            type_id      =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1,
+                             REFERENCES =&gt; {TABLE  =&gt; 'flagtypes',
+                                            COLUMN =&gt; 'id',
+                                            DELETE =&gt; 'CASCADE'}},
+            product_id   =&gt; {TYPE =&gt; 'INT2',
+                             REFERENCES =&gt; {TABLE  =&gt; 'products',
+                                            COLUMN =&gt; 'id',
+                                            DELETE =&gt; 'CASCADE'}},
+            component_id =&gt; {TYPE =&gt; 'INT2',
+                             REFERENCES =&gt; {TABLE  =&gt; 'components',
+                                            COLUMN =&gt; 'id',
+                                            DELETE =&gt; 'CASCADE'}},
</ins><span class="cx">         ],
</span><span class="cx">         INDEXES =&gt; [
</span><span class="cx">             flagexclusions_type_id_idx =&gt;
</span><span class="lines">@@ -560,14 +697,48 @@
</span><span class="cx">                             DEFAULT =&gt; 'FALSE'},
</span><span class="cx">             enter_bug   =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1,
</span><span class="cx">                             DEFAULT =&gt; 'FALSE'},
</span><ins>+            buglist     =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1,
+                            DEFAULT =&gt; 'FALSE'},
+            visibility_field_id =&gt; {TYPE =&gt; 'INT3', 
+                                    REFERENCES =&gt; {TABLE  =&gt; 'fielddefs',
+                                                   COLUMN =&gt; 'id'}},
+            value_field_id =&gt; {TYPE =&gt; 'INT3',
+                               REFERENCES =&gt; {TABLE  =&gt; 'fielddefs',
+                                              COLUMN =&gt; 'id'}},
+            reverse_desc =&gt; {TYPE =&gt; 'TINYTEXT'},
+            is_mandatory =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1,
+                             DEFAULT =&gt; 'FALSE'},
+            is_numeric    =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1,
+                             DEFAULT =&gt; 'FALSE'},
</ins><span class="cx">         ],
</span><span class="cx">         INDEXES =&gt; [
</span><span class="cx">             fielddefs_name_idx    =&gt; {FIELDS =&gt; ['name'],
</span><span class="cx">                                       TYPE =&gt; 'UNIQUE'},
</span><span class="cx">             fielddefs_sortkey_idx =&gt; ['sortkey'],
</span><ins>+            fielddefs_value_field_id_idx =&gt; ['value_field_id'],
+            fielddefs_is_mandatory_idx =&gt; ['is_mandatory'],
</ins><span class="cx">         ],
</span><span class="cx">     },
</span><span class="cx"> 
</span><ins>+    # Field Visibility Information
+    # -------------------------
+
+    field_visibility =&gt; {
+        FIELDS =&gt; [
+            field_id =&gt; {TYPE =&gt; 'INT3', 
+                         REFERENCES =&gt; {TABLE  =&gt; 'fielddefs',
+                                        COLUMN =&gt; 'id',
+                                        DELETE =&gt; 'CASCADE'}},
+            value_id =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1}
+        ],
+        INDEXES =&gt; [
+            field_visibility_field_id_idx =&gt; {
+                FIELDS =&gt; [qw(field_id value_id)],
+                TYPE   =&gt; 'UNIQUE'
+            },
+        ],
+    },
+
</ins><span class="cx">     # Per-product Field Values
</span><span class="cx">     # ------------------------
</span><span class="cx"> 
</span><span class="lines">@@ -576,7 +747,12 @@
</span><span class="cx">             id         =&gt;  {TYPE =&gt; 'MEDIUMSERIAL', NOTNULL =&gt; 1,
</span><span class="cx">                             PRIMARYKEY =&gt; 1},
</span><span class="cx">             value      =&gt;  {TYPE =&gt; 'varchar(64)', NOTNULL =&gt; 1},
</span><del>-            product_id =&gt;  {TYPE =&gt; 'INT2', NOTNULL =&gt; 1},
</del><ins>+            product_id =&gt;  {TYPE =&gt; 'INT2', NOTNULL =&gt; 1,
+                            REFERENCES =&gt; {TABLE  =&gt; 'products',
+                                           COLUMN =&gt; 'id',
+                                           DELETE =&gt; 'CASCADE'}},
+            isactive   =&gt;  {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1, 
+                            DEFAULT =&gt; 'TRUE'},
</ins><span class="cx">         ],
</span><span class="cx">         INDEXES =&gt; [
</span><span class="cx">             versions_product_id_idx =&gt; {FIELDS =&gt; [qw(product_id value)],
</span><span class="lines">@@ -588,10 +764,15 @@
</span><span class="cx">         FIELDS =&gt; [
</span><span class="cx">             id         =&gt; {TYPE =&gt; 'MEDIUMSERIAL', NOTNULL =&gt; 1, 
</span><span class="cx">                            PRIMARYKEY =&gt; 1},
</span><del>-            product_id =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1},
</del><ins>+            product_id =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1,
+                           REFERENCES =&gt; {TABLE  =&gt; 'products',
+                                          COLUMN =&gt; 'id',
+                                          DELETE =&gt; 'CASCADE'}},
</ins><span class="cx">             value      =&gt; {TYPE =&gt; 'varchar(20)', NOTNULL =&gt; 1},
</span><span class="cx">             sortkey    =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1,
</span><span class="cx">                            DEFAULT =&gt; 0},
</span><ins>+            isactive   =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1, 
+                           DEFAULT =&gt; 'TRUE'},
</ins><span class="cx">         ],
</span><span class="cx">         INDEXES =&gt; [
</span><span class="cx">             milestones_product_id_idx =&gt; {FIELDS =&gt; [qw(product_id value)],
</span><span class="lines">@@ -604,106 +785,79 @@
</span><span class="cx"> 
</span><span class="cx">     bug_status =&gt; {
</span><span class="cx">         FIELDS =&gt; [
</span><del>-            id       =&gt; {TYPE =&gt; 'SMALLSERIAL', NOTNULL =&gt; 1,
-                         PRIMARYKEY =&gt; 1},
-            value    =&gt; {TYPE =&gt; 'varchar(64)', NOTNULL =&gt; 1},
-            sortkey  =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1, DEFAULT =&gt; 0},
-            isactive =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1, 
-                         DEFAULT =&gt; 'TRUE'},
</del><ins>+            @{ dclone(FIELD_TABLE_SCHEMA-&gt;{FIELDS}) },
</ins><span class="cx">             is_open  =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1, DEFAULT =&gt; 'TRUE'},
</span><ins>+
</ins><span class="cx">         ],
</span><span class="cx">         INDEXES =&gt; [
</span><span class="cx">             bug_status_value_idx  =&gt; {FIELDS =&gt; ['value'],
</span><span class="cx">                                        TYPE =&gt; 'UNIQUE'},
</span><span class="cx">             bug_status_sortkey_idx =&gt; ['sortkey', 'value'],
</span><ins>+            bug_status_visibility_value_id_idx =&gt; ['visibility_value_id'],
</ins><span class="cx">         ],
</span><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     resolution =&gt; {
</span><del>-        FIELDS =&gt; [
-            id       =&gt; {TYPE =&gt; 'SMALLSERIAL', NOTNULL =&gt; 1,
-                         PRIMARYKEY =&gt; 1},
-            value    =&gt; {TYPE =&gt; 'varchar(64)', NOTNULL =&gt; 1},
-            sortkey  =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1, DEFAULT =&gt; 0},
-            isactive =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1, 
-                         DEFAULT =&gt; 'TRUE'},
-        ],
</del><ins>+        FIELDS =&gt; dclone(FIELD_TABLE_SCHEMA-&gt;{FIELDS}),
</ins><span class="cx">         INDEXES =&gt; [
</span><span class="cx">             resolution_value_idx   =&gt; {FIELDS =&gt; ['value'],
</span><span class="cx">                                        TYPE =&gt; 'UNIQUE'},
</span><span class="cx">             resolution_sortkey_idx =&gt; ['sortkey', 'value'],
</span><ins>+            resolution_visibility_value_id_idx =&gt; ['visibility_value_id'],
</ins><span class="cx">         ],
</span><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     bug_severity =&gt; {
</span><del>-        FIELDS =&gt; [
-            id       =&gt; {TYPE =&gt; 'SMALLSERIAL', NOTNULL =&gt; 1, 
-                         PRIMARYKEY =&gt; 1},
-            value    =&gt; {TYPE =&gt; 'varchar(64)', NOTNULL =&gt; 1},
-            sortkey  =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1, DEFAULT =&gt; 0},
-            isactive =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1, 
-                         DEFAULT =&gt; 'TRUE'},
-        ],
</del><ins>+        FIELDS =&gt; dclone(FIELD_TABLE_SCHEMA-&gt;{FIELDS}),
</ins><span class="cx">         INDEXES =&gt; [
</span><span class="cx">             bug_severity_value_idx   =&gt; {FIELDS =&gt; ['value'],
</span><span class="cx">                                          TYPE =&gt; 'UNIQUE'},
</span><span class="cx">             bug_severity_sortkey_idx =&gt; ['sortkey', 'value'],
</span><ins>+            bug_severity_visibility_value_id_idx =&gt; ['visibility_value_id'],
</ins><span class="cx">         ],
</span><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     priority =&gt; {
</span><del>-        FIELDS =&gt; [
-            id       =&gt; {TYPE =&gt; 'SMALLSERIAL', NOTNULL =&gt; 1,
-                         PRIMARYKEY =&gt; 1},
-            value    =&gt; {TYPE =&gt; 'varchar(64)', NOTNULL =&gt; 1},
-            sortkey  =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1, DEFAULT =&gt; 0},
-            isactive =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1, 
-                         DEFAULT =&gt; 'TRUE'},
-        ],
</del><ins>+        FIELDS =&gt; dclone(FIELD_TABLE_SCHEMA-&gt;{FIELDS}),
</ins><span class="cx">         INDEXES =&gt; [
</span><span class="cx">             priority_value_idx   =&gt; {FIELDS =&gt; ['value'],
</span><span class="cx">                                      TYPE =&gt; 'UNIQUE'},
</span><span class="cx">             priority_sortkey_idx =&gt; ['sortkey', 'value'],
</span><ins>+            priority_visibility_value_id_idx =&gt; ['visibility_value_id'],
</ins><span class="cx">         ],
</span><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     rep_platform =&gt; {
</span><del>-        FIELDS =&gt; [
-            id       =&gt; {TYPE =&gt; 'SMALLSERIAL', NOTNULL =&gt; 1,
-                         PRIMARYKEY =&gt; 1},
-            value    =&gt; {TYPE =&gt; 'varchar(64)', NOTNULL =&gt; 1},
-            sortkey  =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1, DEFAULT =&gt; 0},
-            isactive =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1, 
-                         DEFAULT =&gt; 'TRUE'},
-        ],
</del><ins>+        FIELDS =&gt; dclone(FIELD_TABLE_SCHEMA-&gt;{FIELDS}),
</ins><span class="cx">         INDEXES =&gt; [
</span><span class="cx">             rep_platform_value_idx   =&gt; {FIELDS =&gt; ['value'],
</span><span class="cx">                                          TYPE =&gt; 'UNIQUE'},
</span><span class="cx">             rep_platform_sortkey_idx =&gt; ['sortkey', 'value'],
</span><ins>+            rep_platform_visibility_value_id_idx =&gt; ['visibility_value_id'],
</ins><span class="cx">         ],
</span><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     op_sys =&gt; {
</span><del>-        FIELDS =&gt; [
-            id       =&gt; {TYPE =&gt; 'SMALLSERIAL', NOTNULL =&gt; 1,
-                         PRIMARYKEY =&gt; 1},
-            value    =&gt; {TYPE =&gt; 'varchar(64)', NOTNULL =&gt; 1},
-            sortkey  =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1, DEFAULT =&gt; 0},
-            isactive =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1, 
-                         DEFAULT =&gt; 'TRUE'},
-        ],
</del><ins>+        FIELDS =&gt; dclone(FIELD_TABLE_SCHEMA-&gt;{FIELDS}),
</ins><span class="cx">         INDEXES =&gt; [
</span><span class="cx">             op_sys_value_idx   =&gt; {FIELDS =&gt; ['value'],
</span><span class="cx">                                    TYPE =&gt; 'UNIQUE'},
</span><span class="cx">             op_sys_sortkey_idx =&gt; ['sortkey', 'value'],
</span><ins>+            op_sys_visibility_value_id_idx =&gt; ['visibility_value_id'],
</ins><span class="cx">         ],
</span><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     status_workflow =&gt; {
</span><span class="cx">         FIELDS =&gt; [
</span><span class="cx">             # On bug creation, there is no old value.
</span><del>-            old_status      =&gt; {TYPE =&gt; 'INT2'},
-            new_status      =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1},
</del><ins>+            old_status      =&gt; {TYPE =&gt; 'INT2',
+                                REFERENCES =&gt; {TABLE  =&gt; 'bug_status', 
+                                               COLUMN =&gt; 'id',
+                                               DELETE =&gt; 'CASCADE'}},
+            new_status      =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1,
+                                REFERENCES =&gt; {TABLE  =&gt; 'bug_status', 
+                                               COLUMN =&gt; 'id',
+                                               DELETE =&gt; 'CASCADE'}},
</ins><span class="cx">             require_comment =&gt; {TYPE =&gt; 'INT1', NOTNULL =&gt; 1, DEFAULT =&gt; 0},
</span><span class="cx">         ],
</span><span class="cx">         INDEXES =&gt; [
</span><span class="lines">@@ -733,13 +887,32 @@
</span><span class="cx">             mybugslink     =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1,
</span><span class="cx">                                DEFAULT =&gt; 'TRUE'},
</span><span class="cx">             extern_id      =&gt; {TYPE =&gt; 'varchar(64)'},
</span><ins>+            is_enabled     =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1, 
+                               DEFAULT =&gt; 'TRUE'}, 
</ins><span class="cx">         ],
</span><span class="cx">         INDEXES =&gt; [
</span><span class="cx">             profiles_login_name_idx =&gt; {FIELDS =&gt; ['login_name'],
</span><span class="cx">                                         TYPE =&gt; 'UNIQUE'},
</span><ins>+            profiles_extern_id_idx =&gt; {FIELDS =&gt; ['extern_id'],
+                                       TYPE   =&gt; 'UNIQUE'}
</ins><span class="cx">         ],
</span><span class="cx">     },
</span><span class="cx"> 
</span><ins>+    profile_search =&gt; {
+        FIELDS =&gt; [
+            id         =&gt; {TYPE =&gt; 'INTSERIAL', NOTNULL =&gt; 1, PRIMARYKEY =&gt; 1},
+            user_id    =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1, 
+                           REFERENCES =&gt; {TABLE  =&gt; 'profiles', 
+                                          COLUMN =&gt; 'userid', 
+                                          DELETE =&gt; 'CASCADE'}},
+            bug_list   =&gt; {TYPE =&gt; 'MEDIUMTEXT', NOTNULL =&gt; 1},
+            list_order =&gt; {TYPE =&gt; 'MEDIUMTEXT'},
+        ],
+        INDEXES =&gt; [
+            profile_search_user_id_idx =&gt; [qw(user_id)],
+        ],
+    },
+
</ins><span class="cx">     profiles_activity =&gt; {
</span><span class="cx">         FIELDS =&gt; [
</span><span class="cx">             userid        =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
</span><span class="lines">@@ -807,7 +980,6 @@
</span><span class="cx">                                             DELETE =&gt; 'CASCADE'}},
</span><span class="cx">             name         =&gt; {TYPE =&gt; 'varchar(64)', NOTNULL =&gt; 1},
</span><span class="cx">             query        =&gt; {TYPE =&gt; 'LONGTEXT', NOTNULL =&gt; 1},
</span><del>-            query_type   =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1, DEFAULT =&gt; 0},
</del><span class="cx">         ],
</span><span class="cx">         INDEXES =&gt; [
</span><span class="cx">             namedqueries_userid_idx =&gt; {FIELDS =&gt; [qw(userid name)],
</span><span class="lines">@@ -833,6 +1005,36 @@
</span><span class="cx">         ],
</span><span class="cx">     },
</span><span class="cx"> 
</span><ins>+    tag =&gt; {
+        FIELDS =&gt; [
+            id   =&gt; {TYPE =&gt; 'MEDIUMSERIAL', NOTNULL =&gt; 1, PRIMARYKEY =&gt; 1},
+            name =&gt; {TYPE =&gt; 'varchar(64)', NOTNULL =&gt; 1},
+            user_id  =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                         REFERENCES =&gt; {TABLE  =&gt; 'profiles',
+                                        COLUMN =&gt; 'userid',
+                                        DELETE =&gt; 'CASCADE'}},
+        ],
+        INDEXES =&gt; [
+            tag_user_id_idx =&gt; {FIELDS =&gt; [qw(user_id name)], TYPE =&gt; 'UNIQUE'},
+        ],
+    },
+
+    bug_tag =&gt; {
+        FIELDS =&gt; [
+            bug_id =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                       REFERENCES =&gt; {TABLE  =&gt; 'bugs',
+                                      COLUMN =&gt; 'bug_id',
+                                      DELETE =&gt; 'CASCADE'}},
+            tag_id =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                       REFERENCES =&gt; {TABLE  =&gt; 'tag',
+                                      COLUMN =&gt; 'id',
+                                      DELETE =&gt; 'CASCADE'}},
+        ],
+        INDEXES =&gt; [
+            bug_tag_bug_id_idx =&gt; {FIELDS =&gt; [qw(bug_id tag_id)], TYPE =&gt; 'UNIQUE'},
+        ],
+    },
+
</ins><span class="cx">     component_cc =&gt; {
</span><span class="cx"> 
</span><span class="cx">         FIELDS =&gt; [
</span><span class="lines">@@ -840,7 +1042,10 @@
</span><span class="cx">                              REFERENCES =&gt; {TABLE  =&gt; 'profiles',
</span><span class="cx">                                             COLUMN =&gt; 'userid',
</span><span class="cx">                                             DELETE =&gt; 'CASCADE'}},
</span><del>-            component_id =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1},
</del><ins>+            component_id =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1,
+                             REFERENCES =&gt; {TABLE  =&gt; 'components',
+                                            COLUMN =&gt; 'id',
+                                            DELETE =&gt; 'CASCADE'}},
</ins><span class="cx">         ],
</span><span class="cx">         INDEXES =&gt; [
</span><span class="cx">             component_cc_user_id_idx =&gt; {FIELDS =&gt; [qw(component_id user_id)],
</span><span class="lines">@@ -859,7 +1064,7 @@
</span><span class="cx">                          REFERENCES =&gt; {TABLE  =&gt; 'profiles',
</span><span class="cx">                                         COLUMN =&gt; 'userid',
</span><span class="cx">                                         DELETE =&gt; 'CASCADE'}},
</span><del>-            ipaddr   =&gt; {TYPE =&gt; 'varchar(40)', NOTNULL =&gt; 1},
</del><ins>+            ipaddr   =&gt; {TYPE =&gt; 'varchar(40)'},
</ins><span class="cx">             lastused =&gt; {TYPE =&gt; 'DATETIME', NOTNULL =&gt; 1},
</span><span class="cx">         ],
</span><span class="cx">         INDEXES =&gt; [
</span><span class="lines">@@ -867,6 +1072,25 @@
</span><span class="cx">         ],
</span><span class="cx">     },
</span><span class="cx"> 
</span><ins>+    login_failure =&gt; {
+        FIELDS =&gt; [
+            user_id    =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                           REFERENCES =&gt; {TABLE  =&gt; 'profiles',
+                                          COLUMN =&gt; 'userid',
+                                          DELETE =&gt; 'CASCADE'}},
+            login_time =&gt; {TYPE =&gt; 'DATETIME', NOTNULL =&gt; 1},
+            ip_addr    =&gt; {TYPE =&gt; 'varchar(40)', NOTNULL =&gt; 1},
+        ],
+        INDEXES =&gt; [
+            # We do lookups by every item in the table simultaneously, but 
+            # having an index with all three items would be the same size as
+            # the table. So instead we have an index on just the smallest item, 
+            # to speed lookups.
+            login_failure_user_id_idx =&gt; ['user_id'],
+        ],
+    },
+
+
</ins><span class="cx">     # &quot;tokens&quot; stores the tokens users receive when a password or email
</span><span class="cx">     #     change is requested.  Tokens provide an extra measure of security
</span><span class="cx">     #     for these changes.
</span><span class="lines">@@ -909,12 +1133,22 @@
</span><span class="cx"> 
</span><span class="cx">     group_control_map =&gt; {
</span><span class="cx">         FIELDS =&gt; [
</span><del>-            group_id      =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1},
-            product_id    =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1},
-            entry         =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1},
-            membercontrol =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1},
-            othercontrol  =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1},
-            canedit       =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1},
</del><ins>+            group_id      =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                              REFERENCES =&gt; {TABLE  =&gt; 'groups',
+                                             COLUMN =&gt; 'id',
+                                             DELETE =&gt; 'CASCADE'}},
+            product_id    =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1,
+                              REFERENCES =&gt; {TABLE  =&gt;  'products',
+                                             COLUMN =&gt;  'id',
+                                             DELETE =&gt;  'CASCADE'}},
+            entry         =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1,
+                              DEFAULT =&gt; 'FALSE'},
+            membercontrol =&gt; {TYPE =&gt; 'INT1', NOTNULL =&gt; 1,
+                              DEFAULT =&gt; CONTROLMAPNA},
+            othercontrol  =&gt; {TYPE =&gt; 'INT1', NOTNULL =&gt; 1,
+                              DEFAULT =&gt; CONTROLMAPNA},
+            canedit       =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1,
+                              DEFAULT =&gt; 'FALSE'},
</ins><span class="cx">             editcomponents =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1,
</span><span class="cx">                                DEFAULT =&gt; 'FALSE'},
</span><span class="cx">             editbugs      =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1,
</span><span class="lines">@@ -938,8 +1172,14 @@
</span><span class="cx">     # if GRANT_REGEXP - record was created by evaluating a regexp
</span><span class="cx">     user_group_map =&gt; {
</span><span class="cx">         FIELDS =&gt; [
</span><del>-            user_id    =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1},
-            group_id   =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1},
</del><ins>+            user_id    =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                           REFERENCES =&gt; {TABLE  =&gt; 'profiles',
+                                          COLUMN =&gt; 'userid',
+                                          DELETE =&gt; 'CASCADE'}},
+            group_id   =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                           REFERENCES =&gt; {TABLE  =&gt; 'groups',
+                                          COLUMN =&gt; 'id',
+                                          DELETE =&gt; 'CASCADE'}},
</ins><span class="cx">             isbless    =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1,
</span><span class="cx">                            DEFAULT =&gt; 'FALSE'},
</span><span class="cx">             grant_type =&gt; {TYPE =&gt; 'INT1', NOTNULL =&gt; 1,
</span><span class="lines">@@ -961,8 +1201,14 @@
</span><span class="cx">     # if GROUP_VISIBLE - member groups may see grantor group
</span><span class="cx">     group_group_map =&gt; {
</span><span class="cx">         FIELDS =&gt; [
</span><del>-            member_id  =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1},
-            grantor_id =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1},
</del><ins>+            member_id  =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                           REFERENCES =&gt; {TABLE  =&gt; 'groups',
+                                          COLUMN =&gt; 'id',
+                                          DELETE =&gt; 'CASCADE'}},
+            grantor_id =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                           REFERENCES =&gt; {TABLE  =&gt; 'groups',
+                                          COLUMN =&gt; 'id',
+                                          DELETE =&gt; 'CASCADE'}},
</ins><span class="cx">             grant_type =&gt; {TYPE =&gt; 'INT1', NOTNULL =&gt; 1,
</span><span class="cx">                            DEFAULT =&gt; GROUP_MEMBERSHIP},
</span><span class="cx">         ],
</span><span class="lines">@@ -977,8 +1223,14 @@
</span><span class="cx">     # in order to see a bug.
</span><span class="cx">     bug_group_map =&gt; {
</span><span class="cx">         FIELDS =&gt; [
</span><del>-            bug_id   =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1},
-            group_id =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1},
</del><ins>+            bug_id   =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                         REFERENCES =&gt; {TABLE  =&gt; 'bugs',
+                                        COLUMN =&gt; 'bug_id',
+                                        DELETE =&gt; 'CASCADE'}},
+            group_id =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                         REFERENCES =&gt; {TABLE  =&gt; 'groups',
+                                        COLUMN =&gt; 'id',
+                                        DELETE =&gt; 'CASCADE'}},
</ins><span class="cx">         ],
</span><span class="cx">         INDEXES =&gt; [
</span><span class="cx">             bug_group_map_bug_id_idx   =&gt;
</span><span class="lines">@@ -991,8 +1243,14 @@
</span><span class="cx">     # in order to see a named query somebody else shares.
</span><span class="cx">     namedquery_group_map =&gt; {
</span><span class="cx">         FIELDS =&gt; [
</span><del>-            namedquery_id =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1},
-            group_id      =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1},
</del><ins>+            namedquery_id =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                              REFERENCES =&gt; {TABLE  =&gt; 'namedqueries',
+                                             COLUMN =&gt; 'id',
+                                             DELETE =&gt; 'CASCADE'}},
+            group_id      =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                              REFERENCES =&gt; {TABLE  =&gt; 'groups',
+                                             COLUMN =&gt; 'id',
+                                             DELETE =&gt; 'CASCADE'}},
</ins><span class="cx">         ],
</span><span class="cx">         INDEXES =&gt; [
</span><span class="cx">             namedquery_group_map_namedquery_id_idx   =&gt;
</span><span class="lines">@@ -1003,8 +1261,14 @@
</span><span class="cx"> 
</span><span class="cx">     category_group_map =&gt; {
</span><span class="cx">         FIELDS =&gt; [
</span><del>-            category_id =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1},
-            group_id    =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1},
</del><ins>+            category_id =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1,
+                            REFERENCES =&gt; {TABLE  =&gt; 'series_categories',
+                                           COLUMN =&gt;  'id',
+                                           DELETE =&gt; 'CASCADE'}},
+            group_id    =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                            REFERENCES =&gt; {TABLE  =&gt; 'groups',
+                                           COLUMN =&gt; 'id',
+                                           DELETE =&gt; 'CASCADE'}},
</ins><span class="cx">         ],
</span><span class="cx">         INDEXES =&gt; [
</span><span class="cx">             category_group_map_category_id_idx =&gt;
</span><span class="lines">@@ -1036,20 +1300,17 @@
</span><span class="cx">                                   PRIMARYKEY =&gt; 1},
</span><span class="cx">             name              =&gt; {TYPE =&gt; 'varchar(64)', NOTNULL =&gt; 1},
</span><span class="cx">             classification_id =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1,
</span><del>-                                  DEFAULT =&gt; '1'},
-            description       =&gt; {TYPE =&gt; 'MEDIUMTEXT'},
-            milestoneurl      =&gt; {TYPE =&gt; 'TINYTEXT', NOTNULL =&gt; 1,
-                                  DEFAULT =&gt; &quot;''&quot;},
-            disallownew       =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1,
-                                  DEFAULT =&gt; 0},
-            votesperuser      =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1,
-                                  DEFAULT =&gt; 0},
-            maxvotesperbug    =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1,
-                                  DEFAULT =&gt; '10000'},
-            votestoconfirm    =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1,
-                                  DEFAULT =&gt; 0},
</del><ins>+                                  DEFAULT =&gt; '1',
+                                  REFERENCES =&gt; {TABLE  =&gt; 'classifications',
+                                                 COLUMN =&gt; 'id',
+                                                 DELETE =&gt; 'CASCADE'}},
+            description       =&gt; {TYPE =&gt; 'MEDIUMTEXT', NOTNULL =&gt; 1},
+            isactive          =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1,
+                                  DEFAULT =&gt; 1},
</ins><span class="cx">             defaultmilestone  =&gt; {TYPE =&gt; 'varchar(20)',
</span><span class="cx">                                   NOTNULL =&gt; 1, DEFAULT =&gt; &quot;'---'&quot;},
</span><ins>+            allows_unconfirmed =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1,
+                                   DEFAULT =&gt; 'TRUE'},
</ins><span class="cx">         ],
</span><span class="cx">         INDEXES =&gt; [
</span><span class="cx">             products_name_idx   =&gt; {FIELDS =&gt; ['name'],
</span><span class="lines">@@ -1062,7 +1323,10 @@
</span><span class="cx">             id               =&gt; {TYPE =&gt; 'SMALLSERIAL', NOTNULL =&gt; 1,
</span><span class="cx">                                  PRIMARYKEY =&gt; 1},
</span><span class="cx">             name             =&gt; {TYPE =&gt; 'varchar(64)', NOTNULL =&gt; 1},
</span><del>-            product_id       =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1},
</del><ins>+            product_id       =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1,
+                                 REFERENCES =&gt; {TABLE  =&gt; 'products',
+                                                COLUMN =&gt; 'id',
+                                                DELETE =&gt; 'CASCADE'}},
</ins><span class="cx">             initialowner     =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
</span><span class="cx">                                  REFERENCES =&gt; {TABLE  =&gt; 'profiles',
</span><span class="cx">                                                 COLUMN =&gt; 'userid'}},
</span><span class="lines">@@ -1071,6 +1335,8 @@
</span><span class="cx">                                                 COLUMN =&gt; 'userid',
</span><span class="cx">                                                 DELETE =&gt; 'SET NULL'}},
</span><span class="cx">             description      =&gt; {TYPE =&gt; 'MEDIUMTEXT', NOTNULL =&gt; 1},
</span><ins>+            isactive         =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1, 
+                                 DEFAULT =&gt; 'TRUE'},
</ins><span class="cx">         ],
</span><span class="cx">         INDEXES =&gt; [
</span><span class="cx">             components_product_id_idx =&gt; {FIELDS =&gt; [qw(product_id name)],
</span><span class="lines">@@ -1086,26 +1352,37 @@
</span><span class="cx">         FIELDS =&gt; [
</span><span class="cx">             series_id   =&gt; {TYPE =&gt; 'MEDIUMSERIAL', NOTNULL =&gt; 1,
</span><span class="cx">                             PRIMARYKEY =&gt; 1},
</span><del>-            creator     =&gt; {TYPE =&gt; 'INT3'},
-            category    =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1},
-            subcategory =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1},
</del><ins>+            creator     =&gt; {TYPE =&gt; 'INT3',
+                            REFERENCES =&gt; {TABLE  =&gt; 'profiles',
+                                           COLUMN =&gt; 'userid',
+                                           DELETE =&gt; 'CASCADE'}},
+            category    =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1,
+                            REFERENCES =&gt; {TABLE  =&gt; 'series_categories',
+                                           COLUMN =&gt; 'id',
+                                           DELETE =&gt; 'CASCADE'}},
+            subcategory =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1,
+                            REFERENCES =&gt; {TABLE  =&gt; 'series_categories',
+                                           COLUMN =&gt; 'id',
+                                           DELETE =&gt; 'CASCADE'}},
</ins><span class="cx">             name        =&gt; {TYPE =&gt; 'varchar(64)', NOTNULL =&gt; 1},
</span><span class="cx">             frequency   =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1},
</span><del>-            last_viewed =&gt; {TYPE =&gt; 'DATETIME'},
</del><span class="cx">             query       =&gt; {TYPE =&gt; 'MEDIUMTEXT', NOTNULL =&gt; 1},
</span><span class="cx">             is_public   =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1,
</span><span class="cx">                             DEFAULT =&gt; 'FALSE'},
</span><span class="cx">         ],
</span><span class="cx">         INDEXES =&gt; [
</span><del>-            series_creator_idx  =&gt;
-                {FIELDS =&gt; [qw(creator category subcategory name)],
-                 TYPE =&gt; 'UNIQUE'},
</del><ins>+            series_creator_idx  =&gt; ['creator'],
+            series_category_idx =&gt; {FIELDS =&gt; [qw(category subcategory name)],
+                                    TYPE =&gt; 'UNIQUE'},
</ins><span class="cx">         ],
</span><span class="cx">     },
</span><span class="cx"> 
</span><span class="cx">     series_data =&gt; {
</span><span class="cx">         FIELDS =&gt; [
</span><del>-            series_id    =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1},
</del><ins>+            series_id    =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                             REFERENCES =&gt; {TABLE  =&gt; 'series',
+                                            COLUMN =&gt; 'series_id',
+                                            DELETE =&gt; 'CASCADE'}},
</ins><span class="cx">             series_date  =&gt; {TYPE =&gt; 'DATETIME', NOTNULL =&gt; 1},
</span><span class="cx">             series_value =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1},
</span><span class="cx">         ],
</span><span class="lines">@@ -1183,6 +1460,8 @@
</span><span class="cx">                                             DELETE =&gt; 'CASCADE'}},
</span><span class="cx">             subject      =&gt; {TYPE =&gt; 'varchar(128)'},
</span><span class="cx">             body         =&gt; {TYPE =&gt; 'MEDIUMTEXT'},
</span><ins>+            mailifnobugs =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1,
+                             DEFAULT =&gt; 'FALSE'},
</ins><span class="cx">         ],
</span><span class="cx">     },
</span><span class="cx"> 
</span><span class="lines">@@ -1193,7 +1472,10 @@
</span><span class="cx">         FIELDS =&gt; [
</span><span class="cx">             quipid   =&gt; {TYPE =&gt; 'MEDIUMSERIAL', NOTNULL =&gt; 1,
</span><span class="cx">                          PRIMARYKEY =&gt; 1},
</span><del>-            userid   =&gt; {TYPE =&gt; 'INT3'},
</del><ins>+            userid   =&gt; {TYPE =&gt; 'INT3',
+                         REFERENCES =&gt; {TABLE  =&gt; 'profiles', 
+                                        COLUMN =&gt; 'userid',
+                                        DELETE =&gt; 'SET NULL'}},
</ins><span class="cx">             quip     =&gt; {TYPE =&gt; 'MEDIUMTEXT', NOTNULL =&gt; 1},
</span><span class="cx">             approved =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1,
</span><span class="cx">                          DEFAULT =&gt; 'TRUE'},
</span><span class="lines">@@ -1226,7 +1508,10 @@
</span><span class="cx"> 
</span><span class="cx">     setting_value =&gt; {
</span><span class="cx">         FIELDS =&gt; [
</span><del>-            name        =&gt; {TYPE =&gt; 'varchar(32)', NOTNULL =&gt; 1},
</del><ins>+            name        =&gt; {TYPE =&gt; 'varchar(32)', NOTNULL =&gt; 1,
+                            REFERENCES =&gt; {TABLE  =&gt; 'setting', 
+                                           COLUMN =&gt; 'name',
+                                           DELETE =&gt; 'CASCADE'}},
</ins><span class="cx">             value       =&gt; {TYPE =&gt; 'varchar(32)', NOTNULL =&gt; 1},
</span><span class="cx">             sortindex   =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1},
</span><span class="cx">         ],
</span><span class="lines">@@ -1244,7 +1529,10 @@
</span><span class="cx">                               REFERENCES =&gt; {TABLE  =&gt; 'profiles',
</span><span class="cx">                                              COLUMN =&gt; 'userid',
</span><span class="cx">                                              DELETE =&gt; 'CASCADE'}},
</span><del>-            setting_name  =&gt; {TYPE =&gt; 'varchar(32)', NOTNULL =&gt; 1},
</del><ins>+            setting_name  =&gt; {TYPE =&gt; 'varchar(32)', NOTNULL =&gt; 1,
+                              REFERENCES =&gt; {TABLE  =&gt; 'setting',
+                                             COLUMN =&gt; 'name',
+                                             DELETE =&gt; 'CASCADE'}},
</ins><span class="cx">             setting_value =&gt; {TYPE =&gt; 'varchar(32)', NOTNULL =&gt; 1},
</span><span class="cx">         ],
</span><span class="cx">         INDEXES =&gt; [
</span><span class="lines">@@ -1253,6 +1541,93 @@
</span><span class="cx">         ],
</span><span class="cx">      },
</span><span class="cx"> 
</span><ins>+    # THESCHWARTZ TABLES
+    # ------------------
+    # Note: In the standard TheSchwartz schema, most integers are unsigned,
+    # but we didn't implement unsigned ints for Bugzilla schemas, so we
+    # just create signed ints, which should be fine.
+
+    ts_funcmap =&gt; {
+        FIELDS =&gt; [
+            funcid   =&gt; {TYPE =&gt; 'INTSERIAL', PRIMARYKEY =&gt; 1, NOTNULL =&gt; 1},
+            funcname =&gt; {TYPE =&gt; 'varchar(255)', NOTNULL =&gt; 1},
+        ],
+        INDEXES =&gt; [
+            ts_funcmap_funcname_idx =&gt; {FIELDS =&gt; ['funcname'], 
+                                          TYPE =&gt; 'UNIQUE'},
+        ],
+    },
+
+    ts_job =&gt; {
+        FIELDS =&gt; [
+            # In a standard TheSchwartz schema, this is a BIGINT, but we
+            # don't have those and I didn't want to add them just for this.
+            jobid         =&gt; {TYPE =&gt; 'INTSERIAL', PRIMARYKEY =&gt; 1, 
+                              NOTNULL =&gt; 1},
+            funcid        =&gt; {TYPE =&gt; 'INT4', NOTNULL =&gt; 1},
+            # In standard TheSchwartz, this is a MEDIUMBLOB.
+            arg           =&gt; {TYPE =&gt; 'LONGBLOB'},
+            uniqkey       =&gt; {TYPE =&gt; 'varchar(255)'},
+            insert_time   =&gt; {TYPE =&gt; 'INT4'},
+            run_after     =&gt; {TYPE =&gt; 'INT4', NOTNULL =&gt; 1},
+            grabbed_until =&gt; {TYPE =&gt; 'INT4', NOTNULL =&gt; 1},
+            priority      =&gt; {TYPE =&gt; 'INT2'},
+            coalesce      =&gt; {TYPE =&gt; 'varchar(255)'},
+        ],
+        INDEXES =&gt; [
+            ts_job_funcid_idx =&gt; {FIELDS =&gt; [qw(funcid uniqkey)],
+                                  TYPE   =&gt; 'UNIQUE'},
+            # In a standard TheSchewartz schema, these both go in the other
+            # direction, but there's no reason to have three indexes that
+            # all start with the same column, and our naming scheme doesn't
+            # allow it anyhow.
+            ts_job_run_after_idx =&gt; [qw(run_after funcid)],
+            ts_job_coalesce_idx  =&gt; [qw(coalesce funcid)],
+        ],
+    },
+
+    ts_note =&gt; {
+        FIELDS =&gt; [
+            # This is a BIGINT in standard TheSchwartz schemas.
+            jobid   =&gt; {TYPE =&gt; 'INT4', NOTNULL =&gt; 1},
+            notekey =&gt; {TYPE =&gt; 'varchar(255)'},
+            value   =&gt; {TYPE =&gt; 'LONGBLOB'},
+        ],
+        INDEXES =&gt; [
+            ts_note_jobid_idx =&gt; {FIELDS =&gt; [qw(jobid notekey)], 
+                                    TYPE =&gt; 'UNIQUE'},
+        ],
+    },
+
+    ts_error =&gt; {
+        FIELDS =&gt; [
+            error_time =&gt; {TYPE =&gt; 'INT4', NOTNULL =&gt; 1},
+            jobid      =&gt; {TYPE =&gt; 'INT4', NOTNULL =&gt; 1},
+            message    =&gt; {TYPE =&gt; 'varchar(255)', NOTNULL =&gt; 1},
+            funcid     =&gt; {TYPE =&gt; 'INT4', NOTNULL =&gt; 1, DEFAULT =&gt; 0},
+        ],
+        INDEXES =&gt; [
+            ts_error_funcid_idx     =&gt; [qw(funcid error_time)],
+            ts_error_error_time_idx =&gt; ['error_time'],
+            ts_error_jobid_idx      =&gt; ['jobid'],
+        ],
+    },
+
+    ts_exitstatus =&gt; {
+        FIELDS =&gt; [
+            jobid           =&gt; {TYPE =&gt; 'INTSERIAL', PRIMARYKEY =&gt; 1,
+                                NOTNULL =&gt; 1},
+            funcid          =&gt; {TYPE =&gt; 'INT4', NOTNULL =&gt; 1, DEFAULT =&gt; 0},
+            status          =&gt; {TYPE =&gt; 'INT2'},
+            completion_time =&gt; {TYPE =&gt; 'INT4'},
+            delete_after    =&gt; {TYPE =&gt; 'INT4'},
+        ],
+        INDEXES =&gt; [
+            ts_exitstatus_funcid_idx       =&gt; ['funcid'],
+            ts_exitstatus_delete_after_idx =&gt; ['delete_after'],
+        ],
+    },
+
</ins><span class="cx">     # SCHEMA STORAGE
</span><span class="cx">     # --------------
</span><span class="cx"> 
</span><span class="lines">@@ -1265,23 +1640,7 @@
</span><span class="cx"> 
</span><span class="cx"> };
</span><span class="cx"> 
</span><del>-use constant FIELD_TABLE_SCHEMA =&gt; {
-    FIELDS =&gt; [
-        id       =&gt; {TYPE =&gt; 'SMALLSERIAL', NOTNULL =&gt; 1,
-                     PRIMARYKEY =&gt; 1},
-        value    =&gt; {TYPE =&gt; 'varchar(64)', NOTNULL =&gt; 1},
-        sortkey  =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1, DEFAULT =&gt; 0},
-        isactive =&gt; {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1,
-                     DEFAULT =&gt; 'TRUE'},
-    ],
-    # Note that bz_add_field_table should prepend the table name
-    # to these index names.
-    INDEXES =&gt; [
-        value_idx   =&gt; {FIELDS =&gt; ['value'], TYPE =&gt; 'UNIQUE'},
-        sortkey_idx =&gt; ['sortkey', 'value'],
-    ],
-};
-
</del><ins>+# Foreign Keys are added in Bugzilla::DB::bz_add_field_tables
</ins><span class="cx"> use constant MULTI_SELECT_VALUE_TABLE =&gt; {
</span><span class="cx">     FIELDS =&gt; [
</span><span class="cx">         bug_id =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1},
</span><span class="lines">@@ -1292,7 +1651,6 @@
</span><span class="cx">     ],
</span><span class="cx"> };
</span><span class="cx"> 
</span><del>-
</del><span class="cx"> #--------------------------------------------------------------------------
</span><span class="cx"> 
</span><span class="cx"> =head1 METHODS
</span><span class="lines">@@ -1384,7 +1742,7 @@
</span><span class="cx">                 if exists $abstract_schema-&gt;{$table};
</span><span class="cx">         }
</span><span class="cx">         unlock_keys(%$abstract_schema);
</span><del>-        Bugzilla::Hook::process('db_schema-abstract_schema', 
</del><ins>+        Bugzilla::Hook::process('db_schema_abstract_schema', 
</ins><span class="cx">                                 { schema =&gt; $abstract_schema });
</span><span class="cx">         unlock_hash(%$abstract_schema);
</span><span class="cx">     }
</span><span class="lines">@@ -1490,8 +1848,9 @@
</span><span class="cx">     # DEFAULT attribute must appear before any column constraints
</span><span class="cx">     # (e.g., NOT NULL), for Oracle
</span><span class="cx">     $type_ddl .= &quot; DEFAULT $default&quot; if (defined($default));
</span><ins>+    # PRIMARY KEY must appear before NOT NULL for SQLite.
+    $type_ddl .= &quot; PRIMARY KEY&quot; if ($finfo-&gt;{PRIMARYKEY});
</ins><span class="cx">     $type_ddl .= &quot; NOT NULL&quot; if ($finfo-&gt;{NOTNULL});
</span><del>-    $type_ddl .= &quot; PRIMARY KEY&quot; if ($finfo-&gt;{PRIMARYKEY});
</del><span class="cx"> 
</span><span class="cx">     return($type_ddl);
</span><span class="cx"> 
</span><span class="lines">@@ -1564,13 +1923,35 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-sub get_add_fk_sql {
-    my ($self, $table, $column, $def) = @_;
</del><ins>+sub get_add_fks_sql {
+    my ($self, $table, $column_fks) = @_;
</ins><span class="cx"> 
</span><del>-    my $fk_string = $self-&gt;get_fk_ddl($table, $column, $def);
-    return (&quot;ALTER TABLE $table ADD $fk_string&quot;);
</del><ins>+    my @add = $self-&gt;_column_fks_to_ddl($table, $column_fks);
+
+    my @sql;
+    if ($self-&gt;MULTIPLE_FKS_IN_ALTER) {
+        my $alter = &quot;ALTER TABLE $table ADD &quot; . join(', ADD ', @add);
+        push(@sql, $alter);
+    }
+    else {
+        foreach my $fk_string (@add) {
+            push(@sql, &quot;ALTER TABLE $table ADD $fk_string&quot;);
+        }
+    }
+    return @sql;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub _column_fks_to_ddl {
+    my ($self, $table, $column_fks) = @_;
+    my @ddl;
+    foreach my $column (keys %$column_fks) {
+        my $def = $column_fks-&gt;{$column};
+        my $fk_string = $self-&gt;get_fk_ddl($table, $column, $def);
+        push(@ddl, $fk_string);
+    }
+    return @ddl;
+}
+
</ins><span class="cx"> sub get_drop_fk_sql { 
</span><span class="cx">     my ($self, $table, $column, $references) = @_;
</span><span class="cx">     my $fk_name = $self-&gt;_get_fk_name($table, $column, $references);
</span><span class="lines">@@ -1710,7 +2091,7 @@
</span><span class="cx">     return @ddl;
</span><span class="cx"> 
</span><span class="cx"> } #eosub--get_table_ddl
</span><del>-#--------------------------------------------------------------------------
</del><ins>+
</ins><span class="cx"> sub _get_create_table_ddl {
</span><span class="cx"> 
</span><span class="cx"> =item C&lt;_get_create_table_ddl&gt;
</span><span class="lines">@@ -1726,25 +2107,27 @@
</span><span class="cx"> 
</span><span class="cx">     my $thash = $self-&gt;{schema}{$table};
</span><span class="cx">     die &quot;Table $table does not exist in the database schema.&quot;
</span><del>-        unless (ref($thash));
</del><ins>+        unless ref $thash;
</ins><span class="cx"> 
</span><del>-    my $create_table = &quot;CREATE TABLE $table \(\n&quot;;
-
</del><ins>+    my (@col_lines, @fk_lines);
</ins><span class="cx">     my @fields = @{ $thash-&gt;{FIELDS} };
</span><span class="cx">     while (@fields) {
</span><span class="cx">         my $field = shift(@fields);
</span><span class="cx">         my $finfo = shift(@fields);
</span><del>-        $create_table .= &quot;\t$field\t&quot; . $self-&gt;get_type_ddl($finfo);
-        $create_table .= &quot;,&quot; if (@fields);
-        $create_table .= &quot;\n&quot;;
</del><ins>+        push(@col_lines, &quot;\t$field\t&quot; . $self-&gt;get_type_ddl($finfo));
+        if ($self-&gt;FK_ON_CREATE and $finfo-&gt;{REFERENCES}) {
+            my $fk = $finfo-&gt;{REFERENCES};
+            my $fk_ddl = $self-&gt;get_fk_ddl($table, $field, $fk);
+            push(@fk_lines, $fk_ddl);
+        }
</ins><span class="cx">     }
</span><ins>+    
+    my $sql = &quot;CREATE TABLE $table (\n&quot; . join(&quot;,\n&quot;, @col_lines, @fk_lines)
+              . &quot;\n)&quot;;
+    return $sql
</ins><span class="cx"> 
</span><del>-    $create_table .= &quot;\)&quot;;
</del><ins>+} 
</ins><span class="cx"> 
</span><del>-    return($create_table)
-
-} #eosub--_get_create_table_ddl
-#--------------------------------------------------------------------------
</del><span class="cx"> sub _get_create_index_ddl {
</span><span class="cx"> 
</span><span class="cx"> =item C&lt;_get_create_index_ddl&gt;
</span><span class="lines">@@ -1798,8 +2181,8 @@
</span><span class="cx">         if defined $init_value;
</span><span class="cx"> 
</span><span class="cx">     if (defined $definition-&gt;{REFERENCES}) {
</span><del>-        push(@statements, $self-&gt;get_add_fk_sql($table, $column,
-                                                $definition-&gt;{REFERENCES}));
</del><ins>+        push(@statements, $self-&gt;get_add_fks_sql($table, { $column =&gt;
+                                                           $definition-&gt;{REFERENCES} }));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     return (@statements);
</span><span class="lines">@@ -1859,7 +2242,8 @@
</span><span class="cx"> 
</span><span class="cx"> =cut
</span><span class="cx"> 
</span><del>-    my ($self, $table, $column, $new_def, $set_nulls_to) = @_;
</del><ins>+    my $self = shift;
+    my ($table, $column, $new_def, $set_nulls_to) = @_;
</ins><span class="cx"> 
</span><span class="cx">     my @statements;
</span><span class="cx">     my $old_def = $self-&gt;get_column_abstract($table, $column);
</span><span class="lines">@@ -1873,6 +2257,10 @@
</span><span class="cx"> 
</span><span class="cx">     my $default = $new_def-&gt;{DEFAULT};
</span><span class="cx">     my $default_old = $old_def-&gt;{DEFAULT};
</span><ins>+
+    if (defined $default) {
+        $default = $specific-&gt;{$default} if exists $specific-&gt;{$default};
+    }
</ins><span class="cx">     # This first condition prevents &quot;uninitialized value&quot; errors.
</span><span class="cx">     if (!defined $default &amp;&amp; !defined $default_old) {
</span><span class="cx">         # Do Nothing
</span><span class="lines">@@ -1886,24 +2274,13 @@
</span><span class="cx">     elsif ( (defined $default &amp;&amp; !defined $default_old) || 
</span><span class="cx">             ($default ne $default_old) ) 
</span><span class="cx">     {
</span><del>-        $default = $specific-&gt;{$default} if exists $specific-&gt;{$default};
</del><span class="cx">         push(@statements, &quot;ALTER TABLE $table ALTER COLUMN $column &quot;
</span><span class="cx">                          . &quot; SET DEFAULT $default&quot;);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # If we went from NULL to NOT NULL.
</span><span class="cx">     if (!$old_def-&gt;{NOTNULL} &amp;&amp; $new_def-&gt;{NOTNULL}) {
</span><del>-        my $setdefault;
-        # Handle any fields that were NULL before, if we have a default,
-        $setdefault = $new_def-&gt;{DEFAULT} if exists $new_def-&gt;{DEFAULT};
-        # But if we have a set_nulls_to, that overrides the DEFAULT 
-        # (although nobody would usually specify both a default and 
-        # a set_nulls_to.)
-        $setdefault = $set_nulls_to if defined $set_nulls_to;
-        if (defined $setdefault) {
-            push(@statements, &quot;UPDATE $table SET $column = $setdefault&quot;
-                            . &quot;  WHERE $column IS NULL&quot;);
-        }
</del><ins>+        push(@statements, $self-&gt;_set_nulls_sql(@_));
</ins><span class="cx">         push(@statements, &quot;ALTER TABLE $table ALTER COLUMN $column&quot;
</span><span class="cx">                         . &quot; SET NOT NULL&quot;);
</span><span class="cx">     }
</span><span class="lines">@@ -1925,6 +2302,27 @@
</span><span class="cx">     return @statements;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# Helps handle any fields that were NULL before, if we have a default,
+# when doing an ALTER COLUMN.
+sub _set_nulls_sql {
+    my ($self, $table, $column, $new_def, $set_nulls_to) = @_;
+    my $default = $new_def-&gt;{DEFAULT};
+    # If we have a set_nulls_to, that overrides the DEFAULT 
+    # (although nobody would usually specify both a default and 
+    # a set_nulls_to.)
+    $default = $set_nulls_to if defined $set_nulls_to;
+    if (defined $default) {
+         my $specific = $self-&gt;{db_specific};
+         $default = $specific-&gt;{$default} if exists $specific-&gt;{$default};
+    }
+    my @sql;
+    if (defined $default) {
+        push(@sql, &quot;UPDATE $table SET $column = $default&quot;
+                . &quot;  WHERE $column IS NULL&quot;);
+    }
+    return @sql;
+}
+
</ins><span class="cx"> sub get_drop_index_ddl {
</span><span class="cx"> 
</span><span class="cx"> =item C&lt;get_drop_index_ddl($table, $name)&gt;
</span><span class="lines">@@ -2204,7 +2602,7 @@
</span><span class="cx">     my ($self, $table, $column) = @_;
</span><span class="cx"> 
</span><span class="cx">     my $abstract_fields = $self-&gt;{abstract_schema}{$table}{FIELDS};
</span><del>-    my $name_position = lsearch($abstract_fields, $column);
</del><ins>+    my $name_position = firstidx { $_ eq $column } @$abstract_fields;
</ins><span class="cx">     die &quot;Attempted to delete nonexistent column ${table}.${column}&quot; 
</span><span class="cx">         if $name_position == -1;
</span><span class="cx">     # Delete the key/value pair from the array.
</span><span class="lines">@@ -2258,6 +2656,28 @@
</span><span class="cx">     $self-&gt;_set_object($table, $column, $new_def, $fields);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+=item C&lt;set_fk($table, $column \%fk_def)&gt;
+
+Sets the C&lt;REFERENCES&gt; item on the specified column.
+
+=cut
+
+sub set_fk {
+    my ($self, $table, $column, $fk_def) = @_;
+    # Don't want to modify the source def before we explicitly set it below.
+    # This is just us being extra-cautious.
+    my $column_def = dclone($self-&gt;get_column_abstract($table, $column));
+    die &quot;Tried to set an fk on $table.$column, but that column doesn't exist&quot;
+        if !$column_def;
+    if ($fk_def) {
+        $column_def-&gt;{REFERENCES} = $fk_def;
+    }
+    else {
+        delete $column_def-&gt;{REFERENCES};
+    }
+    $self-&gt;set_column($table, $column, $column_def);
+}
+
</ins><span class="cx"> sub set_index {
</span><span class="cx"> 
</span><span class="cx"> =item C&lt;set_index($table, $name, $definition)&gt;
</span><span class="lines">@@ -2293,7 +2713,7 @@
</span><span class="cx"> sub _set_object {
</span><span class="cx">     my ($self, $table, $name, $definition, $array_to_change) = @_;
</span><span class="cx"> 
</span><del>-    my $obj_position = lsearch($array_to_change, $name) + 1;
</del><ins>+    my $obj_position = (firstidx { $_ eq $name } @$array_to_change) + 1;
</ins><span class="cx">     # If the object doesn't exist, then add it.
</span><span class="cx">     if (!$obj_position) {
</span><span class="cx">         push(@$array_to_change, $name);
</span><span class="lines">@@ -2326,7 +2746,7 @@
</span><span class="cx">     my ($self, $table, $name) = @_;
</span><span class="cx"> 
</span><span class="cx">     my $indexes = $self-&gt;{abstract_schema}{$table}{INDEXES};
</span><del>-    my $name_position = lsearch($indexes, $name);
</del><ins>+    my $name_position = firstidx { $_ eq $name } @$indexes;
</ins><span class="cx">     die &quot;Attempted to delete nonexistent index $name on the $table table&quot; 
</span><span class="cx">         if $name_position == -1;
</span><span class="cx">     # Delete the key/value pair from the array.
</span><span class="lines">@@ -2410,7 +2830,7 @@
</span><span class="cx">  Description: Used for when you've read a serialized Schema off the disk,
</span><span class="cx">               and you want a Schema object that represents that data.
</span><span class="cx">  Params:      $serialized - scalar. The serialized data.
</span><del>-              $version - A number in the format X.YZ. The &quot;version&quot;
</del><ins>+              $version - A number. The &quot;version&quot;
</ins><span class="cx">                   of the Schema that did the serialization.
</span><span class="cx">                   See the docs for C&lt;SCHEMA_VERSION&gt; for more details.
</span><span class="cx">  Returns:     A Schema object. It will have the methods of (and work 
</span><span class="lines">@@ -2423,7 +2843,7 @@
</span><span class="cx">     my ($class, $serialized, $version) = @_;
</span><span class="cx"> 
</span><span class="cx">     my $thawed_hash;
</span><del>-    if (int($version) &lt; 2) {
</del><ins>+    if ($version &lt; 2) {
</ins><span class="cx">         $thawed_hash = thaw($serialized);
</span><span class="cx">     }
</span><span class="cx">     else {
</span><span class="lines">@@ -2433,6 +2853,22 @@
</span><span class="cx">         $thawed_hash = ${$cpt-&gt;varglob('VAR1')};
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    # Version 2 didn't have the &quot;created&quot; key for REFERENCES items.
+    if ($version &lt; 3) {
+        my $standard = $class-&gt;new()-&gt;{abstract_schema};
+        foreach my $table_name (keys %$thawed_hash) {
+            my %standard_fields = 
+                @{ $standard-&gt;{$table_name}-&gt;{FIELDS} || [] };
+            my $table = $thawed_hash-&gt;{$table_name};
+            my %fields = @{ $table-&gt;{FIELDS} || [] };
+            while (my ($field, $def) = each %fields) {
+                if (exists $def-&gt;{REFERENCES}) {
+                    $def-&gt;{REFERENCES}-&gt;{created} = 1;
+                }
+            }
+        }
+    }
+
</ins><span class="cx">     return $class-&gt;new(undef, $thawed_hash);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -2502,7 +2938,7 @@
</span><span class="cx"> 
</span><span class="cx"> =item C&lt;SMALLSERIAL&gt;
</span><span class="cx"> 
</span><del>-An auto-increment L&lt;/INT1&gt;
</del><ins>+An auto-increment L&lt;/INT2&gt;
</ins><span class="cx"> 
</span><span class="cx"> =item C&lt;MEDIUMSERIAL&gt;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaDBSqlitepm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/DB/Sqlite.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/DB/Sqlite.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/DB/Sqlite.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,311 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Everything Solved, Inc.
+# Portions created by the Initial Developer are Copyright (C) 2010 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+use strict;
+package Bugzilla::DB::Sqlite;
+use base qw(Bugzilla::DB);
+
+use Bugzilla::Constants;
+use Bugzilla::Error;
+use Bugzilla::Install::Util qw(install_string);
+
+use DateTime;
+use POSIX ();
+
+# SQLite only supports the SERIALIZABLE and READ UNCOMMITTED isolation
+# levels. SERIALIZABLE is used by default and SET TRANSACTION ISOLATION
+# LEVEL is not implemented.
+use constant ISOLATION_LEVEL =&gt; undef;
+
+# Since we're literally using Perl's regexes, we can use something
+# simpler and more efficient than what Bugzilla::DB uses.
+use constant WORD_START =&gt; '(?:^|\W)';
+use constant WORD_END   =&gt; '(?:$|\W)';
+
+# For some reason, dropping the related FKs causes the index to
+# disappear early, which causes all sorts of problems.
+use constant INDEX_DROPS_REQUIRE_FK_DROPS =&gt; 0;
+
+####################################
+# Functions Added To SQLite Itself #
+####################################
+
+# A case-insensitive, Unicode collation for SQLite. This allows us to
+# make all comparisons and sorts case-insensitive (though unfortunately
+# not accent-insensitive).
+sub _sqlite_collate_ci { lc($_[0]) cmp lc($_[1]) }
+
+sub _sqlite_mod { $_[0] % $_[1] }
+
+sub _sqlite_now {
+    my $now = DateTime-&gt;now(time_zone =&gt; Bugzilla-&gt;local_timezone);
+    return $now-&gt;ymd . ' ' . $now-&gt;hms;
+}
+
+# SQL's POSITION starts its values from 1 instead of 0 (so we add 1).
+sub _sqlite_position {
+    my ($text, $fragment) = @_;
+    if (!defined $text or !defined $fragment) {
+        return undef;
+    }
+    my $pos = index $text, $fragment;
+    return $pos + 1;
+}
+
+sub _sqlite_position_ci {
+    my ($text, $fragment) = @_;
+    return _sqlite_position(lc($text), lc($fragment));
+}
+
+###############
+# Constructor #
+###############
+
+sub new {
+    my ($class, $params) = @_;
+    my $db_name = $params-&gt;{db_name};
+    
+    # Let people specify paths intead of data/ for the DB.
+    if ($db_name and $db_name !~ m{[\\/]}) {
+        # When the DB is first created, there's a chance that the
+        # data directory doesn't exist at all, because the Install::Filesystem
+        # code happens after DB creation. So we create the directory ourselves
+        # if it doesn't exist.
+        my $datadir = bz_locations()-&gt;{datadir};
+        if (!-d $datadir) {
+            mkdir $datadir or warn &quot;$datadir: $!&quot;;
+        }
+        if (!-d &quot;$datadir/db/&quot;) {
+            mkdir &quot;$datadir/db/&quot; or warn &quot;$datadir/db: $!&quot;;
+        }
+        $db_name = bz_locations()-&gt;{datadir} . &quot;/db/$db_name&quot;;
+    }
+
+    # construct the DSN from the parameters we got
+    my $dsn = &quot;dbi:SQLite:dbname=$db_name&quot;;
+
+    my $attrs = {
+        # XXX Should we just enforce this to be always on?
+        sqlite_unicode =&gt; Bugzilla-&gt;params-&gt;{'utf8'},
+    };
+
+    my $self = $class-&gt;db_new({ dsn =&gt; $dsn, user =&gt; '', 
+                                pass =&gt; '', attrs =&gt; $attrs });
+    # Needed by TheSchwartz
+    $self-&gt;{private_bz_dsn} = $dsn;
+    
+    my %pragmas = (
+        # Make sure that the sqlite file doesn't grow without bound.
+        auto_vacuum =&gt; 1,
+        encoding =&gt; &quot;'UTF-8'&quot;,
+        foreign_keys =&gt; 'ON',
+        # We want the latest file format.
+        legacy_file_format =&gt; 'OFF',
+        # This guarantees that we get column names like &quot;foo&quot;
+        # instead of &quot;table.foo&quot; in selectrow_hashref.
+        short_column_names =&gt; 'ON',
+        # The write-ahead log mode in SQLite 3.7 gets us better concurrency,
+        # but breaks backwards-compatibility with older versions of
+        # SQLite. (Which is important because people may also want to use
+        # command-line clients to access and back up their DB.) If you need
+        # better concurrency and don't need 3.6 compatibility, then you can
+        # uncomment this line.
+        #journal_mode =&gt; &quot;'WAL'&quot;,
+    );
+    
+    while (my ($name, $value) = each %pragmas) {
+        $self-&gt;do(&quot;PRAGMA $name = $value&quot;);
+    }
+    
+    $self-&gt;sqlite_create_collation('bugzilla', \&amp;_sqlite_collate_ci);
+    $self-&gt;sqlite_create_function('position', 2, \&amp;_sqlite_position);
+    $self-&gt;sqlite_create_function('iposition', 2, \&amp;_sqlite_position_ci);
+    # SQLite has a &quot;substr&quot; function, but other DBs call it &quot;SUBSTRING&quot;
+    # so that's what we use, and I don't know of any way in SQLite to
+    # alias the SQL &quot;substr&quot; function to be called &quot;SUBSTRING&quot;.
+    $self-&gt;sqlite_create_function('substring', 3, \&amp;CORE::substr);
+    $self-&gt;sqlite_create_function('mod', 2, \&amp;_sqlite_mod);
+    $self-&gt;sqlite_create_function('now', 0, \&amp;_sqlite_now);
+    $self-&gt;sqlite_create_function('localtimestamp', 1, \&amp;_sqlite_now);
+    $self-&gt;sqlite_create_function('floor', 1, \&amp;POSIX::floor);
+
+    bless ($self, $class);
+    return $self;
+}
+
+###############
+# SQL Methods #
+###############
+
+sub sql_position {
+    my ($self, $fragment, $text) = @_;
+    return &quot;POSITION($text, $fragment)&quot;;
+}
+
+sub sql_iposition {
+    my ($self, $fragment, $text) = @_;
+    return &quot;IPOSITION($text, $fragment)&quot;;
+}
+
+# SQLite does not have to GROUP BY the optional columns.
+sub sql_group_by {
+    my ($self, $needed_columns, $optional_columns) = @_;
+    my $expression = &quot;GROUP BY $needed_columns&quot;;
+    return $expression;
+}
+
+# XXX SQLite does not support sorting a GROUP_CONCAT, so $sort is unimplemented.
+sub sql_group_concat {
+    my ($self, $column, $separator, $sort) = @_;
+    $separator = $self-&gt;quote(', ') if !defined $separator;
+    # In SQLite, a GROUP_CONCAT call with a DISTINCT argument can't
+    # specify its separator, and has to accept the default of &quot;,&quot;.
+    if ($column =~ /^DISTINCT/) {
+        return &quot;GROUP_CONCAT($column)&quot;;
+    }
+    return &quot;GROUP_CONCAT($column, $separator)&quot;;
+}
+
+sub sql_istring {
+    my ($self, $string) = @_;
+    return $string;
+}
+
+sub sql_regexp {
+    my ($self, $expr, $pattern, $nocheck, $real_pattern) = @_;
+    $real_pattern ||= $pattern;
+
+    $self-&gt;bz_check_regexp($real_pattern) if !$nocheck;
+
+    return &quot;$expr REGEXP $pattern&quot;;
+}
+
+sub sql_not_regexp {
+    my $self = shift;
+    my $re_expression = $self-&gt;sql_regexp(@_);
+    return &quot;NOT($re_expression)&quot;;
+}
+
+sub sql_limit {
+    my ($self, $limit, $offset) = @_;
+
+    if (defined($offset)) {
+        return &quot;LIMIT $limit OFFSET $offset&quot;;
+    } else {
+        return &quot;LIMIT $limit&quot;;
+    }
+}
+
+sub sql_from_days {
+    my ($self, $days) = @_;
+    return &quot;DATETIME($days)&quot;;
+}
+
+sub sql_to_days {
+    my ($self, $date) = @_;
+    return &quot;JULIANDAY($date)&quot;;
+}
+
+sub sql_date_format {
+    my ($self, $date, $format) = @_;
+    $format = &quot;%Y.%m.%d %H:%M:%s&quot; if !$format;
+    $format =~ s/\%i/\%M/g;
+    return &quot;STRFTIME(&quot; . $self-&gt;quote($format) . &quot;, $date)&quot;;
+}
+
+sub sql_date_math {
+    my ($self, $date, $operator, $interval, $units) = @_;
+    # We do the || thing (concatenation) so that placeholders work properly.
+    return &quot;DATETIME($date, '$operator' || $interval || ' $units')&quot;;
+}
+
+###############
+# bz_ methods #
+###############
+
+sub bz_setup_database {
+    my $self = shift;
+    $self-&gt;SUPER::bz_setup_database(@_);
+
+    # If we created TheSchwartz tables with COLLATE bugzilla (during the
+    # 4.1.x development series) re-create them without it.
+    my @tables = $self-&gt;bz_table_list();
+    my @ts_tables = grep { /^ts_/ } @tables;
+    my $drop_ok;
+    foreach my $table (@ts_tables) {
+        my $create_table =
+            $self-&gt;_bz_real_schema-&gt;_sqlite_create_table($table);
+        if ($create_table =~ /COLLATE bugzilla/) {
+            if (!$drop_ok) {
+                _sqlite_jobqueue_drop_message();
+                $drop_ok = 1;
+            }
+            $self-&gt;bz_drop_table($table);
+            $self-&gt;bz_add_table($table);
+        }
+    }
+}
+
+sub _sqlite_jobqueue_drop_message {
+    # This is not translated because this situation will only happen if
+    # you are updating from a 4.1.x development version of Bugzilla using
+    # SQLite, and we don't want to maintain this string in strings.txt.pl
+    # forever for just this one uncommon circumstance.
+    print &lt;&lt;END;
+WARNING: We have to re-create all the database tables used by jobqueue.pl.
+If there are any pending jobs in the database (that is, emails that
+haven't been sent), they will be deleted.
+
+END
+    unless (Bugzilla-&gt;installation_answers-&gt;{NO_PAUSE}) {
+        print install_string('enter_or_ctrl_c');
+        getc;
+    }
+}
+
+# XXX This needs to be implemented.
+sub bz_explain { }
+
+sub bz_table_list_real {
+    my $self = shift;
+    my @tables = $self-&gt;SUPER::bz_table_list_real(@_);
+    # SQLite includes a sqlite_sequence table in every database that isn't
+    # one of our real tables. We exclude any table that starts with sqlite_,
+    # just to be safe.
+    @tables = grep { $_ !~ /^sqlite_/ } @tables;
+    return @tables;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::DB::Sqlite - Bugzilla database compatibility layer for SQLite
+
+=head1 DESCRIPTION
+
+This module overrides methods of the Bugzilla::DB module with a
+SQLite-specific implementation. It is instantiated by the Bugzilla::DB module
+and should never be used directly.
+
+For interface details see L&lt;Bugzilla::DB&gt; and L&lt;DBI&gt;.
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaDBpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/DB.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/DB.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/DB.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -37,7 +37,7 @@
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla::Constants;
</span><span class="cx"> use Bugzilla::Install::Requirements;
</span><del>-use Bugzilla::Install::Util qw(vers_cmp);
</del><ins>+use Bugzilla::Install::Util qw(vers_cmp install_string);
</ins><span class="cx"> use Bugzilla::Install::Localconfig;
</span><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> use Bugzilla::Error;
</span><span class="lines">@@ -52,7 +52,6 @@
</span><span class="cx"> 
</span><span class="cx"> use constant BLOB_TYPE =&gt; DBI::SQL_BLOB;
</span><span class="cx"> use constant ISOLATION_LEVEL =&gt; 'REPEATABLE READ';
</span><del>-use constant GROUPBY_REGEXP =&gt; '(?:.*\s+AS\s+)?(\w+(\.\w+)?)(?:\s+(ASC|DESC))?$';
</del><span class="cx"> 
</span><span class="cx"> # Set default values for what used to be the enum types.  These values
</span><span class="cx"> # are no longer stored in localconfig.  If we are upgrading from a
</span><span class="lines">@@ -66,16 +65,52 @@
</span><span class="cx"> use constant ENUM_DEFAULTS =&gt; {
</span><span class="cx">     bug_severity  =&gt; ['blocker', 'critical', 'major', 'normal',
</span><span class="cx">                       'minor', 'trivial', 'enhancement'],
</span><del>-    priority     =&gt; [&quot;P1&quot;,&quot;P2&quot;,&quot;P3&quot;,&quot;P4&quot;,&quot;P5&quot;],
</del><ins>+    priority     =&gt; [&quot;Highest&quot;, &quot;High&quot;, &quot;Normal&quot;, &quot;Low&quot;, &quot;Lowest&quot;, &quot;---&quot;],
</ins><span class="cx">     op_sys       =&gt; [&quot;All&quot;,&quot;Windows&quot;,&quot;Mac OS&quot;,&quot;Linux&quot;,&quot;Other&quot;],
</span><span class="cx">     rep_platform =&gt; [&quot;All&quot;,&quot;PC&quot;,&quot;Macintosh&quot;,&quot;Other&quot;],
</span><del>-    bug_status   =&gt; [&quot;UNCONFIRMED&quot;,&quot;NEW&quot;,&quot;ASSIGNED&quot;,&quot;REOPENED&quot;,&quot;RESOLVED&quot;,
-                     &quot;VERIFIED&quot;,&quot;CLOSED&quot;],
-    resolution   =&gt; [&quot;&quot;,&quot;FIXED&quot;,&quot;INVALID&quot;,&quot;WONTFIX&quot;, &quot;DUPLICATE&quot;,&quot;WORKSFORME&quot;,
-                     &quot;MOVED&quot;],
</del><ins>+    bug_status   =&gt; [&quot;UNCONFIRMED&quot;,&quot;CONFIRMED&quot;,&quot;IN_PROGRESS&quot;,&quot;RESOLVED&quot;,
+                     &quot;VERIFIED&quot;],
+    resolution   =&gt; [&quot;&quot;,&quot;FIXED&quot;,&quot;INVALID&quot;,&quot;WONTFIX&quot;, &quot;DUPLICATE&quot;,&quot;WORKSFORME&quot;],
</ins><span class="cx"> };
</span><span class="cx"> 
</span><ins>+# The character that means &quot;OR&quot; in a boolean fulltext search. If empty,
+# the database doesn't support OR searches in fulltext searches.
+# Used by Bugzilla::Bug::possible_duplicates.
+use constant FULLTEXT_OR =&gt; '';
+
+# These are used in regular expressions to mean &quot;the start or end of a word&quot;.
+#
+# We don't use [[:&lt;:]] and [[:&gt;:]], even though they mean
+# &quot;start and end of a word&quot; and are supported by both MySQL and PostgreSQL,
+# because they don't work if your search starts or ends with a non-alphanumeric
+# character, and there's a fair chance somebody will want to use the &quot;word&quot;
+# search to search flags for something like &quot;review+&quot;.
+#
+# We do use [:almum:] because it is supported by at least MySQL and
+# PostgreSQL, and hopefully will get us as much Unicode support as possible,
+# depending on how well the regexp engines of the various databases support
+# Unicode.
+use constant WORD_START =&gt; '(^|[^[:alnum:]])';
+use constant WORD_END   =&gt; '($|[^[:alnum:]])';
+
+# On most databases, in order to drop an index, you have to first drop
+# the foreign keys that use that index. However, on some databases,
+# dropping the FK immediately before dropping the index causes problems
+# and doesn't need to be done anyway, so those DBs set this to 0.
+use constant INDEX_DROPS_REQUIRE_FK_DROPS =&gt; 1;
+
</ins><span class="cx"> #####################################################################
</span><ins>+# Overridden Superclass Methods 
+#####################################################################
+
+sub quote {
+    my $self = shift;
+    my $retval = $self-&gt;SUPER::quote(@_);
+    trick_taint($retval) if defined $retval;
+    return $retval;
+}
+
+#####################################################################
</ins><span class="cx"> # Connection Methods
</span><span class="cx"> #####################################################################
</span><span class="cx"> 
</span><span class="lines">@@ -84,22 +119,27 @@
</span><span class="cx">     die &quot;Tried to connect to non-existent shadowdb&quot; 
</span><span class="cx">         unless $params-&gt;{'shadowdb'};
</span><span class="cx"> 
</span><del>-    my $lc = Bugzilla-&gt;localconfig;
</del><ins>+    # Instead of just passing in a new hashref, we locally modify the
+    # values of &quot;localconfig&quot;, because some drivers access it while
+    # connecting.
+    my %connect_params = %{ Bugzilla-&gt;localconfig };
+    $connect_params{db_host} = $params-&gt;{'shadowdbhost'};
+    $connect_params{db_name} = $params-&gt;{'shadowdb'};
+    $connect_params{db_port} = $params-&gt;{'shadowdbport'};
+    $connect_params{db_sock} = $params-&gt;{'shadowdbsock'};
</ins><span class="cx"> 
</span><del>-    return _connect($lc-&gt;{db_driver}, $params-&gt;{&quot;shadowdbhost&quot;},
-                    $params-&gt;{'shadowdb'}, $params-&gt;{&quot;shadowdbport&quot;},
-                    $params-&gt;{&quot;shadowdbsock&quot;}, $lc-&gt;{db_user}, $lc-&gt;{db_pass});
</del><ins>+    return _connect(\%connect_params);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub connect_main {
</span><span class="cx">     my $lc = Bugzilla-&gt;localconfig;
</span><del>-    return _connect($lc-&gt;{db_driver}, $lc-&gt;{db_host}, $lc-&gt;{db_name}, $lc-&gt;{db_port},
-                    $lc-&gt;{db_sock}, $lc-&gt;{db_user}, $lc-&gt;{db_pass});
</del><ins>+    return _connect(Bugzilla-&gt;localconfig); 
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _connect {
</span><del>-    my ($driver, $host, $dbname, $port, $sock, $user, $pass) = @_;
</del><ins>+    my ($params) = @_;
</ins><span class="cx"> 
</span><ins>+    my $driver = $params-&gt;{db_driver};
</ins><span class="cx">     my $pkg_module = DB_MODULE-&gt;{lc($driver)}-&gt;{db};
</span><span class="cx"> 
</span><span class="cx">     # do the actual import
</span><span class="lines">@@ -108,7 +148,7 @@
</span><span class="cx">                 . &quot; localconfig: &quot; . $@);
</span><span class="cx"> 
</span><span class="cx">     # instantiate the correct DB specific module
</span><del>-    my $dbh = $pkg_module-&gt;new($user, $pass, $host, $dbname, $port, $sock);
</del><ins>+    my $dbh = $pkg_module-&gt;new($params);
</ins><span class="cx"> 
</span><span class="cx">     return $dbh;
</span><span class="cx"> }
</span><span class="lines">@@ -128,27 +168,42 @@
</span><span class="cx"> 
</span><span class="cx">     my $lc = Bugzilla-&gt;localconfig;
</span><span class="cx">     my $db = DB_MODULE-&gt;{lc($lc-&gt;{db_driver})};
</span><ins>+
</ins><span class="cx">     # Only certain values are allowed for $db_driver.
</span><span class="cx">     if (!defined $db) {
</span><span class="cx">         die &quot;$lc-&gt;{db_driver} is not a valid choice for \$db_driver in&quot;
</span><span class="cx">             . bz_locations()-&gt;{'localconfig'};
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    die(&quot;It is not safe to run Bugzilla inside the 'mysql' database.\n&quot;
-        . &quot;Please pick a different value for \$db_name in localconfig.&quot;)
-        if $lc-&gt;{db_name} eq 'mysql';
</del><ins>+    # Check the existence and version of the DBD that we need.
+    my $dbd = $db-&gt;{dbd};
+    _bz_check_dbd($db, $output);
</ins><span class="cx"> 
</span><del>-    # Check the existence and version of the DBD that we need.
-    my $dbd        = $db-&gt;{dbd};
-    my $sql_server = $db-&gt;{name};
-    my $sql_want   = $db-&gt;{db_version};
</del><ins>+    # We don't try to connect to the actual database if $db_check is
+    # disabled.
+    unless ($lc-&gt;{db_check}) {
+        print &quot;\n&quot; if $output;
+        return;
+    }
+
+    # And now check the version of the database server itself.
+    my $dbh = _get_no_db_connection();
+    $dbh-&gt;bz_check_server_version($db, $output);
+
+    print &quot;\n&quot; if $output;
+}
+
+sub _bz_check_dbd {
+    my ($db, $output) = @_;
+
+    my $dbd = $db-&gt;{dbd};
</ins><span class="cx">     unless (have_vers($dbd, $output)) {
</span><ins>+        my $sql_server = $db-&gt;{name};
</ins><span class="cx">         my $command = install_command($dbd);
</span><span class="cx">         my $root    = ROOT_USER;
</span><span class="cx">         my $dbd_mod = $dbd-&gt;{module};
</span><span class="cx">         my $dbd_ver = $dbd-&gt;{version};
</span><del>-        my $version = $dbd_ver ? &quot; $dbd_ver or higher&quot; : '';
-        print &lt;&lt;EOT;
</del><ins>+        die &lt;&lt;EOT;
</ins><span class="cx"> 
</span><span class="cx"> For $sql_server, Bugzilla requires that perl's $dbd_mod $dbd_ver or later be
</span><span class="cx"> installed. To install this module, run the following command (as $root):
</span><span class="lines">@@ -156,40 +211,39 @@
</span><span class="cx">     $command
</span><span class="cx"> 
</span><span class="cx"> EOT
</span><del>-        exit;
</del><span class="cx">     }
</span><ins>+}
</ins><span class="cx"> 
</span><del>-    # We don't try to connect to the actual database if $db_check is
-    # disabled.
-    unless ($lc-&gt;{db_check}) {
-        print &quot;\n&quot; if $output;
-        return;
-    }
</del><ins>+sub bz_check_server_version {
+    my ($self, $db, $output) = @_;
</ins><span class="cx"> 
</span><del>-    # And now check the version of the database server itself.
-    my $dbh = _get_no_db_connection();
</del><ins>+    my $sql_vers = $self-&gt;bz_server_version;
+    $self-&gt;disconnect;
</ins><span class="cx"> 
</span><del>-    printf(&quot;Checking for %15s %-9s &quot;, $sql_server, &quot;(v$sql_want)&quot;)
-        if $output;
-    my $sql_vers = $dbh-&gt;bz_server_version;
-    $dbh-&gt;disconnect;
</del><ins>+    my $sql_want = $db-&gt;{db_version};
+    my $version_ok = vers_cmp($sql_vers, $sql_want) &gt; -1 ? 1 : 0;
</ins><span class="cx"> 
</span><ins>+    my $sql_server = $db-&gt;{name};
+    if ($output) {
+        Bugzilla::Install::Requirements::_checking_for({
+            package =&gt; $sql_server, wanted =&gt; $sql_want,
+            found   =&gt; $sql_vers, ok =&gt; $version_ok });
+    }
+
</ins><span class="cx">     # Check what version of the database server is installed and let
</span><span class="cx">     # the user know if the version is too old to be used with Bugzilla.
</span><del>-    if ( vers_cmp($sql_vers,$sql_want) &gt; -1 ) {
-        print &quot;ok: found v$sql_vers\n&quot; if $output;
-    } else {
-        print &lt;&lt;EOT;
</del><ins>+    if (!$version_ok) {
+        die &lt;&lt;EOT;
</ins><span class="cx"> 
</span><span class="cx"> Your $sql_server v$sql_vers is too old. Bugzilla requires version
</span><span class="cx"> $sql_want or later of $sql_server. Please download and install a
</span><span class="cx"> newer version.
</span><span class="cx"> 
</span><span class="cx"> EOT
</span><del>-        exit;
</del><span class="cx">     }
</span><span class="cx"> 
</span><del>-    print &quot;\n&quot; if $output;
</del><ins>+    # This is used by subclasses.
+    return $sql_vers;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> # Note that this function requires that localconfig exist and
</span><span class="lines">@@ -197,7 +251,7 @@
</span><span class="cx"> sub bz_create_database {
</span><span class="cx">     my $dbh;
</span><span class="cx">     # See if we can connect to the actual Bugzilla database.
</span><del>-    my $conn_success = eval { $dbh = connect_main(); };
</del><ins>+    my $conn_success = eval { $dbh = connect_main() };
</ins><span class="cx">     my $db_name = Bugzilla-&gt;localconfig-&gt;{db_name};
</span><span class="cx"> 
</span><span class="cx">     if (!$conn_success) {
</span><span class="lines">@@ -214,10 +268,9 @@
</span><span class="cx">         if (!$success) {
</span><span class="cx">             my $error = $dbh-&gt;errstr || $@;
</span><span class="cx">             chomp($error);
</span><del>-            print STDERR  &quot;The '$db_name' database could not be created.&quot;,
-                          &quot; The error returned was:\n\n    $error\n\n&quot;,
-                          _bz_connect_error_reasons();
-            exit;
</del><ins>+            die &quot;The '$db_name' database could not be created.&quot;,
+                &quot; The error returned was:\n\n    $error\n\n&quot;,
+                _bz_connect_error_reasons();
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -228,19 +281,19 @@
</span><span class="cx"> sub _get_no_db_connection {
</span><span class="cx">     my ($sql_server) = @_;
</span><span class="cx">     my $dbh;
</span><del>-    my $lc = Bugzilla-&gt;localconfig;
</del><ins>+    my %connect_params = %{ Bugzilla-&gt;localconfig };
+    $connect_params{db_name} = '';
</ins><span class="cx">     my $conn_success = eval {
</span><del>-        $dbh = _connect($lc-&gt;{db_driver}, $lc-&gt;{db_host}, '', $lc-&gt;{db_port},
-                        $lc-&gt;{db_sock}, $lc-&gt;{db_user}, $lc-&gt;{db_pass});
</del><ins>+        $dbh = _connect(\%connect_params);
</ins><span class="cx">     };
</span><span class="cx">     if (!$conn_success) {
</span><del>-        my $sql_server = DB_MODULE-&gt;{lc($lc-&gt;{db_driver})}-&gt;{name};
</del><ins>+        my $driver = $connect_params{db_driver};
+        my $sql_server = DB_MODULE-&gt;{lc($driver)}-&gt;{name};
</ins><span class="cx">         # Can't use $dbh-&gt;errstr because $dbh is undef.
</span><span class="cx">         my $error = $DBI::errstr || $@;
</span><span class="cx">         chomp($error);
</span><del>-        print STDERR &quot;There was an error connecting to $sql_server:\n\n&quot;,
-                     &quot;    $error\n\n&quot;, _bz_connect_error_reasons();
-        exit;
</del><ins>+        die &quot;There was an error connecting to $sql_server:\n\n&quot;,
+            &quot;    $error\n\n&quot;, _bz_connect_error_reasons(), &quot;\n&quot;;
</ins><span class="cx">     }
</span><span class="cx">     return $dbh;    
</span><span class="cx"> }
</span><span class="lines">@@ -272,9 +325,9 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> # List of abstract methods we are checking the derived class implements
</span><del>-our @_abstract_methods = qw(REQUIRED_VERSION PROGRAM_NAME DBD_VERSION
-                            new sql_regexp sql_not_regexp sql_limit sql_to_days
-                            sql_date_format sql_interval);
</del><ins>+our @_abstract_methods = qw(new sql_regexp sql_not_regexp sql_limit sql_to_days
+                            sql_date_format sql_date_math bz_explain
+                            sql_group_concat);
</ins><span class="cx"> 
</span><span class="cx"> # This overridden import method will check implementation of inherited classes
</span><span class="cx"> # for missing implementation of abstract methods
</span><span class="lines">@@ -287,7 +340,7 @@
</span><span class="cx">         # make sure all abstract methods are implemented
</span><span class="cx">         foreach my $meth (@_abstract_methods) {
</span><span class="cx">             $pkg-&gt;can($meth)
</span><del>-                or croak(&quot;Class $pkg does not define method $meth&quot;);
</del><ins>+                or die(&quot;Class $pkg does not define method $meth&quot;);
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -342,6 +395,15 @@
</span><span class="cx">     return '(' . join(' || ', @params) . ')';
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub sql_string_until {
+    my ($self, $string, $substring) = @_;
+
+    my $position = $self-&gt;sql_position($substring, $string);
+    return &quot;CASE WHEN $position != 0&quot;
+             . &quot; THEN SUBSTR($string, 1, $position - 1)&quot;
+             . &quot; ELSE $string END&quot;;
+}
+
</ins><span class="cx"> sub sql_in {
</span><span class="cx">     my ($self, $column_name, $in_list_ref) = @_;
</span><span class="cx">     return &quot; $column_name IN (&quot; . join(',', @$in_list_ref) . &quot;) &quot;;
</span><span class="lines">@@ -357,21 +419,34 @@
</span><span class="cx">     # make the string lowercase to do case insensitive search
</span><span class="cx">     my $lower_text = lc($text);
</span><span class="cx"> 
</span><del>-    # split the text we search for into separate words
-    my @words = split(/\s+/, $lower_text);
</del><ins>+    # split the text we're searching for into separate words. As a hack
+    # to allow quicksearch to work, if the field starts and ends with
+    # a double-quote, then we don't split it into words. We can't use
+    # Text::ParseWords here because it gets very confused by unbalanced
+    # quotes, which breaks searches like &quot;don't try this&quot; (because of the
+    # unbalanced single-quote in &quot;don't&quot;).
+    my @words;
+    if ($lower_text =~ /^&quot;/ and $lower_text =~ /&quot;$/) {
+        $lower_text =~ s/^&quot;//;
+        $lower_text =~ s/&quot;$//;
+        @words = ($lower_text);
+    }
+    else {
+        @words = split(/\s+/, $lower_text);
+    }
</ins><span class="cx"> 
</span><span class="cx">     # surround the words with wildcards and SQL quotes so we can use them
</span><span class="cx">     # in LIKE search clauses
</span><del>-    @words = map($self-&gt;quote(&quot;%$_%&quot;), @words);
</del><ins>+    @words = map($self-&gt;quote(&quot;\%$_\%&quot;), @words);
</ins><span class="cx"> 
</span><span class="cx">     # untaint words, since they are safe to use now that we've quoted them
</span><del>-    map(trick_taint($_), @words);
</del><ins>+    trick_taint($_) foreach @words;
</ins><span class="cx"> 
</span><span class="cx">     # turn the words into a set of LIKE search clauses
</span><span class="cx">     @words = map(&quot;LOWER($column) LIKE $_&quot;, @words);
</span><span class="cx"> 
</span><span class="cx">     # search for occurrences of all specified words in the column
</span><del>-    return &quot;CASE WHEN (&quot; . join(&quot; AND &quot;, @words) . &quot;) THEN 1 ELSE 0 END&quot;;
</del><ins>+    return join (&quot; AND &quot;, @words), &quot;CASE WHEN (&quot; . join(&quot; AND &quot;, @words) . &quot;) THEN 1 ELSE 0 END&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #####################################################################
</span><span class="lines">@@ -391,6 +466,15 @@
</span><span class="cx">                                  $table, $column);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub bz_check_regexp {
+    my ($self, $pattern) = @_;
+
+    eval { $self-&gt;do(&quot;SELECT &quot; . $self-&gt;sql_regexp($self-&gt;quote(&quot;a&quot;), $pattern, 1)) };
+
+    $@ &amp;&amp; ThrowUserError('illegal_regexp', 
+        { value =&gt; $pattern, dberror =&gt; $self-&gt;errstr }); 
+}
+
</ins><span class="cx"> #####################################################################
</span><span class="cx"> # Database Setup
</span><span class="cx"> #####################################################################
</span><span class="lines">@@ -401,11 +485,18 @@
</span><span class="cx">     # If we haven't ever stored a serialized schema,
</span><span class="cx">     # set up the bz_schema table and store it.
</span><span class="cx">     $self-&gt;_bz_init_schema_storage();
</span><del>-    
</del><ins>+   
+    # We don't use bz_table_list here, because that uses _bz_real_schema.
+    # We actually want the table list from the ABSTRACT_SCHEMA in
+    # Bugzilla::DB::Schema.
</ins><span class="cx">     my @desired_tables = $self-&gt;_bz_schema-&gt;get_table_list();
</span><ins>+    my $bugs_exists = $self-&gt;bz_table_info('bugs');
+    if (!$bugs_exists) {
+        print install_string('db_table_setup'), &quot;\n&quot;;
+    }
</ins><span class="cx"> 
</span><span class="cx">     foreach my $table_name (@desired_tables) {
</span><del>-        $self-&gt;bz_add_table($table_name);
</del><ins>+        $self-&gt;bz_add_table($table_name, { silently =&gt; !$bugs_exists });
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -415,28 +506,59 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub bz_populate_enum_tables {
</span><del>-    my ($self) = @_;
</del><ins>+    my ($self) = @_; 
</ins><span class="cx"> 
</span><ins>+    my $any_severities = $self-&gt;selectrow_array(
+        'SELECT 1 FROM bug_severity ' . $self-&gt;sql_limit(1));
+    print install_string('db_enum_setup'), &quot;\n  &quot; if !$any_severities;
+
</ins><span class="cx">     my $enum_values = $self-&gt;bz_enum_initial_values();
</span><span class="cx">     while (my ($table, $values) = each %$enum_values) {
</span><span class="cx">         $self-&gt;_bz_populate_enum_table($table, $values);
</span><span class="cx">     }
</span><ins>+
+    print &quot;\n&quot; if !$any_severities;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub bz_setup_foreign_keys {
</span><span class="cx">     my ($self) = @_;
</span><span class="cx"> 
</span><del>-    # We use _bz_schema because bz_add_table has removed all REFERENCES
-    # items from _bz_real_schema.
-    my @tables = $self-&gt;_bz_schema-&gt;get_table_list();
</del><ins>+    # profiles_activity was the first table to get foreign keys,
+    # so if it doesn't have them, then we're setting up FKs
+    # for the first time, and should be quieter about it.
+    my $activity_fk = $self-&gt;bz_fk_info('profiles_activity', 'userid');
+    my $any_fks = $activity_fk &amp;&amp; $activity_fk-&gt;{created};
+    if (!$any_fks) {
+        print get_text('install_fk_setup'), &quot;\n&quot;;
+    }
+
+    my @tables = $self-&gt;bz_table_list();
</ins><span class="cx">     foreach my $table (@tables) {
</span><del>-        my @columns = $self-&gt;_bz_schema-&gt;get_table_columns($table);
</del><ins>+        my @columns = $self-&gt;bz_table_columns($table);
+        my %add_fks;
</ins><span class="cx">         foreach my $column (@columns) {
</span><del>-            my $def = $self-&gt;_bz_schema-&gt;get_column_abstract($table, $column);
-            if ($def-&gt;{REFERENCES}) {
-                $self-&gt;bz_add_fk($table, $column, $def-&gt;{REFERENCES});
</del><ins>+            # First we check for any FKs that have created =&gt; 0,
+            # in the _bz_real_schema. This also picks up FKs with
+            # created =&gt; 1, but bz_add_fks will ignore those.
+            my $fk = $self-&gt;bz_fk_info($table, $column);
+            # Then we check the abstract schema to see if there
+            # should be an FK on this column, but one wasn't set in the
+            # _bz_real_schema for some reason. We do this to handle
+            # various problems caused by upgrading from versions
+            # prior to 4.2, and also to handle problems caused
+            # by enabling an extension pre-4.2, disabling it for
+            # the 4.2 upgrade, and then re-enabling it later.
+            unless ($fk &amp;&amp; $fk-&gt;{created}) {
+                my $standard_def = 
+                    $self-&gt;_bz_schema-&gt;get_column_abstract($table, $column);
+                if (exists $standard_def-&gt;{REFERENCES}) {
+                    $fk = dclone($standard_def-&gt;{REFERENCES});
+                }
</ins><span class="cx">             }
</span><ins>+
+            $add_fks{$column} = $fk if $fk;
</ins><span class="cx">         }
</span><ins>+        $self-&gt;bz_add_fks($table, \%add_fks, { silently =&gt; !$any_fks });
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -444,9 +566,9 @@
</span><span class="cx"> sub bz_drop_foreign_keys {
</span><span class="cx">     my ($self) = @_;
</span><span class="cx"> 
</span><del>-    my @tables = $self-&gt;_bz_real_schema-&gt;get_table_list();
</del><ins>+    my @tables = $self-&gt;bz_table_list();
</ins><span class="cx">     foreach my $table (@tables) {
</span><del>-        my @columns = $self-&gt;_bz_real_schema-&gt;get_table_columns($table);
</del><ins>+        my @columns = $self-&gt;bz_table_columns($table);
</ins><span class="cx">         foreach my $column (@columns) {
</span><span class="cx">             $self-&gt;bz_drop_fk($table, $column);
</span><span class="cx">         }
</span><span class="lines">@@ -483,6 +605,20 @@
</span><span class="cx">         foreach my $sql (@statements) {
</span><span class="cx">             $self-&gt;do($sql);
</span><span class="cx">         }
</span><ins>+
+        # To make things easier for callers, if they don't specify
+        # a REFERENCES item, we pull it from the _bz_schema if the
+        # column exists there and has a REFERENCES item.
+        # bz_setup_foreign_keys will then add this FK at the end of
+        # Install::DB.
+        my $col_abstract = 
+            $self-&gt;_bz_schema-&gt;get_column_abstract($table, $name);
+        if (exists $col_abstract-&gt;{REFERENCES}) {
+            my $new_fk = dclone($col_abstract-&gt;{REFERENCES});
+            $new_fk-&gt;{created} = 0;
+            $new_def-&gt;{REFERENCES} = $new_fk;
+        }
+        
</ins><span class="cx">         $self-&gt;_bz_real_schema-&gt;set_column($table, $name, $new_def);
</span><span class="cx">         $self-&gt;_bz_store_real_schema;
</span><span class="cx">     }
</span><span class="lines">@@ -490,20 +626,40 @@
</span><span class="cx"> 
</span><span class="cx"> sub bz_add_fk {
</span><span class="cx">     my ($self, $table, $column, $def) = @_;
</span><ins>+    $self-&gt;bz_add_fks($table, { $column =&gt; $def });
+}
</ins><span class="cx"> 
</span><del>-    my $col_def = $self-&gt;bz_column_info($table, $column);
-    if (!$col_def-&gt;{REFERENCES}) {
-        $self-&gt;_check_references($table, $column, $def-&gt;{TABLE},
-                                 $def-&gt;{COLUMN});
-        print get_text('install_fk_add',
-                       { table =&gt; $table, column =&gt; $column, fk =&gt; $def }) 
-            . &quot;\n&quot; if Bugzilla-&gt;usage_mode == USAGE_MODE_CMDLINE;
-        my @sql = $self-&gt;_bz_real_schema-&gt;get_add_fk_sql($table, $column, $def);
-        $self-&gt;do($_) foreach @sql;
-        $col_def-&gt;{REFERENCES} = $def;
-        $self-&gt;_bz_real_schema-&gt;set_column($table, $column, $col_def);
-        $self-&gt;_bz_store_real_schema;
</del><ins>+sub bz_add_fks {
+    my ($self, $table, $column_fks, $options) = @_;
+
+    my %add_these;
+    foreach my $column (keys %$column_fks) {
+        my $current_fk = $self-&gt;bz_fk_info($table, $column);
+        next if ($current_fk and $current_fk-&gt;{created});
+        my $new_fk = $column_fks-&gt;{$column};
+        $self-&gt;_check_references($table, $column, $new_fk);
+        $add_these{$column} = $new_fk;
+        if (Bugzilla-&gt;usage_mode == USAGE_MODE_CMDLINE 
+            and !$options-&gt;{silently}) 
+        {
+            print get_text('install_fk_add',
+                           { table =&gt; $table, column =&gt; $column, 
+                             fk    =&gt; $new_fk }), &quot;\n&quot;;
+        }
</ins><span class="cx">     }
</span><ins>+
+    return if !scalar(keys %add_these);
+
+    my @sql = $self-&gt;_bz_real_schema-&gt;get_add_fks_sql($table, \%add_these);
+    $self-&gt;do($_) foreach @sql;
+
+    foreach my $column (keys %add_these) {
+        my $fk_def = $add_these{$column};
+        $fk_def-&gt;{created} = 1;
+        $self-&gt;_bz_real_schema-&gt;set_fk($table, $column, $fk_def);
+    }
+
+    $self-&gt;_bz_store_real_schema();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub bz_alter_column {
</span><span class="lines">@@ -524,6 +680,11 @@
</span><span class="cx">             ThrowCodeError('column_not_null_no_default_alter', 
</span><span class="cx">                            { name =&gt; &quot;$table.$name&quot; }) if ($any_nulls);
</span><span class="cx">         }
</span><ins>+        # Preserve foreign key definitions in the Schema object when altering
+        # types.
+        if (my $fk = $self-&gt;bz_fk_info($table, $name)) {
+            $new_def-&gt;{REFERENCES} = $fk;
+        }
</ins><span class="cx">         $self-&gt;bz_alter_column_raw($table, $name, $new_def, $current_def,
</span><span class="cx">                                    $set_nulls_to);
</span><span class="cx">         $self-&gt;_bz_real_schema-&gt;set_column($table, $name, $new_def);
</span><span class="lines">@@ -568,6 +729,15 @@
</span><span class="cx">     $self-&gt;do($_) foreach (@statements);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub bz_alter_fk {
+    my ($self, $table, $column, $fk_def) = @_;
+    my $current_fk = $self-&gt;bz_fk_info($table, $column);
+    ThrowCodeError('column_alter_nonexistent_fk',
+                   { table =&gt; $table, column =&gt; $column }) if !$current_fk;
+    $self-&gt;bz_drop_fk($table, $column);
+    $self-&gt;bz_add_fk($table, $column, $fk_def);
+}
+
</ins><span class="cx"> sub bz_add_index {
</span><span class="cx">     my ($self, $table, $name, $definition) = @_;
</span><span class="cx"> 
</span><span class="lines">@@ -605,12 +775,12 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub bz_add_table {
</span><del>-    my ($self, $name) = @_;
</del><ins>+    my ($self, $name, $options) = @_;
</ins><span class="cx"> 
</span><span class="cx">     my $table_exists = $self-&gt;bz_table_info($name);
</span><span class="cx"> 
</span><span class="cx">     if (!$table_exists) {
</span><del>-        $self-&gt;_bz_add_table_raw($name);
</del><ins>+        $self-&gt;_bz_add_table_raw($name, $options);
</ins><span class="cx">         my $table_def = dclone($self-&gt;_bz_schema-&gt;get_table_abstract($name));
</span><span class="cx"> 
</span><span class="cx">         my %fields = @{$table_def-&gt;{FIELDS}};
</span><span class="lines">@@ -619,8 +789,11 @@
</span><span class="cx">             # initial table creation, because column names have changed
</span><span class="cx">             # over history and it's impossible to keep track of that info
</span><span class="cx">             # in ABSTRACT_SCHEMA.
</span><del>-            delete $fields{$col}-&gt;{REFERENCES};
</del><ins>+            next unless exists $fields{$col}-&gt;{REFERENCES};
+            $fields{$col}-&gt;{REFERENCES}-&gt;{created} =
+                $self-&gt;_bz_real_schema-&gt;FK_ON_CREATE;
</ins><span class="cx">         }
</span><ins>+        
</ins><span class="cx">         $self-&gt;_bz_real_schema-&gt;add_table($name, $table_def);
</span><span class="cx">         $self-&gt;_bz_store_real_schema;
</span><span class="cx">     }
</span><span class="lines">@@ -641,9 +814,13 @@
</span><span class="cx"> # Returns:     nothing
</span><span class="cx"> #
</span><span class="cx"> sub _bz_add_table_raw {
</span><del>-    my ($self, $name) = @_;
</del><ins>+    my ($self, $name, $options) = @_;
</ins><span class="cx">     my @statements = $self-&gt;_bz_schema-&gt;get_table_ddl($name);
</span><del>-    print &quot;Adding new table $name ...\n&quot; unless i_am_cgi();
</del><ins>+    if (Bugzilla-&gt;usage_mode == USAGE_MODE_CMDLINE
+        and !$options-&gt;{silently})
+    {
+        print install_string('db_table_new', { table =&gt; $name }), &quot;\n&quot;;
+    }
</ins><span class="cx">     $self-&gt;do($_) foreach (@statements);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -672,12 +849,18 @@
</span><span class="cx">     my ($self, $field) = @_;
</span><span class="cx">     
</span><span class="cx">     $self-&gt;_bz_add_field_table($field-&gt;name,
</span><del>-                                $self-&gt;_bz_schema-&gt;FIELD_TABLE_SCHEMA);
-    if ( $field-&gt;type == FIELD_TYPE_MULTI_SELECT ) {
-        $self-&gt;_bz_add_field_table('bug_' . $field-&gt;name,
-                $self-&gt;_bz_schema-&gt;MULTI_SELECT_VALUE_TABLE);
</del><ins>+                               $self-&gt;_bz_schema-&gt;FIELD_TABLE_SCHEMA, $field-&gt;type);
+    if ($field-&gt;type == FIELD_TYPE_MULTI_SELECT) {
+        my $ms_table = &quot;bug_&quot; . $field-&gt;name;
+        $self-&gt;_bz_add_field_table($ms_table,
+            $self-&gt;_bz_schema-&gt;MULTI_SELECT_VALUE_TABLE);
+
+        $self-&gt;bz_add_fks($ms_table, 
+            { bug_id =&gt; {TABLE =&gt; 'bugs', COLUMN =&gt; 'bug_id',
+                         DELETE =&gt; 'CASCADE'},
+
+              value  =&gt; {TABLE  =&gt; $field-&gt;name, COLUMN =&gt; 'value'} });
</ins><span class="cx">     }
</span><del>-
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub bz_drop_field_tables {
</span><span class="lines">@@ -713,27 +896,72 @@
</span><span class="cx"> sub bz_drop_fk {
</span><span class="cx">     my ($self, $table, $column) = @_;
</span><span class="cx"> 
</span><del>-    my $col_def = $self-&gt;bz_column_info($table, $column);
-    if ($col_def &amp;&amp; exists $col_def-&gt;{REFERENCES}) {
-        my $def = $col_def-&gt;{REFERENCES};
</del><ins>+    my $fk_def = $self-&gt;bz_fk_info($table, $column);
+    if ($fk_def and $fk_def-&gt;{created}) {
</ins><span class="cx">         print get_text('install_fk_drop',
</span><del>-                       { table =&gt; $table, column =&gt; $column, fk =&gt; $def })
</del><ins>+                       { table =&gt; $table, column =&gt; $column, fk =&gt; $fk_def })
</ins><span class="cx">             . &quot;\n&quot; if Bugzilla-&gt;usage_mode == USAGE_MODE_CMDLINE;
</span><del>-        my @sql = $self-&gt;_bz_real_schema-&gt;get_drop_fk_sql($table,$column,$def);
-        $self-&gt;do($_) foreach @sql;
-        delete $col_def-&gt;{REFERENCES};
-        $self-&gt;_bz_real_schema-&gt;set_column($table, $column, $col_def);
</del><ins>+        my @statements = 
+            $self-&gt;_bz_real_schema-&gt;get_drop_fk_sql($table, $column, $fk_def);
+        foreach my $sql (@statements) {
+            # Because this is a deletion, we don't want to die hard if
+            # we fail because of some local customization. If something
+            # is already gone, that's fine with us!
+            eval { $self-&gt;do($sql); } or warn &quot;Failed SQL: [$sql] Error: $@&quot;;
+        }
+        # Under normal circumstances, we don't permanently drop the fk--
+        # we want checksetup to re-create it again later. The only
+        # time that FKs get permanently dropped is if the column gets
+        # dropped.
+        $fk_def-&gt;{created} = 0;
+        $self-&gt;_bz_real_schema-&gt;set_fk($table, $column, $fk_def);
</ins><span class="cx">         $self-&gt;_bz_store_real_schema;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub bz_get_related_fks {
+    my ($self, $table, $column) = @_;
+    my @tables = $self-&gt;_bz_real_schema-&gt;get_table_list();
+    my @related;
+    foreach my $check_table (@tables) {
+        my @columns = $self-&gt;bz_table_columns($check_table);
+        foreach my $check_column (@columns) {
+            my $fk = $self-&gt;bz_fk_info($check_table, $check_column);
+            if ($fk 
+                and (($fk-&gt;{TABLE} eq $table and $fk-&gt;{COLUMN} eq $column)
+                     or ($check_column eq $column and $check_table eq $table)))
+            {
+                push(@related, [$check_table, $check_column, $fk]);
+            }
+        } # foreach $column
+    } # foreach $table
+
+    return \@related;
+}
+
+sub bz_drop_related_fks {
+    my $self = shift;
+    my $related = $self-&gt;bz_get_related_fks(@_);
+    foreach my $item (@$related) {
+        my ($table, $column) = @$item;
+        $self-&gt;bz_drop_fk($table, $column);
+    }
+    return $related;
+}
+
</ins><span class="cx"> sub bz_drop_index {
</span><span class="cx">     my ($self, $table, $name) = @_;
</span><span class="cx"> 
</span><span class="cx">     my $index_exists = $self-&gt;bz_index_info($table, $name);
</span><span class="cx"> 
</span><span class="cx">     if ($index_exists) {
</span><ins>+        if ($self-&gt;INDEX_DROPS_REQUIRE_FK_DROPS) {
+            # We cannot delete an index used by a FK.
+            foreach my $column (@{$index_exists-&gt;{FIELDS}}) {
+                $self-&gt;bz_drop_related_fks($table, $column);
+            }
+        }
</ins><span class="cx">         $self-&gt;bz_drop_index_raw($table, $name);
</span><span class="cx">         $self-&gt;_bz_real_schema-&gt;delete_index($table, $name);
</span><span class="cx">         $self-&gt;_bz_store_real_schema;        
</span><span class="lines">@@ -789,6 +1017,14 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub bz_fk_info {
+    my ($self, $table, $column) = @_;
+    my $col_info = $self-&gt;bz_column_info($table, $column);
+    return undef if !$col_info;
+    my $fk = $col_info-&gt;{REFERENCES};
+    return $fk;
+}
+
</ins><span class="cx"> sub bz_rename_column {
</span><span class="cx">     my ($self, $table, $old_name, $new_name) = @_;
</span><span class="cx"> 
</span><span class="lines">@@ -822,6 +1058,18 @@
</span><span class="cx">     my $new = $self-&gt;bz_table_info($new_name);
</span><span class="cx">     ThrowCodeError('db_rename_conflict', { old =&gt; $old_name,
</span><span class="cx">                                            new =&gt; $new_name }) if $new;
</span><ins>+
+    # FKs will all have the wrong names unless we drop and then let them
+    # be re-created later. Under normal circumstances, checksetup.pl will
+    # automatically re-create these dropped FKs at the end of its DB upgrade
+    # run, so we don't need to re-create them in this method.
+    my @columns = $self-&gt;bz_table_columns($old_name);
+    foreach my $column (@columns) {
+        # these just return silently if there's no FK to drop
+        $self-&gt;bz_drop_fk($old_name, $column);
+        $self-&gt;bz_drop_related_fks($old_name, $column);
+    }
+
</ins><span class="cx">     my @sql = $self-&gt;_bz_real_schema-&gt;get_rename_table_sql($old_name, $new_name);
</span><span class="cx">     print get_text('install_table_rename', 
</span><span class="cx">                    { old =&gt; $old_name, new =&gt; $new_name }) . &quot;\n&quot;
</span><span class="lines">@@ -831,6 +1079,16 @@
</span><span class="cx">     $self-&gt;_bz_store_real_schema;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub bz_set_next_serial_value {
+    my ($self, $table, $column, $value) = @_;
+    if (!$value) {
+        $value = $self-&gt;selectrow_array(&quot;SELECT MAX($column) FROM $table&quot;) || 0;
+        $value++;
+    }
+    my @sql = $self-&gt;_bz_real_schema-&gt;get_set_serial_sql($table, $column, $value);
+    $self-&gt;do($_) foreach @sql;
+}
+
</ins><span class="cx"> #####################################################################
</span><span class="cx"> # Schema Information Methods
</span><span class="cx"> #####################################################################
</span><span class="lines">@@ -899,6 +1157,11 @@
</span><span class="cx">     return \%return_indexes;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub bz_table_list {
+    my ($self) = @_;
+    return $self-&gt;_bz_real_schema-&gt;get_table_list();
+}
+
</ins><span class="cx"> #####################################################################
</span><span class="cx"> # Protected &quot;Real Database&quot; Schema Information Methods
</span><span class="cx"> #####################################################################
</span><span class="lines">@@ -953,7 +1216,10 @@
</span><span class="cx">         # what we need in Bugzilla to be safe, for what we do.
</span><span class="cx">         # Different DBs have different defaults for their isolation
</span><span class="cx">         # level, so we just set it here manually.
</span><del>-        $self-&gt;do('SET TRANSACTION ISOLATION LEVEL ' . $self-&gt;ISOLATION_LEVEL);
</del><ins>+        if ($self-&gt;ISOLATION_LEVEL) {
+            $self-&gt;do('SET TRANSACTION ISOLATION LEVEL ' 
+                      . $self-&gt;ISOLATION_LEVEL);
+        }
</ins><span class="cx">         $self-&gt;{private_bz_transaction_count} = 1;
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="lines">@@ -989,7 +1255,9 @@
</span><span class="cx"> #####################################################################
</span><span class="cx"> 
</span><span class="cx"> sub db_new {
</span><del>-    my ($class, $dsn, $user, $pass, $override_attrs) = @_;
</del><ins>+    my ($class, $params) = @_;
+    my ($dsn, $user, $pass, $override_attrs) = 
+        @$params{qw(dsn user pass attrs)};
</ins><span class="cx"> 
</span><span class="cx">     # set up default attributes used to connect to the database
</span><span class="cx">     # (may be overridden by DB driver implementations)
</span><span class="lines">@@ -1072,7 +1340,7 @@
</span><span class="cx">             $self-&gt;_bz_add_table_raw('bz_schema');
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        print &quot;Initializing the new Schema storage...\n&quot;;
</del><ins>+        print install_string('db_schema_init'), &quot;\n&quot;;
</ins><span class="cx">         my $sth = $self-&gt;prepare(&quot;INSERT INTO bz_schema &quot;
</span><span class="cx">                                  .&quot; (schema_data, version) VALUES (?,?)&quot;);
</span><span class="cx">         $sth-&gt;bind_param(1, $store_me, $self-&gt;BLOB_TYPE);
</span><span class="lines">@@ -1175,14 +1443,13 @@
</span><span class="cx"> 
</span><span class="cx">     # If the table is empty...
</span><span class="cx">     if (!$table_size) {
</span><ins>+        print &quot; $table&quot;;
</ins><span class="cx">         my $insert = $self-&gt;prepare(
</span><span class="cx">             &quot;INSERT INTO $sql_table (value,sortkey) VALUES (?,?)&quot;);
</span><del>-        print &quot;Inserting values into the '$table' table:\n&quot;;
</del><span class="cx">         my $sortorder = 0;
</span><span class="cx">         my $maxlen    = max(map(length($_), @$valuelist)) + 2;
</span><span class="cx">         foreach my $value (@$valuelist) {
</span><span class="cx">             $sortorder += 100;
</span><del>-            printf &quot;%-${maxlen}s sortkey: $sortorder\n&quot;, &quot;'$value'&quot;;
</del><span class="cx">             $insert-&gt;execute($value, $sortorder);
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -1191,33 +1458,55 @@
</span><span class="cx"> # This is used before adding a foreign key to a column, to make sure
</span><span class="cx"> # that the database won't fail adding the key.
</span><span class="cx"> sub _check_references {
</span><del>-    my ($self, $table, $column, $foreign_table, $foreign_column) = @_;
</del><ins>+    my ($self, $table, $column, $fk) = @_;
+    my $foreign_table = $fk-&gt;{TABLE};
+    my $foreign_column = $fk-&gt;{COLUMN};
</ins><span class="cx"> 
</span><ins>+    # We use table aliases because sometimes we join a table to itself,
+    # and we can't use the same table name on both sides of the join.
+    # We also can't use the words &quot;table&quot; or &quot;foreign&quot; because those are
+    # reserved words.
</ins><span class="cx">     my $bad_values = $self-&gt;selectcol_arrayref(
</span><del>-        &quot;SELECT DISTINCT $table.$column 
-           FROM $table LEFT JOIN $foreign_table
-                ON $table.$column = $foreign_table.$foreign_column
-          WHERE $foreign_table.$foreign_column IS NULL
-                AND $table.$column IS NOT NULL&quot;);
</del><ins>+        &quot;SELECT DISTINCT tabl.$column 
+           FROM $table AS tabl LEFT JOIN $foreign_table AS forn
+                ON tabl.$column = forn.$foreign_column
+          WHERE forn.$foreign_column IS NULL
+                AND tabl.$column IS NOT NULL&quot;);
</ins><span class="cx"> 
</span><span class="cx">     if (@$bad_values) {
</span><del>-        my $values = join(', ', @$bad_values);
-        print &lt;&lt;EOT;
-
-ERROR: There are invalid values for the $column column in the $table 
-table. (These values do not exist in the $foreign_table table, in the 
-$foreign_column column.)
-
-Before continuing with checksetup, you will need to fix these values,
-either by deleting these rows from the database, or changing the values
-of $column in $table to point to valid values in $foreign_table.$foreign_column.
-
-The bad values from the $table.$column column are:
-$values
-
-EOT
-        # I just picked a number above 2, to be considered &quot;abnormal exit.&quot;
-        exit 3;
</del><ins>+        my $delete_action = $fk-&gt;{DELETE} || '';
+        if ($delete_action eq 'CASCADE') {
+            $self-&gt;do(&quot;DELETE FROM $table WHERE $column IN (&quot; 
+                      . join(',', ('?') x @$bad_values)  . &quot;)&quot;,
+                      undef, @$bad_values);
+            if (Bugzilla-&gt;usage_mode == USAGE_MODE_CMDLINE) {
+                print &quot;\n&quot;, get_text('install_fk_invalid_fixed',
+                    { table =&gt; $table, column =&gt; $column,
+                      foreign_table =&gt; $foreign_table,
+                      foreign_column =&gt; $foreign_column,
+                      'values' =&gt; $bad_values, action =&gt; 'delete' }), &quot;\n&quot;;
+            }
+        }
+        elsif ($delete_action eq 'SET NULL') {
+            $self-&gt;do(&quot;UPDATE $table SET $column = NULL
+                        WHERE $column IN (&quot;
+                      . join(',', ('?') x @$bad_values)  . &quot;)&quot;,
+                      undef, @$bad_values);
+            if (Bugzilla-&gt;usage_mode == USAGE_MODE_CMDLINE) {
+                print &quot;\n&quot;, get_text('install_fk_invalid_fixed',
+                    { table =&gt; $table, column =&gt; $column,
+                      foreign_table =&gt; $foreign_table, 
+                      foreign_column =&gt; $foreign_column,
+                      'values' =&gt; $bad_values, action =&gt; 'null' }), &quot;\n&quot;;
+            }
+        }
+        else {
+            die &quot;\n&quot;, get_text('install_fk_invalid',
+                { table =&gt; $table, column =&gt; $column,
+                  foreign_table =&gt; $foreign_table,
+                  foreign_column =&gt; $foreign_column,
+                 'values' =&gt; $bad_values }), &quot;\n&quot;;
+        }
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1518,6 +1807,11 @@
</span><span class="cx"> 
</span><span class="cx"> =item C&lt;$pattern&gt; - the regular expression to search for (scalar)
</span><span class="cx"> 
</span><ins>+=item C&lt;$nocheck&gt; - true if the pattern should not be tested; false otherwise (boolean)
+
+=item C&lt;$real_pattern&gt; - the real regular expression to search for.
+This argument is used when C&lt;$pattern&gt; is a placeholder ('?').
+
</ins><span class="cx"> =back
</span><span class="cx"> 
</span><span class="cx"> =item B&lt;Returns&gt;
</span><span class="lines">@@ -1540,14 +1834,8 @@
</span><span class="cx"> 
</span><span class="cx"> =item B&lt;Params&gt;
</span><span class="cx"> 
</span><del>-=over
</del><ins>+Same as L&lt;/sql_regexp&gt;.
</ins><span class="cx"> 
</span><del>-=item C&lt;$expr&gt; - SQL expression for the text to be searched (scalar)
-
-=item C&lt;$pattern&gt; - the regular expression to search for (scalar)
-
-=back
-
</del><span class="cx"> =item B&lt;Returns&gt;
</span><span class="cx"> 
</span><span class="cx"> Formatted SQL for negative regular expression search (e.g. NOT REGEXP) 
</span><span class="lines">@@ -1660,13 +1948,13 @@
</span><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><del>-=item C&lt;sql_interval&gt;
</del><ins>+=item C&lt;sql_date_math&gt;
</ins><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><span class="cx"> =item B&lt;Description&gt;
</span><span class="cx"> 
</span><del>-Outputs proper SQL syntax for a time interval function.
</del><ins>+Outputs proper SQL syntax for adding some amount of time to a date.
</ins><span class="cx"> 
</span><span class="cx"> Abstract method, should be overridden by database specific code.
</span><span class="cx"> 
</span><span class="lines">@@ -1674,15 +1962,28 @@
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><del>-=item C&lt;$interval&gt; - the time interval requested (e.g. '30') (integer)
</del><ins>+=item C&lt;$date&gt;
</ins><span class="cx"> 
</span><del>-=item C&lt;$units&gt; - the units the interval is in (e.g. 'MINUTE') (string)
</del><ins>+C&lt;string&gt; The date being added to or subtracted from.
</ins><span class="cx"> 
</span><ins>+=item C&lt;$operator&gt;
+
+C&lt;string&gt; Either C&lt;-&gt; or C&lt;+&gt;, depending on whether you're subtracting
+or adding.
+
+=item C&lt;$interval&gt;
+
+C&lt;integer&gt; The time interval you're adding or subtracting (e.g. C&lt;30&gt;)
+
+=item C&lt;$units&gt; 
+
+C&lt;string&gt; the units the interval is in (e.g. 'MINUTE')
+
</ins><span class="cx"> =back
</span><span class="cx"> 
</span><span class="cx"> =item B&lt;Returns&gt;
</span><span class="cx"> 
</span><del>-Formatted SQL for interval function (scalar)
</del><ins>+Formatted SQL for adding or subtracting a date and some amount of time (scalar)
</ins><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><span class="lines">@@ -1774,15 +2075,42 @@
</span><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><ins>+=item C&lt;sql_string_until&gt;
+
+=over
+
+=item B&lt;Description&gt;
+
+Returns SQL for truncating a string at the first occurrence of a certain
+substring.
+
+=item B&lt;Params&gt;
+
+Note that both parameters need to be sql-quoted.
+
+=item C&lt;$string&gt; The string we're truncating
+
+=item C&lt;$substring&gt; The substring we're truncating at.
+
+=back
+
</ins><span class="cx"> =item C&lt;sql_fulltext_search&gt;
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><span class="cx"> =item B&lt;Description&gt;
</span><span class="cx"> 
</span><del>-Returns SQL syntax for performing a full text search for specified text 
-on a given column.
</del><ins>+Returns one or two SQL expressions for performing a full text search for
+specified text on a given column.
</ins><span class="cx"> 
</span><ins>+If one value is returned, it is a numeric expression that indicates
+a match with a positive value and a non-match with zero. In this case,
+the DB must support casting numeric expresions to booleans.
+
+If two values are returned, then the first value is a boolean expression
+that indicates the presence of a match, and the second value is a numeric
+expression that can be used for ranking.
+
</ins><span class="cx"> There is a ANSI SQL version of this method implemented using LIKE operator,
</span><span class="cx"> but it's not a real full text search. DB specific modules should override 
</span><span class="cx"> this, as this generic implementation will be always much slower. This 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaErrorpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Error.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Error.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Error.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -31,6 +31,9 @@
</span><span class="cx"> use Bugzilla::Constants;
</span><span class="cx"> use Bugzilla::WebService::Constants;
</span><span class="cx"> use Bugzilla::Util;
</span><ins>+
+use Carp;
+use Data::Dumper;
</ins><span class="cx"> use Date::Format;
</span><span class="cx"> 
</span><span class="cx"> # We cannot use $^S to detect if we are in an eval(), because mod_perl
</span><span class="lines">@@ -64,7 +67,7 @@
</span><span class="cx">         for (1..75) { $mesg .= &quot;-&quot;; };
</span><span class="cx">         $mesg .= &quot;\n[$$] &quot; . time2str(&quot;%D %H:%M:%S &quot;, time());
</span><span class="cx">         $mesg .= &quot;$name $error &quot;;
</span><del>-        $mesg .= &quot;$ENV{REMOTE_ADDR} &quot; if $ENV{REMOTE_ADDR};
</del><ins>+        $mesg .= remote_ip();
</ins><span class="cx">         $mesg .= Bugzilla-&gt;user-&gt;login;
</span><span class="cx">         $mesg .= (' actually ' . Bugzilla-&gt;sudoer-&gt;login) if Bugzilla-&gt;sudoer;
</span><span class="cx">         $mesg .= &quot;\n&quot;;
</span><span class="lines">@@ -89,31 +92,63 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     my $template = Bugzilla-&gt;template;
</span><ins>+    my $message;
+    # There are some tests that throw and catch a lot of errors,
+    # and calling $template-&gt;process over and over for those errors
+    # is too slow. So instead, we just &quot;die&quot; with a dump of the arguments.
+    if (Bugzilla-&gt;error_mode != ERROR_MODE_TEST) {
+        $template-&gt;process($name, $vars, \$message)
+          || ThrowTemplateError($template-&gt;error());
+    }
+
+    # Let's call the hook first, so that extensions can override
+    # or extend the default behavior, or add their own error codes.
+    require Bugzilla::Hook;
+    Bugzilla::Hook::process('error_catch', { error =&gt; $error, vars =&gt; $vars,
+                                             message =&gt; \$message });
+
</ins><span class="cx">     if (Bugzilla-&gt;error_mode == ERROR_MODE_WEBPAGE) {
</span><span class="cx">         print Bugzilla-&gt;cgi-&gt;header();
</span><del>-        $template-&gt;process($name, $vars)
-          || ThrowTemplateError($template-&gt;error());
</del><ins>+        print $message;
</ins><span class="cx">     }
</span><del>-    else {
-        my $message;
-        $template-&gt;process($name, $vars, \$message)
-          || ThrowTemplateError($template-&gt;error());
-        if (Bugzilla-&gt;error_mode == ERROR_MODE_DIE) {
-            die(&quot;$message\n&quot;);
</del><ins>+    elsif (Bugzilla-&gt;error_mode == ERROR_MODE_TEST) {
+        die Dumper($vars);
+    }
+    elsif (Bugzilla-&gt;error_mode == ERROR_MODE_DIE) {
+        die(&quot;$message\n&quot;);
+    }
+    elsif (Bugzilla-&gt;error_mode == ERROR_MODE_DIE_SOAP_FAULT
+           || Bugzilla-&gt;error_mode == ERROR_MODE_JSON_RPC)
+    {
+        # Clone the hash so we aren't modifying the constant.
+        my %error_map = %{ WS_ERROR_CODE() };
+        Bugzilla::Hook::process('webservice_error_codes',
+                                { error_map =&gt; \%error_map });
+        my $code = $error_map{$error};
+        if (!$code) {
+            $code = ERROR_UNKNOWN_FATAL if $name =~ /code/i;
+            $code = ERROR_UNKNOWN_TRANSIENT if $name =~ /user/i;
</ins><span class="cx">         }
</span><del>-        elsif (Bugzilla-&gt;error_mode == ERROR_MODE_DIE_SOAP_FAULT) {
-            # Clone the hash so we aren't modifying the constant.
-            my %error_map = %{ WS_ERROR_CODE() };
-            require Bugzilla::Hook;
-            Bugzilla::Hook::process('webservice-error_codes', 
-                                    { error_map =&gt; \%error_map });
-            my $code = $error_map{$error};
-            if (!$code) {
-                $code = ERROR_UNKNOWN_FATAL if $name =~ /code/i;
-                $code = ERROR_UNKNOWN_TRANSIENT if $name =~ /user/i;
-            }
</del><ins>+
+        if (Bugzilla-&gt;error_mode == ERROR_MODE_DIE_SOAP_FAULT) {
</ins><span class="cx">             die SOAP::Fault-&gt;faultcode($code)-&gt;faultstring($message);
</span><span class="cx">         }
</span><ins>+        else {
+            my $server = Bugzilla-&gt;_json_server;
+            # Technically JSON-RPC isn't allowed to have error numbers
+            # higher than 999, but we do this to avoid conflicts with
+            # the internal JSON::RPC error codes.
+            $server-&gt;raise_error(code    =&gt; 100000 + $code,
+                                 message =&gt; $message,
+                                 id      =&gt; $server-&gt;{_bz_request_id},
+                                 version =&gt; $server-&gt;version);
+            # Most JSON-RPC Throw*Error calls happen within an eval inside
+            # of JSON::RPC. So, in that circumstance, instead of exiting,
+            # we die with no message. JSON::RPC checks raise_error before
+            # it checks $@, so it returns the proper error.
+            die if _in_eval();
+            $server-&gt;response($server-&gt;error_response_header);
+        }
</ins><span class="cx">     }
</span><span class="cx">     exit;
</span><span class="cx"> }
</span><span class="lines">@@ -123,6 +158,16 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub ThrowCodeError {
</span><ins>+    my (undef, $vars) = @_;
+
+    # Don't show function arguments, in case they contain
+    # confidential data.
+    local $Carp::MaxArgNums = -1;
+    # Don't show the error as coming from Bugzilla::Error, show it
+    # as coming from the caller.
+    local $Carp::CarpInternal{'Bugzilla::Error'} = 1;
+    $vars-&gt;{traceback} = Carp::longmess();
+
</ins><span class="cx">     _throw_error(&quot;global/code-error.html.tmpl&quot;, @_);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaExtensionpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/Extension.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Extension.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Extension.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,823 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Everything Solved, Inc.
+# Portions created by the Initial Developers are Copyright (C) 2009 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+package Bugzilla::Extension;
+use strict;
+
+use Bugzilla::Constants;
+use Bugzilla::Error;
+use Bugzilla::Install::Util qw(
+    extension_code_files extension_template_directory 
+    extension_package_directory extension_web_directory);
+
+use File::Basename;
+use File::Spec;
+
+####################
+# Subclass Methods #
+####################
+
+sub new {
+    my ($class, $params) = @_;
+    $params ||= {};
+    bless $params, $class;
+    return $params;
+}
+
+#######################################
+# Class (Bugzilla::Extension) Methods #
+#######################################
+
+sub load {
+    my ($class, $extension_file, $config_file) = @_;
+    my $package;
+
+    # This is needed during checksetup.pl, because Extension packages can 
+    # only be loaded once (they return &quot;1&quot; the second time they're loaded,
+    # instead of their name). During checksetup.pl, extensions are loaded
+    # once by Bugzilla::Install::Requirements, and then later again via
+    # Bugzilla-&gt;extensions (because of hooks).
+    my $map = Bugzilla-&gt;request_cache-&gt;{extension_requirement_package_map};
+
+    if ($config_file) {
+        if ($map and defined $map-&gt;{$config_file}) {
+            $package = $map-&gt;{$config_file};
+        }
+        else {
+            my $name = require $config_file;
+            if ($name =~ /^\d+$/) {
+                ThrowCodeError('extension_must_return_name',
+                               { extension =&gt; $config_file, 
+                                 returned  =&gt; $name });
+            }
+            $package = &quot;${class}::$name&quot;;
+        }
+
+        __do_call($package, 'modify_inc', $config_file);
+    }
+
+    if ($map and defined $map-&gt;{$extension_file}) {
+        $package = $map-&gt;{$extension_file};
+        $package-&gt;modify_inc($extension_file) if !$config_file;
+    }
+    else {
+        my $name = require $extension_file;
+        if ($name =~ /^\d+$/) {
+            ThrowCodeError('extension_must_return_name', 
+                           { extension =&gt; $extension_file, returned =&gt; $name });
+        }
+        $package = &quot;${class}::$name&quot;;
+        $package-&gt;modify_inc($extension_file) if !$config_file;
+    }
+
+    $class-&gt;_validate_package($package, $extension_file);
+    return $package;
+}
+
+sub _validate_package {
+    my ($class, $package, $extension_file) = @_;
+
+    # For extensions from data/extensions/additional, we don't have a file
+    # name, so we fake it.
+    if (!$extension_file) {
+        $extension_file = $package;
+        $extension_file =~ s/::/\//g;
+        $extension_file .= '.pm';
+    }
+
+    if (!eval { $package-&gt;NAME }) {
+        ThrowCodeError('extension_no_name', 
+                       { filename =&gt; $extension_file, package =&gt; $package });
+    }
+
+    if (!$package-&gt;isa($class)) {
+        ThrowCodeError('extension_must_be_subclass',
+                       { filename =&gt; $extension_file,
+                         package  =&gt; $package,
+                         class    =&gt; $class });
+    }
+}
+
+sub load_all {
+    my $class = shift;
+    my ($file_sets, $extra_packages) = extension_code_files();
+    my @packages;
+    foreach my $file_set (@$file_sets) {
+        my $package = $class-&gt;load(@$file_set);
+        push(@packages, $package);
+    }
+
+    # Extensions from data/extensions/additional
+    foreach my $package (@$extra_packages) {
+        # Don't load an &quot;additional&quot; extension if we already have an extension
+        # loaded with that name.
+        next if grep($_ eq $package, @packages);
+        # Untaint the package name
+        $package =~ /([\w:]+)/;
+        $package = $1;
+        eval(&quot;require $package&quot;) || die $@;
+        $package-&gt;_validate_package($package);
+        push(@packages, $package);
+    }
+
+    return \@packages;
+}
+
+# Modifies @INC so that extensions can use modules like
+# &quot;use Bugzilla::Extension::Foo::Bar&quot;, when Bar.pm is in the lib/
+# directory of the extension.
+sub modify_inc {
+    my ($class, $file) = @_;
+
+    # Note that this package_dir call is necessary to set things up
+    # for my_inc, even if we didn't take its return value.
+    my $package_dir = __do_call($class, 'package_dir', $file);
+    # Don't modify @INC for extensions that are just files in the extensions/
+    # directory. We don't want Bugzilla's base lib/CGI.pm being loaded as 
+    # Bugzilla::Extension::Foo::CGI or any other confusing thing like that.
+    return if $package_dir eq bz_locations-&gt;{'extensionsdir'};
+    unshift(@INC, sub { __do_call($class, 'my_inc', @_) });
+}
+
+# This is what gets put into @INC by modify_inc.
+sub my_inc {
+    my ($class, undef, $file) = @_;
+    
+    # This avoids infinite recursion in case anything inside of this function
+    # does a &quot;require&quot;. (I know for sure that File::Spec-&gt;case_tolerant does
+    # a &quot;require&quot; on Windows, for example.)
+    return if $file !~ /^Bugzilla/;
+
+    my $lib_dir = __do_call($class, 'lib_dir');
+    my @class_parts = split('::', $class);
+    my ($vol, $dir, $file_name) = File::Spec-&gt;splitpath($file);
+    my @dir_parts = File::Spec-&gt;splitdir($dir);
+    # File::Spec::Win32 (any maybe other OSes) add an empty directory at the
+    # end of @dir_parts.
+    @dir_parts = grep { $_ ne '' } @dir_parts;
+    # Validate that this is a sub-package of Bugzilla::Extension::Foo ($class).
+    for (my $i = 0; $i &lt; scalar(@class_parts); $i++) {
+        return if !@dir_parts;
+        if (File::Spec-&gt;case_tolerant) {
+            return if lc($class_parts[$i]) ne lc($dir_parts[0]);
+        }
+        else {
+            return if $class_parts[$i] ne $dir_parts[0];
+        }
+        shift(@dir_parts);
+    }
+    # For Bugzilla::Extension::Foo::Bar, this would look something like
+    # extensions/Example/lib/Bar.pm
+    my $resolved_path = File::Spec-&gt;catfile($lib_dir, @dir_parts, $file_name);
+    open(my $fh, '&lt;', $resolved_path);
+    return $fh;
+}
+
+####################
+# Instance Methods #
+####################
+
+use constant enabled =&gt; 1;
+
+sub lib_dir {
+    my $invocant = shift;
+    my $package_dir = __do_call($invocant, 'package_dir');
+    # For extensions that are just files in the extensions/ directory,
+    # use the base lib/ dir as our &quot;lib_dir&quot;. Note that Bugzilla never
+    # uses lib_dir in this case, though, because modify_inc is prevented
+    # from modifying @INC when we're just a file in the extensions/ directory.
+    # So this particular code block exists just to make lib_dir return
+    # something right in case an extension needs it for some odd reason.
+    if ($package_dir eq bz_locations()-&gt;{'extensionsdir'}) {
+        return bz_locations-&gt;{'ext_libpath'};
+    }
+    return File::Spec-&gt;catdir($package_dir, 'lib');
+}
+
+sub template_dir { return extension_template_directory(@_); }
+sub package_dir  { return extension_package_directory(@_);  }
+sub web_dir      { return extension_web_directory(@_);      }
+
+######################
+# Helper Subroutines #
+######################
+
+# In order to not conflict with extensions' private subroutines, any helpers
+# here should start with a double underscore.
+
+# This is for methods that can optionally be overridden in Config.pm.
+# It falls back to the local implementation if $class cannot do
+# the method. This is necessary because Config.pm is not a subclass of
+# Bugzilla::Extension.
+sub __do_call {
+    my ($class, $method, @args) = @_;
+    if ($class-&gt;can($method)) {
+        return $class-&gt;$method(@args);
+    }
+    my $function_ref;
+    { no strict 'refs'; $function_ref = \&amp;{$method}; }
+    return $function_ref-&gt;($class, @args);
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::Extension - Base class for Bugzilla Extensions.
+
+=head1 SYNOPSIS
+
+The following would be in F&lt;extensions/Foo/Extension.pm&gt; or 
+F&lt;extensions/Foo.pm&gt;:
+
+ package Bugzilla::Extension::Foo
+ use strict;
+ use base qw(Bugzilla::Extension);
+
+ our $VERSION = '0.02';
+ use constant NAME =&gt; 'Foo';
+
+ sub some_hook_name { ... }
+
+ __PACKAGE__-&gt;NAME;
+
+Custom templates would go into F&lt;extensions/Foo/template/en/default/&gt;.
+L&lt;Template hooks|/Template Hooks&gt; would go into 
+F&lt;extensions/Foo/template/en/default/hook/&gt;.
+
+=head1 DESCRIPTION
+
+This is the base class for all Bugzilla extensions.
+
+=head1 WRITING EXTENSIONS
+
+The L&lt;/SYNOPSIS&gt; above gives a pretty good overview of what's basically
+required to write an extension. This section gives more information
+on exactly how extensions work and how you write them. There is also a 
+L&lt;wiki page|https://wiki.mozilla.org/Bugzilla:Extension_Notes&gt; with additional HOWTOs, tips and tricks.
+
+=head2 Using F&lt;extensions/create.pl&gt;
+
+There is a script, L&lt;extensions::create&gt;, that will set up the framework
+of a new extension for you. To use it, pick a name for your extension
+and, in the base bugzilla directory, do:
+
+C&lt;extensions/create.pl NAME&gt;
+
+But replace C&lt;NAME&gt; with the name you picked for your extension. That
+will create a new directory in the F&lt;extensions/&gt; directory with the name
+of your extension. The directory will contain a full framework for
+a new extension, with helpful comments in each file describing things
+about them.
+
+=head2 Example Extension
+
+There is a sample extension in F&lt;extensions/Example/&gt; that demonstrates
+most of the things described in this document, so if you find the
+documentation confusing, try just reading the code instead.
+
+=head2 Where Extension Code Goes
+
+Extension code lives under the F&lt;extensions/&gt; directory in Bugzilla.
+
+There are two ways to write extensions:
+
+=over
+
+=item 1
+
+If your extension will have only code and no templates or other files,
+you can create a simple C&lt;.pm&gt; file in the F&lt;extensions/&gt; directory. 
+
+For example, if you wanted to create an extension called &quot;Foo&quot; using this
+method, you would put your code into a file called F&lt;extensions/Foo.pm&gt;.
+
+=item 2
+
+If you plan for your extension to have templates and other files, you
+can create a whole directory for your extension, and the main extension
+code would go into a file called F&lt;Extension.pm&gt; in that directory.
+
+For example, if you wanted to create an extension called &quot;Foo&quot; using this
+method, you would put your code into a file called
+F&lt;extensions/Foo/Extension.pm&gt;.
+
+=back
+
+=head2 The Extension C&lt;NAME&gt;.
+
+The &quot;name&quot; of an extension shows up in several places:
+
+=over
+
+=item 1
+
+The name of the package:
+
+C&lt;package Bugzilla::Extension::Foo;&gt;
+
+=item 2
+
+In a C&lt;NAME&gt; constant that B&lt;must&gt; be defined for every extension:
+
+C&lt;&lt; use constant NAME =&gt; 'Foo'; &gt;&gt;
+
+=item 3
+
+At the very end of the file:
+
+C&lt;&lt; __PACKAGE__-&gt;NAME; &gt;&gt;
+
+You'll notice that though most Perl packages end with C&lt;1;&gt;, Bugzilla
+Extensions must B&lt;always&gt; end with C&lt;&lt; __PACKAGE__-&gt;NAME; &gt;&gt;.
+
+=back
+
+The name must be identical in all of those locations.
+
+=head2 Hooks
+
+In L&lt;Bugzilla::Hook&gt;, there is a L&lt;list of hooks|Bugzilla::Hook/HOOKS&gt;.
+These are the various areas of Bugzilla that an extension can &quot;hook&quot; into,
+which allow your extension to perform code during that point in Bugzilla's
+execution.
+
+If your extension wants to implement a hook, all you have to do is
+write a subroutine in your hook package that has the same name as
+the hook. The subroutine will be called as a method on your extension,
+and it will get the arguments specified in the hook's documentation as
+named parameters in a hashref.
+
+For example, here's an implementation of a hook named C&lt;foo_start&gt;
+that gets an argument named C&lt;bar&gt;:
+
+ sub foo_start {
+     my ($self, $args) = @_;
+     my $bar = $args-&gt;{bar};
+     print &quot;I got $bar!\n&quot;;
+ }
+
+And that would go into your extension's code file--the file that was
+described in the L&lt;/Where Extension Code Goes&gt; section above.
+
+During your subroutine, you may want to know what values were passed
+as CGI arguments  to the current script, or what arguments were passed to
+the current WebService method. You can get that data via 
+L&lt;Bugzilla/input_params&gt;.
+
+=head3 Adding New Hooks To Bugzilla
+
+If you need a new hook for your extension and you want that hook to be
+added to Bugzilla itself, see our development process at 
+L&lt;http://wiki.mozilla.org/Bugzilla:Developers&gt;.
+
+In order for a new hook to be accepted into Bugzilla, it has to work,
+it must have documentation in L&lt;Bugzilla::Hook&gt;, and it must have example
+code in F&lt;extensions/Example/Extension.pm&gt;.
+
+One question that is often asked about new hooks is, &quot;Is this the most
+flexible way to implement this hook?&quot; That is, the more power extension
+authors get from a hook, the more likely it is to be accepted into Bugzilla.
+Hooks that only hook a very specific part of Bugzilla will not be accepted
+if their functionality can be accomplished equally well with a more generic
+hook.
+
+=head2 If Your Extension Requires Certain Perl Modules
+
+If there are certain Perl modules that your extension requires in order
+to run, there is a way you can tell Bugzilla this, and then L&lt;checksetup&gt;
+will make sure that those modules are installed, when you run L&lt;checksetup&gt;.
+
+To do this, you need to specify a constant called C&lt;REQUIRED_MODULES&gt;
+in your extension. This constant has the same format as
+L&lt;Bugzilla::Install::Requirements/REQUIRED_MODULES&gt;.
+
+If there are optional modules that add additional functionality to your
+application, you can specify them in a constant called OPTIONAL_MODULES,
+which has the same format as 
+L&lt;Bugzilla::Install::Requirements/OPTIONAL_MODULES&gt;.
+
+=head3 If Your Extension Needs Certain Modules In Order To Compile
+
+If your extension needs a particular Perl module in order to
+I&lt;compile&gt;, then you have a &quot;chicken and egg&quot; problem--in order to
+read C&lt;REQUIRED_MODULES&gt;, we have to compile your extension. In order
+to compile your extension, we need to already have the modules in
+C&lt;REQUIRED_MODULES&gt;!
+
+To get around this problem, Bugzilla allows you to have an additional
+file, besides F&lt;Extension.pm&gt;, called F&lt;Config.pm&gt;, that contains
+just C&lt;REQUIRED_MODULES&gt;. If you have a F&lt;Config.pm&gt;, it must also
+contain the C&lt;NAME&gt; constant, instead of your main F&lt;Extension.pm&gt;
+containing the C&lt;NAME&gt; constant.
+
+The contents of the file would look something like this for an extension
+named C&lt;Foo&gt;:
+
+  package Bugzilla::Extension::Foo;
+  use strict;
+  use constant NAME =&gt; 'Foo';
+  use constant REQUIRED_MODULES =&gt; [
+    {
+      package =&gt; 'Some-Package',
+      module  =&gt; 'Some::Module',
+      version =&gt; 0,
+    }
+  ];
+  __PACKAGE__-&gt;NAME;
+
+Note that it is I&lt;not&gt; a subclass of C&lt;Bugzilla::Extension&gt;, because
+at the time that module requirements are being checked in L&lt;checksetup&gt;,
+C&lt;Bugzilla::Extension&gt; cannot be loaded. Also, just like F&lt;Extension.pm&gt;,
+it ends with C&lt;&lt; __PACKAGE__-&gt;NAME; &gt;&gt;. Note also that it has the 
+B&lt;exact same&gt; C&lt;package&gt; name as F&lt;Extension.pm&gt;.
+
+This file may not use any Perl modules other than L&lt;Bugzilla::Constants&gt;,
+L&lt;Bugzilla::Install::Util&gt;, L&lt;Bugzilla::Install::Requirements&gt;, and 
+modules that ship with Perl itself.
+
+If you want to define both C&lt;REQUIRED_MODULES&gt; and C&lt;OPTIONAL_MODULES&gt;,
+they must both be in F&lt;Config.pm&gt; or both in F&lt;Extension.pm&gt;.
+
+Every time your extension is loaded by Bugzilla, F&lt;Config.pm&gt; will be
+read and then F&lt;Extension.pm&gt; will be read, so your methods in F&lt;Extension.pm&gt;
+will have access to everything in F&lt;Config.pm&gt;. Don't define anything
+with an identical name in both files, or Perl may throw a warning that
+you are redefining things.
+
+This method of setting C&lt;REQUIRED_MODULES&gt; is of course not available if 
+your extension is a single file named C&lt;Foo.pm&gt;.
+
+If any of this is confusing, just look at the code of the Example extension.
+It uses this method to specify requirements.
+
+=head2 Libraries
+
+Extensions often want to have their own Perl modules. Your extension
+can load any Perl module in its F&lt;lib/&gt; directory. (So, if your extension is 
+F&lt;extensions/Foo/&gt;, then your Perl modules go into F&lt;extensions/Foo/lib/&gt;.)
+
+However, the C&lt;package&gt; name of your libraries will not work quite
+like normal Perl modules do. F&lt;extensions/Foo/lib/Bar.pm&gt; is
+loaded as C&lt;Bugzilla::Extension::Foo::Bar&gt;. Or, to say it another way,
+C&lt;use Bugzilla::Extension::Foo::Bar;&gt; loads F&lt;extensions/Foo/lib/Bar.pm&gt;,
+which should have C&lt;package Bugzilla::Extension::Foo::Bar;&gt; as its package
+name.
+
+This allows any place in Bugzilla to load your modules, which is important
+for some hooks. It even allows other extensions to load your modules, and 
+allows you to install your modules into the global Perl install
+as F&lt;Bugzilla/Extension/Foo/Bar.pm&gt;, if you'd like, which helps allow CPAN
+distribution of Bugzilla extensions.
+
+B&lt;Note:&gt; If you want to C&lt;use&gt; or C&lt;require&gt; a module that's in 
+F&lt;extensions/Foo/lib/&gt; at the top level of your F&lt;Extension.pm&gt;,
+you must have a F&lt;Config.pm&gt; (see above) with at least the C&lt;NAME&gt;
+constant defined in it.
+
+=head2 Templates
+
+Extensions store templates in a C&lt;template&gt; subdirectory of the extension.
+(Obviously, this isn't available for extensions that aren't a directory.)
+
+The format of this directory is exactly like the normal layout of Bugzilla's
+C&lt;template&gt; directory--in fact, your extension's C&lt;template&gt; directory
+becomes part of Bugzilla's template &quot;search path&quot; as described in
+L&lt;Bugzilla::Install::Util/template_include_path&gt;.
+
+You can actually include templates in your extension without having any
+C&lt;.pm&gt; files in your extension at all, if you want. (That is, it's entirely
+valid to have an extension that's just template files and no code files.)
+
+Bugzilla's templates are written in a language called Template Toolkit.
+You can find out more about Template Toolkit at L&lt;http://template-toolkit.org&gt;.
+
+There are two ways to extend or modify Bugzilla's templates: you can use
+template hooks (described below) or you can override existing templates
+entirely (described further down).
+
+=head2 Template Hooks
+
+Templates can be extended using a system of &quot;hooks&quot; that add new UI elements
+to a particular area of Bugzilla without modifying the code of the existing
+templates. This is the recommended way for extensions to modify the user
+interface of Bugzilla.
+
+=head3 Which Templates Can Be Hooked
+
+There is no list of template hooks like there is for standard code hooks.
+To find what places in the user interface can be hooked, search for the 
+string C&lt;Hook.process&gt; in Bugzilla's templates (in the 
+F&lt;template/en/default/&gt; directory). That will also give you the name of 
+the hooks--the first argument to C&lt;Hook.process&gt; is the name of the hook.
+(A later section in this document explains how to use that name).
+
+For example, if you see C&lt;Hook.process(&quot;additional_header&quot;)&gt;, that means 
+the name of the hook is C&lt;additional_header&gt;.
+
+=head3 Where Template Hooks Go
+
+To extend templates in your extension using template hooks, you put files into
+the F&lt;template/en/default/hook&gt; directory of your extension. So, if you had an
+extension called &quot;Foo&quot;, your template extensions would go into
+F&lt;extensions/Foo/template/en/default/hook/&gt;.
+
+(Note that the base F&lt;template/en/default/hook&gt; directory in Bugzilla itself
+also works, although you would never use that for an extension that you
+intended to distribute.)
+
+The files that go into this directory have a certain name, based on the
+name of the template that is being hooked, and the name of the hook.
+For example, let's imagine that you have an extension named &quot;Foo&quot;,
+and you want to use the C&lt;additional_header&gt; hook in 
+F&lt;template/en/default/global/header.html.tmpl&gt;. Your code would go into
+F&lt;extensions/Foo/template/en/default/hook/global/header-additional_header.html.tmpl&gt;. Any code you put into that file will happen at the point that 
+C&lt;Hook.process(&quot;additional_header&quot;)&gt; is called in 
+F&lt;template/en/default/global/header.html.tmpl&gt;.
+
+As you can see, template extension file names follow a pattern. The
+pattern looks like:
+
+ &lt;templates&gt;/hook/&lt;template path&gt;/&lt;template name&gt;-&lt;hook name&gt;.&lt;template type&gt;.tmpl
+
+=over
+
+=item &lt;templates&gt;
+
+This is the full path to the template directory, like 
+F&lt;extensions/Foo/template/en/default&gt;. This works much like normal templates
+do, in the sense that template extensions in C&lt;custom&gt; override template
+extensions in C&lt;default&gt; for your extension, templates for different languages
+can be supplied, etc. Template extensions are searched for and run in the
+order described in L&lt;Bugzilla::Install::Util/template_include_path&gt;.
+
+The difference between normal templates and template hooks is that hooks
+will be run for I&lt;every&gt; extension, whereas for normal templates, Bugzilla
+just takes the first one it finds and stops searching. So while a template
+extension in the C&lt;custom&gt; directory may override the same-named template
+extension in the  C&lt;default&gt; directory I&lt;within your Bugzilla extension&gt;,
+it will not override the same-named template extension in the C&lt;default&gt; 
+directory of another Bugzilla extension.
+
+=item &lt;template path&gt;
+
+This is the part of the path (excluding the filename) that comes after 
+F&lt;template/en/default/&gt; in a template's path. So, for 
+F&lt;template/en/default/global/header.html.tmpl&gt;, this would simply be
+C&lt;global&gt;.
+
+=item &lt;template name&gt;
+
+This is the file name of the template, before the C&lt;.html.tmpl&gt; part.
+So, for F&lt;template/en/default/global/header.html.tmpl&gt;, this would be
+C&lt;header&gt;.
+
+=item &lt;hook name&gt;
+
+This is the name of the hook--what you saw in C&lt;Hook.process&gt; inside
+of the template you want to hook. In our example, this is 
+C&lt;additional_header&gt;.
+
+=item &lt;template type&gt;
+
+This is what comes after the template name but before C&lt;.tmpl&gt; in the
+template's path. In most cases this is C&lt;html&gt;, but sometimes it's
+C&lt;none&gt;, C&lt;txt&gt;, C&lt;js&gt;, or various other formats, indicating what
+type of output the template has.
+
+=back
+
+=head3 Adding New Template Hooks to Bugzilla
+
+Adding new template hooks is just like adding code hooks (see 
+L&lt;/Adding New Hooks To Bugzilla&gt;) except that you don't have to
+document them, and including example code is optional.
+
+=head2 Overriding Existing Templates
+
+Sometimes you don't want to extend a template, you just want to replace
+it entirely with your extension's template, or you want to add an entirely
+new template to Bugzilla for your extension to use.
+
+To replace the F&lt;template/en/default/global/banner.html.tmpl&gt; template
+in an extension named &quot;Foo&quot;, create a file called 
+F&lt;extensions/Foo/template/en/default/global/banner.html.tmpl&gt;. Note that this
+is very similar to the path for a template hook, except that it excludes
+F&lt;hook/&gt;, and the template is named I&lt;exactly&gt; like the standard Bugzilla
+template. 
+
+You can also use this method to add entirely new templates. If you have
+an extension named &quot;Foo&quot;, and you add a file named
+F&lt;extensions/Foo/template/en/default/foo/bar.html.tmpl&gt;, you can load
+that in your code using C&lt;&lt; $template-&gt;process('foo/bar.html.tmpl') &gt;&gt;.
+
+=head3 A Warning About Extensions That You Want To Distribute
+
+You should never override an existing Bugzilla template in an
+extension that you plan to distribute to others, because only one extension
+can override any given template, and which extension will &quot;win&quot; that war
+if there are multiple extensions installed is totally undefined.
+
+However, adding new templates in an extension that you want to distribute
+is fine, though you have to be careful about how you name them, because
+any templates with an identical path and name (say, both called
+F&lt;global/stuff.html.tmpl&gt;) will conflict. The usual way to work around
+this is to put all your custom templates into a template path that's
+named after your extension (since the name of your extension has to be
+unique anyway). So if your extension was named Foo, your custom templates
+would go into F&lt;extensions/Foo/template/en/default/foo/&gt;. The only
+time that doesn't work is with the C&lt;page_before_template&gt; extension, in which
+case your templates should probably be in a directory like
+F&lt;extensions/Foo/template/en/default/page/foo/&gt; so as not to conflict with
+other pages that other extensions might add.
+
+=head2 CSS, JavaScript, and Images
+
+If you include CSS, JavaScript, and images in your extension that are
+served directly to the user (that is, they're not read by a script and
+then printed--they're just linked directly in your HTML), they should go
+into the F&lt;web/&gt; subdirectory of your extension. 
+
+So, for example, if you had a CSS file called F&lt;style.css&gt; and your
+extension was called F&lt;Foo&gt;, your file would go into 
+F&lt;extensions/Foo/web/style.css&gt;.
+
+=head2 Disabling Your Extension
+
+If you want your extension to be totally ignored by Bugzilla (it will
+not be compiled or seen to exist at all), then create a file called
+C&lt;disabled&gt; in your extension's directory. (If your extension is just
+a file, like F&lt;extensions/Foo.pm&gt;, you cannot use this method to disable
+your extension, and will just have to remove it from the directory if you
+want to totally disable it.) Note that if you are running under mod_perl,
+you may have to restart your web server for this to take effect.
+
+If you want your extension to be compiled and have L&lt;checksetup&gt; check
+for its module pre-requisites, but you don't want the module to be used
+by Bugzilla, then you should make your extension's L&lt;/enabled&gt; method
+return C&lt;0&gt; or some false value.
+
+=head1 DISTRIBUTING EXTENSIONS
+
+If you've made an extension and you want to publish it, the first
+thing you'll want to do is package up your extension's code and
+then put a link to it in the appropriate section of 
+L&lt;http://wiki.mozilla.org/Bugzilla:Addons&gt;.
+
+=head2 Distributing on CPAN
+
+If you want a centralized distribution point that makes it easy
+for Bugzilla users to install your extension, it is possible to 
+distribute your Bugzilla Extension through CPAN.
+
+The details of making a standard CPAN module are too much to
+go into here, but a lot of it is covered in L&lt;perlmodlib&gt;
+and on L&lt;http://www.cpan.org/&gt; among other places.
+
+When you distribute your extension via CPAN, your F&lt;Extension.pm&gt;
+should simply install itself as F&lt;Bugzilla/Extension/Foo.pm&gt;, 
+where C&lt;Foo&gt; is the name of your module. You do not need a separate
+F&lt;Config.pm&gt; file, because CPAN itself will handle installing
+the prerequisites of your module, so Bugzilla doesn't have to
+worry about it.
+
+=head3 Templates in extensions distributed on CPAN
+
+If your extension is F&lt;/usr/lib/perl5/Bugzilla/Extension/Foo.pm&gt;,
+then Bugzilla will look for templates in the directory
+F&lt;/usr/lib/perl5/Bugzilla/Extension/Foo/template/&gt;.
+
+You can change this behavior by overriding the L&lt;/template_dir&gt;
+or L&lt;/package_dir&gt; methods described lower down in this document.
+
+=head3 Using an extension distributed on CPAN
+
+There is a file named F&lt;data/extensions/additional&gt; in Bugzilla.
+This is a plain-text file. Each line is the name of a module,
+like C&lt;Bugzilla::Extension::Foo&gt;. In addition to the extensions
+in the F&lt;extensions/&gt; directory, each module listed in this file
+will be loaded as a Bugzilla Extension whenever Bugzilla loads or
+uses extensions.
+
+=head1 GETTING HELP WITH WRITING EXTENSIONS
+
+If you are an extension author and you'd like some assistance from other
+extension authors or the Bugzilla development team, you can use the
+normal support channels described at L&lt;http://www.bugzilla.org/support/&gt;.
+
+=head1 ADDITIONAL CONSTANTS
+
+In addition to C&lt;NAME&gt;, there are some other constants you might
+want to define:
+
+=head2 C&lt;$VERSION&gt;
+
+This should be a string that describes what version of your extension
+this is. Something like C&lt;1.0&gt;, C&lt;1.3.4&gt; or a similar string.
+
+There are no particular restrictions on the format of version numbers,
+but you should probably keep them to just numbers and periods, in the
+interest of other software that parses version numbers.
+
+By default, this will be C&lt;undef&gt; if you don't define it.
+
+=head1 SUBCLASS METHODS
+
+In addition to hooks, there are a few methods that your extension can
+define to modify its behavior, if you want:
+
+=head2 Class Methods
+
+These methods are called on your extension's class. (Like
+C&lt;&lt; Bugzilla::Extension::Foo-&gt;some_method &gt;&gt;).
+
+=head3 C&lt;new&gt;
+
+Once every request, this method is called on your extension in order
+to create an &quot;instance&quot; of it. (Extensions are treated like objects--they
+are instantiated once per request in Bugzilla, and then methods are
+called on the object.)
+
+=head2 Instance Methods
+
+These are called on an instantiated Extension object.
+
+=head3 C&lt;enabled&gt;
+
+This should return C&lt;1&gt; if this extension's hook code should be run
+by Bugzilla, and C&lt;0&gt; otherwise.
+
+=head3 C&lt;package_dir&gt;
+
+This returns the directory that your extension is located in. 
+
+If this is an extension that was installed via CPAN, the directory will 
+be the path to F&lt;Bugzilla/Extension/Foo/&gt;, if C&lt;Foo.pm&gt; is the name of your
+extension.
+
+If you want to override this method, and you have a F&lt;Config.pm&gt;, you must
+override this method in F&lt;Config.pm&gt;.
+
+=head3 C&lt;template_dir&gt;
+
+The directory that your package's templates are in.
+
+This defaults to the C&lt;template&gt; subdirectory of the L&lt;/package_dir&gt;.
+
+If you want to override this method, and you have a F&lt;Config.pm&gt;, you must
+override this method in F&lt;Config.pm&gt;.
+
+=head3 C&lt;web_dir&gt;
+
+The directory that your package's web related files are in, such as css and javascript.
+
+This defaults to the C&lt;web&gt; subdirectory of the L&lt;/package_dir&gt;.
+
+If you want to override this method, and you have a F&lt;Config.pm&gt;, you must
+override this method in F&lt;Config.pm&gt;.
+
+=head3 C&lt;lib_dir&gt;
+
+The directory where your extension's libraries are.
+
+This defaults to the C&lt;lib&gt; subdirectory of the L&lt;/package_dir&gt;.
+
+If you want to override this method, and you have a F&lt;Config.pm&gt;, you must
+override this method in F&lt;Config.pm&gt;.
+
+=head1 BUGZILLA::EXTENSION CLASS METHODS
+
+These are used internally by Bugzilla to load and set up extensions.
+If you are an extension author, you don't need to care about these.
+
+=head2 C&lt;load&gt;
+
+Takes two arguments, the path to F&lt;Extension.pm&gt; and the path to F&lt;Config.pm&gt;,
+for an extension. Loads the extension's code packages into memory using
+C&lt;require&gt;, does some sanity-checking on the extension, and returns the
+package name of the loaded extension.
+
+=head2 C&lt;load_all&gt;
+
+Calls L&lt;/load&gt; for every enabled extension installed into Bugzilla,
+and returns an arrayref of all the package names that were loaded.
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaFieldChoicepm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/Field/Choice.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Field/Choice.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Field/Choice.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,347 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Initial Developer of the Original Code is NASA.
+# Portions created by NASA are Copyright (C) 2006 San Jose State
+# University Foundation. All Rights Reserved.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# Contributor(s): Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+#                 Greg Hendricks &lt;ghendricks@novell.com&gt;
+
+use strict;
+
+package Bugzilla::Field::Choice;
+
+use base qw(Bugzilla::Field::ChoiceInterface Bugzilla::Object);
+
+use Bugzilla::Config qw(SetParam write_params);
+use Bugzilla::Constants;
+use Bugzilla::Error;
+use Bugzilla::Field;
+use Bugzilla::Util qw(trim detaint_natural);
+
+use Scalar::Util qw(blessed);
+
+##################
+# Initialization #
+##################
+
+use constant DB_COLUMNS =&gt; qw(
+    id
+    value
+    sortkey
+    isactive
+    visibility_value_id
+);
+
+use constant UPDATE_COLUMNS =&gt; qw(
+    value
+    sortkey
+    isactive
+    visibility_value_id
+);
+
+use constant NAME_FIELD =&gt; 'value';
+use constant LIST_ORDER =&gt; 'sortkey, value';
+
+use constant VALIDATORS =&gt; {
+    value   =&gt; \&amp;_check_value,
+    sortkey =&gt; \&amp;_check_sortkey,
+    visibility_value_id =&gt; \&amp;_check_visibility_value_id,
+    isactive =&gt; \&amp;_check_isactive,
+};
+
+use constant CLASS_MAP =&gt; {
+    bug_status =&gt; 'Bugzilla::Status',
+    classification =&gt; 'Bugzilla::Classification',
+    component  =&gt; 'Bugzilla::Component',
+    product    =&gt; 'Bugzilla::Product',
+};
+
+use constant DEFAULT_MAP =&gt; {
+    op_sys       =&gt; 'defaultopsys',
+    rep_platform =&gt; 'defaultplatform',
+    priority     =&gt; 'defaultpriority',
+    bug_severity =&gt; 'defaultseverity',
+};
+
+#################
+# Class Factory #
+#################
+
+# Bugzilla::Field::Choice is actually an abstract base class. Every field
+# type has its own dynamically-generated class for its values. This allows
+# certain fields to have special types, like how bug_status's values
+# are Bugzilla::Status objects.
+
+sub type {
+    my ($class, $field) = @_;
+    my $field_obj = blessed $field ? $field : Bugzilla::Field-&gt;check($field);
+    my $field_name = $field_obj-&gt;name;
+
+    if ($class-&gt;CLASS_MAP-&gt;{$field_name}) {
+        return $class-&gt;CLASS_MAP-&gt;{$field_name};
+    }
+
+    # For generic classes, we use a lowercase class name, so as
+    # not to interfere with any real subclasses we might make some day.
+    my $package = &quot;Bugzilla::Field::Choice::$field_name&quot;;
+    Bugzilla-&gt;request_cache-&gt;{&quot;field_$package&quot;} = $field_obj;
+
+    # This package only needs to be created once. We check if the DB_TABLE
+    # glob for this package already exists, which tells us whether or not
+    # we need to create the package (this works even under mod_perl, where
+    # this package definition will persist across requests)).
+    if (!defined *{&quot;${package}::DB_TABLE&quot;}) {
+        eval &lt;&lt;EOC;
+            package $package;
+            use base qw(Bugzilla::Field::Choice);
+            use constant DB_TABLE =&gt; '$field_name';
+EOC
+    }
+
+    return $package;
+}
+
+################
+# Constructors #
+################
+
+# We just make new() enforce this, which should give developers 
+# the understanding that you can't use Bugzilla::Field::Choice
+# without calling type().
+sub new {
+    my $class = shift;
+    if ($class eq 'Bugzilla::Field::Choice') {
+        ThrowCodeError('field_choice_must_use_type');
+    }
+    $class-&gt;SUPER::new(@_);
+}
+
+#########################
+# Database Manipulation #
+#########################
+
+# Our subclasses can take more arguments than we normally accept.
+# So, we override create() to remove arguments that aren't valid
+# columns. (Normally Bugzilla::Object dies if you pass arguments
+# that aren't valid columns.)
+sub create {
+    my $class = shift;
+    my ($params) = @_;
+    foreach my $key (keys %$params) {
+        if (!grep {$_ eq $key} $class-&gt;_get_db_columns) {
+            delete $params-&gt;{$key};
+        }
+    }
+    return $class-&gt;SUPER::create(@_);
+}
+
+sub update {
+    my $self = shift;
+    my $dbh = Bugzilla-&gt;dbh;
+    my $fname = $self-&gt;field-&gt;name;
+
+    $dbh-&gt;bz_start_transaction();
+
+    my ($changes, $old_self) = $self-&gt;SUPER::update(@_);
+    if (exists $changes-&gt;{value}) {
+        my ($old, $new) = @{ $changes-&gt;{value} };
+        if ($self-&gt;field-&gt;type == FIELD_TYPE_MULTI_SELECT) {
+            $dbh-&gt;do(&quot;UPDATE bug_$fname SET value = ? WHERE value = ?&quot;,
+                     undef, $new, $old);
+        }
+        else {
+            $dbh-&gt;do(&quot;UPDATE bugs SET $fname = ? WHERE $fname = ?&quot;,
+                     undef, $new, $old);
+        }
+
+        if ($old_self-&gt;is_default) {
+            my $param = $self-&gt;DEFAULT_MAP-&gt;{$self-&gt;field-&gt;name};
+            SetParam($param, $self-&gt;name);
+            write_params();
+        }
+    }
+
+    $dbh-&gt;bz_commit_transaction();
+    return wantarray ? ($changes, $old_self) : $changes;
+}
+
+sub remove_from_db {
+    my $self = shift;
+    if ($self-&gt;is_default) {
+        ThrowUserError('fieldvalue_is_default',
+                       { field =&gt; $self-&gt;field, value =&gt; $self,
+                         param_name =&gt; $self-&gt;DEFAULT_MAP-&gt;{$self-&gt;field-&gt;name},
+                       });
+    }
+    if ($self-&gt;is_static) {
+        ThrowUserError('fieldvalue_not_deletable', 
+                       { field =&gt; $self-&gt;field, value =&gt; $self });
+    }
+    if ($self-&gt;bug_count) {
+        ThrowUserError(&quot;fieldvalue_still_has_bugs&quot;,
+                       { field =&gt; $self-&gt;field, value =&gt; $self });
+    }
+    $self-&gt;_check_if_controller(); # From ChoiceInterface.
+    $self-&gt;SUPER::remove_from_db();
+}
+
+############
+# Mutators #
+############
+
+sub set_is_active { $_[0]-&gt;set('isactive', $_[1]); }
+sub set_name      { $_[0]-&gt;set('value', $_[1]);    }
+sub set_sortkey   { $_[0]-&gt;set('sortkey', $_[1]);  }
+sub set_visibility_value {
+    my ($self, $value) = @_;
+    $self-&gt;set('visibility_value_id', $value);
+    delete $self-&gt;{visibility_value};
+}
+
+##############
+# Validators #
+##############
+
+sub _check_isactive {
+    my ($invocant, $value) = @_;
+    $value = Bugzilla::Object::check_boolean($invocant, $value);
+    if (!$value and ref $invocant) {
+        if ($invocant-&gt;is_default) {
+            my $field = $invocant-&gt;field;
+            ThrowUserError('fieldvalue_is_default', 
+                           { value =&gt; $invocant, field =&gt; $field,
+                             param_name =&gt; $invocant-&gt;DEFAULT_MAP-&gt;{$field-&gt;name}
+                           });
+        }
+        if ($invocant-&gt;is_static) {
+            ThrowUserError('fieldvalue_not_deletable',
+                           { value =&gt; $invocant, field =&gt; $invocant-&gt;field });
+        }
+    }
+    return $value;
+}
+
+sub _check_value {
+    my ($invocant, $value) = @_;
+
+    my $field = $invocant-&gt;field;
+
+    $value = trim($value);
+
+    # Make sure people don't rename static values
+    if (blessed($invocant) &amp;&amp; $value ne $invocant-&gt;name 
+        &amp;&amp; $invocant-&gt;is_static) 
+    {
+        ThrowUserError('fieldvalue_not_editable',
+                       { field =&gt; $field, old_value =&gt; $invocant });
+    }
+
+    ThrowUserError('fieldvalue_undefined') if !defined $value || $value eq &quot;&quot;;
+    ThrowUserError('fieldvalue_name_too_long', { value =&gt; $value })
+        if length($value) &gt; MAX_FIELD_VALUE_SIZE;
+
+    my $exists = $invocant-&gt;type($field)-&gt;new({ name =&gt; $value });
+    if ($exists &amp;&amp; (!blessed($invocant) || $invocant-&gt;id != $exists-&gt;id)) {
+        ThrowUserError('fieldvalue_already_exists', 
+                       { field =&gt; $field, value =&gt; $exists });
+    }
+
+    return $value;
+}
+
+sub _check_sortkey {
+    my ($invocant, $value) = @_;
+    $value = trim($value);
+    return 0 if !$value;
+    # Store for the error message in case detaint_natural clears it.
+    my $orig_value = $value;
+    detaint_natural($value)
+        || ThrowUserError('fieldvalue_sortkey_invalid',
+                          { sortkey =&gt; $orig_value,
+                            field   =&gt; $invocant-&gt;field });
+    return $value;
+}
+
+sub _check_visibility_value_id {
+    my ($invocant, $value_id) = @_;
+    $value_id = trim($value_id);
+    my $field = $invocant-&gt;field-&gt;value_field;
+    return undef if !$field || !$value_id;
+    my $value_obj = Bugzilla::Field::Choice-&gt;type($field)
+                    -&gt;check({ id =&gt; $value_id });
+    return $value_obj-&gt;id;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::Field::Choice - A legal value for a &lt;select&gt;-type field.
+
+=head1 SYNOPSIS
+
+ my $field = new Bugzilla::Field({name =&gt; 'bug_status'});
+
+ my $choice = new Bugzilla::Field::Choice-&gt;type($field)-&gt;new(1);
+
+ my $choices = Bugzilla::Field::Choice-&gt;type($field)-&gt;new_from_list([1,2,3]);
+ my $choices = Bugzilla::Field::Choice-&gt;type($field)-&gt;get_all();
+ my $choices = Bugzilla::Field::Choice-&gt;type($field-&gt;match({ sortkey =&gt; 10 }); 
+
+=head1 DESCRIPTION
+
+This is an implementation of L&lt;Bugzilla::Object&gt;, but with a twist.
+You can't call any class methods (such as C&lt;new&gt;, C&lt;create&gt;, etc.) 
+directly on C&lt;Bugzilla::Field::Choice&gt; itself. Instead, you have to
+call C&lt;Bugzilla::Field::Choice-E&lt;gt&gt;type($field)&gt; to get the class
+you're going to instantiate, and then you call the methods on that.
+
+We do that because each field has its own database table for its values, so
+each value type needs its own class.
+
+See the L&lt;/SYNOPSIS&gt; for examples of how this works.
+
+This class implements L&lt;Bugzilla::Field::ChoiceInterface&gt;, and so all
+methods of that class are also available here.
+
+=head1 METHODS
+
+=head2 Class Factory
+
+In object-oriented design, a &quot;class factory&quot; is a method that picks
+and returns the right class for you, based on an argument that you pass.
+
+=over
+
+=item C&lt;type&gt;
+
+Takes a single argument, which is either the name of a field from the
+C&lt;fielddefs&gt; table, or a L&lt;Bugzilla::Field&gt; object representing a field.
+
+Returns an appropriate subclass of C&lt;Bugzilla::Field::Choice&gt; that you
+can now call class methods on (like C&lt;new&gt;, C&lt;create&gt;, C&lt;match&gt;, etc.)
+
+B&lt;NOTE&gt;: YOU CANNOT CALL CLASS METHODS ON C&lt;Bugzilla::Field::Choice&gt;. You
+must call C&lt;type&gt; to get a class you can call methods on.
+
+=back
+
+=head2 Mutators
+
+This class implements mutators for all of the settable accessors in
+L&lt;Bugzilla::Field::ChoiceInterface&gt;.
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaFieldChoiceInterfacepm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/Field/ChoiceInterface.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Field/ChoiceInterface.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Field/ChoiceInterface.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,284 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Initial Developer of the Original Code is NASA.
+# Portions created by NASA are Copyright (C) 2006 San Jose State
+# University Foundation. All Rights Reserved.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# Contributor(s): Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+#                 Greg Hendricks &lt;ghendricks@novell.com&gt;
+
+package Bugzilla::Field::ChoiceInterface;
+use strict;
+
+use Bugzilla::Constants;
+use Bugzilla::Error;
+use Bugzilla::Field;
+
+use Scalar::Util qw(blessed);
+
+# Helps implement the &quot;field&quot; accessor without subclasses having to
+# write code.
+sub FIELD_NAME { return $_[0]-&gt;DB_TABLE; }
+
+####################
+# Subclass Helpers #
+####################
+
+sub _check_if_controller {
+    my $self = shift;
+    my $vis_fields = $self-&gt;controls_visibility_of_fields;
+    my $values = $self-&gt;controlled_values_array;
+    if (@$vis_fields || @$values) {
+        ThrowUserError('fieldvalue_is_controller',
+            { value =&gt; $self, fields =&gt; [map($_-&gt;name, @$vis_fields)],
+              vals =&gt; $self-&gt;controlled_values });
+    }
+}
+
+
+#############
+# Accessors #
+#############
+
+sub is_active { return $_[0]-&gt;{'isactive'}; }
+sub sortkey   { return $_[0]-&gt;{'sortkey'};  }
+
+sub bug_count {
+    my $self = shift;
+    return $self-&gt;{bug_count} if defined $self-&gt;{bug_count};
+    my $dbh = Bugzilla-&gt;dbh;
+    my $fname = $self-&gt;field-&gt;name;
+    my $count;
+    if ($self-&gt;field-&gt;type == FIELD_TYPE_MULTI_SELECT) {
+        $count = $dbh-&gt;selectrow_array(&quot;SELECT COUNT(*) FROM bug_$fname
+                                         WHERE value = ?&quot;, undef, $self-&gt;name);
+    }
+    else {
+        $count = $dbh-&gt;selectrow_array(&quot;SELECT COUNT(*) FROM bugs 
+                                         WHERE $fname = ?&quot;,
+                                       undef, $self-&gt;name);
+    }
+    $self-&gt;{bug_count} = $count;
+    return $count;
+}
+
+sub field {
+    my $invocant = shift;
+    my $class = ref $invocant || $invocant;
+    my $cache = Bugzilla-&gt;request_cache;
+    # This is just to make life easier for subclasses. Our auto-generated
+    # subclasses from Bugzilla::Field::Choice-&gt;type() already have this set.
+    $cache-&gt;{&quot;field_$class&quot;} ||=  
+        new Bugzilla::Field({ name =&gt; $class-&gt;FIELD_NAME });
+    return $cache-&gt;{&quot;field_$class&quot;};
+}
+
+sub is_default {
+    my $self = shift;
+    my $name = $self-&gt;DEFAULT_MAP-&gt;{$self-&gt;field-&gt;name};
+    # If it doesn't exist in DEFAULT_MAP, then there is no parameter
+    # related to this field.
+    return 0 unless $name;
+    return ($self-&gt;name eq Bugzilla-&gt;params-&gt;{$name}) ? 1 : 0;
+}
+
+sub is_static {
+    my $self = shift;
+    # If we need to special-case Resolution for *anything* else, it should
+    # get its own subclass.
+    if ($self-&gt;field-&gt;name eq 'resolution') {
+        return grep($_ eq $self-&gt;name, ('', 'FIXED', 'DUPLICATE'))
+               ? 1 : 0;
+    }
+    elsif ($self-&gt;field-&gt;custom) {
+        return $self-&gt;name eq '---' ? 1 : 0;
+    }
+    return 0;
+}
+
+sub controls_visibility_of_fields {
+    my $self = shift;
+    my $dbh = Bugzilla-&gt;dbh;
+
+    if (!$self-&gt;{controls_visibility_of_fields}) {
+        my $ids = $dbh-&gt;selectcol_arrayref(
+            &quot;SELECT id FROM fielddefs
+               INNER JOIN field_visibility
+                 ON fielddefs.id = field_visibility.field_id
+             WHERE value_id = ? AND visibility_field_id = ?&quot;, undef,
+            $self-&gt;id, $self-&gt;field-&gt;id);
+
+        $self-&gt;{controls_visibility_of_fields} =
+            Bugzilla::Field-&gt;new_from_list($ids);
+   }
+
+   return $self-&gt;{controls_visibility_of_fields};
+}
+
+sub visibility_value {
+    my $self = shift;
+    if ($self-&gt;{visibility_value_id}) {
+        require Bugzilla::Field::Choice;
+        $self-&gt;{visibility_value} ||=
+            Bugzilla::Field::Choice-&gt;type($self-&gt;field-&gt;value_field)-&gt;new(
+                $self-&gt;{visibility_value_id});
+    }
+    return $self-&gt;{visibility_value};
+}
+
+sub controlled_values {
+    my $self = shift;
+    return $self-&gt;{controlled_values} if defined $self-&gt;{controlled_values};
+    my $fields = $self-&gt;field-&gt;controls_values_of;
+    my %controlled_values;
+    require Bugzilla::Field::Choice;
+    foreach my $field (@$fields) {
+        $controlled_values{$field-&gt;name} = 
+            Bugzilla::Field::Choice-&gt;type($field)
+            -&gt;match({ visibility_value_id =&gt; $self-&gt;id });
+    }
+    $self-&gt;{controlled_values} = \%controlled_values;
+    return $self-&gt;{controlled_values};
+}
+
+sub controlled_values_array {
+    my ($self) = @_;
+    my $values = $self-&gt;controlled_values;
+    return [map { @{ $values-&gt;{$_} } } keys %$values];
+}
+
+sub is_visible_on_bug {
+    my ($self, $bug) = @_;
+
+    # Values currently set on the bug are always shown.
+    return 1 if $self-&gt;is_set_on_bug($bug);
+
+    # Inactive values are, otherwise, never shown.
+    return 0 if !$self-&gt;is_active;
+
+    # Values without a visibility value are, otherwise, always shown.
+    my $visibility_value = $self-&gt;visibility_value;
+    return 1 if !$visibility_value;
+
+    # Values with a visibility value are only shown if the visibility
+    # value is set on the bug.
+    return $visibility_value-&gt;is_set_on_bug($bug); 
+}
+
+sub is_set_on_bug {
+    my ($self, $bug) = @_;
+    my $field_name = $self-&gt;FIELD_NAME;
+    # This allows bug/create/create.html.tmpl to pass in a hashref that 
+    # looks like a bug object.
+    my $value = blessed($bug) ? $bug-&gt;$field_name : $bug-&gt;{$field_name};
+    return 0 if !defined $value;
+
+    if ($self-&gt;field-&gt;type == FIELD_TYPE_BUG_URLS
+        or $self-&gt;field-&gt;type == FIELD_TYPE_MULTI_SELECT)
+    {
+        return grep($_ eq $self-&gt;name, @$value) ? 1 : 0;
+    }
+    return $value eq $self-&gt;name ? 1 : 0;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::Field::ChoiceInterface - Makes an object act like a
+Bugzilla::Field::Choice.
+
+=head1 DESCRIPTION
+
+This is an &quot;interface&quot;, in the Java sense (sometimes called a &quot;Role&quot;
+or a &quot;Mixin&quot; in other languages). L&lt;Bugzilla::Field::Choice&gt; is the
+primary implementor of this interface, but other classes also implement
+it if they want to &quot;act like&quot; L&lt;Bugzilla::Field::Choice&gt;.
+
+=head1 METHODS
+
+=head2 Accessors
+
+These are in addition to the standard L&lt;Bugzilla::Object&gt; accessors.
+
+=over
+
+=item C&lt;sortkey&gt;
+
+The key that determines the sort order of this item.
+
+=item C&lt;field&gt;
+
+The L&lt;Bugzilla::Field&gt; object that this field value belongs to.
+
+=item C&lt;is_active&gt;
+
+Whether or not this value should appear as an option on bugs that do
+not already have it set as the current value.
+
+=item C&lt;is_static&gt;
+
+C&lt;0&gt; if this field value can be renamed or deleted, C&lt;1&gt; otherwise.
+
+=item C&lt;is_default&gt;
+
+C&lt;1&gt; if this is the default value for this field, C&lt;0&gt; otherwise.
+
+=item C&lt;bug_count&gt;
+
+An integer count of the number of bugs that have this value set.
+
+=item C&lt;controls_visibility_of_fields&gt;
+
+Returns an arrayref of L&lt;Bugzilla::Field&gt; objects, representing any
+fields whose visibility are controlled by this field value.
+
+=item C&lt;controlled_values&gt;
+
+Tells you which values in B&lt;other&gt; fields appear (become visible) when this
+value is set in its field.
+
+Returns a hashref of arrayrefs. The hash keys are the names of fields,
+and the values are arrays of objects that implement
+C&lt;Bugzilla::Field::ChoiceInterface&gt;, representing values that this value 
+controls the visibility of, for that field.
+
+=item C&lt;visibility_value&gt;
+
+Returns an object that implements C&lt;Bugzilla::Field::ChoiceInterface&gt;,
+which represents the value that needs to be set in order for this
+value to appear in the UI.
+
+=item C&lt;is_visible_on_bug&gt;
+
+Returns C&lt;1&gt; if, according to the settings of C&lt;is_active&gt; and 
+C&lt;visibility_value&gt;, this value should be displayed as an option
+when viewing a bug. Returns C&lt;0&gt; otherwise.
+
+Takes a single argument, a L&lt;Bugzilla::Bug&gt; object or a hash with
+similar fields to a L&lt;Bugzilla::Bug&gt; object.
+
+=item C&lt;is_set_on_bug&gt;
+
+Returns C&lt;1&gt; if this value is the current value set for its field on
+the passed-in L&lt;Bugzilla::Bug&gt; object (or a hash that looks like a
+L&lt;Bugzilla::Bug&gt;). For multi-valued fields, we return C&lt;1&gt; if
+I&lt;any&gt; of the currently selected values are this value.
+
+Returns C&lt;0&gt; otherwise.
+
+=back
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaFieldpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Field.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Field.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Field.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -15,6 +15,7 @@
</span><span class="cx"> # Contributor(s): Dan Mosedale &lt;dmose@mozilla.org&gt;
</span><span class="cx"> #                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
</span><span class="cx"> #                 Myk Melez &lt;myk@mozilla.org&gt;
</span><ins>+#                 Greg Hendricks &lt;ghendricks@novell.com&gt;
</ins><span class="cx"> 
</span><span class="cx"> =head1 NAME
</span><span class="cx"> 
</span><span class="lines">@@ -27,7 +28,7 @@
</span><span class="cx">   use Data::Dumper;
</span><span class="cx"> 
</span><span class="cx">   # Display information about all fields.
</span><del>-  print Dumper(Bugzilla-&gt;get_fields());
</del><ins>+  print Dumper(Bugzilla-&gt;fields());
</ins><span class="cx"> 
</span><span class="cx">   # Display information about non-obsolete custom fields.
</span><span class="cx">   print Dumper(Bugzilla-&gt;active_custom_fields);
</span><span class="lines">@@ -35,9 +36,9 @@
</span><span class="cx">   use Bugzilla::Field;
</span><span class="cx"> 
</span><span class="cx">   # Display information about non-obsolete custom fields.
</span><del>-  # Bugzilla-&gt;get_fields() is a wrapper around Bugzilla::Field-&gt;match(),
-  # so both methods take the same arguments.
-  print Dumper(Bugzilla::Field-&gt;match({ obsolete =&gt; 0, custom =&gt; 1 }));
</del><ins>+  # Bugzilla-&gt;fields() is a wrapper around Bugzilla::Field-&gt;get_all(),
+  # with arguments which filter the fields before returning them.
+  print Dumper(Bugzilla-&gt;fields({ obsolete =&gt; 0, custom =&gt; 1 }));
</ins><span class="cx"> 
</span><span class="cx">   # Create or update a custom field or field definition.
</span><span class="cx">   my $field = Bugzilla::Field-&gt;create(
</span><span class="lines">@@ -73,10 +74,13 @@
</span><span class="cx"> use base qw(Exporter Bugzilla::Object);
</span><span class="cx"> @Bugzilla::Field::EXPORT = qw(check_field get_field_id get_legal_field_values);
</span><span class="cx"> 
</span><del>-use Bugzilla::Util;
</del><span class="cx"> use Bugzilla::Constants;
</span><span class="cx"> use Bugzilla::Error;
</span><ins>+use Bugzilla::Util;
+use List::MoreUtils qw(any);
</ins><span class="cx"> 
</span><ins>+use Scalar::Util qw(blessed);
+
</ins><span class="cx"> ###############################
</span><span class="cx"> ####    Initialization     ####
</span><span class="cx"> ###############################
</span><span class="lines">@@ -84,110 +88,195 @@
</span><span class="cx"> use constant DB_TABLE   =&gt; 'fielddefs';
</span><span class="cx"> use constant LIST_ORDER =&gt; 'sortkey, name';
</span><span class="cx"> 
</span><del>-use constant DB_COLUMNS =&gt; (
-    'id',
-    'name',
-    'description',
-    'type',
-    'custom',
-    'mailhead',
-    'sortkey',
-    'obsolete',
-    'enter_bug',
</del><ins>+use constant DB_COLUMNS =&gt; qw(
+    id
+    name
+    description
+    type
+    custom
+    mailhead
+    sortkey
+    obsolete
+    enter_bug
+    buglist
+    visibility_field_id
+    value_field_id
+    reverse_desc
+    is_mandatory
+    is_numeric
</ins><span class="cx"> );
</span><span class="cx"> 
</span><del>-use constant REQUIRED_CREATE_FIELDS =&gt; qw(name description);
-
</del><span class="cx"> use constant VALIDATORS =&gt; {
</span><del>-    custom      =&gt; \&amp;_check_custom,
-    description =&gt; \&amp;_check_description,
-    enter_bug   =&gt; \&amp;_check_enter_bug,
-    mailhead    =&gt; \&amp;_check_mailhead,
-    obsolete    =&gt; \&amp;_check_obsolete,
-    sortkey     =&gt; \&amp;_check_sortkey,
-    type        =&gt; \&amp;_check_type,
</del><ins>+    custom       =&gt; \&amp;_check_custom,
+    description  =&gt; \&amp;_check_description,
+    enter_bug    =&gt; \&amp;_check_enter_bug,
+    buglist      =&gt; \&amp;Bugzilla::Object::check_boolean,
+    mailhead     =&gt; \&amp;_check_mailhead,
+    name         =&gt; \&amp;_check_name,
+    obsolete     =&gt; \&amp;_check_obsolete,
+    reverse_desc =&gt; \&amp;_check_reverse_desc,
+    sortkey      =&gt; \&amp;_check_sortkey,
+    type         =&gt; \&amp;_check_type,
+    value_field_id      =&gt; \&amp;_check_value_field_id,
+    visibility_field_id =&gt; \&amp;_check_visibility_field_id,
+    visibility_values =&gt; \&amp;_check_visibility_values,
+    is_mandatory =&gt; \&amp;Bugzilla::Object::check_boolean,
+    is_numeric   =&gt; \&amp;_check_is_numeric,
</ins><span class="cx"> };
</span><span class="cx"> 
</span><ins>+use constant VALIDATOR_DEPENDENCIES =&gt; {
+    is_numeric =&gt; ['type'],
+    name =&gt; ['custom'],
+    type =&gt; ['custom'],
+    reverse_desc =&gt; ['type'],
+    value_field_id =&gt; ['type'],
+    visibility_values =&gt; ['visibility_field_id'],
+};
+
</ins><span class="cx"> use constant UPDATE_COLUMNS =&gt; qw(
</span><span class="cx">     description
</span><span class="cx">     mailhead
</span><span class="cx">     sortkey
</span><span class="cx">     obsolete
</span><span class="cx">     enter_bug
</span><ins>+    buglist
+    visibility_field_id
+    value_field_id
+    reverse_desc
+    is_mandatory
+    is_numeric
+    type
</ins><span class="cx"> );
</span><span class="cx"> 
</span><span class="cx"> # How various field types translate into SQL data definitions.
</span><span class="cx"> use constant SQL_DEFINITIONS =&gt; {
</span><span class="cx">     # Using commas because these are constants and they shouldn't
</span><span class="cx">     # be auto-quoted by the &quot;=&gt;&quot; operator.
</span><del>-    FIELD_TYPE_FREETEXT,      { TYPE =&gt; 'varchar(255)' },
</del><ins>+    FIELD_TYPE_FREETEXT,      { TYPE =&gt; 'varchar(255)', 
+                                NOTNULL =&gt; 1, DEFAULT =&gt; &quot;''&quot;},
</ins><span class="cx">     FIELD_TYPE_SINGLE_SELECT, { TYPE =&gt; 'varchar(64)', NOTNULL =&gt; 1,
</span><span class="cx">                                 DEFAULT =&gt; &quot;'---'&quot; },
</span><del>-    FIELD_TYPE_TEXTAREA,      { TYPE =&gt; 'MEDIUMTEXT' },
</del><ins>+    FIELD_TYPE_TEXTAREA,      { TYPE =&gt; 'MEDIUMTEXT', 
+                                NOTNULL =&gt; 1, DEFAULT =&gt; &quot;''&quot;},
</ins><span class="cx">     FIELD_TYPE_DATETIME,      { TYPE =&gt; 'DATETIME'   },
</span><ins>+    FIELD_TYPE_BUG_ID,        { TYPE =&gt; 'INT3'       },
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> # Field definitions for the fields that ship with Bugzilla.
</span><span class="cx"> # These are used by populate_field_definitions to populate
</span><span class="cx"> # the fielddefs table.
</span><ins>+# 'days_elapsed' is set in populate_field_definitions() itself.
</ins><span class="cx"> use constant DEFAULT_FIELDS =&gt; (
</span><del>-    {name =&gt; 'bug_id',       desc =&gt; 'Bug #',      in_new_bugmail =&gt; 1},
-    {name =&gt; 'short_desc',   desc =&gt; 'Summary',    in_new_bugmail =&gt; 1},
-    {name =&gt; 'classification', desc =&gt; 'Classification', in_new_bugmail =&gt; 1},
-    {name =&gt; 'product',      desc =&gt; 'Product',    in_new_bugmail =&gt; 1},
-    {name =&gt; 'version',      desc =&gt; 'Version',    in_new_bugmail =&gt; 1},
-    {name =&gt; 'rep_platform', desc =&gt; 'Platform',   in_new_bugmail =&gt; 1},
-    {name =&gt; 'bug_file_loc', desc =&gt; 'URL',        in_new_bugmail =&gt; 1},
-    {name =&gt; 'op_sys',       desc =&gt; 'OS/Version', in_new_bugmail =&gt; 1},
-    {name =&gt; 'bug_status',   desc =&gt; 'Status',     in_new_bugmail =&gt; 1},
</del><ins>+    {name =&gt; 'bug_id',       desc =&gt; 'Bug #',      in_new_bugmail =&gt; 1,
+     buglist =&gt; 1, is_numeric =&gt; 1},
+    {name =&gt; 'short_desc',   desc =&gt; 'Summary',    in_new_bugmail =&gt; 1,
+     is_mandatory =&gt; 1, buglist =&gt; 1},
+    {name =&gt; 'classification', desc =&gt; 'Classification', in_new_bugmail =&gt; 1,
+     type =&gt; FIELD_TYPE_SINGLE_SELECT, buglist =&gt; 1},
+    {name =&gt; 'product',      desc =&gt; 'Product',    in_new_bugmail =&gt; 1,
+     is_mandatory =&gt; 1,
+     type =&gt; FIELD_TYPE_SINGLE_SELECT, buglist =&gt; 1},
+    {name =&gt; 'version',      desc =&gt; 'Version',    in_new_bugmail =&gt; 1,
+     is_mandatory =&gt; 1, buglist =&gt; 1},
+    {name =&gt; 'rep_platform', desc =&gt; 'Platform',   in_new_bugmail =&gt; 1,
+     type =&gt; FIELD_TYPE_SINGLE_SELECT, buglist =&gt; 1},
+    {name =&gt; 'bug_file_loc', desc =&gt; 'URL',        in_new_bugmail =&gt; 1,
+     buglist =&gt; 1},
+    {name =&gt; 'op_sys',       desc =&gt; 'OS/Version', in_new_bugmail =&gt; 1,
+     type =&gt; FIELD_TYPE_SINGLE_SELECT, buglist =&gt; 1},
+    {name =&gt; 'bug_status',   desc =&gt; 'Status',     in_new_bugmail =&gt; 1,
+     type =&gt; FIELD_TYPE_SINGLE_SELECT, buglist =&gt; 1},
</ins><span class="cx">     {name =&gt; 'status_whiteboard', desc =&gt; 'Status Whiteboard',
</span><del>-     in_new_bugmail =&gt; 1},
-    {name =&gt; 'keywords',     desc =&gt; 'Keywords',   in_new_bugmail =&gt; 1},
-    {name =&gt; 'resolution',   desc =&gt; 'Resolution'},
-    {name =&gt; 'bug_severity', desc =&gt; 'Severity',   in_new_bugmail =&gt; 1},
-    {name =&gt; 'priority',     desc =&gt; 'Priority',   in_new_bugmail =&gt; 1},
-    {name =&gt; 'component',    desc =&gt; 'Component',  in_new_bugmail =&gt; 1},
-    {name =&gt; 'assigned_to',  desc =&gt; 'AssignedTo', in_new_bugmail =&gt; 1},
-    {name =&gt; 'reporter',     desc =&gt; 'ReportedBy', in_new_bugmail =&gt; 1},
-    {name =&gt; 'votes',        desc =&gt; 'Votes'},
-    {name =&gt; 'qa_contact',   desc =&gt; 'QAContact',  in_new_bugmail =&gt; 1},
</del><ins>+     in_new_bugmail =&gt; 1, buglist =&gt; 1},
+    {name =&gt; 'keywords',     desc =&gt; 'Keywords',   in_new_bugmail =&gt; 1,
+     type =&gt; FIELD_TYPE_KEYWORDS, buglist =&gt; 1},
+    {name =&gt; 'resolution',   desc =&gt; 'Resolution',
+     type =&gt; FIELD_TYPE_SINGLE_SELECT, buglist =&gt; 1},
+    {name =&gt; 'bug_severity', desc =&gt; 'Severity',   in_new_bugmail =&gt; 1,
+     type =&gt; FIELD_TYPE_SINGLE_SELECT, buglist =&gt; 1},
+    {name =&gt; 'priority',     desc =&gt; 'Priority',   in_new_bugmail =&gt; 1,
+     type =&gt; FIELD_TYPE_SINGLE_SELECT, buglist =&gt; 1},
+    {name =&gt; 'component',    desc =&gt; 'Component',  in_new_bugmail =&gt; 1,
+     is_mandatory =&gt; 1,
+     type =&gt; FIELD_TYPE_SINGLE_SELECT, buglist =&gt; 1},
+    {name =&gt; 'assigned_to',  desc =&gt; 'AssignedTo', in_new_bugmail =&gt; 1,
+     buglist =&gt; 1},
+    {name =&gt; 'reporter',     desc =&gt; 'ReportedBy', in_new_bugmail =&gt; 1,
+     buglist =&gt; 1},
+    {name =&gt; 'qa_contact',   desc =&gt; 'QAContact',  in_new_bugmail =&gt; 1,
+     buglist =&gt; 1},
</ins><span class="cx">     {name =&gt; 'cc',           desc =&gt; 'CC',         in_new_bugmail =&gt; 1},
</span><del>-    {name =&gt; 'dependson',    desc =&gt; 'Depends on', in_new_bugmail =&gt; 1},
-    {name =&gt; 'blocked',      desc =&gt; 'Blocks',     in_new_bugmail =&gt; 1},
</del><ins>+    {name =&gt; 'dependson',    desc =&gt; 'Depends on', in_new_bugmail =&gt; 1,
+     is_numeric =&gt; 1},
+    {name =&gt; 'blocked',      desc =&gt; 'Blocks',     in_new_bugmail =&gt; 1,
+     is_numeric =&gt; 1},
</ins><span class="cx"> 
</span><span class="cx">     {name =&gt; 'attachments.description', desc =&gt; 'Attachment description'},
</span><span class="cx">     {name =&gt; 'attachments.filename',    desc =&gt; 'Attachment filename'},
</span><span class="cx">     {name =&gt; 'attachments.mimetype',    desc =&gt; 'Attachment mime type'},
</span><del>-    {name =&gt; 'attachments.ispatch',     desc =&gt; 'Attachment is patch'},
-    {name =&gt; 'attachments.isobsolete',  desc =&gt; 'Attachment is obsolete'},
-    {name =&gt; 'attachments.isprivate',   desc =&gt; 'Attachment is private'},
</del><ins>+    {name =&gt; 'attachments.ispatch',     desc =&gt; 'Attachment is patch',
+     is_numeric =&gt; 1},
+    {name =&gt; 'attachments.isobsolete',  desc =&gt; 'Attachment is obsolete',
+     is_numeric =&gt; 1},
+    {name =&gt; 'attachments.isprivate',   desc =&gt; 'Attachment is private',
+     is_numeric =&gt; 1},
</ins><span class="cx">     {name =&gt; 'attachments.submitter',   desc =&gt; 'Attachment creator'},
</span><span class="cx"> 
</span><del>-    {name =&gt; 'target_milestone',      desc =&gt; 'Target Milestone'},
-    {name =&gt; 'creation_ts', desc =&gt; 'Creation date', in_new_bugmail =&gt; 1},
-    {name =&gt; 'delta_ts', desc =&gt; 'Last changed date', in_new_bugmail =&gt; 1},
</del><ins>+    {name =&gt; 'target_milestone',      desc =&gt; 'Target Milestone',
+     buglist =&gt; 1},
+    {name =&gt; 'creation_ts',           desc =&gt; 'Creation date',
+     buglist =&gt; 1},
+    {name =&gt; 'delta_ts',              desc =&gt; 'Last changed date',
+     buglist =&gt; 1},
</ins><span class="cx">     {name =&gt; 'longdesc',              desc =&gt; 'Comment'},
</span><del>-    {name =&gt; 'longdescs.isprivate',   desc =&gt; 'Comment is private'},
-    {name =&gt; 'alias',                 desc =&gt; 'Alias'},
-    {name =&gt; 'everconfirmed',         desc =&gt; 'Ever Confirmed'},
-    {name =&gt; 'reporter_accessible',   desc =&gt; 'Reporter Accessible'},
-    {name =&gt; 'cclist_accessible',     desc =&gt; 'CC Accessible'},
-    {name =&gt; 'bug_group',             desc =&gt; 'Group'},
-    {name =&gt; 'estimated_time', desc =&gt; 'Estimated Hours', in_new_bugmail =&gt; 1},
-    {name =&gt; 'remaining_time',        desc =&gt; 'Remaining Hours'},
-    {name =&gt; 'deadline',              desc =&gt; 'Deadline', in_new_bugmail =&gt; 1},
</del><ins>+    {name =&gt; 'longdescs.isprivate',   desc =&gt; 'Comment is private',
+     is_numeric =&gt; 1},
+    {name =&gt; 'longdescs.count',       desc =&gt; 'Number of Comments',
+     buglist =&gt; 1, is_numeric =&gt; 1},
+    {name =&gt; 'alias',                 desc =&gt; 'Alias', buglist =&gt; 1},
+    {name =&gt; 'everconfirmed',         desc =&gt; 'Ever Confirmed',
+     is_numeric =&gt; 1},
+    {name =&gt; 'reporter_accessible',   desc =&gt; 'Reporter Accessible',
+     is_numeric =&gt; 1},
+    {name =&gt; 'cclist_accessible',     desc =&gt; 'CC Accessible',
+     is_numeric =&gt; 1},
+    {name =&gt; 'bug_group',             desc =&gt; 'Group', in_new_bugmail =&gt; 1},
+    {name =&gt; 'estimated_time',        desc =&gt; 'Estimated Hours',
+     in_new_bugmail =&gt; 1, buglist =&gt; 1, is_numeric =&gt; 1},
+    {name =&gt; 'remaining_time',        desc =&gt; 'Remaining Hours', buglist =&gt; 1,
+     is_numeric =&gt; 1},
+    {name =&gt; 'deadline',              desc =&gt; 'Deadline',
+     type =&gt; FIELD_TYPE_DATETIME, in_new_bugmail =&gt; 1, buglist =&gt; 1},
</ins><span class="cx">     {name =&gt; 'commenter',             desc =&gt; 'Commenter'},
</span><del>-    {name =&gt; 'flagtypes.name',        desc =&gt; 'Flag'},
</del><ins>+    {name =&gt; 'flagtypes.name',        desc =&gt; 'Flags', buglist =&gt; 1},
</ins><span class="cx">     {name =&gt; 'requestees.login_name', desc =&gt; 'Flag Requestee'},
</span><span class="cx">     {name =&gt; 'setters.login_name',    desc =&gt; 'Flag Setter'},
</span><del>-    {name =&gt; 'work_time',             desc =&gt; 'Hours Worked'},
-    {name =&gt; 'percentage_complete',   desc =&gt; 'Percentage Complete'},
</del><ins>+    {name =&gt; 'work_time',             desc =&gt; 'Hours Worked', buglist =&gt; 1,
+     is_numeric =&gt; 1},
+    {name =&gt; 'percentage_complete',   desc =&gt; 'Percentage Complete',
+     buglist =&gt; 1, is_numeric =&gt; 1},
</ins><span class="cx">     {name =&gt; 'content',               desc =&gt; 'Content'},
</span><span class="cx">     {name =&gt; 'attach_data.thedata',   desc =&gt; 'Attachment data'},
</span><del>-    {name =&gt; 'attachments.isurl',     desc =&gt; 'Attachment is a URL'},
</del><span class="cx">     {name =&gt; &quot;owner_idle_time&quot;,       desc =&gt; &quot;Time Since Assignee Touched&quot;},
</span><ins>+    {name =&gt; 'see_also',              desc =&gt; &quot;See Also&quot;,
+     type =&gt; FIELD_TYPE_BUG_URLS},
+    {name =&gt; 'tag',                   desc =&gt; 'Tags'},
</ins><span class="cx"> );
</span><span class="cx"> 
</span><ins>+################
+# Constructors #
+################
+
+# Override match to add is_select.
+sub match {
+    my $self = shift;
+    my ($params) = @_;
+    if (delete $params-&gt;{is_select}) {
+        $params-&gt;{type} = [FIELD_TYPE_SINGLE_SELECT, FIELD_TYPE_MULTI_SELECT];
+    }
+    return $self-&gt;SUPER::match(@_);
+}
+
</ins><span class="cx"> ##############
</span><span class="cx"> # Validators #
</span><span class="cx"> ##############
</span><span class="lines">@@ -203,10 +292,17 @@
</span><span class="cx"> 
</span><span class="cx"> sub _check_enter_bug { return $_[1] ? 1 : 0; }
</span><span class="cx"> 
</span><ins>+sub _check_is_numeric {
+    my ($invocant, $value, undef, $params) = @_;
+    my $type = blessed($invocant) ? $invocant-&gt;type : $params-&gt;{type};
+    return 1 if $type == FIELD_TYPE_BUG_ID;
+    return $value ? 1 : 0;
+}
+
</ins><span class="cx"> sub _check_mailhead { return $_[1] ? 1 : 0; }
</span><span class="cx"> 
</span><span class="cx"> sub _check_name {
</span><del>-    my ($invocant, $name, $is_custom) = @_;
</del><ins>+    my ($class, $name, undef, $params) = @_;
</ins><span class="cx">     $name = lc(clean_text($name));
</span><span class="cx">     $name || ThrowUserError('field_missing_name');
</span><span class="cx"> 
</span><span class="lines">@@ -214,7 +310,7 @@
</span><span class="cx">     my $name_regex = qr/^[\w\.]+$/;
</span><span class="cx">     # Custom fields have more restrictive name requirements than
</span><span class="cx">     # standard fields.
</span><del>-    $name_regex = qr/^\w+$/ if $is_custom;
</del><ins>+    $name_regex = qr/^[a-zA-Z0-9_]+$/ if $params-&gt;{custom};
</ins><span class="cx">     # Custom fields can't be named just &quot;cf_&quot;, and there is no normal
</span><span class="cx">     # field named just &quot;cf_&quot;.
</span><span class="cx">     ($name =~ $name_regex &amp;&amp; $name ne &quot;cf_&quot;)
</span><span class="lines">@@ -222,7 +318,7 @@
</span><span class="cx"> 
</span><span class="cx">     # If it's custom, prepend cf_ to the custom field name to distinguish 
</span><span class="cx">     # it from standard fields.
</span><del>-    if ($name !~ /^cf_/ &amp;&amp; $is_custom) {
</del><ins>+    if ($name !~ /^cf_/ &amp;&amp; $params-&gt;{custom}) {
</ins><span class="cx">         $name = 'cf_' . $name;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -249,15 +345,87 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _check_type {
</span><del>-    my ($invocant, $type) = @_;
</del><ins>+    my ($invocant, $type, undef, $params) = @_;
</ins><span class="cx">     my $saved_type = $type;
</span><span class="cx">     # The constant here should be updated every time a new,
</span><span class="cx">     # higher field type is added.
</span><del>-    (detaint_natural($type) &amp;&amp; $type &lt;= FIELD_TYPE_DATETIME)
</del><ins>+    (detaint_natural($type) &amp;&amp; $type &lt;= FIELD_TYPE_KEYWORDS)
</ins><span class="cx">       || ThrowCodeError('invalid_customfield_type', { type =&gt; $saved_type });
</span><ins>+
+    my $custom = blessed($invocant) ? $invocant-&gt;custom : $params-&gt;{custom};
+    if ($custom &amp;&amp; !$type) {
+        ThrowCodeError('field_type_not_specified');
+    }
+
</ins><span class="cx">     return $type;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub _check_value_field_id {
+    my ($invocant, $field_id, undef, $params) = @_;
+    my $is_select = $invocant-&gt;is_select($params);
+    if ($field_id &amp;&amp; !$is_select) {
+        ThrowUserError('field_value_control_select_only');
+    }
+    return $invocant-&gt;_check_visibility_field_id($field_id);
+}
+
+sub _check_visibility_field_id {
+    my ($invocant, $field_id) = @_;
+    $field_id = trim($field_id);
+    return undef if !$field_id;
+    my $field = Bugzilla::Field-&gt;check({ id =&gt; $field_id });
+    if (blessed($invocant) &amp;&amp; $field-&gt;id == $invocant-&gt;id) {
+        ThrowUserError('field_cant_control_self', { field =&gt; $field });
+    }
+    if (!$field-&gt;is_select) {
+        ThrowUserError('field_control_must_be_select',
+                       { field =&gt; $field });
+    }
+    return $field-&gt;id;
+}
+
+sub _check_visibility_values {
+    my ($invocant, $values, undef, $params) = @_;
+    my $field;
+    if (blessed $invocant) {
+        $field = $invocant-&gt;visibility_field;
+    }
+    elsif ($params-&gt;{visibility_field_id}) {
+        $field = $invocant-&gt;new($params-&gt;{visibility_field_id});
+    }
+    # When no field is set, no values are set.
+    return [] if !$field;
+
+    if (!scalar @$values) {
+        ThrowUserError('field_visibility_values_must_be_selected',
+                       { field =&gt; $field });
+    }
+
+    my @visibility_values;
+    my $choice = Bugzilla::Field::Choice-&gt;type($field);
+    foreach my $value (@$values) {
+        if (!blessed $value) {
+            $value = $choice-&gt;check({ id =&gt; $value });
+        }
+        push(@visibility_values, $value);
+    }
+
+    return \@visibility_values;
+}
+
+sub _check_reverse_desc {
+    my ($invocant, $reverse_desc, undef, $params) = @_;
+    my $type = blessed($invocant) ? $invocant-&gt;type : $params-&gt;{type};
+    if ($type != FIELD_TYPE_BUG_ID) {
+        return undef; # store NULL for non-reversible field types
+    }
+    
+    $reverse_desc = clean_text($reverse_desc);
+    return $reverse_desc;
+}
+
+sub _check_is_mandatory { return $_[1] ? 1 : 0; }
+
</ins><span class="cx"> =pod
</span><span class="cx"> 
</span><span class="cx"> =head2 Instance Properties
</span><span class="lines">@@ -361,25 +529,300 @@
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><ins>+=item C&lt;buglist&gt;
+
+A boolean specifying whether or not this field is selectable
+as a display or order column in buglist.cgi
+
+=back
+
+=cut
+
+sub buglist { return $_[0]-&gt;{buglist} }
+
+=over
+
+=item C&lt;is_select&gt;
+
+True if this is a C&lt;FIELD_TYPE_SINGLE_SELECT&gt; or C&lt;FIELD_TYPE_MULTI_SELECT&gt;
+field. It is only safe to call L&lt;/legal_values&gt; if this is true.
+
</ins><span class="cx"> =item C&lt;legal_values&gt;
</span><span class="cx"> 
</span><del>-A reference to an array with valid active values for this field.
</del><ins>+Valid values for this field, as an array of L&lt;Bugzilla::Field::Choice&gt;
+objects.
</ins><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><span class="cx"> =cut
</span><span class="cx"> 
</span><ins>+sub is_select {
+    my ($invocant, $params) = @_;
+    # This allows this method to be called by create() validators.
+    my $type = blessed($invocant) ? $invocant-&gt;type : $params-&gt;{type}; 
+    return ($type == FIELD_TYPE_SINGLE_SELECT 
+            || $type == FIELD_TYPE_MULTI_SELECT) ? 1 : 0 
+}
+
+=over
+
+=item C&lt;is_abnormal&gt;
+
+Most fields that have a C&lt;SELECT&gt; L&lt;/type&gt; have a certain schema for
+the table that stores their values, the table has the same name as the field,
+and the field's legal values can be edited via F&lt;editvalues.cgi&gt;.
+
+However, some fields do not follow that pattern. Those fields are
+considered &quot;abnormal&quot;.
+
+This method returns C&lt;1&gt; if the field is &quot;abnormal&quot;, C&lt;0&gt; otherwise.
+
+=back
+
+=cut
+
+sub is_abnormal {
+    my $self = shift;
+    return ABNORMAL_SELECTS-&gt;{$self-&gt;name} ? 1 : 0;
+}
+
</ins><span class="cx"> sub legal_values {
</span><span class="cx">     my $self = shift;
</span><span class="cx"> 
</span><span class="cx">     if (!defined $self-&gt;{'legal_values'}) {
</span><del>-        $self-&gt;{'legal_values'} = get_legal_field_values($self-&gt;name);
</del><ins>+        require Bugzilla::Field::Choice;
+        my @values = Bugzilla::Field::Choice-&gt;type($self)-&gt;get_all();
+        $self-&gt;{'legal_values'} = \@values;
</ins><span class="cx">     }
</span><span class="cx">     return $self-&gt;{'legal_values'};
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> =pod
</span><span class="cx"> 
</span><ins>+=over
+
+=item C&lt;is_timetracking&gt;
+
+True if this is a time-tracking field that should only be shown to users
+in the C&lt;timetrackinggroup&gt;.
+
+=back
+
+=cut
+
+sub is_timetracking {
+    my ($self) = @_;
+    return grep($_ eq $self-&gt;name, TIMETRACKING_FIELDS) ? 1 : 0;
+}
+
+=pod
+
+=over
+
+=item C&lt;visibility_field&gt;
+
+What field controls this field's visibility? Returns a C&lt;Bugzilla::Field&gt;
+object representing the field that controls this field's visibility.
+
+Returns undef if there is no field that controls this field's visibility.
+
+=back
+
+=cut
+
+sub visibility_field {
+    my $self = shift;
+    if ($self-&gt;{visibility_field_id}) {
+        $self-&gt;{visibility_field} ||= 
+            $self-&gt;new($self-&gt;{visibility_field_id});
+    }
+    return $self-&gt;{visibility_field};
+}
+
+=pod
+
+=over
+
+=item C&lt;visibility_values&gt;
+
+If we have a L&lt;/visibility_field&gt;, then what values does that field have to
+be set to in order to show this field? Returns a L&lt;Bugzilla::Field::Choice&gt;
+or undef if there is no C&lt;visibility_field&gt; set.
+
+=back
+
+=cut
+
+sub visibility_values {
+    my $self = shift;
+    my $dbh = Bugzilla-&gt;dbh;
+    
+    return [] if !$self-&gt;{visibility_field_id};
+
+    if (!defined $self-&gt;{visibility_values}) {
+        my $visibility_value_ids =
+            $dbh-&gt;selectcol_arrayref(&quot;SELECT value_id FROM field_visibility
+                                      WHERE field_id = ?&quot;, undef, $self-&gt;id);
+
+        $self-&gt;{visibility_values} =
+            Bugzilla::Field::Choice-&gt;type($self-&gt;visibility_field)
+            -&gt;new_from_list($visibility_value_ids);
+    }
+
+    return $self-&gt;{visibility_values};
+}
+
+=pod
+
+=over
+
+=item C&lt;controls_visibility_of&gt;
+
+An arrayref of C&lt;Bugzilla::Field&gt; objects, representing fields that this
+field controls the visibility of.
+
+=back
+
+=cut
+
+sub controls_visibility_of {
+    my $self = shift;
+    $self-&gt;{controls_visibility_of} ||= 
+        Bugzilla::Field-&gt;match({ visibility_field_id =&gt; $self-&gt;id });
+    return $self-&gt;{controls_visibility_of};
+}
+
+=pod
+
+=over
+
+=item C&lt;value_field&gt;
+
+The Bugzilla::Field that controls the list of values for this field.
+
+Returns undef if there is no field that controls this field's visibility.
+
+=back
+
+=cut
+
+sub value_field {
+    my $self = shift;
+    if ($self-&gt;{value_field_id}) {
+        $self-&gt;{value_field} ||= $self-&gt;new($self-&gt;{value_field_id});
+    }
+    return $self-&gt;{value_field};
+}
+
+=pod
+
+=over
+
+=item C&lt;controls_values_of&gt;
+
+An arrayref of C&lt;Bugzilla::Field&gt; objects, representing fields that this
+field controls the values of.
+
+=back
+
+=cut
+
+sub controls_values_of {
+    my $self = shift;
+    $self-&gt;{controls_values_of} ||=
+        Bugzilla::Field-&gt;match({ value_field_id =&gt; $self-&gt;id });
+    return $self-&gt;{controls_values_of};
+}
+
+=over
+
+=item C&lt;is_visible_on_bug&gt;
+
+See L&lt;Bugzilla::Field::ChoiceInterface&gt;.
+
+=back
+
+=cut
+
+sub is_visible_on_bug {
+    my ($self, $bug) = @_;
+
+    # Always return visible, if this field is not
+    # visibility controlled.
+    return 1 if !$self-&gt;{visibility_field_id};
+
+    my $visibility_values = $self-&gt;visibility_values;
+
+    return (any { $_-&gt;is_set_on_bug($bug) } @$visibility_values) ? 1 : 0;
+}
+
+=over
+
+=item C&lt;is_relationship&gt;
+
+Applies only to fields of type FIELD_TYPE_BUG_ID.
+Checks to see if a reverse relationship description has been set.
+This is the canonical condition to enable reverse link display,
+dependency tree display, and similar functionality.
+
+=back
+
+=cut
+
+sub is_relationship  {     
+    my $self = shift;
+    my $desc = $self-&gt;reverse_desc;
+    if (defined $desc &amp;&amp; $desc ne &quot;&quot;) {
+        return 1;
+    }
+    return 0;
+}
+
+=over
+
+=item C&lt;reverse_desc&gt;
+
+Applies only to fields of type FIELD_TYPE_BUG_ID.
+Describes the reverse relationship of this field.
+For example, if a BUG_ID field is called &quot;Is a duplicate of&quot;,
+the reverse description would be &quot;Duplicates of this bug&quot;.
+
+=back
+
+=cut
+
+sub reverse_desc { return $_[0]-&gt;{reverse_desc} }
+
+=over
+
+=item C&lt;is_mandatory&gt;
+
+a boolean specifying whether or not the field is mandatory;
+
+=back
+
+=cut
+
+sub is_mandatory { return $_[0]-&gt;{is_mandatory} }
+
+=over
+
+=item C&lt;is_numeric&gt;
+
+A boolean specifying whether or not this field logically contains
+numeric (integer, decimal, or boolean) values. By &quot;logically contains&quot; we
+mean that the user inputs numbers into the value of the field in the UI.
+This is mostly used by L&lt;Bugzilla::Search&gt;.
+
+=back
+
+=cut
+
+sub is_numeric { return $_[0]-&gt;{is_numeric} }
+
+
+=pod
+
</ins><span class="cx"> =head2 Instance Mutators
</span><span class="cx"> 
</span><span class="cx"> These set the particular field that they are named after.
</span><span class="lines">@@ -400,16 +843,51 @@
</span><span class="cx"> 
</span><span class="cx"> =item C&lt;set_in_new_bugmail&gt;
</span><span class="cx"> 
</span><ins>+=item C&lt;set_buglist&gt;
+
+=item C&lt;set_reverse_desc&gt;
+
+=item C&lt;set_visibility_field&gt;
+
+=item C&lt;set_visibility_values&gt;
+
+=item C&lt;set_value_field&gt;
+
+=item C&lt;set_is_mandatory&gt;
+
+
</ins><span class="cx"> =back
</span><span class="cx"> 
</span><span class="cx"> =cut
</span><span class="cx"> 
</span><span class="cx"> sub set_description    { $_[0]-&gt;set('description', $_[1]); }
</span><span class="cx"> sub set_enter_bug      { $_[0]-&gt;set('enter_bug',   $_[1]); }
</span><ins>+sub set_is_numeric     { $_[0]-&gt;set('is_numeric',  $_[1]); }
</ins><span class="cx"> sub set_obsolete       { $_[0]-&gt;set('obsolete',    $_[1]); }
</span><span class="cx"> sub set_sortkey        { $_[0]-&gt;set('sortkey',     $_[1]); }
</span><span class="cx"> sub set_in_new_bugmail { $_[0]-&gt;set('mailhead',    $_[1]); }
</span><ins>+sub set_buglist        { $_[0]-&gt;set('buglist',     $_[1]); }
+sub set_reverse_desc    { $_[0]-&gt;set('reverse_desc', $_[1]); }
+sub set_visibility_field {
+    my ($self, $value) = @_;
+    $self-&gt;set('visibility_field_id', $value);
+    delete $self-&gt;{visibility_field};
+    delete $self-&gt;{visibility_values};
+}
+sub set_visibility_values {
+    my ($self, $value_ids) = @_;
+    $self-&gt;set('visibility_values', $value_ids);
+}
+sub set_value_field {
+    my ($self, $value) = @_;
+    $self-&gt;set('value_field_id', $value);
+    delete $self-&gt;{value_field};
+}
+sub set_is_mandatory { $_[0]-&gt;set('is_mandatory', $_[1]); }
</ins><span class="cx"> 
</span><ins>+# This is only used internally by upgrade code in Bugzilla::Field.
+sub _set_type { $_[0]-&gt;set('type', $_[1]); }
+
</ins><span class="cx"> =pod
</span><span class="cx"> 
</span><span class="cx"> =head2 Instance Method
</span><span class="lines">@@ -456,16 +934,14 @@
</span><span class="cx">         $bugs_query = &quot;SELECT COUNT(*) FROM bug_$name&quot;;
</span><span class="cx">     }
</span><span class="cx">     else {
</span><del>-        $bugs_query = &quot;SELECT COUNT(*) FROM bugs WHERE $name IS NOT NULL
-                                AND $name != ''&quot;;
</del><ins>+        $bugs_query = &quot;SELECT COUNT(*) FROM bugs WHERE $name IS NOT NULL&quot;;
+        if ($self-&gt;type != FIELD_TYPE_BUG_ID &amp;&amp; $self-&gt;type != FIELD_TYPE_DATETIME) {
+            $bugs_query .= &quot; AND $name != ''&quot;;
+        }
</ins><span class="cx">         # Ignore the default single select value
</span><span class="cx">         if ($self-&gt;type == FIELD_TYPE_SINGLE_SELECT) {
</span><span class="cx">             $bugs_query .= &quot; AND $name != '---'&quot;;
</span><span class="cx">         }
</span><del>-        # Ignore blank dates.
-        if ($self-&gt;type == FIELD_TYPE_DATETIME) {
-            $bugs_query .= &quot; AND $name != '00-00-00 00:00:00'&quot;;
-        }
</del><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     my $has_bugs = $dbh-&gt;selectrow_array($bugs_query);
</span><span class="lines">@@ -483,9 +959,7 @@
</span><span class="cx">         $dbh-&gt;bz_drop_column('bugs', $name);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if ($type == FIELD_TYPE_SINGLE_SELECT
-        || $type == FIELD_TYPE_MULTI_SELECT)
-    {
</del><ins>+    if ($self-&gt;is_select) {
</ins><span class="cx">         # Delete the table that holds the legal values for this field.
</span><span class="cx">         $dbh-&gt;bz_drop_field_tables($self);
</span><span class="cx">     }
</span><span class="lines">@@ -520,8 +994,13 @@
</span><span class="cx"> =item C&lt;enter_bug&gt; - boolean - Whether this field is
</span><span class="cx"> editable on the bug creation form. Defaults to 0.
</span><span class="cx"> 
</span><ins>+=item C&lt;buglist&gt; - boolean - Whether this field is
+selectable as a display or order column in bug lists. Defaults to 0.
+
</ins><span class="cx"> C&lt;obsolete&gt; - boolean - Whether this field is obsolete. Defaults to 0.
</span><span class="cx"> 
</span><ins>+C&lt;is_mandatory&gt; - boolean - Whether this field is mandatory. Defaults to 0.
+
</ins><span class="cx"> =back
</span><span class="cx"> 
</span><span class="cx"> =back
</span><span class="lines">@@ -530,9 +1009,25 @@
</span><span class="cx"> 
</span><span class="cx"> sub create {
</span><span class="cx">     my $class = shift;
</span><del>-    my $field = $class-&gt;SUPER::create(@_);
</del><ins>+    my ($params) = @_;
+    my $dbh = Bugzilla-&gt;dbh;
</ins><span class="cx"> 
</span><del>-    my $dbh = Bugzilla-&gt;dbh;
</del><ins>+    # This makes sure the &quot;sortkey&quot; validator runs, even if
+    # the parameter isn't sent to create().
+    $params-&gt;{sortkey} = undef if !exists $params-&gt;{sortkey};
+    $params-&gt;{type} ||= 0;
+    
+    $dbh-&gt;bz_start_transaction();
+    $class-&gt;check_required_create_fields(@_);
+    my $field_values      = $class-&gt;run_create_validators($params);
+    my $visibility_values = delete $field_values-&gt;{visibility_values};
+    my $field             = $class-&gt;insert_create_data($field_values);
+    
+    $field-&gt;set_visibility_values($visibility_values);
+    $field-&gt;_update_visibility_values();
+
+    $dbh-&gt;bz_commit_transaction();
+
</ins><span class="cx">     if ($field-&gt;custom) {
</span><span class="cx">         my $name = $field-&gt;name;
</span><span class="cx">         my $type = $field-&gt;type;
</span><span class="lines">@@ -541,9 +1036,7 @@
</span><span class="cx">             $dbh-&gt;bz_add_column('bugs', $name, SQL_DEFINITIONS-&gt;{$type});
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if ($type == FIELD_TYPE_SINGLE_SELECT
-                || $type == FIELD_TYPE_MULTI_SELECT) 
-        {
</del><ins>+        if ($field-&gt;is_select) {
</ins><span class="cx">             # Create the table that holds the legal values for this field.
</span><span class="cx">             $dbh-&gt;bz_add_field_tables($field);
</span><span class="cx">         }
</span><span class="lines">@@ -557,21 +1050,37 @@
</span><span class="cx">     return $field;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub run_create_validators {
-    my $class = shift;
</del><ins>+sub update {
+    my $self = shift;
+    my $changes = $self-&gt;SUPER::update(@_);
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><del>-    my $params = $class-&gt;SUPER::run_create_validators(@_);
</del><ins>+    if ($changes-&gt;{value_field_id} &amp;&amp; $self-&gt;is_select) {
+        $dbh-&gt;do(&quot;UPDATE &quot; . $self-&gt;name . &quot; SET visibility_value_id = NULL&quot;);
+    }
+    $self-&gt;_update_visibility_values();
+    return $changes;
+}
</ins><span class="cx"> 
</span><del>-    $params-&gt;{name} = $class-&gt;_check_name($params-&gt;{name}, $params-&gt;{custom});
-    if (!exists $params-&gt;{sortkey}) {
-        $params-&gt;{sortkey} = $dbh-&gt;selectrow_array(
-            &quot;SELECT MAX(sortkey) + 100 FROM fielddefs&quot;) || 100;
</del><ins>+sub _update_visibility_values {
+    my $self = shift;
+    my $dbh = Bugzilla-&gt;dbh;
+
+    my @visibility_value_ids = map($_-&gt;id, @{$self-&gt;visibility_values});
+    $self-&gt;_delete_visibility_values();
+    for my $value_id (@visibility_value_ids) {
+        $dbh-&gt;do(&quot;INSERT INTO field_visibility (field_id, value_id)
+                  VALUES (?, ?)&quot;, undef, $self-&gt;id, $value_id);
</ins><span class="cx">     }
</span><ins>+}
</ins><span class="cx"> 
</span><del>-    return $params;
</del><ins>+sub _delete_visibility_values {
+    my ($self) = @_;
+    my $dbh = Bugzilla-&gt;dbh;
+    $dbh-&gt;do(&quot;DELETE FROM field_visibility WHERE field_id = ?&quot;,
+        undef, $self-&gt;id);
+    delete $self-&gt;{visibility_values};
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-
</del><span class="cx"> =pod
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="lines">@@ -625,6 +1134,10 @@
</span><span class="cx">         if ($field) {
</span><span class="cx">             $field-&gt;set_description($def-&gt;{desc});
</span><span class="cx">             $field-&gt;set_in_new_bugmail($def-&gt;{in_new_bugmail});
</span><ins>+            $field-&gt;set_buglist($def-&gt;{buglist});
+            $field-&gt;_set_type($def-&gt;{type}) if $def-&gt;{type};
+            $field-&gt;set_is_mandatory($def-&gt;{is_mandatory});
+            $field-&gt;set_is_numeric($def-&gt;{is_numeric});
</ins><span class="cx">             $field-&gt;update();
</span><span class="cx">         }
</span><span class="cx">         else {
</span><span class="lines">@@ -632,8 +1145,7 @@
</span><span class="cx">                 $def-&gt;{mailhead} = $def-&gt;{in_new_bugmail};
</span><span class="cx">                 delete $def-&gt;{in_new_bugmail};
</span><span class="cx">             }
</span><del>-            $def-&gt;{description} = $def-&gt;{desc};
-            delete $def-&gt;{desc};
</del><ins>+            $def-&gt;{description} = delete $def-&gt;{desc};
</ins><span class="cx">             Bugzilla::Field-&gt;create($def);
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -750,13 +1262,19 @@
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx"> 
</span><span class="cx">     # If $legalsRef is undefined, we use the default valid values.
</span><ins>+    # Valid values for this check are all possible values. 
+    # Using get_legal_values would only return active values, but since
+    # some bugs may have inactive values set, we want to check them too. 
</ins><span class="cx">     unless (defined $legalsRef) {
</span><del>-        $legalsRef = get_legal_field_values($name);
</del><ins>+        $legalsRef = Bugzilla::Field-&gt;new({name =&gt; $name})-&gt;legal_values;
+        my @values = map($_-&gt;name, @$legalsRef);
+        $legalsRef = \@values;
+
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (!defined($value)
</span><del>-        || trim($value) eq &quot;&quot;
-        || lsearch($legalsRef, $value) &lt; 0)
</del><ins>+        or trim($value) eq &quot;&quot;
+        or !grep { $_ eq $value } @$legalsRef)
</ins><span class="cx">     {
</span><span class="cx">         return 0 if $no_warn; # We don't want an error to be thrown; return.
</span><span class="cx">         trick_taint($name);
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaFlagpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Flag.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Flag.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Flag.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -53,6 +53,9 @@
</span><span class="cx"> 
</span><span class="cx"> =cut
</span><span class="cx"> 
</span><ins>+use Scalar::Util qw(blessed);
+use Storable qw(dclone);
+
</ins><span class="cx"> use Bugzilla::FlagType;
</span><span class="cx"> use Bugzilla::Hook;
</span><span class="cx"> use Bugzilla::User;
</span><span class="lines">@@ -69,21 +72,40 @@
</span><span class="cx"> ####    Initialization     ####
</span><span class="cx"> ###############################
</span><span class="cx"> 
</span><del>-use constant DB_COLUMNS =&gt; qw(
-    flags.id
-    flags.type_id
-    flags.bug_id
-    flags.attach_id
-    flags.requestee_id
-    flags.setter_id
-    flags.status
-);
-
</del><span class="cx"> use constant DB_TABLE =&gt; 'flags';
</span><span class="cx"> use constant LIST_ORDER =&gt; 'id';
</span><ins>+# Flags are tracked in bugs_activity.
+use constant AUDIT_CREATES =&gt; 0;
+use constant AUDIT_UPDATES =&gt; 0;
+use constant AUDIT_REMOVES =&gt; 0;
</ins><span class="cx"> 
</span><span class="cx"> use constant SKIP_REQUESTEE_ON_ERROR =&gt; 1;
</span><span class="cx"> 
</span><ins>+use constant DB_COLUMNS =&gt; qw(
+    id
+    type_id
+    bug_id
+    attach_id
+    requestee_id
+    setter_id
+    status
+);
+
+use constant UPDATE_COLUMNS =&gt; qw(
+    requestee_id
+    setter_id
+    status
+    type_id
+);
+
+use constant VALIDATORS =&gt; {
+};
+
+use constant UPDATE_VALIDATORS =&gt; {
+    setter =&gt; \&amp;_check_setter,
+    status =&gt; \&amp;_check_status,
+};
+
</ins><span class="cx"> ###############################
</span><span class="cx"> ####      Accessors      ######
</span><span class="cx"> ###############################
</span><span class="lines">@@ -116,11 +138,14 @@
</span><span class="cx"> 
</span><span class="cx"> =cut
</span><span class="cx"> 
</span><del>-sub id     { return $_[0]-&gt;{'id'};     }
-sub name   { return $_[0]-&gt;type-&gt;name; }
-sub bug_id { return $_[0]-&gt;{'bug_id'}; }
-sub attach_id { return $_[0]-&gt;{'attach_id'}; }
-sub status { return $_[0]-&gt;{'status'}; }
</del><ins>+sub id           { return $_[0]-&gt;{'id'};           }
+sub name         { return $_[0]-&gt;type-&gt;name;       }
+sub type_id      { return $_[0]-&gt;{'type_id'};      }
+sub bug_id       { return $_[0]-&gt;{'bug_id'};       }
+sub attach_id    { return $_[0]-&gt;{'attach_id'};    }
+sub status       { return $_[0]-&gt;{'status'};       }
+sub setter_id    { return $_[0]-&gt;{'setter_id'};    }
+sub requestee_id { return $_[0]-&gt;{'requestee_id'}; }
</ins><span class="cx"> 
</span><span class="cx"> ###############################
</span><span class="cx"> ####       Methods         ####
</span><span class="lines">@@ -180,10 +205,18 @@
</span><span class="cx">     return undef unless $self-&gt;attach_id;
</span><span class="cx"> 
</span><span class="cx">     require Bugzilla::Attachment;
</span><del>-    $self-&gt;{'attachment'} ||= Bugzilla::Attachment-&gt;get($self-&gt;attach_id);
</del><ins>+    $self-&gt;{'attachment'} ||= new Bugzilla::Attachment($self-&gt;attach_id);
</ins><span class="cx">     return $self-&gt;{'attachment'};
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub bug {
+    my $self = shift;
+
+    require Bugzilla::Bug;
+    $self-&gt;{'bug'} ||= new Bugzilla::Bug($self-&gt;bug_id);
+    return $self-&gt;{'bug'};
+}
+
</ins><span class="cx"> ################################
</span><span class="cx"> ## Searching/Retrieving Flags ##
</span><span class="cx"> ################################
</span><span class="lines">@@ -192,26 +225,6 @@
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><del>-=item C&lt;has_flags&gt;
-
-Returns 1 if at least one flag exists in the DB, else 0. This subroutine
-is mainly used to decide to display the &quot;(My )Requests&quot; link in the footer.
-
-=back
-
-=cut
-
-sub has_flags {
-    my $dbh = Bugzilla-&gt;dbh;
-
-    my $has_flags = $dbh-&gt;selectrow_array('SELECT 1 FROM flags ' . $dbh-&gt;sql_limit(1));
-    return $has_flags || 0;
-}
-
-=pod
-
-=over
-
</del><span class="cx"> =item C&lt;match($criteria)&gt;
</span><span class="cx"> 
</span><span class="cx"> Queries the database for flags matching the given criteria
</span><span class="lines">@@ -268,746 +281,572 @@
</span><span class="cx"> # Creating and Modifying
</span><span class="cx"> ######################################################################
</span><span class="cx"> 
</span><del>-=pod
</del><ins>+sub set_flag {
+    my ($class, $obj, $params) = @_;
</ins><span class="cx"> 
</span><del>-=over
</del><ins>+    my ($bug, $attachment);
+    if (blessed($obj) &amp;&amp; $obj-&gt;isa('Bugzilla::Attachment')) {
+        $attachment = $obj;
+        $bug = $attachment-&gt;bug;
+    }
+    elsif (blessed($obj) &amp;&amp; $obj-&gt;isa('Bugzilla::Bug')) {
+        $bug = $obj;
+    }
+    else {
+        ThrowCodeError('flag_unexpected_object', { 'caller' =&gt; ref $obj });
+    }
</ins><span class="cx"> 
</span><del>-=item C&lt;validate($bug_id, $attach_id, $skip_requestee_on_error)&gt;
</del><ins>+    # Update (or delete) an existing flag.
+    if ($params-&gt;{id}) {
+        my $flag = $class-&gt;check({ id =&gt; $params-&gt;{id} });
</ins><span class="cx"> 
</span><del>-Validates fields containing flag modifications.
</del><ins>+        # Security check: make sure the flag belongs to the bug/attachment.
+        # We don't check that the user editing the flag can see
+        # the bug/attachment. That's the job of the caller.
+        ($attachment &amp;&amp; $flag-&gt;attach_id &amp;&amp; $attachment-&gt;id == $flag-&gt;attach_id)
+          || (!$attachment &amp;&amp; !$flag-&gt;attach_id &amp;&amp; $bug-&gt;id == $flag-&gt;bug_id)
+          || ThrowCodeError('invalid_flag_association',
+                            { bug_id    =&gt; $bug-&gt;id,
+                              attach_id =&gt; $attachment ? $attachment-&gt;id : undef });
</ins><span class="cx"> 
</span><del>-If the attachment is new, it has no ID yet and $attach_id is set
-to -1 to force its check anyway.
</del><ins>+        # Extract the current flag object from the object.
+        my ($obj_flagtype) = grep { $_-&gt;id == $flag-&gt;type_id } @{$obj-&gt;flag_types};
+        # If no flagtype can be found for this flag, this means the bug is being
+        # moved into a product/component where the flag is no longer valid.
+        # So either we can attach the flag to another flagtype having the same
+        # name, or we remove the flag.
+        if (!$obj_flagtype) {
+            my $success = $flag-&gt;retarget($obj);
+            return unless $success;
</ins><span class="cx"> 
</span><del>-=back
-
-=cut
-
-sub validate {
-    my ($bug_id, $attach_id, $skip_requestee_on_error) = @_;
-    my $cgi = Bugzilla-&gt;cgi;
-    my $dbh = Bugzilla-&gt;dbh;
-
-    # Get a list of flags to validate.  Uses the &quot;map&quot; function
-    # to extract flag IDs from form field names by matching fields
-    # whose name looks like &quot;flag_type-nnn&quot; (new flags) or &quot;flag-nnn&quot;
-    # (existing flags), where &quot;nnn&quot; is the ID, and returning just
-    # the ID portion of matching field names.
-    my @flagtype_ids = map(/^flag_type-(\d+)$/ ? $1 : (), $cgi-&gt;param());
-    my @flag_ids = map(/^flag-(\d+)$/ ? $1 : (), $cgi-&gt;param());
-
-    return unless (scalar(@flagtype_ids) || scalar(@flag_ids));
-
-    # No flag reference should exist when changing several bugs at once.
-    ThrowCodeError(&quot;flags_not_available&quot;, { type =&gt; 'b' }) unless $bug_id;
-
-    # We don't check that these new flags are valid for this bug/attachment,
-    # because the bug may be moved into another product meanwhile.
-    # This check will be done later when creating new flags, see FormToNewFlags().
-
-    if (scalar(@flag_ids)) {
-        # No reference to existing flags should exist when creating a new
-        # attachment.
-        if ($attach_id &amp;&amp; ($attach_id &lt; 0)) {
-            ThrowCodeError('flags_not_available', { type =&gt; 'a' });
</del><ins>+            ($obj_flagtype) = grep { $_-&gt;id == $flag-&gt;type_id } @{$obj-&gt;flag_types};
+            push(@{$obj_flagtype-&gt;{flags}}, $flag);
</ins><span class="cx">         }
</span><ins>+        my ($obj_flag) = grep { $_-&gt;id == $flag-&gt;id } @{$obj_flagtype-&gt;{flags}};
+        # If the flag has the correct type but cannot be found above, this means
+        # the flag is going to be removed (e.g. because this is a pending request
+        # and the attachment is being marked as obsolete).
+        return unless $obj_flag;
</ins><span class="cx"> 
</span><del>-        # Make sure all existing flags belong to the bug/attachment
-        # they pretend to be.
-        my $field = ($attach_id) ? &quot;attach_id&quot; : &quot;bug_id&quot;;
-        my $field_id = $attach_id || $bug_id;
-        my $not = ($attach_id) ? &quot;&quot; : &quot;NOT&quot;;
-
-        my $invalid_data =
-            $dbh-&gt;selectrow_array(
-                      &quot;SELECT 1 FROM flags
-                        WHERE &quot; 
-                       . $dbh-&gt;sql_in('id', \@flag_ids) 
-                       . &quot; AND ($field != ? OR attach_id IS $not NULL) &quot;
-                       . $dbh-&gt;sql_limit(1), undef, $field_id);
-
-        if ($invalid_data) {
-            ThrowCodeError('invalid_flag_association',
-                           { bug_id    =&gt; $bug_id,
-                             attach_id =&gt; $attach_id });
-        }
</del><ins>+        $class-&gt;_validate($obj_flag, $obj_flagtype, $params, $bug, $attachment);
</ins><span class="cx">     }
</span><del>-
-    # Validate new flags.
-    foreach my $id (@flagtype_ids) {
-        my $status = $cgi-&gt;param(&quot;flag_type-$id&quot;);
-        my @requestees = $cgi-&gt;param(&quot;requestee_type-$id&quot;);
-        my $private_attachment = $cgi-&gt;param('isprivate') ? 1 : 0;
-
</del><ins>+    # Create a new flag.
+    elsif ($params-&gt;{type_id}) {
</ins><span class="cx">         # Don't bother validating types the user didn't touch.
</span><del>-        next if $status eq 'X';
</del><ins>+        return if $params-&gt;{status} eq 'X';
</ins><span class="cx"> 
</span><del>-        # Make sure the flag type exists. If it doesn't, FormToNewFlags()
-        # will ignore it, so it's safe to ignore it here.
-        my $flag_type = new Bugzilla::FlagType($id);
-        next unless $flag_type;
</del><ins>+        my $flagtype = Bugzilla::FlagType-&gt;check({ id =&gt; $params-&gt;{type_id} });
+        # Security check: make sure the flag type belongs to the bug/attachment.
+        ($attachment &amp;&amp; $flagtype-&gt;target_type eq 'attachment'
+          &amp;&amp; scalar(grep { $_-&gt;id == $flagtype-&gt;id } @{$attachment-&gt;flag_types}))
+          || (!$attachment &amp;&amp; $flagtype-&gt;target_type eq 'bug'
+                &amp;&amp; scalar(grep { $_-&gt;id == $flagtype-&gt;id } @{$bug-&gt;flag_types}))
+          || ThrowCodeError('invalid_flag_association',
+                            { bug_id    =&gt; $bug-&gt;id,
+                              attach_id =&gt; $attachment ? $attachment-&gt;id : undef });
</ins><span class="cx"> 
</span><span class="cx">         # Make sure the flag type is active.
</span><del>-        unless ($flag_type-&gt;is_active) {
-            ThrowCodeError('flag_type_inactive', {'type' =&gt; $flag_type-&gt;name});
-        }
</del><ins>+        $flagtype-&gt;is_active
+          || ThrowCodeError('flag_type_inactive', { type =&gt; $flagtype-&gt;name });
</ins><span class="cx"> 
</span><del>-        _validate(undef, $flag_type, $status, undef, \@requestees, $private_attachment,
-                  $bug_id, $attach_id, $skip_requestee_on_error);
-    }
</del><ins>+        # Extract the current flagtype object from the object.
+        my ($obj_flagtype) = grep { $_-&gt;id == $flagtype-&gt;id } @{$obj-&gt;flag_types};
</ins><span class="cx"> 
</span><del>-    # Validate existing flags.
-    foreach my $id (@flag_ids) {
-        my $status = $cgi-&gt;param(&quot;flag-$id&quot;);
-        my @requestees = $cgi-&gt;param(&quot;requestee-$id&quot;);
-        my $private_attachment = $cgi-&gt;param('isprivate') ? 1 : 0;
</del><ins>+        # We cannot create a new flag if there is already one and this
+        # flag type is not multiplicable.
+        if (!$flagtype-&gt;is_multiplicable) {
+            if (scalar @{$obj_flagtype-&gt;{flags}}) {
+                ThrowUserError('flag_type_not_multiplicable', { type =&gt; $flagtype });
+            }
+        }
</ins><span class="cx"> 
</span><del>-        # Make sure the flag exists. If it doesn't, process() will ignore it,
-        # so it's safe to ignore it here.
-        my $flag = new Bugzilla::Flag($id);
-        next unless $flag;
-
-        _validate($flag, $flag-&gt;type, $status, undef, \@requestees, $private_attachment,
-                  undef, undef, $skip_requestee_on_error);
</del><ins>+        $class-&gt;_validate(undef, $obj_flagtype, $params, $bug, $attachment);
</ins><span class="cx">     }
</span><ins>+    else {
+        ThrowCodeError('param_required', { function =&gt; $class . '-&gt;set_flag',
+                                           param    =&gt; 'id/type_id' });
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _validate {
</span><del>-    my ($flag, $flag_type, $status, $setter, $requestees, $private_attachment,
-        $bug_id, $attach_id, $skip_requestee_on_error) = @_;
</del><ins>+    my ($class, $flag, $flag_type, $params, $bug, $attachment) = @_;
</ins><span class="cx"> 
</span><del>-    # By default, the flag setter (or requester) is the current user.
-    $setter ||= Bugzilla-&gt;user;
</del><ins>+    # If it's a new flag, let's create it now.
+    my $obj_flag = $flag || bless({ type_id   =&gt; $flag_type-&gt;id,
+                                    status    =&gt; '',
+                                    bug_id    =&gt; $bug-&gt;id,
+                                    attach_id =&gt; $attachment ?
+                                                   $attachment-&gt;id : undef},
+                                    $class);
</ins><span class="cx"> 
</span><del>-    my $id = $flag ? $flag-&gt;id : $flag_type-&gt;id; # Used in the error messages below.
-    $bug_id ||= $flag-&gt;bug_id;
-    $attach_id ||= $flag-&gt;attach_id if $flag; # Maybe it's a bug flag.
</del><ins>+    my $old_status = $obj_flag-&gt;status;
+    my $old_requestee_id = $obj_flag-&gt;requestee_id;
</ins><span class="cx"> 
</span><del>-    # Make sure the user chose a valid status.
-    grep($status eq $_, qw(X + - ?))
-      || ThrowCodeError('flag_status_invalid',
-                        { id =&gt; $id, status =&gt; $status });
</del><ins>+    $obj_flag-&gt;_set_status($params-&gt;{status});
+    $obj_flag-&gt;_set_requestee($params-&gt;{requestee}, $attachment, $params-&gt;{skip_roe});
</ins><span class="cx"> 
</span><del>-    # Make sure the user didn't request the flag unless it's requestable.
-    # If the flag existed and was requested before it became unrequestable,
-    # leave it as is.
-    if ($status eq '?'
-        &amp;&amp; (!$flag || $flag-&gt;status ne '?')
-        &amp;&amp; !$flag_type-&gt;is_requestable)
</del><ins>+    # The setter field MUST NOT be updated if neither the status
+    # nor the requestee fields changed.
+    if (($obj_flag-&gt;status ne $old_status)
+        # The requestee ID can be undefined.
+        || (($obj_flag-&gt;requestee_id || 0) != ($old_requestee_id || 0)))
</ins><span class="cx">     {
</span><del>-        ThrowCodeError('flag_status_invalid',
-                       { id =&gt; $id, status =&gt; $status });
</del><ins>+        $obj_flag-&gt;_set_setter($params-&gt;{setter});
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    # Make sure the user didn't specify a requestee unless the flag
-    # is specifically requestable. For existing flags, if the requestee
-    # was set before the flag became specifically unrequestable, don't
-    # let the user change the requestee, but let the user remove it by
-    # entering an empty string for the requestee.
-    if ($status eq '?' &amp;&amp; !$flag_type-&gt;is_requesteeble) {
-        my $old_requestee = ($flag &amp;&amp; $flag-&gt;requestee) ?
-                                $flag-&gt;requestee-&gt;login : '';
-        my $new_requestee = join('', @$requestees);
-        if ($new_requestee &amp;&amp; $new_requestee ne $old_requestee) {
-            ThrowCodeError('flag_requestee_disabled',
-                           { type =&gt; $flag_type });
-        }
</del><ins>+    # If the flag is deleted, remove it from the list.
+    if ($obj_flag-&gt;status eq 'X') {
+        @{$flag_type-&gt;{flags}} = grep { $_-&gt;id != $obj_flag-&gt;id } @{$flag_type-&gt;{flags}};
</ins><span class="cx">     }
</span><del>-
-    # Make sure the user didn't enter multiple requestees for a flag
-    # that can't be requested from more than one person at a time.
-    if ($status eq '?'
-        &amp;&amp; !$flag_type-&gt;is_multiplicable
-        &amp;&amp; scalar(@$requestees) &gt; 1)
-    {
-        ThrowUserError('flag_not_multiplicable', { type =&gt; $flag_type });
</del><ins>+    # Add the newly created flag to the list.
+    elsif (!$obj_flag-&gt;id) {
+        push(@{$flag_type-&gt;{flags}}, $obj_flag);
</ins><span class="cx">     }
</span><ins>+}
</ins><span class="cx"> 
</span><del>-    # Make sure the requestees are authorized to access the bug
-    # (and attachment, if this installation is using the &quot;insider group&quot;
-    # feature and the attachment is marked private).
-    if ($status eq '?' &amp;&amp; $flag_type-&gt;is_requesteeble) {
-        my $old_requestee = ($flag &amp;&amp; $flag-&gt;requestee) ?
-                                $flag-&gt;requestee-&gt;login : '';
</del><ins>+=pod
</ins><span class="cx"> 
</span><del>-        my @legal_requestees;
-        foreach my $login (@$requestees) {
-            if ($login eq $old_requestee) {
-                # This requestee was already set. Leave him alone.
-                push(@legal_requestees, $login);
-                next;
-            }
</del><ins>+=over
</ins><span class="cx"> 
</span><del>-            # We know the requestee exists because we ran
-            # Bugzilla::User::match_field before getting here.
-            my $requestee = new Bugzilla::User({ name =&gt; $login });
</del><ins>+=item C&lt;create($flag, $timestamp)&gt;
</ins><span class="cx"> 
</span><del>-            # Throw an error if the user can't see the bug.
-            # Note that if permissions on this bug are changed,
-            # can_see_bug() will refer to old settings.
-            if (!$requestee-&gt;can_see_bug($bug_id)) {
-                next if $skip_requestee_on_error;
-                ThrowUserError('flag_requestee_unauthorized',
-                               { flag_type  =&gt; $flag_type,
-                                 requestee  =&gt; $requestee,
-                                 bug_id     =&gt; $bug_id,
-                                 attach_id  =&gt; $attach_id });
-            }
</del><ins>+Creates a flag record in the database.
</ins><span class="cx"> 
</span><del>-            # Throw an error if the target is a private attachment and
-            # the requestee isn't in the group of insiders who can see it.
-            if ($attach_id
-                &amp;&amp; $private_attachment
-                &amp;&amp; Bugzilla-&gt;params-&gt;{'insidergroup'}
-                &amp;&amp; !$requestee-&gt;in_group(Bugzilla-&gt;params-&gt;{'insidergroup'}))
-            {
-                next if $skip_requestee_on_error;
-                ThrowUserError('flag_requestee_unauthorized_attachment',
-                               { flag_type  =&gt; $flag_type,
-                                 requestee  =&gt; $requestee,
-                                 bug_id     =&gt; $bug_id,
-                                 attach_id  =&gt; $attach_id });
-            }
</del><ins>+=back
</ins><span class="cx"> 
</span><del>-            # Throw an error if the user won't be allowed to set the flag.
-            if (!$requestee-&gt;can_set_flag($flag_type)) {
-                next if $skip_requestee_on_error;
-                ThrowUserError('flag_requestee_needs_privs',
-                               {'requestee' =&gt; $requestee,
-                                'flagtype'  =&gt; $flag_type});
-            }
</del><ins>+=cut
</ins><span class="cx"> 
</span><del>-            # This requestee can be set.
-            push(@legal_requestees, $login);
-        }
</del><ins>+sub create {
+    my ($class, $flag, $timestamp) = @_;
+    $timestamp ||= Bugzilla-&gt;dbh-&gt;selectrow_array('SELECT NOW()');
</ins><span class="cx"> 
</span><del>-        # Update the requestee list for this flag.
-        if (scalar(@legal_requestees) &lt; scalar(@$requestees)) {
-            my $field_name = 'requestee_type-' . $flag_type-&gt;id;
-            Bugzilla-&gt;cgi-&gt;delete($field_name);
-            Bugzilla-&gt;cgi-&gt;param(-name =&gt; $field_name, -value =&gt; \@legal_requestees);
-        }
-    }
</del><ins>+    my $params = {};
+    my @columns = grep { $_ ne 'id' } $class-&gt;_get_db_columns;
+    $params-&gt;{$_} = $flag-&gt;{$_} foreach @columns;
</ins><span class="cx"> 
</span><del>-    # Make sure the user is authorized to modify flags, see bug 180879
-    # - The flag exists and is unchanged.
-    return if ($flag &amp;&amp; ($status eq $flag-&gt;status));
</del><ins>+    $params-&gt;{creation_date} = $params-&gt;{modification_date} = $timestamp;
</ins><span class="cx"> 
</span><del>-    # - User in the request_group can clear pending requests and set flags
-    #   and can rerequest set flags.
-    return if (($status eq 'X' || $status eq '?')
-               &amp;&amp; $setter-&gt;can_request_flag($flag_type));
</del><ins>+    $flag = $class-&gt;SUPER::create($params);
+    return $flag;
+}
</ins><span class="cx"> 
</span><del>-    # - User in the grant_group can set/clear flags, including &quot;+&quot; and &quot;-&quot;.
-    return if $setter-&gt;can_set_flag($flag_type);
</del><ins>+sub update {
+    my $self = shift;
+    my $dbh = Bugzilla-&gt;dbh;
+    my $timestamp = shift || $dbh-&gt;selectrow_array('SELECT NOW()');
</ins><span class="cx"> 
</span><del>-    # - Any other flag modification is denied
-    ThrowUserError('flag_update_denied',
-                    { name       =&gt; $flag_type-&gt;name,
-                      status     =&gt; $status,
-                      old_status =&gt; $flag ? $flag-&gt;status : 'X' });
</del><ins>+    my $changes = $self-&gt;SUPER::update(@_);
+
+    if (scalar(keys %$changes)) {
+        $dbh-&gt;do('UPDATE flags SET modification_date = ? WHERE id = ?',
+                 undef, ($timestamp, $self-&gt;id));
+    }
+    return $changes;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub snapshot {
</span><del>-    my ($class, $bug_id, $attach_id) = @_;
</del><ins>+    my ($class, $flags) = @_;
</ins><span class="cx"> 
</span><del>-    my $flags = $class-&gt;match({ 'bug_id'    =&gt; $bug_id,
-                                'attach_id' =&gt; $attach_id });
</del><span class="cx">     my @summaries;
</span><span class="cx">     foreach my $flag (@$flags) {
</span><del>-        my $summary = $flag-&gt;type-&gt;name . $flag-&gt;status;
</del><ins>+        my $summary = $flag-&gt;setter-&gt;nick . ':' . $flag-&gt;type-&gt;name . $flag-&gt;status;
</ins><span class="cx">         $summary .= &quot;(&quot; . $flag-&gt;requestee-&gt;login . &quot;)&quot; if $flag-&gt;requestee;
</span><span class="cx">         push(@summaries, $summary);
</span><span class="cx">     }
</span><span class="cx">     return @summaries;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub update_activity {
+    my ($class, $old_summaries, $new_summaries) = @_;
</ins><span class="cx"> 
</span><del>-=pod
</del><ins>+    my ($removed, $added) = diff_arrays($old_summaries, $new_summaries);
+    if (scalar @$removed || scalar @$added) {
+        # Remove flag requester/setter information
+        foreach (@$removed, @$added) { s/^[^:]+:// }
</ins><span class="cx"> 
</span><del>-=over
-
-=item C&lt;process($bug, $attachment, $timestamp, $hr_vars)&gt;
-
-Processes changes to flags.
-
-The bug and/or the attachment objects are the ones this flag is about,
-the timestamp is the date/time the bug was last touched (so that changes
-to the flag can be stamped with the same date/time).
-
-=back
-
-=cut
-
-sub process {
-    my ($class, $bug, $attachment, $timestamp, $hr_vars) = @_;
-    my $dbh = Bugzilla-&gt;dbh;
-    my $cgi = Bugzilla-&gt;cgi;
-
-    # Make sure the bug (and attachment, if given) exists and is accessible
-    # to the current user. Moreover, if an attachment object is passed,
-    # make sure it belongs to the given bug.
-    return if ($bug-&gt;error || ($attachment &amp;&amp; $bug-&gt;bug_id != $attachment-&gt;bug_id));
-
-    my $bug_id = $bug-&gt;bug_id;
-    my $attach_id = $attachment ? $attachment-&gt;id : undef;
-
-    # Use the date/time we were given if possible (allowing calling code
-    # to synchronize the comment's timestamp with those of other records).
-    $timestamp ||= $dbh-&gt;selectrow_array('SELECT NOW()');
-
-    # Take a snapshot of flags before any changes.
-    my @old_summaries = $class-&gt;snapshot($bug_id, $attach_id);
-
-    # Cancel pending requests if we are obsoleting an attachment.
-    if ($attachment &amp;&amp; $cgi-&gt;param('isobsolete')) {
-        $class-&gt;CancelRequests($bug, $attachment);
</del><ins>+        $removed = join(&quot;, &quot;, @$removed);
+        $added = join(&quot;, &quot;, @$added);
+        return ($removed, $added);
</ins><span class="cx">     }
</span><ins>+    return ();
+}
</ins><span class="cx"> 
</span><del>-    # Create new flags and update existing flags.
-    my $new_flags = FormToNewFlags($bug, $attachment, $cgi, $hr_vars);
-    foreach my $flag (@$new_flags) { create($flag, $bug, $attachment, $timestamp) }
-    modify($bug, $attachment, $cgi, $timestamp);
</del><ins>+sub update_flags {
+    my ($class, $self, $old_self, $timestamp) = @_;
</ins><span class="cx"> 
</span><del>-    # In case the bug's product/component has changed, clear flags that are
-    # no longer valid.
-    my $flag_ids = $dbh-&gt;selectcol_arrayref(
-        &quot;SELECT DISTINCT flags.id
-           FROM flags
-     INNER JOIN bugs
-             ON flags.bug_id = bugs.bug_id
-      LEFT JOIN flaginclusions AS i
-             ON flags.type_id = i.type_id 
-            AND (bugs.product_id = i.product_id OR i.product_id IS NULL)
-            AND (bugs.component_id = i.component_id OR i.component_id IS NULL)
-          WHERE bugs.bug_id = ?
-            AND i.type_id IS NULL&quot;,
-        undef, $bug_id);
</del><ins>+    my @old_summaries = $class-&gt;snapshot($old_self-&gt;flags);
+    my %old_flags = map { $_-&gt;id =&gt; $_ } @{$old_self-&gt;flags};
</ins><span class="cx"> 
</span><del>-    my $flags = Bugzilla::Flag-&gt;new_from_list($flag_ids);
-    foreach my $flag (@$flags) {
-        my $is_retargetted = retarget($flag, $bug);
-        unless ($is_retargetted) {
-            clear($flag, $bug, $flag-&gt;attachment);
-            $hr_vars-&gt;{'message'} = 'flag_cleared';
</del><ins>+    foreach my $new_flag (@{$self-&gt;flags}) {
+        if (!$new_flag-&gt;id) {
+            # This is a new flag.
+            my $flag = $class-&gt;create($new_flag, $timestamp);
+            $new_flag-&gt;{id} = $flag-&gt;id;
+            $class-&gt;notify($new_flag, undef, $self, $timestamp);
</ins><span class="cx">         }
</span><ins>+        else {
+            my $changes = $new_flag-&gt;update($timestamp);
+            if (scalar(keys %$changes)) {
+                $class-&gt;notify($new_flag, $old_flags{$new_flag-&gt;id}, $self, $timestamp);
+            }
+            delete $old_flags{$new_flag-&gt;id};
+        }
</ins><span class="cx">     }
</span><ins>+    # These flags have been deleted.
+    foreach my $old_flag (values %old_flags) {
+        $class-&gt;notify(undef, $old_flag, $self, $timestamp);
+        $old_flag-&gt;remove_from_db();
+    }
</ins><span class="cx"> 
</span><del>-    $flag_ids = $dbh-&gt;selectcol_arrayref(
-        &quot;SELECT DISTINCT flags.id
-        FROM flags, bugs, flagexclusions e
-        WHERE bugs.bug_id = ?
-        AND flags.bug_id = bugs.bug_id
-        AND flags.type_id = e.type_id
-        AND (bugs.product_id = e.product_id OR e.product_id IS NULL)
-        AND (bugs.component_id = e.component_id OR e.component_id IS NULL)&quot;,
-        undef, $bug_id);
-
-    $flags = Bugzilla::Flag-&gt;new_from_list($flag_ids);
-    foreach my $flag (@$flags) {
-        my $is_retargetted = retarget($flag, $bug);
-        clear($flag, $bug, $flag-&gt;attachment) unless $is_retargetted;
</del><ins>+    # If the bug has been moved into another product or component,
+    # we must also take care of attachment flags which are no longer valid,
+    # as well as all bug flags which haven't been forgotten above.
+    if ($self-&gt;isa('Bugzilla::Bug')
+        &amp;&amp; ($self-&gt;{_old_product_name} || $self-&gt;{_old_component_name}))
+    {
+        my @removed = $class-&gt;force_cleanup($self);
+        push(@old_summaries, @removed);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    # Take a snapshot of flags after changes.
-    my @new_summaries = $class-&gt;snapshot($bug_id, $attach_id);
</del><ins>+    my @new_summaries = $class-&gt;snapshot($self-&gt;flags);
+    my @changes = $class-&gt;update_activity(\@old_summaries, \@new_summaries);
</ins><span class="cx"> 
</span><del>-    update_activity($bug_id, $attach_id, $timestamp, \@old_summaries, \@new_summaries);
-
-    Bugzilla::Hook::process('flag-end_of_update', { bug       =&gt; $bug,
</del><ins>+    Bugzilla::Hook::process('flag_end_of_update', { object    =&gt; $self,
</ins><span class="cx">                                                     timestamp =&gt; $timestamp,
</span><span class="cx">                                                     old_flags =&gt; \@old_summaries,
</span><span class="cx">                                                     new_flags =&gt; \@new_summaries,
</span><span class="cx">                                                   });
</span><ins>+    return @changes;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub update_activity {
-    my ($bug_id, $attach_id, $timestamp, $old_summaries, $new_summaries) = @_;
-    my $dbh = Bugzilla-&gt;dbh;
</del><ins>+sub retarget {
+    my ($self, $obj) = @_;
</ins><span class="cx"> 
</span><del>-    $old_summaries = join(&quot;, &quot;, @$old_summaries);
-    $new_summaries = join(&quot;, &quot;, @$new_summaries);
-    my ($removed, $added) = diff_strings($old_summaries, $new_summaries);
-    if ($removed ne $added) {
-        my $field_id = get_field_id('flagtypes.name');
-        $dbh-&gt;do('INSERT INTO bugs_activity
-                  (bug_id, attach_id, who, bug_when, fieldid, removed, added)
-                  VALUES (?, ?, ?, ?, ?, ?, ?)',
-                  undef, ($bug_id, $attach_id, Bugzilla-&gt;user-&gt;id,
-                  $timestamp, $field_id, $removed, $added));
</del><ins>+    my @flagtypes = grep { $_-&gt;name eq $self-&gt;type-&gt;name } @{$obj-&gt;flag_types};
</ins><span class="cx"> 
</span><del>-        $dbh-&gt;do('UPDATE bugs SET delta_ts = ? WHERE bug_id = ?',
-                  undef, ($timestamp, $bug_id));
</del><ins>+    my $success = 0;
+    foreach my $flagtype (@flagtypes) {
+        next if !$flagtype-&gt;is_active;
+        next if (!$flagtype-&gt;is_multiplicable &amp;&amp; scalar @{$flagtype-&gt;{flags}});
+        next unless (($self-&gt;status eq '?' &amp;&amp; $self-&gt;setter-&gt;can_request_flag($flagtype))
+                     || $self-&gt;setter-&gt;can_set_flag($flagtype));
+
+        $self-&gt;{type_id} = $flagtype-&gt;id;
+        delete $self-&gt;{type};
+        $success = 1;
+        last;
</ins><span class="cx">     }
</span><ins>+    return $success;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-=pod
</del><ins>+# In case the bug's product/component has changed, clear flags that are
+# no longer valid.
+sub force_cleanup {
+    my ($class, $bug) = @_;
+    my $dbh = Bugzilla-&gt;dbh;
</ins><span class="cx"> 
</span><del>-=over
</del><ins>+    my $flag_ids = $dbh-&gt;selectcol_arrayref(
+        'SELECT DISTINCT flags.id
+           FROM flags
+          INNER JOIN bugs
+                ON flags.bug_id = bugs.bug_id
+           LEFT JOIN flaginclusions AS i
+                ON flags.type_id = i.type_id
+                AND (bugs.product_id = i.product_id OR i.product_id IS NULL)
+                AND (bugs.component_id = i.component_id OR i.component_id IS NULL)
+          WHERE bugs.bug_id = ? AND i.type_id IS NULL',
+         undef, $bug-&gt;id);
</ins><span class="cx"> 
</span><del>-=item C&lt;create($flag, $bug, $attachment, $timestamp)&gt;
</del><ins>+    my @removed = $class-&gt;force_retarget($flag_ids, $bug);
</ins><span class="cx"> 
</span><del>-Creates a flag record in the database.
</del><ins>+    $flag_ids = $dbh-&gt;selectcol_arrayref(
+        'SELECT DISTINCT flags.id
+           FROM flags, bugs, flagexclusions e
+          WHERE bugs.bug_id = ?
+                AND flags.bug_id = bugs.bug_id
+                AND flags.type_id = e.type_id
+                AND (bugs.product_id = e.product_id OR e.product_id IS NULL)
+                AND (bugs.component_id = e.component_id OR e.component_id IS NULL)',
+         undef, $bug-&gt;id);
</ins><span class="cx"> 
</span><del>-=back
</del><ins>+    push(@removed , $class-&gt;force_retarget($flag_ids, $bug));
+    return @removed;
+}
</ins><span class="cx"> 
</span><del>-=cut
-
-sub create {
-    my ($flag, $bug, $attachment, $timestamp) = @_;
</del><ins>+sub force_retarget {
+    my ($class, $flag_ids, $bug) = @_;
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx"> 
</span><del>-    my $attach_id = $attachment ? $attachment-&gt;id : undef;
-    my $requestee_id;
-    # Be careful! At this point, $flag is *NOT* yet an object!
-    $requestee_id = $flag-&gt;{'requestee'}-&gt;id if $flag-&gt;{'requestee'};
-
-    $dbh-&gt;do('INSERT INTO flags (type_id, bug_id, attach_id, requestee_id,
-                                 setter_id, status, creation_date, modification_date)
-              VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
-              undef, ($flag-&gt;{'type'}-&gt;id, $bug-&gt;bug_id,
-                      $attach_id, $requestee_id, $flag-&gt;{'setter'}-&gt;id,
-                      $flag-&gt;{'status'}, $timestamp, $timestamp));
-
-    # Now that the new flag has been added to the DB, create a real flag object.
-    # This is required to call notify() correctly.
-    my $flag_id = $dbh-&gt;bz_last_key('flags', 'id');
-    $flag = new Bugzilla::Flag($flag_id);
-
-    # Send an email notifying the relevant parties about the flag creation.
-    if ($flag-&gt;requestee &amp;&amp; $flag-&gt;requestee-&gt;wants_mail([EVT_FLAG_REQUESTED])) {
-        $flag-&gt;{'addressee'} = $flag-&gt;requestee;
</del><ins>+    my $flags = $class-&gt;new_from_list($flag_ids);
+    my @removed;
+    foreach my $flag (@$flags) {
+        # $bug is undefined when e.g. editing inclusion and exclusion lists.
+        my $obj = $flag-&gt;attachment || $bug || $flag-&gt;bug;
+        my $is_retargetted = $flag-&gt;retarget($obj);
+        if ($is_retargetted) {
+            $dbh-&gt;do('UPDATE flags SET type_id = ? WHERE id = ?',
+                     undef, ($flag-&gt;type_id, $flag-&gt;id));
+        }
+        else {
+            # Track deleted attachment flags.
+            push(@removed, $class-&gt;snapshot([$flag])) if $flag-&gt;attach_id;
+            $class-&gt;notify(undef, $flag, $bug || $flag-&gt;bug);
+            $flag-&gt;remove_from_db();
+        }
</ins><span class="cx">     }
</span><del>-
-    notify($flag, $bug, $attachment);
-
-    # Return the new flag object.
-    return $flag;
</del><ins>+    return @removed;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-=pod
</del><ins>+###############################
+####      Validators     ######
+###############################
</ins><span class="cx"> 
</span><del>-=over
</del><ins>+sub _set_requestee {
+    my ($self, $requestee, $attachment, $skip_requestee_on_error) = @_;
</ins><span class="cx"> 
</span><del>-=item C&lt;modify($bug, $attachment, $cgi, $timestamp)&gt;
</del><ins>+    $self-&gt;{requestee} =
+      $self-&gt;_check_requestee($requestee, $attachment, $skip_requestee_on_error);
</ins><span class="cx"> 
</span><del>-Modifies flags in the database when a user changes them.
</del><ins>+    $self-&gt;{requestee_id} =
+      $self-&gt;{requestee} ? $self-&gt;{requestee}-&gt;id : undef;
+}
</ins><span class="cx"> 
</span><del>-=back
</del><ins>+sub _set_setter {
+    my ($self, $setter) = @_;
</ins><span class="cx"> 
</span><del>-=cut
</del><ins>+    $self-&gt;set('setter', $setter);
+    $self-&gt;{setter_id} = $self-&gt;setter-&gt;id;
+}
</ins><span class="cx"> 
</span><del>-sub modify {
-    my ($bug, $attachment, $cgi, $timestamp) = @_;
-    my $setter = Bugzilla-&gt;user;
-    my $dbh = Bugzilla-&gt;dbh;
</del><ins>+sub _set_status {
+    my ($self, $status) = @_;
</ins><span class="cx"> 
</span><del>-    # Extract a list of flags from the form data.
-    my @ids = map(/^flag-(\d+)$/ ? $1 : (), $cgi-&gt;param());
</del><ins>+    # Store the old flag status. It's needed by _check_setter().
+    $self-&gt;{_old_status} = $self-&gt;status;
+    $self-&gt;set('status', $status);
+}
</ins><span class="cx"> 
</span><del>-    # Loop over flags and update their record in the database if necessary.
-    # Two kinds of changes can happen to a flag: it can be set to a different
-    # state, and someone else can be asked to set it.  We take care of both
-    # those changes.
-    my @flags;
-    foreach my $id (@ids) {
-        my $flag = new Bugzilla::Flag($id);
-        # If the flag no longer exists, ignore it.
-        next unless $flag;
</del><ins>+sub _check_requestee {
+    my ($self, $requestee, $attachment, $skip_requestee_on_error) = @_;
</ins><span class="cx"> 
</span><del>-        my $status = $cgi-&gt;param(&quot;flag-$id&quot;);
</del><ins>+    # If the flag status is not &quot;?&quot;, then no requestee can be defined.
+    return undef if ($self-&gt;status ne '?');
</ins><span class="cx"> 
</span><del>-        # If the user entered more than one name into the requestee field
-        # (i.e. they want more than one person to set the flag) we can reuse
-        # the existing flag for the first person (who may well be the existing
-        # requestee), but we have to create new flags for each additional.
-        my @requestees = $cgi-&gt;param(&quot;requestee-$id&quot;);
-        my $requestee_email;
-        if ($status eq &quot;?&quot;
-            &amp;&amp; scalar(@requestees) &gt; 1
-            &amp;&amp; $flag-&gt;type-&gt;is_multiplicable)
-        {
-            # The first person, for which we'll reuse the existing flag.
-            $requestee_email = shift(@requestees);
</del><ins>+    # Store this value before updating the flag object.
+    my $old_requestee = $self-&gt;requestee ? $self-&gt;requestee-&gt;login : '';
</ins><span class="cx"> 
</span><del>-            # Create new flags like the existing one for each additional person.
-            foreach my $login (@requestees) {
-                create({ type      =&gt; $flag-&gt;type,
-                         setter    =&gt; $setter, 
-                         status    =&gt; &quot;?&quot;,
-                         requestee =&gt; new Bugzilla::User({ name =&gt; $login }) },
-                       $bug, $attachment, $timestamp);
-            }
-        }
-        else {
-            $requestee_email = trim($cgi-&gt;param(&quot;requestee-$id&quot;) || '');
-        }
</del><ins>+    if ($self-&gt;status eq '?' &amp;&amp; $requestee) {
+        $requestee = Bugzilla::User-&gt;check($requestee);
+    }
+    else {
+        undef $requestee;
+    }
</ins><span class="cx"> 
</span><del>-        # Ignore flags the user didn't change. There are two components here:
-        # either the status changes (trivial) or the requestee changes.
-        # Change of either field will cause full update of the flag.
</del><ins>+    if ($requestee &amp;&amp; $requestee-&gt;login ne $old_requestee) {
+        # Make sure the user didn't specify a requestee unless the flag
+        # is specifically requestable. For existing flags, if the requestee
+        # was set before the flag became specifically unrequestable, the
+        # user can either remove him or leave him alone.
+        ThrowCodeError('flag_requestee_disabled', { type =&gt; $self-&gt;type })
+          if !$self-&gt;type-&gt;is_requesteeble;
</ins><span class="cx"> 
</span><del>-        my $status_changed = ($status ne $flag-&gt;status);
-
-        # Requestee is considered changed, if all of the following apply:
-        # 1. Flag status is '?' (requested)
-        # 2. Flag can have a requestee
-        # 3. The requestee specified on the form is different from the 
-        #    requestee specified in the db.
-
-        my $old_requestee = $flag-&gt;requestee ? $flag-&gt;requestee-&gt;login : '';
-
-        my $requestee_changed = 
-          ($status eq &quot;?&quot; &amp;&amp; 
-           $flag-&gt;type-&gt;is_requesteeble &amp;&amp;
-           $old_requestee ne $requestee_email);
-
-        next unless ($status_changed || $requestee_changed);
-
-        # Since the status is validated, we know it's safe, but it's still
-        # tainted, so we have to detaint it before using it in a query.
-        trick_taint($status);
-
-        if ($status eq '+' || $status eq '-') {
-            $dbh-&gt;do('UPDATE flags
-                         SET setter_id = ?, requestee_id = NULL,
-                             status = ?, modification_date = ?
-                       WHERE id = ?',
-                       undef, ($setter-&gt;id, $status, $timestamp, $flag-&gt;id));
-
-            # If the status of the flag was &quot;?&quot;, we have to notify
-            # the requester (if he wants to).
-            my $requester;
-            if ($flag-&gt;status eq '?') {
-                $requester = $flag-&gt;setter;
-                $flag-&gt;{'requester'} = $requester;
</del><ins>+        # Make sure the requestee can see the bug.
+        # Note that can_see_bug() will query the DB, so if the bug
+        # is being added/removed from some groups and these changes
+        # haven't been committed to the DB yet, they won't be taken
+        # into account here. In this case, old restrictions matters.
+        if (!$requestee-&gt;can_see_bug($self-&gt;bug_id)) {
+            if ($skip_requestee_on_error) {
+                undef $requestee;
</ins><span class="cx">             }
</span><del>-            # Now update the flag object with its new values.
-            $flag-&gt;{'setter'} = $setter;
-            $flag-&gt;{'requestee'} = undef;
-            $flag-&gt;{'requestee_id'} = undef;
-            $flag-&gt;{'status'} = $status;
-
-            # Send an email notifying the relevant parties about the fulfillment,
-            # including the requester.
-            if ($requester &amp;&amp; $requester-&gt;wants_mail([EVT_REQUESTED_FLAG])) {
-                $flag-&gt;{'addressee'} = $requester;
</del><ins>+            else {
+                ThrowUserError('flag_requestee_unauthorized',
+                               { flag_type  =&gt; $self-&gt;type,
+                                 requestee  =&gt; $requestee,
+                                 bug_id     =&gt; $self-&gt;bug_id,
+                                 attach_id  =&gt; $self-&gt;attach_id });
</ins><span class="cx">             }
</span><del>-
-            notify($flag, $bug, $attachment);
</del><span class="cx">         }
</span><del>-        elsif ($status eq '?') {
-            # If the one doing the change is the requestee, then this means he doesn't
-            # want to reply to the request and he simply reassigns the request to
-            # someone else. In this case, we keep the requester unaltered.
-            my $new_setter = $setter;
-            if ($flag-&gt;requestee &amp;&amp; $flag-&gt;requestee-&gt;id == $setter-&gt;id) {
-                $new_setter = $flag-&gt;setter;
</del><ins>+        # Make sure the requestee can see the private attachment.
+        elsif ($self-&gt;attach_id &amp;&amp; $attachment-&gt;isprivate &amp;&amp; !$requestee-&gt;is_insider) {
+            if ($skip_requestee_on_error) {
+                undef $requestee;
</ins><span class="cx">             }
</span><del>-
-            # Get the requestee, if any.
-            my $requestee_id;
-            if ($requestee_email) {
-                $requestee_id = login_to_id($requestee_email);
-                $flag-&gt;{'requestee'} = new Bugzilla::User($requestee_id);
-                $flag-&gt;{'requestee_id'} = $requestee_id;
-            }
</del><span class="cx">             else {
</span><del>-                # If the status didn't change but we only removed the
-                # requestee, we have to clear the requestee field.
-                $flag-&gt;{'requestee'} = undef;
-                $flag-&gt;{'requestee_id'} = undef;
</del><ins>+                ThrowUserError('flag_requestee_unauthorized_attachment',
+                               { flag_type  =&gt; $self-&gt;type,
+                                 requestee  =&gt; $requestee,
+                                 bug_id     =&gt; $self-&gt;bug_id,
+                                 attach_id  =&gt; $self-&gt;attach_id });
</ins><span class="cx">             }
</span><del>-
-            # Update the database with the changes.
-            $dbh-&gt;do('UPDATE flags
-                         SET setter_id = ?, requestee_id = ?,
-                             status = ?, modification_date = ?
-                       WHERE id = ?',
-                       undef, ($new_setter-&gt;id, $requestee_id, $status,
-                               $timestamp, $flag-&gt;id));
-
-            # Now update the flag object with its new values.
-            $flag-&gt;{'setter'} = $new_setter;
-            $flag-&gt;{'status'} = $status;
-
-            # Send an email notifying the relevant parties about the request.
-            if ($flag-&gt;requestee &amp;&amp; $flag-&gt;requestee-&gt;wants_mail([EVT_FLAG_REQUESTED])) {
-                $flag-&gt;{'addressee'} = $flag-&gt;requestee;
</del><ins>+        }
+        # Make sure the user is allowed to set the flag.
+        elsif (!$requestee-&gt;can_set_flag($self-&gt;type)) {
+            if ($skip_requestee_on_error) {
+                undef $requestee;
</ins><span class="cx">             }
</span><del>-
-            notify($flag, $bug, $attachment);
</del><ins>+            else {
+                ThrowUserError('flag_requestee_needs_privs',
+                               {'requestee' =&gt; $requestee,
+                                'flagtype'  =&gt; $self-&gt;type});
+            }
</ins><span class="cx">         }
</span><del>-        elsif ($status eq 'X') {
-            clear($flag, $bug, $attachment);
-        }
-
-        push(@flags, $flag);
</del><span class="cx">     }
</span><del>-
-    return \@flags;
</del><ins>+    return $requestee;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-=pod
</del><ins>+sub _check_setter {
+    my ($self, $setter) = @_;
</ins><span class="cx"> 
</span><del>-=over
</del><ins>+    # By default, the currently logged in user is the setter.
+    $setter ||= Bugzilla-&gt;user;
+    (blessed($setter) &amp;&amp; $setter-&gt;isa('Bugzilla::User') &amp;&amp; $setter-&gt;id)
+      || ThrowCodeError('invalid_user');
</ins><span class="cx"> 
</span><del>-=item C&lt;retarget($flag, $bug)&gt;
</del><ins>+    # set_status() has already been called. So this refers
+    # to the new flag status.
+    my $status = $self-&gt;status;
</ins><span class="cx"> 
</span><del>-Change the type of the flag, if possible. The new flag type must have
-the same name as the current flag type, must exist in the product and
-component the bug is in, and the current settings of the flag must pass
-validation. If no such flag type can be found, the type remains unchanged.
</del><ins>+    # Make sure the user is authorized to modify flags, see bug 180879:
+    # - The flag exists and is unchanged.
+    # - The flag setter can unset flag.
+    # - Users in the request_group can clear pending requests and set flags
+    #   and can rerequest set flags.
+    # - Users in the grant_group can set/clear flags, including &quot;+&quot; and &quot;-&quot;.
+    unless (($status eq $self-&gt;{_old_status})
+            || ($status eq 'X' &amp;&amp; $setter-&gt;id == Bugzilla-&gt;user-&gt;id)
+            || (($status eq 'X' || $status eq '?')
+                &amp;&amp; $setter-&gt;can_request_flag($self-&gt;type))
+            || $setter-&gt;can_set_flag($self-&gt;type))
+    {
+        ThrowUserError('flag_update_denied',
+                        { name       =&gt; $self-&gt;type-&gt;name,
+                          status     =&gt; $status,
+                          old_status =&gt; $self-&gt;{_old_status} });
+    }
</ins><span class="cx"> 
</span><del>-Retargetting flags is a good way to keep flags when moving bugs from one
-product where a flag type is available to another product where the flag
-type is unavailable, but another flag type having the same name exists.
-Most of the time, if they have the same name, this means that they have
-the same meaning, but with different settings.
</del><ins>+    # If the request is being retargetted, we don't update
+    # the setter, so that the setter gets the notification.
+    if ($status eq '?' &amp;&amp; $self-&gt;{_old_status} eq '?') {
+        return $self-&gt;setter;
+    }
+    return $setter;
+}
</ins><span class="cx"> 
</span><del>-=back
</del><ins>+sub _check_status {
+    my ($self, $status) = @_;
</ins><span class="cx"> 
</span><del>-=cut
-
-sub retarget {
-    my ($flag, $bug) = @_;
-    my $dbh = Bugzilla-&gt;dbh;
-
-    # We are looking for flagtypes having the same name as the flagtype
-    # to which the current flag belongs, and being in the new product and
-    # component of the bug.
-    my $flagtypes = Bugzilla::FlagType::match(
-                        {'name'         =&gt; $flag-&gt;name,
-                         'target_type'  =&gt; $flag-&gt;type-&gt;target_type,
-                         'is_active'    =&gt; 1,
-                         'product_id'   =&gt; $bug-&gt;product_id,
-                         'component_id' =&gt; $bug-&gt;component_id});
-
-    # If we found no flagtype, the flag will be deleted.
-    return 0 unless scalar(@$flagtypes);
-
-    # If we found at least one, change the type of the flag,
-    # assuming the setter/requester is allowed to set/request flags
-    # belonging to this flagtype.
-    my $requestee = $flag-&gt;requestee ? [$flag-&gt;requestee-&gt;login] : [];
-    my $is_private = ($flag-&gt;attachment) ? $flag-&gt;attachment-&gt;isprivate : 0;
-    my $is_retargetted = 0;
-
-    foreach my $flagtype (@$flagtypes) {
-        # Get the number of flags of this type already set for this target.
-        my $has_flags = __PACKAGE__-&gt;count(
-            { 'type_id'     =&gt; $flagtype-&gt;id,
-              'bug_id'      =&gt; $bug-&gt;bug_id,
-              'attach_id'   =&gt; $flag-&gt;attach_id });
-
-        # Do not create a new flag of this type if this flag type is
-        # not multiplicable and already has a flag set.
-        next if (!$flagtype-&gt;is_multiplicable &amp;&amp; $has_flags);
-
-        # Check user privileges.
-        my $error_mode_cache = Bugzilla-&gt;error_mode;
-        Bugzilla-&gt;error_mode(ERROR_MODE_DIE);
-        eval {
-            _validate(undef, $flagtype, $flag-&gt;status, $flag-&gt;setter,
-                      $requestee, $is_private, $bug-&gt;bug_id, $flag-&gt;attach_id);
-        };
-        Bugzilla-&gt;error_mode($error_mode_cache);
-        # If the validation failed, then we cannot use this flagtype.
-        next if ($@);
-
-        # Checks are successful, we can retarget the flag to this flagtype.
-        $dbh-&gt;do('UPDATE flags SET type_id = ? WHERE id = ?',
-                  undef, ($flagtype-&gt;id, $flag-&gt;id));
-
-        $is_retargetted = 1;
-        last;
</del><ins>+    # - Make sure the status is valid.
+    # - Make sure the user didn't request the flag unless it's requestable.
+    #   If the flag existed and was requested before it became unrequestable,
+    #   leave it as is.
+    if (!grep($status eq $_ , qw(X + - ?))
+        || ($status eq '?' &amp;&amp; $self-&gt;status ne '?' &amp;&amp; !$self-&gt;type-&gt;is_requestable))
+    {
+        ThrowUserError('flag_status_invalid', { id     =&gt; $self-&gt;id,
+                                                status =&gt; $status });
</ins><span class="cx">     }
</span><del>-    return $is_retargetted;
</del><ins>+    return $status;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+######################################################################
+# Utility Functions
+######################################################################
+
</ins><span class="cx"> =pod
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><del>-=item C&lt;clear($flag, $bug, $attachment)&gt;
</del><ins>+=item C&lt;extract_flags_from_cgi($bug, $attachment, $hr_vars)&gt;
</ins><span class="cx"> 
</span><del>-Remove a flag from the DB.
</del><ins>+Checks whether or not there are new flags to create and returns an
+array of hashes. This array is then passed to Flag::create().
</ins><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><span class="cx"> =cut
</span><span class="cx"> 
</span><del>-sub clear {
-    my ($flag, $bug, $attachment) = @_;
-    my $dbh = Bugzilla-&gt;dbh;
</del><ins>+sub extract_flags_from_cgi {
+    my ($class, $bug, $attachment, $vars, $skip) = @_;
+    my $cgi = Bugzilla-&gt;cgi;
</ins><span class="cx"> 
</span><del>-    $dbh-&gt;do('DELETE FROM flags WHERE id = ?', undef, $flag-&gt;id);
</del><ins>+    my $match_status = Bugzilla::User::match_field({
+        '^requestee(_type)?-(\d+)$' =&gt; { 'type' =&gt; 'multi' },
+    }, undef, $skip);
</ins><span class="cx"> 
</span><del>-    # If we cancel a pending request, we have to notify the requester
-    # (if he wants to).
-    my $requester;
-    if ($flag-&gt;status eq '?') {
-        $requester = $flag-&gt;setter;
-        $flag-&gt;{'requester'} = $requester;
</del><ins>+    $vars-&gt;{'match_field'} = 'requestee';
+    if ($match_status == USER_MATCH_FAILED) {
+        $vars-&gt;{'message'} = 'user_match_failed';
</ins><span class="cx">     }
</span><del>-
-    # Now update the flag object to its new values. The last
-    # requester/setter and requestee are kept untouched (for the
-    # record). Else we could as well delete the flag completely.
-    $flag-&gt;{'exists'} = 0;    
-    $flag-&gt;{'status'} = &quot;X&quot;;
-
-    if ($requester &amp;&amp; $requester-&gt;wants_mail([EVT_REQUESTED_FLAG])) {
-        $flag-&gt;{'addressee'} = $requester;
</del><ins>+    elsif ($match_status == USER_MATCH_MULTIPLE) {
+        $vars-&gt;{'message'} = 'user_match_multiple';
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    notify($flag, $bug, $attachment);
-}
</del><ins>+    # Extract a list of flag type IDs from field names.
+    my @flagtype_ids = map(/^flag_type-(\d+)$/ ? $1 : (), $cgi-&gt;param());
+    @flagtype_ids = grep($cgi-&gt;param(&quot;flag_type-$_&quot;) ne 'X', @flagtype_ids);
</ins><span class="cx"> 
</span><ins>+    # Extract a list of existing flag IDs.
+    my @flag_ids = map(/^flag-(\d+)$/ ? $1 : (), $cgi-&gt;param());
</ins><span class="cx"> 
</span><del>-######################################################################
-# Utility Functions
-######################################################################
</del><ins>+    return () if (!scalar(@flagtype_ids) &amp;&amp; !scalar(@flag_ids));
</ins><span class="cx"> 
</span><del>-=pod
</del><ins>+    my (@new_flags, @flags);
+    foreach my $flag_id (@flag_ids) {
+        my $flag = $class-&gt;new($flag_id);
+        # If the flag no longer exists, ignore it.
+        next unless $flag;
</ins><span class="cx"> 
</span><del>-=over
</del><ins>+        my $status = $cgi-&gt;param(&quot;flag-$flag_id&quot;);
</ins><span class="cx"> 
</span><del>-=item C&lt;FormToNewFlags($bug, $attachment, $cgi, $hr_vars)&gt;
</del><ins>+        # If the user entered more than one name into the requestee field
+        # (i.e. they want more than one person to set the flag) we can reuse
+        # the existing flag for the first person (who may well be the existing
+        # requestee), but we have to create new flags for each additional requestee.
+        my @requestees = $cgi-&gt;param(&quot;requestee-$flag_id&quot;);
+        my $requestee_email;
+        if ($status eq &quot;?&quot;
+            &amp;&amp; scalar(@requestees) &gt; 1
+            &amp;&amp; $flag-&gt;type-&gt;is_multiplicable)
+        {
+            # The first person, for which we'll reuse the existing flag.
+            $requestee_email = shift(@requestees);
</ins><span class="cx"> 
</span><del>-Checks whether or not there are new flags to create and returns an
-array of flag objects. This array is then passed to Flag::create().
</del><ins>+            # Create new flags like the existing one for each additional person.
+            foreach my $login (@requestees) {
+                push(@new_flags, { type_id   =&gt; $flag-&gt;type_id,
+                                   status    =&gt; &quot;?&quot;,
+                                   requestee =&gt; $login,
+                                   skip_roe  =&gt; $skip });
+            }
+        }
+        elsif ($status eq &quot;?&quot; &amp;&amp; scalar(@requestees)) {
+            # If there are several requestees and the flag type is not multiplicable,
+            # this will fail. But that's the job of the validator to complain. All
+            # we do here is to extract and convert data from the CGI.
+            $requestee_email = trim($cgi-&gt;param(&quot;requestee-$flag_id&quot;) || '');
+        }
</ins><span class="cx"> 
</span><del>-=back
</del><ins>+        push(@flags, { id        =&gt; $flag_id,
+                       status    =&gt; $status,
+                       requestee =&gt; $requestee_email,
+                       skip_roe  =&gt; $skip });
+    }
</ins><span class="cx"> 
</span><del>-=cut
-
-sub FormToNewFlags {
-    my ($bug, $attachment, $cgi, $hr_vars) = @_;
-    my $dbh = Bugzilla-&gt;dbh;
-    my $setter = Bugzilla-&gt;user;
-    
-    # Extract a list of flag type IDs from field names.
-    my @type_ids = map(/^flag_type-(\d+)$/ ? $1 : (), $cgi-&gt;param());
-    @type_ids = grep($cgi-&gt;param(&quot;flag_type-$_&quot;) ne 'X', @type_ids);
-
-    return () unless scalar(@type_ids);
-
</del><span class="cx">     # Get a list of active flag types available for this product/component.
</span><span class="cx">     my $flag_types = Bugzilla::FlagType::match(
</span><span class="cx">         { 'product_id'   =&gt; $bug-&gt;{'product_id'},
</span><span class="cx">           'component_id' =&gt; $bug-&gt;{'component_id'},
</span><span class="cx">           'is_active'    =&gt; 1 });
</span><span class="cx"> 
</span><del>-    foreach my $type_id (@type_ids) {
</del><ins>+    foreach my $flagtype_id (@flagtype_ids) {
</ins><span class="cx">         # Checks if there are unexpected flags for the product/component.
</span><del>-        if (!scalar(grep { $_-&gt;id == $type_id } @$flag_types)) {
-            $hr_vars-&gt;{'message'} = 'unexpected_flag_types';
</del><ins>+        if (!scalar(grep { $_-&gt;id == $flagtype_id } @$flag_types)) {
+            $vars-&gt;{'message'} = 'unexpected_flag_types';
</ins><span class="cx">             last;
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    my @flags;
</del><span class="cx">     foreach my $flag_type (@$flag_types) {
</span><span class="cx">         my $type_id = $flag_type-&gt;id;
</span><span class="cx"> 
</span><span class="lines">@@ -1016,10 +855,10 @@
</span><span class="cx">         next unless ($flag_type-&gt;target_type eq 'bug' xor $attachment);
</span><span class="cx"> 
</span><span class="cx">         # We are only interested in flags the user tries to create.
</span><del>-        next unless scalar(grep { $_ == $type_id } @type_ids);
</del><ins>+        next unless scalar(grep { $_ == $type_id } @flagtype_ids);
</ins><span class="cx"> 
</span><span class="cx">         # Get the number of flags of this type already set for this target.
</span><del>-        my $has_flags = __PACKAGE__-&gt;count(
</del><ins>+        my $has_flags = $class-&gt;count(
</ins><span class="cx">             { 'type_id'     =&gt; $type_id,
</span><span class="cx">               'target_type' =&gt; $attachment ? 'attachment' : 'bug',
</span><span class="cx">               'bug_id'      =&gt; $bug-&gt;bug_id,
</span><span class="lines">@@ -1033,32 +872,30 @@
</span><span class="cx">         trick_taint($status);
</span><span class="cx"> 
</span><span class="cx">         my @logins = $cgi-&gt;param(&quot;requestee_type-$type_id&quot;);
</span><del>-        if ($status eq &quot;?&quot; &amp;&amp; scalar(@logins) &gt; 0) {
</del><ins>+        if ($status eq &quot;?&quot; &amp;&amp; scalar(@logins)) {
</ins><span class="cx">             foreach my $login (@logins) {
</span><del>-                push (@flags, { type      =&gt; $flag_type ,
-                                setter    =&gt; $setter , 
-                                status    =&gt; $status ,
-                                requestee =&gt; 
-                                    new Bugzilla::User({ name =&gt; $login }) });
</del><ins>+                push (@new_flags, { type_id   =&gt; $type_id,
+                                    status    =&gt; $status,
+                                    requestee =&gt; $login,
+                                    skip_roe  =&gt; $skip });
</ins><span class="cx">                 last unless $flag_type-&gt;is_multiplicable;
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">         else {
</span><del>-            push (@flags, { type   =&gt; $flag_type ,
-                            setter =&gt; $setter , 
-                            status =&gt; $status });
</del><ins>+            push (@new_flags, { type_id =&gt; $type_id,
+                                status  =&gt; $status });
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    # Return the list of flags.
-    return \@flags;
</del><ins>+    # Return the list of flags to update and/or to create.
+    return (\@flags, \@new_flags);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> =pod
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><del>-=item C&lt;notify($flag, $bug, $attachment)&gt;
</del><ins>+=item C&lt;notify($flag, $old_flag, $object, $timestamp)&gt;
</ins><span class="cx"> 
</span><span class="cx"> Sends an email notification about a flag being created, fulfilled
</span><span class="cx"> or deleted.
</span><span class="lines">@@ -1068,17 +905,53 @@
</span><span class="cx"> =cut
</span><span class="cx"> 
</span><span class="cx"> sub notify {
</span><del>-    my ($flag, $bug, $attachment) = @_;
</del><ins>+    my ($class, $flag, $old_flag, $obj, $timestamp) = @_;
</ins><span class="cx"> 
</span><ins>+    my ($bug, $attachment);
+    if (blessed($obj) &amp;&amp; $obj-&gt;isa('Bugzilla::Attachment')) {
+        $attachment = $obj;
+        $bug = $attachment-&gt;bug;
+    }
+    elsif (blessed($obj) &amp;&amp; $obj-&gt;isa('Bugzilla::Bug')) {
+        $bug = $obj;
+    }
+    else {
+        # Not a good time to throw an error.
+        return;
+    }
+
+    my $addressee;
+    # If the flag is set to '?', maybe the requestee wants a notification.
+    if ($flag &amp;&amp; $flag-&gt;requestee_id
+        &amp;&amp; (!$old_flag || ($old_flag-&gt;requestee_id || 0) != $flag-&gt;requestee_id))
+    {
+        if ($flag-&gt;requestee-&gt;wants_mail([EVT_FLAG_REQUESTED])) {
+            $addressee = $flag-&gt;requestee;
+        }
+    }
+    elsif ($old_flag &amp;&amp; $old_flag-&gt;status eq '?'
+           &amp;&amp; (!$flag || $flag-&gt;status ne '?'))
+    {
+        if ($old_flag-&gt;setter-&gt;wants_mail([EVT_REQUESTED_FLAG])) {
+            $addressee = $old_flag-&gt;setter;
+        }
+    }
+
</ins><span class="cx">     #if WEBKIT_CHANGES
</span><span class="cx">     # Don't send a notification when the flag is in-rietveld,
</span><span class="cx">     # since it isn't a user visible flag, and that mail is spammy.
</span><span class="cx">     return if ($flag-&gt;type-&gt;name eq 'in-rietveld');
</span><span class="cx">     #endif // WEBKIT_CHANGES
</span><span class="cx"> 
</span><del>-    # There is nobody to notify.
-    return unless ($flag-&gt;{'addressee'} || $flag-&gt;type-&gt;cc_list);
</del><ins>+    my $cc_list = $flag ? $flag-&gt;type-&gt;cc_list : $old_flag-&gt;type-&gt;cc_list;
+    # Is there someone to notify?
+    return unless ($addressee || $cc_list);
</ins><span class="cx"> 
</span><ins>+    # The email client will display the Date: header in the desired timezone,
+    # so we can always use UTC here.
+    $timestamp ||= Bugzilla-&gt;dbh-&gt;selectrow_array('SELECT LOCALTIMESTAMP(0)');
+    $timestamp = format_time($timestamp, '%a, %d %b %Y %T %z', 'UTC');
+
</ins><span class="cx">     # If the target bug is restricted to one or more groups, then we need
</span><span class="cx">     # to make sure we don't send email about it to unauthorized users
</span><span class="cx">     # on the request type's CC: list, so we have to trawl the list for users
</span><span class="lines">@@ -1087,7 +960,7 @@
</span><span class="cx">     my $attachment_is_private = $attachment ? $attachment-&gt;isprivate : undef;
</span><span class="cx"> 
</span><span class="cx">     my %recipients;
</span><del>-    foreach my $cc (split(/[, ]+/, $flag-&gt;type-&gt;cc_list)) {
</del><ins>+    foreach my $cc (split(/[, ]+/, $cc_list)) {
</ins><span class="cx">         my $ccuser = new Bugzilla::User({ name =&gt; $cc });
</span><span class="cx">         next if (scalar(@bug_in_groups) &amp;&amp; (!$ccuser || !$ccuser-&gt;can_see_bug($bug-&gt;bug_id)));
</span><span class="cx">         next if $attachment_is_private &amp;&amp; (!$ccuser || !$ccuser-&gt;is_insider);
</span><span class="lines">@@ -1097,72 +970,80 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # Only notify if the addressee is allowed to receive the email.
</span><del>-    if ($flag-&gt;{'addressee'} &amp;&amp; $flag-&gt;{'addressee'}-&gt;email_enabled) {
-        $recipients{$flag-&gt;{'addressee'}-&gt;email} = $flag-&gt;{'addressee'};
</del><ins>+    if ($addressee &amp;&amp; $addressee-&gt;email_enabled) {
+        $recipients{$addressee-&gt;email} = $addressee;
</ins><span class="cx">     }
</span><span class="cx">     # Process and send notification for each recipient.
</span><span class="cx">     # If there are users in the CC list who don't have an account,
</span><span class="cx">     # use the default language for email notifications.
</span><span class="cx">     my $default_lang;
</span><span class="cx">     if (grep { !$_ } values %recipients) {
</span><del>-        my $default_user = new Bugzilla::User();
-        $default_lang = $default_user-&gt;settings-&gt;{'lang'}-&gt;{'value'};
</del><ins>+        $default_lang = Bugzilla::User-&gt;new()-&gt;setting('lang');
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     foreach my $to (keys %recipients) {
</span><span class="cx">         # Add threadingmarker to allow flag notification emails to be the
</span><span class="cx">         # threaded similar to normal bug change emails.
</span><del>-        my $user_id = $recipients{$to} ? $recipients{$to}-&gt;id : 0;
-        my $threadingmarker = build_thread_marker($bug-&gt;id, $user_id);
-    
</del><ins>+        my $thread_user_id = $recipients{$to} ? $recipients{$to}-&gt;id : 0;
+
</ins><span class="cx">         my $vars = { 'flag'            =&gt; $flag,
</span><ins>+                     'old_flag'        =&gt; $old_flag,
</ins><span class="cx">                      'to'              =&gt; $to,
</span><ins>+                     'date'            =&gt; $timestamp,
</ins><span class="cx">                      'bug'             =&gt; $bug,
</span><span class="cx">                      'attachment'      =&gt; $attachment,
</span><del>-                     'threadingmarker' =&gt; $threadingmarker };
</del><ins>+                     'threadingmarker' =&gt; build_thread_marker($bug-&gt;id, $thread_user_id) };
</ins><span class="cx"> 
</span><span class="cx">         my $lang = $recipients{$to} ?
</span><del>-          $recipients{$to}-&gt;settings-&gt;{'lang'}-&gt;{'value'} : $default_lang;
</del><ins>+          $recipients{$to}-&gt;setting('lang') : $default_lang;
</ins><span class="cx"> 
</span><span class="cx">         my $template = Bugzilla-&gt;template_inner($lang);
</span><span class="cx">         my $message;
</span><span class="cx">         $template-&gt;process(&quot;request/email.txt.tmpl&quot;, $vars, \$message)
</span><span class="cx">           || ThrowTemplateError($template-&gt;error());
</span><span class="cx"> 
</span><del>-        Bugzilla-&gt;template_inner(&quot;&quot;);
</del><span class="cx">         MessageToMTA($message);
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-# Cancel all request flags from the attachment being obsoleted.
-sub CancelRequests {
-    my ($class, $bug, $attachment, $timestamp) = @_;
-    my $dbh = Bugzilla-&gt;dbh;
</del><ins>+# This is an internal function used by $bug-&gt;flag_types
+# and $attachment-&gt;flag_types to collect data about available
+# flag types and existing flags set on them. You should never
+# call this function directly.
+sub _flag_types {
+    my ($class, $vars) = @_;
</ins><span class="cx"> 
</span><del>-    my $request_ids =
-        $dbh-&gt;selectcol_arrayref(&quot;SELECT flags.id
-                                  FROM flags
-                                  LEFT JOIN attachments ON flags.attach_id = attachments.attach_id
-                                  WHERE flags.attach_id = ?
-                                  AND flags.status = '?'
-                                  AND attachments.isobsolete = 0&quot;,
-                                  undef, $attachment-&gt;id);
</del><ins>+    my $target_type = $vars-&gt;{target_type};
+    my $flags;
</ins><span class="cx"> 
</span><del>-    return if (!scalar(@$request_ids));
</del><ins>+    # Retrieve all existing flags for this bug/attachment.
+    if ($target_type eq 'bug') {
+        my $bug_id = delete $vars-&gt;{bug_id};
+        $flags = $class-&gt;match({target_type =&gt; 'bug', bug_id =&gt; $bug_id});
+    }
+    elsif ($target_type eq 'attachment') {
+        my $attach_id = delete $vars-&gt;{attach_id};
+        $flags = $class-&gt;match({attach_id =&gt; $attach_id});
+    }
+    else {
+        ThrowCodeError('bad_arg', {argument =&gt; 'target_type',
+                                   function =&gt; $class . '-&gt;_flag_types'});
+    }
</ins><span class="cx"> 
</span><del>-    # Take a snapshot of flags before any changes.
-    my @old_summaries = $class-&gt;snapshot($bug-&gt;bug_id, $attachment-&gt;id)
-        if ($timestamp);
-    my $flags = Bugzilla::Flag-&gt;new_from_list($request_ids);
-    foreach my $flag (@$flags) { clear($flag, $bug, $attachment) }
</del><ins>+    # Get all available flag types for the given product and component.
+    my $cache = Bugzilla-&gt;request_cache-&gt;{flag_types_per_component}-&gt;{$vars-&gt;{target_type}} ||= {};
+    my $flag_data = $cache-&gt;{$vars-&gt;{component_id}} ||= Bugzilla::FlagType::match($vars);
+    my $flag_types = dclone($flag_data);
</ins><span class="cx"> 
</span><del>-    # If $timestamp is undefined, do not update the activity table
-    return unless ($timestamp);
</del><ins>+    $_-&gt;{flags} = [] foreach @$flag_types;
+    my %flagtypes = map { $_-&gt;id =&gt; $_ } @$flag_types;
</ins><span class="cx"> 
</span><del>-    # Take a snapshot of flags after any changes.
-    my @new_summaries = $class-&gt;snapshot($bug-&gt;bug_id, $attachment-&gt;id);
-    update_activity($bug-&gt;bug_id, $attachment-&gt;id, $timestamp,
-                    \@old_summaries, \@new_summaries);
</del><ins>+    # Group existing flags per type, and skip those becoming invalid
+    # (which can happen when a bug is being moved into a new product
+    # or component).
+    @$flags = grep { exists $flagtypes{$_-&gt;type_id} } @$flags;
+    push(@{$flagtypes{$_-&gt;type_id}-&gt;{flags}}, $_) foreach @$flags;
+    return $flag_types;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> =head1 SEE ALSO
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaFlagTypepm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/FlagType.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/FlagType.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/FlagType.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -48,7 +48,7 @@
</span><span class="cx"> 
</span><span class="cx"> =cut
</span><span class="cx"> 
</span><del>-use Bugzilla::User;
</del><ins>+use Bugzilla::Constants;
</ins><span class="cx"> use Bugzilla::Error;
</span><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> use Bugzilla::Group;
</span><span class="lines">@@ -59,58 +59,152 @@
</span><span class="cx"> ####    Initialization     ####
</span><span class="cx"> ###############################
</span><span class="cx"> 
</span><del>-=begin private
</del><ins>+use constant DB_TABLE =&gt; 'flagtypes';
+use constant LIST_ORDER =&gt; 'sortkey, name';
</ins><span class="cx"> 
</span><del>-=head1 PRIVATE VARIABLES/CONSTANTS
</del><ins>+use constant DB_COLUMNS =&gt; qw(
+    id
+    name
+    description
+    cc_list
+    target_type
+    sortkey
+    is_active
+    is_requestable
+    is_requesteeble
+    is_multiplicable
+    grant_group_id
+    request_group_id
+);
</ins><span class="cx"> 
</span><del>-=over
</del><ins>+use constant UPDATE_COLUMNS =&gt; qw(
+    name
+    description
+    cc_list
+    sortkey
+    is_active
+    is_requestable
+    is_requesteeble
+    is_multiplicable
+    grant_group_id
+    request_group_id
+);
</ins><span class="cx"> 
</span><del>-=item C&lt;DB_COLUMNS&gt;
</del><ins>+use constant VALIDATORS =&gt; {
+    name             =&gt; \&amp;_check_name,
+    description      =&gt; \&amp;_check_description,
+    cc_list          =&gt; \&amp;_check_cc_list,
+    target_type      =&gt; \&amp;_check_target_type,
+    sortkey          =&gt; \&amp;_check_sortey,
+    is_active        =&gt; \&amp;Bugzilla::Object::check_boolean,
+    is_requestable   =&gt; \&amp;Bugzilla::Object::check_boolean,
+    is_requesteeble  =&gt; \&amp;Bugzilla::Object::check_boolean,
+    is_multiplicable =&gt; \&amp;Bugzilla::Object::check_boolean,
+    grant_group      =&gt; \&amp;_check_group,
+    request_group    =&gt; \&amp;_check_group,
+};
</ins><span class="cx"> 
</span><del>-basic sets of columns and tables for getting flag types from the
-database.
</del><ins>+use constant UPDATE_VALIDATORS =&gt; {
+    grant_group_id   =&gt; \&amp;_check_group,
+    request_group_id =&gt; \&amp;_check_group,
+};
+###############################
</ins><span class="cx"> 
</span><del>-=back
</del><ins>+sub create {
+    my $class = shift;
+    my $dbh = Bugzilla-&gt;dbh;
</ins><span class="cx"> 
</span><del>-=cut
</del><ins>+    $dbh-&gt;bz_start_transaction();
</ins><span class="cx"> 
</span><del>-use constant DB_COLUMNS =&gt; qw(
-    flagtypes.id
-    flagtypes.name
-    flagtypes.description
-    flagtypes.cc_list
-    flagtypes.target_type
-    flagtypes.sortkey
-    flagtypes.is_active
-    flagtypes.is_requestable
-    flagtypes.is_requesteeble
-    flagtypes.is_multiplicable
-    flagtypes.grant_group_id
-    flagtypes.request_group_id
-);
</del><ins>+    $class-&gt;check_required_create_fields(@_);
+    my $params = $class-&gt;run_create_validators(@_);
+    # In the DB, only the first character of the target type is stored.
+    $params-&gt;{target_type} = substr($params-&gt;{target_type}, 0, 1);
</ins><span class="cx"> 
</span><del>-=pod
</del><ins>+    # Extract everything which is not a valid column name.
+    $params-&gt;{grant_group_id} = delete $params-&gt;{grant_group};
+    $params-&gt;{request_group_id} = delete $params-&gt;{request_group};
+    my $inclusions = delete $params-&gt;{inclusions};
+    my $exclusions = delete $params-&gt;{exclusions};
</ins><span class="cx"> 
</span><del>-=over
</del><ins>+    my $flagtype = $class-&gt;insert_create_data($params);
</ins><span class="cx"> 
</span><del>-=item C&lt;DB_TABLE&gt;
</del><ins>+    $flagtype-&gt;set_clusions({ inclusions =&gt; $inclusions,
+                              exclusions =&gt; $exclusions });
+    $flagtype-&gt;update();
</ins><span class="cx"> 
</span><del>-Which database(s) is the data coming from?
</del><ins>+    $dbh-&gt;bz_commit_transaction();
+    return $flagtype;
+}
</ins><span class="cx"> 
</span><del>-Note: when adding tables to DB_TABLE, make sure to include the separator
-(i.e. words like &quot;LEFT OUTER JOIN&quot;) before the table name, since tables take
-multiple separators based on the join type, and therefore it is not possible
-to join them later using a single known separator.
</del><ins>+sub update {
+    my $self = shift;
+    my $dbh = Bugzilla-&gt;dbh;
+    my $flag_id = $self-&gt;id;
</ins><span class="cx"> 
</span><del>-=back
</del><ins>+    $dbh-&gt;bz_start_transaction();
+    my $changes = $self-&gt;SUPER::update(@_);
</ins><span class="cx"> 
</span><del>-=end private
</del><ins>+    # Update the flaginclusions and flagexclusions tables.
+    foreach my $category ('inclusions', 'exclusions') {
+        next unless delete $self-&gt;{&quot;_update_$category&quot;};
</ins><span class="cx"> 
</span><del>-=cut
</del><ins>+        $dbh-&gt;do(&quot;DELETE FROM flag$category WHERE type_id = ?&quot;, undef, $flag_id);
</ins><span class="cx"> 
</span><del>-use constant DB_TABLE =&gt; 'flagtypes';
-use constant LIST_ORDER =&gt; 'flagtypes.sortkey, flagtypes.name';
</del><ins>+        my $sth = $dbh-&gt;prepare(&quot;INSERT INTO flag$category
+                                (type_id, product_id, component_id) VALUES (?, ?, ?)&quot;);
</ins><span class="cx"> 
</span><ins>+        foreach my $prod_comp (values %{$self-&gt;{$category}}) {
+            my ($prod_id, $comp_id) = split(':', $prod_comp);
+            $prod_id ||= undef;
+            $comp_id ||= undef;
+            $sth-&gt;execute($flag_id, $prod_id, $comp_id);
+        }
+        $changes-&gt;{$category} = [0, 1];
+    }
+
+    # Clear existing flags for bugs/attachments in categories no longer on
+    # the list of inclusions or that have been added to the list of exclusions.
+    my $flag_ids = $dbh-&gt;selectcol_arrayref('SELECT DISTINCT flags.id
+                                               FROM flags
+                                         INNER JOIN bugs
+                                                 ON flags.bug_id = bugs.bug_id
+                                          LEFT JOIN flaginclusions AS i
+                                                 ON (flags.type_id = i.type_id
+                                                     AND (bugs.product_id = i.product_id
+                                                          OR i.product_id IS NULL)
+                                                     AND (bugs.component_id = i.component_id
+                                                          OR i.component_id IS NULL))
+                                              WHERE flags.type_id = ?
+                                                AND i.type_id IS NULL',
+                                             undef, $self-&gt;id);
+    Bugzilla::Flag-&gt;force_retarget($flag_ids);
+
+    $flag_ids = $dbh-&gt;selectcol_arrayref('SELECT DISTINCT flags.id
+                                            FROM flags
+                                      INNER JOIN bugs
+                                              ON flags.bug_id = bugs.bug_id
+                                      INNER JOIN flagexclusions AS e
+                                              ON flags.type_id = e.type_id
+                                           WHERE flags.type_id = ?
+                                             AND (bugs.product_id = e.product_id
+                                                  OR e.product_id IS NULL)
+                                             AND (bugs.component_id = e.component_id
+                                                  OR e.component_id IS NULL)',
+                                          undef, $self-&gt;id);
+    Bugzilla::Flag-&gt;force_retarget($flag_ids);
+
+    # Silently remove requestees from flags which are no longer
+    # specifically requestable.
+    if (!$self-&gt;is_requesteeble) {
+        $dbh-&gt;do('UPDATE flags SET requestee_id = NULL WHERE type_id = ?',
+                  undef, $self-&gt;id);
+    }
+
+    $dbh-&gt;bz_commit_transaction();
+    return $changes;
+}
+
</ins><span class="cx"> ###############################
</span><span class="cx"> ####      Accessors      ######
</span><span class="cx"> ###############################
</span><span class="lines">@@ -180,10 +274,151 @@
</span><span class="cx"> sub request_group_id { return $_[0]-&gt;{'request_group_id'}; }
</span><span class="cx"> sub grant_group_id   { return $_[0]-&gt;{'grant_group_id'};   }
</span><span class="cx"> 
</span><ins>+################################
+# Validators
+################################
+
+sub _check_name {
+    my ($invocant, $name) = @_;
+
+    $name = trim($name);
+    ($name &amp;&amp; $name !~ /[\s,]/ &amp;&amp; length($name) &lt;= 50)
+      || ThrowUserError('flag_type_name_invalid', { name =&gt; $name });
+    return $name;
+}
+
+sub _check_description {
+    my ($invocant, $desc) = @_;
+
+    $desc = trim($desc);
+    $desc || ThrowUserError('flag_type_description_invalid');
+    return $desc;
+}
+
+sub _check_cc_list {
+    my ($invocant, $cc_list) = @_;
+
+    length($cc_list) &lt;= 200
+      || ThrowUserError('flag_type_cc_list_invalid', { cc_list =&gt; $cc_list });
+
+    my @addresses = split(/[,\s]+/, $cc_list);
+    # We do not call Util::validate_email_syntax because these
+    # addresses do not require to match 'emailregexp' and do not
+    # depend on 'emailsuffix'. So we limit ourselves to a simple
+    # sanity check:
+    # - match the syntax of a fully qualified email address;
+    # - do not contain any illegal character.
+    foreach my $address (@addresses) {
+        ($address =~ /^[\w\.\+\-=]+@[\w\.\-]+\.[\w\-]+$/
+           &amp;&amp; $address !~ /[\\\(\)&lt;&gt;&amp;,;:&quot;\[\] \t\r\n\P{ASCII}]/)
+          || ThrowUserError('illegal_email_address',
+                            {addr =&gt; $address, default =&gt; 1});
+    }
+    return $cc_list;
+}
+
+sub _check_target_type {
+    my ($invocant, $target_type) = @_;
+
+    ($target_type eq 'bug' || $target_type eq 'attachment')
+      || ThrowCodeError('flag_type_target_type_invalid', { target_type =&gt; $target_type });
+    return $target_type;
+}
+
+sub _check_sortey {
+    my ($invocant, $sortkey) = @_;
+
+    (detaint_natural($sortkey) &amp;&amp; $sortkey &lt;= MAX_SMALLINT)
+      || ThrowUserError('flag_type_sortkey_invalid', { sortkey =&gt; $sortkey });
+    return $sortkey;
+}
+
+sub _check_group {
+    my ($invocant, $group) = @_;
+    return unless $group;
+
+    trick_taint($group);
+    $group = Bugzilla::Group-&gt;check($group);
+    return $group-&gt;id;
+}
+
</ins><span class="cx"> ###############################
</span><span class="cx"> ####       Methods         ####
</span><span class="cx"> ###############################
</span><span class="cx"> 
</span><ins>+sub set_name             { $_[0]-&gt;set('name', $_[1]); }
+sub set_description      { $_[0]-&gt;set('description', $_[1]); }
+sub set_cc_list          { $_[0]-&gt;set('cc_list', $_[1]); }
+sub set_sortkey          { $_[0]-&gt;set('sortkey', $_[1]); }
+sub set_is_active        { $_[0]-&gt;set('is_active', $_[1]); }
+sub set_is_requestable   { $_[0]-&gt;set('is_requestable', $_[1]); }
+sub set_is_specifically_requestable { $_[0]-&gt;set('is_requesteeble', $_[1]); }
+sub set_is_multiplicable { $_[0]-&gt;set('is_multiplicable', $_[1]); }
+sub set_grant_group      { $_[0]-&gt;set('grant_group_id', $_[1]); }
+sub set_request_group    { $_[0]-&gt;set('request_group_id', $_[1]); }
+
+sub set_clusions {
+    my ($self, $list) = @_;
+    my $user = Bugzilla-&gt;user;
+    my %products;
+    my $params = {};
+
+    # If the user has editcomponents privs, then we only need to make sure
+    # that the product exists.
+    if ($user-&gt;in_group('editcomponents')) {
+        $params-&gt;{allow_inaccessible} = 1;
+    }
+
+    foreach my $category (keys %$list) {
+        my %clusions;
+        my %clusions_as_hash;
+
+        foreach my $prod_comp (@{$list-&gt;{$category} || []}) {
+            my ($prod_id, $comp_id) = split(':', $prod_comp);
+            my $prod_name = '__Any__';
+            my $comp_name = '__Any__';
+            # Does the product exist?
+            if ($prod_id) {
+                detaint_natural($prod_id)
+                  || ThrowCodeError('param_must_be_numeric',
+                                    { function =&gt; 'Bugzilla::FlagType::set_clusions' });
+
+                if (!$products{$prod_id}) {
+                    $params-&gt;{id} = $prod_id;
+                    $products{$prod_id} = Bugzilla::Product-&gt;check($params);
+                    $user-&gt;in_group('editcomponents', $prod_id)
+                      || ThrowUserError('product_access_denied', $params);
+                }
+                $prod_name = $products{$prod_id}-&gt;name;
+
+                # Does the component belong to this product?
+                if ($comp_id) {
+                    detaint_natural($comp_id)
+                      || ThrowCodeError('param_must_be_numeric',
+                                        { function =&gt; 'Bugzilla::FlagType::set_clusions' });
+
+                    my ($component) = grep { $_-&gt;id == $comp_id } @{$products{$prod_id}-&gt;components}
+                                        or ThrowUserError('product_unknown_component',
+                                                          { product =&gt; $prod_name, comp_id =&gt; $comp_id });
+                    $comp_name = $component-&gt;name;
+                }
+                else {
+                    $comp_id = 0;
+                }
+            }
+            else {
+                $prod_id = 0;
+                $comp_id = 0;
+            }
+            $clusions{&quot;$prod_name:$comp_name&quot;} = &quot;$prod_id:$comp_id&quot;;
+            $clusions_as_hash{$prod_id}-&gt;{$comp_id} = 1;
+        }
+        $self-&gt;{$category} = \%clusions;
+        $self-&gt;{&quot;${category}_as_hash&quot;} = \%clusions_as_hash;
+        $self-&gt;{&quot;_update_$category&quot;} = 1;
+    }
+}
+
</ins><span class="cx"> =pod
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="lines">@@ -223,6 +458,7 @@
</span><span class="cx"> 
</span><span class="cx"> sub grant_list {
</span><span class="cx">     my $self = shift;
</span><ins>+    require Bugzilla::User;
</ins><span class="cx">     my @custusers;
</span><span class="cx">     my @allusers = @{Bugzilla-&gt;user-&gt;get_userlist};
</span><span class="cx">     foreach my $user (@allusers) {
</span><span class="lines">@@ -264,17 +500,35 @@
</span><span class="cx"> sub inclusions {
</span><span class="cx">     my $self = shift;
</span><span class="cx"> 
</span><del>-    $self-&gt;{'inclusions'} ||= get_clusions($self-&gt;id, 'in');
-    return $self-&gt;{'inclusions'};
</del><ins>+    if (!defined $self-&gt;{inclusions}) {
+        ($self-&gt;{inclusions}, $self-&gt;{inclusions_as_hash}) = get_clusions($self-&gt;id, 'in');
+    }
+    return $self-&gt;{inclusions};
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub inclusions_as_hash {
+    my $self = shift;
+
+    $self-&gt;inclusions unless defined $self-&gt;{inclusions_as_hash};
+    return $self-&gt;{inclusions_as_hash};
+}
+
</ins><span class="cx"> sub exclusions {
</span><span class="cx">     my $self = shift;
</span><span class="cx"> 
</span><del>-    $self-&gt;{'exclusions'} ||= get_clusions($self-&gt;id, 'ex');
-    return $self-&gt;{'exclusions'};
</del><ins>+    if (!defined $self-&gt;{exclusions}) {
+        ($self-&gt;{exclusions}, $self-&gt;{exclusions_as_hash}) = get_clusions($self-&gt;id, 'ex');
+    }
+    return $self-&gt;{exclusions};
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub exclusions_as_hash {
+    my $self = shift;
+
+    $self-&gt;exclusions unless defined $self-&gt;{exclusions_as_hash};
+    return $self-&gt;{exclusions_as_hash};
+}
+
</ins><span class="cx"> ######################################################################
</span><span class="cx"> # Public Functions
</span><span class="cx"> ######################################################################
</span><span class="lines">@@ -300,17 +554,18 @@
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx"> 
</span><span class="cx">     my $list =
</span><del>-        $dbh-&gt;selectall_arrayref(&quot;SELECT products.id, products.name, &quot; .
-                                 &quot;       components.id, components.name &quot; . 
-                                 &quot;FROM flagtypes, flag${type}clusions &quot; . 
-                                 &quot;LEFT OUTER JOIN products &quot; .
-                                 &quot;  ON flag${type}clusions.product_id = products.id &quot; . 
-                                 &quot;LEFT OUTER JOIN components &quot; .
-                                 &quot;  ON flag${type}clusions.component_id = components.id &quot; . 
-                                 &quot;WHERE flagtypes.id = ? &quot; .
-                                 &quot; AND flag${type}clusions.type_id = flagtypes.id&quot;,
</del><ins>+        $dbh-&gt;selectall_arrayref(&quot;SELECT products.id, products.name,
+                                         components.id, components.name
+                                    FROM flagtypes
+                              INNER JOIN flag${type}clusions
+                                      ON flag${type}clusions.type_id = flagtypes.id
+                               LEFT JOIN products
+                                      ON flag${type}clusions.product_id = products.id
+                               LEFT JOIN components
+                                      ON flag${type}clusions.component_id = components.id
+                                   WHERE flagtypes.id = ?&quot;,
</ins><span class="cx">                                  undef, $id);
</span><del>-    my %clusions;
</del><ins>+    my (%clusions, %clusions_as_hash);
</ins><span class="cx">     foreach my $data (@$list) {
</span><span class="cx">         my ($product_id, $product_name, $component_id, $component_name) = @$data;
</span><span class="cx">         $product_id ||= 0;
</span><span class="lines">@@ -318,8 +573,9 @@
</span><span class="cx">         $component_id ||= 0;
</span><span class="cx">         $component_name ||= &quot;__Any__&quot;;
</span><span class="cx">         $clusions{&quot;$product_name:$component_name&quot;} = &quot;$product_id:$component_id&quot;;
</span><ins>+        $clusions_as_hash{$product_id}-&gt;{$component_id} = 1;
</ins><span class="cx">     }
</span><del>-    return \%clusions;
</del><ins>+    return (\%clusions, \%clusions_as_hash);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> =pod
</span><span class="lines">@@ -423,15 +679,13 @@
</span><span class="cx">         my $is_active = $criteria-&gt;{is_active} ? &quot;1&quot; : &quot;0&quot;;
</span><span class="cx">         push(@criteria, &quot;flagtypes.is_active = $is_active&quot;);
</span><span class="cx">     }
</span><del>-    if ($criteria-&gt;{product_id} &amp;&amp; $criteria-&gt;{'component_id'}) {
</del><ins>+    if ($criteria-&gt;{product_id}) {
</ins><span class="cx">         my $product_id = $criteria-&gt;{product_id};
</span><del>-        my $component_id = $criteria-&gt;{component_id};
</del><span class="cx">         
</span><span class="cx">         # Add inclusions to the query, which simply involves joining the table
</span><span class="cx">         # by flag type ID and target product/component.
</span><span class="cx">         push(@$tables, &quot;INNER JOIN flaginclusions AS i ON flagtypes.id = i.type_id&quot;);
</span><span class="cx">         push(@criteria, &quot;(i.product_id = $product_id OR i.product_id IS NULL)&quot;);
</span><del>-        push(@criteria, &quot;(i.component_id = $component_id OR i.component_id IS NULL)&quot;);
</del><span class="cx">         
</span><span class="cx">         # Add exclusions to the query, which is more complicated.  First of all,
</span><span class="cx">         # we do a LEFT JOIN so we don't miss flag types with no exclusions.
</span><span class="lines">@@ -439,9 +693,19 @@
</span><span class="cx">         # component.  However, since we want flag types that *aren't* on the
</span><span class="cx">         # exclusions list, we add a WHERE criteria to use only records with
</span><span class="cx">         # NULL exclusion type, i.e. without any exclusions.
</span><del>-        my $join_clause = &quot;flagtypes.id = e.type_id &quot; .
-                          &quot;AND (e.product_id = $product_id OR e.product_id IS NULL) &quot; .
-                          &quot;AND (e.component_id = $component_id OR e.component_id IS NULL)&quot;;
</del><ins>+        my $join_clause = &quot;flagtypes.id = e.type_id &quot;;
+
+        my $addl_join_clause = &quot;&quot;;
+        if ($criteria-&gt;{component_id}) {
+            my $component_id = $criteria-&gt;{component_id};
+            push(@criteria, &quot;(i.component_id = $component_id OR i.component_id IS NULL)&quot;);
+            $join_clause .= &quot;AND (e.component_id = $component_id OR e.component_id IS NULL) &quot;;
+        }
+        else {
+            $addl_join_clause = &quot;AND e.component_id IS NULL OR (i.component_id = e.component_id) &quot;;
+        }
+        $join_clause .= &quot;AND ((e.product_id = $product_id $addl_join_clause) OR e.product_id IS NULL)&quot;;
+
</ins><span class="cx">         push(@$tables, &quot;LEFT JOIN flagexclusions AS e ON ($join_clause)&quot;);
</span><span class="cx">         push(@criteria, &quot;e.type_id IS NULL&quot;);
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaGrouppm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Group.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Group.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Group.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -60,8 +60,6 @@
</span><span class="cx">     icon_url    =&gt; \&amp;_check_icon_url,
</span><span class="cx"> };
</span><span class="cx"> 
</span><del>-use constant REQUIRED_CREATE_FIELDS =&gt; qw(name description isbuggroup);
-
</del><span class="cx"> use constant UPDATE_COLUMNS =&gt; qw(
</span><span class="cx">     name
</span><span class="cx">     description
</span><span class="lines">@@ -84,26 +82,54 @@
</span><span class="cx"> sub is_active    { return $_[0]-&gt;{'isactive'};     }
</span><span class="cx"> sub icon_url     { return $_[0]-&gt;{'icon_url'};     }
</span><span class="cx"> 
</span><ins>+sub bugs {
+    my $self = shift;
+    return $self-&gt;{bugs} if exists $self-&gt;{bugs};
+    my $bug_ids = Bugzilla-&gt;dbh-&gt;selectcol_arrayref(
+        'SELECT bug_id FROM bug_group_map WHERE group_id = ?',
+        undef, $self-&gt;id);
+    require Bugzilla::Bug;
+    $self-&gt;{bugs} = Bugzilla::Bug-&gt;new_from_list($bug_ids);
+    return $self-&gt;{bugs};
+}
+
</ins><span class="cx"> sub members_direct {
</span><span class="cx">     my ($self) = @_;
</span><del>-    return $self-&gt;{members_direct} if defined $self-&gt;{members_direct};
</del><ins>+    $self-&gt;{members_direct} ||= $self-&gt;_get_members(GRANT_DIRECT);
+    return $self-&gt;{members_direct};
+}
+
+sub members_non_inherited {
+    my ($self) = @_;
+    $self-&gt;{members_non_inherited} ||= $self-&gt;_get_members();
+    return $self-&gt;{members_non_inherited};
+}
+
+# A helper for members_direct and members_non_inherited
+sub _get_members {
+    my ($self, $grant_type) = @_;
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><ins>+    my $grant_clause = $grant_type ? &quot;AND grant_type = $grant_type&quot; : &quot;&quot;;
</ins><span class="cx">     my $user_ids = $dbh-&gt;selectcol_arrayref(
</span><del>-        &quot;SELECT user_group_map.user_id
</del><ins>+        &quot;SELECT DISTINCT user_id
</ins><span class="cx">            FROM user_group_map
</span><del>-          WHERE user_group_map.group_id = ?
-                AND grant_type = &quot; . GRANT_DIRECT . &quot;
-                AND isbless = 0&quot;, undef, $self-&gt;id);
</del><ins>+          WHERE isbless = 0 $grant_clause AND group_id = ?&quot;, undef, $self-&gt;id);
</ins><span class="cx">     require Bugzilla::User;
</span><del>-    $self-&gt;{members_direct} = Bugzilla::User-&gt;new_from_list($user_ids);
-    return $self-&gt;{members_direct};
</del><ins>+    return Bugzilla::User-&gt;new_from_list($user_ids);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub flag_types {
+    my $self = shift;
+    require Bugzilla::FlagType;
+    $self-&gt;{flag_types} ||= Bugzilla::FlagType::match({ group =&gt; $self-&gt;id });
+    return $self-&gt;{flag_types};
+}
+
</ins><span class="cx"> sub grant_direct {
</span><span class="cx">     my ($self, $type) = @_;
</span><span class="cx">     $self-&gt;{grant_direct} ||= {};
</span><span class="cx">     return $self-&gt;{grant_direct}-&gt;{$type} 
</span><del>-        if defined $self-&gt;{members_direct}-&gt;{$type};
</del><ins>+        if defined $self-&gt;{grant_direct}-&gt;{$type};
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx"> 
</span><span class="cx">     my $ids = $dbh-&gt;selectcol_arrayref(
</span><span class="lines">@@ -131,10 +157,44 @@
</span><span class="cx">     return $self-&gt;{granted_by_direct}-&gt;{$type};
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub products {
+    my $self = shift;
+    return $self-&gt;{products} if exists $self-&gt;{products};
+    my $product_data = Bugzilla-&gt;dbh-&gt;selectall_arrayref(
+        'SELECT product_id, entry, membercontrol, othercontrol,
+                canedit, editcomponents, editbugs, canconfirm
+          FROM  group_control_map WHERE group_id = ?', {Slice=&gt;{}},
+        $self-&gt;id);
+    my @ids = map { $_-&gt;{product_id} } @$product_data;
+    require Bugzilla::Product;
+    my $products = Bugzilla::Product-&gt;new_from_list(\@ids); 
+    my %data_map = map { $_-&gt;{product_id} =&gt; $_ } @$product_data;
+    my @retval;
+    foreach my $product (@$products) {
+        # Data doesn't need to contain product_id--we already have
+        # the product object.
+        delete $data_map{$product-&gt;id}-&gt;{product_id};
+        push(@retval, { controls =&gt; $data_map{$product-&gt;id},
+                        product  =&gt; $product });
+    }
+    $self-&gt;{products} = \@retval;
+    return $self-&gt;{products};
+}
+
</ins><span class="cx"> ###############################
</span><span class="cx"> ####        Methods        ####
</span><span class="cx"> ###############################
</span><span class="cx"> 
</span><ins>+sub check_members_are_visible {
+    my $self = shift;
+    my $user = Bugzilla-&gt;user;
+    return if !Bugzilla-&gt;params-&gt;{'usevisibilitygroups'};
+    my $is_visible = grep { $_-&gt;id == $_ } @{ $user-&gt;visible_groups_inherited };
+    if (!$is_visible) {
+        ThrowUserError('group_not_visible', { group =&gt; $self });
+    }
+}
+
</ins><span class="cx"> sub set_description { $_[0]-&gt;set('description', $_[1]); }
</span><span class="cx"> sub set_is_active   { $_[0]-&gt;set('isactive', $_[1]);    }
</span><span class="cx"> sub set_name        { $_[0]-&gt;set('name', $_[1]);        }
</span><span class="lines">@@ -143,6 +203,8 @@
</span><span class="cx"> 
</span><span class="cx"> sub update {
</span><span class="cx">     my $self = shift;
</span><ins>+    my $dbh = Bugzilla-&gt;dbh;
+    $dbh-&gt;bz_start_transaction();
</ins><span class="cx">     my $changes = $self-&gt;SUPER::update(@_);
</span><span class="cx"> 
</span><span class="cx">     if (exists $changes-&gt;{name}) {
</span><span class="lines">@@ -162,9 +224,76 @@
</span><span class="cx">                                   &amp;&amp; $changes-&gt;{isactive}-&gt;[1]);
</span><span class="cx"> 
</span><span class="cx">     $self-&gt;_rederive_regexp() if exists $changes-&gt;{userregexp};
</span><ins>+
+    Bugzilla::Hook::process('group_end_of_update', 
+                            { group =&gt; $self, changes =&gt; $changes });
+    $dbh-&gt;bz_commit_transaction();
</ins><span class="cx">     return $changes;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub check_remove {
+    my ($self, $params) = @_;
+
+    # System groups cannot be deleted!
+    if (!$self-&gt;is_bug_group) {
+        ThrowUserError(&quot;system_group_not_deletable&quot;, { name =&gt; $self-&gt;name });
+    }
+
+    # Groups having a special role cannot be deleted.
+    my @special_groups;
+    foreach my $special_group (GROUP_PARAMS) {
+        if ($self-&gt;name eq Bugzilla-&gt;params-&gt;{$special_group}) {
+            push(@special_groups, $special_group);
+        }
+    }
+    if (scalar(@special_groups)) {
+        ThrowUserError('group_has_special_role',
+                       { name   =&gt; $self-&gt;name,
+                         groups =&gt; \@special_groups });
+    }
+
+    return if $params-&gt;{'test_only'};
+
+    my $cantdelete = 0;
+
+    my $users = $self-&gt;members_non_inherited;
+    if (scalar(@$users) &amp;&amp; !$params-&gt;{'remove_from_users'}) {
+        $cantdelete = 1;
+    }
+
+    my $bugs = $self-&gt;bugs;
+    if (scalar(@$bugs) &amp;&amp; !$params-&gt;{'remove_from_bugs'}) {
+        $cantdelete = 1;
+    }
+    
+    my $products = $self-&gt;products;
+    if (scalar(@$products) &amp;&amp; !$params-&gt;{'remove_from_products'}) {
+        $cantdelete = 1;
+    }
+
+    my $flag_types = $self-&gt;flag_types;
+    if (scalar(@$flag_types) &amp;&amp; !$params-&gt;{'remove_from_flags'}) {
+        $cantdelete = 1;
+    }
+
+    ThrowUserError('group_cannot_delete', { group =&gt; $self }) if $cantdelete;
+}
+
+sub remove_from_db {
+    my $self = shift;
+    my $dbh = Bugzilla-&gt;dbh;
+    $self-&gt;check_remove(@_);
+    $dbh-&gt;bz_start_transaction();
+    Bugzilla::Hook::process('group_before_delete', { group =&gt; $self });
+    $dbh-&gt;do('DELETE FROM whine_schedules
+               WHERE mailto_type = ? AND mailto = ?',
+              undef, MAILTO_GROUP, $self-&gt;id);
+    # All the other tables will be handled by foreign keys when we
+    # drop the main &quot;groups&quot; row.
+    $self-&gt;SUPER::remove_from_db(@_);
+    $dbh-&gt;bz_commit_transaction();
+}
+
</ins><span class="cx"> # Add missing entries in bug_group_map for bugs created while
</span><span class="cx"> # a mandatory group was disabled and which is now enabled again.
</span><span class="cx"> sub _enforce_mandatory {
</span><span class="lines">@@ -198,23 +327,59 @@
</span><span class="cx"> 
</span><span class="cx"> sub _rederive_regexp {
</span><span class="cx">     my ($self) = @_;
</span><del>-    RederiveRegexp($self-&gt;user_regexp, $self-&gt;id);
</del><ins>+
+    my $dbh = Bugzilla-&gt;dbh;
+    my $sth = $dbh-&gt;prepare(&quot;SELECT userid, login_name, group_id
+                               FROM profiles
+                          LEFT JOIN user_group_map
+                                 ON user_group_map.user_id = profiles.userid
+                                    AND group_id = ?
+                                    AND grant_type = ?
+                                    AND isbless = 0&quot;);
+    my $sthadd = $dbh-&gt;prepare(&quot;INSERT INTO user_group_map
+                                 (user_id, group_id, grant_type, isbless)
+                                 VALUES (?, ?, ?, 0)&quot;);
+    my $sthdel = $dbh-&gt;prepare(&quot;DELETE FROM user_group_map
+                                 WHERE user_id = ? AND group_id = ?
+                                 AND grant_type = ? and isbless = 0&quot;);
+    $sth-&gt;execute($self-&gt;id, GRANT_REGEXP);
+    my $regexp = $self-&gt;user_regexp;
+    while (my ($uid, $login, $present) = $sth-&gt;fetchrow_array) {
+        if ($regexp ne '' and $login =~ /$regexp/i) {
+            $sthadd-&gt;execute($uid, $self-&gt;id, GRANT_REGEXP) unless $present;
+        } else {
+            $sthdel-&gt;execute($uid, $self-&gt;id, GRANT_REGEXP) if $present;
+        }
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub members_non_inherited {
-    my ($self) = @_;
-    return $self-&gt;{members_non_inherited} 
-           if exists $self-&gt;{members_non_inherited};
</del><ins>+sub flatten_group_membership {
+    my ($self, @groups) = @_;
</ins><span class="cx"> 
</span><del>-    my $member_ids = Bugzilla-&gt;dbh-&gt;selectcol_arrayref(
-        'SELECT DISTINCT user_id FROM user_group_map 
-          WHERE isbless = 0 AND group_id = ?',
-        undef, $self-&gt;id) || [];
-    require Bugzilla::User;
-    $self-&gt;{members_non_inherited} = Bugzilla::User-&gt;new_from_list($member_ids);
-    return $self-&gt;{members_non_inherited};
</del><ins>+    my $dbh = Bugzilla-&gt;dbh;
+    my $sth;
+    my @groupidstocheck = @groups;
+    my %groupidschecked = ();
+    $sth = $dbh-&gt;prepare(&quot;SELECT member_id FROM group_group_map
+                             WHERE grantor_id = ? 
+                               AND grant_type = &quot; . GROUP_MEMBERSHIP);
+    while (my $node = shift @groupidstocheck) {
+        $sth-&gt;execute($node);
+        my $member;
+        while (($member) = $sth-&gt;fetchrow_array) {
+            if (!$groupidschecked{$member}) {
+                $groupidschecked{$member} = 1;
+                push @groupidstocheck, $member;
+                push @groups, $member unless grep $_ == $member, @groups;
+            }
+        }
+    }
+    return \@groups;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+
+
+
</ins><span class="cx"> ################################
</span><span class="cx"> #####  Module Subroutines    ###
</span><span class="cx"> ################################
</span><span class="lines">@@ -224,9 +389,14 @@
</span><span class="cx">     my ($params) = @_;
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx"> 
</span><del>-    print get_text('install_group_create', { name =&gt; $params-&gt;{name} }) . &quot;\n&quot; 
-        if Bugzilla-&gt;usage_mode == USAGE_MODE_CMDLINE;
</del><ins>+    my $silently = delete $params-&gt;{silently};
+    if (Bugzilla-&gt;usage_mode == USAGE_MODE_CMDLINE and !$silently) {
+        print get_text('install_group_create', { name =&gt; $params-&gt;{name} }),
+              &quot;\n&quot;;
+    }
</ins><span class="cx"> 
</span><ins>+    $dbh-&gt;bz_start_transaction();
+
</ins><span class="cx">     my $group = $class-&gt;SUPER::create(@_);
</span><span class="cx"> 
</span><span class="cx">     # Since we created a new group, give the &quot;admin&quot; group all privileges
</span><span class="lines">@@ -244,6 +414,9 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     $group-&gt;_rederive_regexp() if $group-&gt;user_regexp;
</span><ins>+
+    Bugzilla::Hook::process('group_end_of_create', { group =&gt; $group });
+    $dbh-&gt;bz_commit_transaction();
</ins><span class="cx">     return $group;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -266,33 +439,19 @@
</span><span class="cx">     return $ret;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-# This sub is not perldoc'ed because we expect it to go away and
-# just become the _rederive_regexp private method.
-sub RederiveRegexp {
-    my ($regexp, $gid) = @_;
-    my $dbh = Bugzilla-&gt;dbh;
-    my $sth = $dbh-&gt;prepare(&quot;SELECT userid, login_name, group_id
-                               FROM profiles
-                          LEFT JOIN user_group_map
-                                 ON user_group_map.user_id = profiles.userid
-                                AND group_id = ?
-                                AND grant_type = ?
-                                AND isbless = 0&quot;);
-    my $sthadd = $dbh-&gt;prepare(&quot;INSERT INTO user_group_map
-                                 (user_id, group_id, grant_type, isbless)
-                                 VALUES (?, ?, ?, 0)&quot;);
-    my $sthdel = $dbh-&gt;prepare(&quot;DELETE FROM user_group_map
-                                 WHERE user_id = ? AND group_id = ?
-                                 AND grant_type = ? and isbless = 0&quot;);
-    $sth-&gt;execute($gid, GRANT_REGEXP);
-    while (my ($uid, $login, $present) = $sth-&gt;fetchrow_array()) {
-        if (($regexp =~ /\S+/) &amp;&amp; ($login =~ m/$regexp/i))
-        {
-            $sthadd-&gt;execute($uid, $gid, GRANT_REGEXP) unless $present;
-        } else {
-            $sthdel-&gt;execute($uid, $gid, GRANT_REGEXP) if $present;
-        }
-    }
</del><ins>+sub check_no_disclose {
+    my ($class, $params) = @_;
+    my $action = delete $params-&gt;{action};
+
+    $action =~ /^(?:add|remove)$/
+      or ThrowCodeError('bad_arg', { argument =&gt; $action,
+                                     function =&gt; &quot;${class}::check_no_disclose&quot; });
+
+    $params-&gt;{_error} = ($action eq 'add') ? 'group_restriction_not_allowed'
+                                           : 'group_invalid_removal';
+
+    my $group = $class-&gt;check($params);
+    return $group;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ###############################
</span><span class="lines">@@ -304,7 +463,7 @@
</span><span class="cx">     $name = trim($name);
</span><span class="cx">     $name || ThrowUserError(&quot;empty_group_name&quot;);
</span><span class="cx">     # If we're creating a Group or changing the name...
</span><del>-    if (!ref($invocant) || $invocant-&gt;name ne $name) {
</del><ins>+    if (!ref($invocant) || lc($invocant-&gt;name) ne lc($name)) {
</ins><span class="cx">         my $exists = new Bugzilla::Group({name =&gt; $name });
</span><span class="cx">         ThrowUserError(&quot;group_exists&quot;, { name =&gt; $name }) if $exists;
</span><span class="cx">     }
</span><span class="lines">@@ -377,22 +536,116 @@
</span><span class="cx"> 
</span><span class="cx"> =item C&lt;ValidateGroupName($name, @users)&gt;
</span><span class="cx"> 
</span><del>- Description: ValidateGroupName checks to see if ANY of the users
-              in the provided list of user objects can see the
-              named group.
</del><ins>+Description: ValidateGroupName checks to see if ANY of the users
+             in the provided list of user objects can see the
+             named group.
</ins><span class="cx"> 
</span><del>- Params:      $name - String with the group name.
-              @users - An array with Bugzilla::User objects.
</del><ins>+Params:      $name - String with the group name.
+             @users - An array with Bugzilla::User objects.
</ins><span class="cx"> 
</span><del>- Returns:     It returns the group id if successful
-              and undef otherwise.
</del><ins>+Returns:     It returns the group id if successful
+             and undef otherwise.
</ins><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> =head1 METHODS
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><ins>+=item C&lt;check_no_disclose&gt;
+
+=over
+
+=item B&lt;Description&gt;
+
+Throws an error if the user cannot add or remove this group to/from a given
+bug, but doesn't specify if this is because the group doesn't exist, or the
+user is not allowed to edit this group restriction.
+
+=item B&lt;Params&gt;
+
+This method takes a single hashref as argument, with the following keys:
+
+=over
+
+=item C&lt;name&gt;
+
+C&lt;string&gt; The name of the group to add or remove.
+
+=item C&lt;bug_id&gt;
+
+C&lt;integer&gt; The ID of the bug to which the group change applies.
+
+=item C&lt;product&gt;
+
+C&lt;string&gt; The name of the product the bug belongs to.
+
+=item C&lt;action&gt;
+
+C&lt;string&gt; Must be either C&lt;add&gt; or C&lt;remove&gt;, depending on whether the group
+must be added or removed from the bug. Any other value will generate an error.
+
+=back
+
+=item C&lt;Returns&gt;
+
+A C&lt;Bugzilla::Group&gt; object on success, else an error is thrown.
+
+=back
+
+=item C&lt;check_members_are_visible&gt;
+
+Throws an error if this group is not visible (according to 
+visibility groups) to the currently-logged-in user.
+
+=item C&lt;check_remove&gt;
+
+=over
+
+=item B&lt;Description&gt;
+
+Determines whether it's OK to remove this group from the database, and
+throws an error if it's not OK.
+
+=item B&lt;Params&gt;
+
+=over
+
+=item C&lt;test_only&gt;
+
+C&lt;boolean&gt; If you want to only check if the group can be deleted I&lt;at all&gt;,
+under any circumstances, specify C&lt;test_only&gt; to just do the most basic tests
+(the other parameters will be ignored in this situation, as those tests won't
+be run).
+
+=item C&lt;remove_from_users&gt;
+
+C&lt;boolean&gt; True if it would be OK to remove all users who are in this group
+from this group.
+
+=item C&lt;remove_from_bugs&gt;
+
+C&lt;boolean&gt; True if it would be OK to remove all bugs that are in this group
+from this group.
+
+=item C&lt;remove_from_flags&gt;
+
+C&lt;boolean&gt; True if it would be OK to stop all flagtypes that reference
+this group from referencing this group (e.g., as their grantgroup or
+requestgroup).
+
+=item C&lt;remove_from_products&gt;
+
+C&lt;boolean&gt; True if it would be OK to remove this group from all group controls
+on products.
+
+=back
+
+=item B&lt;Returns&gt; (nothing)
+
+=back
+
</ins><span class="cx"> =item C&lt;members_non_inherited&gt;
</span><span class="cx"> 
</span><span class="cx"> Returns an arrayref of L&lt;Bugzilla::User&gt; objects representing people who are
</span><span class="lines">@@ -400,4 +653,12 @@
</span><span class="cx"> the group regular expression, or they have been actually added to the
</span><span class="cx"> group manually.
</span><span class="cx"> 
</span><ins>+=item C&lt;flatten_group_membership&gt;
+
+Accepts a list of groups and returns a list of all the groups whose members 
+inherit membership in any group on the list.  So, we can determine if a user
+is in any of the groups input to flatten_group_membership by querying the
+user_group_map for any user with DIRECT or REGEXP membership IN() the list
+of groups returned.
+
</ins><span class="cx"> =back
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaHookpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Hook.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Hook.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Hook.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -18,65 +18,39 @@
</span><span class="cx"> # Rights Reserved.
</span><span class="cx"> #
</span><span class="cx"> # Contributor(s): Zach Lipton &lt;zach@zachlipton.com&gt;
</span><del>-#
</del><ins>+#                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
</ins><span class="cx"> 
</span><span class="cx"> package Bugzilla::Hook;
</span><del>-
-use Bugzilla::Constants;
-use Bugzilla::Util;
-use Bugzilla::Error;
-
</del><span class="cx"> use strict;
</span><span class="cx"> 
</span><span class="cx"> sub process {
</span><span class="cx">     my ($name, $args) = @_;
</span><del>-    
-    # get a list of all extensions
-    my @extensions = glob(bz_locations()-&gt;{'extensionsdir'} . &quot;/*&quot;);
-    
-    # check each extension to see if it uses the hook
-    # if so, invoke the extension source file:
-    foreach my $extension (@extensions) {
-        # all of these variables come directly from code or directory names. 
-        # If there's malicious data here, we have much bigger issues to 
-        # worry about, so we can safely detaint them:
-        trick_taint($extension);
-        # Skip CVS directories and any hidden files/dirs.
-        next if $extension =~ m{/CVS$} || $extension =~ m{/\.[^/]+$};
-        next if -e &quot;$extension/disabled&quot;;
-        if (-e $extension.'/code/'.$name.'.pl') {
-            Bugzilla-&gt;hook_args($args);
-            # Allow extensions to load their own libraries.
-            local @INC = (&quot;$extension/lib&quot;, @INC);
-            do($extension.'/code/'.$name.'.pl');
-            ThrowCodeError('extension_invalid', 
-                { errstr =&gt; $@, name =&gt; $name, extension =&gt; $extension }) if $@;
-            # Flush stored data.
-            Bugzilla-&gt;hook_args({});
</del><ins>+
+    _entering($name);
+
+    foreach my $extension (@{ Bugzilla-&gt;extensions }) {
+        if ($extension-&gt;can($name)) {
+            $extension-&gt;$name($args);
</ins><span class="cx">         }
</span><span class="cx">     }
</span><ins>+
+    _leaving($name);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub enabled_plugins {
-    my $extdir = bz_locations()-&gt;{'extensionsdir'};
-    my @extensions = glob(&quot;$extdir/*&quot;);
-    my %enabled;
-    foreach my $extension (@extensions) {
-        trick_taint($extension);
-        my $extname = $extension;
-        $extname =~ s{^\Q$extdir\E/}{};
-        next if $extname eq 'CVS' || $extname =~ /^\./;
-        next if -e &quot;$extension/disabled&quot;;
-        # Allow extensions to load their own libraries.
-        local @INC = (&quot;$extension/lib&quot;, @INC);
-        $enabled{$extname} = do(&quot;$extension/info.pl&quot;);
-        ThrowCodeError('extension_invalid',
-                { errstr =&gt; $@, name =&gt; 'version',
-                  extension =&gt; $extension }) if $@;
</del><ins>+sub in {
+    my $hook_name = shift;
+    my $currently_in = Bugzilla-&gt;request_cache-&gt;{hook_stack}-&gt;[-1] || '';
+    return $hook_name eq $currently_in ? 1 : 0;
+}
</ins><span class="cx"> 
</span><del>-    }
</del><ins>+sub _entering {
+    my ($hook_name) = @_;
+    my $hook_stack = Bugzilla-&gt;request_cache-&gt;{hook_stack} ||= [];
+    push(@$hook_stack, $hook_name);
+}
</ins><span class="cx"> 
</span><del>-    return \%enabled;
</del><ins>+sub _leaving {
+    pop @{ Bugzilla-&gt;request_cache-&gt;{hook_stack} };
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> 1;
</span><span class="lines">@@ -101,37 +75,20 @@
</span><span class="cx"> to perform additional functions, it uses Bugzilla::Hook's L&lt;/process&gt;
</span><span class="cx"> subroutine to invoke any extension code if installed. 
</span><span class="cx"> 
</span><del>-There is a sample extension in F&lt;extensions/example/&gt; that demonstrates
-most of the things described in this document, as well as many of the
-hooks available.
</del><ins>+The implementation of extensions is described in L&lt;Bugzilla::Extension&gt;.
</ins><span class="cx"> 
</span><ins>+There is sample code for every hook in the Example extension, located in
+F&lt;extensions/Example/Extension.pm&gt;.
+
</ins><span class="cx"> =head2 How Hooks Work
</span><span class="cx"> 
</span><del>-When a hook named C&lt;HOOK_NAME&gt; is run, Bugzilla will attempt to invoke any 
-source files named F&lt;extensions/*/code/HOOK_NAME.pl&gt;.
</del><ins>+When a hook named C&lt;HOOK_NAME&gt; is run, Bugzilla looks through all
+enabled L&lt;extensions|Bugzilla::Extension&gt; for extensions that implement
+a subroutine named C&lt;HOOK_NAME&gt;.
</ins><span class="cx"> 
</span><del>-So, for example, if your extension is called &quot;testopia&quot;, and you
-want to have code run during the L&lt;/install-update_db&gt; hook, you
-would have a file called F&lt;extensions/testopia/code/install-update_db.pl&gt;
-that contained perl code to run during that hook.
</del><ins>+See L&lt;Bugzilla::Extension&gt; for more details about how an extension
+can run code during a hook.
</ins><span class="cx"> 
</span><del>-=head2 Arguments Passed to Hooks
-
-Some L&lt;hooks|/HOOKS&gt; have params that are passed to them.
-
-These params are accessible through L&lt;Bugzilla/hook_args&gt;.
-That returns a hashref. Very frequently, if you want your
-hook to do anything, you have to modify these variables.
-
-=head2 Versioning Extensions
-
-Every extension must have a file in its root called F&lt;info.pl&gt;.
-This file must return a hash when called with C&lt;do&gt;.
-The hash must contain a 'version' key with the current version of the
-extension. Extension authors can also add any extra infomration to this hash if
-required, by adding a new key beginning with x_ which will not be used the
-core Bugzilla code. 
-
</del><span class="cx"> =head1 SUBROUTINES
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="lines">@@ -144,8 +101,8 @@
</span><span class="cx"> 
</span><span class="cx"> Invoke any code hooks with a matching name from any installed extensions.
</span><span class="cx"> 
</span><del>-See C&lt;customization.xml&gt; in the Bugzilla Guide for more information on
-Bugzilla's extension mechanism.
</del><ins>+See L&lt;Bugzilla::Extension&gt; for more information on Bugzilla's extension
+mechanism.
</ins><span class="cx"> 
</span><span class="cx"> =item B&lt;Params&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -154,7 +111,7 @@
</span><span class="cx"> =item C&lt;$name&gt; - The name of the hook to invoke.
</span><span class="cx"> 
</span><span class="cx"> =item C&lt;$args&gt; - A hashref. The named args to pass to the hook. 
</span><del>-They will be accessible to the hook via L&lt;Bugzilla/hook_args&gt;.
</del><ins>+They will be passed as arguments to the hook method in the extension.
</ins><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><span class="lines">@@ -170,8 +127,137 @@
</span><span class="cx"> in alphabetical order, but some related hooks are near each other instead
</span><span class="cx"> of being alphabetical.
</span><span class="cx"> 
</span><del>-=head2 bug-end_of_update
</del><ins>+=head2 admin_editusers_action
</ins><span class="cx"> 
</span><ins>+This hook allows you to add additional actions to the admin Users page.
+
+Params:
+
+=over
+
+=item C&lt;vars&gt;
+
+You can add as many new key/value pairs as you want to this hashref.
+It will be passed to the template.
+
+=item C&lt;action&gt;
+
+A text which indicates the different behaviors that editusers.cgi will have.
+With this hook you can change the behavior of an action or add new actions.
+
+=item C&lt;user&gt;
+
+This is a Bugzilla::User object of the user.
+
+=back
+
+=head2 attachment_process_data
+
+This happens at the very beginning process of the attachment creation.
+You can edit the attachment content itself as well as all attributes
+of the attachment, before they are validated and inserted into the DB.
+
+Params:
+
+=over
+
+=item C&lt;data&gt; - A reference pointing either to the content of the file
+being uploaded or pointing to the filehandle associated with the file.
+
+=item C&lt;attributes&gt; - A hashref whose keys are the same as the input to
+L&lt;Bugzilla::Attachment/create&gt;. The data in this hashref hasn't been validated
+yet.
+
+=back
+
+=head2 auth_login_methods
+
+This allows you to add new login types to Bugzilla.
+(See L&lt;Bugzilla::Auth::Login&gt;.)
+
+Params:
+
+=over
+
+=item C&lt;modules&gt;
+
+This is a hash--a mapping from login-type &quot;names&quot; to the actual module on
+disk. The keys will be all the values that were passed to 
+L&lt;Bugzilla::Auth/login&gt; for the C&lt;Login&gt; parameter. The values are the
+actual path to the module on disk. (For example, if the key is C&lt;DB&gt;, the
+value is F&lt;Bugzilla/Auth/Login/DB.pm&gt;.)
+
+For your extension, the path will start with 
+F&lt;Bugzilla/Extension/Foo/&gt;, where &quot;Foo&quot; is the name of your Extension. 
+(See the code in the example extension.)
+
+If your login type is in the hash as a key, you should set that key to the
+right path to your module. That module's C&lt;new&gt; method will be called,
+probably with empty parameters. If your login type is I&lt;not&gt; in the hash,
+you should not set it.
+
+You will be prevented from adding new keys to the hash, so make sure your
+key is in there before you modify it. (In other words, you can't add in
+login methods that weren't passed to L&lt;Bugzilla::Auth/login&gt;.)
+
+=back
+
+=head2 auth_verify_methods
+
+This works just like L&lt;/auth_login_methods&gt; except it's for
+login verification methods (See L&lt;Bugzilla::Auth::Verify&gt;.) It also
+takes a C&lt;modules&gt; parameter, just like L&lt;/auth_login_methods&gt;.
+
+=head2 bug_columns
+
+B&lt;DEPRECATED&gt; Use L&lt;/object_columns&gt; instead.
+
+This allows you to add new fields that will show up in every L&lt;Bugzilla::Bug&gt;
+object. Note that you will also need to use the L&lt;/bug_fields&gt; hook in
+conjunction with this hook to make this work.
+
+Params:
+
+=over
+
+=item C&lt;columns&gt; - An arrayref containing an array of column names. Push
+your column name(s) onto the array.
+
+=back
+
+=head2 bug_end_of_create
+
+This happens at the end of L&lt;Bugzilla::Bug/create&gt;, after all other changes are
+made to the database. This occurs inside a database transaction.
+
+Params:
+
+=over
+
+=item C&lt;bug&gt; - The created bug object.
+
+=item C&lt;timestamp&gt; - The timestamp used for all updates in this transaction,
+as a SQL date string.
+
+=back
+
+=head2 bug_end_of_create_validators
+
+This happens during L&lt;Bugzilla::Bug/create&gt;, after all parameters have
+been validated, but before anything has been inserted into the database.
+
+Params:
+
+=over
+
+=item C&lt;params&gt;
+
+A hashref. The validated parameters passed to C&lt;create&gt;.
+
+=back
+
+=head2 bug_end_of_update
+
</ins><span class="cx"> This happens at the end of L&lt;Bugzilla::Bug/update&gt;, after all other changes are
</span><span class="cx"> made to the database. This generally occurs inside a database transaction.
</span><span class="cx"> 
</span><span class="lines">@@ -179,26 +265,179 @@
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><del>-=item C&lt;bug&gt; - The changed bug object, with all fields set to their updated
-values.
</del><ins>+=item C&lt;bug&gt; 
</ins><span class="cx"> 
</span><del>-=item C&lt;timestamp&gt; - The timestamp used for all updates in this transaction.
</del><ins>+The changed bug object, with all fields set to their updated values.
</ins><span class="cx"> 
</span><del>-=item C&lt;changes&gt; - The hash of changed fields. 
-C&lt;$changes-E&lt;gt&gt;{field} = [old, new]&gt;
</del><ins>+=item C&lt;old_bug&gt;
</ins><span class="cx"> 
</span><ins>+A bug object pulled from the database before the fields were set to
+their updated values (so it has the old values available for each field).
+
+=item C&lt;timestamp&gt; 
+
+The timestamp used for all updates in this transaction, as a SQL date
+string.
+
+=item C&lt;changes&gt; 
+
+The hash of changed fields. C&lt;&lt; $changes-&gt;{field} = [old, new] &gt;&gt;
+
</ins><span class="cx"> =back
</span><span class="cx"> 
</span><del>-=head2 buglist-columns
</del><ins>+=head2 bug_check_can_change_field
</ins><span class="cx"> 
</span><del>-This happens in buglist.cgi after the standard columns have been defined and
-right before the display column determination.  It gives you the opportunity
-to add additional display columns.
</del><ins>+This hook controls what fields users are allowed to change. You can add code
+here for site-specific policy changes and other customizations. 
</ins><span class="cx"> 
</span><ins>+This hook is only executed if the field's new and old values differ. 
+
+Any denies take priority over any allows. So, if another extension denies
+a change but yours allows the change, the other extension's deny will
+override your extension's allow.
+
</ins><span class="cx"> Params:
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><ins>+=item C&lt;bug&gt;
+
+L&lt;Bugzilla::Bug&gt; - The current bug object that this field is changing on.
+
+=item C&lt;field&gt;
+
+The name (from the C&lt;fielddefs&gt; table) of the field that we are checking.
+
+=item C&lt;new_value&gt;
+
+The new value that the field is being changed to.
+
+=item C&lt;old_value&gt;
+
+The old value that the field is being changed from.
+
+=item C&lt;priv_results&gt;
+
+C&lt;array&gt; - This is how you explicitly allow or deny a change. You should only
+push something into this array if you want to explicitly allow or explicitly
+deny the change, and thus skip all other permission checks that would otherwise
+happen after this hook is called. If you don't care about the field change,
+then don't push anything into the array.
+
+The pushed value should be a choice from the following constants:
+
+=over
+
+=item C&lt;PRIVILEGES_REQUIRED_NONE&gt;
+
+No privileges required. This explicitly B&lt;allows&gt; a change.
+
+=item C&lt;PRIVILEGES_REQUIRED_REPORTER&gt;
+
+User is not the reporter, assignee or an empowered user, so B&lt;deny&gt;.
+
+=item C&lt;PRIVILEGES_REQUIRED_ASSIGNEE&gt;
+
+User is not the assignee or an empowered user, so B&lt;deny&gt;.
+
+=item C&lt;PRIVILEGES_REQUIRED_EMPOWERED&gt;
+
+User is not a sufficiently empowered user, so B&lt;deny&gt;.
+
+=back
+
+=back
+
+=head2 bug_fields
+
+Allows the addition of database fields from the bugs table to the standard
+list of allowable fields in a L&lt;Bugzilla::Bug&gt; object, so that
+you can call the field as a method.
+
+Note: You should add here the names of any fields you added in L&lt;/bug_columns&gt;.
+
+Params:
+
+=over
+
+=item C&lt;columns&gt; - A arrayref containing an array of column names. Push
+your column name(s) onto the array.
+
+=back
+
+=head2 bug_format_comment
+
+Allows you to do custom parsing on comments before they are displayed. You do
+this by returning two regular expressions: one that matches the section you
+want to replace, and then another that says what you want to replace that
+match with.
+
+The matching and replacement will be run with the C&lt;/g&gt; switch on the regex.
+
+Params:
+
+=over
+
+=item C&lt;regexes&gt;
+
+An arrayref of hashrefs.
+
+You should push a hashref containing two keys (C&lt;match&gt; and C&lt;replace&gt;)
+in to this array. C&lt;match&gt; is the regular expression that matches the
+text you want to replace, C&lt;replace&gt; is what you want to replace that
+text with. (This gets passed into a regular expression like 
+C&lt;s/$match/$replace/&gt;.)
+
+Instead of specifying a regular expression for C&lt;replace&gt; you can also
+return a coderef (a reference to a subroutine). If you want to use
+backreferences (using C&lt;$1&gt;, C&lt;$2&gt;, etc. in your C&lt;replace&gt;), you have to use
+this method--it won't work if you specify C&lt;$1&gt;, C&lt;$2&gt; in a regular expression
+for C&lt;replace&gt;. Your subroutine will get a hashref as its only argument. This
+hashref contains a single key, C&lt;matches&gt;. C&lt;matches&gt; is an arrayref that
+contains C&lt;$1&gt;, C&lt;$2&gt;, C&lt;$3&gt;, etc. in order, up to C&lt;$10&gt;. Your subroutine
+should return what you want to replace the full C&lt;match&gt; with. (See the code
+example for this hook if you want to see how this actually all works in code.
+It's simpler than it sounds.)
+
+B&lt;You are responsible for HTML-escaping your returned data.&gt; Failing to
+do so could open a security hole in Bugzilla.
+
+=item C&lt;text&gt;
+
+A B&lt;reference&gt; to the exact text that you are parsing.
+
+Generally you should not modify this yourself. Instead you should be 
+returning regular expressions using the C&lt;regexes&gt; array.
+
+The text has not been parsed in any way. (So, for example, it is not
+HTML-escaped. You get &quot;&amp;&quot;, not &quot;&amp;amp;&quot;.)
+
+=item C&lt;bug&gt;
+
+The L&lt;Bugzilla::Bug&gt; object that this comment is on. Sometimes this is
+C&lt;undef&gt;, meaning that we are parsing text that is not on a bug.
+
+=item C&lt;comment&gt;
+
+A L&lt;Bugzilla::Comment&gt; object representing the comment you are about to
+parse.
+
+Sometimes this is C&lt;undef&gt;, meaning that we are parsing text that is
+not a bug comment (but could still be some other part of a bug, like
+the summary line).
+
+=back
+
+=head2 buglist_columns
+
+This happens in L&lt;Bugzilla::Search/COLUMNS&gt;, which determines legal bug
+list columns for F&lt;buglist.cgi&gt; and F&lt;colchange.cgi&gt;. It gives you the
+opportunity to add additional display columns.
+
+Params:
+
+=over
+
</ins><span class="cx"> =item C&lt;columns&gt; - A hashref, where the keys are unique string identifiers
</span><span class="cx"> for the column being defined and the values are hashrefs with the
</span><span class="cx"> following fields:
</span><span class="lines">@@ -217,24 +456,227 @@
</span><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><del>-=head2 colchange-columns
</del><ins>+=head2 buglist_column_joins
</ins><span class="cx"> 
</span><del>-This happens in F&lt;colchange.cgi&gt; right after the list of possible display
-columns have been defined and gives you the opportunity to add additional
-display columns to the list of selectable columns.
</del><ins>+This allows you to join additional tables to display additional columns
+in buglists. This hook is generally used in combination with the
+C&lt;buglist_columns&gt; hook.
</ins><span class="cx"> 
</span><span class="cx"> Params:
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><del>-=item C&lt;columns&gt; - An arrayref containing an array of column IDs.  Any IDs
-added by this hook must have been defined in the the buglist-columns hook.
-See L&lt;/buglist-columns&gt;.
</del><ins>+=item C&lt;column_joins&gt; - A hashref containing data to return back to
+L&lt;Bugzilla::Search&gt;. This hashref contains names of the columns as keys and 
+a hashref about table to join as values. This hashref has the following keys:
</ins><span class="cx"> 
</span><ins>+=over
+
+=item C&lt;table&gt; - The name of the additional table to join.
+
+=item C&lt;as&gt; - (optional) The alias used for the additional table. This alias
+must not conflict with an existing alias already used in the query.
+
+=item C&lt;from&gt; - (optional) The name of the column in the C&lt;bugs&gt; table which
+the additional table should be linked to. If omitted, C&lt;bug_id&gt; will be used.
+
+=item C&lt;to&gt; - (optional) The name of the column in the additional table which
+should be linked to the column in the C&lt;bugs&gt; table, see C&lt;from&gt; above.
+If omitted, C&lt;bug_id&gt; will be used.
+
+=item C&lt;join&gt; - (optional) Either INNER or LEFT. Determine how the additional
+table should be joined with the C&lt;bugs&gt; table. If omitted, LEFT is used.
+
</ins><span class="cx"> =back
</span><span class="cx"> 
</span><del>-=head2 enter_bug-entrydefaultvars
</del><ins>+=back
</ins><span class="cx"> 
</span><ins>+=head2 search_operator_field_override
+
+This allows you to modify L&lt;Bugzilla::Search/OPERATOR_FIELD_OVERRIDE&gt;,
+which determines the search functions for fields. It allows you to specify
+custom search functionality for certain fields. 
+
+See L&lt;Bugzilla::Search/OPERATOR_FIELD_OVERRIDE&gt; for reference and see
+the code in the example extension.
+
+Note that the interface to this hook is B&lt;UNSTABLE&gt; and it may change in the
+future.
+
+Params:
+
+=over
+
+=item C&lt;operators&gt; - See L&lt;Bugzilla::Search/OPERATOR_FIELD_OVERRIDE&gt; to get
+an idea of the structure.
+
+=item C&lt;search&gt; - The L&lt;Bugzilla::Search&gt; object.
+
+=back
+
+=head2 bugmail_recipients
+
+This allows you to modify the list of users who are going to be receiving
+a particular bugmail. It also allows you to specify why they are receiving
+the bugmail.
+
+Users' bugmail preferences will be applied to any users that you add
+to the list. (So, for example, if you add somebody as though they were
+a CC on the bug, and their preferences state that they don't get email
+when they are a CC, they won't get email.)
+
+This hook is called before watchers or globalwatchers are added to the
+recipient list.
+
+Params:
+
+=over
+
+=item C&lt;bug&gt;
+
+The L&lt;Bugzilla::Bug&gt; that bugmail is being sent about.
+
+=item C&lt;recipients&gt;
+
+This is a hashref. The keys are numeric user ids from the C&lt;profiles&gt;
+table in the database, for each user who should be receiving this bugmail.
+The values are hashrefs. The keys in I&lt;these&gt; hashrefs correspond to
+the &quot;relationship&quot; that the user has to the bug they're being emailed
+about, and the value should always be C&lt;1&gt;. The &quot;relationships&quot;
+are described by the various C&lt;REL_&gt; constants in L&lt;Bugzilla::Constants&gt;.
+
+Here's an example of adding userid C&lt;123&gt; to the recipient list
+as though he were on the CC list:
+
+ $recipients-&gt;{123}-&gt;{+REL_CC} = 1
+
+(We use C&lt;+&gt; in front of C&lt;REL_CC&gt; so that Perl interprets it as a constant
+instead of as a string.)
+
+=item C&lt;users&gt;
+
+This is a hash of L&lt;Bugzilla::User&gt; objects, keyed by id. This is so you can
+find out more information about any of the user ids in the C&lt;recipients&gt; hash.
+Every id in the incoming C&lt;recipients&gt; hash will have an object in here. 
+(But if you add additional recipients to the C&lt;recipients&gt; hash, you are 
+B&lt;not&gt; required to add them to this hash.)
+
+=item C&lt;diffs&gt;
+
+This is a list of hashes, each hash representing a change to the bug. Each 
+hash has the following members: C&lt;field_name&gt;, C&lt;bug_when&gt;, C&lt;old&gt;, C&lt;new&gt; 
+and C&lt;who&gt; (a L&lt;Bugzilla::User&gt;). If appropriate, there will also be 
+C&lt;attach_id&gt; or C&lt;comment_id&gt;; if either is present, there will be 
+C&lt;isprivate&gt;. See C&lt;_get_diffs&gt; in F&lt;Bugzilla/BugMail.pm&gt; to see exactly how 
+it is populated. Warning: the format and existence of the &quot;diffs&quot; parameter 
+is subject to change in future releases of Bugzilla.
+
+=back
+
+=head2 bugmail_relationships
+
+There are various sorts of &quot;relationships&quot; that a user can have to a bug,
+such as Assignee, CC, etc. If you want to add a new type of relationship,
+you should use this hook.
+
+Params:
+
+=over
+
+=item C&lt;relationships&gt;
+
+A hashref, where the keys are numbers and the values are strings.
+
+The keys represent a numeric identifier for the relationship. The
+numeric identifier should be a negative number between -1 and -127.
+The number must be unique across all extensions. (Negative numbers
+are used so as not to conflict with relationship identifiers in Bugzilla
+itself.)
+
+The value is the &quot;name&quot; of this relationship that will show up in email
+headers in bugmails. The &quot;name&quot; should be short and should contain no
+spaces.
+
+=back
+
+
+=head2 config_add_panels
+
+If you want to add new panels to the Parameters administrative interface,
+this is where you do it.
+
+Params:
+
+=over
+
+=item C&lt;panel_modules&gt;
+
+A hashref, where the keys are the &quot;name&quot; of the panel and the value
+is the Perl module representing that panel. For example, if
+the name is C&lt;Auth&gt;, the value would be C&lt;Bugzilla::Config::Auth&gt;.
+
+For your extension, the Perl module would start with 
+C&lt;Bugzilla::Extension::Foo&gt;, where &quot;Foo&quot; is the name of your Extension.
+(See the code in the example extension.)
+
+=back
+
+=head2 config_modify_panels
+
+This is how you modify already-existing panels in the Parameters
+administrative interface. For example, if you wanted to add a new
+Auth method (modifying Bugzilla::Config::Auth) this is how you'd
+do it.
+
+Params:
+
+=over
+
+=item C&lt;panels&gt;
+
+A hashref, where the keys are lower-case panel &quot;names&quot; (like C&lt;auth&gt;, 
+C&lt;admin&gt;, etc.) and the values are hashrefs. The hashref contains a
+single key, C&lt;params&gt;. C&lt;params&gt; is an arrayref--the return value from
+C&lt;get_param_list&gt; for that module. You can modify C&lt;params&gt; and
+your changes will be reflected in the interface.
+
+Adding new keys to C&lt;panels&gt; will have no effect. You should use
+L&lt;/config_add_panels&gt; if you want to add new panels.
+
+=back
+
+=head2 email_in_before_parse
+
+This happens right after an inbound email is converted into an Email::MIME
+object, but before we start parsing the email to extract field data. This
+means the email has already been decoded for you. It gives you a chance
+to interact with the email itself before L&lt;email_in&gt; starts parsing its content.
+
+=over
+
+=item C&lt;mail&gt; - An Email::MIME object. The decoded incoming email.
+
+=item C&lt;fields&gt; - A hashref. The hash which will contain extracted data.
+
+=back
+
+=head2 email_in_after_parse
+
+This happens after all the data has been extracted from the email, but before
+the reporter is validated, during L&lt;email_in&gt;. This lets you do things after
+the normal parsing of the email, such as sanitizing field data, changing the
+user account being used to file a bug, etc.
+
+=over
+
+=item C&lt;fields&gt; - A hashref. The hash containing the extracted field data.
+
+=back
+
+=head2 enter_bug_entrydefaultvars
+
+B&lt;DEPRECATED&gt; - Use L&lt;/template_before_process&gt; instead.
+
</ins><span class="cx"> This happens right before the template is loaded on enter_bug.cgi.
</span><span class="cx"> 
</span><span class="cx"> Params:
</span><span class="lines">@@ -245,11 +687,42 @@
</span><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><del>-=head2 flag-end_of_update
</del><ins>+=head2 error_catch
</ins><span class="cx"> 
</span><del>-This happens at the end of L&lt;Bugzilla::Flag/process&gt;, after all other changes
-are made to the database and after emails are sent. It gives you a before/after
-snapshot of flags so you can react to specific flag changes.
</del><ins>+This hook allows extensions to catch errors thrown by Bugzilla and
+take the appropriate actions.
+
+Params:
+
+=over
+
+=item C&lt;error&gt;
+
+A string representing the error code thrown by Bugzilla. This string
+matches the C&lt;error&gt; variable in C&lt;global/user-error.html.tmpl&gt; and
+C&lt;global/code-error.html.tmpl&gt;.
+
+=item C&lt;message&gt;
+
+If the error mode is set to C&lt;ERROR_MODE_WEBPAGE&gt;, you get a reference to
+the whole HTML page with the error message in it, including its header and
+footer. If you need to extract the error message itself, you can do it by
+looking at the content of the table cell whose ID is C&lt;error_msg&gt;.
+If the error mode is not set to C&lt;ERROR_MODE_WEBPAGE&gt;, you get a reference
+to the error message itself.
+
+=item C&lt;vars&gt;
+
+This hash contains all the data passed to the error template. Its content
+depends on the error thrown.
+
+=back
+
+=head2 flag_end_of_update
+
+This happens at the end of L&lt;Bugzilla::Flag/update_flags&gt;, after all other
+changes are made to the database and after emails are sent. It gives you a
+before/after snapshot of flags so you can react to specific flag changes.
</ins><span class="cx"> This generally occurs inside a database transaction.
</span><span class="cx"> 
</span><span class="cx"> Note that the interface to this hook is B&lt;UNSTABLE&gt; and it may change in the
</span><span class="lines">@@ -259,9 +732,10 @@
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><del>-=item C&lt;bug&gt; - The changed bug object.
</del><ins>+=item C&lt;object&gt; - The changed bug or attachment object.
</ins><span class="cx"> 
</span><del>-=item C&lt;timestamp&gt; - The timestamp used for all updates in this transaction.
</del><ins>+=item C&lt;timestamp&gt; - The timestamp used for all updates in this transaction,
+as a SQL date string.
</ins><span class="cx"> 
</span><span class="cx"> =item C&lt;old_flags&gt; - The snapshot of flag summaries from before the change.
</span><span class="cx"> 
</span><span class="lines">@@ -271,8 +745,55 @@
</span><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><del>-=head2 install-before_final_checks
</del><ins>+=head2 group_before_delete
</ins><span class="cx"> 
</span><ins>+This happens in L&lt;Bugzilla::Group/remove_from_db&gt;, after we've confirmed
+that the group can be deleted, but before any rows have actually
+been removed from the database. This occurs inside a database
+transaction.
+
+Params:
+
+=over
+
+=item C&lt;group&gt; - The L&lt;Bugzilla::Group&gt; being deleted.
+
+=back
+
+=head2 group_end_of_create
+
+This happens at the end of L&lt;Bugzilla::Group/create&gt;, after all other
+changes are made to the database. This occurs inside a database transaction.
+
+Params:
+
+=over
+
+=item C&lt;group&gt; 
+
+The new L&lt;Bugzilla::Group&gt; object that was just created.
+
+=back
+
+=head2 group_end_of_update
+
+This happens at the end of L&lt;Bugzilla::Group/update&gt;, after all other 
+changes are made to the database. This occurs inside a database transaction.
+
+Params:
+
+=over
+
+=item C&lt;group&gt; - The changed L&lt;Bugzilla::Group&gt; object, with all fields set 
+to their updated values.
+
+=item C&lt;changes&gt; - The hash of changed fields. 
+C&lt;&lt; $changes-&gt;{$field} = [$old, $new] &gt;&gt;
+
+=back
+
+=head2 install_before_final_checks
+
</ins><span class="cx"> Allows execution of custom code before the final checks are done in 
</span><span class="cx"> checksetup.pl.
</span><span class="cx"> 
</span><span class="lines">@@ -283,47 +804,127 @@
</span><span class="cx"> =item C&lt;silent&gt;
</span><span class="cx"> 
</span><span class="cx"> A flag that indicates whether or not checksetup is running in silent mode.
</span><ins>+If this is true, messages that are I&lt;always&gt; printed by checksetup.pl should be
+suppressed, but messages about any changes that are just being done this one
+time should be printed.
</ins><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><del>-=head2 install-requirements
</del><ins>+=head2 install_filesystem
</ins><span class="cx"> 
</span><del>-Because of the way Bugzilla installation works, there can't be a normal
-hook during the time that F&lt;checksetup.pl&gt; checks what modules are
-installed. (C&lt;Bugzilla::Hook&gt; needs to have those modules installed--it's
-a chicken-and-egg problem.)
</del><ins>+Allows for additional files and directories to be added to the
+list of files and directories already managed by checksetup.pl.
+You will be able to also set permissions for the files and
+directories using this hook. You can also use this hook to create 
+appropriate .htaccess files for any directory to secure its contents.
+For examples see  L&lt;FILESYSTEM&gt; in L&lt;Bugzilla::Install::Filesystem&gt;.
</ins><span class="cx"> 
</span><del>-So instead of the way hooks normally work, this hook just looks for two 
-subroutines (or constants, since all constants are just subroutines) in 
-your file, called C&lt;OPTIONAL_MODULES&gt; and C&lt;REQUIRED_MODULES&gt;,
-which should return arrayrefs in the same format as C&lt;OPTIONAL_MODULES&gt; and
-C&lt;REQUIRED_MODULES&gt; in L&lt;Bugzilla::Install::Requirements&gt;.
</del><ins>+Params:
</ins><span class="cx"> 
</span><del>-These subroutines will be passed an arrayref that contains the current
-Bugzilla requirements of the same type, in case you want to modify
-Bugzilla's requirements somehow. (Probably the most common would be to
-alter a version number or the &quot;feature&quot; element of C&lt;OPTIONAL_MODULES&gt;.)
</del><ins>+=over
</ins><span class="cx"> 
</span><del>-F&lt;checksetup.pl&gt; will add these requirements to its own.
</del><ins>+=item C&lt;files&gt;
</ins><span class="cx"> 
</span><del>-Please remember--if you put something in C&lt;REQUIRED_MODULES&gt;, then
-F&lt;checksetup.pl&gt; B&lt;cannot complete&gt; unless the user has that module
-installed! So use C&lt;OPTIONAL_MODULES&gt; whenever you can.
</del><ins>+Hash reference of files that are already present when your extension was
+installed but need to have specific permissions set. Each file key
+points to another hash reference containing the following settings.
</ins><span class="cx"> 
</span><del>-=head2 install-update_db
</del><ins>+Params:
</ins><span class="cx"> 
</span><ins>+=over
+
+=item C&lt;perms&gt; - Permissions to be set on the file.
+
+=back
+
+=item C&lt;create_dirs&gt;
+
+Hash reference containing the name of each directory that will be created,
+pointing at its default permissions.
+
+=item C&lt;non_recurse_dirs&gt;
+
+Hash reference containing directories that we want to set the perms on, but not
+recurse through. These are directories not created in checksetup.pl. Each directory
+key's value is the permissions to be set on the directory.
+
+=item C&lt;recurse_dirs&gt;
+
+Hash reference of directories that will have permissions set for each item inside 
+each of the directories, including the directory itself. Each directory key
+points to another hash reference containing the following settings.
+
+Params:
+
+=over
+
+=item C&lt;files&gt; - Permissions to be set on any files beneath the directory.
+
+=item C&lt;dirs&gt; - Permissions to be set on the directory itself and any directories
+beneath it.
+
+=back
+
+=item C&lt;create_files&gt;
+
+Hash reference of additional files to be created. Each file key points to another
+hash reference containing the following settings.
+
+Params:
+
+=over
+
+=item C&lt;perms&gt; - The permissions to be set on the file itself.
+
+=item C&lt;contents&gt; - The contents to be added to the file or leave blank for an
+empty file.
+
+=back
+
+=item C&lt;htaccess&gt;
+
+Hash reference containing htaccess files to be created. You can set the permissions
+for the htaccess as well as the contents of the file. Each file key points to another 
+hash reference containing the following settings.
+
+Params:
+
+=over
+
+=item C&lt;perms&gt; - Permissions to be set on the htaccess file.
+
+=item C&lt;contents&gt; - Contents of the htaccess file. It can be set manually or
+use L&lt;HT_DEFAULT_DENY&gt; defined in L&lt;Bugzilla::Install::Filesystem&gt; to deny all
+by default.
+
+=back
+
+=back
+
+=head2 install_update_db
+
</ins><span class="cx"> This happens at the very end of all the tables being updated
</span><span class="cx"> during an installation or upgrade. If you need to modify your custom
</span><del>-schema, do it here. No params are passed.
</del><ins>+schema or add new columns to existing tables, do it here. No params are
+passed.
</ins><span class="cx"> 
</span><del>-=head2 db_schema-abstract_schema
</del><ins>+=head2 install_update_db_fielddefs
</ins><span class="cx"> 
</span><ins>+This is used to update the schema of the fielddefs table before
+any other schema changes take place. No params are passed.
+
+This hook should only be used for updating the schema of the C&lt;fielddefs&gt;
+table. Do not modify any other table in this hook. To modify other tables, use
+the L&lt;/install_update_db&gt; hook.
+
+=head2 db_schema_abstract_schema
+
</ins><span class="cx"> This allows you to add tables to Bugzilla. Note that we recommend that you 
</span><del>-prefix the names of your tables with some word, so that they don't conflict 
-with any future Bugzilla tables.
</del><ins>+prefix the names of your tables with some word (preferably the name of
+your Extension), so that they don't conflict with any future Bugzilla tables.
</ins><span class="cx"> 
</span><span class="cx"> If you wish to add new I&lt;columns&gt; to existing Bugzilla tables, do that
</span><del>-in L&lt;/install-update_db&gt;.
</del><ins>+in L&lt;/install_update_db&gt;.
</ins><span class="cx"> 
</span><span class="cx"> Params:
</span><span class="cx"> 
</span><span class="lines">@@ -336,8 +937,374 @@
</span><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><del>-=head2 product-confirm_delete
</del><ins>+=head2 job_map
</ins><span class="cx"> 
</span><ins>+Bugzilla has a system - L&lt;Bugzilla::JobQueue&gt; - for running jobs 
+asynchronously, if the administrator has set it up. This hook allows the 
+addition of mappings from job names to handler classes, so an extension can 
+fire off jobs.
+
+Params:
+
+=over
+
+=item C&lt;job_map&gt; - The job map hash. Key: the name of the job, as should be 
+passed to Bugzilla-&gt;job_queue-&gt;insert(). Value: the name of the Perl module 
+which implements the task (an instance of L&lt;TheSchwartz::Worker&gt;). 
+
+=back
+
+=head2 mailer_before_send
+
+Called right before L&lt;Bugzilla::Mailer&gt; sends a message to the MTA.
+
+Params:
+
+=over
+
+=item C&lt;email&gt; - The C&lt;Email::MIME&gt; object that's about to be sent.
+
+=item C&lt;mailer_args&gt; - An arrayref that's passed as C&lt;mailer_args&gt; to
+L&lt;Email::Send/new&gt;.
+
+=back
+
+=head2 object_before_create
+
+This happens at the beginning of L&lt;Bugzilla::Object/create&gt;.
+
+Params:
+
+=over
+
+=item C&lt;class&gt;
+
+The name of the class that C&lt;create&gt; was called on. You can check this 
+like C&lt;&lt; if ($class-&gt;isa('Some::Class')) &gt;&gt; in your code, to perform specific
+tasks before C&lt;create&gt; for only certain classes.
+
+=item C&lt;params&gt;
+
+A hashref. The set of named parameters passed to C&lt;create&gt;.
+
+=back
+
+
+=head2 object_before_delete
+
+This happens in L&lt;Bugzilla::Object/remove_from_db&gt;, after we've confirmed
+that the object can be deleted, but before any rows have actually
+been removed from the database. This sometimes occurs inside a database
+transaction.
+
+Params:
+
+=over
+
+=item C&lt;object&gt; - The L&lt;Bugzilla::Object&gt; being deleted. You will probably
+want to check its type like C&lt;&lt; $object-&gt;isa('Some::Class') &gt;&gt; before doing
+anything with it.
+
+=back
+
+
+=head2 object_before_set
+
+Called during L&lt;Bugzilla::Object/set&gt;, before any actual work is done.
+You can use this to perform actions before a value is changed for
+specific fields on certain types of objects.
+
+Params:
+
+=over
+
+=item C&lt;object&gt;
+
+The object that C&lt;set&gt; was called on. You will probably want to
+do something like C&lt;&lt; if ($object-&gt;isa('Some::Class')) &gt;&gt; in your code to
+limit your changes to only certain subclasses of Bugzilla::Object.
+
+=item C&lt;field&gt;
+
+The name of the field being updated in the object.
+
+=item C&lt;value&gt; 
+
+The value being set on the object.
+
+=back
+
+=head2 object_columns
+
+This hook allows you to add new &quot;fields&quot; to existing Bugzilla objects,
+that correspond to columns in their tables.
+
+For example, if you added an C&lt;example&gt; column to the &quot;bugs&quot; table, you
+would have to also add an C&lt;example&gt; field to the C&lt;Bugzilla::Bug&gt; object
+in order to access that data via Bug objects.
+
+Don't do anything slow inside this hook--it's called several times on
+every page of Bugzilla.
+
+Params:
+
+=over
+
+=item C&lt;class&gt;
+
+The name of the class that this hook is being called on. You can check this 
+like C&lt;&lt; if ($class-&gt;isa('Some::Class')) &gt;&gt; in your code, to add new
+fields only for certain classes.
+
+=item C&lt;columns&gt;
+
+An arrayref. Add the string names of columns to this array to add new
+values to objects. 
+
+For example, if you add an C&lt;example&gt; column to a particular table
+(using L&lt;/install_update_db&gt;), and then push the string C&lt;example&gt; into 
+this array for the object that uses that table, then you can access the
+information in that column via C&lt;&lt; $object-&gt;{example} &gt;&gt; on all objects
+of that type.
+
+This arrayref does not contain the standard column names--you cannot modify
+or remove standard object columns using this hook.
+
+=back
+
+=head2 object_end_of_create
+
+Called at the end of L&lt;Bugzilla::Object/create&gt;, after all other changes are
+made to the database. This occurs inside a database transaction.
+
+Params:
+
+=over
+
+=item C&lt;class&gt;
+
+The name of the class that C&lt;create&gt; was called on. You can check this 
+like C&lt;&lt; if ($class-&gt;isa('Some::Class')) &gt;&gt; in your code, to perform specific
+tasks for only certain classes.
+
+=item C&lt;object&gt;
+
+The created object.
+
+=back
+
+=head2 object_end_of_create_validators
+
+Called at the end of L&lt;Bugzilla::Object/run_create_validators&gt;. You can
+use this to run additional validation when creating an object.
+
+If a subclass has overridden C&lt;run_create_validators&gt;, then this usually
+happens I&lt;before&gt; the subclass does its custom validation.
+
+Params:
+
+=over
+
+=item C&lt;class&gt;
+
+The name of the class that C&lt;create&gt; was called on. You can check this 
+like C&lt;&lt; if ($class-&gt;isa('Some::Class')) &gt;&gt; in your code, to perform specific
+tasks for only certain classes.
+
+=item C&lt;params&gt;
+
+A hashref. The set of named parameters passed to C&lt;create&gt;, modified and
+validated by the C&lt;VALIDATORS&gt; specified for the object.
+
+=back
+
+
+=head2 object_end_of_set
+
+Called during L&lt;Bugzilla::Object/set&gt;, after all the code of the function
+has completed (so the value has been validated and the field has been set
+to the new value). You can use this to perform actions after a value is
+changed for specific fields on certain types of objects.
+
+The new value is not specifically passed to this hook because you can
+get it as C&lt;&lt; $object-&gt;{$field} &gt;&gt;.
+
+Params:
+
+=over
+
+=item C&lt;object&gt;
+
+The object that C&lt;set&gt; was called on. You will probably want to
+do something like C&lt;&lt; if ($object-&gt;isa('Some::Class')) &gt;&gt; in your code to
+limit your changes to only certain subclasses of Bugzilla::Object.
+
+=item C&lt;field&gt;
+
+The name of the field that was updated in the object.
+
+=back
+
+
+=head2 object_end_of_set_all
+
+This happens at the end of L&lt;Bugzilla::Object/set_all&gt;. This is a
+good place to call custom set_ functions on objects, or to make changes
+to an object before C&lt;update()&gt; is called.
+
+Params:
+
+=over
+
+=item C&lt;object&gt;
+
+The L&lt;Bugzilla::Object&gt; which is being updated. You will probably want to
+do something like C&lt;&lt; if ($object-&gt;isa('Some::Class')) &gt;&gt; in your code to
+limit your changes to only certain subclasses of Bugzilla::Object.
+
+=item C&lt;params&gt;
+
+A hashref. The set of named parameters passed to C&lt;set_all&gt;.
+
+=back
+
+=head2 object_end_of_update
+
+Called during L&lt;Bugzilla::Object/update&gt;, after changes are made
+to the database, but while still inside a transaction.
+
+Params:
+
+=over
+
+=item C&lt;object&gt;
+
+The object that C&lt;update&gt; was called on. You will probably want to
+do something like C&lt;&lt; if ($object-&gt;isa('Some::Class')) &gt;&gt; in your code to
+limit your changes to only certain subclasses of Bugzilla::Object.
+
+=item C&lt;old_object&gt;
+
+The object as it was before it was updated.
+
+=item C&lt;changes&gt;
+
+The fields that have been changed, in the same format that
+L&lt;Bugzilla::Object/update&gt; returns.
+
+=back
+
+=head2 object_update_columns
+
+If you've added fields to bugs via L&lt;/object_columns&gt;, then this
+hook allows you to say which of those columns should be updated in the
+database when L&lt;Bugzilla::Object/update&gt; is called on the object.
+
+If you don't use this hook, then your custom columns won't be modified in
+the database by Bugzilla.
+
+Params:
+
+=over
+
+=item C&lt;object&gt;
+
+The object that is about to be updated. You should check this
+like C&lt;&lt; if ($object-&gt;isa('Some::Class')) &gt;&gt; in your code, to modify
+the &quot;update columns&quot; only for certain classes.
+
+=item C&lt;columns&gt;
+
+An arrayref. Add the string names of columns to this array to allow
+that column to be updated when C&lt;update()&gt; is called on the object.
+
+This arrayref does not contain the standard column names--you cannot stop
+standard columns from being updated by using this hook.
+
+=back
+
+=head2 object_validators
+
+Allows you to add new items to L&lt;Bugzilla::Object/VALIDATORS&gt; for
+particular classes.
+
+Params:
+
+=over
+
+=item C&lt;class&gt;
+
+The name of the class that C&lt;VALIDATORS&gt; was called on. You can check this 
+like C&lt;&lt; if ($class-&gt;isa('Some::Class')) &gt;&gt; in your code, to add
+validators only for certain classes.
+
+=item C&lt;validators&gt;
+
+A hashref, where the keys are database columns and the values are subroutine
+references. You can add new validators or modify existing ones. If you modify
+an existing one, you should remember to call the original validator
+inside of your modified validator. (This way, several extensions can all
+modify the same validator.)
+
+=back
+
+
+=head2 page_before_template
+
+This is a simple way to add your own pages to Bugzilla. This hooks C&lt;page.cgi&gt;,
+which loads templates from F&lt;template/en/default/pages&gt;. For example,
+C&lt;page.cgi?id=fields.html&gt; loads F&lt;template/en/default/pages/fields.html.tmpl&gt;.
+
+This hook is called right before the template is loaded, so that you can
+pass your own variables to your own pages.
+
+You can also use this to implement complex custom pages, by doing your own
+output and then calling  C&lt;exit&gt; at the end of the hook, thus preventing
+the normal C&lt;page.cgi&gt; behavior from occurring.
+
+Params:
+
+=over
+
+=item C&lt;page_id&gt;
+
+This is the name of the page being loaded, like C&lt;fields.html&gt;.
+
+Note that if two extensions use the same name, it is uncertain which will
+override the others, so you should be careful with how you name your pages.
+Usually extensions prefix their pages with a directory named after their
+extension, so for an extension named &quot;Foo&quot;, page ids usually look like
+C&lt;foo/mypage.html&gt;.
+
+=item C&lt;vars&gt;
+
+This is a hashref--put variables into here if you want them passed to
+your template.
+
+=back
+
+
+=head2 post_bug_after_creation
+
+B&lt;DEPRECATED&gt; (Use L&lt;/bug_end_of_create&gt; instead.)
+
+This happens after a bug is created and before bug mail is sent
+during C&lt;post_bug.cgi&gt;. Note that this only happens during C&lt;post_bug.cgi&gt;,
+it doesn't happen during any of the other methods of creating a bug.
+
+Params:
+
+=over
+
+=item C&lt;vars&gt; - The template vars hashref.
+
+=back
+
+
+=head2 product_confirm_delete
+
+B&lt;DEPRECATED&gt; - Use L&lt;/template_before_process&gt; instead.
+
</ins><span class="cx"> Called before displaying the confirmation message when deleting a product.
</span><span class="cx"> 
</span><span class="cx"> Params:
</span><span class="lines">@@ -348,6 +1315,178 @@
</span><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><ins>+=head2 product_end_of_create
+
+Called right after a new product has been created, allowing additional
+changes to be made to the new product's attributes. This occurs inside of
+a database transaction, so if the hook throws an error, all previous
+changes will be rolled back, including the creation of the new product.
+(However, note that such rollbacks should not normally be used, as
+some databases that Bugzilla supports have very bad rollback performance.
+If you want to validate input and throw errors before the Product is created,
+use L&lt;/object_end_of_create_validators&gt; instead, or add a validator 
+using L&lt;/object_validators&gt;.)
+
+Params:
+
+=over
+
+=item C&lt;product&gt; - The new L&lt;Bugzilla::Product&gt; object that was just created.
+
+=back
+
+=head2 quicksearch_map
+
+This hook allows you to alter the Quicksearch syntax to include e.g. special 
+searches for custom fields you have.
+
+Params:
+
+=over
+
+=item C&lt;map&gt; - a hash where the key is the name you want to use in 
+Quicksearch, and the value is the name from the C&lt;fielddefs&gt; table that you 
+want it to map to. You can modify existing mappings or add new ones.
+
+=back
+
+=head2 sanitycheck_check
+
+This hook allows for extra sanity checks to be added, for use by
+F&lt;sanitycheck.cgi&gt;.
+
+Params:
+
+=over
+
+=item C&lt;status&gt; - a CODEREF that allows status messages to be displayed
+to the user. (F&lt;sanitycheck.cgi&gt;'s C&lt;Status&gt;)
+
+=back
+
+=head2 sanitycheck_repair
+
+This hook allows for extra sanity check repairs to be made, for use by
+F&lt;sanitycheck.cgi&gt;.
+
+Params:
+
+=over
+
+=item C&lt;status&gt; - a CODEREF that allows status messages to be displayed
+to the user. (F&lt;sanitycheck.cgi&gt;'s C&lt;Status&gt;)
+
+=back
+
+=head2 template_before_create
+
+This hook allows you to modify the configuration of L&lt;Bugzilla::Template&gt;
+objects before they are created. For example, you could add a new
+global template variable this way.
+
+Params:
+
+=over
+
+=item C&lt;config&gt;
+
+A hashref--the configuration that will be passed to L&lt;Template/new&gt;.
+See L&lt;http://template-toolkit.org/docs/modules/Template.html#section_CONFIGURATION_SUMMARY&gt;
+for information on how this configuration variable is structured (or just
+look at the code for C&lt;create&gt; in L&lt;Bugzilla::Template&gt;.)
+
+=back
+
+=head2 template_before_process
+
+This hook is called any time Bugzilla processes a template file, including
+calls to C&lt;&lt; $template-&gt;process &gt;&gt;, C&lt;PROCESS&gt; statements in templates,
+and C&lt;INCLUDE&gt; statements in templates. It is not called when templates
+process a C&lt;BLOCK&gt;, only when they process a file.
+
+This hook allows you to define additional variables that will be available to
+the template being processed, or to modify the variables that are currently
+in the template. It works exactly as though you inserted code to modify
+template variables at the top of a template.
+
+You probably want to restrict this hook to operating only if a certain 
+file is being processed (which is why you get a C&lt;file&gt; argument
+below). Otherwise, modifying the C&lt;vars&gt; argument will affect every single
+template in Bugzilla.
+
+B&lt;Note:&gt; This hook is not called if you are already in this hook.
+(That is, it won't call itself recursively.) This prevents infinite
+recursion in situations where this hook needs to process a template
+(such as if this hook throws an error).
+
+Params:
+
+=over
+
+=item C&lt;vars&gt;
+
+This is the entire set of variables that the current template can see.
+Technically, this is a L&lt;Template::Stash&gt; object, but you can just
+use it like a hashref if you want.
+
+=item C&lt;file&gt;
+
+The name of the template file being processed. This is relative to the
+main template directory for the language (i.e. for
+F&lt;template/en/default/bug/show.html.tmpl&gt;, this variable will contain
+C&lt;bug/show.html.tmpl&gt;).
+
+=item C&lt;context&gt;
+
+A L&lt;Template::Context&gt; object. Usually you will not have to use this, but
+if you need information about the template itself (other than just its
+name), you can get it from here.
+
+=back
+
+=head2 user_preferences
+
+This hook allows you to add additional panels to the User Preferences page,
+and validate data displayed and returned from these panels. It works in
+combination with the C&lt;tabs&gt; hook available in the
+F&lt;template/en/default/account/prefs/prefs.html.tmpl&gt; template. To make it
+work, you must define two templates in your extension:
+F&lt;extensions/Foo/template/en/default/hook/account/prefs/prefs-tabs.html.tmpl&gt;
+contains a list of additional panels to include.
+F&lt;extensions/Foo/template/en/default/account/prefs/bar.html.tmpl&gt; contains
+the content of the panel itself. See the C&lt;Example&gt; extension to see how
+things work.
+
+Params:
+
+=over
+
+=item C&lt;current_tab&gt;
+
+The name of the current panel being viewed by the user. You should always
+make sure that the name of the panel matches what you expect it to be.
+Else you could be interacting with the panel of another extension.
+
+=item C&lt;save_changes&gt;
+
+A boolean which is true when data should be validated and the DB updated
+accordingly. This means the user clicked the &quot;Submit Changes&quot; button.
+
+=item C&lt;handled&gt;
+
+This is a B&lt;reference&gt; to a scalar, not a scalar. (So you would set it like
+C&lt;$$handled = 1&gt;, not like C&lt;$handled = 1&gt;.) Set this to a true value to let
+Bugzilla know that the passed-in panel is valid and that you have handled it.
+(Otherwise, Bugzilla will throw an error that the panel is invalid.) Don't set
+this to true if you didn't handle the panel listed in C&lt;current_tab&gt;.
+
+=item C&lt;vars&gt;
+
+You can add as many new key/value pairs as you want to this hashref.
+It will be passed to the template.
+
+=back
+
</ins><span class="cx"> =head2 webservice
</span><span class="cx"> 
</span><span class="cx"> This hook allows you to add your own modules to the WebService. (See
</span><span class="lines">@@ -359,20 +1498,20 @@
</span><span class="cx"> 
</span><span class="cx"> =item C&lt;dispatch&gt;
</span><span class="cx"> 
</span><del>-A hashref that you can specify the names of your modules and what Perl
</del><ins>+A hashref where you can specify the names of your modules and which Perl
</ins><span class="cx"> module handles the functions for that module. (This is actually sent to 
</span><span class="cx"> L&lt;SOAP::Lite/dispatch_with&gt;. You can see how that's used in F&lt;xmlrpc.cgi&gt;.)
</span><span class="cx"> 
</span><del>-The Perl module name must start with C&lt;extensions::yourextension::lib::&gt;
-(replace C&lt;yourextension&gt; with the name of your extension). The C&lt;package&gt;
-declaration inside that module must also start with 
-C&lt;extensions::yourextension::lib::&gt; in that module's code.
</del><ins>+The Perl module name will most likely start with C&lt;Bugzilla::Extension::Foo::&gt;
+(where &quot;Foo&quot; is the name of your extension).
</ins><span class="cx"> 
</span><span class="cx"> Example:
</span><span class="cx"> 
</span><del>-  $dispatch-&gt;{Example} = &quot;extensions::example::lib::Example&quot;;
</del><ins>+  $dispatch-&gt;{'Example.Blah'} = &quot;Bugzilla::Extension::Example::Webservice::Blah&quot;;
</ins><span class="cx"> 
</span><del>-And then you'd have a module F&lt;extensions/example/lib/Example.pm&gt;
</del><ins>+And then you'd have a module F&lt;extensions/Example/lib/Webservice/Blah.pm&gt;,
+and could call methods from that module like C&lt;Example.Blah.Foo()&gt; using
+the WebServices interface.
</ins><span class="cx"> 
</span><span class="cx"> It's recommended that all the keys you put in C&lt;dispatch&gt; start with the
</span><span class="cx"> name of your extension, so that you don't conflict with the standard Bugzilla
</span><span class="lines">@@ -381,7 +1520,7 @@
</span><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><del>-=head2 webservice-error_codes
</del><ins>+=head2 webservice_error_codes
</ins><span class="cx"> 
</span><span class="cx"> If your webservice extension throws custom errors, you can set numeric
</span><span class="cx"> codes for those errors here.
</span><span class="lines">@@ -399,3 +1538,7 @@
</span><span class="cx"> See L&lt;Bugzilla::WebService::Constants/WS_ERROR_CODE&gt; for an example.
</span><span class="cx"> 
</span><span class="cx"> =back
</span><ins>+
+=head1 SEE ALSO
+
+L&lt;Bugzilla::Extension&gt;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaInstallCPANpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Install/CPAN.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Install/CPAN.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Install/CPAN.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -21,16 +21,49 @@
</span><span class="cx"> package Bugzilla::Install::CPAN;
</span><span class="cx"> use strict;
</span><span class="cx"> use base qw(Exporter);
</span><del>-our @EXPORT = qw(set_cpan_config install_module BZ_LIB);
</del><ins>+our @EXPORT = qw(
+    BZ_LIB
</ins><span class="cx"> 
</span><ins>+    check_cpan_requirements 
+    set_cpan_config
+    install_module 
+);
+
</ins><span class="cx"> use Bugzilla::Constants;
</span><ins>+use Bugzilla::Install::Requirements qw(have_vers);
</ins><span class="cx"> use Bugzilla::Install::Util qw(bin_loc install_string);
</span><span class="cx"> 
</span><ins>+use Config;
</ins><span class="cx"> use CPAN;
</span><span class="cx"> use Cwd qw(abs_path);
</span><span class="cx"> use File::Path qw(rmtree);
</span><span class="cx"> use List::Util qw(shuffle);
</span><span class="cx"> 
</span><ins>+# These are required for install-module.pl to be able to install
+# all modules properly.
+use constant REQUIREMENTS =&gt; (
+    {
+        module  =&gt; 'CPAN',
+        package =&gt; 'CPAN',
+        version =&gt; '1.81',
+    },
+    {
+        # When Module::Build isn't installed, the YAML module allows
+        # CPAN to read META.yml to determine that Module::Build first
+        # needs to be installed to compile a module.
+        module  =&gt; 'YAML',
+        package =&gt; 'YAML',
+        version =&gt; 0,
+    },
+    {
+        # Many modules on CPAN are now built with Dist::Zilla, which
+        # unfortunately means they require this version of EU::MM to install.
+        module  =&gt; 'ExtUtils::MakeMaker',
+        package =&gt; 'ExtUtils-MakeMaker',
+        version =&gt; '6.31',
+    },
+);
+
</ins><span class="cx"> # We need the absolute path of ext_libpath, because CPAN chdirs around
</span><span class="cx"> # and so we can't use a relative directory.
</span><span class="cx"> #
</span><span class="lines">@@ -46,13 +79,16 @@
</span><span class="cx">     auto_commit =&gt; 0,
</span><span class="cx">     # We always force builds, so there's no reason to cache them.
</span><span class="cx">     build_cache =&gt; 0,
</span><ins>+    build_requires_install_policy =&gt; 'yes',
</ins><span class="cx">     cache_metadata =&gt; 1,
</span><ins>+    colorize_output =&gt; 1,
+    colorize_print =&gt; 'bold',
</ins><span class="cx">     index_expire =&gt; 1,
</span><span class="cx">     scan_cache =&gt; 'atstart',
</span><span class="cx"> 
</span><span class="cx">     inhibit_startup_message =&gt; 1,
</span><del>-    mbuild_install_build_command =&gt; './Build',
</del><span class="cx"> 
</span><ins>+    bzip2 =&gt; bin_loc('bzip2'),
</ins><span class="cx">     curl =&gt; bin_loc('curl'),
</span><span class="cx">     gzip =&gt; bin_loc('gzip'),
</span><span class="cx">     links =&gt; bin_loc('links'),
</span><span class="lines">@@ -67,14 +103,65 @@
</span><span class="cx">         http://cpan.pair.com/
</span><span class="cx">         http://mirror.hiwaay.net/CPAN/
</span><span class="cx">         ftp://ftp.dc.aleron.net/pub/CPAN/
</span><del>-        http://perl.secsup.org/
-        http://mirrors.kernel.org/cpan/)],
</del><ins>+        http://mirrors.kernel.org/cpan/
+        http://mirrors2.kernel.org/cpan/)],
</ins><span class="cx"> };
</span><span class="cx"> 
</span><ins>+sub check_cpan_requirements {
+    my ($original_dir, $original_args) = @_;
+
+    _require_compiler();
+
+    my @install;
+    foreach my $module (REQUIREMENTS) {
+        my $installed = have_vers($module, 1);
+        push(@install, $module) if !$installed;
+    }
+
+    return if !@install;
+
+    my $restart_required;
+    foreach my $module (@install) {
+        $restart_required = 1 if $module-&gt;{module} eq 'CPAN';
+        install_module($module-&gt;{module}, 1);
+    }
+
+    if ($restart_required) {
+        chdir $original_dir;
+        exec($^X, $0, @$original_args);
+    }
+}
+
+sub _require_compiler {
+    my @errors;
+
+    my $cc_name = $Config{cc};
+    my $cc_exists = bin_loc($cc_name);
+
+    if (!$cc_exists) {
+        push(@errors, install_string('install_no_compiler'));
+    }
+
+    my $make_name = $CPAN::Config-&gt;{make};
+    my $make_exists = bin_loc($make_name);
+
+    if (!$make_exists) {
+        push(@errors, install_string('install_no_make'));
+    }
+
+    die @errors if @errors;
+}
+
</ins><span class="cx"> sub install_module {
</span><del>-    my ($name, $notest) = @_;
</del><ins>+    my ($name, $test) = @_;
</ins><span class="cx">     my $bzlib = BZ_LIB;
</span><span class="cx"> 
</span><ins>+    # Make Module::AutoInstall install all dependencies and never prompt.
+    local $ENV{PERL_AUTOINSTALL} = '--alldeps';
+    # This makes Net::SSLeay not prompt the user, if it gets installed.
+    # It also makes any other MakeMaker prompts accept their defaults.
+    local $ENV{PERL_MM_USE_DEFAULT} = 1;
+
</ins><span class="cx">     # Certain modules require special stuff in order to not prompt us.
</span><span class="cx">     my $original_makepl = $CPAN::Config-&gt;{makepl_arg};
</span><span class="cx">     # This one's a regex in case we're doing Template::Plugin::GD and it
</span><span class="lines">@@ -85,21 +172,34 @@
</span><span class="cx">     elsif ($name eq 'XML::Twig') {
</span><span class="cx">         $CPAN::Config-&gt;{makepl_arg} = &quot;-n $original_makepl&quot;;
</span><span class="cx">     }
</span><del>-    elsif ($name eq 'Net::LDAP') {
-        $CPAN::Config-&gt;{makepl_arg} .= &quot; --skipdeps&quot;;
-    }
</del><span class="cx">     elsif ($name eq 'SOAP::Lite') {
</span><span class="cx">         $CPAN::Config-&gt;{makepl_arg} .= &quot; --noprompt&quot;;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     my $module = CPAN::Shell-&gt;expand('Module', $name);
</span><ins>+    if (!$module) {
+        die install_string('no_such_module', { module =&gt; $name }) . &quot;\n&quot;;
+    }
+    my $version = $module-&gt;cpan_version;
+    my $module_name = $name;
+
+    if ($name eq 'LWP::UserAgent' &amp;&amp; $^V lt v5.8.8) {
+        # LWP 6.x requires Perl 5.8.8 or newer.
+        # As PAUSE only indexes the very last version of each module,
+        # we have to specify the path to the tarball ourselves.
+        $name = 'GAAS/libwww-perl-5.837.tar.gz';
+        # This tarball contains LWP::UserAgent 5.835.
+        $version = '5.835';
+    }
+
</ins><span class="cx">     print install_string('install_module', 
</span><del>-              { module =&gt; $name, version =&gt; $module-&gt;cpan_version }) . &quot;\n&quot;;
-    if ($notest) {
-        CPAN::Shell-&gt;notest('install', $name);
</del><ins>+              { module =&gt; $module_name, version =&gt; $version }) . &quot;\n&quot;;
+
+    if ($test) {
+        CPAN::Shell-&gt;force('install', $name);
</ins><span class="cx">     }
</span><span class="cx">     else {
</span><del>-        CPAN::Shell-&gt;force('install', $name);
</del><ins>+        CPAN::Shell-&gt;notest('install', $name);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # If it installed any binaries in the Bugzilla directory, delete them.
</span><span class="lines">@@ -137,7 +237,7 @@
</span><span class="cx"> 
</span><span class="cx">         # If we can't make one, we finally try to use the Bugzilla directory.
</span><span class="cx">         if (!-w $dir) {
</span><del>-            print &quot;WARNING: Using the Bugzilla directory as the CPAN home.\n&quot;;
</del><ins>+            print STDERR install_string('cpan_bugzilla_home'), &quot;\n&quot;;
</ins><span class="cx">             $dir = &quot;$bzlib/.cpan&quot;;
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -152,6 +252,8 @@
</span><span class="cx">     
</span><span class="cx">     # Unless specified, we install the modules into the Bugzilla directory.
</span><span class="cx">     if (!$do_global) {
</span><ins>+        require Config;
+
</ins><span class="cx">         $CPAN::Config-&gt;{makepl_arg} .= &quot; LIB=\&quot;$bzlib\&quot;&quot;
</span><span class="cx">             . &quot; INSTALLMAN1DIR=\&quot;$bzlib/man/man1\&quot;&quot;
</span><span class="cx">             . &quot; INSTALLMAN3DIR=\&quot;$bzlib/man/man3\&quot;&quot;
</span><span class="lines">@@ -162,7 +264,10 @@
</span><span class="cx">             # INSTALLDIRS=perl is set because that makes sure that MakeMaker
</span><span class="cx">             # always uses the directories we've specified here.
</span><span class="cx">             . &quot; INSTALLDIRS=perl&quot;;
</span><del>-        $CPAN::Config-&gt;{mbuild_arg} = &quot;--install_base \&quot;$bzlib\&quot;&quot;;
</del><ins>+        $CPAN::Config-&gt;{mbuild_arg} = &quot; --install_base \&quot;$bzlib\&quot;&quot;
+            . &quot; --install_path lib=\&quot;$bzlib\&quot;&quot;
+            . &quot; --install_path arch=\&quot;$bzlib/$Config::Config{archname}\&quot;&quot;;
+        $CPAN::Config-&gt;{mbuild_install_arg} = $CPAN::Config-&gt;{mbuild_arg};
</ins><span class="cx"> 
</span><span class="cx">         # When we're not root, sometimes newer versions of CPAN will
</span><span class="cx">         # try to read/modify things that belong to root, unless we set
</span><span class="lines">@@ -213,7 +318,7 @@
</span><span class="cx">  use Bugzilla::Install::CPAN;
</span><span class="cx"> 
</span><span class="cx">  set_cpan_config();
</span><del>- install_module('Module::Name', 1);
</del><ins>+ install_module('Module::Name');
</ins><span class="cx"> 
</span><span class="cx"> =head1 DESCRIPTION
</span><span class="cx"> 
</span><span class="lines">@@ -240,8 +345,9 @@
</span><span class="cx"> =item C&lt;$name&gt; - The name of the module, just like you'd pass to the
</span><span class="cx"> C&lt;install&gt; command in the CPAN shell.
</span><span class="cx"> 
</span><del>-=item C&lt;$notest&gt; - If true, we skip running tests on this module. This
-can greatly speed up the installation time.
</del><ins>+=item C&lt;$test&gt; - If true, we run tests on this module before installing,
+but we still force the install if the tests fail. This is only used
+when we internally install a newer CPAN module.
</ins><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaInstallDBpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Install/DB.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Install/DB.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Install/DB.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -24,13 +24,19 @@
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla::Constants;
</span><span class="cx"> use Bugzilla::Hook;
</span><ins>+use Bugzilla::Install ();
</ins><span class="cx"> use Bugzilla::Install::Util qw(indicate_progress install_string);
</span><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> use Bugzilla::Series;
</span><ins>+use Bugzilla::BugUrl;
+use Bugzilla::Field;
</ins><span class="cx"> 
</span><span class="cx"> use Date::Parse;
</span><span class="cx"> use Date::Format;
</span><span class="cx"> use IO::File;
</span><ins>+use List::MoreUtils qw(uniq);
+use URI;
+use URI::QueryParam;
</ins><span class="cx"> 
</span><span class="cx"> # NOTE: This is NOT the function for general table updates. See
</span><span class="cx"> # update_table_definitions for that. This is only for the fielddefs table.
</span><span class="lines">@@ -86,6 +92,41 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    $dbh-&gt;bz_add_column('fielddefs', 'visibility_field_id', {TYPE =&gt; 'INT3'});
+    $dbh-&gt;bz_add_column('fielddefs', 'value_field_id', {TYPE =&gt; 'INT3'});
+    $dbh-&gt;bz_add_index('fielddefs', 'fielddefs_value_field_id_idx',
+                       ['value_field_id']);
+
+    # Bug 344878
+    if (!$dbh-&gt;bz_column_info('fielddefs', 'buglist')) {
+        $dbh-&gt;bz_add_column('fielddefs', 'buglist',
+            {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1, DEFAULT =&gt; 'FALSE'});
+        # Set non-multiselect custom fields as valid buglist fields
+        # Note that default fields will be handled in Field.pm
+        $dbh-&gt;do('UPDATE fielddefs SET buglist = 1 WHERE custom = 1 AND type != ' . FIELD_TYPE_MULTI_SELECT);
+    }
+
+    #2008-08-26 elliotte_martin@yahoo.com - Bug 251556
+    $dbh-&gt;bz_add_column('fielddefs', 'reverse_desc', {TYPE =&gt; 'TINYTEXT'});
+
+    $dbh-&gt;do('UPDATE fielddefs SET buglist = 1
+               WHERE custom = 1 AND type = ' . FIELD_TYPE_MULTI_SELECT);
+
+    $dbh-&gt;bz_add_column('fielddefs', 'is_mandatory',
+        {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1, DEFAULT =&gt; 'FALSE'});
+    $dbh-&gt;bz_add_index('fielddefs', 'fielddefs_is_mandatory_idx',
+                       ['is_mandatory']);
+
+    # 2010-04-05 dkl@redhat.com - Bug 479400
+    _migrate_field_visibility_value();
+
+    $dbh-&gt;bz_add_column('fielddefs', 'is_numeric',
+        {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1, DEFAULT =&gt; 'FALSE'});
+    $dbh-&gt;do('UPDATE fielddefs SET is_numeric = 1 WHERE type = '
+             . FIELD_TYPE_BUG_ID);
+             
+    Bugzilla::Hook::process('install_update_db_fielddefs');
+
</ins><span class="cx">     # Remember, this is not the function for adding general table changes.
</span><span class="cx">     # That is below. Add new changes to the fielddefs table above this
</span><span class="cx">     # comment.
</span><span class="lines">@@ -125,7 +166,6 @@
</span><span class="cx"> 
</span><span class="cx">     _add_bug_vote_cache();
</span><span class="cx">     _update_product_name_definition();
</span><del>-    _add_bug_keyword_cache();
</del><span class="cx"> 
</span><span class="cx">     $dbh-&gt;bz_add_column('profiles', 'disabledtext',
</span><span class="cx">                         {TYPE =&gt; 'MEDIUMTEXT', NOTNULL =&gt; 1}, '');
</span><span class="lines">@@ -148,11 +188,6 @@
</span><span class="cx">     $dbh-&gt;bz_add_column('bugs', 'everconfirmed',
</span><span class="cx">                         {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1}, 1);
</span><span class="cx"> 
</span><del>-    $dbh-&gt;bz_add_column('products', 'maxvotesperbug',
-                        {TYPE =&gt; 'INT2', NOTNULL =&gt; 1, DEFAULT =&gt; '10000'});
-    $dbh-&gt;bz_add_column('products', 'votestoconfirm',
-                        {TYPE =&gt; 'INT2', NOTNULL =&gt; 1}, 0);
-
</del><span class="cx">     _populate_milestones_table();
</span><span class="cx"> 
</span><span class="cx">     # 2000-03-22 Changed the default value for target_milestone to be &quot;---&quot;
</span><span class="lines">@@ -341,10 +376,10 @@
</span><span class="cx">     # Add defaults for some fields that should have them but didn't.
</span><span class="cx">     $dbh-&gt;bz_alter_column('bugs', 'status_whiteboard',
</span><span class="cx">         {TYPE =&gt; 'MEDIUMTEXT', NOTNULL =&gt; 1, DEFAULT =&gt; &quot;''&quot;});
</span><del>-    $dbh-&gt;bz_alter_column('bugs', 'keywords',
-        {TYPE =&gt; 'MEDIUMTEXT', NOTNULL =&gt; 1, DEFAULT =&gt; &quot;''&quot;});
-    $dbh-&gt;bz_alter_column('bugs', 'votes',
-                          {TYPE =&gt; 'INT3', NOTNULL =&gt; 1, DEFAULT =&gt; '0'});
</del><ins>+    if ($dbh-&gt;bz_column_info('bugs', 'votes')) {
+        $dbh-&gt;bz_alter_column('bugs', 'votes',
+                              {TYPE =&gt; 'INT3', NOTNULL =&gt; 1, DEFAULT =&gt; '0'});
+    }
</ins><span class="cx"> 
</span><span class="cx">     $dbh-&gt;bz_alter_column('bugs', 'lastdiffed', {TYPE =&gt; 'DATETIME'});
</span><span class="cx"> 
</span><span class="lines">@@ -398,23 +433,16 @@
</span><span class="cx">     _fix_attachments_submitter_id_idx();
</span><span class="cx">     _copy_attachments_thedata_to_attach_data();
</span><span class="cx">     _fix_broken_all_closed_series();
</span><del>-
</del><span class="cx">     # 2005-08-14 bugreport@peshkin.net -- Bug 304583
</span><span class="cx">     # Get rid of leftover DERIVED group permissions
</span><span class="cx">     use constant GRANT_DERIVED =&gt; 1;
</span><span class="cx">     $dbh-&gt;do(&quot;DELETE FROM user_group_map WHERE grant_type = &quot; . GRANT_DERIVED);
</span><span class="cx"> 
</span><ins>+    _rederive_regex_groups();
+
</ins><span class="cx">     # PUBLIC is a reserved word in Oracle.
</span><span class="cx">     $dbh-&gt;bz_rename_column('series', 'public', 'is_public');
</span><span class="cx"> 
</span><del>-    # 2005-09-28 bugreport@peshkin.net Bug 149504
-    $dbh-&gt;bz_add_column('attachments', 'isurl',
-                        {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1, DEFAULT =&gt; 0});
-
-    # 2005-10-21 LpSolit@gmail.com - Bug 313020
-    $dbh-&gt;bz_add_column('namedqueries', 'query_type',
-                        {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1, DEFAULT =&gt; 0});
-
</del><span class="cx">     # 2005-11-04 LpSolit@gmail.com - Bug 305927
</span><span class="cx">     $dbh-&gt;bz_alter_column('groups', 'userregexp',
</span><span class="cx">                           {TYPE =&gt; 'TINYTEXT', NOTNULL =&gt; 1, DEFAULT =&gt; &quot;''&quot;});
</span><span class="lines">@@ -441,14 +469,21 @@
</span><span class="cx">     _move_data_nomail_into_db();
</span><span class="cx"> 
</span><span class="cx">     # The products table lacked sensible defaults.
</span><del>-    $dbh-&gt;bz_alter_column('products', 'milestoneurl',
-                          {TYPE =&gt; 'TINYTEXT', NOTNULL =&gt; 1, DEFAULT =&gt; &quot;''&quot;});
-    $dbh-&gt;bz_alter_column('products', 'disallownew',
-                          {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1,  DEFAULT =&gt; 0});
-    $dbh-&gt;bz_alter_column('products', 'votesperuser', 
-                          {TYPE =&gt; 'INT2', NOTNULL =&gt; 1, DEFAULT =&gt; 0});
-    $dbh-&gt;bz_alter_column('products', 'votestoconfirm',
-                          {TYPE =&gt; 'INT2', NOTNULL =&gt; 1, DEFAULT =&gt; 0});
</del><ins>+    if ($dbh-&gt;bz_column_info('products', 'milestoneurl')) {
+        $dbh-&gt;bz_alter_column('products', 'milestoneurl',
+            {TYPE =&gt; 'TINYTEXT', NOTNULL =&gt; 1, DEFAULT =&gt; &quot;''&quot;});
+    }
+    if ($dbh-&gt;bz_column_info('products', 'disallownew')){
+        $dbh-&gt;bz_alter_column('products', 'disallownew',
+                              {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1,  DEFAULT =&gt; 0});
+    
+        if ($dbh-&gt;bz_column_info('products', 'votesperuser')) {
+            $dbh-&gt;bz_alter_column('products', 'votesperuser', 
+                {TYPE =&gt; 'INT2', NOTNULL =&gt; 1, DEFAULT =&gt; 0});
+            $dbh-&gt;bz_alter_column('products', 'votestoconfirm',
+                {TYPE =&gt; 'INT2', NOTNULL =&gt; 1, DEFAULT =&gt; 0});
+        }
+    }
</ins><span class="cx"> 
</span><span class="cx">     # 2006-08-04 LpSolit@gmail.com - Bug 305941
</span><span class="cx">     $dbh-&gt;bz_drop_column('profiles', 'refreshed_when');
</span><span class="lines">@@ -501,7 +536,7 @@
</span><span class="cx">     _fix_uppercase_index_names();
</span><span class="cx"> 
</span><span class="cx">     # 2007-05-17 LpSolit@gmail.com - Bug 344965
</span><del>-    _initialize_workflow($old_params);
</del><ins>+    _initialize_workflow_for_upgrade($old_params);
</ins><span class="cx"> 
</span><span class="cx">     # 2007-08-08 LpSolit@gmail.com - Bug 332149
</span><span class="cx">     $dbh-&gt;bz_add_column('groups', 'icon_url', {TYPE =&gt; 'TINYTEXT'});
</span><span class="lines">@@ -515,10 +550,6 @@
</span><span class="cx">     # 2007-09-09 LpSolit@gmail.com - Bug 99215
</span><span class="cx">     _fix_attachment_modification_date();
</span><span class="cx"> 
</span><del>-    # This had the wrong definition in DB::Schema.
-    $dbh-&gt;bz_alter_column('namedqueries', 'query_type',
-                          {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1, DEFAULT =&gt; 0});
-
</del><span class="cx">     $dbh-&gt;bz_drop_index('longdescs', 'longdescs_thetext_idx');
</span><span class="cx">     _populate_bugs_fulltext();
</span><span class="cx"> 
</span><span class="lines">@@ -526,12 +557,131 @@
</span><span class="cx">     $dbh-&gt;bz_alter_column('series', 'query',
</span><span class="cx">         { TYPE =&gt; 'MEDIUMTEXT', NOTNULL =&gt; 1 });
</span><span class="cx"> 
</span><ins>+    # Add FK to multi select field tables
+    _add_foreign_keys_to_multiselects();
+
+    # 2008-07-28 tfu@redhat.com - Bug 431669
+    $dbh-&gt;bz_alter_column('group_control_map', 'product_id',
+        { TYPE =&gt; 'INT2', NOTNULL =&gt; 1 });
+
+    # 2008-09-07 LpSolit@gmail.com - Bug 452893
+    _fix_illegal_flag_modification_dates();
+
+    _add_visiblity_value_to_value_tables();
+
+    # 2009-03-02 arbingersys@gmail.com - Bug 423613
+    _add_extern_id_index();
+
+    # 2009-03-31 LpSolit@gmail.com - Bug 478972
+    $dbh-&gt;bz_alter_column('group_control_map', 'entry',
+                          {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1, DEFAULT =&gt; 'FALSE'});
+    $dbh-&gt;bz_alter_column('group_control_map', 'canedit',
+                          {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1, DEFAULT =&gt; 'FALSE'});
+
+    # 2009-01-16 oreomike@gmail.com - Bug 302420
+    $dbh-&gt;bz_add_column('whine_events', 'mailifnobugs',
+        { TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1, DEFAULT =&gt; 'FALSE'});
+        
+    _convert_disallownew_to_isactive();
+
+    $dbh-&gt;bz_alter_column('bugs_activity', 'added', 
+        { TYPE =&gt; 'varchar(255)' });
+    $dbh-&gt;bz_add_index('bugs_activity', 'bugs_activity_added_idx', ['added']);
+
+    # 2009-09-28 LpSolit@gmail.com - Bug 519032
+    $dbh-&gt;bz_drop_column('series', 'last_viewed');
+
+    # 2009-09-28 LpSolit@gmail.com - Bug 399073
+    _fix_logincookies_ipaddr();
+
+    # 2009-11-01 LpSolit@gmail.com - Bug 525025
+    _fix_invalid_custom_field_names();
+
+    _set_attachment_comment_types();
+
+    $dbh-&gt;bz_drop_column('products', 'milestoneurl');
+
+    _add_allows_unconfirmed_to_product_table();
+    _convert_flagtypes_fks_to_set_null();
+    _fix_decimal_types();
+    _fix_series_creator_fk();
+
+    # 2009-11-14 dkl@redhat.com - Bug 310450
+    $dbh-&gt;bz_add_column('bugs_activity', 'comment_id', {TYPE =&gt; 'INT3'});
+
+    # 2010-04-07 LpSolit@gmail.com - Bug 69621
+    $dbh-&gt;bz_drop_column('bugs', 'keywords');
+    
+    # 2010-05-07 ewong@pw-wspx.org - Bug 463945
+    $dbh-&gt;bz_alter_column('group_control_map', 'membercontrol',
+                          {TYPE =&gt; 'INT1', NOTNULL =&gt; 1, DEFAULT =&gt; CONTROLMAPNA});
+    $dbh-&gt;bz_alter_column('group_control_map', 'othercontrol',
+                          {TYPE =&gt; 'INT1', NOTNULL =&gt; 1, DEFAULT =&gt; CONTROLMAPNA});
+
+    # Add NOT NULL to some columns that need it, and DEFAULT to
+    # attachments.ispatch.
+    $dbh-&gt;bz_alter_column('attachments', 'ispatch', 
+        { TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1, DEFAULT =&gt; 'FALSE'});
+    $dbh-&gt;bz_alter_column('keyworddefs', 'description',
+                          { TYPE =&gt; 'MEDIUMTEXT', NOTNULL =&gt; 1 }, '');
+    $dbh-&gt;bz_alter_column('products', 'description',
+                          { TYPE =&gt; 'MEDIUMTEXT', NOTNULL =&gt; 1 }, '');
+
+    # Change the default of allows_unconfirmed to TRUE as part
+    # of the new workflow.
+    $dbh-&gt;bz_alter_column('products', 'allows_unconfirmed',
+        { TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1, DEFAULT =&gt; 'TRUE' });
+
+    # 2010-07-18 LpSolit@gmail.com - Bug 119703
+    _remove_attachment_isurl();
+
+    # 2009-05-07 ghendricks@novell.com - Bug 77193
+    _add_isactive_to_product_fields();
+
+    # 2010-10-09 LpSolit@gmail.com - Bug 505165
+    $dbh-&gt;bz_alter_column('flags', 'setter_id', {TYPE =&gt; 'INT3', NOTNULL =&gt; 1});
+
+    # 2010-10-09 LpSolit@gmail.com - Bug 451735
+    _fix_series_indexes();
+
+    $dbh-&gt;bz_add_column('bug_see_also', 'id',
+        {TYPE =&gt; 'MEDIUMSERIAL', NOTNULL =&gt; 1, PRIMARYKEY =&gt; 1});
+
+    _rename_tags_to_tag();
+
+    # 2011-01-29 LpSolit@gmail.com - Bug 616185
+    _migrate_user_tags();
+
+    _populate_bug_see_also_class();
+
+    # 2011-06-15 dkl@mozilla.com - Bug 658929
+    _migrate_disabledtext_boolean();
+
+    # 2011-10-11 miketosh - Bug 690173
+    _on_delete_set_null_for_audit_log_userid();
+
+    # 2011-11-28 dkl@mozilla.com - Bug 685611
+    _fix_notnull_defaults();
+
+    # 2012-02-15 LpSolit@gmail.com - Bug 722113
+    if ($dbh-&gt;bz_index_info('profile_search', 'profile_search_user_id')) {
+        $dbh-&gt;bz_drop_index('profile_search', 'profile_search_user_id');
+        $dbh-&gt;bz_add_index('profile_search', 'profile_search_user_id_idx', [qw(user_id)]);
+    }
+
</ins><span class="cx">     ################################################################
</span><span class="cx">     # New --TABLE-- changes should go *** A B O V E *** this point #
</span><span class="cx">     ################################################################
</span><span class="cx"> 
</span><del>-    Bugzilla::Hook::process('install-update_db');
</del><ins>+    Bugzilla::Hook::process('install_update_db');
</ins><span class="cx"> 
</span><ins>+    # We do this here because otherwise the foreign key from 
+    # products.classification_id to classifications.id will fail
+    # (because products.classification_id defaults to &quot;1&quot;, so on upgraded
+    # installations it's already been set before the first Classification
+    # exists).
+    Bugzilla::Install::create_default_classification();
+
</ins><span class="cx">     $dbh-&gt;bz_setup_foreign_keys();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -549,10 +699,11 @@
</span><span class="cx">     $dbh-&gt;bz_add_column('bugs', 'qa_contact', {TYPE =&gt; 'INT3'});
</span><span class="cx">     $dbh-&gt;bz_add_column('bugs', 'status_whiteboard',
</span><span class="cx">                        {TYPE =&gt; 'MEDIUMTEXT', NOTNULL =&gt; 1, DEFAULT =&gt; &quot;''&quot;});
</span><del>-    $dbh-&gt;bz_add_column('products', 'disallownew',
-                        {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1}, 0);
-    $dbh-&gt;bz_add_column('products', 'milestoneurl',
-                        {TYPE =&gt; 'TINYTEXT', NOTNULL =&gt; 1}, '');
</del><ins>+    if (!$dbh-&gt;bz_column_info('products', 'isactive')){
+        $dbh-&gt;bz_add_column('products', 'disallownew',
+                            {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1}, 0);
+    }
+
</ins><span class="cx">     $dbh-&gt;bz_add_column('components', 'initialqacontact',
</span><span class="cx">                         {TYPE =&gt; 'TINYTEXT'});
</span><span class="cx">     $dbh-&gt;bz_add_column('components', 'description',
</span><span class="lines">@@ -570,14 +721,14 @@
</span><span class="cx">     # (P.S. All is not lost; it appears that the latest betas of MySQL 
</span><span class="cx">     # support a new table format which will allow 32 indices.)
</span><span class="cx"> 
</span><del>-    $dbh-&gt;bz_drop_column('bugs', 'area');
-    if (!$dbh-&gt;bz_column_info('bugs', 'votes')) {
</del><ins>+    if ($dbh-&gt;bz_column_info('bugs', 'area')) {
+        $dbh-&gt;bz_drop_column('bugs', 'area');
</ins><span class="cx">         $dbh-&gt;bz_add_column('bugs', 'votes', {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
</span><span class="cx">                                               DEFAULT =&gt; 0});
</span><span class="cx">         $dbh-&gt;bz_add_index('bugs', 'bugs_votes_idx', [qw(votes)]);
</span><ins>+        $dbh-&gt;bz_add_column('products', 'votesperuser',
+                            {TYPE =&gt; 'INT2', NOTNULL =&gt; 1}, 0);
</ins><span class="cx">     }
</span><del>-    $dbh-&gt;bz_add_column('products', 'votesperuser',
-                        {TYPE =&gt; 'INT2', NOTNULL =&gt; 1}, 0);
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _update_product_name_definition {
</span><span class="lines">@@ -604,46 +755,6 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _add_bug_keyword_cache {
-    my $dbh = Bugzilla-&gt;dbh;
-    # 2000-01-16 Added a &quot;keywords&quot; field to the bugs table, which
-    # contains a string copy of the entries of the keywords table for this
-    # bug.  This is so that I can easily sort and display a keywords
-    # column in bug lists.
-
-    if (!$dbh-&gt;bz_column_info('bugs', 'keywords')) {
-        $dbh-&gt;bz_add_column('bugs', 'keywords',
-            {TYPE =&gt; 'MEDIUMTEXT', NOTNULL =&gt; 1, DEFAULT =&gt; &quot;''&quot;});
-
-        my @kwords;
-        print &quot;Making sure 'keywords' field of table 'bugs' is empty...\n&quot;;
-        $dbh-&gt;do(&quot;UPDATE bugs SET keywords = '' WHERE keywords != ''&quot;);
-        print &quot;Repopulating 'keywords' field of table 'bugs'...\n&quot;;
-        my $sth = $dbh-&gt;prepare(&quot;SELECT keywords.bug_id, keyworddefs.name &quot; .
-                                  &quot;FROM keywords, keyworddefs &quot; .
-                                 &quot;WHERE keyworddefs.id = keywords.keywordid &quot; .
-                              &quot;ORDER BY keywords.bug_id, keyworddefs.name&quot;);
-        $sth-&gt;execute;
-        my @list;
-        my $bugid = 0;
-        my @row;
-        while (1) {
-            my ($b, $k) = ($sth-&gt;fetchrow_array());
-            if (!defined $b || $b ne $bugid) {
-                if (@list) {
-                    $dbh-&gt;do(&quot;UPDATE bugs SET keywords = &quot; .
-                             $dbh-&gt;quote(join(', ', @list)) .
-                             &quot; WHERE bug_id = $bugid&quot;);
-                }
-                last if !$b;
-                $bugid = $b;
-                @list = ();
-            }
-            push(@list, $k);
-        }
-    }
-}
-
</del><span class="cx"> # A helper for the function below.
</span><span class="cx"> sub _write_one_longdesc {
</span><span class="cx">     my ($id, $who, $when, $buffer) = (@_);
</span><span class="lines">@@ -812,9 +923,11 @@
</span><span class="cx">                            [&quot;votes&quot;, &quot;who&quot;],
</span><span class="cx">                            [&quot;longdescs&quot;, &quot;who&quot;]) {
</span><span class="cx">                 my ($table, $field) = (@$i);
</span><del>-                print &quot;   Updating $table.$field...\n&quot;;
-                $dbh-&gt;do(&quot;UPDATE $table SET $field = $u1 &quot; .
-                          &quot;WHERE $field = $u2&quot;);
</del><ins>+                if ($dbh-&gt;bz_table_info($table)) {
+                    print &quot;   Updating $table.$field...\n&quot;;
+                    $dbh-&gt;do(&quot;UPDATE $table SET $field = $u1 &quot; .
+                              &quot;WHERE $field = $u2&quot;);
+                }
</ins><span class="cx">             }
</span><span class="cx">             $dbh-&gt;do(&quot;DELETE FROM profiles WHERE userid = $u2&quot;);
</span><span class="cx">         }
</span><span class="lines">@@ -972,6 +1085,7 @@
</span><span class="cx">     # 2000-11-27 For Bugzilla 2.5 and later. Copy data from 'comments' to
</span><span class="cx">     # 'longdescs' - the new name of the comments table.
</span><span class="cx">     if ($dbh-&gt;bz_table_info('comments')) {
</span><ins>+        print &quot;Copying data from 'comments' to 'longdescs'...\n&quot;;
</ins><span class="cx">         my $quoted_when = $dbh-&gt;quote_identifier('when');
</span><span class="cx">         $dbh-&gt;do(&quot;INSERT INTO longdescs (bug_when, bug_id, who, thetext)
</span><span class="cx">                   SELECT $quoted_when, bug_id, who, comment
</span><span class="lines">@@ -1179,13 +1293,14 @@
</span><span class="cx">     #
</span><span class="cx">     # Use the ip, not the hostname, in the logincookies table
</span><span class="cx">     if ($dbh-&gt;bz_column_info(&quot;logincookies&quot;, &quot;hostname&quot;)) {
</span><ins>+        print &quot;Clearing the logincookies table...\n&quot;;
</ins><span class="cx">         # We've changed what we match against, so all entries are now invalid
</span><span class="cx">         $dbh-&gt;do(&quot;DELETE FROM logincookies&quot;);
</span><span class="cx"> 
</span><span class="cx">         # Now update the logincookies schema
</span><span class="cx">         $dbh-&gt;bz_drop_column(&quot;logincookies&quot;, &quot;hostname&quot;);
</span><span class="cx">         $dbh-&gt;bz_add_column(&quot;logincookies&quot;, &quot;ipaddr&quot;,
</span><del>-                            {TYPE =&gt; 'varchar(40)', NOTNULL =&gt; 1}, '');
</del><ins>+                            {TYPE =&gt; 'varchar(40)'});
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1204,15 +1319,7 @@
</span><span class="cx">             $dbh-&gt;do(&quot;INSERT INTO quips (quip) VALUES (?)&quot;, undef, $_);
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        print &lt;&lt;EOT;
-
-Quips are now stored in the database, rather than in an external file.
-The quips previously stored in $datadir/comments have been copied into
-the database, and that file has been renamed to $datadir/comments.bak
-You may delete the renamed file once you have confirmed that all your
-quips were moved successfully.
-
-EOT
</del><ins>+        print &quot;\n&quot;, install_string('update_quips', { data =&gt; $datadir }), &quot;\n&quot;;
</ins><span class="cx">         $comments-&gt;close;
</span><span class="cx">         rename(&quot;$datadir/comments&quot;, &quot;$datadir/comments.bak&quot;)
</span><span class="cx">             || warn &quot;Failed to rename: $!&quot;;
</span><span class="lines">@@ -1786,9 +1893,9 @@
</span><span class="cx">                 if (length($tryflagname) &gt; 50) {
</span><span class="cx">                     my $lastchanceflagname = (substr $tryflagname, 0, 47) . '...';
</span><span class="cx">                     if (defined($flagtypes{$lastchanceflagname})) {
</span><del>-                        print &quot;  ... last attempt as \&quot;$lastchanceflagname\&quot; still failed.'\n&quot;,
-                              &quot;Rename the flag by hand and run checksetup.pl again.\n&quot;;
-                        die(&quot;Bad flag type name $flagname&quot;);
</del><ins>+                        print &quot;  ... last attempt as \&quot;$lastchanceflagname\&quot; still failed.'\n&quot;;
+                        die install_string('update_flags_bad_name',
+                                           { flag =&gt; $flagname }), &quot;\n&quot;;
</ins><span class="cx">                     }
</span><span class="cx">                     $tryflagname = $lastchanceflagname;
</span><span class="cx">                 }
</span><span class="lines">@@ -1804,14 +1911,20 @@
</span><span class="cx"> 
</span><span class="cx"> sub _setup_usebuggroups_backward_compatibility {
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><ins>+
+    # Don't run this on newer Bugzillas. This is a reliable test because
+    # the longdescs table existed in 2.16 (which had usebuggroups)
+    # but not in 2.18, and this code happens between 2.16 and 2.18.
+    return if $dbh-&gt;bz_column_info('longdescs', 'already_wrapped');
+
</ins><span class="cx">     # 2002-11-24 - bugreport@peshkin.net - bug 147275
</span><span class="cx">     #
</span><span class="cx">     # If group_control_map is empty, backward-compatibility
</span><span class="cx">     # usebuggroups-equivalent records should be created.
</span><del>-    my $entry = Bugzilla-&gt;params-&gt;{'useentrygroupdefault'};
</del><span class="cx">     my ($maps_exist) = $dbh-&gt;selectrow_array(
</span><span class="cx">         &quot;SELECT DISTINCT 1 FROM group_control_map&quot;);
</span><span class="cx">     if (!$maps_exist) {
</span><ins>+        print &quot;Converting old usebuggroups controls...\n&quot;;
</ins><span class="cx">         # Initially populate group_control_map.
</span><span class="cx">         # First, get all the existing products and their groups.
</span><span class="cx">         my $sth = $dbh-&gt;prepare(&quot;SELECT groups.id, products.id, groups.name,
</span><span class="lines">@@ -1825,11 +1938,9 @@
</span><span class="cx">             if ($groupname eq $productname) {
</span><span class="cx">                 # Product and group have same name.
</span><span class="cx">                 $dbh-&gt;do(&quot;INSERT INTO group_control_map &quot; .
</span><del>-                         &quot;(group_id, product_id, entry, membercontrol, &quot; .
-                         &quot;othercontrol, canedit) &quot; .
-                         &quot;VALUES ($groupid, $productid, $entry, &quot; .
-                         CONTROLMAPDEFAULT . &quot;, &quot; .
-                         CONTROLMAPNA . &quot;, 0)&quot;);
</del><ins>+                         &quot;(group_id, product_id, membercontrol, othercontrol) &quot; .
+                         &quot;VALUES (?, ?, ?, ?)&quot;, undef,
+                         ($groupid, $productid, CONTROLMAPDEFAULT, CONTROLMAPNA));
</ins><span class="cx">             } else {
</span><span class="cx">                 # See if this group is a product group at all.
</span><span class="cx">                 my $sth2 = $dbh-&gt;prepare(&quot;SELECT id FROM products 
</span><span class="lines">@@ -1840,11 +1951,9 @@
</span><span class="cx">                     # If there is no product with the same name as this
</span><span class="cx">                     # group, then it is permitted for all products.
</span><span class="cx">                     $dbh-&gt;do(&quot;INSERT INTO group_control_map &quot; .
</span><del>-                             &quot;(group_id, product_id, entry, membercontrol, &quot; .
-                             &quot;othercontrol, canedit) &quot; .
-                             &quot;VALUES ($groupid, $productid, 0, &quot; .
-                             CONTROLMAPSHOWN . &quot;, &quot; .
-                             CONTROLMAPNA . &quot;, 0)&quot;);
</del><ins>+                             &quot;(group_id, product_id, membercontrol, othercontrol) &quot; .
+                             &quot;VALUES (?, ?, ?, ?)&quot;, undef,
+                             ($groupid, $productid, CONTROLMAPSHOWN, CONTROLMAPNA));
</ins><span class="cx">                 }
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="lines">@@ -1916,9 +2025,11 @@
</span><span class="cx">         my $all_name = &quot;-All-&quot;;
</span><span class="cx">         my $open_name = &quot;All Open&quot;;
</span><span class="cx"> 
</span><ins>+        $dbh-&gt;bz_start_transaction();
</ins><span class="cx">         my $products = $dbh-&gt;selectall_arrayref(&quot;SELECT name FROM products&quot;);
</span><span class="cx"> 
</span><span class="cx">         foreach my $product ((map { $_-&gt;[0] } @$products), &quot;-All-&quot;) {
</span><ins>+            print &quot;$product:\n&quot;;
</ins><span class="cx">             # First, create the series
</span><span class="cx">             my %queries;
</span><span class="cx">             my %seriesids;
</span><span class="lines">@@ -1967,8 +2078,9 @@
</span><span class="cx">             my %data;
</span><span class="cx">             my $last_date = &quot;&quot;;
</span><span class="cx"> 
</span><del>-            while (&lt;$in&gt;) {
-                if (/^(\d+\|.*)/) {
</del><ins>+            my @lines = &lt;$in&gt;;
+            while (my $line = shift @lines) {
+                if ($line =~ /^(\d+\|.*)/) {
</ins><span class="cx">                     my @numbers = split(/\||\r/, $1);
</span><span class="cx"> 
</span><span class="cx">                     # Only take the first line for each date; it was possible to
</span><span class="lines">@@ -1991,6 +2103,9 @@
</span><span class="cx"> 
</span><span class="cx">             $in-&gt;close;
</span><span class="cx"> 
</span><ins>+            my $total_items = (scalar(@fields) + 1) 
+                              * scalar(keys %{ $data{'NEW'} });
+            my $count = 0;
</ins><span class="cx">             foreach my $field (@fields, $open_name) {
</span><span class="cx">                 # Insert values into series_data: series_id, date, value
</span><span class="cx">                 my %fielddata = %{$data{$field}};
</span><span class="lines">@@ -2002,6 +2117,8 @@
</span><span class="cx">                     # We prepared this above
</span><span class="cx">                     $seriesdatasth-&gt;execute($seriesids{$field},
</span><span class="cx">                                             $date, $fielddata{$date} || 0);
</span><ins>+                    indicate_progress({ total =&gt; $total_items, 
+                                        current =&gt; ++$count, every =&gt; 100 });
</ins><span class="cx">                 }
</span><span class="cx">             }
</span><span class="cx"> 
</span><span class="lines">@@ -2028,6 +2145,8 @@
</span><span class="cx">                 }
</span><span class="cx">             }
</span><span class="cx">         }
</span><ins>+
+        $dbh-&gt;bz_commit_transaction();
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -2096,7 +2215,7 @@
</span><span class="cx">     # and attachment.cgi now takes them out, but old ones need converting.
</span><span class="cx">     my $ref = $dbh-&gt;bz_column_info(&quot;attachments&quot;, &quot;filename&quot;);
</span><span class="cx">     if ($ref-&gt;{TYPE} ne 'varchar(100)') {
</span><del>-        print &quot;Removing paths from filenames in attachments table...\n&quot;;
</del><ins>+        print &quot;Removing paths from filenames in attachments table...&quot;;
</ins><span class="cx"> 
</span><span class="cx">         my $sth = $dbh-&gt;prepare(&quot;SELECT attach_id, filename FROM attachments &quot; .
</span><span class="cx">             &quot;WHERE &quot; . $dbh-&gt;sql_position(q{'/'}, 'filename') . &quot; &gt; 0 OR &quot; .
</span><span class="lines">@@ -2112,8 +2231,6 @@
</span><span class="cx"> 
</span><span class="cx">         print &quot;Done.\n&quot;;
</span><span class="cx"> 
</span><del>-        print &quot;Resizing attachments.filename from mediumtext to&quot;,
-              &quot; varchar(100).\n&quot;;
</del><span class="cx">         $dbh-&gt;bz_alter_column(&quot;attachments&quot;, &quot;filename&quot;,
</span><span class="cx">                               {TYPE =&gt; 'varchar(100)', NOTNULL =&gt; 1});
</span><span class="cx">     }
</span><span class="lines">@@ -2127,9 +2244,9 @@
</span><span class="cx">     #
</span><span class="cx">     # Renaming the 'count' column in the votes table because Sybase doesn't
</span><span class="cx">     # like it
</span><del>-    if ($dbh-&gt;bz_column_info('votes', 'count')) {
-        $dbh-&gt;bz_rename_column('votes', 'count', 'vote_count');
-    }
</del><ins>+    return if !$dbh-&gt;bz_table_info('votes');
+    return if $dbh-&gt;bz_column_info('votes', 'count');
+    $dbh-&gt;bz_rename_column('votes', 'count', 'vote_count');
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _fix_group_with_empty_name {
</span><span class="lines">@@ -2169,17 +2286,9 @@
</span><span class="cx">     my ($source, $target) = @_;
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx"> 
</span><del>-    my $sth1 = $dbh-&gt;prepare(&quot;SELECT user_id, relationship FROM email_setting
-                              WHERE event = $source&quot;);
-    my $sth2 = $dbh-&gt;prepare(&quot;INSERT into email_setting &quot; .
-                             &quot;(user_id, relationship, event) VALUES (&quot; .
-                             &quot;?, ?, $target)&quot;);
-
-    $sth1-&gt;execute();
-
-    while (my ($userid, $relationship) = $sth1-&gt;fetchrow_array()) {
-        $sth2-&gt;execute($userid, $relationship);
-    }
</del><ins>+    $dbh-&gt;do(&quot;INSERT INTO email_setting (user_id, relationship, event)
+                   SELECT user_id, relationship, $target FROM email_setting
+                    WHERE event = $source&quot;);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _migrate_email_prefs_to_new_table {
</span><span class="lines">@@ -2195,7 +2304,9 @@
</span><span class="cx">                              &quot;Reporter&quot;  =&gt; REL_REPORTER,
</span><span class="cx">                              &quot;QAcontact&quot; =&gt; REL_QA,
</span><span class="cx">                              &quot;CClist&quot;    =&gt; REL_CC,
</span><del>-                             &quot;Voter&quot;     =&gt; REL_VOTER);
</del><ins>+                             # REL_VOTER was &quot;4&quot; before it was moved to an
+                             #  extension.
+                             &quot;Voter&quot;     =&gt; 4);
</ins><span class="cx"> 
</span><span class="cx">         my %events = (&quot;Removeme&quot;    =&gt; EVT_ADDED_REMOVED,
</span><span class="cx">                       &quot;Comments&quot;    =&gt; EVT_COMMENT,
</span><span class="lines">@@ -2295,10 +2406,11 @@
</span><span class="cx"> 
</span><span class="cx">     foreach my $desc (keys %events) {
</span><span class="cx">         my $event = $events{$desc};
</span><del>-        my $sth = $dbh-&gt;prepare(&quot;SELECT COUNT(*) FROM email_setting 
-                                  WHERE event = $event&quot;);
-        $sth-&gt;execute();
-        if (!($sth-&gt;fetchrow_arrayref()-&gt;[0])) {
</del><ins>+        my $have_events = $dbh-&gt;selectrow_array(
+            &quot;SELECT 1 FROM email_setting WHERE event = $event &quot;
+            . $dbh-&gt;sql_limit(1));
+
+        if (!$have_events) {
</ins><span class="cx">             # No settings in the table yet, so we assume that this is the
</span><span class="cx">             # first time it's being set.
</span><span class="cx">             print &quot;Initializing \&quot;$desc\&quot; email_setting ...\n&quot;;
</span><span class="lines">@@ -2562,6 +2674,54 @@
</span><span class="cx">     } # if (@$broken_nonopen_series)
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# This needs to happen at two times: when we upgrade from 2.16 (thus creating 
+# user_group_map), and when we kill derived gruops in the DB.
+sub _rederive_regex_groups {
+    my $dbh = Bugzilla-&gt;dbh;
+
+    my $regex_groups_exist = $dbh-&gt;selectrow_array(
+        &quot;SELECT 1 FROM groups WHERE userregexp = '' &quot; . $dbh-&gt;sql_limit(1));
+    return if !$regex_groups_exist;
+
+    my $regex_derivations = $dbh-&gt;selectrow_array(
+        'SELECT 1 FROM user_group_map WHERE grant_type = ' . GRANT_REGEXP 
+        . ' ' . $dbh-&gt;sql_limit(1));
+    return if $regex_derivations;
+
+    print &quot;Deriving regex group memberships...\n&quot;;
+
+    # Re-evaluate all regexps, to keep them up-to-date.
+    my $sth = $dbh-&gt;prepare(
+        &quot;SELECT profiles.userid, profiles.login_name, groups.id, 
+                groups.userregexp, user_group_map.group_id
+           FROM (profiles CROSS JOIN groups)
+                LEFT JOIN user_group_map
+                       ON user_group_map.user_id = profiles.userid
+                          AND user_group_map.group_id = groups.id
+                          AND user_group_map.grant_type = ?
+          WHERE userregexp != '' OR user_group_map.group_id IS NOT NULL&quot;);
+
+    my $sth_add = $dbh-&gt;prepare(
+        &quot;INSERT INTO user_group_map (user_id, group_id, isbless, grant_type)
+              VALUES (?, ?, 0, &quot; . GRANT_REGEXP . &quot;)&quot;);
+
+    my $sth_del = $dbh-&gt;prepare(
+        &quot;DELETE FROM user_group_map
+          WHERE user_id  = ? AND group_id = ? AND isbless = 0 
+                AND grant_type = &quot; . GRANT_REGEXP);
+
+    $sth-&gt;execute(GRANT_REGEXP);
+    while (my ($uid, $login, $gid, $rexp, $present) = 
+               $sth-&gt;fetchrow_array()) 
+    {
+        if ($login =~ m/$rexp/i) {
+            $sth_add-&gt;execute($uid, $gid) unless $present;
+        } else {
+            $sth_del-&gt;execute($uid, $gid) if $present;
+        }
+    }
+}
+
</ins><span class="cx"> sub _clean_control_characters_from_short_desc {
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx"> 
</span><span class="lines">@@ -2619,12 +2779,7 @@
</span><span class="cx">                FROM bugs WHERE CHAR_LENGTH(short_desc) &gt; 255');
</span><span class="cx"> 
</span><span class="cx">         if (@$long_summary_bugs) {
</span><del>-            print &lt;&lt;EOT;
-
-WARNING: Some of your bugs had summaries longer than 255 characters.
-They have had their original summary copied into a comment, and then
-the summary was truncated to 255 characters. The affected bug numbers were:
-EOT
</del><ins>+            print &quot;\n&quot;, install_string('update_summary_truncated');
</ins><span class="cx">             my $comment_sth = $dbh-&gt;prepare(
</span><span class="cx">                 'INSERT INTO longdescs (bug_id, who, thetext, bug_when)
</span><span class="cx">                       VALUES (?, ?, ?, NOW())');
</span><span class="lines">@@ -2633,10 +2788,9 @@
</span><span class="cx">             my @affected_bugs;
</span><span class="cx">             foreach my $bug (@$long_summary_bugs) {
</span><span class="cx">                 my ($bug_id, $summary, $reporter_id) = @$bug;
</span><del>-                my $summary_comment = &quot;The original summary for this bug&quot;
-                   . &quot; was longer than 255 characters, and so it was truncated&quot;
-                   . &quot; when Bugzilla was upgraded. The original summary was:&quot;
-                   . &quot;\n\n$summary&quot;;
</del><ins>+                my $summary_comment =
+                    install_string('update_summary_truncate_comment',
+                                   { summary =&gt; $summary });
</ins><span class="cx">                 $comment_sth-&gt;execute($bug_id, $reporter_id, $summary_comment);
</span><span class="cx">                 my $short_summary = substr($summary, 0, 252) . &quot;...&quot;;
</span><span class="cx">                 $desc_sth-&gt;execute($short_summary, $bug_id);
</span><span class="lines">@@ -2709,24 +2863,20 @@
</span><span class="cx">                                       SET disable_mail = 1
</span><span class="cx">                                     WHERE userid = ?');
</span><span class="cx">         foreach my $user_to_check (keys %nomail) {
</span><del>-            my $uid;
-            if ($uid = Bugzilla::User::login_to_id($user_to_check)) {
-                my $user = new Bugzilla::User($uid);
-                print &quot;\tDisabling email for user &quot;, $user-&gt;email, &quot;\n&quot;;
-                $query-&gt;execute($user-&gt;id);
-                delete $nomail{$user-&gt;email};
-            }
</del><ins>+            my $uid = $dbh-&gt;selectrow_array(
+                'SELECT userid FROM profiles WHERE login_name = ?',
+                undef, $user_to_check);
+            next if !$uid;
+            print &quot;\tDisabling email for user $user_to_check\n&quot;;
+            $query-&gt;execute($uid);
+            delete $nomail{$user_to_check};
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         # If there are any nomail entries remaining, move them to nomail.bad
</span><span class="cx">         # and say something to the user.
</span><span class="cx">         if (scalar(keys %nomail)) {
</span><del>-            print &lt;&lt;EOT;
-
-WARNING: The following users were listed in data/nomail, but do not
-have an account here. The unmatched entries have been moved
-to $datadir/nomail.bad:
-EOT
</del><ins>+            print &quot;\n&quot;, install_string('update_nomail_bad',
+                                       { data =&gt; $datadir }), &quot;\n&quot;;
</ins><span class="cx">             my $nomail_bad = new IO::File(&quot;$datadir/nomail.bad&quot;, '&gt;&gt;');
</span><span class="cx">             foreach my $unknown_user (keys %nomail) {
</span><span class="cx">                 print &quot;\t$unknown_user\n&quot;;
</span><span class="lines">@@ -2795,7 +2945,7 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _initialize_workflow {
</del><ins>+sub _initialize_workflow_for_upgrade {
</ins><span class="cx">     my $old_params = shift;
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx"> 
</span><span class="lines">@@ -2808,11 +2958,8 @@
</span><span class="cx">     # and mark these statuses as 'closed', even if some of these statuses are
</span><span class="cx">     # expected to be open statuses. Bug statuses we have no information about
</span><span class="cx">     # are left as 'open'.
</span><del>-    my @closed_statuses =
-      @{$dbh-&gt;selectcol_arrayref('SELECT DISTINCT bug_status FROM bugs
-                                  WHERE resolution != ?', undef, '')};
-
-    # Append the default list of closed statuses *unless* we detect at least
</del><ins>+    #
+    # We append the default list of closed statuses *unless* we detect at least
</ins><span class="cx">     # one closed state in the DB (i.e. with is_open = 0). This would mean that
</span><span class="cx">     # the DB has already been updated at least once and maybe the admin decided
</span><span class="cx">     # that e.g. 'RESOLVED' is now an open state, in which case we don't want to
</span><span class="lines">@@ -2823,6 +2970,9 @@
</span><span class="cx">                                                    WHERE is_open = 0');
</span><span class="cx"> 
</span><span class="cx">     if (!$num_closed_states) {
</span><ins>+        my @closed_statuses =
+            @{$dbh-&gt;selectcol_arrayref('SELECT DISTINCT bug_status FROM bugs
+                                         WHERE resolution != ?', undef, '')};
</ins><span class="cx">         @closed_statuses =
</span><span class="cx">           map {$dbh-&gt;quote($_)} (@closed_statuses, qw(RESOLVED VERIFIED CLOSED));
</span><span class="cx"> 
</span><span class="lines">@@ -2831,6 +2981,11 @@
</span><span class="cx">                   join(', ', @closed_statuses) . ')');
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    # We only populate the workflow here if we're upgrading from a version
+    # before 4.0 (which is where init_workflow was added). This was the
+    # first schema change done for 4.0, so we check this.
+    return if $dbh-&gt;bz_column_info('bugs_activity', 'comment_id');
+
</ins><span class="cx">     # Populate the status_workflow table. We do nothing if the table already
</span><span class="cx">     # has entries. If all bug status transitions have been deleted, the
</span><span class="cx">     # workflow will be restored to its default schema.
</span><span class="lines">@@ -2850,7 +3005,7 @@
</span><span class="cx">         # confirmed bugs, so we use this parameter here.
</span><span class="cx">         my $reassign = $old_params-&gt;{'commentonreassign'} || 0;
</span><span class="cx"> 
</span><del>-        # This is the default workflow.
</del><ins>+        # This is the default workflow for upgrading installations.
</ins><span class="cx">         my @workflow = ([undef, 'UNCONFIRMED', $create],
</span><span class="cx">                         [undef, 'NEW', $create],
</span><span class="cx">                         [undef, 'ASSIGNED', $create],
</span><span class="lines">@@ -2894,7 +3049,25 @@
</span><span class="cx"> 
</span><span class="cx">     # Make sure the bug status used by the 'duplicate_or_move_bug_status'
</span><span class="cx">     # parameter has all the required transitions set.
</span><del>-    Bugzilla::Status::add_missing_bug_status_transitions();
</del><ins>+    my $dup_status = Bugzilla-&gt;params-&gt;{'duplicate_or_move_bug_status'};
+    my $status_id = $dbh-&gt;selectrow_array(
+        'SELECT id FROM bug_status WHERE value = ?', undef, $dup_status);
+    # There's a minor chance that this status isn't in the DB.
+    $status_id || return;
+
+    my $missing_statuses = $dbh-&gt;selectcol_arrayref(
+        'SELECT id FROM bug_status
+                        LEFT JOIN status_workflow ON old_status = id
+                                                     AND new_status = ?
+          WHERE old_status IS NULL', undef, $status_id);
+
+    my $sth = $dbh-&gt;prepare('INSERT INTO status_workflow
+                             (old_status, new_status) VALUES (?, ?)');
+
+    foreach my $old_status_id (@$missing_statuses) {
+        next if ($old_status_id == $status_id);
+        $sth-&gt;execute($old_status_id, $status_id);
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _make_lang_setting_dynamic {
</span><span class="lines">@@ -2975,11 +3148,11 @@
</span><span class="cx">           WHERE CHAR_LENGTH($field_name) &gt; ?&quot;, {Columns=&gt;[1,2]}, $max_length) };
</span><span class="cx"> 
</span><span class="cx">     if (scalar keys %contents) {
</span><del>-        print install_string('install_data_too_long',
-                             { column     =&gt; $field_name,
-                               id_column  =&gt; $id_field,
-                               table      =&gt; $table_name,
-                               max_length =&gt; $max_length });
</del><ins>+        my $error = install_string('install_data_too_long',
+                                   { column     =&gt; $field_name,
+                                     id_column  =&gt; $id_field,
+                                     table      =&gt; $table_name,
+                                     max_length =&gt; $max_length });
</ins><span class="cx">         foreach my $id (keys %contents) {
</span><span class="cx">             my $string = $contents{$id};
</span><span class="cx">             # Don't dump the whole string--it could be 16MB.
</span><span class="lines">@@ -2987,71 +3160,533 @@
</span><span class="cx">                 $string = substr($string, 0, 30) . &quot;...&quot; 
</span><span class="cx">                          . substr($string, -30) . &quot;\n&quot;;
</span><span class="cx">             }
</span><del>-            print &quot;$id: $string\n&quot;;
</del><ins>+            $error .= &quot;$id: $string\n&quot;;
</ins><span class="cx">         }
</span><del>-        exit 3;
</del><ins>+        die $error;
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub _add_foreign_keys_to_multiselects {
+    my $dbh = Bugzilla-&gt;dbh;
+
+    my $names = $dbh-&gt;selectcol_arrayref(
+        'SELECT name 
+           FROM fielddefs 
+          WHERE type = ' . FIELD_TYPE_MULTI_SELECT);
+
+    foreach my $name (@$names) {
+        $dbh-&gt;bz_add_fk(&quot;bug_$name&quot;, &quot;bug_id&quot;, 
+            {TABLE =&gt; 'bugs', COLUMN =&gt; 'bug_id', DELETE =&gt; 'CASCADE'});
+                                                
+        $dbh-&gt;bz_add_fk(&quot;bug_$name&quot;, &quot;value&quot;,
+            {TABLE  =&gt; $name, COLUMN =&gt; 'value', DELETE =&gt; 'RESTRICT'});
+    }
+}
+
+# This subroutine is used in multiple places (for times when we update
+# the text of comments), so it takes an argument, $bug_ids, which causes
+# it to update bugs_fulltext for those bug_ids instead of populating the
+# whole table.
</ins><span class="cx"> sub _populate_bugs_fulltext {
</span><ins>+    my $bug_ids = shift;
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx">     my $fulltext = $dbh-&gt;selectrow_array('SELECT 1 FROM bugs_fulltext '
</span><span class="cx">                                          . $dbh-&gt;sql_limit(1));
</span><del>-    # We only populate the table if it's empty...
-    if (!$fulltext) {
-        # ... and if there are bugs in the bugs table.
-        my $bug_ids = $dbh-&gt;selectcol_arrayref('SELECT bug_id FROM bugs');
</del><ins>+    # We only populate the table if it's empty or if we've been given a
+    # set of bug ids.
+    if ($bug_ids or !$fulltext) {
+        $bug_ids ||= $dbh-&gt;selectcol_arrayref('SELECT bug_id FROM bugs');
+        # If there are no bugs in the bugs table, there's nothing to populate.
</ins><span class="cx">         return if !@$bug_ids;
</span><ins>+        my $num_bugs = scalar @$bug_ids;
</ins><span class="cx"> 
</span><del>-        # Populating bugs_fulltext can be very slow for large installs,
-        # so we special-case any DB that supports GROUP_CONCAT, which is
-        # a much faster way to do things.
-        if (UNIVERSAL::can($dbh, 'sql_group_concat')) {
-            print &quot;Populating bugs_fulltext...&quot;;
</del><ins>+        my $command = &quot;INSERT&quot;;
+        my $where = &quot;&quot;;
+        if ($fulltext) {
+            print &quot;Updating bugs_fulltext for $num_bugs bugs...\n&quot;;
+            $where = &quot;WHERE &quot; . $dbh-&gt;sql_in('bugs.bug_id', $bug_ids);
+            # It turns out that doing a REPLACE INTO is up to 10x faster
+            # than any other possible method of updating the table, in MySQL,
+            # which matters a LOT for large installations.
+            if ($dbh-&gt;isa('Bugzilla::DB::Mysql')) {
+                $command = &quot;REPLACE&quot;;
+            }
+            else {
+                $dbh-&gt;do(&quot;DELETE FROM bugs_fulltext WHERE &quot; 
+                         . $dbh-&gt;sql_in('bug_id', $bug_ids));
+            }
+        }
+        else {
+            print &quot;Populating bugs_fulltext with $num_bugs entries...&quot;;
</ins><span class="cx">             print &quot; (this can take a long time.)\n&quot;;
</span><del>-            $dbh-&gt;do(
-                q{INSERT INTO bugs_fulltext (bug_id, short_desc, comments, 
-                                             comments_noprivate)
-                       SELECT bugs.bug_id, bugs.short_desc, }
-                     . $dbh-&gt;sql_group_concat('longdescs.thetext', '\'\n\'')
-              . ', ' . $dbh-&gt;sql_group_concat('nopriv.thetext',    '\'\n\'') .
-                      q{ FROM bugs 
-                              LEFT JOIN longdescs
-                                     ON bugs.bug_id = longdescs.bug_id
-                              LEFT JOIN longdescs AS nopriv
-                                     ON longdescs.comment_id = nopriv.comment_id
-                                        AND nopriv.isprivate = 0 }
-                     . $dbh-&gt;sql_group_by('bugs.bug_id', 'bugs.short_desc'));
</del><span class="cx">         }
</span><del>-        # The slow way, without group_concat.
</del><ins>+        my $newline = $dbh-&gt;quote(&quot;\n&quot;);
+        $dbh-&gt;do(
+         qq{$command INTO bugs_fulltext (bug_id, short_desc, comments, 
+                                         comments_noprivate)
+                   SELECT bugs.bug_id, bugs.short_desc, }
+                 . $dbh-&gt;sql_group_concat('longdescs.thetext', $newline, 0)
+          . ', ' . $dbh-&gt;sql_group_concat('nopriv.thetext',    $newline, 0) .
+                 qq{ FROM bugs 
+                          LEFT JOIN longdescs
+                                 ON bugs.bug_id = longdescs.bug_id
+                          LEFT JOIN longdescs AS nopriv
+                                 ON longdescs.comment_id = nopriv.comment_id
+                                    AND nopriv.isprivate = 0 
+                     $where }
+                 . $dbh-&gt;sql_group_by('bugs.bug_id', 'bugs.short_desc'));
+    }
+}
+
+sub _fix_illegal_flag_modification_dates {
+    my $dbh = Bugzilla-&gt;dbh;
+
+    my $rows = $dbh-&gt;do('UPDATE flags SET modification_date = creation_date
+                         WHERE modification_date &lt; creation_date');
+    # If no rows are affected, $dbh-&gt;do returns 0E0 instead of 0.
+    print &quot;$rows flags had an illegal modification date. Fixed!\n&quot; if ($rows =~ /^\d+$/);
+}
+
+sub _add_visiblity_value_to_value_tables {
+    my $dbh = Bugzilla-&gt;dbh;
+    my @standard_fields = 
+        qw(bug_status resolution priority bug_severity op_sys rep_platform);
+    my $custom_fields = $dbh-&gt;selectcol_arrayref(
+        'SELECT name FROM fielddefs WHERE custom = 1 AND type IN(?,?)',
+        undef, FIELD_TYPE_SINGLE_SELECT, FIELD_TYPE_MULTI_SELECT);
+    foreach my $field (@standard_fields, @$custom_fields) {
+        $dbh-&gt;bz_add_column($field, 'visibility_value_id', {TYPE =&gt; 'INT2'});
+        $dbh-&gt;bz_add_index($field, &quot;${field}_visibility_value_id_idx&quot;,
+                           ['visibility_value_id']);
+    }
+}
+
+sub _add_extern_id_index {
+    my $dbh = Bugzilla-&gt;dbh;
+    if (!$dbh-&gt;bz_index_info('profiles', 'profiles_extern_id_idx')) {
+        # Some Bugzillas have a multiple empty strings in extern_id,
+        # which need to be converted to NULLs before we add the index.
+        $dbh-&gt;do(&quot;UPDATE profiles SET extern_id = NULL WHERE extern_id = ''&quot;);
+        $dbh-&gt;bz_add_index('profiles', 'profiles_extern_id_idx',
+                           {TYPE =&gt; 'UNIQUE', FIELDS =&gt; [qw(extern_id)]});
+    }
+}
+
+sub _convert_disallownew_to_isactive {
+    my $dbh = Bugzilla-&gt;dbh;
+    if ($dbh-&gt;bz_column_info('products', 'disallownew')){
+        $dbh-&gt;bz_add_column('products', 'isactive', 
+                            { TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1, DEFAULT =&gt; 'TRUE'});
+        
+        # isactive is the boolean reverse of disallownew.
+        $dbh-&gt;do('UPDATE products SET isactive = 0 WHERE disallownew = 1');
+        $dbh-&gt;do('UPDATE products SET isactive = 1 WHERE disallownew = 0');
+        
+        $dbh-&gt;bz_drop_column('products','disallownew');
+    }
+}
+
+sub _fix_logincookies_ipaddr {
+    my $dbh = Bugzilla-&gt;dbh;
+    return if !$dbh-&gt;bz_column_info('logincookies', 'ipaddr')-&gt;{NOTNULL};
+
+    $dbh-&gt;bz_alter_column('logincookies', 'ipaddr', {TYPE =&gt; 'varchar(40)'});
+    $dbh-&gt;do('UPDATE logincookies SET ipaddr = NULL WHERE ipaddr = ?',
+             undef, '0.0.0.0');
+}
+
+sub _fix_invalid_custom_field_names {
+    my $fields = Bugzilla-&gt;fields({ custom =&gt; 1 });
+
+    foreach my $field (@$fields) {
+        next if $field-&gt;name =~ /^[a-zA-Z0-9_]+$/;
+        # The field name is illegal and can break the DB. Kill the field!
+        $field-&gt;set_obsolete(1);
+        print install_string('update_cf_invalid_name',
+                             { field =&gt; $field-&gt;name }), &quot;\n&quot;;
+        eval { $field-&gt;remove_from_db(); };
+        warn $@ if $@;
+    }
+}
+
+sub _set_attachment_comment_type {
+    my ($type, $string) = @_;
+    my $dbh = Bugzilla-&gt;dbh;
+    # We check if there are any comments of this type already, first, 
+    # because this is faster than a full LIKE search on the comments,
+    # and currently this will run every time we run checksetup.
+    my $test = $dbh-&gt;selectrow_array(
+        &quot;SELECT 1 FROM longdescs WHERE type = $type &quot; . $dbh-&gt;sql_limit(1));
+    return [] if $test;
+    my %comments = @{ $dbh-&gt;selectcol_arrayref(
+        &quot;SELECT comment_id, thetext FROM longdescs
+          WHERE thetext LIKE '$string%'&quot;, 
+        {Columns=&gt;[1,2]}) };
+    my @comment_ids = keys %comments;
+    return [] if !scalar @comment_ids;
+    my $what = &quot;update&quot;;
+    if ($type == CMT_ATTACHMENT_CREATED) {
+        $what = &quot;creation&quot;;
+    }
+    print &quot;Setting the type field on attachment $what comments...\n&quot;;
+    my $sth = $dbh-&gt;prepare(
+        'UPDATE longdescs SET thetext = ?, type = ?, extra_data = ?
+          WHERE comment_id = ?');
+    my $count = 0;
+    my $total = scalar @comment_ids;
+    foreach my $id (@comment_ids) {
+        $count++;
+        my $text = $comments{$id};
+        next if $text !~ /^\Q$string\E(\d+)/;
+        my $attachment_id = $1;
+        my @lines = split(&quot;\n&quot;, $text);
+        if ($type == CMT_ATTACHMENT_CREATED) {
+            # Now we have to remove the text up until we find a line that's
+            # just a single newline, because the old &quot;Created an attachment&quot;
+            # text included the attachment description underneath it, and in
+            # Bugzillas before 2.20, that could be wrapped into multiple lines,
+            # in the database.
+            while (1) {
+                my $line = shift @lines;
+                last if (!defined $line or trim($line) eq '');
+            }
+        }
</ins><span class="cx">         else {
</span><del>-            print &quot;Populating bugs_fulltext.short_desc...\n&quot;;
-            $dbh-&gt;do('INSERT INTO bugs_fulltext (bug_id, short_desc)
-                           SELECT bug_id, short_desc FROM bugs');
</del><ins>+            # However, the &quot;From update of attachment&quot; line is always just
+            # one line--the first line of the comment.
+            shift @lines;
+        }
+        $text = join(&quot;\n&quot;, @lines);
+        $sth-&gt;execute($text, $type, $attachment_id, $id);
+        indicate_progress({ total =&gt; $total, current =&gt; $count, 
+                            every =&gt; 25 });
+    }
+    return \@comment_ids;
+}
</ins><span class="cx"> 
</span><del>-            my $count = 1;
-            my $sth_all = $dbh-&gt;prepare('SELECT thetext FROM longdescs 
-                                          WHERE bug_id = ?');
-            my $sth_nopriv = $dbh-&gt;prepare(
-                'SELECT thetext FROM longdescs
-                  WHERE bug_id = ? AND isprivate = 0');
-            my $sth_update = $dbh-&gt;prepare(
-                'UPDATE bugs_fulltext SET comments = ?, comments_noprivate = ?
-                  WHERE bug_id = ?');
</del><ins>+sub _set_attachment_comment_types {
+    my $dbh = Bugzilla-&gt;dbh;
+    $dbh-&gt;bz_start_transaction();
+    my $created_ids = _set_attachment_comment_type(
+        CMT_ATTACHMENT_CREATED, 'Created an attachment (id=');
+    my $updated_ids = _set_attachment_comment_type(
+        CMT_ATTACHMENT_UPDATED, '(From update of attachment ');
+    $dbh-&gt;bz_commit_transaction();
+    return unless (@$created_ids or @$updated_ids);
</ins><span class="cx"> 
</span><del>-            print &quot;Populating bugs_fulltext comment fields...\n&quot;;
-            foreach my $id (@$bug_ids) { 
-                my $all = $dbh-&gt;selectcol_arrayref($sth_all, undef, $id);
-                my $nopriv = $dbh-&gt;selectcol_arrayref($sth_nopriv, undef, $id);
-                $sth_update-&gt;execute(join(&quot;\n&quot;, @$all), join(&quot;\n&quot;, @$nopriv), $id);
-                indicate_progress({ total   =&gt; scalar @$bug_ids, every =&gt; 100,
-                                    current =&gt; $count++ });
</del><ins>+    my @comment_ids = (@$created_ids, @$updated_ids);
+
+    my $bug_ids = $dbh-&gt;selectcol_arrayref(
+        'SELECT DISTINCT bug_id FROM longdescs WHERE '
+        . $dbh-&gt;sql_in('comment_id', \@comment_ids));
+    _populate_bugs_fulltext($bug_ids);
+}
+
+sub _add_allows_unconfirmed_to_product_table {
+    my $dbh = Bugzilla-&gt;dbh;
+    if (!$dbh-&gt;bz_column_info('products', 'allows_unconfirmed')) {
+        $dbh-&gt;bz_add_column('products', 'allows_unconfirmed',
+            { TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1, DEFAULT =&gt; 'FALSE' });
+        if ($dbh-&gt;bz_column_info('products', 'votestoconfirm')) {
+            $dbh-&gt;do('UPDATE products SET allows_unconfirmed = 1 
+                       WHERE votestoconfirm &gt; 0');
+        }
+    }
+}
+
+sub _convert_flagtypes_fks_to_set_null {
+    my $dbh = Bugzilla-&gt;dbh;
+    foreach my $column (qw(request_group_id grant_group_id)) {
+        my $fk = $dbh-&gt;bz_fk_info('flagtypes', $column);
+        if ($fk and !defined $fk-&gt;{DELETE}) {
+            $fk-&gt;{DELETE} = 'SET NULL';
+            $dbh-&gt;bz_alter_fk('flagtypes', $column, $fk);
+        }
+    }
+}
+
+sub _fix_decimal_types {
+    my $dbh = Bugzilla-&gt;dbh;
+    my $type = {TYPE =&gt; 'decimal(7,2)', NOTNULL =&gt; 1, DEFAULT =&gt; '0'};
+    $dbh-&gt;bz_alter_column('bugs', 'estimated_time', $type);
+    $dbh-&gt;bz_alter_column('bugs', 'remaining_time', $type);
+    $dbh-&gt;bz_alter_column('longdescs', 'work_time', $type);
+}
+
+sub _fix_series_creator_fk {
+    my $dbh = Bugzilla-&gt;dbh;
+    my $fk = $dbh-&gt;bz_fk_info('series', 'creator');
+    if ($fk and $fk-&gt;{DELETE} eq 'SET NULL') {
+        $fk-&gt;{DELETE} = 'CASCADE';
+        $dbh-&gt;bz_alter_fk('series', 'creator', $fk);
+    }
+}
+
+sub _remove_attachment_isurl {
+    my $dbh = Bugzilla-&gt;dbh;
+
+    if ($dbh-&gt;bz_column_info('attachments', 'isurl')) {
+        # Now all attachments must have a filename.
+        $dbh-&gt;do('UPDATE attachments SET filename = ? WHERE isurl = 1',
+                 undef, 'url.txt');
+        $dbh-&gt;bz_drop_column('attachments', 'isurl');
+        $dbh-&gt;do(&quot;DELETE FROM fielddefs WHERE name='attachments.isurl'&quot;);
+    }
+}
+
+sub _add_isactive_to_product_fields {
+    my $dbh = Bugzilla-&gt;dbh;
+
+    # If we add the isactive column all values should start off as active
+    if (!$dbh-&gt;bz_column_info('components', 'isactive')) {
+        $dbh-&gt;bz_add_column('components', 'isactive', 
+            {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1, DEFAULT =&gt; 'TRUE'});
+    }
+    
+    if (!$dbh-&gt;bz_column_info('versions', 'isactive')) {
+        $dbh-&gt;bz_add_column('versions', 'isactive', 
+            {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1, DEFAULT =&gt; 'TRUE'});
+    }
+
+    if (!$dbh-&gt;bz_column_info('milestones', 'isactive')) {
+        $dbh-&gt;bz_add_column('milestones', 'isactive', 
+            {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1, DEFAULT =&gt; 'TRUE'});
+    }
+}
+
+sub _migrate_field_visibility_value {
+    my $dbh = Bugzilla-&gt;dbh;
+
+    if ($dbh-&gt;bz_column_info('fielddefs', 'visibility_value_id')) {
+        print &quot;Populating new field_visibility table...\n&quot;;
+
+        $dbh-&gt;bz_start_transaction();
+
+        my %results =
+            @{ $dbh-&gt;selectcol_arrayref(
+                &quot;SELECT id, visibility_value_id FROM fielddefs
+                 WHERE visibility_value_id IS NOT NULL&quot;,
+               { Columns =&gt; [1,2] }) };
+
+        my $insert_sth =
+            $dbh-&gt;prepare(&quot;INSERT INTO field_visibility (field_id, value_id)
+                           VALUES (?, ?)&quot;);
+
+        foreach my $id (keys %results) {
+            $insert_sth-&gt;execute($id, $results{$id});
+        }
+
+        $dbh-&gt;bz_commit_transaction();
+        $dbh-&gt;bz_drop_column('fielddefs', 'visibility_value_id');
+    }
+}
+
+sub _fix_series_indexes {
+    my $dbh = Bugzilla-&gt;dbh;
+    return if $dbh-&gt;bz_index_info('series', 'series_category_idx');
+
+    $dbh-&gt;bz_drop_index('series', 'series_creator_idx');
+
+    # Fix duplicated names under the same category/subcategory before
+    # adding the more restrictive index.
+    my $duplicated_series = $dbh-&gt;selectall_arrayref(
+         'SELECT s1.series_id, s1.category, s1.subcategory, s1.name
+            FROM series AS s1
+      INNER JOIN series AS s2
+              ON s1.category = s2.category
+             AND s1.subcategory = s2.subcategory
+             AND s1.name = s2.name
+           WHERE s1.series_id != s2.series_id');
+    my $sth_series_update = $dbh-&gt;prepare('UPDATE series SET name = ? WHERE series_id = ?');
+    my $sth_series_query = $dbh-&gt;prepare('SELECT 1 FROM series WHERE name = ?
+                                          AND category = ? AND subcategory = ?');
+
+    my %renamed_series;
+    foreach my $series (@$duplicated_series) {
+        my ($series_id, $category, $subcategory, $name) = @$series;
+        # Leave the first series alone, then rename duplicated ones.
+        if ($renamed_series{&quot;${category}_${subcategory}_${name}&quot;}++) {
+            print &quot;Renaming series ${category}/${subcategory}/${name}...\n&quot;;
+            my $c = 0;
+            my $exists = 1;
+            while ($exists) {
+                $sth_series_query-&gt;execute($name . ++$c, $category, $subcategory);
+                $exists = $sth_series_query-&gt;fetchrow_array;
</ins><span class="cx">             }
</span><del>-            print &quot;\n&quot;;
</del><ins>+            $sth_series_update-&gt;execute($name . $c, $series_id);
</ins><span class="cx">         }
</span><span class="cx">     }
</span><ins>+
+    $dbh-&gt;bz_add_index('series', 'series_creator_idx', ['creator']);
+    $dbh-&gt;bz_add_index('series', 'series_category_idx',
+        {FIELDS =&gt; [qw(category subcategory name)], TYPE =&gt; 'UNIQUE'});
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub _migrate_user_tags {
+    my $dbh = Bugzilla-&gt;dbh;
+    return unless $dbh-&gt;bz_column_info('namedqueries', 'query_type');
+
+    my $tags = $dbh-&gt;selectall_arrayref('SELECT id, userid, name, query
+                                           FROM namedqueries
+                                          WHERE query_type != 0');
+
+    my $sth_tags = $dbh-&gt;prepare(
+        'INSERT INTO tag (user_id, name) VALUES (?, ?)');
+    my $sth_tag_id = $dbh-&gt;prepare(
+        'SELECT id FROM tag WHERE user_id = ? AND name = ?');
+    my $sth_bug_tag = $dbh-&gt;prepare('INSERT INTO bug_tag (bug_id, tag_id)
+                                     VALUES (?, ?)');
+    my $sth_nq = $dbh-&gt;prepare('UPDATE namedqueries SET query = ?
+                                WHERE id = ?');
+    my $sth_nq_footer = $dbh-&gt;prepare(
+        'DELETE FROM namedqueries_link_in_footer 
+               WHERE user_id = ? AND namedquery_id = ?');
+
+    if (scalar @$tags) {
+        print install_string('update_queries_to_tags'), &quot;\n&quot;;
+    }
+
+    my $total = scalar(@$tags);
+    my $current = 0;
+
+    $dbh-&gt;bz_start_transaction();
+    foreach my $tag (@$tags) {
+        my ($query_id, $user_id, $name, $query) = @$tag;
+        # Tags are all lowercase.
+        my $tag_name = lc($name);
+
+        $sth_tags-&gt;execute($user_id, $tag_name);
+
+        my $tag_id = $dbh-&gt;selectrow_array($sth_tag_id,
+            undef, $user_id, $tag_name);
+
+        indicate_progress({ current =&gt; ++$current, total =&gt; $total,
+                            every =&gt; 25 });
+
+        my $uri = URI-&gt;new(&quot;buglist.cgi?$query&quot;, 'http');
+        my $bug_id_list = $uri-&gt;query_param_delete('bug_id');
+        if (!$bug_id_list) {
+            warn &quot;No bug_id param for tag $name from user $user_id: $query&quot;;
+            next;
+        }
+        my @bug_ids = split(/[\s,]+/, $bug_id_list);
+        # Make sure that things like &quot;001&quot; get converted to &quot;1&quot;
+        @bug_ids = map { int($_) } @bug_ids;
+        # And remove duplicates
+        @bug_ids = uniq @bug_ids;
+        foreach my $bug_id (@bug_ids) {
+            # If &quot;int&quot; above failed this might be undef. We also
+            # don't want to accept bug 0.
+            next if !$bug_id;
+            $sth_bug_tag-&gt;execute($bug_id, $tag_id);
+        }
+        
+        # Existing tags may be used in whines, or shared with
+        # other users. So we convert them rather than delete them.
+        $uri-&gt;query_param('tag', $tag_name);
+        $sth_nq-&gt;execute($uri-&gt;query, $query_id);
+        # But we don't keep showing them in the footer.
+        $sth_nq_footer-&gt;execute($user_id, $query_id);
+    }
+
+    $dbh-&gt;bz_commit_transaction();
+
+    $dbh-&gt;bz_drop_column('namedqueries', 'query_type');
+}
+
+sub _populate_bug_see_also_class {
+    my $dbh = Bugzilla-&gt;dbh;
+
+    if ($dbh-&gt;bz_column_info('bug_see_also', 'class')) {
+        # The length was incorrectly set to 64 instead of 255.
+        $dbh-&gt;bz_alter_column('bug_see_also', 'class',
+                {TYPE =&gt; 'varchar(255)', NOTNULL =&gt; 1, DEFAULT =&gt; &quot;''&quot;});
+        return;
+    }
+
+    $dbh-&gt;bz_add_column('bug_see_also', 'class',
+        {TYPE =&gt; 'varchar(255)', NOTNULL =&gt; 1, DEFAULT =&gt; &quot;''&quot;}, '');
+
+    my $result = $dbh-&gt;selectall_arrayref(
+        &quot;SELECT id, value FROM bug_see_also&quot;);
+
+    my $update_sth =
+        $dbh-&gt;prepare(&quot;UPDATE bug_see_also SET class = ? WHERE id = ?&quot;);
+    
+    $dbh-&gt;bz_start_transaction();
+    foreach my $see_also (@$result) {
+        my ($id, $value) = @$see_also;
+        my $class = Bugzilla::BugUrl-&gt;class_for($value);
+        $update_sth-&gt;execute($class, $id);
+    }
+    $dbh-&gt;bz_commit_transaction();
+}
+
+sub _migrate_disabledtext_boolean {
+    my $dbh = Bugzilla-&gt;dbh;
+    if (!$dbh-&gt;bz_column_info('profiles', 'is_enabled')) {
+        $dbh-&gt;bz_add_column(&quot;profiles&quot;, 'is_enabled',
+                            {TYPE =&gt; 'BOOLEAN', NOTNULL =&gt; 1, DEFAULT =&gt; 'TRUE'});
+        $dbh-&gt;do(&quot;UPDATE profiles SET is_enabled = 0 
+                  WHERE disabledtext != ''&quot;);
+    }
+}
+
+sub _rename_tags_to_tag {
+    my $dbh = Bugzilla-&gt;dbh;
+    if ($dbh-&gt;bz_table_info('tags')) {
+        # If we get here, it's because the schema created &quot;tag&quot; as an empty
+        # table while &quot;tags&quot; still exists. We get rid of the empty
+        # tag table so we can do the rename over the top of it.
+        $dbh-&gt;bz_drop_table('tag');
+        $dbh-&gt;bz_drop_index('tags', 'tags_user_id_idx');
+        $dbh-&gt;bz_rename_table('tags','tag');
+        $dbh-&gt;bz_add_index('tag', 'tag_user_id_idx',
+                           {FIELDS =&gt; [qw(user_id name)], TYPE =&gt; 'UNIQUE'});
+    }
+    if (my $bug_tag_fk = $dbh-&gt;bz_fk_info('bug_tag', 'tag_id')) {
+        # bz_rename_table() didn't handle FKs correctly.
+        if ($bug_tag_fk-&gt;{TABLE} eq 'tags') {
+            $bug_tag_fk-&gt;{TABLE} = 'tag';
+            $dbh-&gt;bz_alter_fk('bug_tag', 'tag_id', $bug_tag_fk);
+        }
+    }
+}
+
+sub _on_delete_set_null_for_audit_log_userid {
+    my $dbh = Bugzilla-&gt;dbh;
+    my $fk = $dbh-&gt;bz_fk_info('audit_log', 'user_id');
+    if ($fk and !defined $fk-&gt;{DELETE}) {
+        $fk-&gt;{DELETE} = 'SET NULL';
+        $dbh-&gt;bz_alter_fk('audit_log', 'user_id', $fk);
+    }
+}
+
+sub _fix_notnull_defaults {
+    my $dbh = Bugzilla-&gt;dbh;
+
+    $dbh-&gt;bz_alter_column('bugs', 'bug_file_loc', 
+                          {TYPE =&gt; 'MEDIUMTEXT', NOTNULL =&gt; 1,  
+                           DEFAULT =&gt; &quot;''&quot;}, '');
+
+    my $custom_fields = Bugzilla::Field-&gt;match({ 
+        custom =&gt; 1, type =&gt; [ FIELD_TYPE_FREETEXT, FIELD_TYPE_TEXTAREA ] 
+    });
+
+    foreach my $field (@$custom_fields) {
+        if ($field-&gt;type == FIELD_TYPE_FREETEXT) {
+            $dbh-&gt;bz_alter_column('bugs', $field-&gt;name,
+                                  {TYPE =&gt; 'varchar(255)', NOTNULL =&gt; 1,
+                                   DEFAULT =&gt; &quot;''&quot;}, '');
+        }
+        if ($field-&gt;type == FIELD_TYPE_TEXTAREA) {
+            $dbh-&gt;bz_alter_column('bugs', $field-&gt;name,
+                                  {TYPE =&gt; 'MEDIUMTEXT', NOTNULL =&gt; 1,
+                                   DEFAULT =&gt; &quot;''&quot;}, '');
+        }
+    }
+}
+
</ins><span class="cx"> 1;
</span><span class="cx"> 
</span><span class="cx"> __END__
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaInstallFilesystempm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Install/Filesystem.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Install/Filesystem.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Install/Filesystem.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -30,11 +30,14 @@
</span><span class="cx"> use Bugzilla::Constants;
</span><span class="cx"> use Bugzilla::Error;
</span><span class="cx"> use Bugzilla::Install::Localconfig;
</span><ins>+use Bugzilla::Install::Util qw(install_string);
</ins><span class="cx"> use Bugzilla::Util;
</span><ins>+use Bugzilla::Hook;
</ins><span class="cx"> 
</span><span class="cx"> use File::Find;
</span><span class="cx"> use File::Path;
</span><span class="cx"> use File::Basename;
</span><ins>+use File::Copy qw(move);
</ins><span class="cx"> use IO::File;
</span><span class="cx"> use POSIX ();
</span><span class="cx"> 
</span><span class="lines">@@ -43,18 +46,73 @@
</span><span class="cx">     update_filesystem
</span><span class="cx">     create_htaccess
</span><span class="cx">     fix_all_file_permissions
</span><ins>+    fix_dir_permissions
+    fix_file_permissions
</ins><span class="cx"> );
</span><span class="cx"> 
</span><ins>+use constant HT_DEFAULT_DENY =&gt; &lt;&lt;EOT;
+# nothing in this directory is retrievable unless overridden by an .htaccess
+# in a subdirectory
+deny from all
+EOT
+
+###############
+# Permissions #
+###############
+
+# Used by the permissions &quot;constants&quot; below.
+sub _suexec { Bugzilla-&gt;localconfig-&gt;{'use_suexec'}     };
+sub _group  { Bugzilla-&gt;localconfig-&gt;{'webservergroup'} };
+
+# Writeable by the owner only.
+use constant OWNER_WRITE =&gt; 0600;
+# Executable by the owner only.
+use constant OWNER_EXECUTE =&gt; 0700;
+# A directory which is only writeable by the owner.
+use constant DIR_OWNER_WRITE =&gt; 0700;
+
+# A cgi script that the webserver can execute.
+sub WS_EXECUTE { _group() ? 0750 : 0755 };
+# A file that is read by cgi scripts, but is not ever read
+# directly by the webserver.
+sub CGI_READ { _group() ? 0640 : 0644 };
+# A file that is written to by cgi scripts, but is not ever
+# read or written directly by the webserver.
+sub CGI_WRITE { _group() ? 0660 : 0666 };
+# A file that is served directly by the web server.
+sub WS_SERVE { (_group() and !_suexec()) ? 0640 : 0644 };
+
+# A directory whose contents can be read or served by the
+# webserver (so even directories containing cgi scripts
+# would have this permission).
+sub DIR_WS_SERVE { (_group() and !_suexec()) ? 0750 : 0755 };
+# A directory that is read by cgi scripts, but is never accessed
+# directly by the webserver
+sub DIR_CGI_READ { _group() ? 0750 : 0755 };
+# A directory that is written to by cgi scripts, but where the
+# scripts never needs to overwrite files created by other
+# users.
+sub DIR_CGI_WRITE { _group() ? 0770 : 01777 };
+# A directory that is written to by cgi scripts, where the
+# scripts need to overwrite files created by other users.
+sub DIR_CGI_OVERWRITE { _group() ? 0770 : 0777 };
+
+# This can be combined (using &quot;|&quot;) with other permissions for 
+# directories that, in addition to their normal permissions (such
+# as DIR_CGI_WRITE) also have content served directly from them
+# (or their subdirectories) to the user, via the webserver.
+sub DIR_ALSO_WS_SERVE { _suexec() ? 0001 : 0 };
+
</ins><span class="cx"> # This looks like a constant because it effectively is, but
</span><span class="cx"> # it has to call other subroutines and read the current filesystem,
</span><span class="cx"> # so it's defined as a sub. This is not exported, so it doesn't have
</span><span class="cx"> # a perldoc. However, look at the various hashes defined inside this 
</span><span class="cx"> # function to understand what it returns. (There are comments throughout.)
</span><span class="cx"> #
</span><del>-# The rationale for the file permissions is that the web server generally 
-# runs as apache, so the cgi scripts should not be writable for apache,
-# otherwise someone may find it possible to change the cgis when exploiting
-# some security flaw somewhere (not necessarily in Bugzilla!)
</del><ins>+# The rationale for the file permissions is that there is a group the
+# web server executes the scripts as, so the cgi scripts should not be writable
+# by this group. Otherwise someone may find it possible to change the cgis
+# when exploiting some security flaw somewhere (not necessarily in Bugzilla!)
</ins><span class="cx"> sub FILESYSTEM {
</span><span class="cx">     my $datadir       = bz_locations()-&gt;{'datadir'};
</span><span class="cx">     my $attachdir     = bz_locations()-&gt;{'attachdir'};
</span><span class="lines">@@ -64,34 +122,17 @@
</span><span class="cx">     my $libdir        = bz_locations()-&gt;{'libpath'};
</span><span class="cx">     my $extlib        = bz_locations()-&gt;{'ext_libpath'};
</span><span class="cx">     my $skinsdir      = bz_locations()-&gt;{'skinsdir'};
</span><ins>+    my $localconfig   = bz_locations()-&gt;{'localconfig'};
+    my $template_cache = bz_locations()-&gt;{'template_cache'};
+    my $graphsdir     = bz_locations()-&gt;{'graphsdir'};
</ins><span class="cx"> 
</span><del>-    my $ws_group      = Bugzilla-&gt;localconfig-&gt;{'webservergroup'};
</del><ins>+    # We want to set the permissions the same for all localconfig files
+    # across all PROJECTs, so we do something special with $localconfig,
+    # lower down in the permissions section.
+    if ($ENV{PROJECT}) {
+        $localconfig =~ s/\.\Q$ENV{PROJECT}\E$//;
+    }
</ins><span class="cx"> 
</span><del>-    # The set of permissions that we use:
-
-    # FILES
-    # Executable by the web server
-    my $ws_executable = $ws_group ? 0750 : 0755;
-    # Executable by the owner only.
-    my $owner_executable = 0700;
-    # Readable by the web server.
-    my $ws_readable = $ws_group ? 0640 : 0644;
-    # Readable by the owner only.
-    my $owner_readable = 0600;
-    # Writeable by the web server.
-    my $ws_writeable = $ws_group ? 0660 : 0666;
-
-    # DIRECTORIES
-    # Readable by the web server.
-    my $ws_dir_readable  = $ws_group ? 0750 : 0755;
-    # Readable only by the owner.
-    my $owner_dir_readable = 0700;
-    # Writeable by the web server.
-    my $ws_dir_writeable = $ws_group ? 0770 : 01777;
-    # The web server can overwrite files owned by other users, 
-    # in this directory.
-    my $ws_dir_full_control = $ws_group ? 0770 : 0777;
-
</del><span class="cx">     # Note: When being processed by checksetup, these have their permissions
</span><span class="cx">     # set in this order: %all_dirs, %recurse_dirs, %all_files.
</span><span class="cx">     #
</span><span class="lines">@@ -102,35 +143,50 @@
</span><span class="cx"> 
</span><span class="cx">     # --- FILE PERMISSIONS (Non-created files) --- #
</span><span class="cx">     my %files = (
</span><del>-        '*'               =&gt; { perms =&gt; $ws_readable },
-        '*.cgi'           =&gt; { perms =&gt; $ws_executable },
-        'whineatnews.pl'  =&gt; { perms =&gt; $ws_executable },
-        'collectstats.pl' =&gt; { perms =&gt; $ws_executable },
-        'checksetup.pl'   =&gt; { perms =&gt; $owner_executable },
-        'importxml.pl'    =&gt; { perms =&gt; $ws_executable },
-        'runtests.pl'     =&gt; { perms =&gt; $owner_executable },
-        'testserver.pl'   =&gt; { perms =&gt; $ws_executable },
-        'whine.pl'        =&gt; { perms =&gt; $ws_executable },
-        'customfield.pl'  =&gt; { perms =&gt; $owner_executable },
-        'email_in.pl'     =&gt; { perms =&gt; $ws_executable },
-        'sanitycheck.pl'  =&gt; { perms =&gt; $ws_executable },
-        'install-module.pl' =&gt; { perms =&gt; $owner_executable },
</del><ins>+        '*'               =&gt; { perms =&gt; OWNER_WRITE },
+        # Some .pl files are WS_EXECUTE because we want
+        # users to be able to cron them or otherwise run
+        # them as a secure user, like the webserver owner.
+        '*.cgi'           =&gt; { perms =&gt; WS_EXECUTE },
+        'whineatnews.pl'  =&gt; { perms =&gt; WS_EXECUTE },
+        'collectstats.pl' =&gt; { perms =&gt; WS_EXECUTE },
+        'importxml.pl'    =&gt; { perms =&gt; WS_EXECUTE },
+        'testserver.pl'   =&gt; { perms =&gt; WS_EXECUTE },
+        'whine.pl'        =&gt; { perms =&gt; WS_EXECUTE },
+        'email_in.pl'     =&gt; { perms =&gt; WS_EXECUTE },
+        'sanitycheck.pl'  =&gt; { perms =&gt; WS_EXECUTE },
+        'checksetup.pl'   =&gt; { perms =&gt; OWNER_EXECUTE },
+        'runtests.pl'     =&gt; { perms =&gt; OWNER_EXECUTE },
+        'jobqueue.pl'     =&gt; { perms =&gt; OWNER_EXECUTE },
+        'migrate.pl'      =&gt; { perms =&gt; OWNER_EXECUTE },
+        'install-module.pl' =&gt; { perms =&gt; OWNER_EXECUTE },
</ins><span class="cx"> 
</span><del>-        'docs/makedocs.pl'   =&gt; { perms =&gt; $owner_executable },
-        'docs/style.css'       =&gt; { perms =&gt; $ws_readable },
-        'docs/*/rel_notes.txt' =&gt; { perms =&gt; $ws_readable },
-        'docs/*/README.docs'   =&gt; { perms =&gt; $owner_readable },
-        &quot;$datadir/bugzilla-update.xml&quot; =&gt; { perms =&gt; $ws_writeable },
-        &quot;$datadir/params&quot; =&gt; { perms =&gt; $ws_writeable },
-        &quot;$datadir/mailer.testfile&quot; =&gt; { perms =&gt; $ws_writeable },
</del><ins>+        'Bugzilla.pm'   =&gt; { perms =&gt; CGI_READ },
+        &quot;$localconfig*&quot; =&gt; { perms =&gt; CGI_READ },
+        'bugzilla.dtd'  =&gt; { perms =&gt; WS_SERVE },
+        'mod_perl.pl'   =&gt; { perms =&gt; WS_SERVE },
+        'robots.txt'    =&gt; { perms =&gt; WS_SERVE },
+        '.htaccess'     =&gt; { perms =&gt; WS_SERVE },
+
+        'contrib/README'       =&gt; { perms =&gt; OWNER_WRITE },
+        'contrib/*/README'     =&gt; { perms =&gt; OWNER_WRITE },
+        'docs/bugzilla.ent'    =&gt; { perms =&gt; OWNER_WRITE },
+        'docs/makedocs.pl'     =&gt; { perms =&gt; OWNER_EXECUTE },
+        'docs/style.css'       =&gt; { perms =&gt; WS_SERVE },
+        'docs/*/rel_notes.txt' =&gt; { perms =&gt; WS_SERVE },
+        'docs/*/README.docs'   =&gt; { perms =&gt; OWNER_WRITE },
+        &quot;$datadir/params&quot;      =&gt; { perms =&gt; CGI_WRITE },
+        &quot;$datadir/old-params.txt&quot;  =&gt; { perms =&gt; OWNER_WRITE },
+        &quot;$extensionsdir/create.pl&quot; =&gt; { perms =&gt; OWNER_EXECUTE },
+        &quot;$extensionsdir/*/*.pl&quot;    =&gt; { perms =&gt; WS_EXECUTE },
</ins><span class="cx">     );
</span><span class="cx"> 
</span><span class="cx">     # Directories that we want to set the perms on, but not
</span><span class="cx">     # recurse through. These are directories we didn't create
</span><span class="cx">     # in checkesetup.pl.
</span><span class="cx">     my %non_recurse_dirs = (
</span><del>-        '.'  =&gt; $ws_dir_readable,
-        docs =&gt; $ws_dir_readable,
</del><ins>+        '.'  =&gt; DIR_WS_SERVE,
+        docs =&gt; DIR_WS_SERVE,
</ins><span class="cx">     );
</span><span class="cx"> 
</span><span class="cx">     # This sets the permissions for each item inside each of these 
</span><span class="lines">@@ -139,50 +195,68 @@
</span><span class="cx">     # the webserver.
</span><span class="cx">     my %recurse_dirs = (
</span><span class="cx">         # Writeable directories
</span><del>-        &quot;$datadir/template&quot; =&gt; { files =&gt; $ws_readable, 
-                                  dirs =&gt; $ws_dir_full_control },
-         $attachdir         =&gt; { files =&gt; $ws_writeable,
-                                  dirs =&gt; $ws_dir_writeable },
-         $webdotdir         =&gt; { files =&gt; $ws_writeable,
-                                  dirs =&gt; $ws_dir_writeable },
-         graphs             =&gt; { files =&gt; $ws_writeable,
-                                  dirs =&gt; $ws_dir_writeable },
</del><ins>+         $template_cache    =&gt; { files =&gt; CGI_READ,
+                                  dirs =&gt; DIR_CGI_OVERWRITE },
+         $attachdir         =&gt; { files =&gt; CGI_WRITE,
+                                  dirs =&gt; DIR_CGI_WRITE },
+         $webdotdir         =&gt; { files =&gt; WS_SERVE,
+                                  dirs =&gt; DIR_CGI_WRITE | DIR_ALSO_WS_SERVE },
+         $graphsdir         =&gt; { files =&gt; WS_SERVE,
+                                  dirs =&gt; DIR_CGI_WRITE | DIR_ALSO_WS_SERVE },
+         &quot;$datadir/db&quot;      =&gt; { files =&gt; CGI_WRITE,
+                                  dirs =&gt; DIR_CGI_WRITE },
</ins><span class="cx"> 
</span><span class="cx">          # Readable directories
</span><del>-         &quot;$datadir/mining&quot;     =&gt; { files =&gt; $ws_readable,
-                                     dirs =&gt; $ws_dir_readable },
-         &quot;$datadir/duplicates&quot; =&gt; { files =&gt; $ws_readable,
-                                     dirs =&gt; $ws_dir_readable },
-         &quot;$libdir/Bugzilla&quot;    =&gt; { files =&gt; $ws_readable,
-                                     dirs =&gt; $ws_dir_readable },
-         $extlib               =&gt; { files =&gt; $ws_readable,
-                                     dirs =&gt; $ws_dir_readable },
-         $templatedir          =&gt; { files =&gt; $ws_readable,
-                                     dirs =&gt; $ws_dir_readable },
-         $extensionsdir        =&gt; { files =&gt; $ws_readable,
-                                     dirs =&gt; $ws_dir_readable },
-         images                =&gt; { files =&gt; $ws_readable,
-                                     dirs =&gt; $ws_dir_readable },
-         css                   =&gt; { files =&gt; $ws_readable,
-                                     dirs =&gt; $ws_dir_readable },
-         js                    =&gt; { files =&gt; $ws_readable,
-                                     dirs =&gt; $ws_dir_readable },
-         $skinsdir             =&gt; { files =&gt; $ws_readable,
-                                     dirs =&gt; $ws_dir_readable },
-         t                     =&gt; { files =&gt; $owner_readable,
-                                     dirs =&gt; $owner_dir_readable },
-         'docs/*/html'         =&gt; { files =&gt; $ws_readable,
-                                     dirs =&gt; $ws_dir_readable },
-         'docs/*/pdf'          =&gt; { files =&gt; $ws_readable,
-                                     dirs =&gt; $ws_dir_readable },
-         'docs/*/txt'          =&gt; { files =&gt; $ws_readable,
-                                     dirs =&gt; $ws_dir_readable },
-         'docs/*/images'       =&gt; { files =&gt; $ws_readable,
-                                     dirs =&gt; $ws_dir_readable },
-         'docs/lib'            =&gt; { files =&gt; $owner_readable,
-                                     dirs =&gt; $owner_dir_readable },
-         'docs/*/xml'          =&gt; { files =&gt; $owner_readable,
-                                     dirs =&gt; $owner_dir_readable },
</del><ins>+         &quot;$datadir/mining&quot;     =&gt; { files =&gt; CGI_READ,
+                                     dirs =&gt; DIR_CGI_READ },
+         &quot;$libdir/Bugzilla&quot;    =&gt; { files =&gt; CGI_READ,
+                                     dirs =&gt; DIR_CGI_READ },
+         $extlib               =&gt; { files =&gt; CGI_READ,
+                                     dirs =&gt; DIR_CGI_READ },
+         $templatedir          =&gt; { files =&gt; CGI_READ,
+                                     dirs =&gt; DIR_CGI_READ },
+         # Directories in the extensions/ dir are WS_SERVE so that
+         # the web/ directories can be served by the web server.
+         # But, for extra security, we deny direct webserver access to
+         # the lib/ and template/ directories of extensions.
+         $extensionsdir        =&gt; { files =&gt; CGI_READ,
+                                     dirs =&gt; DIR_WS_SERVE },
+         &quot;$extensionsdir/*/lib&quot; =&gt; { files =&gt; CGI_READ,
+                                      dirs =&gt; DIR_CGI_READ },
+         &quot;$extensionsdir/*/template&quot; =&gt; { files =&gt; CGI_READ,
+                                           dirs =&gt; DIR_CGI_READ },
+
+         # Content served directly by the webserver
+         images                =&gt; { files =&gt; WS_SERVE,
+                                     dirs =&gt; DIR_WS_SERVE },
+         js                    =&gt; { files =&gt; WS_SERVE,
+                                     dirs =&gt; DIR_WS_SERVE },
+         $skinsdir             =&gt; { files =&gt; WS_SERVE,
+                                     dirs =&gt; DIR_WS_SERVE },
+         'docs/*/html'         =&gt; { files =&gt; WS_SERVE,
+                                     dirs =&gt; DIR_WS_SERVE },
+         'docs/*/pdf'          =&gt; { files =&gt; WS_SERVE,
+                                     dirs =&gt; DIR_WS_SERVE },
+         'docs/*/txt'          =&gt; { files =&gt; WS_SERVE,
+                                     dirs =&gt; DIR_WS_SERVE },
+         'docs/*/images'       =&gt; { files =&gt; WS_SERVE,
+                                     dirs =&gt; DIR_WS_SERVE },
+         &quot;$extensionsdir/*/web&quot; =&gt; { files =&gt; WS_SERVE,
+                                     dirs =&gt; DIR_WS_SERVE },
+
+         # Directories only for the owner, not for the webserver.
+         '.bzr'                =&gt; { files =&gt; OWNER_WRITE,
+                                    dirs  =&gt; DIR_OWNER_WRITE },
+         t                     =&gt; { files =&gt; OWNER_WRITE,
+                                     dirs =&gt; DIR_OWNER_WRITE },
+         xt                    =&gt; { files =&gt; OWNER_WRITE,
+                                     dirs =&gt; DIR_OWNER_WRITE },
+         'docs/lib'            =&gt; { files =&gt; OWNER_WRITE,
+                                     dirs =&gt; DIR_OWNER_WRITE },
+         'docs/*/xml'          =&gt; { files =&gt; OWNER_WRITE,
+                                     dirs =&gt; DIR_OWNER_WRITE },
+         'contrib'             =&gt; { files =&gt; OWNER_EXECUTE,
+                                     dirs =&gt; DIR_OWNER_WRITE, },
</ins><span class="cx">     );
</span><span class="cx"> 
</span><span class="cx">     # --- FILES TO CREATE --- #
</span><span class="lines">@@ -190,40 +264,39 @@
</span><span class="cx">     # The name of each directory that we should actually *create*,
</span><span class="cx">     # pointing at its default permissions.
</span><span class="cx">     my %create_dirs = (
</span><del>-        $datadir                =&gt; $ws_dir_full_control,
-        &quot;$datadir/mining&quot;       =&gt; $ws_dir_readable,
-        &quot;$datadir/duplicates&quot;   =&gt; $ws_dir_readable,
-        $attachdir              =&gt; $ws_dir_writeable,
-        $extensionsdir          =&gt; $ws_dir_readable,
-        graphs                  =&gt; $ws_dir_writeable,
-        $webdotdir              =&gt; $ws_dir_writeable,
-        &quot;$skinsdir/custom&quot;      =&gt; $ws_dir_readable,
-        &quot;$skinsdir/contrib&quot;     =&gt; $ws_dir_readable,
</del><ins>+        # This is DIR_ALSO_WS_SERVE because it contains $webdotdir.
+        $datadir                =&gt; DIR_CGI_OVERWRITE | DIR_ALSO_WS_SERVE,
+        # Directories that are read-only for cgi scripts
+        &quot;$datadir/mining&quot;       =&gt; DIR_CGI_READ,
+        &quot;$datadir/extensions&quot;   =&gt; DIR_CGI_READ,
+        $extensionsdir          =&gt; DIR_CGI_READ,
+        # Directories that cgi scripts can write to.
+        &quot;$datadir/db&quot;           =&gt; DIR_CGI_WRITE,
+        $attachdir              =&gt; DIR_CGI_WRITE,
+        $graphsdir              =&gt; DIR_CGI_WRITE | DIR_ALSO_WS_SERVE,
+        $webdotdir              =&gt; DIR_CGI_WRITE | DIR_ALSO_WS_SERVE,
+        # Directories that contain content served directly by the web server.
+        &quot;$skinsdir/custom&quot;      =&gt; DIR_WS_SERVE,
+        &quot;$skinsdir/contrib&quot;     =&gt; DIR_WS_SERVE,
</ins><span class="cx">     );
</span><span class="cx"> 
</span><span class="cx">     # The name of each file, pointing at its default permissions and
</span><span class="cx">     # default contents.
</span><del>-    my %create_files = ();
</del><ins>+    my %create_files = (
+        &quot;$datadir/extensions/additional&quot; =&gt; { perms    =&gt; CGI_READ, 
+                                              contents =&gt; '' },
+        # We create this file so that it always has the right owner
+        # and permissions. Otherwise, the webserver creates it as
+        # owned by itself, which can cause problems if jobqueue.pl
+        # or something else is not running as the webserver or root.
+        &quot;$datadir/mailer.testfile&quot; =&gt; { perms    =&gt; CGI_WRITE,
+                                        contents =&gt; '' },
+    );
</ins><span class="cx"> 
</span><del>-    # Each standard stylesheet has an associated custom stylesheet that
-    # we create. Also, we create placeholders for standard stylesheets
-    # for contrib skins which don't provide them themselves.
-    foreach my $skin_dir (&quot;$skinsdir/custom&quot;, &lt;$skinsdir/contrib/*&gt;) {
-        next if basename($skin_dir) =~ /^cvs$/i;
-        $create_dirs{&quot;$skin_dir/yui&quot;} = $ws_dir_readable;
-        foreach my $base_css (&lt;$skinsdir/standard/*.css&gt;) {
-            _add_custom_css($skin_dir, basename($base_css), \%create_files, $ws_readable);
-        }
-        foreach my $dir_css (&lt;$skinsdir/standard/*/*.css&gt;) {
-            $dir_css =~ s{.+?([^/]+/[^/]+)$}{$1};
-            _add_custom_css($skin_dir, $dir_css, \%create_files, $ws_readable);
-        }
-    }
-
</del><span class="cx">     # Because checksetup controls the creation of index.html separately
</span><span class="cx">     # from all other files, it gets its very own hash.
</span><span class="cx">     my %index_html = (
</span><del>-        'index.html' =&gt; { perms =&gt; $ws_readable, contents =&gt; &lt;&lt;EOT
</del><ins>+        'index.html' =&gt; { perms =&gt; WS_SERVE, contents =&gt; &lt;&lt;EOT
</ins><span class="cx"> &lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;&gt;
</span><span class="cx"> &lt;html&gt;
</span><span class="cx"> &lt;head&gt;
</span><span class="lines">@@ -240,31 +313,40 @@
</span><span class="cx">     # Because checksetup controls the .htaccess creation separately
</span><span class="cx">     # by a localconfig variable, these go in a separate variable from
</span><span class="cx">     # %create_files.
</span><del>-    my $ht_default_deny = &lt;&lt;EOT;
-# nothing in this directory is retrievable unless overridden by an .htaccess
-# in a subdirectory
-deny from all
-EOT
-
</del><ins>+    #
+    # Note that these get WS_SERVE as their permission
+    # because they're *read* by the webserver, even though they're not
+    # actually, themselves, served.
</ins><span class="cx">     my %htaccess = (
</span><del>-        &quot;$attachdir/.htaccess&quot;       =&gt; { perms    =&gt; $ws_readable,
-                                          contents =&gt; $ht_default_deny },
-        &quot;$libdir/Bugzilla/.htaccess&quot; =&gt; { perms    =&gt; $ws_readable,
-                                          contents =&gt; $ht_default_deny },
-        &quot;$extlib/.htaccess&quot;          =&gt; { perms    =&gt; $ws_readable,
-                                          contents =&gt; $ht_default_deny },
-        &quot;$templatedir/.htaccess&quot;     =&gt; { perms    =&gt; $ws_readable,
-                                          contents =&gt; $ht_default_deny },
</del><ins>+        &quot;$attachdir/.htaccess&quot;       =&gt; { perms    =&gt; WS_SERVE,
+                                          contents =&gt; HT_DEFAULT_DENY },
+        &quot;$libdir/Bugzilla/.htaccess&quot; =&gt; { perms    =&gt; WS_SERVE,
+                                          contents =&gt; HT_DEFAULT_DENY },
+        &quot;$extlib/.htaccess&quot;          =&gt; { perms    =&gt; WS_SERVE,
+                                          contents =&gt; HT_DEFAULT_DENY },
+        &quot;$templatedir/.htaccess&quot;     =&gt; { perms    =&gt; WS_SERVE,
+                                          contents =&gt; HT_DEFAULT_DENY },
+        'contrib/.htaccess'          =&gt; { perms    =&gt; WS_SERVE,
+                                          contents =&gt; HT_DEFAULT_DENY },
+        't/.htaccess'                =&gt; { perms    =&gt; WS_SERVE,
+                                          contents =&gt; HT_DEFAULT_DENY },
+        'xt/.htaccess'               =&gt; { perms    =&gt; WS_SERVE,
+                                          contents =&gt; HT_DEFAULT_DENY },
+        &quot;$datadir/.htaccess&quot;         =&gt; { perms    =&gt; WS_SERVE,
+                                          contents =&gt; HT_DEFAULT_DENY },
</ins><span class="cx"> 
</span><del>-        '.htaccess' =&gt; { perms =&gt; $ws_readable, contents =&gt; &lt;&lt;EOT
-# Don't allow people to retrieve non-cgi executable files or our private data
-&lt;FilesMatch ^(.*\\.pm|.*\\.pl|.*localconfig.*)\$&gt;
-  deny from all
</del><ins>+        &quot;$graphsdir/.htaccess&quot; =&gt; { perms =&gt; WS_SERVE, contents =&gt; &lt;&lt;EOT
+# Allow access to .png and .gif files.
+&lt;FilesMatch (\\.gif|\\.png)\$&gt;
+  Allow from all
</ins><span class="cx"> &lt;/FilesMatch&gt;
</span><ins>+
+# And no directory listings, either.
+Deny from all
</ins><span class="cx"> EOT
</span><span class="cx">         },
</span><span class="cx"> 
</span><del>-        &quot;$webdotdir/.htaccess&quot; =&gt; { perms =&gt; $ws_readable, contents =&gt; &lt;&lt;EOT
</del><ins>+        &quot;$webdotdir/.htaccess&quot; =&gt; { perms =&gt; WS_SERVE, contents =&gt; &lt;&lt;EOT
</ins><span class="cx"> # Restrict access to .dot files to the public webdot server at research.att.com
</span><span class="cx"> # if research.att.com ever changes their IP, or if you use a different
</span><span class="cx"> # webdot server, you'll need to edit this
</span><span class="lines">@@ -282,24 +364,17 @@
</span><span class="cx"> Deny from all
</span><span class="cx"> EOT
</span><span class="cx">         },
</span><ins>+    );
</ins><span class="cx"> 
</span><del>-        # Even though $datadir may not (and should not) be accessible from the 
-        # web server, we can't know for sure, so create the .htaccess anyway. 
-        # It's harmless if it isn't accessible...
-        &quot;$datadir/.htaccess&quot; =&gt; { perms    =&gt; $ws_readable, contents =&gt; &lt;&lt;EOT
-# Nothing in this directory is retrievable unless overridden by an .htaccess
-# in a subdirectory; the only exception is duplicates.rdf, which is used by
-# duplicates.xul and must be accessible from the web server
-deny from all
-&lt;Files duplicates.rdf&gt;
-  allow from all
-&lt;/Files&gt;
-EOT
</del><ins>+    Bugzilla::Hook::process('install_filesystem', {
+        files            =&gt; \%files,
+        create_dirs      =&gt; \%create_dirs,
+        non_recurse_dirs =&gt; \%non_recurse_dirs,
+        recurse_dirs     =&gt; \%recurse_dirs,
+        create_files     =&gt; \%create_files,
+        htaccess         =&gt; \%htaccess,
+    });
</ins><span class="cx"> 
</span><del>-
-        },
-    );
-
</del><span class="cx">     my %all_files = (%create_files, %htaccess, %index_html, %files);
</span><span class="cx">     my %all_dirs  = (%create_dirs, %non_recurse_dirs);
</span><span class="cx"> 
</span><span class="lines">@@ -322,10 +397,11 @@
</span><span class="cx">     my %files = %{$fs-&gt;{create_files}};
</span><span class="cx"> 
</span><span class="cx">     my $datadir = bz_locations-&gt;{'datadir'};
</span><ins>+    my $graphsdir = bz_locations-&gt;{'graphsdir'};
</ins><span class="cx">     # If the graphs/ directory doesn't exist, we're upgrading from
</span><span class="cx">     # a version old enough that we need to update the $datadir/mining 
</span><span class="cx">     # format.
</span><del>-    if (-d &quot;$datadir/mining&quot; &amp;&amp; !-d 'graphs') {
</del><ins>+    if (-d &quot;$datadir/mining&quot; &amp;&amp; !-d $graphsdir) {
</ins><span class="cx">         _update_old_charts($datadir);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -335,13 +411,26 @@
</span><span class="cx">     foreach my $dir (sort keys %dirs) {
</span><span class="cx">         unless (-d $dir) {
</span><span class="cx">             print &quot;Creating $dir directory...\n&quot;;
</span><del>-            mkdir $dir || die $!;
</del><ins>+            mkdir $dir or die &quot;mkdir $dir failed: $!&quot;;
</ins><span class="cx">             # For some reason, passing in the permissions to &quot;mkdir&quot;
</span><span class="cx">             # doesn't work right, but doing a &quot;chmod&quot; does.
</span><del>-            chmod $dirs{$dir}, $dir || die $!;
</del><ins>+            chmod $dirs{$dir}, $dir or warn &quot;Cannot chmod $dir: $!&quot;;
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    # Move the testfile if we can't write to it, so that we can re-create
+    # it with the correct permissions below.
+    my $testfile = &quot;$datadir/mailer.testfile&quot;;
+    if (-e $testfile and !-w $testfile) {
+        _rename_file($testfile, &quot;$testfile.old&quot;);
+    }
+
+    # If old-params.txt exists in the root directory, move it to datadir.
+    my $oldparamsfile = &quot;old_params.txt&quot;;
+    if (-e $oldparamsfile) {
+        _rename_file($oldparamsfile, &quot;$datadir/$oldparamsfile&quot;);
+    }
+
</ins><span class="cx">     _create_files(%files);
</span><span class="cx">     if ($params-&gt;{index_html}) {
</span><span class="cx">         _create_files(%{$fs-&gt;{index_html}});
</span><span class="lines">@@ -372,45 +461,68 @@
</span><span class="cx">         unlink &quot;$datadir/versioncache&quot;;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    if (-e &quot;$datadir/duplicates.rdf&quot;) {
+        print &quot;Removing duplicates.rdf...\n&quot;;
+        unlink &quot;$datadir/duplicates.rdf&quot;;
+        unlink &quot;$datadir/duplicates-old.rdf&quot;;
+    }
+
+    if (-e &quot;$datadir/duplicates&quot;) {
+        print &quot;Removing duplicates directory...\n&quot;;
+        rmtree(&quot;$datadir/duplicates&quot;);
+    }
+
+    _remove_empty_css_files();
+    _convert_single_file_skins();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-# A simple helper for creating &quot;empty&quot; CSS files.
-sub _add_custom_css {
-    my ($skin_dir, $path, $create_files, $perms) = @_;
-    $create_files-&gt;{&quot;$skin_dir/$path&quot;} = { perms =&gt; $perms, contents =&gt; &lt;&lt;EOT
</del><ins>+sub _remove_empty_css_files {
+    my $skinsdir = bz_locations()-&gt;{'skinsdir'};
+    foreach my $css_file (glob(&quot;$skinsdir/custom/*.css&quot;),
+                          glob(&quot;$skinsdir/contrib/*/*.css&quot;))
+    {
+        _remove_empty_css($css_file);
+    }
+}
+
+# A simple helper for the update code that removes &quot;empty&quot; CSS files.
+sub _remove_empty_css {
+    my ($file) = @_;
+    my $basename = basename($file);
+    my $empty_contents = &lt;&lt;EOT;
</ins><span class="cx"> /*
</span><del>- * Custom rules for $path.
</del><ins>+ * Custom rules for $basename.
</ins><span class="cx">  * The rules you put here override rules in that stylesheet.
</span><span class="cx">  */
</span><span class="cx"> EOT
</span><ins>+    if (length($empty_contents) == -s $file) {
+        open(my $fh, '&lt;', $file) or warn &quot;$file: $!&quot;;
+        my $file_contents;
+        { local $/; $file_contents = &lt;$fh&gt;; }
+        if ($file_contents eq $empty_contents) {
+            print install_string('file_remove', { name =&gt; $file }), &quot;\n&quot;;
+            unlink $file or warn &quot;$file: $!&quot;;
+        }
</ins><span class="cx">     };
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# We used to allow a single css file in the skins/contrib/ directory
+# to be a whole skin.
+sub _convert_single_file_skins {
+    my $skinsdir = bz_locations()-&gt;{'skinsdir'};
+    foreach my $skin_file (glob &quot;$skinsdir/contrib/*.css&quot;) {
+        my $dir_name = $skin_file;
+        $dir_name =~ s/\.css$//;
+        mkdir $dir_name or warn &quot;$dir_name: $!&quot;;
+        _rename_file($skin_file, &quot;$dir_name/global.css&quot;);
+    }
+}
+
</ins><span class="cx"> sub create_htaccess {
</span><span class="cx">     _create_files(%{FILESYSTEM()-&gt;{htaccess}});
</span><span class="cx"> 
</span><span class="cx">     # Repair old .htaccess files
</span><del>-    my $htaccess = new IO::File('.htaccess', 'r') || die &quot;.htaccess: $!&quot;;
-    my $old_data;
-    { local $/; $old_data = &lt;$htaccess&gt;; }
-    $htaccess-&gt;close;
</del><span class="cx"> 
</span><del>-    my $repaired = 0;
-    if ($old_data =~ s/\|localconfig\|/\|.*localconfig.*\|/) {
-        $repaired = 1;
-    }
-    if ($old_data !~ /\(\.\*\\\.pm\|/) {
-        $old_data =~ s/\(/(.*\\.pm\|/;
-        $repaired = 1;
-    }
-    if ($repaired) {
-        print &quot;Repairing .htaccess...\n&quot;;
-        $htaccess = new IO::File('.htaccess', 'w') || die $!;
-        print $htaccess $old_data;
-        $htaccess-&gt;close;
-    }
-
-
</del><span class="cx">     my $webdot_dir = bz_locations()-&gt;{'webdotdir'};
</span><span class="cx">     # The public webdot IP address changed.
</span><span class="cx">     my $webdot = new IO::File(&quot;$webdot_dir/.htaccess&quot;, 'r')
</span><span class="lines">@@ -427,6 +539,17 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub _rename_file {
+    my ($from, $to) = @_;
+    print install_string('file_rename', { from =&gt; $from, to =&gt; $to }), &quot;\n&quot;;
+    if (-e $to) {
+        warn &quot;$to already exists, not moving\n&quot;;
+    }
+    else {
+        move($from, $to) or warn $!;
+    }
+}
+
</ins><span class="cx"> # A helper for the above functions.
</span><span class="cx"> sub _create_files {
</span><span class="cx">     my (%files) = @_;
</span><span class="lines">@@ -523,12 +646,40 @@
</span><span class="cx">     } 
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub fix_dir_permissions {
+    my ($dir) = @_;
+    return if ON_WINDOWS;
+    # Note that _get_owner_and_group is always silent here.
+    my ($owner_id, $group_id) = _get_owner_and_group();
</ins><span class="cx"> 
</span><ins>+    my $perms;
+    my $fs = FILESYSTEM();
+    if ($perms = $fs-&gt;{recurse_dirs}-&gt;{$dir}) {
+        _fix_perms_recursively($dir, $owner_id, $group_id, $perms);
+    }
+    elsif ($perms = $fs-&gt;{all_dirs}-&gt;{$dir}) {
+        _fix_perms($dir, $owner_id, $group_id, $perms);
+    }
+    else {
+        # Do nothing. We know nothing about this directory.
+        warn &quot;Unknown directory $dir&quot;;
+    }
+}
+
+sub fix_file_permissions {
+    my ($file) = @_;
+    return if ON_WINDOWS;
+    my $perms = FILESYSTEM()-&gt;{all_files}-&gt;{$file}-&gt;{perms};
+    # Note that _get_owner_and_group is always silent here.
+    my ($owner_id, $group_id) = _get_owner_and_group();
+    _fix_perms($file, $owner_id, $group_id, $perms);
+}
+
</ins><span class="cx"> sub fix_all_file_permissions {
</span><span class="cx">     my ($output) = @_;
</span><span class="cx"> 
</span><del>-    my $ws_group = Bugzilla-&gt;localconfig-&gt;{'webservergroup'};
-    my $group_id = _check_web_server_group($ws_group, $output);
</del><ins>+    # _get_owner_and_group also checks that the webservergroup is valid.
+    my ($owner_id, $group_id) = _get_owner_and_group($output);
</ins><span class="cx"> 
</span><span class="cx">     return if ON_WINDOWS;
</span><span class="cx"> 
</span><span class="lines">@@ -539,30 +690,18 @@
</span><span class="cx"> 
</span><span class="cx">     print get_text('install_file_perms_fix') . &quot;\n&quot; if $output;
</span><span class="cx"> 
</span><del>-    my $owner_id = POSIX::getuid();
-    $group_id = POSIX::getgid() unless defined $group_id;
-
</del><span class="cx">     foreach my $dir (sort keys %dirs) {
</span><span class="cx">         next unless -d $dir;
</span><span class="cx">         _fix_perms($dir, $owner_id, $group_id, $dirs{$dir});
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    foreach my $dir (sort keys %recurse_dirs) {
-        next unless -d $dir;
-        # Set permissions on the directory itself.
-        my $perms = $recurse_dirs{$dir};
-        _fix_perms($dir, $owner_id, $group_id, $perms-&gt;{dirs});
-        # Now recurse through the directory and set the correct permissions
-        # on subdirectories and files.
-        find({ no_chdir =&gt; 1, wanted =&gt; sub {
-            my $name = $File::Find::name;
-            if (-d $name) {
-                _fix_perms($name, $owner_id, $group_id, $perms-&gt;{dirs});
-            }
-            else {
-                _fix_perms($name, $owner_id, $group_id, $perms-&gt;{files});
-            }
-        }}, $dir);
</del><ins>+    foreach my $pattern (sort keys %recurse_dirs) {
+        my $perms = $recurse_dirs{$pattern};
+        # %recurse_dirs supports globs
+        foreach my $dir (glob $pattern) {
+            next unless -d $dir;
+            _fix_perms_recursively($dir, $owner_id, $group_id, $perms);
+        }
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     foreach my $file (sort keys %files) {
</span><span class="lines">@@ -578,6 +717,16 @@
</span><span class="cx">     _fix_cvs_dirs($owner_id, '.');
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub _get_owner_and_group {
+    my ($output) = @_;
+    my $group_id = _check_web_server_group($output);
+    return () if ON_WINDOWS;
+
+    my $owner_id = POSIX::getuid();
+    $group_id = POSIX::getgid() unless defined $group_id;
+    return ($owner_id, $group_id);
+}
+
</ins><span class="cx"> # A helper for fix_all_file_permissions
</span><span class="cx"> sub _fix_cvs_dirs {
</span><span class="cx">     my ($owner_id, $dir) = @_;
</span><span class="lines">@@ -585,8 +734,13 @@
</span><span class="cx">     find({ no_chdir =&gt; 1, wanted =&gt; sub {
</span><span class="cx">         my $name = $File::Find::name;
</span><span class="cx">         if ($File::Find::dir =~ /\/CVS/ || $_ eq '.cvsignore'
</span><del>-            || (-d $name &amp;&amp; $_ eq 'CVS')) {
-            _fix_perms($name, $owner_id, $owner_gid, 0700);
</del><ins>+            || (-d $name &amp;&amp; $_ =~ /CVS$/)) 
+        {
+            my $perms = 0600;
+            if (-d $name) {
+                $perms = 0700;
+            }
+            _fix_perms($name, $owner_id, $owner_gid, $perms);
</ins><span class="cx">         }
</span><span class="cx">     }}, $dir);
</span><span class="cx"> }
</span><span class="lines">@@ -594,15 +748,39 @@
</span><span class="cx"> sub _fix_perms {
</span><span class="cx">     my ($name, $owner, $group, $perms) = @_;
</span><span class="cx">     #printf (&quot;Changing $name to %o\n&quot;, $perms);
</span><del>-    chown $owner, $group, $name 
-        || warn &quot;Failed to change ownership of $name: $!&quot;;
</del><ins>+
+    # The webserver should never try to chown files.
+    if (Bugzilla-&gt;usage_mode == USAGE_MODE_CMDLINE) {
+        chown $owner, $group, $name
+            or warn install_string('chown_failed', { path =&gt; $name, 
+                                                     error =&gt; $! }) . &quot;\n&quot;;
+    }
</ins><span class="cx">     chmod $perms, $name
</span><del>-        || warn &quot;Failed to change permissions of $name: $!&quot;;
</del><ins>+        or warn install_string('chmod_failed', { path =&gt; $name, 
+                                                 error =&gt; $! }) . &quot;\n&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub _fix_perms_recursively {
+    my ($dir, $owner_id, $group_id, $perms) = @_;
+    # Set permissions on the directory itself.
+    _fix_perms($dir, $owner_id, $group_id, $perms-&gt;{dirs});
+    # Now recurse through the directory and set the correct permissions
+    # on subdirectories and files.
+    find({ no_chdir =&gt; 1, wanted =&gt; sub {
+        my $name = $File::Find::name;
+        if (-d $name) {
+            _fix_perms($name, $owner_id, $group_id, $perms-&gt;{dirs});
+        }
+        else {
+            _fix_perms($name, $owner_id, $group_id, $perms-&gt;{files});
+        }
+    }}, $dir);
+}
+
</ins><span class="cx"> sub _check_web_server_group {
</span><del>-    my ($group, $output) = @_;
</del><ins>+    my ($output) = @_;
</ins><span class="cx"> 
</span><ins>+    my $group    = Bugzilla-&gt;localconfig-&gt;{'webservergroup'};
</ins><span class="cx">     my $filename = bz_locations()-&gt;{'localconfig'};
</span><span class="cx">     my $group_id;
</span><span class="cx"> 
</span><span class="lines">@@ -686,4 +864,16 @@
</span><span class="cx"> 
</span><span class="cx"> Returns:     nothing
</span><span class="cx"> 
</span><ins>+=item C&lt;fix_dir_permissions&gt;
+
+Given the name of a directory, its permissions will be fixed according to
+how they are supposed to be set in Bugzilla's current configuration.
+If it fails to set the permissions, a warning will be printed to STDERR.
+
+=item C&lt;fix_file_permissions&gt;
+
+Given the name of a file, its permissions will be fixed according to
+how they are supposed to be set in Bugzilla's current configuration.
+If it fails to set the permissions, a warning will be printed to STDERR.
+
</ins><span class="cx"> =back
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaInstallLocalconfigpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Install/Localconfig.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Install/Localconfig.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Install/Localconfig.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -31,13 +31,14 @@
</span><span class="cx"> use strict;
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla::Constants;
</span><del>-use Bugzilla::Install::Util qw(bin_loc);
-use Bugzilla::Util qw(generate_random_password);
</del><ins>+use Bugzilla::Install::Util qw(bin_loc install_string);
+use Bugzilla::Util qw(generate_random_password wrap_hard);
</ins><span class="cx"> 
</span><span class="cx"> use Data::Dumper;
</span><span class="cx"> use File::Basename qw(dirname);
</span><span class="cx"> use IO::File;
</span><span class="cx"> use Safe;
</span><ins>+use Term::ANSIColor;
</ins><span class="cx"> 
</span><span class="cx"> use base qw(Exporter);
</span><span class="cx"> 
</span><span class="lines">@@ -50,164 +51,71 @@
</span><span class="cx">     {
</span><span class="cx">         name    =&gt; 'create_htaccess',
</span><span class="cx">         default =&gt; 1,
</span><del>-        desc    =&gt; &lt;&lt;EOT
-# If you are using Apache as your web server, Bugzilla can create .htaccess
-# files for you that will instruct Apache not to serve files that shouldn't
-# be accessed from the web browser (like your local configuration data and non-cgi
-# executable files).  For this to work, the directory your Bugzilla
-# installation is in must be within the jurisdiction of a &lt;Directory&gt; block
-# in the httpd.conf file that has 'AllowOverride Limit' in it.  If it has
-# 'AllowOverride All' or other options with Limit, that's fine.
-# (Older Apache installations may use an access.conf file to store these
-# &lt;Directory&gt; blocks.)
-# If this is set to 1, Bugzilla will create these files if they don't exist.
-# If this is set to 0, Bugzilla will not create these files.
-EOT
</del><span class="cx">     },
</span><span class="cx">     {
</span><span class="cx">         name    =&gt; 'webservergroup',
</span><span class="cx">         default =&gt; ON_WINDOWS ? '' : 'apache',
</span><del>-        desc    =&gt; q{# This is the group your web server runs as.
-# If you have a Windows box, ignore this setting.
-# If you do not have access to the group your web server runs under,
-# set this to &quot;&quot;. If you do set this to &quot;&quot;, then your Bugzilla installation
-# will be _VERY_ insecure, because some files will be world readable/writable,
-# and so anyone who can get local access to your machine can do whatever they
-# want. You should only have this set to &quot;&quot; if this is a testing installation
-# and you cannot set this up any other way. YOU HAVE BEEN WARNED!
-# If you set this to anything other than &quot;&quot;, you will need to run checksetup.pl
-# as} . ROOT_USER . qq{, or as a user who is a member of the specified group.\n}
</del><span class="cx">     },
</span><span class="cx">     {
</span><ins>+        name    =&gt; 'use_suexec',
+        default =&gt; 0,
+    },
+    {
</ins><span class="cx">         name    =&gt; 'db_driver',
</span><span class="cx">         default =&gt; 'mysql',
</span><del>-        desc    =&gt; &lt;&lt;EOT
-# What SQL database to use. Default is mysql. List of supported databases
-# can be obtained by listing Bugzilla/DB directory - every module corresponds
-# to one supported database and the name corresponds to a driver name.
-EOT
</del><span class="cx">     },
</span><span class="cx">     {
</span><span class="cx">         name    =&gt; 'db_host',
</span><del>-        default =&gt; 'localhost',
-        desc    =&gt; 
-            &quot;# The DNS name of the host that the database server runs on.\n&quot;
</del><ins>+        default =&gt; 'localhost',           
</ins><span class="cx">     },
</span><span class="cx">     {
</span><span class="cx">         name    =&gt; 'db_name',
</span><span class="cx">         default =&gt; 'bugs',
</span><del>-        desc    =&gt; &quot;# The name of the database\n&quot;
</del><span class="cx">     },
</span><span class="cx">     {
</span><span class="cx">         name    =&gt; 'db_user',
</span><span class="cx">         default =&gt; 'bugs',
</span><del>-        desc    =&gt; &quot;# Who we connect to the database as.\n&quot;
</del><span class="cx">     },
</span><span class="cx">     {
</span><span class="cx">         name    =&gt; 'db_pass',
</span><span class="cx">         default =&gt; '',
</span><del>-        desc    =&gt; &lt;&lt;EOT
-# Enter your database password here. It's normally advisable to specify
-# a password for your bugzilla database user.
-# If you use apostrophe (') or a backslash (\\) in your password, you'll
-# need to escape it by preceding it with a '\\' character. (\\') or (\\)
-# (Far simpler just not to use those characters.)
-EOT
</del><span class="cx">     },
</span><span class="cx">     {
</span><span class="cx">         name    =&gt; 'db_port',
</span><span class="cx">         default =&gt; 0,
</span><del>-        desc    =&gt; &lt;&lt;EOT
-# Sometimes the database server is running on a non-standard port. If that's
-# the case for your database server, set this to the port number that your
-# database server is running on. Setting this to 0 means &quot;use the default
-# port for my database server.&quot;
-EOT
</del><span class="cx">     },
</span><span class="cx">     {
</span><span class="cx">         name    =&gt; 'db_sock',
</span><span class="cx">         default =&gt; '',
</span><del>-        desc    =&gt; &lt;&lt;EOT
-# MySQL Only: Enter a path to the unix socket for MySQL. If this is
-# blank, then MySQL's compiled-in default will be used. You probably
-# want that.
-EOT
</del><span class="cx">     },
</span><span class="cx">     {
</span><span class="cx">         name    =&gt; 'db_check',
</span><span class="cx">         default =&gt; 1,
</span><del>-        desc    =&gt; &lt;&lt;EOT
-# Should checksetup.pl try to verify that your database setup is correct?
-# (with some combinations of database servers/Perl modules/moonphase this
-# doesn't work)
-EOT
</del><span class="cx">     },
</span><span class="cx">     {
</span><span class="cx">         name    =&gt; 'index_html',
</span><span class="cx">         default =&gt; 0,
</span><del>-        desc    =&gt; &lt;&lt;EOT
-# With the introduction of a configurable index page using the
-# template toolkit, Bugzilla's main index page is now index.cgi.
-# Most web servers will allow you to use index.cgi as a directory
-# index, and many come preconfigured that way, but if yours doesn't
-# then you'll need an index.html file that provides redirection
-# to index.cgi. Setting \$index_html to 1 below will allow
-# checksetup.pl to create one for you if it doesn't exist.
-# NOTE: checksetup.pl will not replace an existing file, so if you
-#       wish to have checksetup.pl create one for you, you must
-#       make sure that index.html doesn't already exist
-EOT
</del><span class="cx">     },
</span><span class="cx">     {
</span><span class="cx">         name    =&gt; 'cvsbin',
</span><del>-        default =&gt; \&amp;_get_default_cvsbin,
-        desc    =&gt; &lt;&lt;EOT
-# For some optional functions of Bugzilla (such as the pretty-print patch
-# viewer), we need the cvs binary to access files and revisions.
-# Because it's possible that this program is not in your path, you can specify
-# its location here.  Please specify the full path to the executable.
-EOT
</del><ins>+        default =&gt; sub { bin_loc('cvs') },
</ins><span class="cx">     },
</span><span class="cx">     {
</span><span class="cx">         name    =&gt; 'interdiffbin',
</span><del>-        default =&gt; \&amp;_get_default_interdiffbin,
-        desc    =&gt; &lt;&lt;EOT
-# For some optional functions of Bugzilla (such as the pretty-print patch
-# viewer), we need the interdiff binary to make diffs between two patches.
-# Because it's possible that this program is not in your path, you can specify
-# its location here.  Please specify the full path to the executable.
-EOT
</del><ins>+        default =&gt; sub { bin_loc('interdiff') },
</ins><span class="cx">     },
</span><span class="cx">     {
</span><span class="cx">         name    =&gt; 'diffpath',
</span><del>-        default =&gt; \&amp;_get_default_diffpath,
-        desc    =&gt; &lt;&lt;EOT
-# The interdiff feature needs diff, so we have to have that path.
-# Please specify the directory name only; do not use trailing slash.
-EOT
</del><ins>+        default =&gt; sub { dirname(bin_loc('diff')) },
</ins><span class="cx">     },
</span><span class="cx">     {
</span><span class="cx">         name    =&gt; 'site_wide_secret',
</span><span class="cx">         # 64 characters is roughly the equivalent of a 384-bit key, which
</span><span class="cx">         # is larger than anybody would ever be able to brute-force.
</span><span class="cx">         default =&gt; sub { generate_random_password(64) },
</span><del>-        desc    =&gt; &lt;&lt;EOT
-# This secret key is used by your installation for the creation and
-# validation of encrypted tokens to prevent unsolicited changes,
-# such as bug changes. A random string is generated by default.
-# It's very important that this key is kept secret. It also must be
-# very long.
-EOT
</del><span class="cx">     },
</span><span class="cx"> );
</span><span class="cx"> 
</span><del>-use constant OLD_LOCALCONFIG_VARS =&gt; qw(
-    mysqlpath
-    contenttypes
-    pages
-    severities platforms opsys priorities
-);
-
</del><span class="cx"> sub read_localconfig {
</span><span class="cx">     my ($include_deprecated) = @_;
</span><span class="cx">     my $filename = bz_locations()-&gt;{'localconfig'};
</span><span class="lines">@@ -221,23 +129,31 @@
</span><span class="cx">         $s-&gt;rdo($filename);
</span><span class="cx">         if ($@ || $!) {
</span><span class="cx">             my $err_msg = $@ ? $@ : $!;
</span><del>-            die &lt;&lt;EOT;
-An error has occurred while reading your 'localconfig' file.  The text of 
-the error message is:
-
-$err_msg
-
-Please fix the error in your 'localconfig' file. Alternately, rename your
-'localconfig' file, rerun checksetup.pl, and re-enter your answers.
-
-  \$ mv -f localconfig localconfig.old
-  \$ ./checksetup.pl
-EOT
</del><ins>+            die install_string('error_localconfig_read',
+                    { error =&gt; $err_msg, localconfig =&gt; $filename }), &quot;\n&quot;;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><del>-        my @vars = map($_-&gt;{name}, LOCALCONFIG_VARS);
-        push(@vars, OLD_LOCALCONFIG_VARS) if $include_deprecated;
-        foreach my $var (@vars) {
</del><ins>+        my @read_symbols;
+        if ($include_deprecated) {
+            # First we have to get the whole symbol table
+            my $safe_root = $s-&gt;root;
+            my %safe_package;
+            { no strict 'refs'; %safe_package = %{$safe_root . &quot;::&quot;}; }
+            # And now we read the contents of every var in the symbol table.
+            # However:
+            # * We only include symbols that start with an alphanumeric
+            #   character. This excludes symbols like &quot;_&lt;./localconfig&quot;
+            #   that show up in some perls.
+            # * We ignore the INC symbol, which exists in every package.
+            # * Perl 5.10 imports a lot of random symbols that all
+            #   contain &quot;::&quot;, and we want to ignore those.
+            @read_symbols = grep { /^[A-Za-z0-1]/ and !/^INC$/ and !/::/ }
+                                 (keys %safe_package);
+        }
+        else {
+            @read_symbols = map($_-&gt;{name}, LOCALCONFIG_VARS);
+        }
+        foreach my $var (@read_symbols) {
</ins><span class="cx">             my $glob = $s-&gt;varglob($var);
</span><span class="cx">             # We can't get the type of a variable out of a Safe automatically.
</span><span class="cx">             # We can only get the glob itself. So we figure out its type this
</span><span class="lines">@@ -250,10 +166,10 @@
</span><span class="cx">             if (defined $$glob) {
</span><span class="cx">                 $localconfig{$var} = $$glob;
</span><span class="cx">             }
</span><del>-            elsif (defined @$glob) {
</del><ins>+            elsif (@$glob) {
</ins><span class="cx">                 $localconfig{$var} = \@$glob;
</span><span class="cx">             }
</span><del>-            elsif (defined %$glob) {
</del><ins>+            elsif (%$glob) {
</ins><span class="cx">                 $localconfig{$var} = \%$glob;
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="lines">@@ -307,74 +223,62 @@
</span><span class="cx">         if (!defined $value) {
</span><span class="cx">             push(@new_vars, $name);
</span><span class="cx">             $var-&gt;{default} = &amp;{$var-&gt;{default}} if ref($var-&gt;{default}) eq 'CODE';
</span><del>-            $localconfig-&gt;{$name} = $answer-&gt;{$name} || $var-&gt;{default};
</del><ins>+            if (exists $answer-&gt;{$name}) {
+                $localconfig-&gt;{$name} = $answer-&gt;{$name};
+            }
+            else {
+                $localconfig-&gt;{$name} = $var-&gt;{default};
+            }
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    my @old_vars;
-    foreach my $name (OLD_LOCALCONFIG_VARS) {
-        push(@old_vars, $name) if defined $localconfig-&gt;{$name};
</del><ins>+    if (!$localconfig-&gt;{'interdiffbin'} &amp;&amp; $output) {
+        print &quot;\n&quot;, install_string('patchutils_missing'), &quot;\n&quot;;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (!$localconfig-&gt;{'interdiffbin'} &amp;&amp; $output) {
-        print &lt;&lt;EOT
-
-OPTIONAL NOTE: If you want to be able to use the 'difference between two
-patches' feature of Bugzilla (which requires the PatchReader Perl module
-as well), you should install patchutils from:
-
-    http://cyberelk.net/tim/patchutils/
-
-EOT
</del><ins>+    my @old_vars;
+    foreach my $var (keys %$localconfig) {
+        push(@old_vars, $var) if !grep($_-&gt;{name} eq $var, LOCALCONFIG_VARS);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     my $filename = bz_locations-&gt;{'localconfig'};
</span><span class="cx"> 
</span><ins>+    # Move any custom or old variables into a separate file.
</ins><span class="cx">     if (scalar @old_vars) {
</span><ins>+        my $filename_old = &quot;$filename.old&quot;;
+        open(my $old_file, &quot;&gt;&gt;:utf8&quot;, $filename_old) 
+            or die &quot;$filename_old: $!&quot;;
+        local $Data::Dumper::Purity = 1;
+        foreach my $var (@old_vars) {
+            print $old_file Data::Dumper-&gt;Dump([$localconfig-&gt;{$var}], 
+                                               [&quot;*$var&quot;]) . &quot;\n\n&quot;;
+        }
+        close $old_file;
</ins><span class="cx">         my $oldstuff = join(', ', @old_vars);
</span><del>-        print &lt;&lt;EOT
-
-The following variables are no longer used in $filename, and
-should be removed: $oldstuff
-
-EOT
</del><ins>+        print install_string('lc_old_vars',
+            { localconfig =&gt; $filename, old_file =&gt; $filename_old,
+              vars =&gt; $oldstuff }), &quot;\n&quot;;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (scalar @new_vars) {
-        my $filename = bz_locations-&gt;{'localconfig'};
-        my $fh = new IO::File($filename, '&gt;&gt;') || die &quot;$filename: $!&quot;;
-        $fh-&gt;seek(0, SEEK_END);
-        foreach my $var (LOCALCONFIG_VARS) {
-            if (grep($_ eq $var-&gt;{name}, @new_vars)) {
-                print $fh &quot;\n&quot;, $var-&gt;{desc},
-                      Data::Dumper-&gt;Dump([$localconfig-&gt;{$var-&gt;{name}}], 
-                                         [&quot;*$var-&gt;{name}&quot;]);
-            }
-        }
-        # When updating site_wide_secret to the new value, don't
-        # leave the old value behind.
-        if (grep { $_ eq 'site_wide_secret' } @new_vars) {
-            my $read = new IO::File($filename, '&lt;') || die &quot;$filename: $!&quot;;
-            my $text;
-            { local $/; $text = &lt;$read&gt; }
-            $read-&gt;close;
-            $text =~ s/^\$site_wide_secret = '\w{256}';$//ms;
-            my $write = new IO::File($filename, '&gt;') || die &quot;$filename: $!&quot;;
-            print $write $text;
-            $write-&gt;close;
-        }
</del><ins>+    # Re-write localconfig
+    open(my $fh, &quot;&gt;:utf8&quot;, $filename) or die &quot;$filename: $!&quot;;
+    foreach my $var (LOCALCONFIG_VARS) {
+        my $name = $var-&gt;{name};
+        my $desc = install_string(&quot;localconfig_$name&quot;, { root =&gt; ROOT_USER });
+        chomp($desc);
+        # Make the description into a comment.
+        $desc =~ s/^/# /mg;
+        print $fh $desc, &quot;\n&quot;,
+                  Data::Dumper-&gt;Dump([$localconfig-&gt;{$name}],
+                                     [&quot;*$name&quot;]), &quot;\n&quot;;
+   }
</ins><span class="cx"> 
</span><ins>+    if (@new_vars) {
</ins><span class="cx">         my $newstuff = join(', ', @new_vars);
</span><del>-        print &lt;&lt;EOT;
-
-This version of Bugzilla contains some variables that you may want to 
-change and adapt to your local settings. Please edit the file 
-$filename and rerun checksetup.pl.
-
-The following variables are new to $filename since you last ran
-checksetup.pl:  $newstuff
-
-EOT
</del><ins>+        print &quot;\n&quot;;
+        print colored(install_string('lc_new_vars', { localconfig =&gt; $filename,
+                                                      new_vars =&gt; wrap_hard($newstuff, 70) }),
+                      COLOR_ERROR), &quot;\n&quot;;
</ins><span class="cx">         exit;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -384,13 +288,6 @@
</span><span class="cx">     return { old_vars =&gt; \@old_vars, new_vars =&gt; \@new_vars };
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _get_default_cvsbin       { return bin_loc('cvs') }
-sub _get_default_interdiffbin { return bin_loc('interdiff') }
-sub _get_default_diffpath {
-    my $diff_bin = bin_loc('diff');
-    return dirname($diff_bin);
-}
-
</del><span class="cx"> 1;
</span><span class="cx"> 
</span><span class="cx"> __END__
</span><span class="lines">@@ -438,31 +335,46 @@
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><del>-=item C&lt;read_localconfig($include_deprecated)&gt;
</del><ins>+=item C&lt;read_localconfig&gt;
</ins><span class="cx"> 
</span><del>-Description: Reads the localconfig file and returns all valid
-             values in a hashref.
</del><ins>+=over
</ins><span class="cx"> 
</span><del>-Params:      C&lt;$include_deprecated&gt; - C&lt;true&gt; if you want the returned
-                 hashref to also include variables listed in 
-                 C&lt;OLD_LOCALCONFIG_VARS&gt;, if they exist. Generally
-                 this is only for use by C&lt;update_localconfig&gt;.
</del><ins>+=item B&lt;Description&gt;
</ins><span class="cx"> 
</span><del>-Returns:     A hashref of the localconfig variables. If an array
-             is defined, it will be an arrayref in the returned hash. If a
-             hash is defined, it will be a hashref in the returned hash.
-             Only includes variables specified in C&lt;LOCALCONFIG_VARS&gt;
-             (and C&lt;OLD_LOCALCONFIG_VARS&gt; if C&lt;$include_deprecated&gt; is
-             specified).
</del><ins>+Reads the localconfig file and returns all valid values in a hashref.
</ins><span class="cx"> 
</span><del>-=item C&lt;update_localconfig({ output =E&lt;gt&gt; 1 })&gt;
</del><ins>+=item B&lt;Params&gt;
</ins><span class="cx"> 
</span><ins>+=over
+
+=item C&lt;$include_deprecated&gt; 
+
+C&lt;true&gt; if you want the returned hashref to include *any* variable
+currently defined in localconfig, even if it doesn't exist in 
+C&lt;LOCALCONFIG_VARS&gt;. Generally this is is only for use 
+by L&lt;/update_localconfig&gt;.
+
+=back
+
+=item B&lt;Returns&gt;
+
+A hashref of the localconfig variables. If an array is defined in
+localconfig, it will be an arrayref in the returned hash. If a
+hash is defined, it will be a hashref in the returned hash.
+Only includes variables specified in C&lt;LOCALCONFIG_VARS&gt;, unless
+C&lt;$include_deprecated&gt; is true.
+
+=back
+
+
+=item C&lt;update_localconfig&gt;
+
</ins><span class="cx"> Description: Adds any new variables to localconfig that aren't
</span><span class="cx">              currently defined there. Also optionally prints out
</span><span class="cx">              a message about vars that *should* be there and aren't.
</span><span class="cx">              Exits the program if it adds any new vars.
</span><span class="cx"> 
</span><del>-Params:      C&lt;output&gt; - C&lt;true&gt; if the function should display informational
</del><ins>+Params:      C&lt;$output&gt; - C&lt;true&gt; if the function should display informational
</ins><span class="cx">                  output and warnings. It will always display errors or
</span><span class="cx">                  any message which would cause program execution to halt.
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaInstallRequirementspm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Install/Requirements.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Install/Requirements.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Install/Requirements.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -25,23 +25,58 @@
</span><span class="cx"> 
</span><span class="cx"> use strict;
</span><span class="cx"> 
</span><del>-use Bugzilla::Install::Util qw(vers_cmp install_string);
</del><ins>+use Bugzilla::Constants;
+use Bugzilla::Install::Util qw(vers_cmp install_string bin_loc 
+                               extension_requirement_packages);
</ins><span class="cx"> use List::Util qw(max);
</span><span class="cx"> use Safe;
</span><ins>+use Term::ANSIColor;
</ins><span class="cx"> 
</span><span class="cx"> use base qw(Exporter);
</span><span class="cx"> our @EXPORT = qw(
</span><span class="cx">     REQUIRED_MODULES
</span><span class="cx">     OPTIONAL_MODULES
</span><ins>+    FEATURE_FILES
</ins><span class="cx"> 
</span><span class="cx">     check_requirements
</span><span class="cx">     check_graphviz
</span><span class="cx">     have_vers
</span><span class="cx">     install_command
</span><ins>+    map_files_to_features
</ins><span class="cx"> );
</span><span class="cx"> 
</span><del>-use Bugzilla::Constants;
</del><ins>+# This is how many *'s are in the top of each &quot;box&quot; message printed
+# by checksetup.pl.
+use constant TABLE_WIDTH =&gt; 71;
</ins><span class="cx"> 
</span><ins>+# Optional Apache modules that have no Perl component to them.
+# If these are installed, Bugzilla has additional functionality.
+#
+# The keys are the names of the modules, the values are what the module
+# is called in the output of &quot;apachectl -t -D DUMP_MODULES&quot;.
+use constant APACHE_MODULES =&gt; { 
+    mod_headers =&gt; 'headers_module',
+    mod_env     =&gt; 'env_module',
+    mod_expires =&gt; 'expires_module',
+};
+
+# These are all of the binaries that we could possibly use that can
+# give us info about which Apache modules are installed.
+# If we can't use &quot;apachectl&quot;, the &quot;httpd&quot; binary itself takes the same
+# parameters. Note that on Debian and Gentoo, there is an &quot;apache2ctl&quot;,
+# but it takes different parameters on each of those two distros, so we
+# don't use apache2ctl.
+use constant APACHE =&gt; qw(apachectl httpd apache2 apache);
+
+# If we don't find any of the above binaries in the normal PATH,
+# these are extra places we look.
+use constant APACHE_PATH =&gt; [qw(
+    /usr/sbin 
+    /usr/local/sbin
+    /usr/libexec
+    /usr/local/libexec
+)];
+
</ins><span class="cx"> # The below two constants are subroutines so that they can implement
</span><span class="cx"> # a hook. Other than that they are actually constants.
</span><span class="cx"> 
</span><span class="lines">@@ -59,66 +94,113 @@
</span><span class="cx">     {
</span><span class="cx">         package =&gt; 'CGI.pm',
</span><span class="cx">         module  =&gt; 'CGI',
</span><del>-        # Perl 5.10 requires CGI 3.33 due to a taint issue when
-        # uploading attachments, see bug 416382.
-        # Require CGI 3.21 for -httponly support, see bug 368502.
-        version =&gt; (vers_cmp($perl_ver, '5.10') &gt; -1) ? '3.33' : '3.21'
</del><ins>+        # 3.51 fixes a security problem that affects Bugzilla.
+        # (bug 591165)
+        version =&gt; '3.51',
</ins><span class="cx">     },
</span><span class="cx">     {
</span><ins>+        package =&gt; 'Digest-SHA',
+        module  =&gt; 'Digest::SHA',
+        version =&gt; 0
+    },
+    {
</ins><span class="cx">         package =&gt; 'TimeDate',
</span><span class="cx">         module  =&gt; 'Date::Format',
</span><span class="cx">         version =&gt; '2.21'
</span><span class="cx">     },
</span><ins>+    # 0.28 fixed some important bugs in DateTime.
</ins><span class="cx">     {
</span><del>-        package =&gt; 'PathTools',
-        module  =&gt; 'File::Spec',
-        version =&gt; '0.84'
</del><ins>+        package =&gt; 'DateTime',
+        module  =&gt; 'DateTime',
+        version =&gt; '0.28'
</ins><span class="cx">     },
</span><ins>+    # 0.79 is required to work on Windows Vista and Windows Server 2008.
+    # As correctly detecting the flavor of Windows is not easy,
+    # we require this version for all Windows installations.
+    # 0.71 fixes a major bug affecting all platforms.
</ins><span class="cx">     {
</span><ins>+        package =&gt; 'DateTime-TimeZone',
+        module  =&gt; 'DateTime::TimeZone',
+        version =&gt; ON_WINDOWS ? '0.79' : '0.71'
+    },
+    {
</ins><span class="cx">         package =&gt; 'DBI',
</span><span class="cx">         module  =&gt; 'DBI',
</span><del>-        version =&gt; '1.41'
</del><ins>+        version =&gt; (vers_cmp($perl_ver, '5.13.3') &gt; -1) ? '1.614' : '1.41'
</ins><span class="cx">     },
</span><ins>+    # 2.22 fixes various problems related to UTF8 strings in hash keys,
+    # as well as line endings on Windows.
</ins><span class="cx">     {
</span><span class="cx">         package =&gt; 'Template-Toolkit',
</span><span class="cx">         module  =&gt; 'Template',
</span><del>-        version =&gt; '2.15'
</del><ins>+        version =&gt; '2.22'
</ins><span class="cx">     },
</span><span class="cx">     {
</span><span class="cx">         package =&gt; 'Email-Send',
</span><span class="cx">         module  =&gt; 'Email::Send',
</span><del>-        version =&gt; ON_WINDOWS ? '2.16' : '2.00'
</del><ins>+        version =&gt; ON_WINDOWS ? '2.16' : '2.00',
+        blacklist =&gt; ['^2\.196$']
</ins><span class="cx">     },
</span><span class="cx">     {
</span><span class="cx">         package =&gt; 'Email-MIME',
</span><span class="cx">         module  =&gt; 'Email::MIME',
</span><del>-        version =&gt; '1.861'
</del><ins>+        # This fixes a memory leak in walk_parts that affected jobqueue.pl.
+        version =&gt; '1.904'
</ins><span class="cx">     },
</span><span class="cx">     {
</span><del>-        package =&gt; 'Email-MIME-Modifier',
-        module  =&gt; 'Email::MIME::Modifier',
-        version =&gt; '1.442'
</del><ins>+        package =&gt; 'URI',
+        module  =&gt; 'URI',
+        # This version properly handles a semicolon as the delimiter
+        # in a URL query string.
+        version =&gt; '1.37',
</ins><span class="cx">     },
</span><ins>+    {
+        package =&gt; 'List-MoreUtils',
+        module  =&gt; 'List::MoreUtils',
+        version =&gt; 0.22,
+    },
+    {
+        package =&gt; 'Math-Random-ISAAC',
+        module  =&gt; 'Math::Random::ISAAC',
+        version =&gt; '1.0.1',
+    },
</ins><span class="cx">     );
</span><span class="cx"> 
</span><del>-    my $all_modules = _get_extension_requirements(
-        'REQUIRED_MODULES', \@modules);
-    return $all_modules;
</del><ins>+    if (ON_WINDOWS) {
+        push(@modules, {
+            package =&gt; 'Win32',
+            module  =&gt; 'Win32',
+            # 0.35 fixes a memory leak in GetOSVersion, which we use.
+            version =&gt; 0.35,
+        }, 
+        {
+            package =&gt; 'Win32-API',
+            module  =&gt; 'Win32::API',
+            # 0.55 fixes a bug with char* that might affect Bugzilla::RNG.
+            version =&gt; '0.55',
+        });
+    }
+
+    my $extra_modules = _get_extension_requirements('REQUIRED_MODULES');
+    push(@modules, @$extra_modules);
+    return \@modules;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> sub OPTIONAL_MODULES {
</span><ins>+    my $perl_ver = sprintf('%vd', $^V);
</ins><span class="cx">     my @modules = (
</span><span class="cx">     {
</span><span class="cx">         package =&gt; 'GD',
</span><span class="cx">         module  =&gt; 'GD',
</span><span class="cx">         version =&gt; '1.20',
</span><del>-        feature =&gt; 'Graphical Reports, New Charts, Old Charts'
</del><ins>+        feature =&gt; [qw(graphical_reports new_charts old_charts)],
</ins><span class="cx">     },
</span><span class="cx">     {
</span><span class="cx">         package =&gt; 'Chart',
</span><del>-        module  =&gt; 'Chart::Base',
-        version =&gt; '1.0',
-        feature =&gt; 'New Charts, Old Charts'
</del><ins>+        module  =&gt; 'Chart::Lines',
+        # Versions below 2.1 cannot be detected accurately.
+        version =&gt; '2.1',
+        feature =&gt; [qw(new_charts old_charts)],
</ins><span class="cx">     },
</span><span class="cx">     {
</span><span class="cx">         package =&gt; 'Template-GD',
</span><span class="lines">@@ -126,150 +208,197 @@
</span><span class="cx">         # on Template-Toolkits after 2.14, and still works with 2.14 and lower.
</span><span class="cx">         module  =&gt; 'Template::Plugin::GD::Image',
</span><span class="cx">         version =&gt; 0,
</span><del>-        feature =&gt; 'Graphical Reports'
</del><ins>+        feature =&gt; ['graphical_reports'],
</ins><span class="cx">     },
</span><span class="cx">     {
</span><span class="cx">         package =&gt; 'GDTextUtil',
</span><span class="cx">         module  =&gt; 'GD::Text',
</span><span class="cx">         version =&gt; 0,
</span><del>-        feature =&gt; 'Graphical Reports'
</del><ins>+        feature =&gt; ['graphical_reports'],
</ins><span class="cx">     },
</span><span class="cx">     {
</span><span class="cx">         package =&gt; 'GDGraph',
</span><span class="cx">         module  =&gt; 'GD::Graph',
</span><span class="cx">         version =&gt; 0,
</span><del>-        feature =&gt; 'Graphical Reports'
</del><ins>+        feature =&gt; ['graphical_reports'],
</ins><span class="cx">     },
</span><span class="cx">     {
</span><del>-        package =&gt; 'XML-Twig',
-        module  =&gt; 'XML::Twig',
-        version =&gt; 0,
-        feature =&gt; 'Move Bugs Between Installations'
-    },
-    {
</del><span class="cx">         package =&gt; 'MIME-tools',
</span><span class="cx">         # MIME::Parser is packaged as MIME::Tools on ActiveState Perl
</span><span class="cx">         module  =&gt; ON_WINDOWS ? 'MIME::Tools' : 'MIME::Parser',
</span><span class="cx">         version =&gt; '5.406',
</span><del>-        feature =&gt; 'Move Bugs Between Installations'
</del><ins>+        feature =&gt; ['moving'],
</ins><span class="cx">     },
</span><span class="cx">     {
</span><span class="cx">         package =&gt; 'libwww-perl',
</span><span class="cx">         module  =&gt; 'LWP::UserAgent',
</span><span class="cx">         version =&gt; 0,
</span><del>-        feature =&gt; 'Automatic Update Notifications'
</del><ins>+        feature =&gt; ['updates'],
</ins><span class="cx">     },
</span><span class="cx">     {
</span><ins>+        package =&gt; 'XML-Twig',
+        module  =&gt; 'XML::Twig',
+        version =&gt; 0,
+        feature =&gt; ['moving', 'updates'],
+    },
+    {
</ins><span class="cx">         package =&gt; 'PatchReader',
</span><span class="cx">         module  =&gt; 'PatchReader',
</span><del>-        version =&gt; '0.9.4',
-        feature =&gt; 'Patch Viewer'
</del><ins>+        # 0.9.6 fixes two notable bugs and significantly improves the UX.
+        version =&gt; '0.9.6',
+        feature =&gt; ['patch_viewer'],
</ins><span class="cx">     },
</span><span class="cx">     {
</span><del>-        package =&gt; 'PerlMagick',
-        module  =&gt; 'Image::Magick',
-        version =&gt; 0,
-        feature =&gt; 'Optionally Convert BMP Attachments to PNGs'
-    },
-    {
</del><span class="cx">         package =&gt; 'perl-ldap',
</span><span class="cx">         module  =&gt; 'Net::LDAP',
</span><span class="cx">         version =&gt; 0,
</span><del>-        feature =&gt; 'LDAP Authentication'
</del><ins>+        feature =&gt; ['auth_ldap'],
</ins><span class="cx">     },
</span><span class="cx">     {
</span><span class="cx">         package =&gt; 'Authen-SASL',
</span><span class="cx">         module  =&gt; 'Authen::SASL',
</span><span class="cx">         version =&gt; 0,
</span><del>-        feature =&gt; 'SMTP Authentication'
</del><ins>+        feature =&gt; ['smtp_auth'],
</ins><span class="cx">     },
</span><span class="cx">     {
</span><span class="cx">         package =&gt; 'RadiusPerl',
</span><span class="cx">         module  =&gt; 'Authen::Radius',
</span><span class="cx">         version =&gt; 0,
</span><del>-        feature =&gt; 'RADIUS Authentication'
</del><ins>+        feature =&gt; ['auth_radius'],
</ins><span class="cx">     },
</span><span class="cx">     {
</span><span class="cx">         package =&gt; 'SOAP-Lite',
</span><span class="cx">         module  =&gt; 'SOAP::Lite',
</span><ins>+        # Fixes various bugs, including 542931 and 552353 + stops
+        # throwing warnings with Perl 5.12.
+        version =&gt; '0.712',
+        feature =&gt; ['xmlrpc'],
+    },
+    {
+        package =&gt; 'JSON-RPC',
+        module  =&gt; 'JSON::RPC',
</ins><span class="cx">         version =&gt; 0,
</span><del>-        # These versions (0.70 -&gt; 0.710.05) are affected by bug 468009
-        blacklist =&gt; ['^0\.70', '^0\.710?\.0[1-5]$'],
-        feature =&gt; 'XML-RPC Interface'
</del><ins>+        feature =&gt; ['jsonrpc'],
</ins><span class="cx">     },
</span><span class="cx">     {
</span><ins>+        package =&gt; 'JSON-XS',
+        module  =&gt; 'JSON::XS',
+        # 2.0 is the first version that will work with JSON::RPC.
+        version =&gt; '2.0',
+        feature =&gt; ['jsonrpc_faster'],
+    },
+    {
+        package =&gt; 'Test-Taint',
+        module  =&gt; 'Test::Taint',
+        version =&gt; 0,
+        feature =&gt; ['jsonrpc', 'xmlrpc'],
+    },
+    {
</ins><span class="cx">         # We need the 'utf8_mode' method of HTML::Parser, for HTML::Scrubber.
</span><span class="cx">         package =&gt; 'HTML-Parser',
</span><span class="cx">         module  =&gt; 'HTML::Parser',
</span><del>-        version =&gt; '3.40',
-        feature =&gt; 'More HTML in Product/Group Descriptions'
</del><ins>+        version =&gt; (vers_cmp($perl_ver, '5.13.3') &gt; -1) ? '3.67' : '3.40',
+        feature =&gt; ['html_desc'],
</ins><span class="cx">     },
</span><span class="cx">     {
</span><span class="cx">         package =&gt; 'HTML-Scrubber',
</span><span class="cx">         module  =&gt; 'HTML::Scrubber',
</span><span class="cx">         version =&gt; 0,
</span><del>-        feature =&gt; 'More HTML in Product/Group Descriptions'
</del><ins>+        feature =&gt; ['html_desc'],
</ins><span class="cx">     },
</span><ins>+    {
+        # we need version 2.21 of Encode for mime_name
+        package =&gt; 'Encode',
+        module  =&gt; 'Encode',
+        version =&gt; 2.21,
+        feature =&gt; ['detect_charset'],
+    },
+    {
+        package =&gt; 'Encode-Detect',
+        module  =&gt; 'Encode::Detect',
+        version =&gt; 0,
+        feature =&gt; ['detect_charset'],
+    },
</ins><span class="cx"> 
</span><span class="cx">     # Inbound Email
</span><span class="cx">     {
</span><span class="cx">         package =&gt; 'Email-MIME-Attachment-Stripper',
</span><span class="cx">         module  =&gt; 'Email::MIME::Attachment::Stripper',
</span><span class="cx">         version =&gt; 0,
</span><del>-        feature =&gt; 'Inbound Email'
</del><ins>+        feature =&gt; ['inbound_email'],
</ins><span class="cx">     },
</span><span class="cx">     {
</span><span class="cx">         package =&gt; 'Email-Reply',
</span><span class="cx">         module  =&gt; 'Email::Reply',
</span><span class="cx">         version =&gt; 0,
</span><del>-        feature =&gt; 'Inbound Email'
</del><ins>+        feature =&gt; ['inbound_email'],
</ins><span class="cx">     },
</span><span class="cx"> 
</span><ins>+    # Mail Queueing
+    {
+        package =&gt; 'TheSchwartz',
+        module  =&gt; 'TheSchwartz',
+        version =&gt; 0,
+        feature =&gt; ['jobqueue'],
+    },
+    {
+        package =&gt; 'Daemon-Generic',
+        module  =&gt; 'Daemon::Generic',
+        version =&gt; 0,
+        feature =&gt; ['jobqueue'],
+    },
+
</ins><span class="cx">     # mod_perl
</span><span class="cx">     {
</span><span class="cx">         package =&gt; 'mod_perl',
</span><span class="cx">         module  =&gt; 'mod_perl2',
</span><span class="cx">         version =&gt; '1.999022',
</span><del>-        feature =&gt; 'mod_perl'
</del><ins>+        feature =&gt; ['mod_perl'],
</ins><span class="cx">     },
</span><span class="cx">     {
</span><del>-        package =&gt; 'Math-Random-Secure',
-        module  =&gt; 'Math::Random::Secure',
-        version =&gt; '0.05',
-        feature =&gt; 'Improve cookie and token security',
</del><ins>+        package =&gt; 'Apache-SizeLimit',
+        module  =&gt; 'Apache2::SizeLimit',
+        # 0.96 properly determines process size on Linux.
+        version =&gt; '0.96',
+        feature =&gt; ['mod_perl'],
</ins><span class="cx">     },
</span><span class="cx">     );
</span><span class="cx"> 
</span><del>-    my $all_modules = _get_extension_requirements(
-        'OPTIONAL_MODULES', \@modules);
-    return $all_modules;
</del><ins>+    my $extra_modules = _get_extension_requirements('OPTIONAL_MODULES');
+    push(@modules, @$extra_modules);
+    return \@modules;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><del>-# This implements the install-requirements hook described in Bugzilla::Hook.
</del><ins>+# This maps features to the files that require that feature in order
+# to compile. It is used by t/001compile.t and mod_perl.pl.
+use constant FEATURE_FILES =&gt; (
+    jsonrpc       =&gt; ['Bugzilla/WebService/Server/JSONRPC.pm', 'jsonrpc.cgi'],
+    xmlrpc        =&gt; ['Bugzilla/WebService/Server/XMLRPC.pm', 'xmlrpc.cgi',
+                      'Bugzilla/WebService.pm', 'Bugzilla/WebService/*.pm'],
+    moving        =&gt; ['importxml.pl'],
+    auth_ldap     =&gt; ['Bugzilla/Auth/Verify/LDAP.pm'],
+    auth_radius   =&gt; ['Bugzilla/Auth/Verify/RADIUS.pm'],
+    inbound_email =&gt; ['email_in.pl'],
+    jobqueue      =&gt; ['Bugzilla/Job/*', 'Bugzilla/JobQueue.pm',
+                      'Bugzilla/JobQueue/*', 'jobqueue.pl'],
+    patch_viewer  =&gt; ['Bugzilla/Attachment/PatchReader.pm'],
+    updates       =&gt; ['Bugzilla/Update.pm'],
+);
+
+# This implements the REQUIRED_MODULES and OPTIONAL_MODULES stuff
+# described in in Bugzilla::Extension.
</ins><span class="cx"> sub _get_extension_requirements {
</span><del>-    my ($function, $base_modules) = @_;
-    my @all_modules;
-    # get a list of all extensions
-    my @extensions = glob(bz_locations()-&gt;{'extensionsdir'} . &quot;/*&quot;);
-    foreach my $extension (@extensions) {
-        my $file = &quot;$extension/code/install-requirements.pl&quot;;
-        if (-e $file) {
-            my $safe = new Safe;
-            # This is a very liberal Safe.
-            $safe-&gt;permit(qw(:browse require entereval caller));
-            $safe-&gt;rdo($file);
-            if ($@) {
-                warn $@;
-                next;
-            }
-            my $modules = eval { &amp;{$safe-&gt;varglob($function)}($base_modules) };
-            next unless $modules;
-            push(@all_modules, @$modules);
</del><ins>+    my ($function) = @_;
+
+    my $packages = extension_requirement_packages();
+    my @modules;
+    foreach my $package (@$packages) {
+        if ($package-&gt;can($function)) {
+            my $extra_modules = $package-&gt;$function;
+            push(@modules, @$extra_modules);
</ins><span class="cx">         }
</span><span class="cx">     }
</span><del>-
-    unshift(@all_modules, @$base_modules);
-    return \@all_modules;
</del><ins>+    return \@modules;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> sub check_requirements {
</span><span class="lines">@@ -290,6 +419,8 @@
</span><span class="cx">     print &quot;\n&quot;, install_string('checking_optional'), &quot;\n&quot; if $output;
</span><span class="cx">     my $missing_optional = _check_missing(OPTIONAL_MODULES, $output);
</span><span class="cx"> 
</span><ins>+    my $missing_apache = _missing_apache_modules(APACHE_MODULES, $output);
+
</ins><span class="cx">     # If we're running on Windows, reset the input line terminator so that
</span><span class="cx">     # console input works properly - loading CGI tends to mess it up
</span><span class="cx">     $/ = &quot;\015\012&quot; if ON_WINDOWS;
</span><span class="lines">@@ -300,6 +431,7 @@
</span><span class="cx">         one_dbd  =&gt; $have_one_dbd,
</span><span class="cx">         missing  =&gt; $missing,
</span><span class="cx">         optional =&gt; $missing_optional,
</span><ins>+        apache   =&gt; $missing_apache,
</ins><span class="cx">         any_missing =&gt; !$pass || scalar(@$missing_optional),
</span><span class="cx">     };
</span><span class="cx"> }
</span><span class="lines">@@ -318,187 +450,202 @@
</span><span class="cx">     return \@missing;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-# Returns the build ID of ActivePerl. If several versions of
-# ActivePerl are installed, it won't be able to know which one
-# you are currently running. But that's our best guess.
-sub _get_activestate_build_id {
-    eval 'use Win32::TieRegistry';
-    return 0 if $@;
-    my $key = Win32::TieRegistry-&gt;new('LMachine\Software\ActiveState\ActivePerl')
-      or return 0;
-    return $key-&gt;GetValue(&quot;CurrentVersion&quot;);
</del><ins>+sub _missing_apache_modules {
+    my ($modules, $output) = @_;
+    my $apachectl = _get_apachectl();
+    return [] if !$apachectl;
+    my $command = &quot;$apachectl -t -D DUMP_MODULES&quot;;
+    my $cmd_info = `$command 2&gt;&amp;1`;
+    # If apachectl returned a value greater than 0, then there was an
+    # error parsing Apache's configuration, and we can't check modules.
+    my $retval = $?;
+    if ($retval &gt; 0) {
+        print STDERR install_string('apachectl_failed', 
+            { command =&gt; $command, root =&gt; ROOT_USER }), &quot;\n&quot;;
+        return [];
+    }
+    my @missing;
+    foreach my $module (keys %$modules) {
+        my $ok = _check_apache_module($module, $modules-&gt;{$module}, 
+                                      $cmd_info, $output);
+        push(@missing, $module) if !$ok;
+    }
+    return \@missing;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub _get_apachectl {
+    foreach my $bin_name (APACHE) {
+        my $bin = bin_loc($bin_name);
+        return $bin if $bin;
+    }
+    # Try again with a possibly different path.
+    foreach my $bin_name (APACHE) {
+        my $bin = bin_loc($bin_name, APACHE_PATH);
+        return $bin if $bin;
+    }
+    return undef;
+}
+
+sub _check_apache_module {
+    my ($module, $config_name, $mod_info, $output) = @_;
+    my $ok;
+    if ($mod_info =~ /^\s+\Q$config_name\E\b/m) {
+        $ok = 1;
+    }
+    if ($output) {
+        _checking_for({ package =&gt; $module, ok =&gt; $ok });
+    }
+    return $ok;
+}
+
</ins><span class="cx"> sub print_module_instructions {
</span><span class="cx">     my ($check_results, $output) = @_;
</span><span class="cx"> 
</span><del>-    # We only print these notes if we have to.
-    if ((!$output &amp;&amp; @{$check_results-&gt;{missing}})
-        || ($output &amp;&amp; $check_results-&gt;{any_missing}))
-    {
-        
-        if (ON_WINDOWS) {
</del><ins>+    # First we print the long explanatory messages.
</ins><span class="cx"> 
</span><del>-            print &quot;\n* NOTE: You must run any commands listed below as &quot;
-                  . ROOT_USER . &quot;.\n\n&quot;;
-
-            my $perl_ver = sprintf('%vd', $^V);
-            
-            # URL when running Perl 5.8.x.
-            my $url_to_theory58S = 'http://theoryx5.uwinnipeg.ca/ppms';
-            my $repo_up_cmd =
-'*                                                                     *';
-            # Packages for Perl 5.10 are not compatible with Perl 5.8.
-            if (vers_cmp($perl_ver, '5.10') &gt; -1) {
-                $url_to_theory58S = 'http://cpan.uwinnipeg.ca/PPMPackages/10xx/';
-            }
-            # ActivePerl older than revision 819 require an additional command.
-            if (_get_activestate_build_id() &lt; 819) {
-                $repo_up_cmd = &lt;&lt;EOT;
-*                                                                     *
-* Then you have to do (also as an Administrator):                     *
-*                                                                     *
-*   ppm repo up theory58S                                             *
-*                                                                     *
-* Do that last command over and over until you see &quot;theory58S&quot; at the *
-* top of the displayed list.                                          *
-EOT
-            }
-            print &lt;&lt;EOT;
-***********************************************************************
-* Note For Windows Users                                              *
-***********************************************************************
-* In order to install the modules listed below, you first have to run * 
-* the following command as an Administrator:                          *
-*                                                                     *
-*   ppm repo add theory58S $url_to_theory58S
-$repo_up_cmd
-***********************************************************************
-EOT
-        }
</del><ins>+    if (scalar @{$check_results-&gt;{missing}}) {
+        print install_string('modules_message_required');
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    # Required Modules
-    if (my @missing = @{$check_results-&gt;{missing}}) {
-        print &lt;&lt;EOT;
-***********************************************************************
-* REQUIRED MODULES                                                    *
-***********************************************************************
-* Bugzilla requires you to install some Perl modules which are either *
-* missing from your system, or the version on your system is too old. *
-*                                                                     *
-* The latest versions of each module can be installed by running the  *
-* commands below.                                                     *
-***********************************************************************
-EOT
-
-        print &quot;COMMANDS:\n\n&quot;;
-        foreach my $package (@missing) {
-            my $command = install_command($package);
-            print &quot;    $command\n&quot;;
-        }
-        print &quot;\n&quot;;
-    }
-
</del><span class="cx">     if (!$check_results-&gt;{one_dbd}) {
</span><del>-        print &lt;&lt;EOT;
-***********************************************************************
-* DATABASE ACCESS                                                     *
-***********************************************************************
-* In order to access your database, Bugzilla requires that the        *
-* correct &quot;DBD&quot; module be installed for the database that you are     *
-* running.                                                            *
-*                                                                     *
-* Pick and run the correct command below for the database that you    *
-* plan to use with Bugzilla.                                          *
-***********************************************************************
-COMMANDS:
-
-EOT
-
-        my %db_modules = %{DB_MODULE()};
-        foreach my $db (keys %db_modules) {
-            my $command = install_command($db_modules{$db}-&gt;{dbd});
-            printf &quot;%10s: \%s\n&quot;, $db_modules{$db}-&gt;{name}, $command;
-            print ' ' x 12 . &quot;Minimum version required: &quot;
-                  . $db_modules{$db}-&gt;{dbd}-&gt;{version} . &quot;\n&quot;;
-        }
-        print &quot;\n&quot;;
</del><ins>+        print install_string('modules_message_db');
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    return unless $output;
-
-    if (my @missing = @{$check_results-&gt;{optional}}) {
-        print &lt;&lt;EOT;
-**********************************************************************
-* OPTIONAL MODULES                                                   *
-**********************************************************************
-* Certain Perl modules are not required by Bugzilla, but by          *
-* installing the latest version you gain access to additional        *
-* features.                                                          *
-*                                                                    *
-* The optional modules you do not have installed are listed below,   *
-* with the name of the feature they enable. If you want to install   *
-* one of these modules, just run the appropriate command in the      *
-* &quot;COMMANDS TO INSTALL&quot; section.                                     *
-**********************************************************************
-
-EOT
</del><ins>+    if (my @missing = @{$check_results-&gt;{optional}} and $output) {
+        print install_string('modules_message_optional');
</ins><span class="cx">         # Now we have to determine how large the table cols will be.
</span><span class="cx">         my $longest_name = max(map(length($_-&gt;{package}), @missing));
</span><span class="cx"> 
</span><span class="cx">         # The first column header is at least 11 characters long.
</span><span class="cx">         $longest_name = 11 if $longest_name &lt; 11;
</span><span class="cx"> 
</span><del>-        # The table is 71 characters long. There are seven mandatory
</del><ins>+        # The table is TABLE_WIDTH characters long. There are seven mandatory
</ins><span class="cx">         # characters (* and space) in the string. So, we have a total
</span><del>-        # of 64 characters to work with.
-        my $remaining_space = 64 - $longest_name;
-        print '*' x 71 . &quot;\n&quot;;
</del><ins>+        # of TABLE_WIDTH - 7 characters to work with.
+        my $remaining_space = (TABLE_WIDTH - 7) - $longest_name;
+        print '*' x TABLE_WIDTH . &quot;\n&quot;;
</ins><span class="cx">         printf &quot;* \%${longest_name}s * %-${remaining_space}s *\n&quot;,
</span><span class="cx">                'MODULE NAME', 'ENABLES FEATURE(S)';
</span><del>-        print '*' x 71 . &quot;\n&quot;;
</del><ins>+        print '*' x TABLE_WIDTH . &quot;\n&quot;;
</ins><span class="cx">         foreach my $package (@missing) {
</span><span class="cx">             printf &quot;* \%${longest_name}s * %-${remaining_space}s *\n&quot;,
</span><del>-                   $package-&gt;{package}, $package-&gt;{feature};
</del><ins>+                   $package-&gt;{package}, 
+                   _translate_feature($package-&gt;{feature});
</ins><span class="cx">         }
</span><del>-        print '*' x 71 . &quot;\n&quot;;
</del><ins>+    }
</ins><span class="cx"> 
</span><del>-        print &quot;COMMANDS TO INSTALL:\n\n&quot;;
</del><ins>+    if (my @missing = @{ $check_results-&gt;{apache} }) {
+        print install_string('modules_message_apache');
+        my $missing_string = join(', ', @missing);
+        my $size = TABLE_WIDTH - 7;
+        printf &quot;*    \%-${size}s *\n&quot;, $missing_string;
+        my $spaces = TABLE_WIDTH - 2;
+        print &quot;*&quot;, (' ' x $spaces), &quot;*\n&quot;;
+    }
+
+    my $need_module_instructions =  
+        ( (!$output and @{$check_results-&gt;{missing}})
+          or ($output and $check_results-&gt;{any_missing}) ) ? 1 : 0;
+
+    # We only print the PPM repository note if we have to.
+    my $perl_ver = sprintf('%vd', $^V);
+    if ($need_module_instructions &amp;&amp; ON_ACTIVESTATE &amp;&amp; vers_cmp($perl_ver, '5.12') &lt; 0) {
+        # URL when running Perl 5.8.x.
+        my $url_to_theory58S = 'http://theoryx5.uwinnipeg.ca/ppms';
+        # Packages for Perl 5.10 are not compatible with Perl 5.8.
+        if (vers_cmp($perl_ver, '5.10') &gt; -1) {
+            $url_to_theory58S = 'http://cpan.uwinnipeg.ca/PPMPackages/10xx/';
+        }
+        print colored(
+            install_string('ppm_repo_add', 
+                           { theory_url =&gt; $url_to_theory58S }),
+            COLOR_ERROR);
+
+        # ActivePerls older than revision 819 require an additional command.
+        if (ON_ACTIVESTATE &lt; 819) {
+            print install_string('ppm_repo_up');
+        }
+    }
+
+    if ($need_module_instructions or @{ $check_results-&gt;{apache} }) {
+        # If any output was required, we want to close the &quot;table&quot;
+        print &quot;*&quot; x TABLE_WIDTH . &quot;\n&quot;;
+    }
+
+    # And now we print the actual installation commands.
+
+    if (my @missing = @{$check_results-&gt;{optional}} and $output) {
+        print install_string('commands_optional') . &quot;\n\n&quot;;
</ins><span class="cx">         foreach my $module (@missing) {
</span><span class="cx">             my $command = install_command($module);
</span><span class="cx">             printf &quot;%15s: $command\n&quot;, $module-&gt;{package};
</span><span class="cx">         }
</span><ins>+        print &quot;\n&quot;;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if ($output &amp;&amp; $check_results-&gt;{any_missing} &amp;&amp; !ON_WINDOWS) {
</del><ins>+    if (!$check_results-&gt;{one_dbd}) {
+        print install_string('commands_dbd') . &quot;\n&quot;;
+        my %db_modules = %{DB_MODULE()};
+        foreach my $db (keys %db_modules) {
+            my $command = install_command($db_modules{$db}-&gt;{dbd});
+            printf &quot;%10s: \%s\n&quot;, $db_modules{$db}-&gt;{name}, $command;
+        }
+        print &quot;\n&quot;;
+    }
+
+    if (my @missing = @{$check_results-&gt;{missing}}) {
+        print colored(install_string('commands_required'), COLOR_ERROR), &quot;\n&quot;;
+        foreach my $package (@missing) {
+            my $command = install_command($package);
+            print &quot;    $command\n&quot;;
+        }
+    }
+
+    if ($output &amp;&amp; $check_results-&gt;{any_missing} &amp;&amp; !ON_ACTIVESTATE
+        &amp;&amp; !$check_results-&gt;{hide_all}) 
+    {
</ins><span class="cx">         print install_string('install_all', { perl =&gt; $^X });
</span><span class="cx">     }
</span><ins>+    if (!$check_results-&gt;{pass}) {
+        print colored(install_string('installation_failed'), COLOR_ERROR),
+              &quot;\n\n&quot;;
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub _translate_feature {
+    my $features = shift;
+    my @strings;
+    foreach my $feature (@$features) {
+        push(@strings, install_string(&quot;feature_$feature&quot;));
+    }
+    return join(', ', @strings);
+}
+
</ins><span class="cx"> sub check_graphviz {
</span><span class="cx">     my ($output) = @_;
</span><span class="cx"> 
</span><del>-    return 1 if (Bugzilla-&gt;params-&gt;{'webdotbase'} =~ /^https?:/);
</del><ins>+    my $webdotbase = Bugzilla-&gt;params-&gt;{'webdotbase'};
+    return 1 if $webdotbase =~ /^https?:/;
</ins><span class="cx"> 
</span><del>-    printf(&quot;Checking for %15s %-9s &quot;, &quot;GraphViz&quot;, &quot;(any)&quot;) if $output;
</del><ins>+    my $return;
+    $return = 1 if -x $webdotbase;
</ins><span class="cx"> 
</span><del>-    my $return = 0;
-    if(-x Bugzilla-&gt;params-&gt;{'webdotbase'}) {
-        print &quot;ok: found\n&quot; if $output;
-        $return = 1;
-    } else {
-        print &quot;not a valid executable: &quot; . Bugzilla-&gt;params-&gt;{'webdotbase'} . &quot;\n&quot;;
</del><ins>+    if ($output) {
+        _checking_for({ package =&gt; 'GraphViz', ok =&gt; $return });
</ins><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    if (!$return) {
+        print install_string('bad_executable', { bin =&gt; $webdotbase }), &quot;\n&quot;;
+    }
+
</ins><span class="cx">     my $webdotdir = bz_locations()-&gt;{'webdotdir'};
</span><span class="cx">     # Check .htaccess allows access to generated images
</span><span class="cx">     if (-e &quot;$webdotdir/.htaccess&quot;) {
</span><span class="cx">         my $htaccess = new IO::File(&quot;$webdotdir/.htaccess&quot;, 'r') 
</span><span class="cx">             || die &quot;$webdotdir/.htaccess: &quot; . $!;
</span><span class="cx">         if (!grep(/png/, $htaccess-&gt;getlines)) {
</span><del>-            print &quot;Dependency graph images are not accessible.\n&quot;;
-            print &quot;delete $webdotdir/.htaccess and re-run checksetup.pl to fix.\n&quot;;
</del><ins>+            print STDERR install_string('webdot_bad_htaccess',
+                                        { dir =&gt; $webdotdir }), &quot;\n&quot;;
</ins><span class="cx">         }
</span><span class="cx">         $htaccess-&gt;close;
</span><span class="cx">     }
</span><span class="lines">@@ -519,9 +666,14 @@
</span><span class="cx">     my $wanted  = $params-&gt;{version};
</span><span class="cx"> 
</span><span class="cx">     eval &quot;require $module;&quot;;
</span><ins>+    # Don't let loading a module change the output-encoding of STDOUT
+    # or STDERR. (CGI.pm tries to set &quot;binmode&quot; on these file handles when
+    # it's loaded, and other modules may do the same in the future.)
+    Bugzilla::Install::Util::set_output_encoding();
</ins><span class="cx"> 
</span><del>-    # VERSION is provided by UNIVERSAL::
-    my $vnum = eval { $module-&gt;VERSION } || -1;
</del><ins>+    # VERSION is provided by UNIVERSAL::, and can be called even if
+    # the module isn't loaded.
+    my $vnum = $module-&gt;VERSION || -1;
</ins><span class="cx"> 
</span><span class="cx">     # CGI's versioning scheme went 2.75, 2.751, 2.752, 2.753, 2.76
</span><span class="cx">     # That breaks the standard version tests, so we need to manually correct
</span><span class="lines">@@ -529,17 +681,10 @@
</span><span class="cx">     if ($module eq 'CGI' &amp;&amp; $vnum =~ /(2\.7\d)(\d+)/) {
</span><span class="cx">         $vnum = $1 . &quot;.&quot; . $2;
</span><span class="cx">     }
</span><del>-
-    my $vstr;
-    if ($vnum eq &quot;-1&quot;) { # string compare just in case it's non-numeric
-        $vstr = install_string('module_not_found');
</del><ins>+    # CPAN did a similar thing, where it has versions like 1.9304.
+    if ($module eq 'CPAN' and $vnum =~ /^(\d\.\d{2})\d{2}$/) {
+        $vnum = $1;
</ins><span class="cx">     }
</span><del>-    elsif (vers_cmp($vnum,&quot;0&quot;) &gt; -1) {
-        $vstr = install_string('module_found', { ver =&gt; $vnum });
-    }
-    else {
-        $vstr = install_string('module_unknown_version');
-    }
</del><span class="cx"> 
</span><span class="cx">     my $vok = (vers_cmp($vnum,$wanted) &gt; -1);
</span><span class="cx">     my $blacklisted;
</span><span class="lines">@@ -549,23 +694,58 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if ($output) {
</span><del>-        my $ok           = $vok ? install_string('module_ok') : '';
-        my $black_string = $blacklisted ? install_string('blacklisted') : '';
-        my $want_string  = $wanted ? &quot;v$wanted&quot; : install_string('any');
-
-        $ok = &quot;$ok:&quot; if $ok;
-        printf &quot;%s %19s %-9s $ok $vstr $black_string\n&quot;,
-            install_string('checking_for'), $package, &quot;($want_string)&quot;;
</del><ins>+        _checking_for({ 
+            package =&gt; $package, ok =&gt; $vok, wanted =&gt; $wanted,
+            found   =&gt; $vnum, blacklisted =&gt; $blacklisted
+        });
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     return $vok ? 1 : 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub _checking_for {
+    my ($params) = @_;
+    my ($package, $ok, $wanted, $blacklisted, $found) = 
+        @$params{qw(package ok wanted blacklisted found)};
+
+    my $ok_string = $ok ? install_string('module_ok') : '';
+
+    # If we're actually checking versions (like for Perl modules), then
+    # we have some rather complex logic to determine what we want to 
+    # show. If we're not checking versions (like for GraphViz) we just
+    # show &quot;ok&quot; or &quot;not found&quot;.
+    if (exists $params-&gt;{found}) {
+        my $found_string;
+        # We do a string compare in case it's non-numeric. We make sure
+        # it's not a version object as negative versions are forbidden.
+        if ($found &amp;&amp; !ref($found) &amp;&amp; $found eq '-1') {
+            $found_string = install_string('module_not_found');
+        }
+        elsif ($found) {
+            $found_string = install_string('module_found', { ver =&gt; $found });
+        }
+        else {
+            $found_string = install_string('module_unknown_version');
+        }
+        $ok_string = $ok ? &quot;$ok_string: $found_string&quot; : $found_string;
+    }
+    elsif (!$ok) {
+        $ok_string = install_string('module_not_found');
+    }
+
+    my $black_string = $blacklisted ? install_string('blacklisted') : '';
+    my $want_string  = $wanted ? &quot;v$wanted&quot; : install_string('any');
+
+    my $str = sprintf &quot;%s %20s %-11s $ok_string $black_string\n&quot;,
+                install_string('checking_for'), $package, &quot;($want_string)&quot;;
+    print $ok ? $str : colored($str, COLOR_ERROR);
+}
+
</ins><span class="cx"> sub install_command {
</span><span class="cx">     my $module = shift;
</span><span class="cx">     my ($command, $package);
</span><span class="cx"> 
</span><del>-    if (ON_WINDOWS) {
</del><ins>+    if (ON_ACTIVESTATE) {
</ins><span class="cx">         $command = 'ppm install %s';
</span><span class="cx">         $package = $module-&gt;{package};
</span><span class="cx">     }
</span><span class="lines">@@ -578,6 +758,21 @@
</span><span class="cx">     return sprintf $command, $package;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# This does a reverse mapping for FEATURE_FILES.
+sub map_files_to_features {
+    my %features = FEATURE_FILES;
+    my %files;
+    foreach my $feature (keys %features) {
+        my @my_files = @{ $features{$feature} };
+        foreach my $pattern (@my_files) {
+            foreach my $file (glob $pattern) {
+                $files{$file} = $feature;
+            }
+        }
+    }
+    return \%files;
+}
+
</ins><span class="cx"> 1;
</span><span class="cx"> 
</span><span class="cx"> __END__
</span><span class="lines">@@ -595,16 +790,42 @@
</span><span class="cx"> 
</span><span class="cx"> =head1 CONSTANTS
</span><span class="cx"> 
</span><del>-=over 4
</del><ins>+=over
</ins><span class="cx"> 
</span><span class="cx"> =item C&lt;REQUIRED_MODULES&gt;
</span><span class="cx"> 
</span><span class="cx"> An arrayref of hashrefs that describes the perl modules required by 
</span><del>-Bugzilla. The hashes have two keys, C&lt;name&gt; and C&lt;version&gt;, which
-represent the name of the module and the version that we require.
</del><ins>+Bugzilla. The hashes have three keys: 
</ins><span class="cx"> 
</span><ins>+=over
+
+=item C&lt;package&gt; - The name of the Perl package that you'd find on
+CPAN for this requirement. 
+
+=item C&lt;module&gt; - The name of a module that can be passed to the
+C&lt;install&gt; command in C&lt;CPAN.pm&gt; to install this module.
+
+=item C&lt;version&gt; - The version of this module that we require, or C&lt;0&gt;
+if any version is acceptable.
+
</ins><span class="cx"> =back
</span><span class="cx"> 
</span><ins>+=item C&lt;OPTIONAL_MODULES&gt;
+
+An arrayref of hashrefs that describes the perl modules that add
+additional features to Bugzilla if installed. Its hashes have all
+the fields of L&lt;/REQUIRED_MODULES&gt;, plus a C&lt;feature&gt; item--an arrayref
+of strings that describe what features require this module.
+
+=item C&lt;FEATURE_FILES&gt;
+
+A hashref that describes what files should only be compiled if a certain
+feature is enabled. The feature is the key, and the values are arrayrefs
+of file names (which are passed to C&lt;glob&gt;, so shell patterns work).
+
+=back
+
+
</ins><span class="cx"> =head1 SUBROUTINES
</span><span class="cx"> 
</span><span class="cx"> =over 4
</span><span class="lines">@@ -641,10 +862,12 @@
</span><span class="cx"> 
</span><span class="cx"> =item C&lt;optional&gt; - The same as C&lt;missing&gt;, but for optional modules.
</span><span class="cx"> 
</span><ins>+=item C&lt;apache&gt; - The name of each optional Apache module that is missing.
+
</ins><span class="cx"> =item C&lt;have_one_dbd&gt; - True if at least one C&lt;DBD::&gt; module is installed.
</span><span class="cx"> 
</span><del>-=item C&lt;any_missing&gt; - True if there are any missing modules, even optional
-modules.
</del><ins>+=item C&lt;any_missing&gt; - True if there are any missing Perl modules, even
+optional modules.
</ins><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><span class="lines">@@ -687,4 +910,9 @@
</span><span class="cx"> 
</span><span class="cx">  Returns:     nothing
</span><span class="cx"> 
</span><ins>+=item C&lt;map_files_to_features&gt;
+
+Returns a hashref where file names are the keys and the value is the feature
+that must be enabled in order to compile that file.
+
</ins><span class="cx"> =back
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaInstallUtilpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Install/Util.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Install/Util.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Install/Util.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -28,35 +28,54 @@
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla::Constants;
</span><span class="cx"> 
</span><ins>+use Encode;
+use ExtUtils::MM ();
</ins><span class="cx"> use File::Basename;
</span><ins>+use File::Spec;
</ins><span class="cx"> use POSIX qw(setlocale LC_CTYPE);
</span><span class="cx"> use Safe;
</span><ins>+use Scalar::Util qw(tainted);
+use Term::ANSIColor qw(colored);
+use PerlIO;
</ins><span class="cx"> 
</span><span class="cx"> use base qw(Exporter);
</span><span class="cx"> our @EXPORT_OK = qw(
</span><span class="cx">     bin_loc
</span><span class="cx">     get_version_and_os
</span><ins>+    extension_code_files
+    extension_package_directory
+    extension_requirement_packages
+    extension_template_directory
+    extension_web_directory
</ins><span class="cx">     indicate_progress
</span><span class="cx">     install_string
</span><span class="cx">     include_languages
</span><ins>+    success
</ins><span class="cx">     template_include_path
</span><span class="cx">     vers_cmp
</span><del>-    get_console_locale
</del><ins>+    init_console
</ins><span class="cx"> );
</span><span class="cx"> 
</span><span class="cx"> sub bin_loc {
</span><del>-    my ($bin) = @_;
-    return '' if ON_WINDOWS;
-    # Don't print any errors from &quot;which&quot;
-    open(my $saveerr, &quot;&gt;&amp;STDERR&quot;);
-    open(STDERR, '&gt;/dev/null');
-    my $loc = `which $bin`;
-    close(STDERR);
-    open(STDERR, &quot;&gt;&amp;&quot;, $saveerr);
-    my $exit_code = $? &gt;&gt; 8; # See the perlvar manpage.
-    return '' if $exit_code &gt; 0;
-    chomp($loc);
-    return $loc;
</del><ins>+    my ($bin, $path) = @_;
+
+    # If the binary is a full path...
+    if ($bin =~ m{[/\\]}) {
+        return MM-&gt;maybe_command($bin) || '';
+    }
+
+    # Otherwise we look for it in the path in a cross-platform way.
+    my @path = $path ? @$path : File::Spec-&gt;path;
+    foreach my $dir (@path) {
+        next if !-d $dir;
+        my $full_path = File::Spec-&gt;catfile($dir, $bin);
+        # MM is an alias for ExtUtils::MM. maybe_command is nice
+        # because it checks .com, .bat, .exe (etc.) on Windows.
+        my $command = MM-&gt;maybe_command($full_path);
+        return $command if $command;
+    }
+
+    return '';
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub get_version_and_os {
</span><span class="lines">@@ -75,6 +94,175 @@
</span><span class="cx">              os_ver   =&gt; $os_details[3] };
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub _extension_paths {
+    my $dir = bz_locations()-&gt;{'extensionsdir'};
+    my @extension_items = glob(&quot;$dir/*&quot;);
+    my @paths;
+    foreach my $item (@extension_items) {
+        my $basename = basename($item);
+        # Skip CVS directories and any hidden files/dirs.
+        next if ($basename eq 'CVS' or $basename =~ /^\./);
+        if (-d $item) {
+            if (!-e &quot;$item/disabled&quot;) {
+                push(@paths, $item);
+            }
+        }
+        elsif ($item =~ /\.pm$/i) {
+            push(@paths, $item);
+        }
+    }
+    return @paths;
+}
+
+sub extension_code_files {
+    my ($requirements_only) = @_;
+    my @files;
+    foreach my $path (_extension_paths()) {
+        my @load_files;
+        if (-d $path) {
+            my $extension_file = &quot;$path/Extension.pm&quot;;
+            my $config_file    = &quot;$path/Config.pm&quot;;
+            if (-e $extension_file) {
+                push(@load_files, $extension_file);
+            }
+            if (-e $config_file) {
+                push(@load_files, $config_file);
+            }
+
+            # Don't load Extension.pm if we just want Config.pm and
+            # we found both.
+            if ($requirements_only and scalar(@load_files) == 2) {
+                shift(@load_files);
+            }
+        }
+        else {
+            push(@load_files, $path);
+        }
+        next if !scalar(@load_files);
+        # We know that these paths are safe, because they came from
+        # extensionsdir and we checked them specifically for their format.
+        # Also, the only thing we ever do with them is pass them to &quot;require&quot;.
+        trick_taint($_) foreach @load_files;
+        push(@files, \@load_files);
+    }
+
+    my @additional;
+    my $datadir = bz_locations()-&gt;{'datadir'};
+    my $addl_file = &quot;$datadir/extensions/additional&quot;;
+    if (-e $addl_file) {
+        open(my $fh, '&lt;', $addl_file) || die &quot;$addl_file: $!&quot;;
+        @additional = map { trim($_) } &lt;$fh&gt;;
+        close($fh);
+    }
+    return (\@files, \@additional);
+}
+
+# Used by _get_extension_requirements in Bugzilla::Install::Requirements.
+sub extension_requirement_packages {
+    # If we're in a .cgi script or some time that's not the requirements phase,
+    # just use Bugzilla-&gt;extensions. This avoids running the below code during
+    # a normal Bugzilla page, which is important because the below code
+    # doesn't actually function right if it runs after 
+    # Bugzilla::Extension-&gt;load_all (because stuff has already been loaded).
+    # (This matters because almost every page calls Bugzilla-&gt;feature, which
+    # calls OPTIONAL_MODULES, which calls this method.)
+    #
+    # We check if Bugzilla.pm is already loaded, instead of doing a &quot;require&quot;,
+    # because we *do* want the code lower down to run during the Requirements
+    # phase of checksetup.pl, instead of Bugzilla-&gt;extensions, and Bugzilla.pm
+    # actually *can* be loaded during the Requirements phase if all the
+    # requirements have already been installed.
+    if ($INC{'Bugzilla.pm'}) {
+        return Bugzilla-&gt;extensions;
+    }
+    my $packages = _cache()-&gt;{extension_requirement_packages};
+    return $packages if $packages;
+    $packages = [];
+    my %package_map;
+    
+    my ($file_sets, $extra_packages) = extension_code_files('requirements only');
+    foreach my $file_set (@$file_sets) {
+        my $file = shift @$file_set;
+        my $name = require $file;
+        if ($name =~ /^\d+$/) {
+            die install_string('extension_must_return_name',
+                               { file =&gt; $file, returned =&gt; $name });
+        }
+        my $package = &quot;Bugzilla::Extension::$name&quot;;
+        if ($package-&gt;can('package_dir')) {
+            $package-&gt;package_dir($file);
+        }
+        else {
+            extension_package_directory($package, $file);
+        }
+        $package_map{$file} = $package;
+        push(@$packages, $package);
+    }
+    foreach my $package (@$extra_packages) {
+        eval(&quot;require $package&quot;) || die $@;
+        push(@$packages, $package);
+    }
+
+    _cache()-&gt;{extension_requirement_packages} = $packages;
+    # Used by Bugzilla::Extension-&gt;load if it's called after this method
+    # (which only happens during checksetup.pl, currently).
+    _cache()-&gt;{extension_requirement_package_map} = \%package_map;
+    return $packages;
+}
+
+# Used in this file and in Bugzilla::Extension.
+sub extension_template_directory {
+    my $extension = shift;
+    my $class = ref($extension) || $extension;
+    my $base_dir = extension_package_directory($class);
+    if ($base_dir eq bz_locations-&gt;{'extensionsdir'}) {
+        return bz_locations-&gt;{'templatedir'};
+    }
+    return &quot;$base_dir/template&quot;;
+}
+
+# Used in this file and in Bugzilla::Extension.
+sub extension_web_directory {
+    my $extension = shift;
+    my $class = ref($extension) || $extension;
+    my $base_dir = extension_package_directory($class);
+    return &quot;$base_dir/web&quot;;
+}
+
+# For extensions that are in the extensions/ dir, this both sets and fetches
+# the name of the directory that stores an extension's &quot;stuff&quot;. We need this
+# when determining the template directory for extensions (or other things
+# that are relative to the extension's base directory).
+sub extension_package_directory {
+    my ($invocant, $file) = @_;
+    my $class = ref($invocant) || $invocant;
+
+    # $file is set on the first invocation, store the value in the extension's
+    # package for retrieval on subsequent calls
+    my $var;
+    {
+        no warnings 'once';
+        no strict 'refs';
+        $var = \${&quot;${class}::EXTENSION_PACKAGE_DIR&quot;};
+    }
+    if ($file) {
+        $$var = dirname($file);
+    }
+    my $value = $$var;
+
+    # This is for extensions loaded from data/extensions/additional.
+    if (!$value) {
+        my $short_path = $class;
+        $short_path =~ s/::/\//g;
+        $short_path .= &quot;.pm&quot;;
+        my $long_path = $INC{$short_path};
+        die &quot;$short_path is not in \%INC&quot; if !$long_path;
+        $value = $long_path;
+        $value =~ s/\.pm//;
+    }
+    return $value;
+}
+
</ins><span class="cx"> sub indicate_progress {
</span><span class="cx">     my ($params) = @_;
</span><span class="cx">     my $current = $params-&gt;{current};
</span><span class="lines">@@ -89,8 +277,8 @@
</span><span class="cx"> 
</span><span class="cx"> sub install_string {
</span><span class="cx">     my ($string_id, $vars) = @_;
</span><del>-    _cache()-&gt;{template_include_path} ||= template_include_path();
-    my $path = _cache()-&gt;{template_include_path};
</del><ins>+    _cache()-&gt;{install_string_path} ||= template_include_path();
+    my $path = _cache()-&gt;{install_string_path};
</ins><span class="cx">     
</span><span class="cx">     my $string_template;
</span><span class="cx">     # Find the first template that defines this string.
</span><span class="lines">@@ -104,12 +292,14 @@
</span><span class="cx">     die &quot;No language defines the string '$string_id'&quot;
</span><span class="cx">         if !defined $string_template;
</span><span class="cx"> 
</span><ins>+    utf8::decode($string_template) if !utf8::is_utf8($string_template);
+
</ins><span class="cx">     $vars ||= {};
</span><span class="cx">     my @replace_keys = keys %$vars;
</span><span class="cx">     foreach my $key (@replace_keys) {
</span><span class="cx">         my $replacement = $vars-&gt;{$key};
</span><span class="cx">         die &quot;'$key' in '$string_id' is tainted: '$replacement'&quot;
</span><del>-            if is_tainted($replacement);
</del><ins>+            if tainted($replacement);
</ins><span class="cx">         # We don't want people to start getting clever and inserting
</span><span class="cx">         # ##variable## into their values. So we check if any other
</span><span class="cx">         # key is listed in the *replacement* string, before doing
</span><span class="lines">@@ -120,82 +310,178 @@
</span><span class="cx">         }
</span><span class="cx">         $string_template =~ s/\Q##$key##\E/$replacement/g;
</span><span class="cx">     }
</span><del>-    
</del><ins>+
</ins><span class="cx">     return $string_template;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub include_languages {
-    my ($params) = @_;
-    $params ||= {};
</del><ins>+sub _wanted_languages {
+    my ($requested, @wanted);
</ins><span class="cx"> 
</span><del>-    # Basically, the way this works is that we have a list of languages
-    # that we *want*, and a list of languages that Bugzilla actually
-    # supports. The caller tells us what languages they want, by setting
-    # $ENV{HTTP_ACCEPT_LANGUAGE} or $params-&gt;{only_language}. The languages
-    # we support are those specified in $params-&gt;{use_languages}. Otherwise
-    # we support every language installed in the template/ directory.
-    
-    my @wanted;
-    if ($params-&gt;{only_language}) {
-        @wanted = ($params-&gt;{only_language});
</del><ins>+    # Checking SERVER_SOFTWARE is the same as i_am_cgi() in Bugzilla::Util.
+    if (exists $ENV{'SERVER_SOFTWARE'}) {
+        my $cgi = eval { Bugzilla-&gt;cgi } || eval { require CGI; return CGI-&gt;new() };
+        $requested = $cgi-&gt;http('Accept-Language') || '';
+        my $lang = $cgi-&gt;cookie('LANG');
+        push(@wanted, $lang) if $lang;
</ins><span class="cx">     }
</span><span class="cx">     else {
</span><del>-        @wanted = _sort_accept_language($ENV{'HTTP_ACCEPT_LANGUAGE'} || '');
</del><ins>+        $requested = get_console_locale();
</ins><span class="cx">     }
</span><del>-    
-    my @supported;
-    if (defined $params-&gt;{use_languages}) {
-        @supported = @{$params-&gt;{use_languages}};
-    }
-    else {
-        my @dirs = glob(bz_locations()-&gt;{'templatedir'} . &quot;/*&quot;);
-        @dirs = map(basename($_), @dirs);
-        @supported = grep($_ ne 'CVS', @dirs);
-    }
-    
-    my @usedlanguages;
-    foreach my $wanted (@wanted) {
</del><ins>+
+    push(@wanted, _sort_accept_language($requested));
+    return \@wanted;
+}
+
+sub _wanted_to_actual_languages {
+    my ($wanted, $supported) = @_;
+
+    my @actual;
+    foreach my $lang (@$wanted) {
</ins><span class="cx">         # If we support the language we want, or *any version* of
</span><del>-        # the language we want, it gets pushed into @usedlanguages.
</del><ins>+        # the language we want, it gets pushed into @actual.
</ins><span class="cx">         #
</span><span class="cx">         # Per RFC 1766 and RFC 2616, things like 'en' match 'en-us' and
</span><span class="cx">         # 'en-uk', but not the other way around. (This is unfortunately
</span><span class="cx">         # not very clearly stated in those RFC; see comment just over 14.5
</span><span class="cx">         # in http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4)
</span><del>-        if(my @found = grep /^\Q$wanted\E(-.+)?$/i, @supported) {
-            push (@usedlanguages, @found);
-        }
</del><ins>+        my @found = grep(/^\Q$lang\E(-.+)?$/i, @$supported);
+        push(@actual, @found) if @found;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # We always include English at the bottom if it's not there, even if
</span><del>-    # somebody removed it from use_languages.
-    if (!grep($_ eq 'en', @usedlanguages)) {
-        push(@usedlanguages, 'en');
</del><ins>+    # it wasn't selected by the user.
+    if (!grep($_ eq 'en', @actual)) {
+        push(@actual, 'en');
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    return @usedlanguages;
</del><ins>+    return \@actual;
</ins><span class="cx"> }
</span><ins>+
+sub supported_languages {
+    my $cache = _cache();
+    return $cache-&gt;{supported_languages} if $cache-&gt;{supported_languages};
+
+    my @dirs = glob(bz_locations()-&gt;{'templatedir'} . &quot;/*&quot;);
+    my @languages;
+    foreach my $dir (@dirs) {
+        # It's a language directory only if it contains &quot;default&quot; or
+        # &quot;custom&quot;. This auto-excludes CVS directories as well.
+        next if (!-d &quot;$dir/default&quot; and !-d &quot;$dir/custom&quot;);
+        my $lang = basename($dir);
+        # Check for language tag format conforming to RFC 1766.
+        next unless $lang =~ /^[a-zA-Z]{1,8}(-[a-zA-Z]{1,8})?$/;
+        push(@languages, $lang);
+    }
+
+    $cache-&gt;{supported_languages} = \@languages;
+    return \@languages;
+}
+
+sub include_languages {
+    my ($params) = @_;
+
+    # Basically, the way this works is that we have a list of languages
+    # that we *want*, and a list of languages that Bugzilla actually
+    # supports.
+    my $wanted;
+    if ($params-&gt;{language}) {
+        # We can pass several languages at once as an arrayref
+        # or a single language.
+        $wanted = $params-&gt;{language};
+        $wanted = [$wanted] unless ref $wanted;
+    }
+    else {
+        $wanted = _wanted_languages();
+    }
+    my $supported = supported_languages();
+    my $actual    = _wanted_to_actual_languages($wanted, $supported);
+    return @$actual;
+}
+
+# Used by template_include_path
+sub _template_lang_directories {
+    my ($languages, $templatedir) = @_;
</ins><span class="cx">     
</span><del>-sub template_include_path {
-    my @usedlanguages = include_languages(@_);
-    # Now, we add template directories in the order they will be searched:
-    
</del><ins>+    my @add = qw(custom default);
+    my $project = bz_locations-&gt;{'project'};
+    unshift(@add, $project) if $project;
+
+    my @result;
+    foreach my $lang (@$languages) {
+        foreach my $dir (@add) {
+            my $full_dir = &quot;$templatedir/$lang/$dir&quot;;
+            if (-d $full_dir) {
+                trick_taint($full_dir);
+                push(@result, $full_dir);
+            }
+        }
+    }
+    return @result;
+}
+
+# Used by template_include_path.
+sub _template_base_directories {
</ins><span class="cx">     # First, we add extension template directories, because extension templates
</span><span class="cx">     # override standard templates. Extensions may be localized in the same way
</span><span class="cx">     # that Bugzilla templates are localized.
</span><ins>+    #
+    # We use extension_requirement_packages instead of Bugzilla-&gt;extensions
+    # because this fucntion is called during the requirements phase of 
+    # installation (so Bugzilla-&gt;extensions isn't available).
+    my $extensions = extension_requirement_packages();
+    my @template_dirs;
+    foreach my $extension (@$extensions) {
+        my $dir;
+        # If there's a template_dir method available in the extension
+        # package, then call it. Note that this has to be defined in
+        # Config.pm for extensions that have a Config.pm, to be effective
+        # during the Requirements phase of checksetup.pl.
+        if ($extension-&gt;can('template_dir')) {
+            $dir = $extension-&gt;template_dir;
+        }
+        else {
+            $dir = extension_template_directory($extension);
+        }
+        if (-d $dir) {
+            push(@template_dirs, $dir);
+        }
+    }
+
+    # Extensions may also contain *only* templates, in which case they
+    # won't show up in extension_requirement_packages.
+    foreach my $path (_extension_paths()) {
+        next if !-d $path;
+        if (!-e &quot;$path/Extension.pm&quot; and !-e &quot;$path/Config.pm&quot;
+            and -d &quot;$path/template&quot;) 
+        {
+            push(@template_dirs, &quot;$path/template&quot;);
+        }
+    }
+
+
+    push(@template_dirs, bz_locations()-&gt;{'templatedir'});
+    return \@template_dirs;
+}
+
+sub template_include_path {
+    my ($params) = @_;
+    my @used_languages = include_languages($params);
+    # Now, we add template directories in the order they will be searched:
+    my $template_dirs = _template_base_directories(); 
+
</ins><span class="cx">     my @include_path;
</span><del>-    my @extensions = glob(bz_locations()-&gt;{'extensionsdir'} . &quot;/*&quot;);
-    foreach my $extension (@extensions) {
-        foreach my $lang (@usedlanguages) {
-            _add_language_set(\@include_path, $lang, &quot;$extension/template&quot;);
</del><ins>+    foreach my $template_dir (@$template_dirs) {
+        my @lang_dirs = _template_lang_directories(\@used_languages, 
+                                                   $template_dir);
+        # Hooks get each set of extension directories separately.
+        if ($params-&gt;{hook}) {
+            push(@include_path, \@lang_dirs);
</ins><span class="cx">         }
</span><ins>+        # Whereas everything else just gets a whole INCLUDE_PATH.
+        else {
+            push(@include_path, @lang_dirs);
+        }
</ins><span class="cx">     }
</span><del>-    
-    # Then, we add normal template directories, sorted by language.
-    foreach my $lang (@usedlanguages) {
-        _add_language_set(\@include_path, $lang);
-    }
-    
</del><span class="cx">     return \@include_path;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -242,6 +528,12 @@
</span><span class="cx">     @A &lt;=&gt; @B;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub no_checksetup_from_cgi {
+    print &quot;Content-Type: text/html; charset=UTF-8\r\n\r\n&quot;;
+    print install_string('no_checksetup_from_cgi');
+    exit;
+}
+
</ins><span class="cx"> ######################
</span><span class="cx"> # Helper Subroutines #
</span><span class="cx"> ######################
</span><span class="lines">@@ -257,24 +549,6 @@
</span><span class="cx">     return $strings{$string_id};
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-# Used by template_include_path.
-sub _add_language_set {
-    my ($array, $lang, $templatedir) = @_;
-    
-    $templatedir ||= bz_locations()-&gt;{'templatedir'};
-    my @add = (&quot;$templatedir/$lang/custom&quot;, &quot;$templatedir/$lang/default&quot;);
-    
-    my $project = bz_locations-&gt;{'project'};
-    unshift(@add, &quot;$templatedir/$lang/$project&quot;) if $project;
-    
-    foreach my $dir (@add) {
-        if (-d $dir) {
-            trick_taint($dir);
-            push(@$array, $dir);
-        }
-    }
-}
-
</del><span class="cx"> # Make an ordered list out of a HTTP Accept-Language header (see RFC 2616, 14.4)
</span><span class="cx"> # We ignore '*' and &lt;language-range&gt;;q=0
</span><span class="cx"> # For languages with the same priority q the order remains unchanged.
</span><span class="lines">@@ -330,14 +604,97 @@
</span><span class="cx">     return $locale;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub set_output_encoding {
+    # If we've already set an encoding layer on STDOUT, don't
+    # add another one.
+    my @stdout_layers = PerlIO::get_layers(STDOUT);
+    return if grep(/^encoding/, @stdout_layers);
</ins><span class="cx"> 
</span><ins>+    my $encoding;
+    if (ON_WINDOWS and eval { require Win32::Console }) {
+        # Although setlocale() works on Windows, it doesn't always return
+        # the current *console's* encoding. So we use OutputCP here instead,
+        # when we can.
+        $encoding = Win32::Console::OutputCP();
+    }
+    else {
+        my $locale = setlocale(LC_CTYPE);
+        if ($locale =~ /\.([^\.]+)$/) {
+            $encoding = $1;
+        }
+    }
+    $encoding = &quot;cp$encoding&quot; if ON_WINDOWS;
+
+    $encoding = Encode::resolve_alias($encoding) if $encoding;
+    if ($encoding and $encoding !~ /utf-8/i) {
+        binmode STDOUT, &quot;:encoding($encoding)&quot;;
+        binmode STDERR, &quot;:encoding($encoding)&quot;;
+    }
+    else {
+        binmode STDOUT, ':utf8';
+        binmode STDERR, ':utf8';
+    }
+}
+
+sub init_console {
+    eval { ON_WINDOWS &amp;&amp; require Win32::Console::ANSI; };
+    $ENV{'ANSI_COLORS_DISABLED'} = 1 if ($@ || !-t *STDOUT);
+    $SIG{__DIE__} = \&amp;_console_die;
+    prevent_windows_dialog_boxes();
+    set_output_encoding();
+}
+
+sub _console_die {
+    my ($message) = @_;
+    # $^S means &quot;we are in an eval&quot;
+    if ($^S) {
+        die $message;
+    }
+    # Remove newlines from the message before we color it, and then
+    # add them back in on display. Otherwise the ANSI escape code
+    # for resetting the color comes after the newline, and Perl thinks
+    # that it should put &quot;at Bugzilla/Install.pm line 1234&quot; after the
+    # message.
+    $message =~ s/\n+$//;
+    # We put quotes around the message to stringify any object exceptions,
+    # like Template::Exception.
+    die colored(&quot;$message&quot;, COLOR_ERROR) . &quot;\n&quot;;
+}
+
+sub success {
+    my ($message) = @_;
+    print colored($message, COLOR_SUCCESS), &quot;\n&quot;;
+}
+
+sub prevent_windows_dialog_boxes {
+    # This code comes from http://bugs.activestate.com/show_bug.cgi?id=82183
+    # and prevents Perl modules from popping up dialog boxes, particularly
+    # during checksetup (since loading DBD::Oracle during checksetup when
+    # Oracle isn't installed causes a scary popup and pauses checksetup).
+    #
+    # Win32::API ships with ActiveState by default, though there could 
+    # theoretically be a Windows installation without it, I suppose.
+    if (ON_WINDOWS and eval { require Win32::API }) {
+        # Call kernel32.SetErrorMode with arguments that mean:
+        # &quot;The system does not display the critical-error-handler message box.
+        # Instead, the system sends the error to the calling process.&quot; and
+        # &quot;A child process inherits the error mode of its parent process.&quot;
+        my $SetErrorMode = Win32::API-&gt;new('kernel32', 'SetErrorMode', 
+                                           'I', 'I');
+        my $SEM_FAILCRITICALERRORS = 0x0001;
+        my $SEM_NOGPFAULTERRORBOX  = 0x0002;
+        $SetErrorMode-&gt;Call($SEM_FAILCRITICALERRORS | $SEM_NOGPFAULTERRORBOX);
+    }
+}
+
</ins><span class="cx"> # This is like request_cache, but it's used only by installation code
</span><del>-# for setup.cgi and things like that.
</del><ins>+# for checksetup.pl and things like that.
</ins><span class="cx"> our $_cache = {};
</span><span class="cx"> sub _cache {
</span><del>-    if ($ENV{MOD_PERL}) {
-        require Apache2::RequestUtil;
-        return Apache2::RequestUtil-&gt;request-&gt;pnotes();
</del><ins>+    # If the normal request_cache is available (which happens any time
+    # after the requirements phase) then we should use that.
+    if (eval { Bugzilla-&gt;request_cache; }) {
+        return Bugzilla-&gt;request_cache;
</ins><span class="cx">     }
</span><span class="cx">     return $_cache;
</span><span class="cx"> }
</span><span class="lines">@@ -354,8 +711,13 @@
</span><span class="cx">     return (defined($_[0]));
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub is_tainted {
-    return not eval { my $foo = join('',@_), kill 0; 1; };
</del><ins>+sub trim {
+    my ($str) = @_;
+    if ($str) {
+      $str =~ s/^\s+//g;
+      $str =~ s/\s+$//g;
+    }
+    return $str;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> __END__
</span><span class="lines">@@ -397,6 +759,10 @@
</span><span class="cx"> Returns the language to use based on the LC_CTYPE value returned by the OS.
</span><span class="cx"> If LC_CTYPE is of the form fr-CH, then fr is appended to the list.
</span><span class="cx"> 
</span><ins>+=item C&lt;init_console&gt;
+
+Sets the C&lt;ANSI_COLORS_DISABLED&gt; and C&lt;HTTP_ACCEPT_LANGUAGE&gt; environment variables.
+
</ins><span class="cx"> =item C&lt;indicate_progress&gt;
</span><span class="cx"> 
</span><span class="cx"> =over
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaInstallpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Install.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Install.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Install.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -26,6 +26,8 @@
</span><span class="cx"> 
</span><span class="cx"> use strict;
</span><span class="cx"> 
</span><ins>+use Bugzilla::Component;
+use Bugzilla::Config qw(:admin);
</ins><span class="cx"> use Bugzilla::Constants;
</span><span class="cx"> use Bugzilla::Error;
</span><span class="cx"> use Bugzilla::Group;
</span><span class="lines">@@ -35,6 +37,24 @@
</span><span class="cx"> use Bugzilla::Util qw(get_text);
</span><span class="cx"> use Bugzilla::Version;
</span><span class="cx"> 
</span><ins>+use constant STATUS_WORKFLOW =&gt; (
+    [undef, 'UNCONFIRMED'],
+    [undef, 'CONFIRMED'],
+    [undef, 'IN_PROGRESS'],
+    ['UNCONFIRMED', 'CONFIRMED'],
+    ['UNCONFIRMED', 'IN_PROGRESS'],
+    ['UNCONFIRMED', 'RESOLVED'],
+    ['CONFIRMED',   'IN_PROGRESS'],
+    ['CONFIRMED',   'RESOLVED'],
+    ['IN_PROGRESS', 'CONFIRMED'],
+    ['IN_PROGRESS', 'RESOLVED'],
+    ['RESOLVED',    'UNCONFIRMED'],
+    ['RESOLVED',    'CONFIRMED'],
+    ['RESOLVED',    'VERIFIED'],
+    ['VERIFIED',    'UNCONFIRMED'],
+    ['VERIFIED',    'CONFIRMED'],
+);
+
</ins><span class="cx"> sub SETTINGS {
</span><span class="cx">     return {
</span><span class="cx">     # 2005-03-03 travis@sedsystems.ca -- Bug 41972
</span><span class="lines">@@ -62,7 +82,17 @@
</span><span class="cx">                             default =&gt; ${Bugzilla-&gt;languages}[0] },
</span><span class="cx">     # 2007-07-02 altlist@gmail.com -- Bug 225731
</span><span class="cx">     quote_replies      =&gt; { options =&gt; ['quoted_reply', 'simple_reply', 'off'],
</span><del>-                            default =&gt; &quot;quoted_reply&quot; }
</del><ins>+                            default =&gt; &quot;quoted_reply&quot; },
+    # 2009-02-01 mozilla@matt.mchenryfamily.org -- Bug 398473
+    comment_box_position =&gt; { options =&gt; ['before_comments', 'after_comments'],
+                              default =&gt; 'before_comments' },
+    # 2008-08-27 LpSolit@gmail.com -- Bug 182238
+    timezone           =&gt; { subclass =&gt; 'Timezone', default =&gt; 'local' },
+    # 2011-02-07 dkl@mozilla.com -- Bug 580490
+    quicksearch_fulltext =&gt; { options =&gt; ['on', 'off'], default =&gt; 'on' },
+    # 2011-06-21 glob@mozilla.com -- Bug 589128
+    email_format       =&gt; { options =&gt; ['html', 'text_only'],
+                            default =&gt; 'html' },
</ins><span class="cx">     }
</span><span class="cx"> };
</span><span class="cx"> 
</span><span class="lines">@@ -105,14 +135,29 @@
</span><span class="cx">         description =&gt; 'Can confirm a bug or mark it a duplicate'
</span><span class="cx">     },
</span><span class="cx">     {
</span><del>-        name        =&gt; 'bz_canusewhines',
-        description =&gt; 'User can configure whine reports for self'
</del><ins>+        name         =&gt; 'bz_canusewhineatothers',
+        description  =&gt; 'Can configure whine reports for other users',
</ins><span class="cx">     },
</span><span class="cx">     {
</span><ins>+        name         =&gt; 'bz_canusewhines',
+        description  =&gt; 'User can configure whine reports for self',
+        # inherited_by means that users in the groups listed below are
+        # automatically members of bz_canusewhines.
+        inherited_by =&gt; ['editbugs', 'bz_canusewhineatothers'],
+    },
+    {
</ins><span class="cx">         name        =&gt; 'bz_sudoers',
</span><del>-        description =&gt; 'Can perform actions as other users'
</del><ins>+        description =&gt; 'Can perform actions as other users',
</ins><span class="cx">     },
</span><del>-    # There are also other groups created in update_system_groups.
</del><ins>+    {
+        name         =&gt; 'bz_sudo_protect',
+        description  =&gt; 'Can not be impersonated by other users',
+        inherited_by =&gt; ['bz_sudoers'],
+    },
+    {
+        name         =&gt; 'bz_quip_moderators',
+        description  =&gt; 'Can moderate quips',
+    },
</ins><span class="cx"> );
</span><span class="cx"> 
</span><span class="cx"> use constant DEFAULT_CLASSIFICATION =&gt; {
</span><span class="lines">@@ -124,7 +169,10 @@
</span><span class="cx">     name =&gt; 'TestProduct',
</span><span class="cx">     description =&gt; 'This is a test product.'
</span><span class="cx">         . ' This ought to be blown away and replaced with real stuff in a'
</span><del>-        . ' finished installation of bugzilla.'
</del><ins>+        . ' finished installation of bugzilla.',
+    version =&gt; Bugzilla::Version::DEFAULT_VERSION,
+    classification =&gt; 'Unclassified',
+    defaultmilestone =&gt; DEFAULT_MILESTONE,
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> use constant DEFAULT_COMPONENT =&gt; {
</span><span class="lines">@@ -135,136 +183,117 @@
</span><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> sub update_settings {
</span><ins>+    my $dbh = Bugzilla-&gt;dbh;
+    # If we're setting up settings for the first time, we want to be quieter.
+    my $any_settings = $dbh-&gt;selectrow_array(
+        'SELECT 1 FROM setting ' . $dbh-&gt;sql_limit(1));
+    if (!$any_settings) {
+        print get_text('install_setting_setup'), &quot;\n&quot;;
+    }
+
</ins><span class="cx">     my %settings = %{SETTINGS()};
</span><span class="cx">     foreach my $setting (keys %settings) {
</span><span class="cx">         add_setting($setting,
</span><span class="cx">                     $settings{$setting}-&gt;{options}, 
</span><span class="cx">                     $settings{$setting}-&gt;{default},
</span><del>-                    $settings{$setting}-&gt;{subclass});
</del><ins>+                    $settings{$setting}-&gt;{subclass}, undef,
+                    !$any_settings);
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub update_system_groups {
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx"> 
</span><ins>+    $dbh-&gt;bz_start_transaction();
+
+    # If there is no editbugs group, this is the first time we're
+    # adding groups.
+    my $editbugs_exists = new Bugzilla::Group({ name =&gt; 'editbugs' });
+    if (!$editbugs_exists) {
+        print get_text('install_groups_setup'), &quot;\n&quot;;
+    }
+
</ins><span class="cx">     # Create most of the system groups
</span><span class="cx">     foreach my $definition (SYSTEM_GROUPS) {
</span><span class="cx">         my $exists = new Bugzilla::Group({ name =&gt; $definition-&gt;{name} });
</span><del>-        $definition-&gt;{isbuggroup} = 0;
-        Bugzilla::Group-&gt;create($definition) unless $exists;
</del><ins>+        if (!$exists) {
+            $definition-&gt;{isbuggroup} = 0;
+            $definition-&gt;{silently} = !$editbugs_exists;
+            my $inherited_by = delete $definition-&gt;{inherited_by};
+            my $created = Bugzilla::Group-&gt;create($definition);
+            # Each group in inherited_by is automatically a member of this
+            # group.
+            if ($inherited_by) {
+                foreach my $name (@$inherited_by) {
+                    my $member = Bugzilla::Group-&gt;check($name);
+                    $dbh-&gt;do('INSERT INTO group_group_map (grantor_id, 
+                                          member_id) VALUES (?,?)',
+                             undef, $created-&gt;id, $member-&gt;id);
+                }
+            }
+        }
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    # Certain groups need something done after they are created. We do
-    # that here.
</del><ins>+    $dbh-&gt;bz_commit_transaction();
+}
</ins><span class="cx"> 
</span><del>-    # Make sure people who can whine at others can also whine.
-    if (!new Bugzilla::Group({name =&gt; 'bz_canusewhineatothers'})) {
-        my $whineatothers = Bugzilla::Group-&gt;create({
-            name        =&gt; 'bz_canusewhineatothers',
-            description =&gt; 'Can configure whine reports for other users',
-            isbuggroup  =&gt; 0 });
-        my $whine = new Bugzilla::Group({ name =&gt; 'bz_canusewhines' });
</del><ins>+sub create_default_classification {
+    my $dbh = Bugzilla-&gt;dbh;
</ins><span class="cx"> 
</span><del>-        $dbh-&gt;do('INSERT INTO group_group_map (grantor_id, member_id) 
-                       VALUES (?,?)', undef, $whine-&gt;id, $whineatothers-&gt;id);
</del><ins>+    # Make the default Classification if it doesn't already exist.
+    if (!$dbh-&gt;selectrow_array('SELECT 1 FROM classifications')) {
+        print get_text('install_default_classification',
+                       { name =&gt; DEFAULT_CLASSIFICATION-&gt;{name} }) . &quot;\n&quot;;
+        Bugzilla::Classification-&gt;create(DEFAULT_CLASSIFICATION);
</ins><span class="cx">     }
</span><del>-
-    # Make sure sudoers are automatically protected from being sudoed.
-    if (!new Bugzilla::Group({name =&gt; 'bz_sudo_protect'})) {
-        my $sudo_protect = Bugzilla::Group-&gt;create({
-            name        =&gt; 'bz_sudo_protect',
-            description =&gt; 'Can not be impersonated by other users',
-            isbuggroup  =&gt; 0 });
-        my $sudo = new Bugzilla::Group({ name =&gt; 'bz_sudoers' });
-        $dbh-&gt;do('INSERT INTO group_group_map (grantor_id, member_id) 
-                       VALUES (?,?)', undef, $sudo_protect-&gt;id, $sudo-&gt;id);
-    }
-
-    # Re-evaluate all regexps, to keep them up-to-date.
-    my $sth = $dbh-&gt;prepare(
-        &quot;SELECT profiles.userid, profiles.login_name, groups.id, 
-                groups.userregexp, user_group_map.group_id
-           FROM (profiles CROSS JOIN groups)
-                LEFT JOIN user_group_map
-                ON user_group_map.user_id = profiles.userid
-                   AND user_group_map.group_id = groups.id
-                   AND user_group_map.grant_type = ?
-          WHERE userregexp != '' OR user_group_map.group_id IS NOT NULL&quot;);
-
-    my $sth_add = $dbh-&gt;prepare(
-        &quot;INSERT INTO user_group_map (user_id, group_id, isbless, grant_type)
-              VALUES (?, ?, 0, &quot; . GRANT_REGEXP . &quot;)&quot;);
-
-    my $sth_del = $dbh-&gt;prepare(
-        &quot;DELETE FROM user_group_map
-          WHERE user_id  = ? AND group_id = ? AND isbless = 0 
-                AND grant_type = &quot; . GRANT_REGEXP);
-
-    $sth-&gt;execute(GRANT_REGEXP);
-    while (my ($uid, $login, $gid, $rexp, $present) = $sth-&gt;fetchrow_array()) {
-        if ($login =~ m/$rexp/i) {
-            $sth_add-&gt;execute($uid, $gid) unless $present;
-        } else {
-            $sth_del-&gt;execute($uid, $gid) if $present;
-        }
-    }
-
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> # This function should be called only after creating the admin user.
</span><span class="cx"> sub create_default_product {
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx"> 
</span><del>-    # Make the default Classification if it doesn't already exist.
-    if (!$dbh-&gt;selectrow_array('SELECT 1 FROM classifications')) {
-        my $class = DEFAULT_CLASSIFICATION;
-        print get_text('install_default_classification', 
-                       { name =&gt; $class-&gt;{name} }) . &quot;\n&quot;;
-        $dbh-&gt;do('INSERT INTO classifications (name, description)
-                       VALUES (?, ?)',
-                 undef, $class-&gt;{name}, $class-&gt;{description});
-    }
-
</del><span class="cx">     # And same for the default product/component.
</span><span class="cx">     if (!$dbh-&gt;selectrow_array('SELECT 1 FROM products')) {
</span><del>-        my $default_prod = DEFAULT_PRODUCT;
</del><span class="cx">         print get_text('install_default_product', 
</span><del>-                       { name =&gt; $default_prod-&gt;{name} }) . &quot;\n&quot;;
</del><ins>+                       { name =&gt; DEFAULT_PRODUCT-&gt;{name} }) . &quot;\n&quot;;
</ins><span class="cx"> 
</span><del>-        $dbh-&gt;do(q{INSERT INTO products (name, description)
-                        VALUES (?,?)}, 
-                 undef, $default_prod-&gt;{name}, $default_prod-&gt;{description});
</del><ins>+        my $product = Bugzilla::Product-&gt;create(DEFAULT_PRODUCT);
</ins><span class="cx"> 
</span><del>-        my $product = new Bugzilla::Product({name =&gt; $default_prod-&gt;{name}});
-
-        # The default version.
-        Bugzilla::Version::create(Bugzilla::Version::DEFAULT_VERSION, $product);
-
-        # And we automatically insert the default milestone.
-        $dbh-&gt;do(q{INSERT INTO milestones (product_id, value, sortkey)
-                        SELECT id, defaultmilestone, 0
-                          FROM products});
-
-        # Get the user who will be the owner of the Product.
-        # We pick the admin with the lowest id, or we insert
-        # an invalid &quot;0&quot; into the database, just so that we can
-        # create the component.
</del><ins>+        # Get the user who will be the owner of the Component.
+        # We pick the admin with the lowest id, which is probably the
+        # admin checksetup.pl just created.
</ins><span class="cx">         my $admin_group = new Bugzilla::Group({name =&gt; 'admin'});
</span><span class="cx">         my ($admin_id)  = $dbh-&gt;selectrow_array(
</span><span class="cx">             'SELECT user_id FROM user_group_map WHERE group_id = ?
</span><span class="cx">            ORDER BY user_id ' . $dbh-&gt;sql_limit(1),
</span><del>-            undef, $admin_group-&gt;id) || 0;

-        my $default_comp = DEFAULT_COMPONENT;
</del><ins>+            undef, $admin_group-&gt;id);
+        my $admin = Bugzilla::User-&gt;new($admin_id);
</ins><span class="cx"> 
</span><del>-        $dbh-&gt;do(&quot;INSERT INTO components (name, product_id, description,
-                                          initialowner)
-                       VALUES (?, ?, ?, ?)&quot;, undef, $default_comp-&gt;{name},
-                 $product-&gt;id, $default_comp-&gt;{description}, $admin_id);
</del><ins>+        Bugzilla::Component-&gt;create({
+            %{ DEFAULT_COMPONENT() }, product =&gt; $product,
+            initialowner =&gt; $admin-&gt;login });
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub init_workflow {
+    my $dbh = Bugzilla-&gt;dbh;
+    my $has_workflow = $dbh-&gt;selectrow_array('SELECT 1 FROM status_workflow');
+    return if $has_workflow;
+
+    print get_text('install_workflow_init'), &quot;\n&quot;;
+
+    my %status_ids = @{ $dbh-&gt;selectcol_arrayref(
+        'SELECT value, id FROM bug_status', {Columns=&gt;[1,2]}) };
+
+    foreach my $pair (STATUS_WORKFLOW) {
+        my $old_id = $pair-&gt;[0] ? $status_ids{$pair-&gt;[0]} : undef;
+        my $new_id = $status_ids{$pair-&gt;[1]};
+        $dbh-&gt;do('INSERT INTO status_workflow (old_status, new_status)
+                       VALUES (?,?)', undef, $old_id, $new_id);
+    }
+}
+
</ins><span class="cx"> sub create_admin {
</span><span class="cx">     my ($params) = @_;
</span><span class="cx">     my $dbh      = Bugzilla-&gt;dbh;
</span><span class="lines">@@ -272,7 +301,7 @@
</span><span class="cx"> 
</span><span class="cx">     my $admin_group = new Bugzilla::Group({ name =&gt; 'admin' });
</span><span class="cx">     my $admin_inheritors = 
</span><del>-        Bugzilla::User-&gt;flatten_group_membership($admin_group-&gt;id);
</del><ins>+        Bugzilla::Group-&gt;flatten_group_membership($admin_group-&gt;id);
</ins><span class="cx">     my $admin_group_ids = join(',', @$admin_inheritors);
</span><span class="cx"> 
</span><span class="cx">     my ($admin_count) = $dbh-&gt;selectrow_array(
</span><span class="lines">@@ -325,14 +354,12 @@
</span><span class="cx">     $user = ref($user) ? $user 
</span><span class="cx">             : new Bugzilla::User(login_to_id($user, THROW_ERROR));
</span><span class="cx"> 
</span><del>-    my $admin_group = new Bugzilla::Group({ name =&gt; 'admin' });
-
-    # Admins get explicit membership and bless capability for the admin group
-    $dbh-&gt;selectrow_array(&quot;SELECT id FROM groups WHERE name = 'admin'&quot;);
-
</del><span class="cx">     my $group_insert = $dbh-&gt;prepare(
</span><span class="cx">         'INSERT INTO user_group_map (user_id, group_id, isbless, grant_type)
</span><span class="cx">               VALUES (?, ?, ?, ?)');
</span><ins>+
+    # Admins get explicit membership and bless capability for the admin group
+    my $admin_group = new Bugzilla::Group({ name =&gt; 'admin' });
</ins><span class="cx">     # These are run in an eval so that we can ignore the error of somebody
</span><span class="cx">     # already being granted these things.
</span><span class="cx">     eval { 
</span><span class="lines">@@ -349,7 +376,15 @@
</span><span class="cx">         $group_insert-&gt;execute($user-&gt;id, $editusers-&gt;id, 0, GRANT_DIRECT); 
</span><span class="cx">     };
</span><span class="cx"> 
</span><del>-    print &quot;\n&quot;, get_text('install_admin_created', { user =&gt; $user }), &quot;\n&quot;;
</del><ins>+    # If there is no maintainer set, make this user the maintainer.
+    if (!Bugzilla-&gt;params-&gt;{'maintainer'}) {
+        SetParam('maintainer', $user-&gt;email);
+        write_params();
+    }
+
+    if (Bugzilla-&gt;usage_mode == USAGE_MODE_CMDLINE) {
+        print &quot;\n&quot;, get_text('install_admin_created', { user =&gt; $user }), &quot;\n&quot;;
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _prompt_for_password {
</span><span class="lines">@@ -440,9 +475,14 @@
</span><span class="cx"> 
</span><span class="cx"> Returns:     nothing.
</span><span class="cx"> 
</span><ins>+=item C&lt;create_default_classification&gt;
+
+Creates the default &quot;Unclassified&quot; L&lt;Classification|Bugzilla::Classification&gt;
+if it doesn't already exist
+
</ins><span class="cx"> =item C&lt;create_default_product()&gt;
</span><span class="cx"> 
</span><del>-Description: Creates the default product and classification if
</del><ins>+Description: Creates the default product and component if
</ins><span class="cx">              they don't exist.
</span><span class="cx"> 
</span><span class="cx"> Params:      none
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaJobMailerpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/Job/Mailer.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Job/Mailer.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Job/Mailer.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,57 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Mozilla Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2008
+# Mozilla Corporation. All Rights Reserved.
+#
+# Contributor(s): 
+#   Mark Smith &lt;mark@mozilla.com&gt;
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+package Bugzilla::Job::Mailer;
+use strict;
+use Bugzilla::Mailer;
+BEGIN { eval &quot;use base qw(TheSchwartz::Worker)&quot;; }
+
+# The longest we expect a job to possibly take, in seconds.
+use constant grab_for =&gt; 300;
+# We don't want email to fail permanently very easily. Retry for 30 days.
+use constant max_retries =&gt; 725;
+
+# The first few retries happen quickly, but after that we wait an hour for
+# each retry.
+sub retry_delay {
+    my ($class, $num_retries) = @_;
+    if ($num_retries &lt; 5) {
+        return (10, 30, 60, 300, 600)[$num_retries];
+    }
+    # One hour
+    return 60*60;
+}
+
+sub work {
+    my ($class, $job) = @_;
+    my $msg = $job-&gt;arg-&gt;{msg};
+    my $success = eval { MessageToMTA($msg, 1); 1; };
+    if (!$success) {
+        $job-&gt;failed($@);
+        undef $@;
+    } 
+    else {
+        $job-&gt;completed;
+    }
+}
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaJobQueueRunnerpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/JobQueue/Runner.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/JobQueue/Runner.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/JobQueue/Runner.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,246 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Mozilla Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2008
+# Mozilla Corporation. All Rights Reserved.
+#
+# Contributor(s): 
+#   Mark Smith &lt;mark@mozilla.com&gt;
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+# XXX In order to support Windows, we have to make gd_redirect_output
+# use Log4Perl or something instead of calling &quot;logger&quot;. We probably
+# also need to use Win32::Daemon or something like that to daemonize.
+
+package Bugzilla::JobQueue::Runner;
+
+use strict;
+use Cwd qw(abs_path);
+use File::Basename;
+use File::Copy;
+use Pod::Usage;
+
+use Bugzilla::Constants;
+use Bugzilla::JobQueue;
+use Bugzilla::Util qw(get_text);
+BEGIN { eval &quot;use base qw(Daemon::Generic)&quot;; }
+
+our $VERSION = BUGZILLA_VERSION;
+
+# Info we need to install/uninstall the daemon.
+our $chkconfig = &quot;/sbin/chkconfig&quot;;
+our $initd = &quot;/etc/init.d&quot;;
+our $initscript = &quot;bugzilla-queue&quot;;
+
+# The Daemon::Generic docs say that it uses all sorts of
+# things from gd_preconfig, but in fact it does not. The
+# only thing it uses from gd_preconfig is the &quot;pidfile&quot;
+# config parameter.
+sub gd_preconfig {
+    my $self = shift;
+
+    my $pidfile = $self-&gt;{gd_args}{pidfile};
+    if (!$pidfile) {
+        $pidfile = bz_locations()-&gt;{datadir} . '/' . $self-&gt;{gd_progname} 
+                   . &quot;.pid&quot;;
+    }
+    return (pidfile =&gt; $pidfile);
+}
+
+# All config other than the pidfile has to be done in gd_getopt
+# in order for it to be set up early enough.
+sub gd_getopt {
+    my $self = shift;
+
+    $self-&gt;SUPER::gd_getopt();
+
+    if ($self-&gt;{gd_args}{progname}) {
+        $self-&gt;{gd_progname} = $self-&gt;{gd_args}{progname};
+    }
+    else {
+        $self-&gt;{gd_progname} = basename($0);
+    }
+
+    # There are places that Daemon Generic's new() uses $0 instead of
+    # gd_progname, which it really shouldn't, but this hack fixes it.
+    $self-&gt;{_original_zero} = $0;
+    $0 = $self-&gt;{gd_progname};
+}
+
+sub gd_postconfig {
+    my $self = shift;
+    # See the hack above in gd_getopt. This just reverses it
+    # in case anything else needs the accurate $0.
+    $0 = delete $self-&gt;{_original_zero};
+}
+
+sub gd_more_opt {
+    my $self = shift;
+    return (
+        'pidfile=s' =&gt; \$self-&gt;{gd_args}{pidfile},
+        'n=s'       =&gt; \$self-&gt;{gd_args}{progname},
+    );
+}
+
+sub gd_usage {
+    pod2usage({ -verbose =&gt; 0, -exitval =&gt; 'NOEXIT' });
+    return 0
+}
+
+sub gd_can_install {
+    my $self = shift;
+
+    my $source_file;
+    if ( -e &quot;/etc/SuSE-release&quot; ) {
+        $source_file = &quot;contrib/$initscript.suse&quot;;
+    } else {
+        $source_file = &quot;contrib/$initscript.rhel&quot;;
+    }
+    my $dest_file = &quot;$initd/$initscript&quot;;
+    my $sysconfig = '/etc/sysconfig';
+    my $config_file = &quot;$sysconfig/$initscript&quot;;
+
+    if (!-x $chkconfig  or !-d $initd) {
+        return $self-&gt;SUPER::gd_can_install(@_);
+    }
+
+    return sub {
+        if (!-w $initd) {
+            print &quot;You must run the 'install' command as root.\n&quot;;
+            return;
+        }
+        if (-e $dest_file) {
+            print &quot;$initscript already in $initd.\n&quot;;
+        }
+        else {
+            copy($source_file, $dest_file)
+                or die &quot;Could not copy $source_file to $dest_file: $!&quot;;
+            chmod(0755, $dest_file)
+                or die &quot;Could not change permissions on $dest_file: $!&quot;;
+        }
+
+        system($chkconfig, '--add', $initscript);
+        print &quot;$initscript installed.&quot;,
+              &quot; To start the daemon, do \&quot;$dest_file start\&quot; as root.\n&quot;;
+
+        if (-d $sysconfig and -w $sysconfig) {
+            if (-e $config_file) {
+                print &quot;$config_file already exists.\n&quot;;
+                return;
+            }
+
+            open(my $config_fh, &quot;&gt;&quot;, $config_file)
+                or die &quot;Could not write to $config_file: $!&quot;;
+            my $directory = abs_path(dirname($self-&gt;{_original_zero}));
+            my $owner_id = (stat $self-&gt;{_original_zero})[4];
+            my $owner = getpwuid($owner_id);
+            print $config_fh &lt;&lt;END;
+#!/bin/sh
+BUGZILLA=&quot;$directory&quot;
+USER=$owner
+END
+            close($config_fh);
+        }
+        else {
+            print &quot;Please edit $dest_file to configure the daemon.\n&quot;;
+        }
+    }
+}
+
+sub gd_can_uninstall {
+    my $self = shift;
+
+    if (-x $chkconfig and -d $initd) {
+        return sub {
+            if (!-e &quot;$initd/$initscript&quot;) {
+                print &quot;$initscript not installed.\n&quot;;
+                return;
+            }
+            system($chkconfig, '--del', $initscript);
+            print &quot;$initscript disabled.&quot;,
+                  &quot; To stop it, run: $initd/$initscript stop\n&quot;;
+        }
+    }
+
+    return $self-&gt;SUPER::gd_can_install(@_);
+}
+
+sub gd_check {
+    my $self = shift;
+
+    # Get a count of all the jobs currently in the queue.
+    my $jq = Bugzilla-&gt;job_queue();
+    my @dbs = $jq-&gt;bz_databases();
+    my $count = 0;
+    foreach my $driver (@dbs) {
+        $count += $driver-&gt;select_one('SELECT COUNT(*) FROM ts_job', []);
+    }
+    print get_text('job_queue_depth', { count =&gt; $count }) . &quot;\n&quot;;
+}
+
+sub gd_setup_signals {
+    my $self = shift;
+    $self-&gt;SUPER::gd_setup_signals();
+    $SIG{TERM} = sub { $self-&gt;gd_quit_event(); }
+}
+
+sub gd_other_cmd {
+    my ($self) = shift;
+    if ($ARGV[0] eq &quot;once&quot;) {
+        $self-&gt;_do_work(&quot;work_once&quot;);
+
+        exit(0);
+    }
+    
+    $self-&gt;SUPER::gd_other_cmd();
+}
+
+sub gd_run {
+    my $self = shift;
+
+    $self-&gt;_do_work(&quot;work&quot;);
+}
+
+sub _do_work {
+    my ($self, $fn) = @_;
+
+    my $jq = Bugzilla-&gt;job_queue();
+    $jq-&gt;set_verbose($self-&gt;{debug});
+    foreach my $module (values %{ Bugzilla::JobQueue-&gt;job_map() }) {
+        eval &quot;use $module&quot;;
+        $jq-&gt;can_do($module);
+    }
+
+    $jq-&gt;$fn;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::JobQueue::Runner - A class representing the daemon that runs the
+job queue.
+
+=head1 SYNOPSIS
+
+ use Bugzilla::JobQueue::Runner;
+ Bugzilla::JobQueue::Runner-&gt;new();
+
+=head1 DESCRIPTION
+
+This is a subclass of L&lt;Daemon::Generic&gt; that is used by L&lt;jobqueue&gt;
+to run the Bugzilla job queue.
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaJobQueuepm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/JobQueue.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/JobQueue.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/JobQueue.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,126 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Mozilla Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2008
+# Mozilla Corporation. All Rights Reserved.
+#
+# Contributor(s): 
+#   Mark Smith &lt;mark@mozilla.com&gt;
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+package Bugzilla::JobQueue;
+
+use strict;
+
+use Bugzilla::Constants;
+use Bugzilla::Error;
+use Bugzilla::Install::Util qw(install_string);
+use base qw(TheSchwartz);
+
+# This maps job names for Bugzilla::JobQueue to the appropriate modules.
+# If you add new types of jobs, you should add a mapping here.
+use constant JOB_MAP =&gt; {
+    send_mail =&gt; 'Bugzilla::Job::Mailer',
+};
+
+# Without a driver cache TheSchwartz opens a new database connection
+# for each email it sends.  This cached connection doesn't persist
+# across requests.
+use constant DRIVER_CACHE_TIME =&gt; 300; # 5 minutes
+
+sub job_map {
+    if (!defined(Bugzilla-&gt;request_cache-&gt;{job_map})) {
+        my $job_map = JOB_MAP;
+        Bugzilla::Hook::process('job_map', { job_map =&gt; $job_map });
+        Bugzilla-&gt;request_cache-&gt;{job_map} = $job_map;
+    }
+    
+    return Bugzilla-&gt;request_cache-&gt;{job_map};
+}
+
+sub new {
+    my $class = shift;
+
+    if (!Bugzilla-&gt;feature('jobqueue')) {
+        ThrowCodeError('feature_disabled', { feature =&gt; 'jobqueue' });
+    }
+
+    my $lc = Bugzilla-&gt;localconfig;
+    # We need to use the main DB as TheSchwartz module is going
+    # to write to it.
+    my $self = $class-&gt;SUPER::new(
+        databases =&gt; [{
+            dsn    =&gt; Bugzilla-&gt;dbh_main-&gt;{private_bz_dsn},
+            user   =&gt; $lc-&gt;{db_user},
+            pass   =&gt; $lc-&gt;{db_pass},
+            prefix =&gt; 'ts_',
+        }],
+        driver_cache_expiration =&gt; DRIVER_CACHE_TIME,
+    );
+
+    return $self;
+}
+
+# A way to get access to the underlying databases directly.
+sub bz_databases {
+    my $self = shift;
+    my @hashes = keys %{ $self-&gt;{databases} };
+    return map { $self-&gt;driver_for($_) } @hashes;
+}
+
+# inserts a job into the queue to be processed and returns immediately
+sub insert {
+    my $self = shift;
+    my $job = shift;
+
+    my $mapped_job = Bugzilla::JobQueue-&gt;job_map()-&gt;{$job};
+    ThrowCodeError('jobqueue_no_job_mapping', { job =&gt; $job })
+        if !$mapped_job;
+    unshift(@_, $mapped_job);
+
+    my $retval = $self-&gt;SUPER::insert(@_);
+    # XXX Need to get an error message here if insert fails, but
+    # I don't see any way to do that in TheSchwartz.
+    ThrowCodeError('jobqueue_insert_failed', { job =&gt; $job, errmsg =&gt; $@ })
+        if !$retval;

+    return $retval;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::JobQueue - Interface between Bugzilla and TheSchwartz.
+
+=head1 SYNOPSIS
+
+ use Bugzilla;
+
+ my $obj = Bugzilla-&gt;job_queue();
+ $obj-&gt;insert('send_mail', { msg =&gt; $message });
+
+=head1 DESCRIPTION
+
+Certain tasks should be done asyncronously.  The job queue system allows
+Bugzilla to use some sort of service to schedule jobs to happen asyncronously.
+
+=head2 Inserting a Job
+
+See the synopsis above for an easy to follow example on how to insert a
+job into the queue.  Give it a name and some arguments and the job will
+be sent away to be done later.
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaKeywordpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Keyword.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Keyword.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Keyword.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -35,8 +35,6 @@
</span><span class="cx"> 
</span><span class="cx"> use constant DB_TABLE =&gt; 'keyworddefs';
</span><span class="cx"> 
</span><del>-use constant REQUIRED_CREATE_FIELDS =&gt; qw(name description);
-
</del><span class="cx"> use constant VALIDATORS =&gt; {
</span><span class="cx">     name        =&gt; \&amp;_check_name,
</span><span class="cx">     description =&gt; \&amp;_check_description,
</span><span class="lines">@@ -74,17 +72,12 @@
</span><span class="cx"> ####      Subroutines    ######
</span><span class="cx"> ###############################
</span><span class="cx"> 
</span><del>-sub keyword_count {
-    my ($count) = 
-        Bugzilla-&gt;dbh-&gt;selectrow_array('SELECT COUNT(*) FROM keyworddefs');
-    return $count;
-}
-
</del><span class="cx"> sub get_all_with_bug_count {
</span><span class="cx">     my $class = shift;
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx">     my $keywords =
</span><del>-      $dbh-&gt;selectall_arrayref('SELECT ' . join(', ', DB_COLUMNS) . ',
</del><ins>+      $dbh-&gt;selectall_arrayref('SELECT ' 
+                                      . join(', ', $class-&gt;_get_db_columns) . ',
</ins><span class="cx">                                        COUNT(keywords.bug_id) AS bug_count
</span><span class="cx">                                   FROM keyworddefs
</span><span class="cx">                              LEFT JOIN keywords
</span><span class="lines">@@ -111,7 +104,9 @@
</span><span class="cx">     my ($self, $name) = @_;
</span><span class="cx"> 
</span><span class="cx">     $name = trim($name);
</span><del>-    $name eq &quot;&quot; &amp;&amp; ThrowUserError(&quot;keyword_blank_name&quot;);
</del><ins>+    if (!defined $name or $name eq &quot;&quot;) {
+        ThrowUserError(&quot;keyword_blank_name&quot;);
+    }
</ins><span class="cx">     if ($name =~ /[\s,]/) {
</span><span class="cx">         ThrowUserError(&quot;keyword_invalid_name&quot;);
</span><span class="cx">     }
</span><span class="lines">@@ -129,7 +124,9 @@
</span><span class="cx"> sub _check_description {
</span><span class="cx">     my ($self, $desc) = @_;
</span><span class="cx">     $desc = trim($desc);
</span><del>-    $desc eq '' &amp;&amp; ThrowUserError(&quot;keyword_blank_description&quot;);
</del><ins>+    if (!defined $desc or $desc eq '') {
+        ThrowUserError(&quot;keyword_blank_description&quot;);
+    }
</ins><span class="cx">     return $desc;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -145,8 +142,6 @@
</span><span class="cx"> 
</span><span class="cx">  use Bugzilla::Keyword;
</span><span class="cx"> 
</span><del>- my $count = Bugzilla::Keyword::keyword_count;
-
</del><span class="cx">  my $description = $keyword-&gt;description;
</span><span class="cx"> 
</span><span class="cx">  my $keywords = Bugzilla::Keyword-&gt;get_all_with_bug_count();
</span><span class="lines">@@ -166,14 +161,6 @@
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><del>-=item C&lt;keyword_count()&gt; 
-
- Description: A utility function to get the total number
-              of keywords defined. Mostly used to see
-              if there are any keywords defined at all.
- Params:      none
- Returns:     An integer, the count of keywords.
-
</del><span class="cx"> =item C&lt;get_all_with_bug_count()&gt; 
</span><span class="cx"> 
</span><span class="cx">  Description: Returns all defined keywords. This is an efficient way
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaMailerpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Mailer.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Mailer.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Mailer.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -39,6 +39,7 @@
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla::Constants;
</span><span class="cx"> use Bugzilla::Error;
</span><ins>+use Bugzilla::Hook;
</ins><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> 
</span><span class="cx"> use Date::Format qw(time2str);
</span><span class="lines">@@ -47,15 +48,18 @@
</span><span class="cx"> use Encode::MIME::Header;
</span><span class="cx"> use Email::Address;
</span><span class="cx"> use Email::MIME;
</span><del>-# Loading this gives us encoding_set.
-use Email::MIME::Modifier;
</del><span class="cx"> use Email::Send;
</span><span class="cx"> 
</span><span class="cx"> sub MessageToMTA {
</span><del>-    my ($msg) = (@_);
</del><ins>+    my ($msg, $send_now) = (@_);
</ins><span class="cx">     my $method = Bugzilla-&gt;params-&gt;{'mail_delivery_method'};
</span><span class="cx">     return if $method eq 'None';
</span><span class="cx"> 
</span><ins>+    if (Bugzilla-&gt;params-&gt;{'use_mailer_queue'} and !$send_now) {
+        Bugzilla-&gt;job_queue-&gt;insert('send_mail', { msg =&gt; $msg });
+        return;
+    }
+
</ins><span class="cx">     my $email;
</span><span class="cx">     if (ref $msg) {
</span><span class="cx">         $email = $msg;
</span><span class="lines">@@ -71,6 +75,14 @@
</span><span class="cx">         $email = new Email::MIME($msg);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    # We add this header to uniquely identify all email that we
+    # send as coming from this Bugzilla installation.
+    #
+    # We don't use correct_urlbase, because we want this URL to
+    # *always* be the same for this Bugzilla, in every email,
+    # even if the admin changes the &quot;ssl_redirect&quot; parameter some day.
+    $email-&gt;header_set('X-Bugzilla-URL', Bugzilla-&gt;params-&gt;{'urlbase'});
+    
</ins><span class="cx">     # We add this header to mark the mail as &quot;auto-generated&quot; and
</span><span class="cx">     # thus to hopefully avoid auto replies.
</span><span class="cx">     $email-&gt;header_set('Auto-Submitted', 'auto-generated');
</span><span class="lines">@@ -79,7 +91,11 @@
</span><span class="cx">         my ($part) = @_;
</span><span class="cx">         return if $part-&gt;parts &gt; 1; # Top-level
</span><span class="cx">         my $content_type = $part-&gt;content_type || '';
</span><del>-        if ($content_type !~ /;/) {
</del><ins>+        $content_type =~ /charset=['&quot;](.+)['&quot;]/;
+        # If no charset is defined or is the default us-ascii,
+        # then we encode the email to UTF-8 if Bugzilla has utf8 enabled.
+        # XXX - This is a hack to workaround bug 723944.
+        if (!$1 || $1 eq 'us-ascii') {
</ins><span class="cx">             my $body = $part-&gt;body;
</span><span class="cx">             if (Bugzilla-&gt;params-&gt;{'utf8'}) {
</span><span class="cx">                 $part-&gt;charset_set('UTF-8');
</span><span class="lines">@@ -131,8 +147,6 @@
</span><span class="cx">                 push(@args, &quot;-f$from_email&quot;) if $from_email;
</span><span class="cx">             }
</span><span class="cx">         }
</span><del>-        push(@args, &quot;-ODeliveryMode=deferred&quot;)
-            if !Bugzilla-&gt;params-&gt;{&quot;sendmailnow&quot;};
</del><span class="cx">     }
</span><span class="cx">     else {
</span><span class="cx">         # Sendmail will automatically append our hostname to the From
</span><span class="lines">@@ -145,7 +159,7 @@
</span><span class="cx">         
</span><span class="cx">         # Sendmail adds a Date: header also, but others may not.
</span><span class="cx">         if (!defined $email-&gt;header('Date')) {
</span><del>-            $email-&gt;header_set('Date', time2str(&quot;%a, %e %b %Y %T %z&quot;, time()));
</del><ins>+            $email-&gt;header_set('Date', time2str(&quot;%a, %d %b %Y %T %z&quot;, time()));
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -157,6 +171,9 @@
</span><span class="cx">                     Debug =&gt; Bugzilla-&gt;params-&gt;{'smtp_debug'};
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    Bugzilla::Hook::process('mailer_before_send', 
+                            { email =&gt; $email, mailer_args =&gt; \@args });
+
</ins><span class="cx">     if ($method eq &quot;Test&quot;) {
</span><span class="cx">         my $filename = bz_locations()-&gt;{'datadir'} . '/mailer.testfile';
</span><span class="cx">         open TESTFILE, '&gt;&gt;', $filename;
</span><span class="lines">@@ -195,7 +212,9 @@
</span><span class="cx">         $threadingmarker = &quot;Message-ID: &lt;bug-$bug_id-$user_id$sitespec&gt;&quot;;
</span><span class="cx">     }
</span><span class="cx">     else {
</span><del>-        $threadingmarker = &quot;In-Reply-To: &lt;bug-$bug_id-$user_id$sitespec&gt;&quot; .
</del><ins>+        my $rand_bits = generate_random_password(10);
+        $threadingmarker = &quot;Message-ID: &lt;bug-$bug_id-$user_id-$rand_bits$sitespec&gt;&quot; .
+                           &quot;\nIn-Reply-To: &lt;bug-$bug_id-$user_id$sitespec&gt;&quot; .
</ins><span class="cx">                            &quot;\nReferences: &lt;bug-$bug_id-$user_id$sitespec&gt;&quot;;
</span><span class="cx">     }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaMigrateGnatspm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/Migrate/Gnats.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Migrate/Gnats.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Migrate/Gnats.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,712 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is The Bugzilla Migration Tool.
+#
+# The Initial Developer of the Original Code is Lambda Research
+# Corporation. Portions created by the Initial Developer are Copyright
+# (C) 2009 the Initial Developer. All Rights Reserved.
+#
+# Contributor(s): 
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+package Bugzilla::Migrate::Gnats;
+use strict;
+use base qw(Bugzilla::Migrate);
+
+use Bugzilla::Constants;
+use Bugzilla::Install::Util qw(indicate_progress);
+use Bugzilla::Util qw(format_time trim generate_random_password);
+
+use Email::Address;
+use Email::MIME;
+use File::Basename;
+use IO::File;
+use List::MoreUtils qw(firstidx);
+use List::Util qw(first);
+
+use constant REQUIRED_MODULES =&gt; [
+    {
+        package =&gt; 'Email-Simple-FromHandle',
+        module  =&gt; 'Email::Simple::FromHandle',
+        # This version added seekable handles.
+        version =&gt; 0.050,
+    },
+];
+
+use constant FIELD_MAP =&gt; {
+    'Number'         =&gt; 'bug_id',
+    'Category'       =&gt; 'product',
+    'Synopsis'       =&gt; 'short_desc',
+    'Responsible'    =&gt; 'assigned_to',
+    'State'          =&gt; 'bug_status',
+    'Class'          =&gt; 'cf_type',
+    'Classification' =&gt; '',
+    'Originator'     =&gt; 'reporter',
+    'Arrival-Date'   =&gt; 'creation_ts',
+    'Last-Modified'  =&gt; 'delta_ts',
+    'Release'        =&gt; 'version',
+    'Severity'       =&gt; 'bug_severity',
+    'Description'    =&gt; 'comment',
+};
+
+use constant VALUE_MAP =&gt; {
+    bug_severity =&gt; {
+        'serious'      =&gt; 'major',
+        'cosmetic'     =&gt; 'trivial',
+        'new-feature'  =&gt; 'enhancement',
+        'non-critical' =&gt; 'normal',
+    },
+    bug_status =&gt; {
+        'open'      =&gt; 'CONFIRMED',
+        'analyzed'  =&gt; 'IN_PROGRESS',
+        'suspended' =&gt; 'RESOLVED',
+        'feedback'  =&gt; 'RESOLVED',
+        'released'  =&gt; 'VERIFIED',
+    },
+    bug_status_resolution =&gt; {
+        'feedback'  =&gt; 'FIXED',
+        'released'  =&gt; 'FIXED',
+        'closed'    =&gt; 'FIXED',
+        'suspended' =&gt; 'LATER',
+    },
+    priority =&gt; {
+        'medium' =&gt; 'Normal',
+    },
+};
+
+use constant GNATS_CONFIG_VARS =&gt; (
+    {
+        name    =&gt; 'gnats_path',
+        default =&gt; '/var/lib/gnats',
+        desc    =&gt; &lt;&lt;END,
+# The path to the directory that contains the GNATS database.
+END
+    },
+    {
+        name    =&gt; 'default_email_domain',
+        default =&gt; 'example.com',
+        desc    =&gt; &lt;&lt;'END',
+# Some GNATS users do not have full email addresses, but Bugzilla requires
+# every user to have an email address. What domain should be appended to
+# usernames that don't have emails, to make them into email addresses?
+# (For example, if you leave this at the default, &quot;unknown&quot; would become
+# &quot;unknown@example.com&quot;.)
+END
+    },
+    {
+        name    =&gt; 'component_name',
+        default =&gt; 'General',
+        desc    =&gt; &lt;&lt;'END',
+# GNATS has only &quot;Category&quot; to classify bugs. However, Bugzilla has a
+# multi-level system of Products that contain Components. When importing
+# GNATS categories, they become a Product with one Component. What should
+# the name of that Component be?
+END
+    },
+    {
+        name    =&gt; 'version_regex',
+        default =&gt; '',
+        desc    =&gt; &lt;&lt;'END',
+# In GNATS, the &quot;version&quot; field can contain almost anything. However, in
+# Bugzilla, it's a drop-down, so you don't want too many choices in there.
+# If you specify a regular expression here, versions will be tested against
+# this regular expression, and if they match, the first match (the first set
+# of parentheses in the regular expression, also called &quot;$1&quot;) will be used
+# as the version value for the bug instead of the full version value specified
+# in GNATS.
+END
+    },
+    {
+        name    =&gt; 'default_originator',
+        default =&gt; 'gnats-admin',
+        desc    =&gt; &lt;&lt;'END',
+# Sometimes, a PR has no valid Originator, so we fall back to the From
+# header of the email. If the From header also isn't a valid username
+# (is just a name with spaces in it--we can't convert that to an email
+# address) then this username (which can either be a GNATS username or an
+# email address) will be considered to be the Originator of the PR.
+END
+    }
+);
+
+sub CONFIG_VARS {
+    my $self = shift;
+    my @vars = (GNATS_CONFIG_VARS, $self-&gt;SUPER::CONFIG_VARS);
+    my $field_map = first { $_-&gt;{name} eq 'translate_fields' } @vars;
+    $field_map-&gt;{default} = FIELD_MAP;
+    my $value_map = first { $_-&gt;{name} eq 'translate_values' } @vars;
+    $value_map-&gt;{default} = VALUE_MAP;
+    return @vars;
+}
+
+# Directories that aren't projects, or that we shouldn't be parsing
+use constant SKIP_DIRECTORIES =&gt; qw(
+    gnats-adm
+    gnats-queue
+    pending
+);
+
+use constant NON_COMMENT_FIELDS =&gt; qw(
+    Audit-Trail
+    Closed-Date
+    Confidential
+    Unformatted
+    attachments
+);
+
+# Certain fields can contain things that look like fields in them,
+# because they might contain quoted emails. To avoid mis-parsing,
+# we list out here the exact order of fields at the end of a PR
+# and wait for the next field to consider that we actually have
+# a field to parse.
+use constant END_FIELD_ORDER =&gt; qw(
+    Description
+    How-To-Repeat
+    Fix
+    Release-Note
+    Audit-Trail
+    Unformatted
+);
+
+use constant CUSTOM_FIELDS =&gt; {
+    cf_type =&gt; {
+        type        =&gt; FIELD_TYPE_SINGLE_SELECT,
+        description =&gt; 'Type',
+    },
+};
+
+use constant FIELD_REGEX =&gt; qr/^&gt;(\S+):\s*(.*)$/;
+
+# Used for bugs that have no Synopsis.
+use constant NO_SUBJECT =&gt; &quot;(no subject)&quot;;
+
+# This is the divider that GNATS uses between attachments in its database
+# files. It's missign two hyphens at the beginning because MIME Emails use
+# -- to start boundaries.
+use constant GNATS_BOUNDARY =&gt; '----gnatsweb-attachment----';
+
+use constant LONG_VERSION_LENGTH =&gt; 32;
+
+#########
+# Hooks #
+#########
+
+sub before_insert {
+    my $self = shift;
+
+    # gnats_id isn't a valid User::create field, and we don't need it
+    # anymore now.
+    delete $_-&gt;{gnats_id} foreach @{ $self-&gt;users };
+
+    # Grab a version out of a bug for each product, so that there is a
+    # valid &quot;version&quot; argument for Bugzilla::Product-&gt;create.
+    foreach my $product (@{ $self-&gt;products }) {
+        my $bug = first { $_-&gt;{product} eq $product-&gt;{name} and $_-&gt;{version} }
+                        @{ $self-&gt;bugs };
+        if (defined $bug) {
+            $product-&gt;{version} = $bug-&gt;{version};
+        }
+        else {
+            $product-&gt;{version} = 'unspecified';
+        }
+    }
+}
+
+#########
+# Users #
+#########
+
+sub _read_users {
+    my $self = shift;
+    my $path = $self-&gt;config('gnats_path');
+    my $file =  &quot;$path/gnats-adm/responsible&quot;;
+    $self-&gt;debug(&quot;Reading users from $file&quot;);
+    my $default_domain = $self-&gt;config('default_email_domain');
+    open(my $users_fh, '&lt;', $file) || die &quot;$file: $!&quot;;
+    my @users;
+    foreach my $line (&lt;$users_fh&gt;) {
+        $line = trim($line);
+        next if $line =~ /^#/;
+        my ($id, $name, $email) = split(':', $line, 3);
+        $email ||= &quot;$id\@$default_domain&quot;;
+        # We can't call our own translate_value, because that depends on
+        # the existence of user_map, which doesn't exist until after
+        # this method. However, we still want to translate any users found.
+        $email = $self-&gt;SUPER::translate_value('user', $email);
+        push(@users, { realname =&gt; $name, login_name =&gt; $email,
+                       gnats_id =&gt; $id });
+    }
+    close($users_fh);
+    return \@users;
+}
+
+sub user_map {
+    my $self = shift;
+    $self-&gt;{user_map} ||= { map { $_-&gt;{gnats_id} =&gt; $_-&gt;{login_name} }
+                                @{ $self-&gt;users } };
+    return $self-&gt;{user_map};
+}
+
+sub add_user {
+    my ($self, $id, $email) = @_;
+    return if defined $self-&gt;user_map-&gt;{$id};
+    $self-&gt;user_map-&gt;{$id} = $email;
+    push(@{ $self-&gt;users }, { login_name =&gt; $email, gnats_id =&gt; $id });
+}
+
+sub user_to_email {
+    my ($self, $value) = @_;
+    if (defined $self-&gt;user_map-&gt;{$value}) {
+        $value = $self-&gt;user_map-&gt;{$value};
+    }
+    elsif ($value !~ /@/) {
+        my $domain = $self-&gt;config('default_email_domain');
+        $value = &quot;$value\@$domain&quot;;
+    }
+    return $value;
+}
+
+############
+# Products #
+############
+
+sub _read_products {
+    my $self = shift;
+    my $path = $self-&gt;config('gnats_path');
+    my $file =  &quot;$path/gnats-adm/categories&quot;;
+    $self-&gt;debug(&quot;Reading categories from $file&quot;);
+
+    open(my $categories_fh, '&lt;', $file) || die &quot;$file: $!&quot;;    
+    my @products;
+    foreach my $line (&lt;$categories_fh&gt;) {
+        $line = trim($line);
+        next if $line =~ /^#/;
+        my ($name, $description, $assigned_to, $cc) = split(':', $line, 4);
+        my %product = ( name =&gt; $name, description =&gt; $description );
+        
+        my @initial_cc = split(',', $cc);
+        @initial_cc = @{ $self-&gt;translate_value('user', \@initial_cc) };
+        $assigned_to = $self-&gt;translate_value('user', $assigned_to);
+        my %component = ( name         =&gt; $self-&gt;config('component_name'),
+                          description  =&gt; $description,
+                          initialowner =&gt; $assigned_to,
+                          initial_cc   =&gt; \@initial_cc );
+        $product{components} = [\%component];
+        push(@products, \%product);
+    }
+    close($categories_fh);
+    return \@products;
+}
+
+################
+# Reading Bugs #
+################
+
+sub _read_bugs {
+    my $self = shift;
+    my $path = $self-&gt;config('gnats_path');
+    my @directories = glob(&quot;$path/*&quot;);
+    my @bugs;
+    foreach my $directory (@directories) {
+        next if !-d $directory;
+        my $name = basename($directory);
+        next if grep($_ eq $name, SKIP_DIRECTORIES);
+        push(@bugs, @{ $self-&gt;_parse_project($directory) });
+    }
+    @bugs = sort { $a-&gt;{Number} &lt;=&gt; $b-&gt;{Number} } @bugs;
+    return \@bugs;
+}
+
+sub _parse_project {
+    my ($self, $directory) = @_;
+    my @files = glob(&quot;$directory/*&quot;);
+
+    $self-&gt;debug(&quot;Reading Project: $directory&quot;);
+    # Sometimes other files get into gnats directories.
+    @files = grep { basename($_) =~ /^\d+$/ } @files;
+    my @bugs;
+    my $count = 1;
+    my $total = scalar @files;
+    print basename($directory) . &quot;:\n&quot;;
+    foreach my $file (@files) {
+        push(@bugs, $self-&gt;_parse_bug_file($file));
+        if (!$self-&gt;verbose) {
+            indicate_progress({ current =&gt; $count++, every =&gt; 5,
+                                total =&gt; $total });
+        }
+    }
+    return \@bugs;
+}
+
+sub _parse_bug_file {
+    my ($self, $file) = @_;
+    $self-&gt;debug(&quot;Reading $file&quot;);
+    open(my $fh, &quot;&lt;&quot;, $file) || die &quot;$file: $!&quot;;
+    my $email = Email::Simple::FromHandle-&gt;new($fh);
+    my $fields = $self-&gt;_get_gnats_field_data($email);
+    # We parse attachments here instead of during translate_bug,
+    # because otherwise we'd be taking up huge amounts of memory storing
+    # all the raw attachment data in memory.
+    $fields-&gt;{attachments} = $self-&gt;_parse_attachments($fields);
+    close($fh);
+    return $fields;
+}
+
+sub _get_gnats_field_data {
+    my ($self, $email) = @_;
+    my ($current_field, @value_lines, %fields);
+    $email-&gt;reset_handle();
+    my $handle = $email-&gt;handle;
+    foreach my $line (&lt;$handle&gt;) {
+        # If this line starts a field name
+        if ($line =~ FIELD_REGEX) {
+            my ($new_field, $rest_of_line) = ($1, $2);
+            
+            # If this is one of the last few PR fields, then make sure
+            # that we're getting our fields in the right order.
+            my $new_field_valid = 1;
+            my $search_for = $current_field || '';
+            my $current_field_pos = firstidx { $_ eq $search_for }
+                                             END_FIELD_ORDER;
+            if ($current_field_pos &gt; -1) {
+                my $new_field_pos = firstidx { $_ eq $new_field } 
+                                             END_FIELD_ORDER;
+                # We accept any field, as long as it's later than this one.
+                $new_field_valid = $new_field_pos &gt; $current_field_pos ? 1 : 0;
+            }
+            
+            if ($new_field_valid) {
+                if ($current_field) {
+                    $fields{$current_field} = _handle_lines(\@value_lines);
+                    @value_lines = ();
+                }
+                $current_field = $new_field;
+                $line = $rest_of_line;
+            }
+        }
+        push(@value_lines, $line) if defined $line;
+    }
+    $fields{$current_field} = _handle_lines(\@value_lines);
+    $fields{cc} = [$email-&gt;header('Cc')] if $email-&gt;header('Cc');
+    
+    # If the Originator is invalid and we don't have a translation for it,
+    # use the From header instead.
+    my $originator = $self-&gt;translate_value('reporter', $fields{Originator},
+                                            { check_only =&gt; 1 });
+    if ($originator !~ Bugzilla-&gt;params-&gt;{emailregexp}) {
+        # We use the raw header sometimes, because it looks like &quot;From: user&quot;
+        # which Email::Address won't parse but we can still use.
+        my $address = $email-&gt;header('From');
+        my ($parsed) = Email::Address-&gt;parse($address);
+        if ($parsed) {
+            $address = $parsed-&gt;address;
+        }
+        if ($address) {
+            $self-&gt;debug(
+                &quot;PR $fields{Number} had an Originator that was not a valid&quot;
+                . &quot; user ($fields{Originator}). Using From ($address)&quot;
+                . &quot; instead.\n&quot;);
+            my $address_email = $self-&gt;translate_value('reporter', $address,
+                                                       { check_only =&gt; 1 });
+            if ($address_email !~ Bugzilla-&gt;params-&gt;{emailregexp}) {
+                $self-&gt;debug(&quot; From was also invalid, using default_originator.\n&quot;);
+                $address = $self-&gt;config('default_originator');
+            }
+            $fields{Originator} = $address;
+        }
+    }
+
+    $self-&gt;debug(\%fields, 3);
+    return \%fields;
+}
+
+sub _handle_lines {
+    my ($lines) = @_;
+    my $value = join('', @$lines);
+    $value =~ s/\s+$//;
+    return $value;
+}
+
+####################
+# Translating Bugs #
+####################
+
+sub translate_bug {
+    my ($self, $fields) = @_;
+
+    my ($bug, $other_fields) = $self-&gt;SUPER::translate_bug($fields);
+
+    $bug-&gt;{attachments} = delete $other_fields-&gt;{attachments};
+
+    if (defined $other_fields-&gt;{_add_to_comment}) {
+        $bug-&gt;{comment} .= delete $other_fields-&gt;{_add_to_comment};
+    }
+
+    my ($changes, $extra_comment) =
+        $self-&gt;_parse_audit_trail($bug, $other_fields-&gt;{'Audit-Trail'});
+
+    my @comments;
+    foreach my $change (@$changes) {
+        if (exists $change-&gt;{comment}) {
+            push(@comments, {
+                thetext  =&gt; $change-&gt;{comment},
+                who      =&gt; $change-&gt;{who},
+                bug_when =&gt; $change-&gt;{bug_when} });
+            delete $change-&gt;{comment};
+        }
+    }
+    $bug-&gt;{history}  = $changes;
+
+    if (trim($extra_comment)) {
+        push(@comments, { thetext =&gt; $extra_comment, who =&gt; $bug-&gt;{reporter},
+                          bug_when =&gt; $bug-&gt;{delta_ts} || $bug-&gt;{creation_ts} });
+    }
+    $bug-&gt;{comments} = \@comments;
+    
+    $bug-&gt;{component} = $self-&gt;config('component_name');
+    if (!$bug-&gt;{short_desc}) {
+        $bug-&gt;{short_desc} = NO_SUBJECT;
+    }
+    
+    foreach my $attachment (@{ $bug-&gt;{attachments} || [] }) {
+        $attachment-&gt;{submitter} = $bug-&gt;{reporter};
+        $attachment-&gt;{creation_ts} = $bug-&gt;{creation_ts};
+    }
+
+    $self-&gt;debug($bug, 3);
+    return $bug;
+}
+
+sub _parse_audit_trail {
+    my ($self, $bug, $audit_trail) = @_;
+    return [] if !trim($audit_trail);
+    $self-&gt;debug(&quot; Parsing audit trail...&quot;, 2);
+    
+    if ($audit_trail !~ /^\S+-Changed-\S+:/ms) {
+        # This is just a comment from the bug's creator.
+        $self-&gt;debug(&quot;  Audit trail is just a comment.&quot;, 2);
+        return ([], $audit_trail);
+    }
+    
+    my (@changes, %current_data, $current_column, $on_why);
+    my $extra_comment = '';
+    my $current_field;
+    my @all_lines = split(&quot;\n&quot;, $audit_trail);
+    foreach my $line (@all_lines) {
+        # GNATS history looks like:
+        # Status-Changed-From-To: open-&gt;closed
+        # Status-Changed-By: jack
+        # Status-Changed-When: Mon May 12 14:46:59 2003
+        # Status-Changed-Why:
+        #     This is some comment here about the change.
+        if ($line =~ /^(\S+)-Changed-(\S+):(.*)/) {
+            my ($field, $column, $value) = ($1, $2, $3);
+            my $bz_field = $self-&gt;translate_field($field);
+            # If it's not a field we're importing, we don't care about
+            # its history.
+            next if !$bz_field;
+            # GNATS doesn't track values for description changes,
+            # unfortunately, and that's the only information we'd be able to
+            # use in Bugzilla for the audit trail on that field.
+            next if $bz_field eq 'comment';
+            $current_field = $bz_field if !$current_field;
+            if ($bz_field ne $current_field) {
+                $self-&gt;_store_audit_change(
+                    \@changes, $current_field, \%current_data);
+                %current_data = ();
+                $current_field = $bz_field;
+            }
+            $value = trim($value);
+            $self-&gt;debug(&quot;  $bz_field $column: $value&quot;, 3);
+            if ($column eq 'From-To') {
+                my ($from, $to) = split('-&gt;', $value, 2);
+                # Sometimes there's just a - instead of a -&gt; between the values.
+                if (!defined($to)) {
+                    ($from, $to) = split('-', $value, 2);
+                }
+                $current_data{added} = $to;
+                $current_data{removed} = $from;
+            }
+            elsif ($column eq 'By') {
+                my $email = $self-&gt;translate_value('user', $value);
+                # Sometimes we hit users in the audit trail that we haven't
+                # seen anywhere else.
+                $current_data{who} = $email;
+            }
+            elsif ($column eq 'When') {
+                $current_data{bug_when} = $self-&gt;parse_date($value);
+            }
+            if ($column eq 'Why') {
+                $value = '' if !defined $value;
+                $current_data{comment} = $value;
+                $on_why = 1;
+            }
+            else {
+                $on_why = 0;
+            }
+        }
+        elsif ($on_why) {
+            # &quot;Why&quot; lines are indented four characters.
+            $line =~ s/^\s{4}//;
+            $current_data{comment} .= &quot;$line\n&quot;;
+        }
+        else {
+            $self-&gt;debug(
+                &quot;Extra Audit-Trail line on $bug-&gt;{product} $bug-&gt;{bug_id}:&quot;
+                 . &quot; $line\n&quot;, 2);
+            $extra_comment .= &quot;$line\n&quot;;
+        }
+    }
+    $self-&gt;_store_audit_change(\@changes, $current_field, \%current_data);
+    return (\@changes, $extra_comment);
+}
+
+sub _store_audit_change {
+    my ($self, $changes, $old_field, $current_data) = @_;
+
+    $current_data-&gt;{field} = $old_field;
+    $current_data-&gt;{removed} = 
+        $self-&gt;translate_value($old_field, $current_data-&gt;{removed});
+    $current_data-&gt;{added} =
+        $self-&gt;translate_value($old_field, $current_data-&gt;{added});
+    push(@$changes, { %$current_data });
+}
+
+sub _parse_attachments {
+    my ($self, $fields) = @_;
+    my $unformatted = delete $fields-&gt;{'Unformatted'};
+    my $gnats_boundary = GNATS_BOUNDARY;
+    # A sanity checker to make sure that we're parsing attachments right.
+    my $num_attachments = 0;
+    $num_attachments++ while ($unformatted =~ /\Q$gnats_boundary\E/g);
+    # Sometimes there's a GNATS_BOUNDARY that is on the same line as other data.
+    $unformatted =~ s/(\S\s*)\Q$gnats_boundary\E$/$1\n$gnats_boundary/mg;
+    # Often the &quot;Unformatted&quot; section starts with stuff before
+    # ----gnatsweb-attachment---- that isn't necessary.
+    $unformatted =~ s/^\s*From:.+?Reply-to:[^\n]+//s;
+    $unformatted = trim($unformatted);
+    return [] if !$unformatted;
+    $self-&gt;debug('Reading attachments...', 2);
+    my $boundary = generate_random_password(48);
+    $unformatted =~ s/\Q$gnats_boundary\E/--$boundary/g;
+    # Sometimes the whole Unformatted section is indented by exactly
+    # one space, and needs to be fixed.
+    if ($unformatted =~ /--\Q$boundary\E\n /) {
+        $unformatted =~ s/^ //mg;
+    }
+    $unformatted = &lt;&lt;END;
+From: nobody
+MIME-Version: 1.0
+Content-Type: multipart/mixed; boundary=&quot;$boundary&quot;
+
+This is a multi-part message in MIME format.
+--$boundary
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 7bit
+
+$unformatted
+--$boundary--
+END
+    my $email = new Email::MIME(\$unformatted);
+    my @parts = $email-&gt;parts;
+    # Remove the fake body.
+    my $part1 = shift @parts;
+    if ($part1-&gt;body) {
+        $self-&gt;debug(&quot; Additional Unformatted data found on &quot;
+                     . $fields-&gt;{Category} . &quot; bug &quot; . $fields-&gt;{Number});
+        $self-&gt;debug($part1-&gt;body, 3);
+        $fields-&gt;{_add_comment} .= &quot;\n\nUnformatted:\n&quot; . $part1-&gt;body;
+    }
+
+    my @attachments;
+    foreach my $part (@parts) {
+        $self-&gt;debug('  Parsing attachment: ' . $part-&gt;filename);
+        my $temp_fh = IO::File-&gt;new_tmpfile or die (&quot;Can't create tempfile: $!&quot;);
+        $temp_fh-&gt;binmode;
+        print $temp_fh $part-&gt;body;
+        my $content_type = $part-&gt;content_type;
+        $content_type =~ s/; name=.+$//;
+        my $attachment = { filename    =&gt; $part-&gt;filename,
+                           description =&gt; $part-&gt;filename,
+                           mimetype    =&gt; $content_type,
+                           data        =&gt; $temp_fh };
+        $self-&gt;debug($attachment, 3);
+        push(@attachments, $attachment);
+    }
+    
+    if (scalar(@attachments) ne $num_attachments) {
+        warn &quot;WARNING: Expected $num_attachments attachments but got &quot;
+             . scalar(@attachments) . &quot;\n&quot; ;
+        $self-&gt;debug($unformatted, 3);
+    }
+    return \@attachments;
+}
+
+sub translate_value {
+    my $self = shift;
+    my ($field, $value, $options) = @_;
+    my $original_value = $value;
+    $options ||= {};
+
+    if (!ref($value) and grep($_ eq $field, $self-&gt;USER_FIELDS)) {
+        if ($value =~ /(\S+\@\S+)/) {
+            $value = $1;
+            $value =~ s/^&lt;//;
+            $value =~ s/&gt;$//;
+        }
+        else {
+            # Sometimes names have extra stuff on the end like &quot;(Somebody's Name)&quot;
+            $value =~ s/\s+\(.+\)$//;
+            # Sometimes user fields look like &quot;(user)&quot; instead of just &quot;user&quot;.
+            $value =~ s/^\((.+)\)$/$1/;
+            $value = trim($value);
+        }
+    }
+
+    if ($field eq 'version' and $value ne '') {
+        my $version_re = $self-&gt;config('version_regex');
+        if ($version_re and $value =~ $version_re) {
+            $value = $1;
+        }
+        # In the GNATS that I tested this with, there were many extremely long
+        # values for &quot;version&quot; that caused some import problems (they were
+        # longer than the max allowed version value). So if the version value
+        # is longer than 32 characters, pull out the first thing that looks
+        # like a version number.
+        elsif (length($value) &gt; LONG_VERSION_LENGTH) {
+            $value =~ s/^.+?\b(\d[\w\.]+)\b.+$/$1/;
+        }
+    }
+    
+    my @args = @_;
+    $args[1] = $value;
+    
+    $value = $self-&gt;SUPER::translate_value(@args);
+    return $value if ref $value;
+    
+    if (grep($_ eq $field, $self-&gt;USER_FIELDS)) {
+        my $from_value = $value;
+        $value = $self-&gt;user_to_email($value);
+        $args[1] = $value;
+        # If we got something new from user_to_email, do any necessary
+        # translation of it.
+        $value = $self-&gt;SUPER::translate_value(@args);
+        if (!$options-&gt;{check_only}) {
+            $self-&gt;add_user($from_value, $value);
+        }
+    }
+    
+    return $value;
+}
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaMigratepm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/Migrate.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Migrate.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Migrate.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,1174 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is The Bugzilla Migration Tool.
+#
+# The Initial Developer of the Original Code is Lambda Research
+# Corporation. Portions created by the Initial Developer are Copyright
+# (C) 2009 the Initial Developer. All Rights Reserved.
+#
+# Contributor(s): 
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+package Bugzilla::Migrate;
+use strict;
+
+use Bugzilla::Attachment;
+use Bugzilla::Bug qw(LogActivityEntry);
+use Bugzilla::Component;
+use Bugzilla::Constants;
+use Bugzilla::Error;
+use Bugzilla::Install::Requirements ();
+use Bugzilla::Install::Util qw(indicate_progress);
+use Bugzilla::Product;
+use Bugzilla::Util qw(get_text trim generate_random_password);
+use Bugzilla::User ();
+use Bugzilla::Status ();
+use Bugzilla::Version;
+
+use Data::Dumper;
+use Date::Parse;
+use DateTime;
+use Fcntl qw(SEEK_SET);
+use File::Basename;
+use List::Util qw(first);
+use Safe;
+
+use constant CUSTOM_FIELDS      =&gt; {};
+use constant REQUIRED_MODULES   =&gt; [];
+use constant NON_COMMENT_FIELDS =&gt; ();
+
+use constant CONFIG_VARS =&gt; (
+    {
+        name    =&gt; 'translate_fields',
+        default =&gt; {},
+        desc    =&gt; &lt;&lt;'END',
+# This maps field names in your bug-tracker to Bugzilla field names. If a field
+# has the same name in your bug-tracker and Bugzilla (case-insensitively), it
+# doesn't need a mapping here. If a field isn't listed here and doesn't have
+# an equivalent field in Bugzilla, its data will be added to the initial
+# description of each bug migrated. If the right side is an empty string, it
+# means &quot;just put the value of this field into the initial description of the
+# bug&quot;.
+#
+# Generally, you can keep the defaults, here.
+#
+# If you want to know the internal names of various Bugzilla fields
+# (as used on the right side here), see the fielddefs table in the Bugzilla
+# database.
+#
+# If you are mapping to any custom fields in Bugzilla, you have to create
+# the custom fields using Bugzilla Administration interface before you run
+# migrate.pl. However, if they are drop down or multi-select fields, you 
+# don't have to populate the list of values--migrate.pl will do that for you.
+# Some migrators create certain custom fields by default. If you see a
+# field name starting with &quot;cf_&quot; on the right side of this configuration
+# variable by default, then that field will be automatically created by
+# the migrator and you don't have to worry about it.
+END
+    },
+    {
+        name    =&gt; 'translate_values',
+        default =&gt; {},
+        desc    =&gt; &lt;&lt;'END',
+# This configuration variable allows you to say that a particular field
+# value in your current bug-tracker should be translated to a different
+# value when it's imported into Bugzilla.
+#
+# The value of this variable should look something like this:
+#
+# {
+#     bug_status =&gt; {
+#         # Translate &quot;Handled&quot; into &quot;RESOLVED&quot;.
+#         &quot;Handled&quot;     =&gt; &quot;RESOLVED&quot;,
+#         &quot;In Progress&quot; =&gt; &quot;IN_PROGRESS&quot;,
+#     },
+#
+#     priority =&gt; {
+#         # Translate &quot;Serious&quot; into &quot;Highest&quot;
+#         &quot;Serious&quot; =&gt; &quot;Highest&quot;,
+#     },
+# };
+#
+# Values are translated case-insensitively, so &quot;foo&quot; will match &quot;Foo&quot;, &quot;FOO&quot;,
+# and &quot;foo&quot;.
+#
+# Note that the field names used are *Bugzilla* field names (from the fielddefs
+# table in the database), not the field names from your current bug-tracker.
+#
+# The special field name &quot;user&quot; will be used to translate any field that
+# can contain a user, including reporter, assigned_to, qa_contact, and cc.
+# You should use &quot;user&quot; instead of specifying reporter, assigned_to, etc.
+# manually.
+#
+# The special field &quot;bug_status_resolution&quot; can be used to give certain
+# statuses in your bug-tracker a resolution in Bugzilla. So, for example,
+# you could translate the &quot;fixed&quot; status in your Bugzilla to &quot;RESOLVED&quot;
+# in the &quot;bug_status&quot; field, and then put &quot;fixed =&gt; 'FIXED'&quot; in the
+# &quot;bug_status_resolution&quot; field to translated a &quot;fixed&quot; bug into
+# RESOLVED FIXED in Bugzilla.
+#
+# Values that don't get translated will be imported as-is.
+END
+    },
+    {
+        name    =&gt; 'starting_bug_id',
+        default =&gt; 0,
+        desc    =&gt; &lt;&lt;'END',
+# What bug ID do you want the first imported bug to get? If you set this to
+# 0, then the imported bug ids will just start right after the current
+# bug ids. If you use this configuration variable, you must make sure that
+# nobody else is using your Bugzilla while you run the migration, or a new
+# bug filed by a user might take this ID instead.
+END
+    },
+    {
+        name    =&gt; 'timezone',
+        default =&gt; 'local',
+        desc =&gt; &lt;&lt;'END',
+# If migrate.pl comes across any dates without timezones, while doing the
+# migration, what timezone should we assume those dates are in? 
+# The best format for this variable is something like &quot;America/Los Angeles&quot;.
+# However, time zone abbreviations (like PST, PDT, etc.) are also acceptable,
+# but will result in a less-accurate conversion of times and dates.
+#
+# The special value &quot;local&quot; means &quot;use the same timezone as the system I
+# am running this script on now&quot;.
+END
+    },
+);
+
+use constant USER_FIELDS =&gt; qw(user assigned_to qa_contact reporter cc);
+
+#########################
+# Main Migration Method #
+#########################
+
+sub do_migration {
+    my $self = shift;
+    my $dbh = Bugzilla-&gt;dbh;
+    # On MySQL, setting serial values implicitly commits a transaction,
+    # so we want to do it up here, outside of any transaction. This also
+    # has the advantage of loading the config before anything else is done.
+    if ($self-&gt;config('starting_bug_id')) {
+        $dbh-&gt;bz_set_next_serial_value('bugs', 'bug_id',
+                                       $self-&gt;config('starting_bug_id'));
+    }    
+    $dbh-&gt;bz_start_transaction();
+
+    # Read Other Database
+    my $users    = $self-&gt;users;
+    my $products = $self-&gt;products;
+    my $bugs     = $self-&gt;bugs;
+    $self-&gt;after_read();
+    
+    $self-&gt;translate_all_bugs($bugs);
+
+    Bugzilla-&gt;set_user(Bugzilla::User-&gt;super_user);
+    
+    # Insert into Bugzilla
+    $self-&gt;before_insert();
+    $self-&gt;insert_users($users);
+    $self-&gt;insert_products($products);
+    $self-&gt;create_custom_fields();
+    $self-&gt;create_legal_values($bugs);
+    $self-&gt;insert_bugs($bugs);
+    $self-&gt;after_insert();
+    if ($self-&gt;dry_run) {
+        $dbh-&gt;bz_rollback_transaction();
+        $self-&gt;reset_serial_values();
+    }
+    else {
+        $dbh-&gt;bz_commit_transaction();
+    }
+}
+
+################
+# Constructors #
+################
+
+sub new {
+    my ($class) = @_;
+    my $self = { };
+    bless $self, $class;
+    return $self;
+}
+
+sub load {
+    my ($class, $from) = @_;
+    my $libdir = bz_locations()-&gt;{libpath};
+    my @migration_modules = glob(&quot;$libdir/Bugzilla/Migrate/*&quot;);
+    my ($module) = grep { basename($_) =~ /^\Q$from\E\.pm$/i }
+                          @migration_modules;
+    if (!$module) {
+        ThrowUserError('migrate_from_invalid', { from =&gt; $from });
+    }
+    require $module;
+    my $canonical_name = _canonical_name($module);
+    return &quot;Bugzilla::Migrate::$canonical_name&quot;-&gt;new;
+}
+
+#############
+# Accessors #
+#############
+
+sub name {
+    my $self = shift;
+    return _canonical_name(ref $self);
+}
+
+sub dry_run {
+    my ($self, $value) = @_;
+    if (scalar(@_) &gt; 1) {
+        $self-&gt;{dry_run} = $value;
+    }
+    return $self-&gt;{dry_run} || 0;
+}
+
+
+sub verbose {
+    my ($self, $value) = @_;
+    if (scalar(@_) &gt; 1) {
+        $self-&gt;{verbose} = $value;
+    }
+    return $self-&gt;{verbose} || 0;
+}
+
+sub debug {
+    my ($self, $value, $level) = @_;
+    $level ||= 1;
+    if ($self-&gt;verbose &gt;= $level) {
+        $value = Dumper($value) if ref $value;
+        print STDERR $value, &quot;\n&quot;;
+    }
+}
+
+sub bug_fields {
+    my $self = shift;
+    $self-&gt;{bug_fields} ||= Bugzilla-&gt;fields({ by_name =&gt; 1 });
+    return $self-&gt;{bug_fields};
+}
+
+sub users {
+    my $self = shift;
+    if (!exists $self-&gt;{users}) {
+        print get_text('migrate_reading_users'), &quot;\n&quot;;
+        $self-&gt;{users} = $self-&gt;_read_users();
+    }
+    return $self-&gt;{users};
+}
+
+sub products {
+    my $self = shift;
+    if (!exists $self-&gt;{products}) {
+        print get_text('migrate_reading_products'), &quot;\n&quot;;
+        $self-&gt;{products} = $self-&gt;_read_products();
+    }
+    return $self-&gt;{products};
+}
+
+sub bugs {
+    my $self = shift;
+    if (!exists $self-&gt;{bugs}) {
+        print get_text('migrate_reading_bugs'), &quot;\n&quot;;
+        $self-&gt;{bugs} = $self-&gt;_read_bugs();
+    }
+    return $self-&gt;{bugs};
+}
+
+###########
+# Methods #
+###########
+
+sub check_requirements {
+    my $self = shift;
+    my $missing = Bugzilla::Install::Requirements::_check_missing(
+        $self-&gt;REQUIRED_MODULES, 1);
+    my %results = (
+        apache      =&gt; [],
+        pass        =&gt; @$missing ? 0 : 1,
+        missing     =&gt; $missing,
+        any_missing =&gt; @$missing ? 1 : 0,
+        hide_all    =&gt; 1,
+        # These are just for compatibility with print_module_instructions
+        one_dbd  =&gt; 1,
+        optional =&gt; [],
+    );
+    Bugzilla::Install::Requirements::print_module_instructions(
+        \%results, 1);
+    exit(1) if @$missing;
+}
+
+sub reset_serial_values {
+    my $self = shift;
+    return if $self-&gt;{serial_values_reset};
+    my $dbh = Bugzilla-&gt;dbh;
+    my %reset = (
+        'bugs'        =&gt; 'bug_id',
+        'attachments' =&gt; 'attach_id',
+        'profiles'    =&gt; 'userid',
+        'longdescs'   =&gt; 'comment_id',
+        'products'    =&gt; 'id',
+        'components'  =&gt; 'id',
+        'versions'    =&gt; 'id',
+        'milestones'  =&gt; 'id',
+    );
+    my @select_fields = grep { $_-&gt;is_select } (values %{ $self-&gt;bug_fields });
+    foreach my $field (@select_fields) {
+        next if $field-&gt;is_abnormal;
+        $reset{$field-&gt;name} = 'id';
+    }
+    
+    while (my ($table, $column) = each %reset) {
+        $dbh-&gt;bz_set_next_serial_value($table, $column);
+    }
+    
+    $self-&gt;{serial_values_reset} = 1;
+}
+
+###################
+# Bug Translation #
+###################
+
+sub translate_all_bugs {
+    my ($self, $bugs) = @_;
+    print get_text('migrate_translating_bugs'), &quot;\n&quot;;
+    # We modify the array in place so that $self-&gt;bugs will return the
+    # modified bugs, in case $self-&gt;before_insert wants them.
+    my $num_bugs = scalar(@$bugs);
+    for (my $i = 0; $i &lt; $num_bugs; $i++) {
+        $bugs-&gt;[$i] = $self-&gt;translate_bug($bugs-&gt;[$i]);
+    }
+}
+
+sub translate_bug {
+    my ($self, $fields) = @_;
+    my (%bug, %other_fields);
+    my $original_status;
+    foreach my $field (keys %$fields) {
+        my $value = delete $fields-&gt;{$field};
+        my $bz_field = $self-&gt;translate_field($field);
+        if ($bz_field) {
+            $bug{$bz_field} = $self-&gt;translate_value($bz_field, $value);
+            if ($bz_field eq 'bug_status') {
+                $original_status = $value;
+            }
+        }
+        else {
+            $other_fields{$field} = $value;
+        }
+    }
+    
+    if (defined $original_status and !defined $bug{resolution}
+        and $self-&gt;map_value('bug_status_resolution', $original_status))
+    {
+        $bug{resolution} = $self-&gt;map_value('bug_status_resolution',
+                                            $original_status);
+    }
+    
+    $bug{comment} = $self-&gt;_generate_description(\%bug, \%other_fields);
+    
+    return wantarray ? (\%bug, \%other_fields) : \%bug;
+}
+
+sub _generate_description {
+    my ($self, $bug, $fields) = @_;
+    
+    my $description = &quot;&quot;;
+    foreach my $field (sort keys %$fields) {
+        next if grep($_ eq $field, $self-&gt;NON_COMMENT_FIELDS);
+        my $value = delete $fields-&gt;{$field};
+        next if $value eq '';
+        $description .= &quot;$field: $value\n&quot;;
+    }
+    $description .= &quot;\n&quot; if $description;
+
+    return $description . $bug-&gt;{comment};
+}
+
+sub translate_field {
+    my ($self, $field) = @_;
+    my $mapped = $self-&gt;config('translate_fields')-&gt;{$field};
+    return $mapped if defined $mapped;
+    ($mapped) = grep { lc($_) eq lc($field) } (keys %{ $self-&gt;bug_fields });
+    return $mapped;
+}
+
+sub parse_date {
+    my ($self, $date) = @_;
+    my @time = strptime($date);
+    # Handle times with timezones that strptime doesn't know about.
+    if (!scalar @time) {
+        $date =~ s/\s+\S+$//;
+        @time = strptime($date);
+    }
+    my $tz;
+    if ($time[6]) {
+        $tz = Bugzilla-&gt;local_timezone-&gt;offset_as_string($time[6]);
+    }
+    else {
+        $tz = $self-&gt;config('timezone');
+        $tz =~ s/\s/_/g;
+        if ($tz eq 'local') {
+            $tz = Bugzilla-&gt;local_timezone;
+        }
+    }
+    my $dt = DateTime-&gt;new({
+        year   =&gt; $time[5] + 1900,
+        month  =&gt; $time[4] + 1,
+        day    =&gt; $time[3],
+        hour   =&gt; $time[2],
+        minute =&gt; $time[1],
+        second =&gt; int($time[0]),
+        time_zone =&gt; $tz, 
+    });
+    $dt-&gt;set_time_zone(Bugzilla-&gt;local_timezone);
+    return $dt-&gt;iso8601;
+}
+
+sub translate_value {
+    my ($self, $field, $value) = @_;
+    
+    if (!defined $value) {
+        warn(&quot;Got undefined value for $field\n&quot;);
+        $value = '';
+    }
+    
+    if (ref($value) eq 'ARRAY') {
+        return [ map($self-&gt;translate_value($field, $_), @$value) ];
+    }
+
+    
+    if (defined $self-&gt;map_value($field, $value)) {
+        return $self-&gt;map_value($field, $value);
+    }
+    
+    if (grep($_ eq $field, USER_FIELDS)) {
+        if (defined $self-&gt;map_value('user', $value)) {
+            return $self-&gt;map_value('user', $value);
+        }
+    }
+
+    my $field_obj = $self-&gt;bug_fields-&gt;{$field};
+    if ($field eq 'creation_ts' or $field eq 'delta_ts'
+        or ($field_obj and $field_obj-&gt;type == FIELD_TYPE_DATETIME))
+    {
+        $value = trim($value);
+        return undef if !$value;
+        return $self-&gt;parse_date($value);
+    }
+    
+    return $value;
+}
+
+
+sub map_value {
+    my ($self, $field, $value) = @_;
+    return $self-&gt;_value_map-&gt;{$field}-&gt;{lc($value)};
+}
+
+sub _value_map {
+    my $self = shift;
+    if (!defined $self-&gt;{_value_map}) {
+        # Lowercase all values to make them case-insensitive.
+        my %map;
+        my $translation = $self-&gt;config('translate_values');
+        foreach my $field (keys %$translation) {
+            my $value_mapping = $translation-&gt;{$field};
+            foreach my $value (keys %$value_mapping) {
+                $map{$field}-&gt;{lc($value)} = $value_mapping-&gt;{$value};
+            }
+        }
+        $self-&gt;{_value_map} = \%map;
+    }
+    return $self-&gt;{_value_map};
+}
+
+#################
+# Configuration #
+#################
+
+sub config {
+    my ($self, $var) = @_;
+    if (!exists $self-&gt;{config}) {
+        $self-&gt;{config} = $self-&gt;read_config;
+    }
+    return $self-&gt;{config}-&gt;{$var};
+}
+
+sub config_file_name {
+    my $self = shift;
+    my $name = $self-&gt;name;
+    my $dir = bz_locations()-&gt;{datadir};
+    return &quot;$dir/migrate-$name.cfg&quot;
+}
+
+sub read_config {
+    my ($self) = @_;
+    my $file = $self-&gt;config_file_name;
+    if (!-e $file) {
+        $self-&gt;write_config();
+        ThrowUserError('migrate_config_created', { file =&gt; $file });
+    }
+    open(my $fh, &quot;&lt;&quot;, $file) || die &quot;$file: $!&quot;;
+    my $safe = new Safe;
+    $safe-&gt;rdo($file);
+    my @read_symbols = map($_-&gt;{name}, $self-&gt;CONFIG_VARS);
+    my %config;
+    foreach my $var (@read_symbols) {
+        my $glob = $safe-&gt;varglob($var);
+        $config{$var} = $$glob;
+    }
+    return \%config;
+}
+
+sub write_config {
+    my ($self) = @_;
+    my $file = $self-&gt;config_file_name;
+    open(my $fh, &quot;&gt;&quot;, $file) || die &quot;$file: $!&quot;;
+    # Fixed indentation
+    local $Data::Dumper::Indent = 1;
+    local $Data::Dumper::Quotekeys = 0;
+    local $Data::Dumper::Sortkeys = 1;
+    foreach my $var ($self-&gt;CONFIG_VARS) {
+        print $fh &quot;\n&quot;, $var-&gt;{desc},
+        Data::Dumper-&gt;Dump([$var-&gt;{default}], [$var-&gt;{name}]);
+    }
+    close($fh);
+}
+
+####################################
+# Default Implementations of Hooks #
+####################################
+
+sub after_insert  {}
+sub before_insert {}
+sub after_read    {}
+
+#############
+# Inserters #
+#############
+
+sub insert_users {
+    my ($self, $users) = @_;
+    foreach my $user (@$users) {
+        next if new Bugzilla::User({ name =&gt; $user-&gt;{login_name} });
+        my $generated_password;
+        if (!defined $user-&gt;{cryptpassword}) {
+            $generated_password = lc(generate_random_password());
+            $user-&gt;{cryptpassword} = $generated_password;
+        }
+        my $created = Bugzilla::User-&gt;create($user);
+        print get_text('migrate_user_created',
+                       { created  =&gt; $created,
+                         password =&gt; $generated_password }), &quot;\n&quot;;
+    }
+}
+
+# XXX This should also insert Classifications.
+sub insert_products {
+    my ($self, $products) = @_;
+    foreach my $product (@$products) {
+        my $components = delete $product-&gt;{components};
+        
+        my $created_prod = new Bugzilla::Product({ name =&gt; $product-&gt;{name} });
+        if (!$created_prod) {
+            $created_prod = Bugzilla::Product-&gt;create($product);
+            print get_text('migrate_product_created',
+                           { created =&gt; $created_prod }), &quot;\n&quot;;
+        }
+        
+        foreach my $component (@$components) {
+            next if new Bugzilla::Component({ product =&gt; $created_prod,
+                                              name    =&gt; $component-&gt;{name} });
+            my $created_comp = Bugzilla::Component-&gt;create(
+                { %$component, product =&gt; $created_prod });
+            print '  ', get_text('migrate_component_created',
+                                 { comp =&gt; $created_comp,
+                                   product =&gt; $created_prod }), &quot;\n&quot;;
+        }
+    }
+}
+
+sub create_custom_fields {
+    my $self = shift;
+    foreach my $field (keys %{ $self-&gt;CUSTOM_FIELDS }) {
+        next if new Bugzilla::Field({ name =&gt; $field });
+        my %values = %{ $self-&gt;CUSTOM_FIELDS-&gt;{$field} };
+        # We set these all here for the dry-run case.
+        my $created = { %values, name =&gt; $field, custom =&gt; 1 };
+        if (!$self-&gt;dry_run) {
+            $created = Bugzilla::Field-&gt;create($created);
+        }
+        print get_text('migrate_field_created', { field =&gt; $created }), &quot;\n&quot;;
+    }
+    delete $self-&gt;{bug_fields};
+}
+
+sub create_legal_values {
+    my ($self, $bugs) = @_;
+    my @select_fields = grep($_-&gt;is_select, values %{ $self-&gt;bug_fields });
+
+    # Get all the values in use on all the bugs we're importing.
+    my (%values, %product_values);
+    foreach my $bug (@$bugs) {
+        foreach my $field (@select_fields) {
+            my $name = $field-&gt;name;
+            next if !defined $bug-&gt;{$name};
+            $values{$name}-&gt;{$bug-&gt;{$name}} = 1;
+        }
+        foreach my $field (qw(version target_milestone)) {
+            # Fix per-product bug values here, because it's easier than
+            # doing it during _insert_bugs.
+            if (!defined $bug-&gt;{$field} or trim($bug-&gt;{$field}) eq '') {
+                my $accessor = $field;
+                $accessor =~ s/^target_//; $accessor .= &quot;s&quot;;
+                my $product = Bugzilla::Product-&gt;check($bug-&gt;{product});
+                $bug-&gt;{$field} = $product-&gt;$accessor-&gt;[0]-&gt;name;
+                next;
+            }
+            $product_values{$bug-&gt;{product}}-&gt;{$field}-&gt;{$bug-&gt;{$field}} = 1;
+        }
+    }
+    
+    foreach my $field (@select_fields) {
+        next if $field-&gt;is_abnormal;
+        my $name = $field-&gt;name;
+        foreach my $value (keys %{ $values{$name} }) {
+            next if Bugzilla::Field::Choice-&gt;type($field)-&gt;new({ name =&gt; $value });
+            Bugzilla::Field::Choice-&gt;type($field)-&gt;create({ value =&gt; $value });
+            print get_text('migrate_value_created',
+                           { field =&gt; $field, value =&gt; $value }), &quot;\n&quot;;
+        }
+    }
+    
+    foreach my $product (keys %product_values) {
+        my $prod_obj = Bugzilla::Product-&gt;check($product);
+        foreach my $version (keys %{ $product_values{$product}-&gt;{version} }) {
+            next if new Bugzilla::Version({ product =&gt; $prod_obj,
+                                            name    =&gt; $version });
+            my $created = Bugzilla::Version-&gt;create({ product =&gt; $prod_obj,
+                                                      value   =&gt; $version });
+            my $field = $self-&gt;bug_fields-&gt;{version};
+            print get_text('migrate_value_created', { product =&gt; $prod_obj,
+                                                      field   =&gt; $field,
+                                                      value   =&gt; $created-&gt;name }), &quot;\n&quot;;
+        }
+        foreach my $milestone (keys %{ $product_values{$product}-&gt;{target_milestone} }) {
+            next if new Bugzilla::Milestone({ product =&gt; $prod_obj,
+                                              name    =&gt; $milestone });
+            my $created = Bugzilla::Milestone-&gt;create(
+                { product =&gt; $prod_obj, value =&gt; $milestone });
+            my $field = $self-&gt;bug_fields-&gt;{target_milestone};
+            print get_text('migrate_value_created', { product =&gt; $prod_obj,
+                                                      field   =&gt; $field,
+                                                      value   =&gt; $created-&gt;name }), &quot;\n&quot;;
+            
+        }
+    }
+    
+}
+
+sub insert_bugs {
+    my ($self, $bugs) = @_;
+    my $dbh = Bugzilla-&gt;dbh;
+    print get_text('migrate_creating_bugs'), &quot;\n&quot;;
+
+    my $init_statuses = Bugzilla::Status-&gt;can_change_to();
+    my %allowed_statuses = map { lc($_-&gt;name) =&gt; 1 } @$init_statuses;
+    # Bypass the question of whether or not we can file UNCONFIRMED
+    # in any product by simply picking a non-UNCONFIRMED status as our
+    # default for bugs that don't have a status specified.
+    my $default_status = first { $_-&gt;name ne 'UNCONFIRMED' } @$init_statuses;
+    # Use the first resolution that's not blank.
+    my $default_resolution =
+        first { $_-&gt;name ne '' }
+              @{ $self-&gt;bug_fields-&gt;{resolution}-&gt;legal_values };
+
+    # Set the values of any required drop-down fields that aren't set.
+    my @standard_drop_downs = grep { !$_-&gt;custom and $_-&gt;is_select }
+                                   (values %{ $self-&gt;bug_fields });
+    # Make bug_status get set before resolution.
+    @standard_drop_downs = sort { $a-&gt;name cmp $b-&gt;name } @standard_drop_downs;
+    # Cache all statuses for setting the resolution.
+    my %statuses = map { lc($_-&gt;name) =&gt; $_ } Bugzilla::Status-&gt;get_all;
+
+    my $total = scalar @$bugs;
+    my $count = 1;
+    foreach my $bug (@$bugs) {
+        my $comments    = delete $bug-&gt;{comments};
+        my $history     = delete $bug-&gt;{history};
+        my $attachments = delete $bug-&gt;{attachments};
+
+        $self-&gt;debug($bug, 3);
+
+        foreach my $field (@standard_drop_downs) {
+            next if $field-&gt;is_abnormal;
+            my $field_name = $field-&gt;name;
+            if (!defined $bug-&gt;{$field_name}) {
+                # If there's a default value for this, then just let create()
+                # pick it.
+                next if grep($_-&gt;is_default, @{ $field-&gt;legal_values });
+                # Otherwise, pick the first valid value if this is a required
+                # field.
+                if ($field_name eq 'bug_status') {
+                    $bug-&gt;{bug_status} = $default_status;
+                }
+                elsif ($field_name eq 'resolution') {
+                    my $status = $statuses{lc($bug-&gt;{bug_status})};
+                    if (!$status-&gt;is_open) {
+                        $bug-&gt;{resolution} =  $default_resolution;
+                    }
+                }
+                else {
+                    $bug-&gt;{$field_name} = $field-&gt;legal_values-&gt;[0]-&gt;name;
+                }
+            }
+        }
+        
+        my $product = Bugzilla::Product-&gt;check($bug-&gt;{product});
+        
+        # If this isn't a legal starting status, or if the bug has a
+        # resolution, then those will have to be set after creating the bug.
+        # We make them into objects so that we can normalize their names.
+        my ($set_status, $set_resolution);
+        if (defined $bug-&gt;{resolution}) {
+            $set_resolution = Bugzilla::Field::Choice-&gt;type('resolution')
+                              -&gt;new({ name =&gt; delete $bug-&gt;{resolution} });
+        }
+        if (!$allowed_statuses{lc($bug-&gt;{bug_status})}) {
+            $set_status = new Bugzilla::Status({ name =&gt; $bug-&gt;{bug_status} });
+            # Set the starting status to some status that Bugzilla will
+            # accept. We're going to overwrite it immediately afterward.
+            $bug-&gt;{bug_status} = $default_status;
+        }
+        
+        # If we're in dry-run mode, our custom fields haven't been created
+        # yet, so we shouldn't try to set them on creation.
+        if ($self-&gt;dry_run) {
+            foreach my $field (keys %{ $self-&gt;CUSTOM_FIELDS }) {
+                delete $bug-&gt;{$field};
+            }
+        }
+        
+        # File the bug as the reporter.
+        my $super_user = Bugzilla-&gt;user;
+        my $reporter = Bugzilla::User-&gt;check($bug-&gt;{reporter});
+        # Allow the user to file a bug in any product, no matter his current
+        # permissions.
+        $reporter-&gt;{groups} = $super_user-&gt;groups;
+        Bugzilla-&gt;set_user($reporter);
+        my $created = Bugzilla::Bug-&gt;create($bug);
+        $self-&gt;debug('Created bug ' . $created-&gt;id);
+        Bugzilla-&gt;set_user($super_user);
+
+        if (defined $bug-&gt;{creation_ts}) {
+            $dbh-&gt;do('UPDATE bugs SET creation_ts = ?, delta_ts = ? 
+                       WHERE bug_id = ?', undef, $bug-&gt;{creation_ts},
+                     $bug-&gt;{creation_ts}, $created-&gt;id);
+        }
+        if (defined $bug-&gt;{delta_ts}) {
+            $dbh-&gt;do('UPDATE bugs SET delta_ts = ? WHERE bug_id = ?',
+                     undef, $bug-&gt;{delta_ts}, $created-&gt;id);
+        }
+        # We don't need to send email for imported bugs.
+        $dbh-&gt;do('UPDATE bugs SET lastdiffed = delta_ts WHERE bug_id = ?',
+                 undef, $created-&gt;id);
+
+        # We don't use set_ and update() because that would create
+        # a bugs_activity entry that we don't want.
+        if ($set_status) {
+            $dbh-&gt;do('UPDATE bugs SET bug_status = ? WHERE bug_id = ?',
+                     undef, $set_status-&gt;name, $created-&gt;id);
+        }
+        if ($set_resolution) {
+            $dbh-&gt;do('UPDATE bugs SET resolution = ? WHERE bug_id = ?',
+                     undef, $set_resolution-&gt;name, $created-&gt;id);
+        }
+        
+        $self-&gt;_insert_comments($created, $comments);
+        $self-&gt;_insert_history($created, $history);
+        $self-&gt;_insert_attachments($created, $attachments);
+
+        # bugs_fulltext isn't transactional, so if we're in a dry-run we
+        # need to delete anything that we put in there.
+        if ($self-&gt;dry_run) {
+            $dbh-&gt;do('DELETE FROM bugs_fulltext WHERE bug_id = ?',
+                     undef, $created-&gt;id);
+        }
+
+        if (!$self-&gt;verbose) {
+            indicate_progress({ current =&gt; $count++, every =&gt; 5, total =&gt; $total });
+        }
+    }
+}
+
+sub _insert_comments {
+    my ($self, $bug, $comments) = @_;
+    return if !$comments;
+    $self-&gt;debug(' Inserting comments:', 2);
+    foreach my $comment (@$comments) {
+        $self-&gt;debug($comment, 3);
+        my %copy = %$comment;
+        # XXX In the future, if we have a Bugzilla::Comment-&gt;create, this
+        # should use it.
+        my $who = Bugzilla::User-&gt;check(delete $copy{who});
+        $copy{who} = $who-&gt;id;
+        $copy{bug_id} = $bug-&gt;id;
+        $self-&gt;_do_table_insert('longdescs', \%copy);
+        $self-&gt;debug(&quot;  Inserted comment from &quot; . $who-&gt;login, 2);
+    }
+    $bug-&gt;_sync_fulltext();
+}
+
+sub _insert_history {
+    my ($self, $bug, $history) = @_;
+    return if !$history;
+    $self-&gt;debug(' Inserting history:', 2);
+    foreach my $item (@$history) {
+        $self-&gt;debug($item, 3);
+        my $who = Bugzilla::User-&gt;check($item-&gt;{who});
+        LogActivityEntry($bug-&gt;id, $item-&gt;{field}, $item-&gt;{removed},
+                         $item-&gt;{added}, $who-&gt;id, $item-&gt;{bug_when});
+        $self-&gt;debug(&quot;  $item-&gt;{field} change from &quot; . $who-&gt;login, 2);
+    }
+}
+
+sub _insert_attachments {
+    my ($self, $bug, $attachments) = @_;
+    return if !$attachments;
+    $self-&gt;debug(' Inserting attachments:', 2);
+    foreach my $attachment (@$attachments) {
+        $self-&gt;debug($attachment, 3);
+        # Make sure that our pointer is at the beginning of the file,
+        # because usually it will be at the end, having just been fully
+        # written to.
+        if (ref $attachment-&gt;{data}) {
+            $attachment-&gt;{data}-&gt;seek(0, SEEK_SET);
+        }
+
+        my $submitter = Bugzilla::User-&gt;check(delete $attachment-&gt;{submitter});
+        my $super_user = Bugzilla-&gt;user;
+        # Make sure the submitter can attach this attachment no matter what.
+        $submitter-&gt;{groups} = $super_user-&gt;groups;
+        Bugzilla-&gt;set_user($submitter);
+        my $created =
+            Bugzilla::Attachment-&gt;create({ %$attachment, bug =&gt; $bug });
+        $self-&gt;debug('  Attachment ' . $created-&gt;description . ' from '
+                     . $submitter-&gt;login, 2);
+        Bugzilla-&gt;set_user($super_user);
+    }
+}
+
+sub _do_table_insert {
+    my ($self, $table, $hash) = @_;
+    my @fields    = keys %$hash;
+    my @questions = ('?') x @fields;
+    my @values    = map { $hash-&gt;{$_} } @fields;
+    my $field_sql    = join(',', @fields);
+    my $question_sql = join(',', @questions);
+    Bugzilla-&gt;dbh-&gt;do(&quot;INSERT INTO $table ($field_sql) VALUES ($question_sql)&quot;,
+                      undef, @values);
+}
+
+######################
+# Helper Subroutines #
+######################
+
+sub _canonical_name {
+    my ($module) = @_;
+    $module =~ s{::}{/}g;
+    $module = basename($module);
+    $module =~ s/\.pm$//g;
+    return $module;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::Migrate - Functions to migrate from other databases
+
+=head1 DESCRIPTION
+
+This module acts as a base class for the various modules that migrate
+from other bug-trackers.
+
+The documentation for this module exists mostly to assist people in
+creating new migrators for other bug-trackers than the ones currently
+supported.
+
+=head1 HOW MIGRATION WORKS
+
+Before writing anything to the Bugzilla database, the migrator will read
+everything from the other bug-tracker's database. Here's the exact order
+of what happens:
+
+=over
+
+=item 1
+
+Users are read from the other bug-tracker.
+
+=item 2
+
+Products are read from the other bug-tracker.
+
+=item 3
+
+Bugs are read from the other bug-tracker.
+
+=item 4
+
+The L&lt;/after_read&gt; method is called.
+
+=item 5
+
+All bugs are translated from the other bug-tracker's fields/values
+into Bugzilla's fields values using L&lt;/translate_bug&gt;.
+
+=item 6
+
+Users are inserted into Bugzilla.
+
+=item 7
+
+Products are inserted into Bugzilla.
+
+=item 8
+
+Some migrators need to create custom fields before migrating, and
+so that happens here.
+
+=item 9
+
+Any legal values that need to be created for any drop-down or
+multi-select fields are created. This is done by reading all the
+values on every bug that was read in and creating any values that
+don't already exist in Bugzilla for every drop-down or multi-select
+field on each bug. This includes creating any product versions and
+milestones that need to be created.
+
+=item 10
+
+Bugs are inserted into Bugzilla.
+
+=item 11
+
+The L&lt;/after_insert&gt; method is called.
+
+=back
+
+Everything happens in one big transaction, so in general, if there are
+any errors during the process, nothing will be changed.
+
+The migrator never creates anything that already exists. So users, products,
+components, etc. that already exist will just be re-used by this script,
+not re-created.
+
+=head1 CONSTRUCTOR
+
+=head2 load
+
+Called like C&lt;&lt; Bugzilla::Migrate-&gt;load('Module') &gt;&gt;. Returns a new
+C&lt;Bugzilla::Migrate&gt; object that can be used to migrate from the
+requested bug-tracker.
+
+=head1 METHODS YOUR SUBCLASS CAN USE
+
+=head2 config
+
+Takes a single parameter, a string, and returns the value of the
+configuration variable with that name (always a scalar). The first time
+you call C&lt;config&gt;, if the configuration file hasn't been read, it will
+be read in.
+
+=head2 debug
+
+If the user hasn't specified C&lt;--verbose&gt; on the command line, this
+does nothing.
+
+Takes two arguments:
+
+The first argument is a string or reference to print to C&lt;STDERR&gt;.
+If it's a reference, L&lt;Data::Dumper&gt; will be used to print the
+data structure.
+
+The second argument is a number--the string will only be printed if the
+user specified C&lt;--verbose&gt; at least that many times on the command line.
+
+=head2 parse_date
+
+(Note: Usually you don't need to call this, because L&lt;/translate_bug&gt;
+handles date translations for you, for bug data.)
+
+Parses a date string and returns a formatted date string that can be inserted
+into the database. If the input date is missing a timezone, the &quot;timezone&quot;
+configuration parameter will be used as the timezone of the date.
+
+=head2 translate_bug
+
+(Note: Normally you don't have to call this yourself, as 
+C&lt;Bugzilla::Migrate&gt; does it for you.)
+
+Uses the C&lt;$translate_fields&gt; and C&lt;$translate_values&gt; configuration variables
+to convert a hashref of &quot;other bug-tracker&quot; fields into Bugzilla fields.
+It takes one argument, the hashref to convert. Any unrecognized fields will
+have their value prepended to the C&lt;comment&gt; element in the returned
+hashref, unless they are listed in L&lt;/NON_COMMENT_FIELDS&gt;.
+
+In scalar context, returns the translated bug. In array context,
+returns both the translated bug and a second hashref containing the values
+of any untranslated fields that were listed in C&lt;NON_COMMENT_FIELDS&gt;.
+
+B&lt;Note:&gt; To save memory, the hashref that you pass in will be destroyed
+(all keys will be deleted).
+
+=head2 translate_value
+
+(Note: Generally you only need to use this during L&lt;/_read_products&gt;
+and L&lt;/_read_users&gt; if necessary, because the data returned from
+L&lt;/_read_bugs&gt; will be put through L&lt;/translate_bug&gt;.)
+
+Uses the C&lt;$translate_values&gt; configuration variable to convert
+field values from your bug-tracker to Bugzilla. Takes two arguments,
+the first being a field name and the second being a value. If the value
+is an arrayref, C&lt;translate_value&gt; will be called recursively on all
+the array elements.
+
+Also, any date field will be converted into ISO 8601 format, for
+inserting into the database.
+
+=head2 translate_field
+
+(Note: Normally you don't need to use this, because L&lt;/translate_bug&gt; 
+handles it for you.)
+
+Translates a field name in your bug-tracker to a field name in Bugzilla,
+using the rules described in the description of the C&lt;$translate_fields&gt;
+configuration variable.
+
+Takes a single argument--the name of a field to translate.
+
+Returns C&lt;undef&gt; if the field could not be translated.
+
+=head1 METHODS YOU MUST IMPLEMENT
+
+These are methods that subclasses must implement:
+
+=head2 _read_bugs
+
+Should return an arrayref of hashes. The hashes will be passed to
+L&lt;Bugzilla::Bug/create&gt; to create bugs in Bugzilla. In addition to
+the normal C&lt;create&gt; fields, the hashes can contain three additional
+items:
+
+=over
+
+=item comments
+
+An arrayref of hashes, representing comments to be added to the
+database. The keys should be the names of columns in the longdescs
+table that you want to set for each comment. C&lt;who&gt; must be a
+username instead of a user id, though.
+
+You don't need to specify a value for the C&lt;bug_id&gt; column.
+
+=item history
+
+An arrayref of hashes, representing the history of changes made
+to this bug. The keys should be the names of columns in the
+bugs_activity table to set for each change. C&lt;who&gt; must be a username
+instead of a user id, though, and C&lt;field&gt; (containing the name of some field)
+is taken instead of C&lt;fieldid&gt;.
+
+You don't need to specify a value for the C&lt;bug_id&gt; column.
+
+=item attachments
+
+An arrayref of hashes, representing values to pass to
+L&lt;Bugzilla::Attachment/create&gt;. (Remember that the C&lt;data&gt; argument
+must be a file handle--we recommend using L&lt;IO::File/new_tmpfile&gt; to create
+anonymous temporary files for this purpose.) You should specify a
+C&lt;submitter&gt; argument containing the username of the attachment's submitter.
+
+You don't need to specify a value for the the C&lt;bug&gt; argument.
+
+=back
+
+=head2 _read_products
+
+Should return an arrayref of hashes to pass to L&lt;Bugzilla::Product/create&gt;.
+In addition to the normal C&lt;create&gt; fields, this also accepts an additional
+argument, C&lt;components&gt;, which is an arrayref of hashes to pass to
+L&lt;Bugzilla::Component/create&gt; (though you do not need to specify the
+C&lt;product&gt; argument for L&lt;Bugzilla::Component/create&gt;).
+
+=head2 _read_users
+
+Should return an arrayref of hashes to be passed to
+L&lt;Bugzilla::User/create&gt;.
+
+=head1 METHODS YOU MIGHT WANT TO IMPLEMENT
+
+These are methods that you may want to override in your migrator.
+All of these methods are called on an instantiated L&lt;Bugzilla::Migrate&gt;
+object of your subclass by L&lt;Bugzilla::Migrate&gt; itself.
+
+=head2 REQUIRED_MODULES
+
+Returns an arrayref of Perl modules that must be installed in order
+for your migrator to run, in the same format as 
+L&lt;Bugzilla::Install::Requirements/REQUIRED_MODULES&gt;.
+
+=head2 CUSTOM_FIELDS
+
+Returns a hashref, where the keys are the names of custom fields
+to create in the database before inserting bugs. The values of the
+hashref are the arguments (other than &quot;name&quot;) that should be passed
+to Bugzilla::Field-&gt;create() when creating the field. (C&lt;&lt; custom =&gt; 1 &gt;&gt;
+will be specified automatically for you, so you don't need to specify it.)
+
+=head2 CONFIG_VARS
+
+This should return an array (not an arrayref) in the same format as
+L&lt;Bugzilla::Install::Localconfig/LOCALCONFIG_VARS&gt;, describing
+configuration variables for migrating from your bug-tracker. You should
+always include the default C&lt;CONFIG_VARS&gt; (by calling
+$self-&gt;SUPER::CONFIG_VARS) as part of your return value, if you
+override this method.
+
+=head2 NON_COMMENT_FIELDS
+
+An array (not an arrayref). If there are fields that are not translated
+and yet shouldn't be added to the initial description of the bug when
+translating bugs, then they should be listed here. See L&lt;/translate_bug&gt; for
+more detail.
+
+=head2 after_read
+
+This is run after all data is read from the other bug-tracker, but
+before the bug fields/values have been translated, and before any data
+is inserted into Bugzilla. The default implementation does nothing.
+
+=head2 before_insert
+
+This is called after all bugs are translated from their &quot;other bug-tracker&quot;
+values to Bugzilla values, but before any data is inserted into the database
+or any custom fields are created. The default implementation does nothing.
+
+=head2 after_insert
+
+This is run after all data is inserted into Bugzilla. The default
+implementation does nothing.
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaMilestonepm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Milestone.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Milestone.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Milestone.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -26,6 +26,8 @@
</span><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> use Bugzilla::Error;
</span><span class="cx"> 
</span><ins>+use Scalar::Util qw(blessed);
+
</ins><span class="cx"> ################################
</span><span class="cx"> #####    Initialization    #####
</span><span class="cx"> ################################
</span><span class="lines">@@ -41,25 +43,28 @@
</span><span class="cx">     value
</span><span class="cx">     product_id
</span><span class="cx">     sortkey
</span><ins>+    isactive
</ins><span class="cx"> );
</span><span class="cx"> 
</span><del>-use constant REQUIRED_CREATE_FIELDS =&gt; qw(
-    name
-    product
-);
</del><ins>+use constant REQUIRED_FIELD_MAP =&gt; {
+    product_id =&gt; 'product',
+};
</ins><span class="cx"> 
</span><span class="cx"> use constant UPDATE_COLUMNS =&gt; qw(
</span><span class="cx">     value
</span><span class="cx">     sortkey
</span><ins>+    isactive
</ins><span class="cx"> );
</span><span class="cx"> 
</span><span class="cx"> use constant VALIDATORS =&gt; {
</span><del>-    product =&gt; \&amp;_check_product,
-    sortkey =&gt; \&amp;_check_sortkey,
</del><ins>+    product  =&gt; \&amp;_check_product,
+    sortkey  =&gt; \&amp;_check_sortkey,
+    value    =&gt; \&amp;_check_value,
+    isactive =&gt; \&amp;Bugzilla::Object::check_boolean,
</ins><span class="cx"> };
</span><span class="cx"> 
</span><del>-use constant UPDATE_VALIDATORS =&gt; {
-    value =&gt; \&amp;_check_value,
</del><ins>+use constant VALIDATOR_DEPENDENCIES =&gt; {
+    value =&gt; ['product'],
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> ################################
</span><span class="lines">@@ -94,14 +99,10 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub run_create_validators {
</span><del>-    my $class  = shift;
</del><ins>+    my $class = shift;
</ins><span class="cx">     my $params = $class-&gt;SUPER::run_create_validators(@_);
</span><del>-
</del><span class="cx">     my $product = delete $params-&gt;{product};
</span><span class="cx">     $params-&gt;{product_id} = $product-&gt;id;
</span><del>-    $params-&gt;{value} = $class-&gt;_check_value($params-&gt;{name}, $product);
-    delete $params-&gt;{name};
-
</del><span class="cx">     return $params;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -165,7 +166,8 @@
</span><span class="cx"> ################################
</span><span class="cx"> 
</span><span class="cx"> sub _check_value {
</span><del>-    my ($invocant, $name, $product) = @_;
</del><ins>+    my ($invocant, $name, undef, $params) = @_;
+    my $product = blessed($invocant) ? $invocant-&gt;product : $params-&gt;{product};
</ins><span class="cx"> 
</span><span class="cx">     $name = trim($name);
</span><span class="cx">     $name || ThrowUserError('milestone_blank_name');
</span><span class="lines">@@ -173,7 +175,6 @@
</span><span class="cx">         ThrowUserError('milestone_name_too_long', {name =&gt; $name});
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    $product = $invocant-&gt;product if (ref $invocant);
</del><span class="cx">     my $milestone = new Bugzilla::Milestone({product =&gt; $product, name =&gt; $name});
</span><span class="cx">     if ($milestone &amp;&amp; (!ref $invocant || $milestone-&gt;id != $invocant-&gt;id)) {
</span><span class="cx">         ThrowUserError('milestone_already_exists', { name    =&gt; $milestone-&gt;name,
</span><span class="lines">@@ -196,6 +197,8 @@
</span><span class="cx"> 
</span><span class="cx"> sub _check_product {
</span><span class="cx">     my ($invocant, $product) = @_;
</span><ins>+    $product || ThrowCodeError('param_required',
+                    { function =&gt; &quot;$invocant-&gt;create&quot;, param =&gt; &quot;product&quot; });
</ins><span class="cx">     return Bugzilla-&gt;user-&gt;check_can_admin_product($product-&gt;name);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -203,8 +206,9 @@
</span><span class="cx"> # Methods
</span><span class="cx"> ################################
</span><span class="cx"> 
</span><del>-sub set_name { $_[0]-&gt;set('value', $_[1]); }
-sub set_sortkey { $_[0]-&gt;set('sortkey', $_[1]); }
</del><ins>+sub set_name      { $_[0]-&gt;set('value', $_[1]);    }
+sub set_sortkey   { $_[0]-&gt;set('sortkey', $_[1]);  }
+sub set_is_active { $_[0]-&gt;set('isactive', $_[1]); }
</ins><span class="cx"> 
</span><span class="cx"> sub bug_count {
</span><span class="cx">     my $self = shift;
</span><span class="lines">@@ -226,6 +230,7 @@
</span><span class="cx"> sub name       { return $_[0]-&gt;{'value'};      }
</span><span class="cx"> sub product_id { return $_[0]-&gt;{'product_id'}; }
</span><span class="cx"> sub sortkey    { return $_[0]-&gt;{'sortkey'};    }
</span><ins>+sub is_active  { return $_[0]-&gt;{'isactive'};   }
</ins><span class="cx"> 
</span><span class="cx"> sub product {
</span><span class="cx">     my $self = shift;
</span><span class="lines">@@ -255,7 +260,7 @@
</span><span class="cx">     my $sortkey    = $milestone-&gt;sortkey;
</span><span class="cx"> 
</span><span class="cx">     my $milestone = Bugzilla::Milestone-&gt;create(
</span><del>-        { name =&gt; $name, product =&gt; $product, sortkey =&gt; $sortkey });
</del><ins>+        { value =&gt; $name, product =&gt; $product, sortkey =&gt; $sortkey });
</ins><span class="cx"> 
</span><span class="cx">     $milestone-&gt;set_name($new_name);
</span><span class="cx">     $milestone-&gt;set_sortkey($new_sortkey);
</span><span class="lines">@@ -361,11 +366,11 @@
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><del>-=item C&lt;create({name =&gt; $name, product =&gt; $product, sortkey =&gt; $sortkey})&gt;
</del><ins>+=item C&lt;create({value =&gt; $value, product =&gt; $product, sortkey =&gt; $sortkey})&gt;
</ins><span class="cx"> 
</span><span class="cx">  Description: Create a new milestone for the given product.
</span><span class="cx"> 
</span><del>- Params:      $name    - name of the new milestone (string). This name
</del><ins>+ Params:      $value   - name of the new milestone (string). This name
</ins><span class="cx">                          must be unique within the product.
</span><span class="cx">               $product - a Bugzilla::Product object.
</span><span class="cx">               $sortkey - the sortkey of the new milestone (signed integer)
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaObjectpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Object.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Object.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Object.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -24,10 +24,13 @@
</span><span class="cx"> package Bugzilla::Object;
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla::Constants;
</span><ins>+use Bugzilla::Hook;
</ins><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> use Bugzilla::Error;
</span><span class="cx"> 
</span><span class="cx"> use Date::Parse;
</span><ins>+use List::MoreUtils qw(part);
+use Scalar::Util qw(blessed);
</ins><span class="cx"> 
</span><span class="cx"> use constant NAME_FIELD =&gt; 'name';
</span><span class="cx"> use constant ID_FIELD   =&gt; 'id';
</span><span class="lines">@@ -36,7 +39,19 @@
</span><span class="cx"> use constant UPDATE_VALIDATORS =&gt; {};
</span><span class="cx"> use constant NUMERIC_COLUMNS   =&gt; ();
</span><span class="cx"> use constant DATE_COLUMNS      =&gt; ();
</span><ins>+use constant VALIDATOR_DEPENDENCIES =&gt; {};
+# XXX At some point, this will be joined with FIELD_MAP.
+use constant REQUIRED_FIELD_MAP  =&gt; {};
+use constant EXTRA_REQUIRED_FIELDS =&gt; ();
+use constant AUDIT_CREATES =&gt; 1;
+use constant AUDIT_UPDATES =&gt; 1;
+use constant AUDIT_REMOVES =&gt; 1;
</ins><span class="cx"> 
</span><ins>+# This allows the JSON-RPC interface to return Bugzilla::Object instances
+# as though they were hashes. In the future, this may be modified to return
+# less information.
+sub TO_JSON { return { %{ $_[0] } }; }
+
</ins><span class="cx"> ###############################
</span><span class="cx"> ####    Initialization     ####
</span><span class="cx"> ###############################
</span><span class="lines">@@ -58,12 +73,15 @@
</span><span class="cx">     my $class = shift;
</span><span class="cx">     my ($param) = @_;
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><del>-    my $columns = join(',', $class-&gt;DB_COLUMNS);
</del><ins>+    my $columns = join(',', $class-&gt;_get_db_columns);
</ins><span class="cx">     my $table   = $class-&gt;DB_TABLE;
</span><span class="cx">     my $name_field = $class-&gt;NAME_FIELD;
</span><span class="cx">     my $id_field   = $class-&gt;ID_FIELD;
</span><span class="cx"> 
</span><del>-    my $id = $param unless (ref $param eq 'HASH');
</del><ins>+    my $id = $param;
+    if (ref $param eq 'HASH') {
+        $id = $param-&gt;{id};
+    }
</ins><span class="cx">     my $object;
</span><span class="cx"> 
</span><span class="cx">     if (defined $id) {
</span><span class="lines">@@ -73,6 +91,9 @@
</span><span class="cx">           || ThrowCodeError('param_must_be_numeric',
</span><span class="cx">                             {function =&gt; $class . '::_init'});
</span><span class="cx"> 
</span><ins>+        # Too large integers make PostgreSQL crash.
+        return if $id &gt; MAX_INT_32;
+
</ins><span class="cx">         $object = $dbh-&gt;selectrow_hashref(qq{
</span><span class="cx">             SELECT $columns FROM $table
</span><span class="cx">              WHERE $id_field = ?}, undef, $id);
</span><span class="lines">@@ -114,14 +135,29 @@
</span><span class="cx">     if (!ref $param) {
</span><span class="cx">         $param = { name =&gt; $param };
</span><span class="cx">     }
</span><del>-    # Don't allow empty names.
-    if (exists $param-&gt;{name}) {
-        $param-&gt;{name} = trim($param-&gt;{name});
-        $param-&gt;{name} || ThrowUserError('object_name_not_specified',
-                                          { class =&gt; $class });
</del><ins>+
+    # Don't allow empty names or ids.
+    my $check_param = exists $param-&gt;{id} ? 'id' : 'name';
+    $param-&gt;{$check_param} = trim($param-&gt;{$check_param});
+    # If somebody passes us &quot;0&quot;, we want to throw an error like
+    # &quot;there is no X with the name 0&quot;. This is true even for ids. So here,
+    # we only check if the parameter is undefined or empty.
+    if (!defined $param-&gt;{$check_param} or $param-&gt;{$check_param} eq '') {
+        ThrowUserError('object_not_specified', { class =&gt; $class });
</ins><span class="cx">     }
</span><del>-    my $obj = $class-&gt;new($param)
-        || ThrowUserError('object_does_not_exist', {%$param, class =&gt; $class});
</del><ins>+
+    my $obj = $class-&gt;new($param);
+    if (!$obj) {
+        # We don't want to override the normal template &quot;user&quot; object if
+        # &quot;user&quot; is one of the params.
+        delete $param-&gt;{user};
+        if (my $error = delete $param-&gt;{_error}) {
+            ThrowUserError($error, { %$param, class =&gt; $class });
+        }
+        else {
+            ThrowUserError('object_does_not_exist', { %$param, class =&gt; $class });
+        }
+    }
</ins><span class="cx">     return $obj;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -136,6 +172,8 @@
</span><span class="cx">         detaint_natural($id) ||
</span><span class="cx">             ThrowCodeError('param_must_be_numeric',
</span><span class="cx">                           {function =&gt; $class . '::new_from_list'});
</span><ins>+        # Too large integers make PostgreSQL crash.
+        next if $id &gt; MAX_INT_32;
</ins><span class="cx">         push(@detainted_ids, $id);
</span><span class="cx">     }
</span><span class="cx">     # We don't do $invocant-&gt;match because some classes have
</span><span class="lines">@@ -155,10 +193,44 @@
</span><span class="cx"> 
</span><span class="cx">     return [$class-&gt;get_all] if !$criteria;
</span><span class="cx"> 
</span><del>-    my (@terms, @values);
</del><ins>+    my (@terms, @values, $postamble);
</ins><span class="cx">     foreach my $field (keys %$criteria) {
</span><ins>+        my $value = $criteria-&gt;{$field};
+        
+        # allow for LIMIT and OFFSET expressions via the criteria.
+        next if $field eq 'OFFSET';
+        if ( $field eq 'LIMIT' ) {
+            next unless defined $value;
+            detaint_natural($value)
+              or ThrowCodeError('param_must_be_numeric', 
+                                { param    =&gt; 'LIMIT', 
+                                  function =&gt; &quot;${class}::match&quot; });
+            my $offset;
+            if (defined $criteria-&gt;{OFFSET}) {
+                $offset = $criteria-&gt;{OFFSET};
+                detaint_signed($offset)
+                  or ThrowCodeError('param_must_be_numeric', 
+                                    { param    =&gt; 'OFFSET',
+                                      function =&gt; &quot;${class}::match&quot; });
+            }
+            $postamble = $dbh-&gt;sql_limit($value, $offset);
+            next;
+        }
+        elsif ( $field eq 'WHERE' ) {
+            # the WHERE value is a hashref where the keys are
+            # &quot;column_name operator ?&quot; and values are the placeholder's
+            # value (either a scalar or an array of values).
+            foreach my $k (keys %$value) {
+                push(@terms, $k);
+                my @this_value = ref($value-&gt;{$k}) ? @{ $value-&gt;{$k} } 
+                                                   : ($value-&gt;{$k});
+                push(@values, @this_value);
+            }            
+            next;
+        }
+        
</ins><span class="cx">         $class-&gt;_check_field($field, 'match');
</span><del>-        my $value = $criteria-&gt;{$field};
</del><ins>+
</ins><span class="cx">         if (ref $value eq 'ARRAY') {
</span><span class="cx">             # IN () is invalid SQL, and if we have an empty list
</span><span class="cx">             # to match against, we're just returning an empty
</span><span class="lines">@@ -181,14 +253,14 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    my $where = join(' AND ', @terms);
-    return $class-&gt;_do_list_select($where, \@values);
</del><ins>+    my $where = join(' AND ', @terms) if scalar @terms;
+    return $class-&gt;_do_list_select($where, \@values, $postamble);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _do_list_select {
</span><del>-    my ($class, $where, $values) = @_;
</del><ins>+    my ($class, $where, $values, $postamble) = @_;
</ins><span class="cx">     my $table = $class-&gt;DB_TABLE;
</span><del>-    my $cols  = join(',', $class-&gt;DB_COLUMNS);
</del><ins>+    my $cols  = join(',', $class-&gt;_get_db_columns);
</ins><span class="cx">     my $order = $class-&gt;LIST_ORDER;
</span><span class="cx"> 
</span><span class="cx">     my $sql = &quot;SELECT $cols FROM $table&quot;;
</span><span class="lines">@@ -196,9 +268,16 @@
</span><span class="cx">         $sql .= &quot; WHERE $where &quot;;
</span><span class="cx">     }
</span><span class="cx">     $sql .= &quot; ORDER BY $order&quot;;
</span><del>-
</del><ins>+    
+    $sql .= &quot; $postamble&quot; if $postamble;
+        
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><del>-    my $objects = $dbh-&gt;selectall_arrayref($sql, {Slice=&gt;{}}, @$values);
</del><ins>+    # Sometimes the values are tainted, but we don't want to untaint them
+    # for the caller. So we copy the array. It's safe to untaint because
+    # they're only used in placeholders here.
+    my @untainted = @{ $values || [] };
+    trick_taint($_) foreach @untainted;
+    my $objects = $dbh-&gt;selectall_arrayref($sql, {Slice=&gt;{}}, @untainted);
</ins><span class="cx">     bless ($_, $class) foreach @$objects;
</span><span class="cx">     return $objects
</span><span class="cx"> }
</span><span class="lines">@@ -218,13 +297,18 @@
</span><span class="cx">     my ($self, $field, $value) = @_;
</span><span class="cx"> 
</span><span class="cx">     # This method is protected. It's used to help implement set_ functions.
</span><del>-    caller-&gt;isa('Bugzilla::Object')
</del><ins>+    my $caller = caller;
+    $caller-&gt;isa('Bugzilla::Object') || $caller-&gt;isa('Bugzilla::Extension')
</ins><span class="cx">         || ThrowCodeError('protection_violation', 
</span><span class="cx">                           { caller     =&gt; caller,
</span><span class="cx">                             superclass =&gt; __PACKAGE__,
</span><span class="cx">                             function   =&gt; 'Bugzilla::Object-&gt;set' });
</span><span class="cx"> 
</span><del>-    my %validators = (%{$self-&gt;VALIDATORS}, %{$self-&gt;UPDATE_VALIDATORS});
</del><ins>+    Bugzilla::Hook::process('object_before_set',
+                            { object =&gt; $self, field =&gt; $field,
+                              value =&gt; $value });
+
+    my %validators = (%{$self-&gt;_get_validators}, %{$self-&gt;UPDATE_VALIDATORS});
</ins><span class="cx">     if (exists $validators{$field}) {
</span><span class="cx">         my $validator = $validators{$field};
</span><span class="cx">         $value = $self-&gt;$validator($value, $field);
</span><span class="lines">@@ -236,8 +320,30 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     $self-&gt;{$field} = $value;
</span><ins>+
+    Bugzilla::Hook::process('object_end_of_set',
+                            { object =&gt; $self, field =&gt; $field });
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub set_all {
+    my ($self, $params) = @_;
+
+    # Don't let setters modify the values in $params for the caller.
+    my %field_values = %$params;
+
+    my @sorted_names = $self-&gt;_sort_by_dep(keys %field_values);
+    foreach my $key (@sorted_names) {
+        # It's possible for one set_ method to delete a key from $params
+        # for another set method, so if that's happened, we don't call the
+        # other set method.
+        next if !exists $field_values{$key};
+        my $method = &quot;set_$key&quot;;
+        $self-&gt;$method($field_values{$key}, \%field_values);
+    }
+    Bugzilla::Hook::process('object_end_of_set_all', 
+                            { object =&gt; $self, params =&gt; \%field_values });
+}
+
</ins><span class="cx"> sub update {
</span><span class="cx">     my $self = shift;
</span><span class="cx"> 
</span><span class="lines">@@ -248,11 +354,17 @@
</span><span class="cx">     $dbh-&gt;bz_start_transaction();
</span><span class="cx"> 
</span><span class="cx">     my $old_self = $self-&gt;new($self-&gt;id);
</span><del>-    
</del><ins>+   
+    my @all_columns = $self-&gt;UPDATE_COLUMNS;
+    my @hook_columns;
+    Bugzilla::Hook::process('object_update_columns',
+                            { object =&gt; $self, columns =&gt; \@hook_columns });
+    push(@all_columns, @hook_columns);
+
</ins><span class="cx">     my %numeric = map { $_ =&gt; 1 } $self-&gt;NUMERIC_COLUMNS;
</span><span class="cx">     my %date    = map { $_ =&gt; 1 } $self-&gt;DATE_COLUMNS;
</span><span class="cx">     my (@update_columns, @values, %changes);
</span><del>-    foreach my $column ($self-&gt;UPDATE_COLUMNS) {
</del><ins>+    foreach my $column (@all_columns) {
</ins><span class="cx">         my ($old, $new) = ($old_self-&gt;{$column}, $self-&gt;{$column});
</span><span class="cx">         # This has to be written this way in order to allow us to set a field
</span><span class="cx">         # from undef or to undef, and avoid warnings about comparing an undef
</span><span class="lines">@@ -279,15 +391,78 @@
</span><span class="cx">     $dbh-&gt;do(&quot;UPDATE $table SET $columns WHERE $id_field = ?&quot;, undef, 
</span><span class="cx">              @values, $self-&gt;id) if @values;
</span><span class="cx"> 
</span><ins>+    Bugzilla::Hook::process('object_end_of_update',
+                            { object =&gt; $self, old_object =&gt; $old_self,
+                              changes =&gt; \%changes });
+
+    $self-&gt;audit_log(\%changes) if $self-&gt;AUDIT_UPDATES;
+
</ins><span class="cx">     $dbh-&gt;bz_commit_transaction();
</span><span class="cx"> 
</span><ins>+    if (wantarray) {
+        return (\%changes, $old_self);
+    }
+
</ins><span class="cx">     return \%changes;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub remove_from_db {
+    my $self = shift;
+    Bugzilla::Hook::process('object_before_delete', { object =&gt; $self });
+    my $table = $self-&gt;DB_TABLE;
+    my $id_field = $self-&gt;ID_FIELD;
+    my $dbh = Bugzilla-&gt;dbh;
+    $dbh-&gt;bz_start_transaction();
+    $self-&gt;audit_log(AUDIT_REMOVE) if $self-&gt;AUDIT_REMOVES;
+    $dbh-&gt;do(&quot;DELETE FROM $table WHERE $id_field = ?&quot;, undef, $self-&gt;id);
+    $dbh-&gt;bz_commit_transaction();
+    undef $self;
+}
+
+sub audit_log {
+    my ($self, $changes) = @_;
+    my $class = ref $self;
+    my $dbh = Bugzilla-&gt;dbh;
+    my $user_id = Bugzilla-&gt;user-&gt;id || undef;
+    my $sth = $dbh-&gt;prepare(
+        'INSERT INTO audit_log (user_id, class, object_id, field,
+                                removed, added, at_time) 
+              VALUES (?,?,?,?,?,?,LOCALTIMESTAMP(0))');
+    # During creation or removal, $changes is actually just a string
+    # indicating whether we're creating or removing the object.
+    if ($changes eq AUDIT_CREATE or $changes eq AUDIT_REMOVE) {
+        # We put the object's name in the &quot;added&quot; or &quot;removed&quot; field.
+        # We do this thing with NAME_FIELD because $self-&gt;name returns
+        # the wrong thing for Bugzilla::User.
+        my $name = $self-&gt;{$self-&gt;NAME_FIELD};
+        my @added_removed = $changes eq AUDIT_CREATE ? (undef, $name) 
+                                                     : ($name, undef);
+        $sth-&gt;execute($user_id, $class, $self-&gt;id, $changes, @added_removed);
+        return;
+    }
+
+    # During update, it's the actual %changes hash produced by update().
+    foreach my $field (keys %$changes) {
+        # Skip private changes.
+        next if $field =~ /^_/;
+        my ($from, $to) = @{ $changes-&gt;{$field} };
+        $sth-&gt;execute($user_id, $class, $self-&gt;id, $field, $from, $to);
+    }
+}
+
</ins><span class="cx"> ###############################
</span><span class="cx"> ####      Subroutines    ######
</span><span class="cx"> ###############################
</span><span class="cx"> 
</span><ins>+sub any_exist {
+    my $class = shift;
+    my $table = $class-&gt;DB_TABLE;
+    my $dbh = Bugzilla-&gt;dbh;
+    my $any_exist = $dbh-&gt;selectrow_array(
+        &quot;SELECT 1 FROM $table &quot; . $dbh-&gt;sql_limit(1));
+    return $any_exist ? 1 : 0;
+}
+
</ins><span class="cx"> sub create {
</span><span class="cx">     my ($class, $params) = @_;
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="lines">@@ -315,36 +490,52 @@
</span><span class="cx"> sub check_required_create_fields {
</span><span class="cx">     my ($class, $params) = @_;
</span><span class="cx"> 
</span><del>-    foreach my $field ($class-&gt;REQUIRED_CREATE_FIELDS) {
-        ThrowCodeError('param_required',
-            { function =&gt; &quot;${class}-&gt;create&quot;, param =&gt; $field })
-            if !exists $params-&gt;{$field};
</del><ins>+    # This hook happens here so that even subclasses that don't call
+    # SUPER::create are still affected by the hook.
+    Bugzilla::Hook::process('object_before_create', { class =&gt; $class,
+                                                      params =&gt; $params });
+
+    my @check_fields = $class-&gt;_required_create_fields();
+    foreach my $field (@check_fields) {
+        $params-&gt;{$field} = undef if !exists $params-&gt;{$field};
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub run_create_validators {
</span><del>-    my ($class, $params) = @_;
</del><ins>+    my ($class, $params, $options) = @_;
</ins><span class="cx"> 
</span><del>-    my $validators = $class-&gt;VALIDATORS;
</del><ins>+    my $validators = $class-&gt;_get_validators;
+    my %field_values = %$params;
</ins><span class="cx"> 
</span><del>-    my %field_values;
-    # We do the sort just to make sure that validation always
-    # happens in a consistent order.
-    foreach my $field (sort keys %$params) {
</del><ins>+    # Make a hash skiplist for easier searching later
+    my %skip_list = map { $_ =&gt; 1 } @{ $options-&gt;{skip} || [] };
+
+    # Get the sorted field names
+    my @sorted_names = $class-&gt;_sort_by_dep(keys %field_values);
+
+    # Remove the skipped names
+    my @unskipped = grep { !$skip_list{$_} } @sorted_names;
+
+    foreach my $field (@unskipped) {
</ins><span class="cx">         my $value;
</span><span class="cx">         if (exists $validators-&gt;{$field}) {
</span><span class="cx">             my $validator = $validators-&gt;{$field};
</span><del>-            $value = $class-&gt;$validator($params-&gt;{$field}, $field);
</del><ins>+            $value = $class-&gt;$validator($field_values{$field}, $field,
+                                        \%field_values);
</ins><span class="cx">         }
</span><span class="cx">         else {
</span><del>-            $value = $params-&gt;{$field};
</del><ins>+            $value = $field_values{$field};
</ins><span class="cx">         }
</span><ins>+
</ins><span class="cx">         # We want people to be able to explicitly set fields to NULL,
</span><span class="cx">         # and that means they can be set to undef.
</span><span class="cx">         trick_taint($value) if defined $value &amp;&amp; !ref($value);
</span><span class="cx">         $field_values{$field} = $value;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    Bugzilla::Hook::process('object_end_of_create_validators',
+                            { class =&gt; $class, params =&gt; \%field_values });
+
</ins><span class="cx">     return \%field_values;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -365,7 +556,14 @@
</span><span class="cx">     $dbh-&gt;do(&quot;INSERT INTO $table (&quot; . join(', ', @field_names)
</span><span class="cx">              . &quot;) VALUES ($qmarks)&quot;, undef, @values);
</span><span class="cx">     my $id = $dbh-&gt;bz_last_key($table, $class-&gt;ID_FIELD);
</span><del>-    return $class-&gt;new($id);
</del><ins>+
+    my $object = $class-&gt;new($id);
+
+    Bugzilla::Hook::process('object_end_of_create', { class =&gt; $class,
+                                                      object =&gt; $object });
+    $object-&gt;audit_log(AUDIT_CREATE) if $object-&gt;AUDIT_CREATES;
+
+    return $object;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub get_all {
</span><span class="lines">@@ -379,6 +577,173 @@
</span><span class="cx"> 
</span><span class="cx"> sub check_boolean { return $_[1] ? 1 : 0 }
</span><span class="cx"> 
</span><ins>+sub check_time {
+    my ($invocant, $value, $field, $params, $allow_negative) = @_;
+
+    # If we don't have a current value default to zero
+    my $current = blessed($invocant) ? $invocant-&gt;{$field}
+                                     : 0;
+    $current ||= 0;
+
+    # Get the new value or zero if it isn't defined
+    $value = trim($value) || 0;
+
+    # Make sure the new value is well formed
+    _validate_time($value, $field, $allow_negative);
+
+    return $value;
+}
+
+
+###################
+# General Helpers #
+###################
+
+sub _validate_time {
+    my ($time, $field, $allow_negative) = @_;
+
+    # regexp verifies one or more digits, optionally followed by a period and
+    # zero or more digits, OR we have a period followed by one or more digits
+    # (allow negatives, though, so people can back out errors in time reporting)
+    if ($time !~ /^-?(?:\d+(?:\.\d*)?|\.\d+)$/) {
+        ThrowUserError(&quot;number_not_numeric&quot;,
+                       {field =&gt; $field, num =&gt; &quot;$time&quot;});
+    }
+
+    # Callers can optionally allow negative times
+    if ( ($time &lt; 0) &amp;&amp; !$allow_negative ) {
+        ThrowUserError(&quot;number_too_small&quot;,
+                       {field =&gt; $field, num =&gt; &quot;$time&quot;, min_num =&gt; &quot;0&quot;});
+    }
+
+    if ($time &gt; 99999.99) {
+        ThrowUserError(&quot;number_too_large&quot;,
+                       {field =&gt; $field, num =&gt; &quot;$time&quot;, max_num =&gt; &quot;99999.99&quot;});
+    }
+}
+
+# Sorts fields according to VALIDATOR_DEPENDENCIES. This is not a
+# traditional topological sort, because a &quot;dependency&quot; does not
+# *have* to be in the list--it just has to be earlier than its dependent
+# if it *is* in the list.
+sub _sort_by_dep {
+    my ($invocant, @fields) = @_;
+
+    my $dependencies = $invocant-&gt;VALIDATOR_DEPENDENCIES;
+    my ($has_deps, $no_deps) = part { $dependencies-&gt;{$_} ? 0 : 1 } @fields;
+
+    # For fields with no dependencies, we sort them alphabetically,
+    # so that validation always happens in a consistent order.
+    # Fields with no dependencies come at the start of the list.
+    my @result = sort @{ $no_deps || [] };
+
+    # Fields with dependencies all go at the end of the list, and if
+    # they have dependencies on *each other*, then they have to be
+    # sorted properly. We go through $has_deps in sorted order to be
+    # sure that fields always validate in a consistent order.
+    foreach my $field (sort @{ $has_deps || [] }) {
+        if (!grep { $_ eq $field } @result) {
+            _insert_dep_field($field, $has_deps, $dependencies, \@result);
+        }
+    }
+    return @result;
+}
+
+sub _insert_dep_field {
+    my ($field, $insert_me, $dependencies, $result, $loop_tracking) = @_;
+
+    if ($loop_tracking-&gt;{$field}) {
+        ThrowCodeError('object_dep_sort_loop', 
+                       { field =&gt; $field, 
+                         considered =&gt; [keys %$loop_tracking] });
+    }
+    $loop_tracking-&gt;{$field} = 1;
+
+    my $required_fields = $dependencies-&gt;{$field};
+    # Imagine Field A requires field B...
+    foreach my $required_field (@$required_fields) {
+        # If our dependency is already satisfied, we're good.
+        next if grep { $_ eq $required_field } @$result;
+
+        # If our dependency is not in the remaining fields to insert,
+        # then we're also OK.
+        next if !grep { $_ eq $required_field } @$insert_me;
+
+        # So, at this point, we know that Field B is in $insert_me.
+        # So let's put the required field into the result.
+        _insert_dep_field($required_field, $insert_me, $dependencies,
+                          $result, $loop_tracking);
+    }
+    push(@$result, $field);
+}
+
+####################
+# Constant Helpers #
+####################
+
+# For some classes, some constants take time to generate, so we cache them
+# and only access them through the below methods. This also allows certain
+# hooks to only run once per request instead of multiple times on each
+# page.
+
+sub _get_db_columns {
+    my $invocant = shift;
+    my $class = ref($invocant) || $invocant;
+    my $cache = Bugzilla-&gt;request_cache;
+    my $cache_key = &quot;object_${class}_db_columns&quot;;
+    return @{ $cache-&gt;{$cache_key} } if $cache-&gt;{$cache_key};
+    # Currently you can only add new columns using object_columns, not
+    # remove or modify existing columns, because removing columns would
+    # almost certainly cause Bugzilla to function improperly.
+    my @add_columns;
+    Bugzilla::Hook::process('object_columns',
+                            { class =&gt; $class, columns =&gt; \@add_columns });
+    my @columns = ($invocant-&gt;DB_COLUMNS, @add_columns);
+    $cache-&gt;{$cache_key} = \@columns;
+    return @{ $cache-&gt;{$cache_key} };
+}
+
+# This method is private and should only be called by Bugzilla::Object.
+sub _get_validators {
+    my $invocant = shift;
+    my $class = ref($invocant) || $invocant;
+    my $cache = Bugzilla-&gt;request_cache;
+    my $cache_key = &quot;object_${class}_validators&quot;;
+    return $cache-&gt;{$cache_key} if $cache-&gt;{$cache_key};
+    # We copy this into a hash so that the hook doesn't modify the constant.
+    # (That could be bad in mod_perl.)
+    my %validators = %{ $invocant-&gt;VALIDATORS };
+    Bugzilla::Hook::process('object_validators', 
+                            { class =&gt; $class, validators =&gt; \%validators });
+    $cache-&gt;{$cache_key} = \%validators;
+    return $cache-&gt;{$cache_key};
+}
+
+# These are all the fields that need to be checked, always, when
+# calling create(), because they have no DEFAULT and they are marked
+# NOT NULL.
+sub _required_create_fields {
+    my $class = shift;
+    my $dbh = Bugzilla-&gt;dbh;
+    my $table = $class-&gt;DB_TABLE;
+
+    my @columns = $dbh-&gt;bz_table_columns($table);
+    my @required;
+    foreach my $column (@columns) {
+        my $def = $dbh-&gt;bz_column_info($table, $column);
+        if ($def-&gt;{NOTNULL} and !defined $def-&gt;{DEFAULT}
+            # SERIAL fields effectively have a DEFAULT, but they're not
+            # listed as having a DEFAULT in DB::Schema.
+            and $def-&gt;{TYPE} !~ /serial/i) 
+        {
+            my $field = $class-&gt;REQUIRED_FIELD_MAP-&gt;{$column} || $column;
+            push(@required, $field);
+        }
+    }
+    push(@required, $class-&gt;EXTRA_REQUIRED_FIELDS);
+    return @required;
+}
+
</ins><span class="cx"> 1;
</span><span class="cx"> 
</span><span class="cx"> __END__
</span><span class="lines">@@ -425,6 +790,12 @@
</span><span class="cx"> The names of the columns that you want to read out of the database
</span><span class="cx"> and into this object. This should be an array.
</span><span class="cx"> 
</span><ins>+I&lt;Note&gt;: Though normally you will never need to access this constant's data 
+directly in your subclass, if you do, you should access it by calling the
+C&lt;_get_db_columns&gt; method instead of accessing the constant directly. (The
+only exception to this rule is calling C&lt;SUPER::DB_COLUMNS&gt; from within
+your own C&lt;DB_COLUMNS&gt; subroutine in a subclass.)
+
</ins><span class="cx"> =item C&lt;NAME_FIELD&gt;
</span><span class="cx"> 
</span><span class="cx"> The name of the column that should be considered to be the unique
</span><span class="lines">@@ -444,11 +815,6 @@
</span><span class="cx"> in. This should be the name of a database column. Defaults to
</span><span class="cx"> L&lt;/NAME_FIELD&gt;.
</span><span class="cx"> 
</span><del>-=item C&lt;REQUIRED_CREATE_FIELDS&gt;
-
-The list of fields that B&lt;must&gt; be specified when the user calls
-C&lt;create()&gt;. This should be an array.
-
</del><span class="cx"> =item C&lt;VALIDATORS&gt;
</span><span class="cx"> 
</span><span class="cx"> A hashref that points to a function that will validate each param to
</span><span class="lines">@@ -479,12 +845,69 @@
</span><span class="cx"> 
</span><span class="cx"> L&lt;Bugzilla::Bug&gt; has good examples in its code of when to use this.
</span><span class="cx"> 
</span><ins>+=item C&lt;VALIDATOR_DEPENDENCIES&gt;
+
+During L&lt;/create&gt; and L&lt;/set_all&gt;, validators are normally called in
+a somewhat-random order.  If you need one field to be validated and set
+before another field, this constant is how you do it, by saying that
+one field &quot;depends&quot; on the value of other fields.
+
+This is a hashref, where the keys are field names and the values are
+arrayrefs of field names. You specify what fields a field depends on using
+the arrayrefs. So, for example, to say that a C&lt;component&gt; field depends
+on the C&lt;product&gt; field being set, you would do:
+
+ component =&gt; ['product']
+
</ins><span class="cx"> =item C&lt;UPDATE_COLUMNS&gt;
</span><span class="cx"> 
</span><span class="cx"> A list of columns to update when L&lt;/update&gt; is called.
</span><span class="cx"> If a field can't be changed, it shouldn't be listed here. (For example,
</span><span class="cx"> the L&lt;/ID_FIELD&gt; usually can't be updated.)
</span><span class="cx"> 
</span><ins>+=item C&lt;REQUIRED_FIELD_MAP&gt;
+
+This is a hashref that maps database column names to L&lt;/create&gt; argument
+names. You only need to specify values for fields where the argument passed
+to L&lt;/create&gt; has a different name in the database than it does in the
+L&lt;/create&gt; arguments. (For example, L&lt;Bugzilla::Bug/create&gt; takes a
+C&lt;product&gt; argument, but the column name in the C&lt;bugs&gt; table is
+C&lt;product_id&gt;.)
+
+=item C&lt;EXTRA_REQUIRED_FIELDS&gt;
+
+Normally, Bugzilla::Object automatically figures out which fields
+are required for L&lt;/create&gt;. It then I&lt;always&gt; runs those fields' validators,
+even if those fields weren't passed as arguments to L&lt;/create&gt;. That way,
+any default values or required checks can be done for those fields by
+the validators.
+
+L&lt;/create&gt; figures out which fields are required by looking for database
+columns in the L&lt;/DB_TABLE&gt; that are NOT NULL and have no DEFAULT set.
+However, there are some fields that this check doesn't work for:
+
+=over
+
+=item *
+
+Fields that have database defaults (or are marked NULL in the database)
+but actually have different defaults specified by validators. (For example,
+the qa_contact field in the C&lt;bugs&gt; table can be NULL, so it won't be
+caught as being required. However, in reality it defaults to the
+component's initial_qa_contact.)
+
+=item * 
+
+Fields that have defaults that should be set by validators, but are
+actually stored in a table different from L&lt;/DB_TABLE&gt; (like the &quot;cc&quot;
+field for bugs, which defaults to the &quot;initialcc&quot; of the Component, but won't
+be caught as a normal required field because it's in a separate table.) 
+
+=back
+
+Any field matching the above criteria needs to have its name listed in
+this constant. For an example of use, see the code of L&lt;Bugzilla::Bug&gt;.
+
</ins><span class="cx"> =item C&lt;NUMERIC_COLUMNS&gt;
</span><span class="cx"> 
</span><span class="cx"> When L&lt;/update&gt; is called, it compares each column in the object to its
</span><span class="lines">@@ -524,7 +947,9 @@
</span><span class="cx"> 
</span><span class="cx"> If you pass in a hashref, you can pass a C&lt;name&gt; key. The 
</span><span class="cx"> value of the C&lt;name&gt; key is the case-insensitive name of the object 
</span><del>-(from L&lt;/NAME_FIELD&gt;) in the DB.
</del><ins>+(from L&lt;/NAME_FIELD&gt;) in the DB. You can also pass in an C&lt;id&gt; key
+which will be interpreted as the id of the object you want (overriding the 
+C&lt;name&gt; key).
</ins><span class="cx"> 
</span><span class="cx"> B&lt;Additional Parameters Available for Subclasses&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -614,6 +1039,26 @@
</span><span class="cx"> which means &quot;give me objects where this field is NULL or NOT NULL,
</span><span class="cx"> respectively.&quot;
</span><span class="cx"> 
</span><ins>+In addition to the column keys, there are a few special keys that
+can be used to rig the underlying database queries. These are 
+C&lt;LIMIT&gt;, C&lt;OFFSET&gt;, and C&lt;WHERE&gt;.
+
+The value for the C&lt;LIMIT&gt; key is expected to be an integer defining 
+the number of objects to return, while the value for C&lt;OFFSET&gt; defines
+the position, relative to the number of objects the query would normally 
+return, at which to begin the result set. If C&lt;OFFSET&gt; is defined without 
+a corresponding C&lt;LIMIT&gt; it is silently ignored.
+
+The C&lt;WHERE&gt; key provides a mechanism for adding arbitrary WHERE
+clauses to the underlying query. Its value is expected to a hash 
+reference whose keys are the columns, operators and placeholders, and the 
+values are the placeholders' bind value. For example:
+
+ WHERE =&gt; { 'some_column &gt;= ?' =&gt; $some_value }
+
+would constrain the query to only those objects in the table whose
+'some_column' column has a value greater than or equal to $some_value.
+
</ins><span class="cx"> If you don't specify any criteria, calling this function is the same
</span><span class="cx"> as doing C&lt;[$class-E&lt;gt&gt;get_all]&gt;.
</span><span class="cx"> 
</span><span class="lines">@@ -636,17 +1081,13 @@
</span><span class="cx">              are invalid.
</span><span class="cx"> 
</span><span class="cx"> Params:      C&lt;$params&gt; - hashref - A value to put in each database
</span><del>-               field for this object. Certain values must be set (the 
-               ones specified in L&lt;/REQUIRED_CREATE_FIELDS&gt;), and
-               the function will throw a Code Error if you don't set
-               them.
</del><ins>+             field for this object.
</ins><span class="cx"> 
</span><span class="cx"> Returns:     The Object just created in the database.
</span><span class="cx"> 
</span><span class="cx"> Notes:       In order for this function to work in your subclass,
</span><span class="cx">              your subclass's L&lt;/ID_FIELD&gt; must be of C&lt;SERIAL&gt;
</span><del>-             type in the database. Your subclass also must
-             define L&lt;/REQUIRED_CREATE_FIELDS&gt; and L&lt;/VALIDATORS&gt;.
</del><ins>+             type in the database.
</ins><span class="cx"> 
</span><span class="cx">              Subclass Implementors: This function basically just
</span><span class="cx">              calls L&lt;/check_required_create_fields&gt;, then
</span><span class="lines">@@ -661,8 +1102,10 @@
</span><span class="cx"> 
</span><span class="cx"> =item B&lt;Description&gt;
</span><span class="cx"> 
</span><del>-Part of L&lt;/create&gt;. Throws an error if any of the L&lt;/REQUIRED_CREATE_FIELDS&gt;
-have not been specified in C&lt;$params&gt;
</del><ins>+Part of L&lt;/create&gt;. Modifies the incoming C&lt;$params&gt; argument so that
+any field that does not have a database default will be checked
+later by L&lt;/run_create_validators&gt;, even if that field wasn't specified
+as an argument to L&lt;/create&gt;.
</ins><span class="cx"> 
</span><span class="cx"> =item B&lt;Params&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -684,7 +1127,11 @@
</span><span class="cx">              of their input parameters. This method is B&lt;only&gt; called
</span><span class="cx">              by L&lt;/create&gt;.
</span><span class="cx"> 
</span><del>-Params:      The same as L&lt;/create&gt;.
</del><ins>+Params:      C&lt;$params&gt; - hashref - A value to put in each database
+             field for this object.
+             C&lt;$options&gt; - hashref - Processing options. Currently
+             the only option supported is B&lt;skip&gt;, which can be
+             used to specify a list of fields to not validate.
</ins><span class="cx"> 
</span><span class="cx"> Returns:     A hash, in a similar format as C&lt;$params&gt;, except that
</span><span class="cx">              these are the values to be inserted into the database,
</span><span class="lines">@@ -711,6 +1158,8 @@
</span><span class="cx"> 
</span><span class="cx"> =item B&lt;Returns&gt;
</span><span class="cx"> 
</span><ins>+B&lt;In scalar context:&gt;
+
</ins><span class="cx"> A hashref showing what changed during the update. The keys are the column
</span><span class="cx"> names from L&lt;/UPDATE_COLUMNS&gt;. If a field was not changed, it will not be
</span><span class="cx"> in the hash at all. If the field was changed, the key will point to an arrayref.
</span><span class="lines">@@ -719,14 +1168,27 @@
</span><span class="cx"> 
</span><span class="cx"> If there were no changes, we return a reference to an empty hash.
</span><span class="cx"> 
</span><ins>+B&lt;In array context:&gt;
+
+Returns a list, where the first item is the above hashref. The second item
+is the object as it was in the database before update() was called. (This
+is mostly useful to subclasses of C&lt;Bugzilla::Object&gt; that are implementing
+C&lt;update&gt;.)
+
</ins><span class="cx"> =back
</span><span class="cx"> 
</span><ins>+=item C&lt;remove_from_db&gt;
+
+Removes this object from the database. Will throw an error if you can't
+remove it for some reason. The object will then be destroyed, as it is
+not safe to use the object after it has been removed from the database.
+
</ins><span class="cx"> =back
</span><span class="cx"> 
</span><del>-=head2 Subclass Helpers
</del><ins>+=head2 Mutators
</ins><span class="cx"> 
</span><del>-These functions are intended only for use by subclasses. If
-you call them from anywhere else, they will throw a C&lt;CodeError&gt;.
</del><ins>+These are used for updating the values in objects, before calling
+C&lt;update&gt;.
</ins><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><span class="lines">@@ -747,9 +1209,11 @@
</span><span class="cx"> the validator for this particular field. C&lt;_set_global_validator&gt; does not
</span><span class="cx"> return anything.
</span><span class="cx"> 
</span><del>-
</del><span class="cx"> See L&lt;/VALIDATORS&gt; for more information.
</span><span class="cx"> 
</span><ins>+B&lt;NOTE&gt;: This function is intended only for use by subclasses. If
+you call it from anywhere else, it will throw a C&lt;CodeError&gt;.
+
</ins><span class="cx"> =item B&lt;Params&gt;
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="lines">@@ -765,8 +1229,29 @@
</span><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><ins>+
+=item C&lt;set_all&gt;
+
+=over
+
+=item B&lt;Description&gt;
+
+This is a convenience function which is simpler than calling many different
+C&lt;set_&gt; functions in a row. You pass a hashref of parameters and it calls
+C&lt;set_$key($value)&gt; for every item in the hashref.
+
+=item B&lt;Params&gt;
+
+Takes a hashref of the fields that need to be set, pointing to the value
+that should be passed to the C&lt;set_&gt; function that is called.
+
+=item B&lt;Returns&gt; (nothing)
+
</ins><span class="cx"> =back
</span><span class="cx"> 
</span><ins>+
+=back
+
</ins><span class="cx"> =head2 Simple Validators
</span><span class="cx"> 
</span><span class="cx"> You can use these in your subclass L&lt;/VALIDATORS&gt; or L&lt;/UPDATE_VALIDATORS&gt;.
</span><span class="lines">@@ -785,6 +1270,11 @@
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><ins>+=item C&lt;any_exist&gt;
+
+Returns C&lt;1&gt; if there are any of these objects in the database,
+C&lt;0&gt; otherwise.
+
</ins><span class="cx"> =item C&lt;get_all&gt;
</span><span class="cx"> 
</span><span class="cx">  Description: Returns all objects in this table from the database.
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaProductpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Product.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Product.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Product.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -13,22 +13,27 @@
</span><span class="cx"> # The Original Code is the Bugzilla Bug Tracking System.
</span><span class="cx"> #
</span><span class="cx"> # Contributor(s): Tiago R. Mello &lt;timello@async.com.br&gt;
</span><ins>+#                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
</ins><span class="cx"> 
</span><ins>+package Bugzilla::Product;
</ins><span class="cx"> use strict;
</span><ins>+use base qw(Bugzilla::Field::ChoiceInterface Bugzilla::Object);
</ins><span class="cx"> 
</span><del>-package Bugzilla::Product;
-
-use Bugzilla::Version;
-use Bugzilla::Milestone;
-
</del><span class="cx"> use Bugzilla::Constants;
</span><span class="cx"> use Bugzilla::Util;
</span><ins>+use Bugzilla::Error;
</ins><span class="cx"> use Bugzilla::Group;
</span><del>-use Bugzilla::Error;
-
</del><ins>+use Bugzilla::Version;
+use Bugzilla::Milestone;
+use Bugzilla::Field;
+use Bugzilla::Status;
</ins><span class="cx"> use Bugzilla::Install::Requirements;
</span><ins>+use Bugzilla::Mailer;
+use Bugzilla::Series;
+use Bugzilla::Hook;
+use Bugzilla::FlagType;
</ins><span class="cx"> 
</span><del>-use base qw(Bugzilla::Object);
</del><ins>+use Scalar::Util qw(blessed);
</ins><span class="cx"> 
</span><span class="cx"> use constant DEFAULT_CLASSIFICATION_ID =&gt; 1;
</span><span class="cx"> 
</span><span class="lines">@@ -39,27 +44,77 @@
</span><span class="cx"> use constant DB_TABLE =&gt; 'products';
</span><span class="cx"> 
</span><span class="cx"> use constant DB_COLUMNS =&gt; qw(
</span><del>-   products.id
-   products.name
-   products.classification_id
-   products.description
-   products.milestoneurl
-   products.disallownew
-   products.votesperuser
-   products.maxvotesperbug
-   products.votestoconfirm
-   products.defaultmilestone
</del><ins>+   id
+   name
+   classification_id
+   description
+   isactive
+   defaultmilestone
+   allows_unconfirmed
</ins><span class="cx"> );
</span><span class="cx"> 
</span><ins>+use constant UPDATE_COLUMNS =&gt; qw(
+    name
+    description
+    defaultmilestone
+    isactive
+    allows_unconfirmed
+);
+
+use constant VALIDATORS =&gt; {
+    allows_unconfirmed =&gt; \&amp;Bugzilla::Object::check_boolean,
+    classification   =&gt; \&amp;_check_classification,
+    name             =&gt; \&amp;_check_name,
+    description      =&gt; \&amp;_check_description,
+    version          =&gt; \&amp;_check_version,
+    defaultmilestone =&gt; \&amp;_check_default_milestone,
+    isactive         =&gt; \&amp;Bugzilla::Object::check_boolean,
+    create_series    =&gt; \&amp;Bugzilla::Object::check_boolean
+};
+
</ins><span class="cx"> ###############################
</span><span class="cx"> ####     Constructors     #####
</span><span class="cx"> ###############################
</span><span class="cx"> 
</span><ins>+sub create {
+    my $class = shift;
+    my $dbh = Bugzilla-&gt;dbh;
+
+    $dbh-&gt;bz_start_transaction();
+
+    $class-&gt;check_required_create_fields(@_);
+
+    my $params = $class-&gt;run_create_validators(@_);
+    # Some fields do not exist in the DB as is.
+    if (defined $params-&gt;{classification}) {
+        $params-&gt;{classification_id} = delete $params-&gt;{classification}; 
+    }
+    my $version = delete $params-&gt;{version};
+    my $create_series = delete $params-&gt;{create_series};
+
+    my $product = $class-&gt;insert_create_data($params);
+    Bugzilla-&gt;user-&gt;clear_product_cache();
+
+    # Add the new version and milestone into the DB as valid values.
+    Bugzilla::Version-&gt;create({ value =&gt; $version, product =&gt; $product });
+    Bugzilla::Milestone-&gt;create({ value =&gt; $product-&gt;default_milestone, 
+                                  product =&gt; $product });
+
+    # Create groups and series for the new product, if requested.
+    $product-&gt;_create_bug_group() if Bugzilla-&gt;params-&gt;{'makeproductgroups'};
+    $product-&gt;_create_series() if $create_series;
+
+    Bugzilla::Hook::process('product_end_of_create', { product =&gt; $product });
+
+    $dbh-&gt;bz_commit_transaction();
+    return $product;
+}
+
</ins><span class="cx"> # This is considerably faster than calling new_from_list three times
</span><span class="cx"> # for each product in the list, particularly with hundreds or thousands
</span><span class="cx"> # of products.
</span><span class="cx"> sub preload {
</span><del>-    my ($products) = @_;
</del><ins>+    my ($products, $preload_flagtypes) = @_;
</ins><span class="cx">     my %prods = map { $_-&gt;id =&gt; $_ } @$products;
</span><span class="cx">     my @prod_ids = keys %prods;
</span><span class="cx">     return unless @prod_ids;
</span><span class="lines">@@ -76,12 +131,417 @@
</span><span class="cx">             push(@{$prods{$product_id}-&gt;{&quot;${field}s&quot;}}, $obj);
</span><span class="cx">         }
</span><span class="cx">     }
</span><ins>+    if ($preload_flagtypes) {
+        $_-&gt;flag_types foreach @$products;
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub update {
+    my $self = shift;
+    my $dbh = Bugzilla-&gt;dbh;
+
+    # Don't update the DB if something goes wrong below -&gt; transaction.
+    $dbh-&gt;bz_start_transaction();
+    my ($changes, $old_self) = $self-&gt;SUPER::update(@_);
+
+    # Also update group settings.
+    if ($self-&gt;{check_group_controls}) {
+        require Bugzilla::Bug;
+        import Bugzilla::Bug qw(LogActivityEntry);
+
+        my $old_settings = $old_self-&gt;group_controls;
+        my $new_settings = $self-&gt;group_controls;
+        my $timestamp = $dbh-&gt;selectrow_array('SELECT NOW()');
+
+        foreach my $gid (keys %$new_settings) {
+            my $old_setting = $old_settings-&gt;{$gid} || {};
+            my $new_setting = $new_settings-&gt;{$gid};
+            # If all new settings are 0 for a given group, we delete the entry
+            # from group_control_map, so we have to track it here.
+            my $all_zero = 1;
+            my @fields;
+            my @values;
+
+            foreach my $field ('entry', 'membercontrol', 'othercontrol', 'canedit',
+                               'editcomponents', 'editbugs', 'canconfirm')
+            {
+                my $old_value = $old_setting-&gt;{$field};
+                my $new_value = $new_setting-&gt;{$field};
+                $all_zero = 0 if $new_value;
+                next if (defined $old_value &amp;&amp; $old_value == $new_value);
+                push(@fields, $field);
+                # The value has already been validated.
+                detaint_natural($new_value);
+                push(@values, $new_value);
+            }
+            # Is there anything to update?
+            next unless scalar @fields;
+
+            if ($all_zero) {
+                $dbh-&gt;do('DELETE FROM group_control_map
+                          WHERE product_id = ? AND group_id = ?',
+                          undef, $self-&gt;id, $gid);
+            }
+            else {
+                if (exists $old_setting-&gt;{group}) {
+                    # There is already an entry in the DB.
+                    my $set_fields = join(', ', map {&quot;$_ = ?&quot;} @fields);
+                    $dbh-&gt;do(&quot;UPDATE group_control_map SET $set_fields
+                              WHERE product_id = ? AND group_id = ?&quot;,
+                              undef, (@values, $self-&gt;id, $gid));
+                }
+                else {
+                    # No entry yet.
+                    my $fields = join(', ', @fields);
+                    # +2 because of the product and group IDs.
+                    my $qmarks = join(',', ('?') x (scalar @fields + 2));
+                    $dbh-&gt;do(&quot;INSERT INTO group_control_map (product_id, group_id, $fields)
+                              VALUES ($qmarks)&quot;, undef, ($self-&gt;id, $gid, @values));
+                }
+            }
+
+            # If the group is mandatory, restrict all bugs to it.
+            if ($new_setting-&gt;{membercontrol} == CONTROLMAPMANDATORY) {
+                my $bug_ids =
+                  $dbh-&gt;selectcol_arrayref('SELECT bugs.bug_id
+                                              FROM bugs
+                                                   LEFT JOIN bug_group_map
+                                                   ON bug_group_map.bug_id = bugs.bug_id
+                                                   AND group_id = ?
+                                             WHERE product_id = ?
+                                                   AND bug_group_map.bug_id IS NULL',
+                                             undef, $gid, $self-&gt;id);
+
+                if (scalar @$bug_ids) {
+                    my $sth = $dbh-&gt;prepare('INSERT INTO bug_group_map (bug_id, group_id)
+                                             VALUES (?, ?)');
+
+                    foreach my $bug_id (@$bug_ids) {
+                        $sth-&gt;execute($bug_id, $gid);
+                        # Add this change to the bug history.
+                        LogActivityEntry($bug_id, 'bug_group', '',
+                                         $new_setting-&gt;{group}-&gt;name,
+                                         Bugzilla-&gt;user-&gt;id, $timestamp);
+                    }
+                    push(@{$changes-&gt;{'_group_controls'}-&gt;{'now_mandatory'}},
+                         {name      =&gt; $new_setting-&gt;{group}-&gt;name,
+                          bug_count =&gt; scalar @$bug_ids});
+                }
+            }
+            # If the group can no longer be used to restrict bugs, remove them.
+            elsif ($new_setting-&gt;{membercontrol} == CONTROLMAPNA) {
+                my $bug_ids =
+                  $dbh-&gt;selectcol_arrayref('SELECT bugs.bug_id
+                                              FROM bugs
+                                                   INNER JOIN bug_group_map
+                                                   ON bug_group_map.bug_id = bugs.bug_id
+                                             WHERE product_id = ? AND group_id = ?',
+                                             undef, $self-&gt;id, $gid);
+
+                if (scalar @$bug_ids) {
+                    $dbh-&gt;do('DELETE FROM bug_group_map WHERE group_id = ? AND ' .
+                              $dbh-&gt;sql_in('bug_id', $bug_ids), undef, $gid);
+
+                    # Add this change to the bug history.
+                    foreach my $bug_id (@$bug_ids) {
+                        LogActivityEntry($bug_id, 'bug_group',
+                                         $old_setting-&gt;{group}-&gt;name, '',
+                                         Bugzilla-&gt;user-&gt;id, $timestamp);
+                    }
+                    push(@{$changes-&gt;{'_group_controls'}-&gt;{'now_na'}},
+                         {name =&gt; $old_setting-&gt;{group}-&gt;name,
+                          bug_count =&gt; scalar @$bug_ids});
+                }
+            }
+        }
+
+        delete $self-&gt;{groups_available};
+        delete $self-&gt;{groups_mandatory};
+    }
+    $dbh-&gt;bz_commit_transaction();
+    # Changes have been committed.
+    delete $self-&gt;{check_group_controls};
+    Bugzilla-&gt;user-&gt;clear_product_cache();
+
+    return $changes;
+}
+
+sub remove_from_db {
+    my ($self, $params) = @_;
+    my $user = Bugzilla-&gt;user;
+    my $dbh = Bugzilla-&gt;dbh;
+
+    $dbh-&gt;bz_start_transaction();
+
+    $self-&gt;_check_if_controller();
+
+    if ($self-&gt;bug_count) {
+        if (Bugzilla-&gt;params-&gt;{'allowbugdeletion'}) {
+            require Bugzilla::Bug;
+            foreach my $bug_id (@{$self-&gt;bug_ids}) {
+                # Note that we allow the user to delete bugs he can't see,
+                # which is okay, because he's deleting the whole Product.
+                my $bug = new Bugzilla::Bug($bug_id);
+                $bug-&gt;remove_from_db();
+            }
+        }
+        else {
+            ThrowUserError('product_has_bugs', { nb =&gt; $self-&gt;bug_count });
+        }
+    }
+
+    if ($params-&gt;{delete_series}) {
+        my $series_ids =
+          $dbh-&gt;selectcol_arrayref('SELECT series_id
+                                      FROM series
+                                INNER JOIN series_categories
+                                        ON series_categories.id = series.category
+                                     WHERE series_categories.name = ?',
+                                    undef, $self-&gt;name);
+
+        if (scalar @$series_ids) {
+            $dbh-&gt;do('DELETE FROM series WHERE ' . $dbh-&gt;sql_in('series_id', $series_ids));
+        }
+
+        # If no subcategory uses this product name, completely purge it.
+        my $in_use =
+          $dbh-&gt;selectrow_array('SELECT 1
+                                   FROM series
+                             INNER JOIN series_categories
+                                     ON series_categories.id = series.subcategory
+                                  WHERE series_categories.name = ? ' .
+                                   $dbh-&gt;sql_limit(1),
+                                  undef, $self-&gt;name);
+        if (!$in_use) {
+            $dbh-&gt;do('DELETE FROM series_categories WHERE name = ?', undef, $self-&gt;name);
+        }
+    }
+
+    $dbh-&gt;do(&quot;DELETE FROM products WHERE id = ?&quot;, undef, $self-&gt;id);
+
+    $dbh-&gt;bz_commit_transaction();
+
+    # We have to delete these internal variables, else we get
+    # the old lists of products and classifications again.
+    delete $user-&gt;{selectable_products};
+    delete $user-&gt;{selectable_classifications};
+
+}
+
</ins><span class="cx"> ###############################
</span><ins>+####      Validators       ####
+###############################
+
+sub _check_classification {
+    my ($invocant, $classification_name) = @_;
+
+    my $classification_id = 1;
+    if (Bugzilla-&gt;params-&gt;{'useclassification'}) {
+        my $classification = Bugzilla::Classification-&gt;check($classification_name);
+        $classification_id = $classification-&gt;id;
+    }
+    return $classification_id;
+}
+
+sub _check_name {
+    my ($invocant, $name) = @_;
+
+    $name = trim($name);
+    $name || ThrowUserError('product_blank_name');
+
+    if (length($name) &gt; MAX_PRODUCT_SIZE) {
+        ThrowUserError('product_name_too_long', {'name' =&gt; $name});
+    }
+
+    my $product = new Bugzilla::Product({name =&gt; $name});
+    if ($product &amp;&amp; (!ref $invocant || $product-&gt;id != $invocant-&gt;id)) {
+        # Check for exact case sensitive match:
+        if ($product-&gt;name eq $name) {
+            ThrowUserError('product_name_already_in_use', {'product' =&gt; $product-&gt;name});
+        }
+        else {
+            ThrowUserError('product_name_diff_in_case', {'product'          =&gt; $name,
+                                                         'existing_product' =&gt; $product-&gt;name});
+        }
+    }
+    return $name;
+}
+
+sub _check_description {
+    my ($invocant, $description) = @_;
+
+    $description  = trim($description);
+    $description || ThrowUserError('product_must_have_description');
+    return $description;
+}
+
+sub _check_version {
+    my ($invocant, $version) = @_;
+
+    $version = trim($version);
+    $version || ThrowUserError('product_must_have_version');
+    # We will check the version length when Bugzilla::Version-&gt;create will do it.
+    return $version;
+}
+
+sub _check_default_milestone {
+    my ($invocant, $milestone) = @_;
+
+    # Do nothing if target milestones are not in use.
+    unless (Bugzilla-&gt;params-&gt;{'usetargetmilestone'}) {
+        return (ref $invocant) ? $invocant-&gt;default_milestone : '---';
+    }
+
+    $milestone = trim($milestone);
+
+    if (ref $invocant) {
+        # The default milestone must be one of the existing milestones.
+        my $mil_obj = new Bugzilla::Milestone({name =&gt; $milestone, product =&gt; $invocant});
+
+        $mil_obj || ThrowUserError('product_must_define_defaultmilestone',
+                                   {product   =&gt; $invocant-&gt;name,
+                                    milestone =&gt; $milestone});
+    }
+    else {
+        $milestone ||= '---';
+    }
+    return $milestone;
+}
+
+sub _check_milestone_url {
+    my ($invocant, $url) = @_;
+
+    # Do nothing if target milestones are not in use.
+    unless (Bugzilla-&gt;params-&gt;{'usetargetmilestone'}) {
+        return (ref $invocant) ? $invocant-&gt;milestone_url : '';
+    }
+
+    $url = trim($url || '');
+    return $url;
+}
+
+#####################################
+# Implement Bugzilla::Field::Choice #
+#####################################
+
+use constant FIELD_NAME =&gt; 'product';
+use constant is_default =&gt; 0;
+
+###############################
</ins><span class="cx"> ####       Methods         ####
</span><span class="cx"> ###############################
</span><span class="cx"> 
</span><ins>+sub _create_bug_group {
+    my $self = shift;
+    my $dbh = Bugzilla-&gt;dbh;
+
+    my $group_name = $self-&gt;name;
+    while (new Bugzilla::Group({name =&gt; $group_name})) {
+        $group_name .= '_';
+    }
+    my $group_description = get_text('bug_group_description', {product =&gt; $self});
+
+    my $group = Bugzilla::Group-&gt;create({name        =&gt; $group_name,
+                                         description =&gt; $group_description,
+                                         isbuggroup  =&gt; 1});
+
+    # Associate the new group and new product.
+    $dbh-&gt;do('INSERT INTO group_control_map
+              (group_id, product_id, membercontrol, othercontrol)
+              VALUES (?, ?, ?, ?)',
+              undef, ($group-&gt;id, $self-&gt;id, CONTROLMAPDEFAULT, CONTROLMAPNA));
+}
+
+sub _create_series {
+    my $self = shift;
+
+    my @series;
+    # We do every status, every resolution, and an &quot;opened&quot; one as well.
+    foreach my $bug_status (@{get_legal_field_values('bug_status')}) {
+        push(@series, [$bug_status, &quot;bug_status=&quot; . url_quote($bug_status)]);
+    }
+
+    foreach my $resolution (@{get_legal_field_values('resolution')}) {
+        next if !$resolution;
+        push(@series, [$resolution, &quot;resolution=&quot; . url_quote($resolution)]);
+    }
+
+    my @openedstatuses = BUG_STATE_OPEN;
+    my $query = join(&quot;&amp;&quot;, map { &quot;bug_status=&quot; . url_quote($_) } @openedstatuses);
+    push(@series, [get_text('series_all_open'), $query]);
+
+    foreach my $sdata (@series) {
+        my $series = new Bugzilla::Series(undef, $self-&gt;name,
+                        get_text('series_subcategory'),
+                        $sdata-&gt;[0], Bugzilla-&gt;user-&gt;id, 1,
+                        $sdata-&gt;[1] . &quot;&amp;product=&quot; . url_quote($self-&gt;name), 1);
+        $series-&gt;writeToDatabase();
+    }
+}
+
+sub set_name { $_[0]-&gt;set('name', $_[1]); }
+sub set_description { $_[0]-&gt;set('description', $_[1]); }
+sub set_default_milestone { $_[0]-&gt;set('defaultmilestone', $_[1]); }
+sub set_is_active { $_[0]-&gt;set('isactive', $_[1]); }
+sub set_allows_unconfirmed { $_[0]-&gt;set('allows_unconfirmed', $_[1]); }
+
+sub set_group_controls {
+    my ($self, $group, $settings) = @_;
+
+    $group-&gt;is_active_bug_group
+      || ThrowUserError('product_illegal_group', {group =&gt; $group});
+
+    scalar(keys %$settings)
+      || ThrowCodeError('product_empty_group_controls', {group =&gt; $group});
+
+    # We store current settings for this group.
+    my $gs = $self-&gt;group_controls-&gt;{$group-&gt;id};
+    # If there is no entry for this group yet, create a default hash.
+    unless (defined $gs) {
+        $gs = { entry          =&gt; 0,
+                membercontrol  =&gt; CONTROLMAPNA,
+                othercontrol   =&gt; CONTROLMAPNA,
+                canedit        =&gt; 0,
+                editcomponents =&gt; 0,
+                editbugs       =&gt; 0,
+                canconfirm     =&gt; 0,
+                group          =&gt; $group };
+    }
+
+    # Both settings must be defined, or none of them can be updated.
+    if (defined $settings-&gt;{membercontrol} &amp;&amp; defined $settings-&gt;{othercontrol}) {
+        #  Legality of control combination is a function of
+        #  membercontrol\othercontrol
+        #                 NA SH DE MA
+        #              NA  +  -  -  -
+        #              SH  +  +  +  +
+        #              DE  +  -  +  +
+        #              MA  -  -  -  +
+        foreach my $field ('membercontrol', 'othercontrol') {
+            my ($is_legal) = grep { $settings-&gt;{$field} == $_ }
+              (CONTROLMAPNA, CONTROLMAPSHOWN, CONTROLMAPDEFAULT, CONTROLMAPMANDATORY);
+            defined $is_legal || ThrowCodeError('product_illegal_group_control',
+                                   { field =&gt; $field, value =&gt; $settings-&gt;{$field} });
+        }
+        unless ($settings-&gt;{membercontrol} == $settings-&gt;{othercontrol}
+                || $settings-&gt;{membercontrol} == CONTROLMAPSHOWN
+                || ($settings-&gt;{membercontrol} == CONTROLMAPDEFAULT
+                    &amp;&amp; $settings-&gt;{othercontrol} != CONTROLMAPSHOWN))
+        {
+            ThrowUserError('illegal_group_control_combination', {groupname =&gt; $group-&gt;name});
+        }
+        $gs-&gt;{membercontrol} = $settings-&gt;{membercontrol};
+        $gs-&gt;{othercontrol} = $settings-&gt;{othercontrol};
+    }
+
+    foreach my $field ('entry', 'canedit', 'editcomponents', 'editbugs', 'canconfirm') {
+        next unless defined $settings-&gt;{$field};
+        $gs-&gt;{$field} = $settings-&gt;{$field} ? 1 : 0;
+    }
+    $self-&gt;{group_controls}-&gt;{$group-&gt;id} = $gs;
+    $self-&gt;{check_group_controls} = 1;
+}
+
</ins><span class="cx"> sub components {
</span><span class="cx">     my $self = shift;
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="lines">@@ -99,25 +559,33 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub group_controls {
</span><del>-    my $self = shift;
</del><ins>+    my ($self, $full_data) = @_;
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx"> 
</span><del>-    if (!defined $self-&gt;{group_controls}) {
-        my $query = qq{SELECT
-                       groups.id,
-                       group_control_map.entry,
-                       group_control_map.membercontrol,
-                       group_control_map.othercontrol,
-                       group_control_map.canedit,
-                       group_control_map.editcomponents,
-                       group_control_map.editbugs,
-                       group_control_map.canconfirm
-                  FROM groups
-                  LEFT JOIN group_control_map
-                        ON groups.id = group_control_map.group_id
-                  WHERE group_control_map.product_id = ?
-                  AND   groups.isbuggroup != 0
-                  ORDER BY groups.name};
</del><ins>+    # By default, we don't return groups which are not listed in
+    # group_control_map. If $full_data is true, then we also
+    # return groups whose settings could be set for the product.
+    my $where_or_and = 'WHERE';
+    my $and_or_where = 'AND';
+    if ($full_data) {
+        $where_or_and = 'AND';
+        $and_or_where = 'WHERE';
+    }
+
+    # If $full_data is true, we collect all the data in all cases,
+    # even if the cache is already populated.
+    # $full_data is never used except in the very special case where
+    # all configurable bug groups are displayed to administrators,
+    # so we don't care about collecting all the data again in this case.
+    if (!defined $self-&gt;{group_controls} || $full_data) {
+        # Include name to the list, to allow us sorting data more easily.
+        my $query = qq{SELECT id, name, entry, membercontrol, othercontrol,
+                              canedit, editcomponents, editbugs, canconfirm
+                         FROM groups
+                              LEFT JOIN group_control_map
+                              ON id = group_id 
+                $where_or_and product_id = ?
+                $and_or_where isbuggroup = 1};
</ins><span class="cx">         $self-&gt;{group_controls} = 
</span><span class="cx">             $dbh-&gt;selectall_hashref($query, 'id', undef, $self-&gt;id);
</span><span class="cx"> 
</span><span class="lines">@@ -126,26 +594,107 @@
</span><span class="cx">         my $groups = Bugzilla::Group-&gt;new_from_list(\@gids);
</span><span class="cx">         $self-&gt;{group_controls}-&gt;{$_-&gt;id}-&gt;{group} = $_ foreach @$groups;
</span><span class="cx">     }
</span><ins>+
+    # We never cache bug counts, for the same reason as above.
+    if ($full_data) {
+        my $counts =
+          $dbh-&gt;selectall_arrayref('SELECT group_id, COUNT(bugs.bug_id) AS bug_count
+                                      FROM bug_group_map
+                                INNER JOIN bugs
+                                        ON bugs.bug_id = bug_group_map.bug_id
+                                     WHERE bugs.product_id = ? ' .
+                                     $dbh-&gt;sql_group_by('group_id'),
+                          {'Slice' =&gt; {}}, $self-&gt;id);
+        foreach my $data (@$counts) {
+            $self-&gt;{group_controls}-&gt;{$data-&gt;{group_id}}-&gt;{bug_count} = $data-&gt;{bug_count};
+        }
+    }
</ins><span class="cx">     return $self-&gt;{group_controls};
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub groups_mandatory_for {
-    my ($self, $user) = @_;
-    my $groups = $user-&gt;groups_as_string;
</del><ins>+sub groups_available {
+    my ($self) = @_;
+    return $self-&gt;{groups_available} if defined $self-&gt;{groups_available};
+    my $dbh = Bugzilla-&gt;dbh;
+    my $shown = CONTROLMAPSHOWN;
+    my $default = CONTROLMAPDEFAULT;
+    my %member_groups = @{ $dbh-&gt;selectcol_arrayref(
+        &quot;SELECT group_id, membercontrol
+           FROM group_control_map
+                INNER JOIN groups ON group_control_map.group_id = groups.id
+          WHERE isbuggroup = 1 AND isactive = 1 AND product_id = ?
+                AND (membercontrol = $shown OR membercontrol = $default)
+                AND &quot; . Bugzilla-&gt;user-&gt;groups_in_sql(),
+        {Columns=&gt;[1,2]}, $self-&gt;id) };
+    # We don't need to check the group membership here, because we only
+    # add these groups to the list below if the group isn't already listed
+    # for membercontrol.
+    my %other_groups = @{ $dbh-&gt;selectcol_arrayref(
+        &quot;SELECT group_id, othercontrol
+           FROM group_control_map
+                INNER JOIN groups ON group_control_map.group_id = groups.id
+          WHERE isbuggroup = 1 AND isactive = 1 AND product_id = ?
+                AND (othercontrol = $shown OR othercontrol = $default)&quot;, 
+        {Columns=&gt;[1,2]}, $self-&gt;id) };
+
+    # If the user is a member, then we use the membercontrol value.
+    # Otherwise, we use the othercontrol value.
+    my %all_groups = %member_groups;
+    foreach my $id (keys %other_groups) {
+        if (!defined $all_groups{$id}) {
+            $all_groups{$id} = $other_groups{$id};
+        }
+    }
+
+    my $available = Bugzilla::Group-&gt;new_from_list([keys %all_groups]);
+    foreach my $group (@$available) {
+        $group-&gt;{is_default} = 1 if $all_groups{$group-&gt;id} == $default;
+    }
+
+    $self-&gt;{groups_available} = $available;
+    return $self-&gt;{groups_available};
+}
+
+sub groups_mandatory {
+    my ($self) = @_;
+    return $self-&gt;{groups_mandatory} if $self-&gt;{groups_mandatory};
+    my $groups = Bugzilla-&gt;user-&gt;groups_as_string;
</ins><span class="cx">     my $mandatory = CONTROLMAPMANDATORY;
</span><span class="cx">     # For membercontrol we don't check group_id IN, because if membercontrol
</span><span class="cx">     # is Mandatory, the group is Mandatory for everybody, regardless of their
</span><span class="cx">     # group membership.
</span><span class="cx">     my $ids = Bugzilla-&gt;dbh-&gt;selectcol_arrayref(
</span><del>-        &quot;SELECT group_id FROM group_control_map
-          WHERE product_id = ?
</del><ins>+        &quot;SELECT group_id 
+           FROM group_control_map
+                INNER JOIN groups ON group_control_map.group_id = groups.id
+          WHERE product_id = ? AND isactive = 1
</ins><span class="cx">                 AND (membercontrol = $mandatory
</span><span class="cx">                      OR (othercontrol = $mandatory
</span><span class="cx">                          AND group_id NOT IN ($groups)))&quot;,
</span><span class="cx">         undef, $self-&gt;id);
</span><del>-    return Bugzilla::Group-&gt;new_from_list($ids);
</del><ins>+    $self-&gt;{groups_mandatory} = Bugzilla::Group-&gt;new_from_list($ids);
+    return $self-&gt;{groups_mandatory};
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# We don't just check groups_valid, because we want to know specifically
+# if this group can be validly set by the currently-logged-in user.
+sub group_is_settable {
+    my ($self, $group) = @_;
+
+    return 0 unless ($group-&gt;is_active &amp;&amp; $group-&gt;is_bug_group);
+
+    my $is_mandatory = grep { $group-&gt;id == $_-&gt;id }
+                            @{ $self-&gt;groups_mandatory };
+    my $is_available = grep { $group-&gt;id == $_-&gt;id }
+                            @{ $self-&gt;groups_available };
+    return ($is_mandatory or $is_available) ? 1 : 0;
+}
+
+sub group_is_valid {
+    my ($self, $group) = @_;
+    return grep($_-&gt;id == $group-&gt;id, @{ $self-&gt;groups_valid }) ? 1 : 0;
+}
+
</ins><span class="cx"> sub groups_valid {
</span><span class="cx">     my ($self) = @_;
</span><span class="cx">     return $self-&gt;{groups_valid} if defined $self-&gt;{groups_valid};
</span><span class="lines">@@ -232,32 +781,53 @@
</span><span class="cx"> sub flag_types {
</span><span class="cx">     my $self = shift;
</span><span class="cx"> 
</span><del>-    if (!defined $self-&gt;{'flag_types'}) {
-        $self-&gt;{'flag_types'} = {};
-        foreach my $type ('bug', 'attachment') {
-            my %flagtypes;
-            foreach my $component (@{$self-&gt;components}) {
-                foreach my $flagtype (@{$component-&gt;flag_types-&gt;{$type}}) {
-                    $flagtypes{$flagtype-&gt;{'id'}} ||= $flagtype;
-                }
</del><ins>+    return $self-&gt;{'flag_types'} if defined $self-&gt;{'flag_types'};
+
+    # We cache flag types to avoid useless calls to get_clusions().
+    my $cache = Bugzilla-&gt;request_cache-&gt;{flag_types_per_product} ||= {};
+    $self-&gt;{flag_types} = {};
+    my $prod_id = $self-&gt;id;
+    my $flagtypes = Bugzilla::FlagType::match({ product_id =&gt; $prod_id });
+
+    foreach my $type ('bug', 'attachment') {
+        my @flags = grep { $_-&gt;target_type eq $type } @$flagtypes;
+        $self-&gt;{flag_types}-&gt;{$type} = \@flags;
+
+        # Also populate component flag types, while we are here.
+        foreach my $comp (@{$self-&gt;components}) {
+            $comp-&gt;{flag_types} ||= {};
+            my $comp_id = $comp-&gt;id;
+
+            foreach my $flag (@flags) {
+                my $flag_id = $flag-&gt;id;
+                $cache-&gt;{$flag_id} ||= $flag;
+                my $i = $cache-&gt;{$flag_id}-&gt;inclusions_as_hash;
+                my $e = $cache-&gt;{$flag_id}-&gt;exclusions_as_hash;
+                my $included = $i-&gt;{0}-&gt;{0} || $i-&gt;{0}-&gt;{$comp_id}
+                               || $i-&gt;{$prod_id}-&gt;{0} || $i-&gt;{$prod_id}-&gt;{$comp_id};
+                my $excluded = $e-&gt;{0}-&gt;{0} || $e-&gt;{0}-&gt;{$comp_id}
+                               || $e-&gt;{$prod_id}-&gt;{0} || $e-&gt;{$prod_id}-&gt;{$comp_id};
+                push(@{$comp-&gt;{flag_types}-&gt;{$type}}, $flag) if ($included &amp;&amp; !$excluded);
</ins><span class="cx">             }
</span><del>-            $self-&gt;{'flag_types'}-&gt;{$type} = [sort { $a-&gt;{'sortkey'} &lt;=&gt; $b-&gt;{'sortkey'}
-                                                    || $a-&gt;{'name'} cmp $b-&gt;{'name'} } values %flagtypes];
</del><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     return $self-&gt;{'flag_types'};
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub classification {
+    my $self = shift;
+    $self-&gt;{'classification'} ||= 
+        new Bugzilla::Classification($self-&gt;classification_id);
+    return $self-&gt;{'classification'};
+}
+
</ins><span class="cx"> ###############################
</span><span class="cx"> ####      Accessors      ######
</span><span class="cx"> ###############################
</span><span class="cx"> 
</span><ins>+sub allows_unconfirmed { return $_[0]-&gt;{'allows_unconfirmed'}; }
</ins><span class="cx"> sub description       { return $_[0]-&gt;{'description'};       }
</span><del>-sub milestone_url     { return $_[0]-&gt;{'milestoneurl'};      }
-sub disallow_new      { return $_[0]-&gt;{'disallownew'};       }
-sub votes_per_user    { return $_[0]-&gt;{'votesperuser'};      }
-sub max_votes_per_bug { return $_[0]-&gt;{'maxvotesperbug'};    }
-sub votes_to_confirm  { return $_[0]-&gt;{'votestoconfirm'};    }
</del><ins>+sub is_active         { return $_[0]-&gt;{'isactive'};       }
</ins><span class="cx"> sub default_milestone { return $_[0]-&gt;{'defaultmilestone'};  }
</span><span class="cx"> sub classification_id { return $_[0]-&gt;{'classification_id'}; }
</span><span class="cx"> 
</span><span class="lines">@@ -265,17 +835,19 @@
</span><span class="cx"> ####      Subroutines    ######
</span><span class="cx"> ###############################
</span><span class="cx"> 
</span><del>-sub check_product {
-    my ($product_name) = @_;
</del><ins>+sub check {
+    my ($class, $params) = @_;
+    $params = { name =&gt; $params } if !ref $params;
+    if (!$params-&gt;{allow_inaccessible}) {
+        $params-&gt;{_error} = 'product_access_denied';
+    }
+    my $product = $class-&gt;SUPER::check($params);
</ins><span class="cx"> 
</span><del>-    unless ($product_name) {
-        ThrowUserError('product_not_specified');
</del><ins>+    if (!$params-&gt;{allow_inaccessible}
+        &amp;&amp; !Bugzilla-&gt;user-&gt;can_access_product($product))
+    {
+        ThrowUserError('product_access_denied', $params);
</ins><span class="cx">     }
</span><del>-    my $product = new Bugzilla::Product({name =&gt; $product_name});
-    unless ($product) {
-        ThrowUserError('product_doesnt_exist',
-                       {'product' =&gt; $product_name});
-    }
</del><span class="cx">     return $product;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -302,17 +874,15 @@
</span><span class="cx">     my $bug_ids         = $product-&gt;bug_ids();
</span><span class="cx">     my $has_access      = $product-&gt;user_has_access($user);
</span><span class="cx">     my $flag_types      = $product-&gt;flag_types();
</span><ins>+    my $classification  = $product-&gt;classification();
</ins><span class="cx"> 
</span><span class="cx">     my $id               = $product-&gt;id;
</span><span class="cx">     my $name             = $product-&gt;name;
</span><span class="cx">     my $description      = $product-&gt;description;
</span><del>-    my $milestoneurl     = $product-&gt;milestone_url;
-    my disallownew       = $product-&gt;disallow_new;
-    my votesperuser      = $product-&gt;votes_per_user;
-    my maxvotesperbug    = $product-&gt;max_votes_per_bug;
-    my votestoconfirm    = $product-&gt;votes_to_confirm;
</del><ins>+    my isactive          = $product-&gt;is_active;
</ins><span class="cx">     my $defaultmilestone = $product-&gt;default_milestone;
</span><span class="cx">     my $classificationid = $product-&gt;classification_id;
</span><ins>+    my $allows_unconfirmed = $product-&gt;allows_unconfirmed;
</ins><span class="cx"> 
</span><span class="cx"> =head1 DESCRIPTION
</span><span class="cx"> 
</span><span class="lines">@@ -341,28 +911,56 @@
</span><span class="cx">  Description: Returns a hash (group id as key) with all product
</span><span class="cx">               group controls.
</span><span class="cx"> 
</span><del>- Params:      none.
</del><ins>+ Params:      $full_data (optional, false by default) - when true,
+              the number of bugs per group applicable to the product
+              is also returned. Moreover, bug groups which have no
+              special settings for the product are also returned.
</ins><span class="cx"> 
</span><span class="cx">  Returns:     A hash with group id as key and hash containing 
</span><span class="cx">               a Bugzilla::Group object and the properties of group
</span><span class="cx">               relative to the product.
</span><span class="cx"> 
</span><del>-=item C&lt;groups_mandatory_for&gt;
</del><ins>+=item C&lt;groups_available&gt;
</ins><span class="cx"> 
</span><ins>+Tells you what groups are set to Default or Shown for the 
+currently-logged-in user (taking into account both OtherControl and
+MemberControl). Returns an arrayref of L&lt;Bugzilla::Group&gt; objects with
+an extra hash keys set, C&lt;is_default&gt;, which is true if the group
+is set to Default for the currently-logged-in user.
+
+=item C&lt;groups_mandatory&gt;
+
+Tells you what groups are mandatory for bugs in this product, for the
+currently-logged-in user. Returns an arrayref of C&lt;Bugzilla::Group&gt; objects.
+
+=item C&lt;group_is_settable&gt;
+
</ins><span class="cx"> =over
</span><span class="cx"> 
</span><span class="cx"> =item B&lt;Description&gt;
</span><span class="cx"> 
</span><del>-Tells you what groups are mandatory for bugs in this product.
</del><ins>+Tells you whether or not the currently-logged-in user can set a group
+on a bug (whether or not they match the MemberControl/OtherControl
+settings for a group in this product). Groups that are C&lt;Mandatory&gt; for
+the currently-loggeed-in user are also acceptable since from Bugzilla's
+perspective, there's no problem with &quot;setting&quot; a Mandatory group on
+a bug. (In fact, the user I&lt;must&gt; set the Mandatory group on the bug.)
</ins><span class="cx"> 
</span><span class="cx"> =item B&lt;Params&gt;
</span><span class="cx"> 
</span><del>-C&lt;$user&gt; - The user who you want to check.
</del><ins>+=over
</ins><span class="cx"> 
</span><del>-=item B&lt;Returns&gt; An arrayref of C&lt;Bugzilla::Group&gt; objects.
</del><ins>+=item C&lt;$group&gt; - A L&lt;Bugzilla::Group&gt; object.
</ins><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><ins>+=item B&lt;Returns&gt;
+
+C&lt;1&gt; if the group is valid in this product, C&lt;0&gt; otherwise.
+
+=back
+
+
</ins><span class="cx"> =item C&lt;groups_valid&gt;
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="lines">@@ -371,7 +969,9 @@
</span><span class="cx"> 
</span><span class="cx"> Returns an arrayref of L&lt;Bugzilla::Group&gt; objects, representing groups
</span><span class="cx"> that bugs could validly be restricted to within this product. Used mostly
</span><del>-by L&lt;Bugzilla::Bug&gt; to assure that you're adding valid groups to a bug.
</del><ins>+when you need the list of all possible groups that could be set in a product
+by anybody, disregarding whether or not the groups are active or who the
+currently logged-in user is.
</ins><span class="cx"> 
</span><span class="cx"> B&lt;Note&gt;: This doesn't check whether or not the current user can add/remove
</span><span class="cx"> bugs to/from these groups. It just tells you that bugs I&lt;could be in&gt; these
</span><span class="lines">@@ -383,6 +983,13 @@
</span><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><ins>+=item C&lt;group_is_valid&gt;
+
+Returns C&lt;1&gt; if the passed-in L&lt;Bugzilla::Group&gt; or group id could be set
+on a bug by I&lt;anybody&gt;, in this product. Even inactive groups are considered
+valid. (This is a shortcut for searching L&lt;/groups_valid&gt; to find out if
+a group is valid in a particular product.)
+
</ins><span class="cx"> =item C&lt;versions&gt;
</span><span class="cx"> 
</span><span class="cx">  Description: Returns all valid versions for that product.
</span><span class="lines">@@ -436,6 +1043,14 @@
</span><span class="cx"> 
</span><span class="cx">  Returns:     Two references to an array of flagtype objects.
</span><span class="cx"> 
</span><ins>+=item C&lt;classification()&gt;
+
+ Description: Returns the classification the product belongs to.
+
+ Params:      none.
+
+ Returns:     A Bugzilla::Classification object.
+
</ins><span class="cx"> =back
</span><span class="cx"> 
</span><span class="cx"> =head1 SUBROUTINES
</span><span class="lines">@@ -448,18 +1063,12 @@
</span><span class="cx"> L&lt;/milestones&gt;, L&lt;/components&gt;, and L&lt;/versions&gt;, which is much faster
</span><span class="cx"> than calling those accessors on every item in the array individually.
</span><span class="cx"> 
</span><ins>+If the 2nd argument passed to C&lt;preload&gt; is true, flag types for these
+products and their components are also preloaded.
+
</ins><span class="cx"> This function is not exported, so must be called like 
</span><span class="cx"> C&lt;Bugzilla::Product::preload($products)&gt;.
</span><span class="cx"> 
</span><del>-=item C&lt;check_product($product_name)&gt;
-
- Description: Checks if the product name was passed in and if is a valid
-              product.
-
- Params:      $product_name - String with a product name.
-
- Returns:     Bugzilla::Product object.
-
</del><span class="cx"> =back
</span><span class="cx"> 
</span><span class="cx"> =head1 SEE ALSO
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaRNGpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/RNG.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/RNG.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/RNG.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,233 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Google Inc.
+# Portions created by the Initial Developer are Copyright (C) 2011
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s): 
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+package Bugzilla::RNG;
+use strict;
+use base qw(Exporter);
+use Bugzilla::Constants qw(ON_WINDOWS);
+
+use IO::File;
+use Math::Random::ISAAC;
+use if ON_WINDOWS, 'Win32::API';
+
+our $RNG;
+our @EXPORT_OK = qw(rand srand irand);
+
+# ISAAC, a 32-bit generator, should only be capable of generating numbers
+# between 0 and 2^32 - 1. We want _to_float to generate numbers possibly
+# including 0, but always less than 1.0. Dividing the integer produced
+# by irand() by this number should do that exactly.
+use constant DIVIDE_BY =&gt; 2**32;
+
+# How many bytes of seed to read.
+use constant SEED_SIZE =&gt; 16; # 128 bits.
+
+#################
+# Windows Stuff #
+#################
+
+# The type of cryptographic service provider we want to use.
+# This doesn't really matter for our purposes, so we just pick
+# PROV_RSA_FULL, which seems reasonable. For more info, see
+# http://msdn.microsoft.com/en-us/library/aa380244(v=VS.85).aspx
+use constant PROV_RSA_FULL =&gt; 1;
+
+# Flags for CryptGenRandom:
+# Don't ever display a UI to the user, just fail if one would be needed.
+use constant CRYPT_SILENT =&gt; 64;
+# Don't require existing public/private keypairs.
+use constant CRYPT_VERIFYCONTEXT =&gt; 0xF0000000;
+
+# For some reason, BOOLEAN doesn't work properly as a return type with 
+# Win32::API.
+use constant RTLGENRANDOM_PROTO =&gt; &lt;&lt;END;
+INT SystemFunction036(
+  PVOID RandomBuffer,
+  ULONG RandomBufferLength
+)
+END
+
+#################
+# RNG Functions #
+#################
+
+sub rand (;$) {
+    my ($limit) = @_;
+    my $int = irand();
+    return _to_float($int, $limit);
+}
+
+sub irand (;$) {
+    my ($limit) = @_;
+    Bugzilla::RNG::srand() if !defined $RNG;
+    my $int = $RNG-&gt;irand();
+    if (defined $limit) {
+        # We can't just use the mod operator because it will bias
+        # our output. Search for &quot;modulo bias&quot; on the Internet for
+        # details. This is slower than mod(), but does not have a bias,
+        # as demonstrated by Math::Random::Secure's uniform.t test.
+        return int(_to_float($int, $limit));
+    }
+    return $int;
+}
+
+sub srand (;$) {
+    my ($value) = @_;
+    # Remove any RNG that might already have been made.
+    $RNG = undef;
+    my %args;
+    if (defined $value) {
+        $args{seed} = $value;
+    }
+    $RNG = _create_rng(\%args);
+}
+
+sub _to_float {
+    my ($integer, $limit) = @_;
+    $limit ||= 1;
+    return ($integer / DIVIDE_BY) * $limit;
+}
+
+##########################
+# Seed and PRNG Creation #
+##########################
+
+sub _create_rng {
+    my ($params) = @_;
+
+    if (!defined $params-&gt;{seed}) {
+        $params-&gt;{seed} = _get_seed();
+    }
+
+    _check_seed($params-&gt;{seed});
+
+    my @seed_ints = unpack('L*', $params-&gt;{seed});
+
+    my $rng = Math::Random::ISAAC-&gt;new(@seed_ints);
+
+    # It's faster to skip the frontend interface of Math::Random::ISAAC
+    # and just use the backend directly. However, in case the internal
+    # code of Math::Random::ISAAC changes at some point, we do make sure
+    # that the {backend} element actually exists first.
+    return $rng-&gt;{backend} ? $rng-&gt;{backend} : $rng;
+}
+
+sub _check_seed {
+    my ($seed) = @_;
+    if (length($seed) &lt; 8) {
+        warn &quot;Your seed is less than 8 bytes (64 bits). It could be&quot;
+             . &quot; easy to crack&quot;;
+    }
+    # If it looks like we were seeded with a 32-bit integer, warn the
+    # user that they are making a dangerous, easily-crackable mistake.
+    elsif (length($seed) &lt;= 10 and $seed =~ /^\d+$/) {
+        warn &quot;RNG seeded with a 32-bit integer, this is easy to crack&quot;;
+    }
+}
+
+sub _get_seed {
+    return _windows_seed() if ON_WINDOWS;
+
+    if (-r '/dev/urandom') {
+        return _read_seed_from('/dev/urandom');
+    }
+
+    return _read_seed_from('/dev/random');
+}
+
+sub _read_seed_from {
+    my ($from) = @_;
+
+    my $fh = IO::File-&gt;new($from, &quot;r&quot;) or die &quot;$from: $!&quot;;
+    my $buffer;
+    $fh-&gt;read($buffer, SEED_SIZE);
+    if (length($buffer) &lt; SEED_SIZE) {
+        die &quot;Could not read enough seed bytes from $from, got only &quot; 
+            . length($buffer);
+    }
+    $fh-&gt;close;
+    return $buffer;
+}
+
+sub _windows_seed {
+    my ($major, $minor) = (Win32::GetOSVersion())[1,2];
+    if ($major &lt; 5) {
+        die &quot;Bugzilla does not support versions of Windows before&quot;
+            . &quot; Windows 2000&quot;;
+    }
+    # This means Windows 2000.
+    if ($major == 5 and $minor == 0) {
+        return _win2k_seed();
+    }
+
+    my $rtlgenrand = Win32::API-&gt;new('advapi32', RTLGENRANDOM_PROTO);
+    if (!defined $rtlgenrand) {
+        die &quot;Could not import RtlGenRand: $^E&quot;;
+    }
+    my $buffer = chr(0) x SEED_SIZE;
+    my $result = $rtlgenrand-&gt;Call($buffer, SEED_SIZE);
+    if (!$result) {
+        die &quot;RtlGenRand failed: $^E&quot;;
+    }
+    return $buffer;
+}
+
+sub _win2k_seed {
+    my $crypt_acquire = Win32::API-&gt;new(
+        &quot;advapi32&quot;, 'CryptAcquireContext', 'PPPNN', 'I');
+    if (!defined $crypt_acquire) {
+        die &quot;Could not import CryptAcquireContext: $^E&quot;;
+    }
+
+    my $crypt_release = Win32::API-&gt;new(
+        &quot;advapi32&quot;, 'CryptReleaseContext', 'NN', 'I');
+    if (!defined $crypt_release) {
+        die &quot;Could not import CryptReleaseContext: $^E&quot;;
+    }
+
+    my $crypt_gen_random = Win32::API-&gt;new(
+        &quot;advapi32&quot;, 'CryptGenRandom', 'NNP', 'I');
+    if (!defined $crypt_gen_random) {
+        die &quot;Could not import CryptGenRandom: $^E&quot;;
+    }
+
+    my $context = chr(0) x Win32::API::Type-&gt;sizeof('PULONG');
+    my $acquire_result = $crypt_acquire-&gt;Call(
+        $context, 0, 0, PROV_RSA_FULL, CRYPT_SILENT | CRYPT_VERIFYCONTEXT);
+    if (!defined $acquire_result) {
+        die &quot;CryptAcquireContext failed: $^E&quot;;
+    }
+
+    my $pack_type = Win32::API::Type::packing('PULONG');
+    $context = unpack($pack_type, $context);
+
+    my $buffer = chr(0) x SEED_SIZE;
+    my $rand_result = $crypt_gen_random-&gt;Call($context, SEED_SIZE, $buffer);
+    my $rand_error = $^E;
+    # We don't check this if it fails, we don't care.
+    $crypt_release-&gt;Call($context, 0);
+    if (!defined $rand_result) {
+        die &quot;CryptGenRandom failed: $rand_error&quot;;
+    }
+    return $buffer;
+}
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaSearchClausepm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/Search/Clause.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Search/Clause.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Search/Clause.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,138 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is BugzillaSource, Inc.
+# Portions created by the Initial Developer are Copyright (C) 2011 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+package Bugzilla::Search::Clause;
+use strict;
+
+use Bugzilla::Error;
+use Bugzilla::Search::Condition qw(condition);
+use Bugzilla::Util qw(trick_taint);
+
+sub new {
+    my ($class, $joiner) = @_;
+    if ($joiner and $joiner ne 'OR' and $joiner ne 'AND') {
+        ThrowCodeError('search_invalid_joiner', { joiner =&gt; $joiner });
+    }
+    # This will go into SQL directly so needs to be untainted.
+    trick_taint($joiner) if $joiner;
+    bless { joiner =&gt; $joiner || 'AND' }, $class;
+}
+
+sub children {
+    my ($self) = @_;
+    $self-&gt;{children} ||= [];
+    return $self-&gt;{children};
+}
+
+sub joiner { return $_[0]-&gt;{joiner} }
+
+sub has_translated_conditions {
+    my ($self) = @_;
+    my $children = $self-&gt;children;
+    return 1 if grep { $_-&gt;isa('Bugzilla::Search::Condition')
+                       &amp;&amp; $_-&gt;translated } @$children;
+    foreach my $child (@$children) {
+        next if $child-&gt;isa('Bugzilla::Search::Condition');
+        return 1 if $child-&gt;has_translated_conditions;
+    }
+    return 0;
+}
+
+sub add {
+    my $self = shift;
+    my $children = $self-&gt;children;
+    if (@_ == 3) {
+        push(@$children, condition(@_));
+        return;
+    }
+    
+    my ($child) = @_;
+    return if !defined $child;
+    $child-&gt;isa(__PACKAGE__) || $child-&gt;isa('Bugzilla::Search::Condition')
+        || die 'child not the right type: ' . $child;
+    push(@{ $self-&gt;children }, $child);
+}
+
+sub negate {
+    my ($self, $value) = @_;
+    if (@_ == 2) {
+        $self-&gt;{negate} = $value ? 1 : 0;
+    }
+    return $self-&gt;{negate};
+}
+
+sub walk_conditions {
+    my ($self, $callback) = @_;
+    foreach my $child (@{ $self-&gt;children }) {
+        if ($child-&gt;isa('Bugzilla::Search::Condition')) {
+            $callback-&gt;($child);
+        }
+        else {
+            $child-&gt;walk_conditions($callback);
+        }
+    }
+}
+
+sub as_string {
+    my ($self) = @_;
+    my @strings;
+    foreach my $child (@{ $self-&gt;children }) {
+        next if $child-&gt;isa(__PACKAGE__) &amp;&amp; !$child-&gt;has_translated_conditions;
+        next if $child-&gt;isa('Bugzilla::Search::Condition')
+                &amp;&amp; !$child-&gt;translated;
+
+        my $string = $child-&gt;as_string;
+        if ($self-&gt;joiner eq 'AND') {
+            $string = &quot;( $string )&quot; if $string =~ /OR/;
+        }
+        else {
+            $string = &quot;( $string )&quot; if $string =~ /AND/;
+        }
+        push(@strings, $string);
+    }
+    
+    my $sql = join(' ' . $self-&gt;joiner . ' ', @strings);
+    $sql = &quot;NOT( $sql )&quot; if $sql &amp;&amp; $self-&gt;negate;
+    return $sql;
+}
+
+# Search.pm converts URL parameters to Clause objects. This helps do the
+# reverse.
+sub as_params {
+    my ($self) = @_;
+    my @params;
+    foreach my $child (@{ $self-&gt;children }) {
+        if ($child-&gt;isa(__PACKAGE__)) {
+            my %open_paren = (f =&gt; 'OP', n =&gt; scalar $child-&gt;negate,
+                              j =&gt; $child-&gt;joiner);
+            push(@params, \%open_paren);
+            push(@params, $child-&gt;as_params);
+            my %close_paren =  (f =&gt; 'CP');
+            push(@params, \%close_paren);
+        }
+        else {
+            push(@params, $child-&gt;as_params);
+        }
+    }
+    return @params;
+}
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaSearchConditionpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/Search/Condition.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Search/Condition.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Search/Condition.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,82 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is BugzillaSource, Inc.
+# Portions created by the Initial Developer are Copyright (C) 2011 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+package Bugzilla::Search::Condition;
+use strict;
+use base qw(Exporter);
+our @EXPORT_OK = qw(condition);
+
+sub new {
+    my ($class, $params) = @_;
+    my %self = %$params;
+    bless \%self, $class;
+    return \%self;
+}
+
+sub field    { return $_[0]-&gt;{field}    }
+sub operator { return $_[0]-&gt;{operator} }
+sub value    { return $_[0]-&gt;{value}    }
+
+sub fov {
+    my ($self) = @_;
+    return ($self-&gt;field, $self-&gt;operator, $self-&gt;value);
+}
+
+sub translated {
+    my ($self, $params) = @_;
+    if (@_ == 2) {
+        $self-&gt;{translated} = $params;
+    }
+    return $self-&gt;{translated};
+}
+
+sub as_string {
+    my ($self) = @_;
+    my $term = $self-&gt;translated-&gt;{term};
+    $term = &quot;NOT( $term )&quot; if $term &amp;&amp; $self-&gt;negate;
+    return $term;
+}
+
+sub as_params {
+    my ($self) = @_;
+    return { f =&gt; $self-&gt;field, o =&gt; $self-&gt;operator, v =&gt; $self-&gt;value,
+             n =&gt; scalar $self-&gt;negate };
+}
+
+sub negate {
+    my ($self, $value) = @_;
+    if (@_ == 2) {
+        $self-&gt;{negate} = $value ? 1 : 0;
+    }
+    return $self-&gt;{negate};
+}
+
+###########################
+# Convenience Subroutines #
+###########################
+
+sub condition {
+    my ($field, $operator, $value) = @_;
+    return __PACKAGE__-&gt;new({ field =&gt; $field, operator =&gt; $operator,
+                              value =&gt; $value });
+}
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaSearchQuicksearchpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Search/Quicksearch.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Search/Quicksearch.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Search/Quicksearch.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -30,73 +30,93 @@
</span><span class="cx"> use Bugzilla::Field;
</span><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> 
</span><ins>+use List::Util qw(min max);
+use List::MoreUtils qw(firstidx);
+use Text::ParseWords qw(parse_line);
+
</ins><span class="cx"> use base qw(Exporter);
</span><span class="cx"> @Bugzilla::Search::Quicksearch::EXPORT = qw(quicksearch);
</span><span class="cx"> 
</span><del>-# Word renamings
</del><ins>+# Custom mappings for some fields.
</ins><span class="cx"> use constant MAPPINGS =&gt; {
</span><del>-                # Status, Resolution, Platform, OS, Priority, Severity
-                &quot;status&quot; =&gt; &quot;bug_status&quot;,
-                &quot;resolution&quot; =&gt; &quot;resolution&quot;,  # no change
-                &quot;platform&quot; =&gt; &quot;rep_platform&quot;,
-                &quot;os&quot; =&gt; &quot;op_sys&quot;,
-                &quot;opsys&quot; =&gt; &quot;op_sys&quot;,
-                &quot;priority&quot; =&gt; &quot;priority&quot;,    # no change
-                &quot;pri&quot; =&gt; &quot;priority&quot;,
-                &quot;severity&quot; =&gt; &quot;bug_severity&quot;,
-                &quot;sev&quot; =&gt; &quot;bug_severity&quot;,
-                # People: AssignedTo, Reporter, QA Contact, CC, Added comment (?)
-                &quot;owner&quot; =&gt; &quot;assigned_to&quot;,    # deprecated since bug 76507
-                &quot;assignee&quot; =&gt; &quot;assigned_to&quot;,
-                &quot;assignedto&quot; =&gt; &quot;assigned_to&quot;,
-                &quot;reporter&quot; =&gt; &quot;reporter&quot;,    # no change
-                &quot;rep&quot; =&gt; &quot;reporter&quot;,
-                &quot;qa&quot; =&gt; &quot;qa_contact&quot;,
-                &quot;qacontact&quot; =&gt; &quot;qa_contact&quot;,
-                &quot;cc&quot; =&gt; &quot;cc&quot;,          # no change
-                # Product, Version, Component, Target Milestone
-                &quot;product&quot; =&gt; &quot;product&quot;,     # no change
-                &quot;prod&quot; =&gt; &quot;product&quot;,
-                &quot;version&quot; =&gt; &quot;version&quot;,     # no change
-                &quot;ver&quot; =&gt; &quot;version&quot;,
-                &quot;component&quot; =&gt; &quot;component&quot;,   # no change
-                &quot;comp&quot; =&gt; &quot;component&quot;,
-                &quot;milestone&quot; =&gt; &quot;target_milestone&quot;,
-                &quot;target&quot; =&gt; &quot;target_milestone&quot;,
-                &quot;targetmilestone&quot; =&gt; &quot;target_milestone&quot;,
-                # Summary, Description, URL, Status whiteboard, Keywords
-                &quot;summary&quot; =&gt; &quot;short_desc&quot;,
-                &quot;shortdesc&quot; =&gt; &quot;short_desc&quot;,
-                &quot;desc&quot; =&gt; &quot;longdesc&quot;,
-                &quot;description&quot; =&gt; &quot;longdesc&quot;,
-                #&quot;comment&quot; =&gt; &quot;longdesc&quot;,    # ???
-                          # reserve &quot;comment&quot; for &quot;added comment&quot; email search?
-                &quot;longdesc&quot; =&gt; &quot;longdesc&quot;,
-                &quot;url&quot; =&gt; &quot;bug_file_loc&quot;,
-                &quot;whiteboard&quot; =&gt; &quot;status_whiteboard&quot;,
-                &quot;statuswhiteboard&quot; =&gt; &quot;status_whiteboard&quot;,
-                &quot;sw&quot; =&gt; &quot;status_whiteboard&quot;,
-                &quot;keywords&quot; =&gt; &quot;keywords&quot;,    # no change
-                &quot;kw&quot; =&gt; &quot;keywords&quot;,
-                &quot;group&quot; =&gt; &quot;bug_group&quot;,
-                &quot;flag&quot; =&gt; &quot;flagtypes.name&quot;,
-                &quot;requestee&quot; =&gt; &quot;requestees.login_name&quot;,
-                &quot;req&quot; =&gt; &quot;requestees.login_name&quot;,
-                &quot;setter&quot; =&gt; &quot;setters.login_name&quot;,
-                &quot;set&quot; =&gt; &quot;setters.login_name&quot;,
-                # Attachments
-                &quot;attachment&quot; =&gt; &quot;attachments.description&quot;,
-                &quot;attachmentdesc&quot; =&gt; &quot;attachments.description&quot;,
-                &quot;attachdesc&quot; =&gt; &quot;attachments.description&quot;,
-                &quot;attachmentdata&quot; =&gt; &quot;attach_data.thedata&quot;,
-                &quot;attachdata&quot; =&gt; &quot;attach_data.thedata&quot;,
-                &quot;attachmentmimetype&quot; =&gt; &quot;attachments.mimetype&quot;,
-                &quot;attachmimetype&quot; =&gt; &quot;attachments.mimetype&quot;
</del><ins>+    # Status, Resolution, Platform, OS, Priority, Severity
+    &quot;status&quot;   =&gt; &quot;bug_status&quot;,
+    &quot;platform&quot; =&gt; &quot;rep_platform&quot;,
+    &quot;os&quot;       =&gt; &quot;op_sys&quot;,
+    &quot;severity&quot; =&gt; &quot;bug_severity&quot;,
+
+    # People: AssignedTo, Reporter, QA Contact, CC, etc.
+    &quot;assignee&quot; =&gt; &quot;assigned_to&quot;,
+    &quot;owner&quot;    =&gt; &quot;assigned_to&quot;,
+
+    # Product, Version, Component, Target Milestone
+    &quot;milestone&quot; =&gt; &quot;target_milestone&quot;,
+
+    # Summary, Description, URL, Status whiteboard, Keywords
+    &quot;summary&quot;     =&gt; &quot;short_desc&quot;,
+    &quot;description&quot; =&gt; &quot;longdesc&quot;,
+    &quot;comment&quot;     =&gt; &quot;longdesc&quot;,
+    &quot;url&quot;         =&gt; &quot;bug_file_loc&quot;,
+    &quot;whiteboard&quot;  =&gt; &quot;status_whiteboard&quot;,
+    &quot;sw&quot;          =&gt; &quot;status_whiteboard&quot;,
+    &quot;kw&quot;          =&gt; &quot;keywords&quot;,
+    &quot;group&quot;       =&gt; &quot;bug_group&quot;,
+
+    # Flags
+    &quot;flag&quot;        =&gt; &quot;flagtypes.name&quot;,
+    &quot;requestee&quot;   =&gt; &quot;requestees.login_name&quot;,
+    &quot;setter&quot;      =&gt; &quot;setters.login_name&quot;,
+
+    # Attachments
+    &quot;attachment&quot;     =&gt; &quot;attachments.description&quot;,
+    &quot;attachmentdesc&quot; =&gt; &quot;attachments.description&quot;,
+    &quot;attachdesc&quot;     =&gt; &quot;attachments.description&quot;,
+    &quot;attachmentdata&quot; =&gt; &quot;attach_data.thedata&quot;,
+    &quot;attachdata&quot;     =&gt; &quot;attach_data.thedata&quot;,
+    &quot;attachmentmimetype&quot; =&gt; &quot;attachments.mimetype&quot;,
+    &quot;attachmimetype&quot; =&gt; &quot;attachments.mimetype&quot;
</ins><span class="cx"> };
</span><span class="cx"> 
</span><ins>+sub FIELD_MAP {
+    my $cache = Bugzilla-&gt;request_cache;
+    return $cache-&gt;{quicksearch_fields} if $cache-&gt;{quicksearch_fields};
+
+    # Get all the fields whose names don't contain periods. (Fields that
+    # contain periods are always handled in MAPPINGS.) 
+    my @db_fields = grep { $_-&gt;name !~ /\./ } 
+                         @{ Bugzilla-&gt;fields({ obsolete =&gt; 0 }) };
+    my %full_map = (%{ MAPPINGS() }, map { $_-&gt;name =&gt; $_-&gt;name } @db_fields);
+
+    # Eliminate the fields that start with bug_ or rep_, because those are
+    # handled by the MAPPINGS instead, and we don't want too many names
+    # for them. (Also, otherwise &quot;rep&quot; doesn't match &quot;reporter&quot;.)
+    #
+    # Remove &quot;status_whiteboard&quot; because we have &quot;whiteboard&quot; for it in
+    # the mappings, and otherwise &quot;stat&quot; can't match &quot;status&quot;.
+    #
+    # Also, don't allow searching the _accessible stuff via quicksearch
+    # (both because it's unnecessary and because otherwise 
+    # &quot;reporter_accessible&quot; and &quot;reporter&quot; both match &quot;rep&quot;.
+    delete @full_map{qw(rep_platform bug_status bug_file_loc bug_group
+                        bug_severity bug_status
+                        status_whiteboard
+                        cclist_accessible reporter_accessible)};
+
+    Bugzilla::Hook::process('quicksearch_map', {'map' =&gt; \%full_map} );
+
+    $cache-&gt;{quicksearch_fields} = \%full_map;
+
+    return $cache-&gt;{quicksearch_fields};
+}
+
+# Certain fields, when specified like &quot;field:value&quot; get an operator other
+# than &quot;substring&quot;
+use constant FIELD_OPERATOR =&gt; {
+    content         =&gt; 'matches',
+    owner_idle_time =&gt; 'greaterthan',
+};
+
</ins><span class="cx"> # We might want to put this into localconfig or somewhere
</span><del>-use constant PLATFORMS =&gt; ('pc', 'sun', 'macintosh', 'mac');
-use constant OPSYSTEMS =&gt; ('windows', 'win', 'linux');
</del><span class="cx"> use constant PRODUCT_EXCEPTIONS =&gt; (
</span><span class="cx">     'row',   # [Browser]
</span><span class="cx">              #   ^^^
</span><span class="lines">@@ -109,12 +129,11 @@
</span><span class="cx"> );
</span><span class="cx"> 
</span><span class="cx"> # Quicksearch-wide globals for boolean charts.
</span><del>-our ($chart, $and, $or);
</del><ins>+our ($chart, $and, $or, $fulltext, $bug_status_set);
</ins><span class="cx"> 
</span><span class="cx"> sub quicksearch {
</span><span class="cx">     my ($searchstring) = (@_);
</span><span class="cx">     my $cgi = Bugzilla-&gt;cgi;
</span><del>-    my $urlbase = correct_urlbase();
</del><span class="cx"> 
</span><span class="cx">     $chart = 0;
</span><span class="cx">     $and   = 0;
</span><span class="lines">@@ -125,281 +144,107 @@
</span><span class="cx">     ThrowUserError('buglist_parameters_required') unless ($searchstring);
</span><span class="cx"> 
</span><span class="cx">     if ($searchstring =~ m/^[0-9,\s]*$/) {
</span><del>-        # Bug number(s) only.
-
-        # Allow separation by comma or whitespace.
-        $searchstring =~ s/[,\s]+/,/g;
-
-        if (index($searchstring, ',') &lt; $[) {
-            # Single bug number; shortcut to show_bug.cgi.
-            print $cgi-&gt;redirect(-uri =&gt; &quot;${urlbase}show_bug.cgi?id=$searchstring&quot;);
-            exit;
-        }
-        else {
-            # List of bug numbers.
-            $cgi-&gt;param('bug_id', $searchstring);
-            $cgi-&gt;param('order', 'bugs.bug_id');
-            $cgi-&gt;param('bugidtype', 'include');
-        }
</del><ins>+        _bug_numbers_only($searchstring);
</ins><span class="cx">     }
</span><span class="cx">     else {
</span><del>-        # It's not just a bug number or a list of bug numbers.
-        # Maybe it's an alias?
-        if ($searchstring =~ /^([^,\s]+)$/) {
-            if (Bugzilla-&gt;dbh-&gt;selectrow_array(q{SELECT COUNT(*)
-                                                   FROM bugs
-                                                  WHERE alias = ?},
-                                               undef,
-                                               $1)) {
-                print $cgi-&gt;redirect(-uri =&gt; &quot;${urlbase}show_bug.cgi?id=$1&quot;);
-                exit;
-            }
-        }
</del><ins>+        _handle_alias($searchstring);
</ins><span class="cx"> 
</span><del>-        # It's no alias either, so it's a more complex query.
-        my $legal_statuses = get_legal_field_values('bug_status');
-        my $legal_resolutions = get_legal_field_values('resolution');
</del><ins>+        # Retain backslashes and quotes, to know which strings are quoted,
+        # and which ones are not.
+        my @words = parse_line('\s+', 1, $searchstring);
+        # If parse_line() returns no data, this means strings are badly quoted.
+        # Rather than trying to guess what the user wanted to do, we throw an error.
+        scalar(@words)
+          || ThrowUserError('quicksearch_unbalanced_quotes', {string =&gt; $searchstring});
</ins><span class="cx"> 
</span><del>-        # Globally translate &quot; AND &quot;, &quot; OR &quot;, &quot; NOT &quot; to space, pipe, dash.
-        $searchstring =~ s/\s+AND\s+/ /g;
-        $searchstring =~ s/\s+OR\s+/|/g;
-        $searchstring =~ s/\s+NOT\s+/ -/g;
</del><ins>+        # A query cannot start with AND or OR, nor can it end with AND, OR or NOT.
+        ThrowUserError('quicksearch_invalid_query')
+          if ($words[0] =~ /^(?:AND|OR)$/ || $words[$#words] =~ /^(?:AND|OR|NOT)$/);
</ins><span class="cx"> 
</span><del>-        my @words = splitString($searchstring);
-        my $searchComments = 
-            $#words &lt; Bugzilla-&gt;params-&gt;{'quicksearch_comment_cutoff'};
-        my @openStates = BUG_STATE_OPEN;
-        my @closedStates;
-        my @unknownFields;
-        my (%states, %resolutions);
-
-        foreach (@$legal_statuses) {
-            push(@closedStates, $_) unless is_open_state($_);
-        }
-        foreach (@openStates) { $states{$_} = 1 }
-        if ($words[0] eq 'ALL') {
-            foreach (@$legal_statuses) { $states{$_} = 1 }
-            shift @words;
-        }
-        elsif ($words[0] eq 'OPEN') {
-            shift @words;
-        }
-        elsif ($words[0] =~ /^\+[A-Z]+(,[A-Z]+)*$/) {
-            # e.g. +DUP,FIX
-            if (matchPrefixes(\%states,
-                              \%resolutions,
-                              [split(/,/, substr($words[0], 1))],
-                              \@closedStates,
-                              $legal_resolutions)) {
-                shift @words;
-                # Allowing additional resolutions means we need to keep
-                # the &quot;no resolution&quot; resolution.
-                $resolutions{'---'} = 1;
</del><ins>+        my (@qswords, @or_group);
+        while (scalar @words) {
+            my $word = shift @words;
+            # AND is the default word separator, similar to a whitespace,
+            # but |a AND OR b| is not a valid combination.
+            if ($word eq 'AND') {
+                ThrowUserError('quicksearch_invalid_query', {operators =&gt; ['AND', 'OR']})
+                  if $words[0] eq 'OR';
</ins><span class="cx">             }
</span><del>-            else {
-                # Carry on if no match found.
</del><ins>+            # |a OR AND b| is not a valid combination.
+            # |a OR OR b| is equivalent to |a OR b| and so is harmless.
+            elsif ($word eq 'OR') {
+                ThrowUserError('quicksearch_invalid_query', {operators =&gt; ['OR', 'AND']})
+                  if $words[0] eq 'AND';
</ins><span class="cx">             }
</span><del>-        }
-        elsif ($words[0] =~ /^[A-Z]+(,[A-Z]+)*$/) {
-            # e.g. NEW,ASSI,REOP,FIX
-            undef %states;
-            if (matchPrefixes(\%states,
-                              \%resolutions,
-                              [split(/,/, $words[0])],
-                              $legal_statuses,
-                              $legal_resolutions)) {
-                shift @words;
</del><ins>+            # NOT negates the following word.
+            # |NOT AND| and |NOT OR| are not valid combinations.
+            # |NOT NOT| is fine but has no effect as they cancel themselves.
+            elsif ($word eq 'NOT') {
+                $word = shift @words;
+                next if $word eq 'NOT';
+                if ($word eq 'AND' || $word eq 'OR') {
+                    ThrowUserError('quicksearch_invalid_query', {operators =&gt; ['NOT', $word]});
+                }
+                unshift(@words, &quot;-$word&quot;);
</ins><span class="cx">             }
</span><span class="cx">             else {
</span><del>-                # Carry on if no match found
-                foreach (@openStates) { $states{$_} = 1 }
</del><ins>+                # OR groups words together, as OR has higher precedence than AND.
+                push(@or_group, $word);
+                # If the next word is not OR, then we are not in a OR group,
+                # or we are leaving it.
+                if (!defined $words[0] || $words[0] ne 'OR') {
+                    push(@qswords, join('|', @or_group));
+                    @or_group = ();
+                }
</ins><span class="cx">             }
</span><span class="cx">         }
</span><del>-        else {
-            # Default: search for unresolved bugs only.
-            # Put custom code here if you would like to change this behaviour.
-        }
</del><span class="cx"> 
</span><del>-        # If we have wanted resolutions, allow closed states
-        if (keys(%resolutions)) {
-            foreach (@closedStates) { $states{$_} = 1 }
-        }
</del><ins>+        _handle_status_and_resolution($qswords[0]);
+        shift(@qswords) if $bug_status_set;
</ins><span class="cx"> 
</span><del>-        $cgi-&gt;param('bug_status', keys(%states));
-        $cgi-&gt;param('resolution', keys(%resolutions));
</del><ins>+        my (@unknownFields, %ambiguous_fields);
+        $fulltext = Bugzilla-&gt;user-&gt;setting('quicksearch_fulltext') eq 'on' ? 1 : 0;
</ins><span class="cx"> 
</span><span class="cx">         # Loop over all main-level QuickSearch words.
</span><del>-        foreach my $qsword (@words) {
-            my $negate = substr($qsword, 0, 1) eq '-';
-            if ($negate) {
-                $qsword = substr($qsword, 1);
-            }
-
-            my $firstChar = substr($qsword, 0, 1);
-            my $baseWord = substr($qsword, 1);
-            my @subWords = split(/[\|,]/, $baseWord);
-            if ($firstChar eq '+') {
-                foreach (@subWords) {
-                    addChart('short_desc', 'substring', $qsword, $negate);
</del><ins>+        foreach my $qsword (@qswords) {
+            my @or_operand = parse_line('\|', 1, $qsword);
+            foreach my $term (@or_operand) {
+                my $negate = substr($term, 0, 1) eq '-';
+                if ($negate) {
+                    $term = substr($term, 1);
</ins><span class="cx">                 }
</span><del>-            }
-            elsif ($firstChar eq '#') {
-                addChart('short_desc', 'anywords', $baseWord, $negate);
-                if ($searchComments) {
-                    addChart('longdesc', 'anywords', $baseWord, $negate);
-                }
-            }
-            elsif ($firstChar eq ':') {
-                foreach (@subWords) {
-                    addChart('product', 'substring', $_, $negate);
-                    addChart('component', 'substring', $_, $negate);
-                }
-            }
-            elsif ($firstChar eq '@') {
-                foreach (@subWords) {
-                    addChart('assigned_to', 'substring', $_, $negate);
-                }
-            }
-            elsif ($firstChar eq '[') {
-                addChart('short_desc', 'substring', $baseWord, $negate);
-                addChart('status_whiteboard', 'substring', $baseWord, $negate);
-            }
-            elsif ($firstChar eq '!') {
-                addChart('keywords', 'anywords', $baseWord, $negate);
</del><span class="cx"> 
</span><del>-            }
-            else { # No special first char
</del><ins>+                next if _handle_special_first_chars($term, $negate);
+                next if _handle_field_names($term, $negate, \@unknownFields,
+                                            \%ambiguous_fields);
</ins><span class="cx"> 
</span><del>-                # Split by '|' to get all operands for a boolean OR.
-                foreach my $or_operand (split(/\|/, $qsword)) {
-                    if ($or_operand =~ /^votes:([0-9]+)$/) {
-                        # votes:xx (&quot;at least xx votes&quot;)
-                        addChart('votes', 'greaterthan', $1 - 1, $negate);
</del><ins>+                # Having ruled out the special cases, we may now split
+                # by comma, which is another legal boolean OR indicator.
+                # Remove quotes from quoted words, if any.
+                @words = parse_line(',', 0, $term);
+                foreach my $word (@words) {
+                    if (!_special_field_syntax($word, $negate)) {
+                        _default_quicksearch_word($word, $negate);
</ins><span class="cx">                     }
</span><del>-                    elsif ($or_operand =~ /^(?:flag:)?([^\?]+\?)([^\?]*)$/) {
-                        # Flag and requestee shortcut
-                        addChart('flagtypes.name', 'substring', $1, $negate);
-                        $chart++; $and = $or = 0; # Next chart for boolean AND
-                        addChart('requestees.login_name', 'substring', $2, $negate);
-                    }
-                    elsif ($or_operand =~ /^([^:]+):([^:]+)$/) {
-                        # generic field1,field2,field3:value1,value2 notation
-                        my @fields = split(/,/, $1);
-                        my @values = split(/,/, $2);
-                        foreach my $field (@fields) {
-                            # Skip and record any unknown fields
-                            if (!defined(MAPPINGS-&gt;{$field})) {
-                                push(@unknownFields, $field);
-                                next;
-                            }
-                            $field = MAPPINGS-&gt;{$field};
-                            foreach (@values) {
-                                addChart($field, 'substring', $_, $negate);
-                            }
-                        }
-
-                    }
-                    else {
-
-                        # Having ruled out the special cases, we may now split
-                        # by comma, which is another legal boolean OR indicator.
-                        foreach my $word (split(/,/, $or_operand)) {
-                            # Platform and operating system
-                            if (grep({lc($word) eq $_} PLATFORMS)
-                                || grep({lc($word) eq $_} OPSYSTEMS)) {
-                                addChart('rep_platform', 'substring',
-                                         $word, $negate);
-                                addChart('op_sys', 'substring',
-                                         $word, $negate);
-                            }
-                            # Priority
-                            elsif ($word =~ m/^[pP]([1-5](-[1-5])?)$/) {
-                                addChart('priority', 'regexp',
-                                         &quot;[$1]&quot;, $negate);
-                            }
-                            # Severity
-                            elsif (grep({lc($word) eq substr($_, 0, 3)}
-                                        @{get_legal_field_values('bug_severity')})) {
-                                addChart('bug_severity', 'substring',
-                                         $word, $negate);
-                            }
-                            # Votes (votes&gt;xx)
-                            elsif ($word =~ m/^votes&gt;([0-9]+)$/) {
-                                addChart('votes', 'greaterthan',
-                                         $1, $negate);
-                            }
-                            # Votes (votes&gt;=xx, votes=&gt;xx)
-                            elsif ($word =~ m/^votes(&gt;=|=&gt;)([0-9]+)$/) {
-                                addChart('votes', 'greaterthan',
-                                         $2-1, $negate);
-
-                            }
-                            else { # Default QuickSearch word
-
-                                if (!grep({lc($word) eq $_}
-                                          PRODUCT_EXCEPTIONS) &amp;&amp;
-                                    length($word)&gt;2
-                                   ) {
-                                    addChart('product', 'substring',
-                                             $word, $negate);
-                                }
-                                if (!grep({lc($word) eq $_}
-                                          COMPONENT_EXCEPTIONS) &amp;&amp;
-                                    length($word)&gt;2
-                                   ) {
-                                    addChart('component', 'substring',
-                                             $word, $negate);
-                                }
-                                if (grep({lc($word) eq lc($_)}
-                                         map($_-&gt;name, Bugzilla::Keyword-&gt;get_all))) {
-                                    addChart('keywords', 'substring',
-                                             $word, $negate);
-                                    if (length($word)&gt;2) {
-                                        addChart('short_desc', 'substring',
-                                                 $word, $negate);
-                                        addChart('status_whiteboard',
-                                                 'substring',
-                                                 $word, $negate);
-                                    }
-
-                                }
-                                else {
-
-                                    addChart('short_desc', 'substring',
-                                             $word, $negate);
-                                    addChart('status_whiteboard', 'substring',
-                                             $word, $negate);
-                                }
-                                if ($searchComments) {
-                                    addChart('longdesc', 'substring',
-                                             $word, $negate);
-                                }
-                            }
-                            # URL field (for IP addrs, host.names,
-                            # scheme://urls)
-                            if ($word =~ m/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/
-                                  || $word =~ /^[A-Za-z]+(\.[A-Za-z]+)+/
-                                  || $word =~ /:[\\\/][\\\/]/
-                                  || $word =~ /localhost/
-                                  || $word =~ /mailto[:]?/
-                                  # || $word =~ /[A-Za-z]+[:][0-9]+/ #host:port
-                                  ) {
-                                addChart('bug_file_loc', 'substring',
-                                         $word, $negate);
-                            }
-                        } # foreach my $word (split(/,/, $qsword))
-                    } # votes and generic field detection
-                } # foreach (split(/\|/, $_))
-            } # &quot;switch&quot; $firstChar
</del><ins>+                    _handle_urls($word, $negate);
+                }
+            }
</ins><span class="cx">             $chart++;
</span><span class="cx">             $and = 0;
</span><span class="cx">             $or = 0;
</span><del>-        } # foreach (@words)
</del><ins>+        }
</ins><span class="cx"> 
</span><ins>+        # If there is no mention of a bug status, we restrict the query
+        # to open bugs by default.
+        unless ($bug_status_set) {
+            $cgi-&gt;param('bug_status', BUG_STATE_OPEN);
+        }
+
</ins><span class="cx">         # Inform user about any unknown fields
</span><del>-        if (scalar(@unknownFields)) {
</del><ins>+        if (scalar(@unknownFields) || scalar(keys %ambiguous_fields)) {
</ins><span class="cx">             ThrowUserError(&quot;quicksearch_unknown_field&quot;,
</span><del>-                           { fields =&gt; \@unknownFields });
</del><ins>+                           { unknown   =&gt; \@unknownFields,
+                             ambiguous =&gt; \%ambiguous_fields });
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         # Make sure we have some query terms left
</span><span class="lines">@@ -411,6 +256,7 @@
</span><span class="cx">     my $modified_query_string = $cgi-&gt;canonicalise_query(@params_to_strip);
</span><span class="cx"> 
</span><span class="cx">     if ($cgi-&gt;param('load')) {
</span><ins>+        my $urlbase = correct_urlbase();
</ins><span class="cx">         # Param 'load' asks us to display the query in the advanced search form.
</span><span class="cx">         print $cgi-&gt;redirect(-uri =&gt; &quot;${urlbase}query.cgi?format=advanced&amp;amp;&quot;
</span><span class="cx">                              . $modified_query_string);
</span><span class="lines">@@ -423,50 +269,305 @@
</span><span class="cx">     return $modified_query_string;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-###########################################################################
-# Helpers
-###########################################################################
</del><ins>+##########################
+# Parts of quicksearch() #
+##########################
</ins><span class="cx"> 
</span><del>-# Split string on whitespace, retaining quoted strings as one
-sub splitString {
-    my $string = shift;
-    my @quoteparts;
-    my @parts;
-    my $i = 0;
</del><ins>+sub _bug_numbers_only {
+    my $searchstring = shift;
+    my $cgi = Bugzilla-&gt;cgi;
+    # Allow separation by comma or whitespace.
+    $searchstring =~ s/[,\s]+/,/g;
</ins><span class="cx"> 
</span><del>-    # Now split on quote sign; be tolerant about unclosed quotes
-    @quoteparts = split(/&quot;/, $string);
-    foreach my $part (@quoteparts) {
-        # After every odd quote, quote special chars
-        $part = url_quote($part) if $i++ % 2;
</del><ins>+    if ($searchstring !~ /,/) {
+        # Single bug number; shortcut to show_bug.cgi.
+        print $cgi-&gt;redirect(
+            -uri =&gt; correct_urlbase() . &quot;show_bug.cgi?id=$searchstring&quot;);
+        exit;
</ins><span class="cx">     }
</span><del>-    # Join again
-    $string = join('&quot;', @quoteparts);
</del><ins>+    else {
+        # List of bug numbers.
+        $cgi-&gt;param('bug_id', $searchstring);
+        $cgi-&gt;param('order', 'bugs.bug_id');
+        $cgi-&gt;param('bug_id_type', 'anyexact');
+    }
+}
</ins><span class="cx"> 
</span><del>-    # Now split on unescaped whitespace
-    @parts = split(/\s+/, $string);
-    foreach (@parts) {
-        # Protect plus signs from becoming a blank.
-        # If &quot;+&quot; appears as the first character, leave it alone
-        # as it has a special meaning. Strings which start with
-        # &quot;+&quot; must be quoted.
-        s/(?&lt;!^)\+/%2B/g;
-        # Remove quotes
-        s/&quot;//g;
</del><ins>+sub _handle_alias {
+    my $searchstring = shift;
+    if ($searchstring =~ /^([^,\s]+)$/) {
+        my $alias = $1;
+        # We use this direct SQL because we want quicksearch to be VERY fast.
+        my $is_alias = Bugzilla-&gt;dbh-&gt;selectrow_array(
+            q{SELECT 1 FROM bugs WHERE alias = ?}, undef, $alias);
+        if ($is_alias) {
+            $alias = url_quote($alias);
+            print Bugzilla-&gt;cgi-&gt;redirect(
+                -uri =&gt; correct_urlbase() . &quot;show_bug.cgi?id=$alias&quot;);
+            exit;
+        }
</ins><span class="cx">     }
</span><del>-    return @parts;
</del><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub _handle_status_and_resolution {
+    my $word = shift;
+    my $legal_statuses = get_legal_field_values('bug_status');
+    my (%states, %resolutions);
+    $bug_status_set = 1;
+
+    if ($word eq 'OPEN') {
+        $states{$_} = 1 foreach BUG_STATE_OPEN;
+    }
+    # If we want all bugs, then there is nothing to do.
+    elsif ($word ne 'ALL'
+           &amp;&amp; !matchPrefixes(\%states, \%resolutions, $word, $legal_statuses))
+    {
+        $bug_status_set = 0;
+    }
+
+    # If we have wanted resolutions, allow closed states
+    if (keys(%resolutions)) {
+        foreach my $status (@$legal_statuses) {
+            $states{$status} = 1 unless is_open_state($status);
+        }
+    }
+
+    Bugzilla-&gt;cgi-&gt;param('bug_status', keys(%states));
+    Bugzilla-&gt;cgi-&gt;param('resolution', keys(%resolutions));
+}
+
+
+sub _handle_special_first_chars {
+    my ($qsword, $negate) = @_;
+
+    my $firstChar = substr($qsword, 0, 1);
+    my $baseWord = substr($qsword, 1);
+    my @subWords = split(/,/, $baseWord);
+
+    if ($firstChar eq '#') {
+        addChart('short_desc', 'substring', $baseWord, $negate);
+        addChart('content', 'matches', _matches_phrase($baseWord), $negate) if $fulltext;
+        return 1;
+    }
+    if ($firstChar eq ':') {
+        foreach (@subWords) {
+            addChart('product', 'substring', $_, $negate);
+            addChart('component', 'substring', $_, $negate);
+        }
+        return 1;
+    }
+    if ($firstChar eq '@') {
+        addChart('assigned_to', 'substring', $_, $negate) foreach (@subWords);
+        return 1;
+    }
+    if ($firstChar eq '[') {
+        addChart('short_desc', 'substring', $baseWord, $negate);
+        addChart('status_whiteboard', 'substring', $baseWord, $negate);
+        return 1;
+    }
+    if ($firstChar eq '!') {
+        addChart('keywords', 'anywords', $baseWord, $negate);
+        return 1;
+    }
+    return 0;
+}
+
+sub _handle_field_names {
+    my ($or_operand, $negate, $unknownFields, $ambiguous_fields) = @_;
+
+    # Flag and requestee shortcut
+    if ($or_operand =~ /^(?:flag:)?([^\?]+\?)([^\?]*)$/) {
+        addChart('flagtypes.name', 'substring', $1, $negate);
+        $chart++; $and = $or = 0; # Next chart for boolean AND
+        addChart('requestees.login_name', 'substring', $2, $negate);
+        return 1;
+    }
+
+    # Generic field1,field2,field3:value1,value2 notation.
+    # We have to correctly ignore commas and colons in quotes.
+    my @field_values = parse_line(':', 1, $or_operand);
+    if (scalar @field_values == 2) {
+        my @fields = parse_line(',', 1, $field_values[0]);
+        my @values = parse_line(',', 1, $field_values[1]);
+        foreach my $field (@fields) {
+            my $translated = _translate_field_name($field);
+            # Skip and record any unknown fields
+            if (!defined $translated) {
+                push(@$unknownFields, $field);
+            }
+            # If we got back an array, that means the substring is
+            # ambiguous and could match more than field name
+            elsif (ref $translated) {
+                $ambiguous_fields-&gt;{$field} = $translated;
+            }
+            else {
+                if ($translated eq 'bug_status' || $translated eq 'resolution') {
+                    $bug_status_set = 1;
+                }
+                foreach my $value (@values) {
+                    my $operator = FIELD_OPERATOR-&gt;{$translated} || 'substring';
+                    # If the string was quoted to protect some special
+                    # characters such as commas and colons, we need
+                    # to remove quotes.
+                    if ($value =~ /^([&quot;'])(.+)\1$/) {
+                        $value = $2;
+                        $value =~ s/\\([&quot;'])/$1/g;
+                    }
+                    addChart($translated, $operator, $value, $negate);
+                }
+            }
+        }
+        return 1;
+    }
+    return 0;
+}
+
+sub _translate_field_name {
+    my $field = shift;
+    $field = lc($field);
+    my $field_map = FIELD_MAP;
+
+    # If the field exactly matches a mapping, just return right now.
+    return $field_map-&gt;{$field} if exists $field_map-&gt;{$field};
+
+    # Check if we match, as a starting substring, exactly one field.
+    my @field_names = keys %$field_map;
+    my @matches = grep { $_ =~ /^\Q$field\E/ } @field_names;
+    # Eliminate duplicates that are actually the same field
+    # (otherwise &quot;assi&quot; matches both &quot;assignee&quot; and &quot;assigned_to&quot;, and
+    # the lines below fail when they shouldn't.)
+    my %match_unique = map { $field_map-&gt;{$_} =&gt; $_ } @matches;
+    @matches = values %match_unique;
+
+    if (scalar(@matches) == 1) {
+        return $field_map-&gt;{$matches[0]};
+    }
+    elsif (scalar(@matches) &gt; 1) {
+        return \@matches;
+    }
+
+    # Check if we match exactly one custom field, ignoring the cf_ on the
+    # custom fields (to allow people to type things like &quot;build&quot; for 
+    # &quot;cf_build&quot;).
+    my %cfless;
+    foreach my $name (@field_names) {
+        my $no_cf = $name;
+        if ($no_cf =~ s/^cf_//) {
+            if ($field eq $no_cf) {
+                return $field_map-&gt;{$name};
+            }
+            $cfless{$no_cf} = $name;
+        }
+    }
+
+    # See if we match exactly one substring of any of the cf_-less fields.
+    my @cfless_matches = grep { $_ =~ /^\Q$field\E/ } (keys %cfless);
+
+    if (scalar(@cfless_matches) == 1) {
+        my $match = $cfless_matches[0];
+        my $actual_field = $cfless{$match};
+        return $field_map-&gt;{$actual_field};
+    }
+    elsif (scalar(@matches) &gt; 1) {
+        return \@matches;
+    }
+
+    return undef;
+}
+
+sub _special_field_syntax {
+    my ($word, $negate) = @_;
+    
+    # P1-5 Syntax
+    if ($word =~ m/^P(\d+)(?:-(\d+))?$/i) {
+        my ($p_start, $p_end) = ($1, $2);
+        my $legal_priorities = get_legal_field_values('priority');
+
+        # If Pn exists explicitly, use it.
+        my $start = firstidx { $_ eq &quot;P$p_start&quot; } @$legal_priorities;
+        my $end;
+        $end = firstidx { $_ eq &quot;P$p_end&quot; } @$legal_priorities if defined $p_end;
+
+        # If Pn doesn't exist explicitly, then we mean the nth priority.
+        if ($start == -1) {
+            $start = max(0, $p_start - 1);
+        }
+        my $prios = $legal_priorities-&gt;[$start];
+
+        if (defined $end) {
+            # If Pn doesn't exist explicitly, then we mean the nth priority.
+            if ($end == -1) {
+                $end = min(scalar(@$legal_priorities), $p_end) - 1;
+                $end = max(0, $end); # Just in case the user typed P0.
+            }
+            ($start, $end) = ($end, $start) if $end &lt; $start;
+            $prios = join(',', @$legal_priorities[$start..$end])
+        }
+
+        addChart('priority', 'anyexact', $prios, $negate);
+        return 1;
+    }
+    return 0;    
+}
+
+sub _default_quicksearch_word {
+    my ($word, $negate) = @_;
+    
+    if (!grep { lc($word) eq $_ } PRODUCT_EXCEPTIONS and length($word) &gt; 2) {
+        addChart('product', 'substring', $word, $negate);
+    }
+    
+    if (!grep { lc($word) eq $_ } COMPONENT_EXCEPTIONS and length($word) &gt; 2) {
+        addChart('component', 'substring', $word, $negate);
+    }
+    
+    my @legal_keywords = map($_-&gt;name, Bugzilla::Keyword-&gt;get_all);
+    if (grep { lc($word) eq lc($_) } @legal_keywords) {
+        addChart('keywords', 'substring', $word, $negate);
+    }
+    
+    addChart('alias', 'substring', $word, $negate);
+    addChart('short_desc', 'substring', $word, $negate);
+    addChart('status_whiteboard', 'substring', $word, $negate);
+    addChart('content', 'matches', _matches_phrase($word), $negate) if $fulltext;
+}
+
+sub _handle_urls {
+    my ($word, $negate) = @_;
+    # URL field (for IP addrs, host.names,
+    # scheme://urls)
+    if ($word =~ m/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/
+        || $word =~ /^[A-Za-z]+(\.[A-Za-z]+)+/
+        || $word =~ /:[\\\/][\\\/]/
+        || $word =~ /localhost/
+        || $word =~ /mailto[:]?/)
+        # || $word =~ /[A-Za-z]+[:][0-9]+/ #host:port
+    {
+        addChart('bug_file_loc', 'substring', $word, $negate);
+    }
+}
+
+###########################################################################
+# Helpers
+###########################################################################
+
+# Quote and escape a phrase appropriately for a &quot;content matches&quot; search.
+sub _matches_phrase {
+    my ($phrase) = @_;
+    $phrase =~ s/&quot;/\\&quot;/g;
+    return &quot;\&quot;$phrase\&quot;&quot;;
+}
+
</ins><span class="cx"> # Expand found prefixes to states or resolutions
</span><span class="cx"> sub matchPrefixes {
</span><del>-    my $hr_states = shift;
-    my $hr_resolutions = shift;
-    my $ar_prefixes = shift;
-    my $ar_check_states = shift;
-    my $ar_check_resolutions = shift;
</del><ins>+    my ($hr_states, $hr_resolutions, $word, $ar_check_states) = @_;
+    return unless $word =~ /^[A-Z_]+(,[A-Z_]+)*$/;
+
+    my @ar_prefixes = split(/,/, $word);
+    my $ar_check_resolutions = get_legal_field_values('resolution');
</ins><span class="cx">     my $foundMatch = 0;
</span><span class="cx"> 
</span><del>-    foreach my $prefix (@$ar_prefixes) {
</del><ins>+    foreach my $prefix (@ar_prefixes) {
</ins><span class="cx">         foreach (@$ar_check_states) {
</span><span class="cx">             if (/^$prefix/) {
</span><span class="cx">                 $$hr_states{$_} = 1;
</span><span class="lines">@@ -487,19 +588,10 @@
</span><span class="cx"> sub negateComparisonType {
</span><span class="cx">     my $comparisonType = shift;
</span><span class="cx"> 
</span><del>-    if ($comparisonType eq 'substring') {
-        return 'notsubstring';
-    }
-    elsif ($comparisonType eq 'anywords') {
</del><ins>+    if ($comparisonType eq 'anywords') {
</ins><span class="cx">         return 'nowords';
</span><span class="cx">     }
</span><del>-    elsif ($comparisonType eq 'regexp') {
-        return 'notregexp';
-    }
-    else {
-        # Don't know how to negate that
-        ThrowCodeError('unknown_comparison_type');
-    }
</del><ins>+    return &quot;not$comparisonType&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> # Add a boolean chart
</span><span class="lines">@@ -524,7 +616,7 @@
</span><span class="cx">     my $cgi = Bugzilla-&gt;cgi;
</span><span class="cx">     $cgi-&gt;param(&quot;field$expr&quot;, $field);
</span><span class="cx">     $cgi-&gt;param(&quot;type$expr&quot;,  $type);
</span><del>-    $cgi-&gt;param(&quot;value$expr&quot;, url_decode($value));
</del><ins>+    $cgi-&gt;param(&quot;value$expr&quot;, $value);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> 1;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaSearchRecentpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/Search/Recent.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Search/Recent.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Search/Recent.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,172 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Everything Solved, Inc.
+# Portions created by the Initial Developer are Copyright (C) 2010 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+package Bugzilla::Search::Recent;
+use strict;
+use base qw(Bugzilla::Object);
+
+use Bugzilla::Constants;
+use Bugzilla::Error;
+use Bugzilla::Util;
+
+#############
+# Constants #
+#############
+
+use constant DB_TABLE =&gt; 'profile_search';
+use constant LIST_ORDER =&gt; 'id DESC';
+# Do not track buglists viewed by users.
+use constant AUDIT_CREATES =&gt; 0;
+use constant AUDIT_UPDATES =&gt; 0;
+use constant AUDIT_REMOVES =&gt; 0;
+
+use constant DB_COLUMNS =&gt; qw(
+    id
+    user_id
+    bug_list
+    list_order
+);
+
+use constant VALIDATORS =&gt; {
+    user_id    =&gt; \&amp;_check_user_id,
+    bug_list   =&gt; \&amp;_check_bug_list,
+    list_order =&gt; \&amp;_check_list_order,
+};
+
+use constant UPDATE_COLUMNS =&gt; qw(bug_list list_order);
+
+###################
+# DB Manipulation #
+###################
+
+sub create {
+    my $class = shift;
+    my $dbh = Bugzilla-&gt;dbh;
+    $dbh-&gt;bz_start_transaction();
+    my $search = $class-&gt;SUPER::create(@_);
+    my $user_id = $search-&gt;user_id;
+
+    # Enforce there only being SAVE_NUM_SEARCHES per user.
+    my $min_id = $dbh-&gt;selectrow_array(
+        'SELECT id FROM profile_search WHERE user_id = ? ORDER BY id DESC '
+        . $dbh-&gt;sql_limit(1, SAVE_NUM_SEARCHES), undef, $user_id);
+    if ($min_id) {
+        $dbh-&gt;do('DELETE FROM profile_search WHERE user_id = ? AND id &lt;= ?',
+                 undef, ($user_id, $min_id));
+    }
+    $dbh-&gt;bz_commit_transaction();
+    return $search;
+}
+
+sub create_placeholder {
+    my $class = shift;
+    return $class-&gt;create({ user_id  =&gt; Bugzilla-&gt;user-&gt;id,
+                            bug_list =&gt; '' });
+}
+
+###############
+# Constructor #
+###############
+
+sub check {
+    my $class = shift;
+    my $search = $class-&gt;SUPER::check(@_);
+    my $user = Bugzilla-&gt;user;
+    if ($search-&gt;user_id != $user-&gt;id) {
+        ThrowUserError('object_does_not_exist', { id =&gt; $search-&gt;id });
+    }
+    return $search;
+}
+
+sub check_quietly {
+    my $class = shift;
+    my $error_mode = Bugzilla-&gt;error_mode;
+    Bugzilla-&gt;error_mode(ERROR_MODE_DIE);
+    my $search = eval { $class-&gt;check(@_) };
+    Bugzilla-&gt;error_mode($error_mode);
+    return $search;
+}
+
+sub new_from_cookie {
+    my ($invocant, $bug_ids) = @_;
+    my $class = ref($invocant) || $invocant;
+
+    my $search = { id       =&gt; 'cookie',
+                   user_id  =&gt; Bugzilla-&gt;user-&gt;id,
+                   bug_list =&gt; join(',', @$bug_ids) };
+
+    bless $search, $class;
+    return $search;
+}
+
+####################
+# Simple Accessors #
+####################
+
+sub bug_list   { return [split(',', $_[0]-&gt;{'bug_list'})]; }
+sub list_order { return $_[0]-&gt;{'list_order'}; }
+sub user_id    { return $_[0]-&gt;{'user_id'}; }
+
+############
+# Mutators #
+############
+
+sub set_bug_list   { $_[0]-&gt;set('bug_list',   $_[1]); }
+sub set_list_order { $_[0]-&gt;set('list_order', $_[1]); }
+
+##############
+# Validators #
+##############
+
+sub _check_user_id {
+    my ($invocant, $id) = @_;
+    require Bugzilla::User;
+    return Bugzilla::User-&gt;check({ id =&gt; $id })-&gt;id;
+}
+
+sub _check_bug_list {
+    my ($invocant, $list) = @_;
+
+    my @bug_ids = ref($list) ? @$list : split(',', $list || '');
+    detaint_natural($_) foreach @bug_ids;
+    return join(',', @bug_ids);
+}
+
+sub _check_list_order { defined $_[1] ? trim($_[1]) : '' }
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::Search::Recent - A search recently run by a logged-in user.
+
+=head1 SYNOPSIS
+
+ use Bugzilla::Search::Recent;
+
+
+=head1 DESCRIPTION
+
+This is an implementation of L&lt;Bugzilla::Object&gt;, and so has all the
+same methods available as L&lt;Bugzilla::Object&gt;, in addition to what is
+documented below.
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaSearchSavedpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Search/Saved.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Search/Saved.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Search/Saved.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -32,31 +32,90 @@
</span><span class="cx"> use Bugzilla::User;
</span><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> 
</span><ins>+use Scalar::Util qw(blessed);
+
</ins><span class="cx"> #############
</span><span class="cx"> # Constants #
</span><span class="cx"> #############
</span><span class="cx"> 
</span><span class="cx"> use constant DB_TABLE =&gt; 'namedqueries';
</span><ins>+# Do not track buglists saved by users.
+use constant AUDIT_CREATES =&gt; 0;
+use constant AUDIT_UPDATES =&gt; 0;
+use constant AUDIT_REMOVES =&gt; 0;
</ins><span class="cx"> 
</span><span class="cx"> use constant DB_COLUMNS =&gt; qw(
</span><span class="cx">     id
</span><span class="cx">     userid
</span><span class="cx">     name
</span><span class="cx">     query
</span><del>-    query_type
</del><span class="cx"> );
</span><span class="cx"> 
</span><del>-use constant REQUIRED_CREATE_FIELDS =&gt; qw(name query);
-
</del><span class="cx"> use constant VALIDATORS =&gt; {
</span><span class="cx">     name       =&gt; \&amp;_check_name,
</span><span class="cx">     query      =&gt; \&amp;_check_query,
</span><del>-    query_type =&gt; \&amp;_check_query_type,
</del><span class="cx">     link_in_footer =&gt; \&amp;_check_link_in_footer,
</span><span class="cx"> };
</span><span class="cx"> 
</span><del>-use constant UPDATE_COLUMNS =&gt; qw(name query query_type);
</del><ins>+use constant UPDATE_COLUMNS =&gt; qw(name query);
</ins><span class="cx"> 
</span><ins>+###############
+# Constructor #
+###############
+
+sub new {
+    my $class = shift;
+    my $param = shift;
+    my $dbh = Bugzilla-&gt;dbh;
+
+    my $user;
+    if (ref $param) {
+        $user = $param-&gt;{user} || Bugzilla-&gt;user;
+        my $name = $param-&gt;{name};
+        if (!defined $name) {
+            ThrowCodeError('bad_arg',
+                {argument =&gt; 'name',
+                 function =&gt; &quot;${class}::new&quot;});
+        }
+        my $condition = 'userid = ? AND name = ?';
+        my $user_id = blessed $user ? $user-&gt;id : $user;
+        detaint_natural($user_id)
+          || ThrowCodeError('param_must_be_numeric',
+                            {function =&gt; $class . '::_init', param =&gt; 'user'});
+        my @values = ($user_id, $name);
+        $param = { condition =&gt; $condition, values =&gt; \@values };
+    }
+
+    unshift @_, $param;
+    my $self = $class-&gt;SUPER::new(@_);
+    if ($self) {
+        $self-&gt;{user} = $user if blessed $user;
+
+        # Some DBs (read: Oracle) incorrectly mark the query string as UTF-8
+        # when it's coming out of the database, even though it has no UTF-8
+        # characters in it, which prevents Bugzilla::CGI from later reading
+        # it correctly.
+        utf8::downgrade($self-&gt;{query}) if utf8::is_utf8($self-&gt;{query});
+    }
+    return $self;
+}
+
+sub check {
+    my $class = shift;
+    my $search = $class-&gt;SUPER::check(@_);
+    my $user = Bugzilla-&gt;user;
+    return $search if $search-&gt;user-&gt;id == $user-&gt;id;
+
+    if (!$search-&gt;shared_with_group
+        or !$user-&gt;in_group($search-&gt;shared_with_group)) 
+    {
+        ThrowUserError('missing_query', { queryname =&gt; $search-&gt;name, 
+                                          sharer_id =&gt; $search-&gt;user-&gt;id });
+    }
+
+    return $search;
+}
+
</ins><span class="cx"> ##############
</span><span class="cx"> # Validators #
</span><span class="cx"> ##############
</span><span class="lines">@@ -84,12 +143,6 @@
</span><span class="cx">     return $cgi-&gt;query_string;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _check_query_type {
-    my ($invocant, $type) = @_;
-    # Right now the only query type is LIST_OF_BUGS.
-    return $type ? LIST_OF_BUGS : QUERY_LIST;
-}
-
</del><span class="cx"> #########################
</span><span class="cx"> # Database Manipulation #
</span><span class="cx"> #########################
</span><span class="lines">@@ -117,6 +170,40 @@
</span><span class="cx">     return $obj;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub rename_field_value {
+    my ($class, $field, $old_value, $new_value) = @_;
+
+    my $old = url_quote($old_value);
+    my $new = url_quote($new_value);
+    my $old_sql = $old;
+    $old_sql =~ s/([_\%])/\\$1/g;
+
+    my $table = $class-&gt;DB_TABLE;
+    my $id_field = $class-&gt;ID_FIELD;
+
+    my $dbh = Bugzilla-&gt;dbh;
+    $dbh-&gt;bz_start_transaction();
+
+    my %queries = @{ $dbh-&gt;selectcol_arrayref(
+        &quot;SELECT $id_field, query FROM $table WHERE query LIKE ?&quot;,
+        {Columns=&gt;[1,2]}, &quot;\%$old_sql\%&quot;) };
+    foreach my $id (keys %queries) {
+        my $query = $queries{$id};
+        $query =~ s/\b$field=\Q$old\E\b/$field=$new/gi;
+        # Fix boolean charts.
+        while ($query =~ /\bfield(\d+-\d+-\d+)=\Q$field\E\b/gi) {
+            my $chart_id = $1;
+            # Note that this won't handle lists or substrings inside of
+            # boolean charts. Users will have to fix those themselves.
+            $query =~ s/\bvalue\Q$chart_id\E=\Q$old\E\b/value$chart_id=$new/i;
+        }
+        $dbh-&gt;do(&quot;UPDATE $table SET query = ? WHERE $id_field = ?&quot;,
+                 undef, $query, $id);
+    }
+
+    $dbh-&gt;bz_commit_transaction();
+}
+
</ins><span class="cx"> sub preload {
</span><span class="cx">     my ($searches) = @_;
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="lines">@@ -210,8 +297,7 @@
</span><span class="cx"> # Simple Accessors #
</span><span class="cx"> ####################
</span><span class="cx"> 
</span><del>-sub bug_ids_only { return ($_[0]-&gt;{'query_type'} == LIST_OF_BUGS) ? 1 : 0; }
-sub url          { return $_[0]-&gt;{'query'}; }
</del><ins>+sub url  { return $_[0]-&gt;{'query'}; }
</ins><span class="cx"> 
</span><span class="cx"> sub user {
</span><span class="cx">     my ($self) = @_;
</span><span class="lines">@@ -226,7 +312,6 @@
</span><span class="cx"> 
</span><span class="cx"> sub set_name       { $_[0]-&gt;set('name',       $_[1]); }
</span><span class="cx"> sub set_url        { $_[0]-&gt;set('query',      $_[1]); }
</span><del>-sub set_query_type { $_[0]-&gt;set('query_type', $_[1]); }
</del><span class="cx"> 
</span><span class="cx"> 1;
</span><span class="cx"> 
</span><span class="lines">@@ -264,7 +349,8 @@
</span><span class="cx"> 
</span><span class="cx"> =item C&lt;new&gt;
</span><span class="cx"> 
</span><del>-Does not accept a bare C&lt;name&gt; argument. Instead, accepts only an id.
</del><ins>+Takes either an id, or the named parameters C&lt;user&gt; and C&lt;name&gt;.
+C&lt;user&gt; can be either a L&lt;Bugzilla::User&gt; object or a numeric user id.
</ins><span class="cx"> 
</span><span class="cx"> See also: L&lt;Bugzilla::Object/new&gt;.
</span><span class="cx"> 
</span><span class="lines">@@ -297,9 +383,9 @@
</span><span class="cx"> I&lt;current user&gt; (not the owner of the search, but the person actually
</span><span class="cx"> using Bugzilla right now).
</span><span class="cx"> 
</span><del>-=item C&lt;bug_ids_only&gt;
</del><ins>+=item C&lt;type&gt;
</ins><span class="cx"> 
</span><del>-True if the search contains only a list of Bug IDs.
</del><ins>+The numeric id of the type of search this is (from L&lt;Bugzilla::Constants&gt;).
</ins><span class="cx"> 
</span><span class="cx"> =item C&lt;shared_with_group&gt;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaSearchpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Search.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Search.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Search.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -28,12 +28,18 @@
</span><span class="cx"> #                 Joel Peshkin &lt;bugreport@peshkin.net&gt;
</span><span class="cx"> #                 Lance Larsh &lt;lance.larsh@oracle.com&gt;
</span><span class="cx"> #                 Jesse Clark &lt;jjclark1982@gmail.com&gt;
</span><ins>+#                 Rémi Zara &lt;remi_zara@mac.com&gt;
+#                 Reed Loden &lt;reed@reedloden.com&gt;
</ins><span class="cx"> 
</span><span class="cx"> use strict;
</span><span class="cx"> 
</span><span class="cx"> package Bugzilla::Search;
</span><span class="cx"> use base qw(Exporter);
</span><del>-@Bugzilla::Search::EXPORT = qw(IsValidQueryType);
</del><ins>+@Bugzilla::Search::EXPORT = qw(
+    IsValidQueryType
+    split_order_term
+    translate_old_column
+);
</ins><span class="cx"> 
</span><span class="cx"> use Bugzilla::Error;
</span><span class="cx"> use Bugzilla::Util;
</span><span class="lines">@@ -41,828 +47,1949 @@
</span><span class="cx"> use Bugzilla::Group;
</span><span class="cx"> use Bugzilla::User;
</span><span class="cx"> use Bugzilla::Field;
</span><ins>+use Bugzilla::Search::Clause;
+use Bugzilla::Search::Condition qw(condition);
</ins><span class="cx"> use Bugzilla::Status;
</span><span class="cx"> use Bugzilla::Keyword;
</span><span class="cx"> 
</span><ins>+use Data::Dumper;
</ins><span class="cx"> use Date::Format;
</span><span class="cx"> use Date::Parse;
</span><ins>+use Scalar::Util qw(blessed);
+use List::MoreUtils qw(all part uniq);
+use POSIX qw(INT_MAX);
+use Storable qw(dclone);
</ins><span class="cx"> 
</span><del>-# Some fields are not sorted on themselves, but on other fields. 
</del><ins>+# Description Of Boolean Charts
+# -----------------------------
+#
+# A boolean chart is a way of representing the terms in a logical
+# expression.  Bugzilla builds SQL queries depending on how you enter
+# terms into the boolean chart. Boolean charts are represented in
+# urls as three-tuples of (chart id, row, column). The query form
+# (query.cgi) may contain an arbitrary number of boolean charts where
+# each chart represents a clause in a SQL query.
+#
+# The query form starts out with one boolean chart containing one
+# row and one column.  Extra rows can be created by pressing the
+# AND button at the bottom of the chart.  Extra columns are created
+# by pressing the OR button at the right end of the chart. Extra
+# charts are created by pressing &quot;Add another boolean chart&quot;.
+#
+# Each chart consists of an arbitrary number of rows and columns.
+# The terms within a row are ORed together. The expressions represented
+# by each row are ANDed together. The expressions represented by each
+# chart are ANDed together.
+#
+#        ----------------------
+#        | col2 | col2 | col3 |
+# --------------|------|------|
+# | row1 |  a1  |  a2  |      |
+# |------|------|------|------|  =&gt; ((a1 OR a2) AND (b1 OR b2 OR b3) AND (c1))
+# | row2 |  b1  |  b2  |  b3  |
+# |------|------|------|------|
+# | row3 |  c1  |      |      |
+# -----------------------------
+#
+#        --------
+#        | col2 |
+# --------------|
+# | row1 |  d1  | =&gt; (d1)
+# ---------------
+#
+# Together, these two charts represent a SQL expression like this
+# SELECT blah FROM blah WHERE ( (a1 OR a2)AND(b1 OR b2 OR b3)AND(c1)) AND (d1)
+#
+# The terms within a single row of a boolean chart are all constraints
+# on a single piece of data.  If you're looking for a bug that has two
+# different people cc'd on it, then you need to use two boolean charts.
+# This will find bugs with one CC matching 'foo@blah.org' and and another
+# CC matching 'bar@blah.org'.
+#
+# --------------------------------------------------------------
+# CC    | equal to
+# foo@blah.org
+# --------------------------------------------------------------
+# CC    | equal to
+# bar@blah.org
+#
+# If you try to do this query by pressing the AND button in the
+# original boolean chart then what you'll get is an expression that
+# looks for a single CC where the login name is both &quot;foo@blah.org&quot;,
+# and &quot;bar@blah.org&quot;. This is impossible.
+#
+# --------------------------------------------------------------
+# CC    | equal to
+# foo@blah.org
+# AND
+# CC    | equal to
+# bar@blah.org
+# --------------------------------------------------------------
+
+#############
+# Constants #
+#############
+
+# When doing searches, NULL datetimes are treated as this date.
+use constant EMPTY_DATETIME =&gt; '1970-01-01 00:00:00';
+
+# This is the regex for real numbers from Regexp::Common, modified to be
+# more readable.
+use constant NUMBER_REGEX =&gt; qr/
+    ^[+-]?      # A sign, optionally.
+
+    (?=\d|\.)   # Then either a digit or &quot;.&quot;
+    \d*         # Followed by many other digits
+    (?:
+        \.      # Followed possibly by some decimal places
+        (?:\d*)
+    )?

+    (?:         # Followed possibly by an exponent.
+        [Ee]
+        [+-]?
+        \d+
+    )?
+    $
+/x;
+
+# If you specify a search type in the boolean charts, this describes
+# which operator maps to which internal function here.
+use constant OPERATORS =&gt; {
+    equals         =&gt; \&amp;_simple_operator,
+    notequals      =&gt; \&amp;_simple_operator,
+    casesubstring  =&gt; \&amp;_casesubstring,
+    substring      =&gt; \&amp;_substring,
+    substr         =&gt; \&amp;_substring,
+    notsubstring   =&gt; \&amp;_notsubstring,
+    regexp         =&gt; \&amp;_regexp,
+    notregexp      =&gt; \&amp;_notregexp,
+    lessthan       =&gt; \&amp;_simple_operator,
+    lessthaneq     =&gt; \&amp;_simple_operator,
+    matches        =&gt; sub { ThrowUserError(&quot;search_content_without_matches&quot;); },
+    notmatches     =&gt; sub { ThrowUserError(&quot;search_content_without_matches&quot;); },
+    greaterthan    =&gt; \&amp;_simple_operator,
+    greaterthaneq  =&gt; \&amp;_simple_operator,
+    anyexact       =&gt; \&amp;_anyexact,
+    anywordssubstr =&gt; \&amp;_anywordsubstr,
+    allwordssubstr =&gt; \&amp;_allwordssubstr,
+    nowordssubstr  =&gt; \&amp;_nowordssubstr,
+    anywords       =&gt; \&amp;_anywords,
+    allwords       =&gt; \&amp;_allwords,
+    nowords        =&gt; \&amp;_nowords,
+    changedbefore  =&gt; \&amp;_changedbefore_changedafter,
+    changedafter   =&gt; \&amp;_changedbefore_changedafter,
+    changedfrom    =&gt; \&amp;_changedfrom_changedto,
+    changedto      =&gt; \&amp;_changedfrom_changedto,
+    changedby      =&gt; \&amp;_changedby,
+};
+
+# Some operators are really just standard SQL operators, and are
+# all implemented by the _simple_operator function, which uses this
+# constant.
+use constant SIMPLE_OPERATORS =&gt; {
+    equals        =&gt; '=',
+    notequals     =&gt; '!=',
+    greaterthan   =&gt; '&gt;',
+    greaterthaneq =&gt; '&gt;=',
+    lessthan      =&gt; '&lt;',
+    lessthaneq    =&gt; &quot;&lt;=&quot;,
+};
+
+# Most operators just reverse by removing or adding &quot;not&quot; from/to them.
+# However, some operators reverse in a different way, so those are listed
+# here.
+use constant OPERATOR_REVERSE =&gt; {
+    nowords        =&gt; 'anywords',
+    nowordssubstr  =&gt; 'anywordssubstr',
+    anywords       =&gt; 'nowords',
+    anywordssubstr =&gt; 'nowordssubstr',
+    lessthan       =&gt; 'greaterthaneq',
+    lessthaneq     =&gt; 'greaterthan',
+    greaterthan    =&gt; 'lessthaneq',
+    greaterthaneq  =&gt; 'lessthan',
+    # The following don't currently have reversals:
+    # casesubstring, anyexact, allwords, allwordssubstr
+};
+
+# For these operators, even if a field is numeric (is_numeric returns true),
+# we won't treat the input like a number.
+use constant NON_NUMERIC_OPERATORS =&gt; qw(
+    changedafter
+    changedbefore
+    changedfrom
+    changedto
+    regexp
+    notregexp
+);
+
+use constant MULTI_SELECT_OVERRIDE =&gt; {
+    notequals      =&gt; \&amp;_multiselect_negative,
+    notregexp      =&gt; \&amp;_multiselect_negative,
+    notsubstring   =&gt; \&amp;_multiselect_negative,
+    nowords        =&gt; \&amp;_multiselect_negative,
+    nowordssubstr  =&gt; \&amp;_multiselect_negative,
+    
+    allwords       =&gt; \&amp;_multiselect_multiple,
+    allwordssubstr =&gt; \&amp;_multiselect_multiple,
+    anyexact       =&gt; \&amp;_multiselect_multiple,
+    anywords       =&gt; \&amp;_multiselect_multiple,
+    anywordssubstr =&gt; \&amp;_multiselect_multiple,
+    
+    _non_changed    =&gt; \&amp;_multiselect_nonchanged,
+};
+
+use constant OPERATOR_FIELD_OVERRIDE =&gt; {
+    # User fields
+    'attachments.submitter' =&gt; {
+        _non_changed =&gt; \&amp;_user_nonchanged,
+    },
+    assigned_to =&gt; {
+        _non_changed =&gt; \&amp;_user_nonchanged,
+    },
+    cc =&gt; {
+        _non_changed =&gt; \&amp;_user_nonchanged,
+    },
+    commenter =&gt; {
+        _non_changed =&gt; \&amp;_user_nonchanged,
+    },
+    reporter =&gt; {
+        _non_changed =&gt; \&amp;_user_nonchanged,
+    },
+    'requestees.login_name' =&gt; {
+        _non_changed =&gt; \&amp;_user_nonchanged,
+    },
+    'setters.login_name' =&gt; {
+        _non_changed =&gt; \&amp;_user_nonchanged,    
+    },
+    qa_contact =&gt; {
+        _non_changed =&gt; \&amp;_user_nonchanged,
+    },
+    
+    # General Bug Fields
+    alias        =&gt; { _non_changed =&gt; \&amp;_nullable },
+    'attach_data.thedata' =&gt; MULTI_SELECT_OVERRIDE,
+    # We check all attachment fields against this.
+    attachments  =&gt; MULTI_SELECT_OVERRIDE,
+    blocked      =&gt; MULTI_SELECT_OVERRIDE,
+    bug_file_loc =&gt; { _non_changed =&gt; \&amp;_nullable },
+    bug_group    =&gt; MULTI_SELECT_OVERRIDE,
+    classification =&gt; {
+        _non_changed =&gt; \&amp;_classification_nonchanged,
+    },
+    component =&gt; {
+        _non_changed =&gt; \&amp;_component_nonchanged,
+    },
+    content =&gt; {
+        matches    =&gt; \&amp;_content_matches,
+        notmatches =&gt; \&amp;_content_matches,
+        _default   =&gt; sub { ThrowUserError(&quot;search_content_without_matches&quot;); },
+    },
+    days_elapsed =&gt; {
+        _default =&gt; \&amp;_days_elapsed,
+    },
+    dependson        =&gt; MULTI_SELECT_OVERRIDE,
+    keywords         =&gt; MULTI_SELECT_OVERRIDE,
+    'flagtypes.name' =&gt; MULTI_SELECT_OVERRIDE,
+    longdesc =&gt; {
+        %{ MULTI_SELECT_OVERRIDE() },
+        changedby     =&gt; \&amp;_long_desc_changedby,
+        changedbefore =&gt; \&amp;_long_desc_changedbefore_after,
+        changedafter  =&gt; \&amp;_long_desc_changedbefore_after,
+    },
+    'longdescs.count' =&gt; {
+        changedby     =&gt; \&amp;_long_desc_changedby,
+        changedbefore =&gt; \&amp;_long_desc_changedbefore_after,
+        changedafter  =&gt; \&amp;_long_desc_changedbefore_after,
+        changedfrom   =&gt; \&amp;_invalid_combination,
+        changedto     =&gt; \&amp;_invalid_combination,
+        _default      =&gt; \&amp;_long_descs_count,
+    },
+    'longdescs.isprivate' =&gt; MULTI_SELECT_OVERRIDE,
+    owner_idle_time =&gt; {
+        greaterthan   =&gt; \&amp;_owner_idle_time_greater_less,
+        greaterthaneq =&gt; \&amp;_owner_idle_time_greater_less,
+        lessthan      =&gt; \&amp;_owner_idle_time_greater_less,
+        lessthaneq    =&gt; \&amp;_owner_idle_time_greater_less,
+        _default      =&gt; \&amp;_invalid_combination,
+    },
+    product =&gt; {
+        _non_changed =&gt; \&amp;_product_nonchanged,
+    },
+    tag =&gt; MULTI_SELECT_OVERRIDE,
+    
+    # Timetracking Fields
+    deadline =&gt; { _non_changed =&gt; \&amp;_deadline },
+    percentage_complete =&gt; {
+        _non_changed =&gt; \&amp;_percentage_complete,
+    },
+    work_time =&gt; {
+        changedby     =&gt; \&amp;_work_time_changedby,
+        changedbefore =&gt; \&amp;_work_time_changedbefore_after,
+        changedafter  =&gt; \&amp;_work_time_changedbefore_after,
+        _default      =&gt; \&amp;_work_time,
+    },
+    
+    # Custom Fields
+    FIELD_TYPE_FREETEXT, { _non_changed =&gt; \&amp;_nullable },
+    FIELD_TYPE_BUG_ID,   { _non_changed =&gt; \&amp;_nullable_int },
+    FIELD_TYPE_DATETIME, { _non_changed =&gt; \&amp;_nullable_datetime },
+    FIELD_TYPE_TEXTAREA, { _non_changed =&gt; \&amp;_nullable },
+    FIELD_TYPE_MULTI_SELECT, MULTI_SELECT_OVERRIDE,
+    FIELD_TYPE_BUG_URLS,     MULTI_SELECT_OVERRIDE,    
+};
+
+# These are fields where special action is taken depending on the
+# *value* passed in to the chart, sometimes.
+use constant SPECIAL_PARSING =&gt; {
+    # Pronoun Fields (Ones that can accept %user%, etc.)
+    assigned_to =&gt; \&amp;_contact_pronoun,
+    cc          =&gt; \&amp;_cc_pronoun,
+    commenter   =&gt; \&amp;_commenter_pronoun,
+    qa_contact  =&gt; \&amp;_contact_pronoun,
+    reporter    =&gt; \&amp;_contact_pronoun,
+    
+    # Date Fields that accept the 1d, 1w, 1m, 1y, etc. format.
+    creation_ts =&gt; \&amp;_timestamp_translate,
+    deadline    =&gt; \&amp;_timestamp_translate,
+    delta_ts    =&gt; \&amp;_timestamp_translate,
+};
+
+# Information about fields that represent &quot;users&quot;, used by _user_nonchanged.
+# There are other user fields than the ones listed here, but those use
+# defaults in _user_nonchanged.
+use constant USER_FIELDS =&gt; {
+    'attachments.submitter' =&gt; {
+        field    =&gt; 'submitter_id',
+        join     =&gt; { table =&gt; 'attachments' },
+        isprivate =&gt; 1,
+    },
+    cc =&gt; {
+        field =&gt; 'who',
+        join  =&gt; { table =&gt; 'cc' },
+    },
+    commenter =&gt; {
+        field =&gt; 'who',
+        join  =&gt; { table =&gt; 'longdescs', join =&gt; 'INNER' },
+        isprivate =&gt; 1,
+    },
+    qa_contact =&gt; {
+        nullable =&gt; 1,
+    },
+    'requestees.login_name' =&gt; {
+        nullable =&gt; 1,
+        field    =&gt; 'requestee_id',
+        join     =&gt; { table =&gt; 'flags' },
+    },
+    'setters.login_name' =&gt; {
+        field    =&gt; 'setter_id',
+        join     =&gt; { table =&gt; 'flags' },
+    },
+};
+
+# Backwards compatibility for times that we changed the names of fields
+# or URL parameters.
+use constant FIELD_MAP =&gt; {
+    'attachments.thedata' =&gt; 'attach_data.thedata',
+    bugidtype =&gt; 'bug_id_type',
+    changedin =&gt; 'days_elapsed',
+    long_desc =&gt; 'longdesc',
+};
+
+# Some fields are not sorted on themselves, but on other fields.
</ins><span class="cx"> # We need to have a list of these fields and what they map to.
</span><del>-# Each field points to an array that contains the fields mapped 
-# to, in order.
</del><span class="cx"> use constant SPECIAL_ORDER =&gt; {
</span><del>-    'bugs.target_milestone' =&gt; [ 'ms_order.sortkey','ms_order.value' ],
-    'bugs.bug_status' =&gt; [ 'bug_status.sortkey','bug_status.value' ],
-    'bugs.rep_platform' =&gt; [ 'rep_platform.sortkey','rep_platform.value' ],
-    'bugs.priority' =&gt; [ 'priority.sortkey','priority.value' ],
-    'bugs.op_sys' =&gt; [ 'op_sys.sortkey','op_sys.value' ],
-    'bugs.resolution' =&gt; [ 'resolution.sortkey', 'resolution.value' ],
-    'bugs.bug_severity' =&gt; [ 'bug_severity.sortkey','bug_severity.value' ]
</del><ins>+    'target_milestone' =&gt; {
+        order =&gt; ['map_target_milestone.sortkey','map_target_milestone.value'],
+        join  =&gt; {
+            table =&gt; 'milestones',
+            from  =&gt; 'target_milestone',
+            to    =&gt; 'value',
+            extra =&gt; ['bugs.product_id = map_target_milestone.product_id'],
+            join  =&gt; 'INNER',
+        }
+    },
</ins><span class="cx"> };
</span><span class="cx"> 
</span><del>-# When we add certain fields to the ORDER BY, we need to then add a
-# table join to the FROM statement. This hash maps input fields to 
-# the join statements that need to be added.
-use constant SPECIAL_ORDER_JOIN =&gt; {
-    'bugs.target_milestone' =&gt; 'LEFT JOIN milestones AS ms_order ON ms_order.value = bugs.target_milestone AND ms_order.product_id = bugs.product_id',
-    'bugs.bug_status' =&gt; 'LEFT JOIN bug_status ON bug_status.value = bugs.bug_status',
-    'bugs.rep_platform' =&gt; 'LEFT JOIN rep_platform ON rep_platform.value = bugs.rep_platform',
-    'bugs.priority' =&gt; 'LEFT JOIN priority ON priority.value = bugs.priority',
-    'bugs.op_sys' =&gt; 'LEFT JOIN op_sys ON op_sys.value = bugs.op_sys',
-    'bugs.resolution' =&gt; 'LEFT JOIN resolution ON resolution.value = bugs.resolution',
-    'bugs.bug_severity' =&gt; 'LEFT JOIN bug_severity ON bug_severity.value = bugs.bug_severity'
</del><ins>+# Certain columns require other columns to come before them
+# in _select_columns, and should be put there if they're not there.
+use constant COLUMN_DEPENDS =&gt; {
+    classification      =&gt; ['product'],
+    percentage_complete =&gt; ['actual_time', 'remaining_time'],
</ins><span class="cx"> };
</span><span class="cx"> 
</span><del>-# Create a new Search
-# Note that the param argument may be modified by Bugzilla::Search
</del><ins>+# This describes tables that must be joined when you want to display
+# certain columns in the buglist. For the most part, Search.pm uses
+# DB::Schema to figure out what needs to be joined, but for some
+# fields it needs a little help.
+use constant COLUMN_JOINS =&gt; {
+    actual_time =&gt; {
+        table =&gt; '(SELECT bug_id, SUM(work_time) AS total'
+                 . ' FROM longdescs GROUP BY bug_id)',
+        join  =&gt; 'INNER',
+    },
+    assigned_to =&gt; {
+        from  =&gt; 'assigned_to',
+        to    =&gt; 'userid',
+        table =&gt; 'profiles',
+        join  =&gt; 'INNER',
+    },
+    reporter =&gt; {
+        from  =&gt; 'reporter',
+        to    =&gt; 'userid',
+        table =&gt; 'profiles',
+        join  =&gt; 'INNER',
+    },
+    qa_contact =&gt; {
+        from  =&gt; 'qa_contact',
+        to    =&gt; 'userid',
+        table =&gt; 'profiles',
+    },
+    component =&gt; {
+        from  =&gt; 'component_id',
+        to    =&gt; 'id',
+        table =&gt; 'components',
+        join  =&gt; 'INNER',
+    },
+    product =&gt; {
+        from  =&gt; 'product_id',
+        to    =&gt; 'id',
+        table =&gt; 'products',
+        join  =&gt; 'INNER',
+    },
+    classification =&gt; {
+        table =&gt; 'classifications',
+        from  =&gt; 'map_product.classification_id',
+        to    =&gt; 'id',
+        join  =&gt; 'INNER',
+    },
+    'flagtypes.name' =&gt; {
+        as    =&gt; 'map_flags',
+        table =&gt; 'flags',
+        extra =&gt; ['map_flags.attach_id IS NULL'],
+        then_to =&gt; {
+            as    =&gt; 'map_flagtypes',
+            table =&gt; 'flagtypes',
+            from  =&gt; 'map_flags.type_id',
+            to    =&gt; 'id',
+        },
+    },
+    keywords =&gt; {
+        table =&gt; 'keywords',
+        then_to =&gt; {
+            as    =&gt; 'map_keyworddefs',
+            table =&gt; 'keyworddefs',
+            from  =&gt; 'map_keywords.keywordid',
+            to    =&gt; 'id',
+        },
+    },
+    'longdescs.count' =&gt; {
+        table =&gt; 'longdescs',
+        join  =&gt; 'INNER',
+    },
+};
+
+# This constant defines the columns that can be selected in a query 
+# and/or displayed in a bug list.  Column records include the following
+# fields:
+#
+# 1. id: a unique identifier by which the column is referred in code;
+#
+# 2. name: The name of the column in the database (may also be an expression
+#          that returns the value of the column);
+#
+# 3. title: The title of the column as displayed to users.
+# 
+# Note: There are a few hacks in the code that deviate from these definitions.
+#       In particular, the redundant short_desc column is removed when the
+#       client requests &quot;all&quot; columns.
+#
+# This is really a constant--that is, once it's been called once, the value
+# will always be the same unless somebody adds a new custom field. But
+# we have to do a lot of work inside the subroutine to get the data,
+# and we don't want it to happen at compile time, so we have it as a
+# subroutine.
+sub COLUMNS {
+    my $invocant = shift;
+    my $user = blessed($invocant) ? $invocant-&gt;_user : Bugzilla-&gt;user;
+    my $dbh = Bugzilla-&gt;dbh;
+    my $cache = Bugzilla-&gt;request_cache;
+
+    if (defined $cache-&gt;{search_columns}-&gt;{$user-&gt;id}) {
+        return $cache-&gt;{search_columns}-&gt;{$user-&gt;id};
+    }
+
+    # These are columns that don't exist in fielddefs, but are valid buglist
+    # columns. (Also see near the bottom of this function for the definition
+    # of short_short_desc.)
+    my %columns = (
+        relevance            =&gt; { title =&gt; 'Relevance'  },
+        assigned_to_realname =&gt; { title =&gt; 'Assignee'   },
+        reporter_realname    =&gt; { title =&gt; 'Reporter'   },
+        qa_contact_realname  =&gt; { title =&gt; 'QA Contact' },
+    );
+
+    # Next we define columns that have special SQL instead of just something
+    # like &quot;bugs.bug_id&quot;.
+    my $total_time = &quot;(map_actual_time.total + bugs.remaining_time)&quot;;
+    my %special_sql = (
+        deadline    =&gt; $dbh-&gt;sql_date_format('bugs.deadline', '%Y-%m-%d'),
+        actual_time =&gt; 'map_actual_time.total',
+
+        # &quot;FLOOR&quot; is in there to turn this into an integer, making searches
+        # totally predictable. Otherwise you get floating-point numbers that
+        # are rather hard to search reliably if you're asking for exact
+        # numbers.
+        percentage_complete =&gt;
+            &quot;(CASE WHEN $total_time = 0&quot;
+               . &quot; THEN 0&quot;
+               . &quot; ELSE FLOOR(100 * (map_actual_time.total / $total_time))&quot;
+                . &quot; END)&quot;,
+
+        'flagtypes.name' =&gt; $dbh-&gt;sql_group_concat('DISTINCT ' 
+            . $dbh-&gt;sql_string_concat('map_flagtypes.name', 'map_flags.status')),
+
+        'keywords' =&gt; $dbh-&gt;sql_group_concat('DISTINCT map_keyworddefs.name'),
+        
+        'longdescs.count' =&gt; 'COUNT(DISTINCT map_longdescs_count.comment_id)',
+    );
+
+    # Backward-compatibility for old field names. Goes new_name =&gt; old_name.
+    # These are here and not in translate_old_column because the rest of the
+    # code actually still uses the old names, while the fielddefs table uses
+    # the new names (which is not the case for the fields handled by 
+    # translate_old_column).
+    my %old_names = (
+        creation_ts =&gt; 'opendate',
+        delta_ts    =&gt; 'changeddate',
+        work_time   =&gt; 'actual_time',
+    );
+
+    # Fields that are email addresses
+    my @email_fields = qw(assigned_to reporter qa_contact);
+    # Other fields that are stored in the bugs table as an id, but
+    # should be displayed using their name.
+    my @id_fields = qw(product component classification);
+
+    foreach my $col (@email_fields) {
+        my $sql = &quot;map_${col}.login_name&quot;;
+        if (!$user-&gt;id) {
+             $sql = $dbh-&gt;sql_string_until($sql, $dbh-&gt;quote('@'));
+        }
+        $special_sql{$col} = $sql;
+        $columns{&quot;${col}_realname&quot;}-&gt;{name} = &quot;map_${col}.realname&quot;;
+    }
+
+    foreach my $col (@id_fields) {
+        $special_sql{$col} = &quot;map_${col}.name&quot;;
+    }
+
+    # Do the actual column-getting from fielddefs, now.
+    my @fields = @{ Bugzilla-&gt;fields({ obsolete =&gt; 0, buglist =&gt; 1 }) };
+    foreach my $field (@fields) {
+        my $id = $field-&gt;name;
+        $id = $old_names{$id} if exists $old_names{$id};
+        my $sql;
+        if (exists $special_sql{$id}) {
+            $sql = $special_sql{$id};
+        }
+        elsif ($field-&gt;type == FIELD_TYPE_MULTI_SELECT) {
+            $sql = $dbh-&gt;sql_group_concat(
+                'DISTINCT map_' . $field-&gt;name . '.value');
+        }
+        else {
+            $sql = 'bugs.' . $field-&gt;name;
+        }
+        $columns{$id} = { name =&gt; $sql, title =&gt; $field-&gt;description };
+    }
+
+    # The short_short_desc column is identical to short_desc
+    $columns{'short_short_desc'} = $columns{'short_desc'};
+
+    Bugzilla::Hook::process('buglist_columns', { columns =&gt; \%columns });
+
+    $cache-&gt;{search_columns}-&gt;{$user-&gt;id} = \%columns;
+    return $cache-&gt;{search_columns}-&gt;{$user-&gt;id};
+}
+
+sub REPORT_COLUMNS {
+    my $invocant = shift;
+    my $user = blessed($invocant) ? $invocant-&gt;_user : Bugzilla-&gt;user;
+
+    my $columns = dclone(blessed($invocant) ? $invocant-&gt;COLUMNS : COLUMNS);
+    # There's no reason to support reporting on unique fields.
+    # Also, some other fields don't make very good reporting axises,
+    # or simply don't work with the current reporting system.
+    my @no_report_columns = 
+        qw(bug_id alias short_short_desc opendate changeddate
+           flagtypes.name keywords relevance);
+
+    # Multi-select fields are not currently supported.
+    my @multi_selects = @{Bugzilla-&gt;fields(
+        { obsolete =&gt; 0, type =&gt; FIELD_TYPE_MULTI_SELECT })};
+    push(@no_report_columns, map { $_-&gt;name } @multi_selects);
+
+    # If you're not a time-tracker, you can't use time-tracking
+    # columns.
+    if (!$user-&gt;is_timetracker) {
+        push(@no_report_columns, TIMETRACKING_FIELDS);
+    }
+
+    foreach my $name (@no_report_columns) {
+        delete $columns-&gt;{$name};
+    }
+    return $columns;
+}
+
+# These are fields that never go into the GROUP BY on any DB. bug_id
+# is here because it *always* goes into the GROUP BY as the first item,
+# so it should be skipped when determining extra GROUP BY columns.
+use constant GROUP_BY_SKIP =&gt; qw(
+    bug_id
+    flagtypes.name
+    keywords
+    longdescs.count
+    percentage_complete
+);
+
+###############
+# Constructor #
+###############
+
+# Note that the params argument may be modified by Bugzilla::Search
</ins><span class="cx"> sub new {
</span><span class="cx">     my $invocant = shift;
</span><span class="cx">     my $class = ref($invocant) || $invocant;
</span><span class="cx">   
</span><span class="cx">     my $self = { @_ };
</span><span class="cx">     bless($self, $class);
</span><ins>+    $self-&gt;{'user'} ||= Bugzilla-&gt;user;
+    
+    # There are certain behaviors of the CGI &quot;Vars&quot; hash that we don't want.
+    # In particular, if you put a single-value arrayref into it, later you
+    # get back out a string, which breaks anyexact charts (because they
+    # need arrays even for individual items, or we will re-trigger bug 67036).
+    #
+    # We can't just untie the hash--that would give us a hash with no values.
+    # We have to manually copy the hash into a new one, and we have to always
+    # do it, because there's no way to know if we were passed a tied hash
+    # or not.
+    my $params_in = $self-&gt;_params;
+    my %params = map { $_ =&gt; $params_in-&gt;{$_} } keys %$params_in;
+    $self-&gt;{params} = \%params;
</ins><span class="cx"> 
</span><del>-    $self-&gt;init();

</del><span class="cx">     return $self;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub init {
-    my $self = shift;
-    my $fieldsref = $self-&gt;{'fields'};
-    my $params = $self-&gt;{'params'};
-    $self-&gt;{'user'} ||= Bugzilla-&gt;user;
-    my $user = $self-&gt;{'user'};
</del><span class="cx"> 
</span><del>-    my $orderref = $self-&gt;{'order'} || 0;
-    my @inputorder;
-    @inputorder = @$orderref if $orderref;
-    my @orderby;
</del><ins>+####################
+# Public Accessors #
+####################
</ins><span class="cx"> 
</span><del>-    my $debug = 0;
-    my @debugdata;
-    if ($params-&gt;param('debug')) { $debug = 1; }
</del><ins>+sub sql {
+    my ($self) = @_;
+    return $self-&gt;{sql} if $self-&gt;{sql};
+    my $dbh = Bugzilla-&gt;dbh;
+    
+    my ($joins, $clause) = $self-&gt;_charts_to_conditions();
+    my $select = join(', ', $self-&gt;_sql_select);
+    my $from = $self-&gt;_sql_from($joins);
+    my $where = $self-&gt;_sql_where($clause);
+    my $group_by = $dbh-&gt;sql_group_by($self-&gt;_sql_group_by);
+    my $order_by = $self-&gt;_sql_order_by
+                   ? &quot;\nORDER BY &quot; . join(', ', $self-&gt;_sql_order_by) : '';
+    my $limit = $self-&gt;_sql_limit;
+    $limit = &quot;\n$limit&quot; if $limit;
+    
+    my $query = &lt;&lt;END;
+SELECT $select
+  FROM $from
+ WHERE $where
+$group_by$order_by$limit
+END
+    $self-&gt;{sql} = $query;
+    return $self-&gt;{sql};
+}
</ins><span class="cx"> 
</span><del>-    my @fields;
-    my @supptables;
-    my @wherepart;
-    my @having;
-    my @groupby;
-    @fields = @$fieldsref if $fieldsref;
-    my @specialchart;
-    my @andlist;
-    my %chartfields;
</del><ins>+sub search_description {
+    my ($self, $params) = @_;
+    my $desc = $self-&gt;{'search_description'} ||= [];
+    if ($params) {
+        push(@$desc, $params);
+    }
+    # Make sure that the description has actually been generated if
+    # people are asking for the whole thing.
+    else {
+        $self-&gt;sql;
+    }
+    return $self-&gt;{'search_description'};
+}
</ins><span class="cx"> 
</span><del>-    my %special_order      = %{SPECIAL_ORDER()};
-    my %special_order_join = %{SPECIAL_ORDER_JOIN()};
</del><ins>+sub boolean_charts_to_custom_search {
+    my ($self, $cgi_buffer) = @_;
+    my @as_params = $self-&gt;_boolean_charts-&gt;as_params;
</ins><span class="cx"> 
</span><del>-    my @select_fields = Bugzilla-&gt;get_fields({ type =&gt; FIELD_TYPE_SINGLE_SELECT,
-                                               obsolete =&gt; 0 });
-    
-    my @multi_select_fields = Bugzilla-&gt;get_fields({ type =&gt; FIELD_TYPE_MULTI_SELECT,
-                                                     obsolete =&gt; 0 });
-    foreach my $field (@select_fields) {
-        my $name = $field-&gt;name;
-        $special_order{&quot;bugs.$name&quot;} = [ &quot;$name.sortkey&quot;, &quot;$name.value&quot; ],
-        $special_order_join{&quot;bugs.$name&quot;} =
-            &quot;LEFT JOIN $name ON $name.value = bugs.$name&quot;;
</del><ins>+    # We need to start our new ids after the last custom search &quot;f&quot; id.
+    # We can just pick the last id in the array because they are sorted
+    # numerically.
+    my $last_id = ($self-&gt;_field_ids)[-1];
+    my $count = defined($last_id) ? $last_id + 1 : 0;
+    foreach my $param_set (@as_params) {
+        foreach my $name (keys %$param_set) {
+            my $value = $param_set-&gt;{$name};
+            next if !defined $value;
+            $cgi_buffer-&gt;param($name . $count, $value);
+        }
+        $count++;
</ins><span class="cx">     }
</span><ins>+}
</ins><span class="cx"> 
</span><del>-    my $dbh = Bugzilla-&gt;dbh;
</del><ins>+######################
+# Internal Accessors #
+######################
</ins><span class="cx"> 
</span><del>-    # First, deal with all the old hard-coded non-chart-based poop.
-    if (grep(/map_assigned_to/, @$fieldsref)) {
-        push @supptables, &quot;INNER JOIN profiles AS map_assigned_to &quot; .
-                          &quot;ON bugs.assigned_to = map_assigned_to.userid&quot;;
</del><ins>+# Fields that are legal for boolean charts of any kind.
+sub _chart_fields {
+    my ($self) = @_;
+
+    if (!$self-&gt;{chart_fields}) {
+        my $chart_fields = Bugzilla-&gt;fields({ by_name =&gt; 1 });
+
+        if (!$self-&gt;_user-&gt;is_timetracker) {
+            foreach my $tt_field (TIMETRACKING_FIELDS) {
+                delete $chart_fields-&gt;{$tt_field};
+            }
+        }
+        $self-&gt;{chart_fields} = $chart_fields;
</ins><span class="cx">     }
</span><ins>+    return $self-&gt;{chart_fields};
+}
</ins><span class="cx"> 
</span><del>-    if (grep(/map_reporter/, @$fieldsref)) {
-        push @supptables, &quot;INNER JOIN profiles AS map_reporter &quot; .
-                          &quot;ON bugs.reporter = map_reporter.userid&quot;;
</del><ins>+# There are various places in Search.pm that we need to know the list of
+# valid multi-select fields--or really, fields that are stored like
+# multi-selects, which includes BUG_URLS fields.
+sub _multi_select_fields {
+    my ($self) = @_;
+    $self-&gt;{multi_select_fields} ||= Bugzilla-&gt;fields({
+        by_name =&gt; 1,
+        type    =&gt; [FIELD_TYPE_MULTI_SELECT, FIELD_TYPE_BUG_URLS]});
+    return $self-&gt;{multi_select_fields};
+}
+
+# $self-&gt;{params} contains values that could be undef, could be a string,
+# or could be an arrayref. Sometimes we want that value as an array,
+# always.
+sub _param_array {
+    my ($self, $name) = @_;
+    my $value = $self-&gt;_params-&gt;{$name};
+    if (!defined $value) {
+        return ();
</ins><span class="cx">     }
</span><ins>+    if (ref($value) eq 'ARRAY') {
+        return @$value;
+    }
+    return ($value);
+}
</ins><span class="cx"> 
</span><del>-    if (grep(/map_qa_contact/, @$fieldsref)) {
-        push @supptables, &quot;LEFT JOIN profiles AS map_qa_contact &quot; .
-                          &quot;ON bugs.qa_contact = map_qa_contact.userid&quot;;
</del><ins>+sub _params { $_[0]-&gt;{params} }
+sub _user { return $_[0]-&gt;{user} }
+sub _sharer_id { $_[0]-&gt;{sharer} }
+
+##############################
+# Internal Accessors: SELECT #
+##############################
+
+# These are the fields the user has chosen to display on the buglist,
+# exactly as they were passed to new().
+sub _input_columns { @{ $_[0]-&gt;{'fields'} || [] } }
+
+# These are columns that are also going to be in the SELECT for one reason
+# or another, but weren't actually requested by the caller.
+sub _extra_columns {
+    my ($self) = @_;
+    # Everything that's going to be in the ORDER BY must also be
+    # in the SELECT.
+    push(@{ $self-&gt;{extra_columns} }, $self-&gt;_input_order_columns);
+    return @{ $self-&gt;{extra_columns} };
+}
+
+# For search functions to modify extra_columns. It doesn't matter if
+# people push the same column onto this array multiple times, because
+# _select_columns will call &quot;uniq&quot; on its final result.
+sub _add_extra_column {
+    my ($self, $column) = @_;
+    push(@{ $self-&gt;{extra_columns} }, $column);
+}
+
+# These are the columns that we're going to be actually SELECTing.
+sub _select_columns {
+    my ($self) = @_;
+    return @{ $self-&gt;{select_columns} } if $self-&gt;{select_columns};
+
+    my @select_columns;
+    foreach my $column ($self-&gt;_input_columns, $self-&gt;_extra_columns) {
+        if (my $add_first = COLUMN_DEPENDS-&gt;{$column}) {
+            push(@select_columns, @$add_first);
+        }
+        push(@select_columns, $column);
</ins><span class="cx">     }
</span><ins>+    
+    $self-&gt;{select_columns} = [uniq @select_columns];
+    return @{ $self-&gt;{select_columns} };
+}
</ins><span class="cx"> 
</span><del>-    if (lsearch($fieldsref, 'map_products.name') &gt;= 0) {
-        push @supptables, &quot;INNER JOIN products AS map_products &quot; .
-                          &quot;ON bugs.product_id = map_products.id&quot;;
</del><ins>+# This takes _select_columns and translates it into the actual SQL that
+# will go into the SELECT clause.
+sub _sql_select {
+    my ($self) = @_;
+    my @sql_fields;
+    foreach my $column ($self-&gt;_select_columns) {
+        my $alias = $column;
+        # Aliases cannot contain dots in them. We convert them to underscores.
+        $alias =~ s/\./_/g;
+        my $sql = $self-&gt;COLUMNS-&gt;{$column}-&gt;{name} . &quot; AS $alias&quot;;
+        push(@sql_fields, $sql);
</ins><span class="cx">     }
</span><ins>+    return @sql_fields;
+}
</ins><span class="cx"> 
</span><del>-    if (lsearch($fieldsref, 'map_classifications.name') &gt;= 0) {
-        push @supptables, &quot;INNER JOIN products AS map_products &quot; .
-                          &quot;ON bugs.product_id = map_products.id&quot;;
-        push @supptables,
-                &quot;INNER JOIN classifications AS map_classifications &quot; .
-                &quot;ON map_products.classification_id = map_classifications.id&quot;;
</del><ins>+################################
+# Internal Accessors: ORDER BY #
+################################
+
+# The &quot;order&quot; that was requested by the consumer, exactly as it was
+# requested.
+sub _input_order { @{ $_[0]-&gt;{'order'} || [] } }
+# The input order with just the column names, and no ASC or DESC.
+sub _input_order_columns {
+    my ($self) = @_;
+    return map { (split_order_term($_))[0] } $self-&gt;_input_order;
+}
+
+# A hashref that describes all the special stuff that has to be done
+# for various fields if they go into the ORDER BY clause.
+sub _special_order {
+    my ($self) = @_;
+    return $self-&gt;{special_order} if $self-&gt;{special_order};
+    
+    my %special_order = %{ SPECIAL_ORDER() };
+    my $select_fields = Bugzilla-&gt;fields({ type =&gt; FIELD_TYPE_SINGLE_SELECT });
+    foreach my $field (@$select_fields) {
+        next if $field-&gt;is_abnormal;
+        my $name = $field-&gt;name;
+        $special_order{$name} = {
+            order =&gt; [&quot;map_$name.sortkey&quot;, &quot;map_$name.value&quot;],
+            join  =&gt; {
+                table =&gt; $name,
+                from  =&gt; &quot;bugs.$name&quot;,
+                to    =&gt; &quot;value&quot;,
+                join  =&gt; 'INNER',
+            }
+        };
</ins><span class="cx">     }
</span><ins>+    $self-&gt;{special_order} = \%special_order;
+    return $self-&gt;{special_order};
+}
</ins><span class="cx"> 
</span><del>-    if (lsearch($fieldsref, 'map_components.name') &gt;= 0) {
-        push @supptables, &quot;INNER JOIN components AS map_components &quot; .
-                          &quot;ON bugs.component_id = map_components.id&quot;;
</del><ins>+sub _sql_order_by {
+    my ($self) = @_;
+    if (!$self-&gt;{sql_order_by}) {
+        my @order_by = map { $self-&gt;_translate_order_by_column($_) }
+                           $self-&gt;_input_order;
+        $self-&gt;{sql_order_by} = \@order_by;
</ins><span class="cx">     }
</span><ins>+    return @{ $self-&gt;{sql_order_by} };
+}
+
+sub _translate_order_by_column {
+    my ($self, $order_by_item) = @_;
+
+    my ($field, $direction) = split_order_term($order_by_item);
</ins><span class="cx">     
</span><del>-    if (grep($_ =~/AS (actual_time|percentage_complete)$/, @$fieldsref)) {
-        push(@supptables, &quot;LEFT JOIN longdescs AS ldtime &quot; .
-                          &quot;ON ldtime.bug_id = bugs.bug_id&quot;);
</del><ins>+    $direction = '' if lc($direction) eq 'asc';
+    my $special_order = $self-&gt;_special_order-&gt;{$field}-&gt;{order};
+    # Standard fields have underscores in their SELECT alias instead
+    # of a period (because aliases can't have periods).
+    $field =~ s/\./_/g;
+    my @items = $special_order ? @$special_order : $field;
+    if (lc($direction) eq 'desc') {
+        @items = map { &quot;$_ DESC&quot; } @items;
</ins><span class="cx">     }
</span><ins>+    return @items;
+}
</ins><span class="cx"> 
</span><del>-    my $minvotes;
-    if (defined $params-&gt;param('votes')) {
-        my $c = trim($params-&gt;param('votes'));
-        if ($c ne &quot;&quot;) {
-            if ($c !~ /^[0-9]*$/) {
-                ThrowUserError(&quot;illegal_at_least_x_votes&quot;,
-                                  { value =&gt; $c });
-            }
-            push(@specialchart, [&quot;votes&quot;, &quot;greaterthan&quot;, $c - 1]);
</del><ins>+#############################
+# Internal Accessors: LIMIT #
+#############################
+
+sub _sql_limit {
+    my ($self) = @_;
+    my $limit = $self-&gt;_params-&gt;{limit};
+    my $offset = $self-&gt;_params-&gt;{offset};
+    
+    my $max_results = Bugzilla-&gt;params-&gt;{'max_search_results'};
+    if (!$self-&gt;{allow_unlimited} &amp;&amp; (!$limit || $limit &gt; $max_results)) {
+        $limit = $max_results;
+    }
+    
+    if (defined($offset) &amp;&amp; !$limit) {
+        $limit = INT_MAX;
+    }
+    if (defined $limit) {
+        detaint_natural($limit) 
+            || ThrowCodeError('param_must_be_numeric', 
+                              { function =&gt; 'Bugzilla::Search::new',
+                                param    =&gt; 'limit' });
+        if (defined $offset) {
+            detaint_natural($offset)
+                || ThrowCodeError('param_must_be_numeric',
+                                  { function =&gt; 'Bugzilla::Search::new',
+                                    param    =&gt; 'offset' });
</ins><span class="cx">         }
</span><ins>+        return Bugzilla-&gt;dbh-&gt;sql_limit($limit, $offset);
</ins><span class="cx">     }
</span><ins>+    return '';
+}
</ins><span class="cx"> 
</span><del>-    if ($params-&gt;param('bug_id')) {
-        my $type = &quot;anyexact&quot;;
-        if ($params-&gt;param('bugidtype') &amp;&amp; $params-&gt;param('bugidtype') eq 'exclude') {
-            $type = &quot;nowords&quot;;
</del><ins>+############################
+# Internal Accessors: FROM #
+############################
+
+sub _column_join {
+    my ($self, $field) = @_;
+    # The _realname fields require the same join as the username fields.
+    $field =~ s/_realname$//;
+    my $column_joins = $self-&gt;_get_column_joins();
+    my $join_info = $column_joins-&gt;{$field};
+    if ($join_info) {
+        # Don't allow callers to modify the constant.
+        $join_info = dclone($join_info);
+    }
+    else {
+        if ($self-&gt;_multi_select_fields-&gt;{$field}) {
+            $join_info = { table =&gt; &quot;bug_$field&quot; };
</ins><span class="cx">         }
</span><del>-        push(@specialchart, [&quot;bug_id&quot;, $type, join(',', $params-&gt;param('bug_id'))]);
</del><span class="cx">     }
</span><ins>+    if ($join_info and !$join_info-&gt;{as}) {
+        $join_info = dclone($join_info);
+        $join_info-&gt;{as} = &quot;map_$field&quot;;
+    }
+    return $join_info ? $join_info : ();
+}
</ins><span class="cx"> 
</span><del>-    # If the user has selected all of either status or resolution, change to
-    # selecting none. This is functionally equivalent, but quite a lot faster.
-    # Also, if the status is __open__ or __closed__, translate those
-    # into their equivalent lists of open and closed statuses.
-    if ($params-&gt;param('bug_status')) {
-        my @bug_statuses = $params-&gt;param('bug_status');
-        my @legal_statuses = @{get_legal_field_values('bug_status')};
-        if (scalar(@bug_statuses) == scalar(@legal_statuses)
-            || $bug_statuses[0] eq &quot;__all__&quot;)
-        {
-            $params-&gt;delete('bug_status');
</del><ins>+# Sometimes we join the same table more than once. In this case, we
+# want to AND all the various critiera that were used in both joins.
+sub _combine_joins {
+    my ($self, $joins) = @_;
+    my @result;
+    while(my $join = shift @$joins) {
+        my $name = $join-&gt;{as};
+        my ($others_like_me, $the_rest) = part { $_-&gt;{as} eq $name ? 0 : 1 }
+                                               @$joins;
+        if ($others_like_me) {
+            my $from = $join-&gt;{from};
+            my $to   = $join-&gt;{to};
+            # Sanity check to make sure that we have the same from and to
+            # for all the same-named joins.
+            if ($from) {
+                all { $_-&gt;{from} eq $from } @$others_like_me
+                  or die &quot;Not all same-named joins have identical 'from': &quot;
+                         . Dumper($join, $others_like_me);
+            }
+            if ($to) {
+                all { $_-&gt;{to} eq $to } @$others_like_me
+                  or die &quot;Not all same-named joins have identical 'to': &quot;
+                         . Dumper($join, $others_like_me);
+            }
+            
+            # We don't need to call uniq here--translate_join will do that
+            # for us.
+            my @conditions = map { @{ $_-&gt;{extra} || [] } }
+                                 ($join, @$others_like_me);
+            $join-&gt;{extra} = \@conditions;
+            $joins = $the_rest;
</ins><span class="cx">         }
</span><del>-        elsif ($bug_statuses[0] eq '__open__') {
-            $params-&gt;param('bug_status', grep(is_open_state($_), 
-                                              @legal_statuses));
</del><ins>+        push(@result, $join);
+    }
+    
+    return @result;
+}
+
+# Takes all the &quot;then_to&quot; items and just puts them as the next item in
+# the array. Right now this only does one level of &quot;then_to&quot;, but we
+# could re-write this to handle then_to recursively if we need more levels.
+sub _extract_then_to {
+    my ($self, $joins) = @_;
+    my @result;
+    foreach my $join (@$joins) {
+        push(@result, $join);
+        if (my $then_to = $join-&gt;{then_to}) {
+            push(@result, $then_to);
</ins><span class="cx">         }
</span><del>-        elsif ($bug_statuses[0] eq &quot;__closed__&quot;) {
-            $params-&gt;param('bug_status', grep(!is_open_state($_), 
-                                              @legal_statuses));
</del><ins>+    }
+    return @result;
+}
+
+# JOIN statements for the SELECT and ORDER BY columns. This should not be
+# called until the moment it is needed, because _select_columns might be
+# modified by the charts.
+sub _select_order_joins {
+    my ($self) = @_;
+    my @joins;
+    foreach my $field ($self-&gt;_select_columns) {
+        my @column_join = $self-&gt;_column_join($field);
+        push(@joins, @column_join);
+    }
+    foreach my $field ($self-&gt;_input_order_columns) {
+        my $join_info = $self-&gt;_special_order-&gt;{$field}-&gt;{join};
+        if ($join_info) {
+            # Don't let callers modify SPECIAL_ORDER.
+            $join_info = dclone($join_info);
+            if (!$join_info-&gt;{as}) {
+                $join_info-&gt;{as} = &quot;map_$field&quot;;
+            }
+            push(@joins, $join_info);
</ins><span class="cx">         }
</span><span class="cx">     }
</span><ins>+    return @joins;
+}
+
+# These are the joins that are *always* in the FROM clause.
+sub _standard_joins {
+    my ($self) = @_;
+    my $user = $self-&gt;_user;
+    my @joins;
+
+    my $security_join = {
+        table =&gt; 'bug_group_map',
+        as    =&gt; 'security_map',
+    };
+    push(@joins, $security_join);
+
+    if ($user-&gt;id) {
+        $security_join-&gt;{extra} =
+            [&quot;NOT (&quot; . $user-&gt;groups_in_sql('security_map.group_id') . &quot;)&quot;];
+            
+        my $security_cc_join = {
+            table =&gt; 'cc',
+            as    =&gt; 'security_cc',
+            extra =&gt; ['security_cc.who = ' . $user-&gt;id],
+        };
+        push(@joins, $security_cc_join);
+    }
</ins><span class="cx">     
</span><del>-    if ($params-&gt;param('resolution')) {
-        my @resolutions = $params-&gt;param('resolution');
-        my $legal_resolutions = get_legal_field_values('resolution');
-        if (scalar(@resolutions) == scalar(@$legal_resolutions)) {
-            $params-&gt;delete('resolution');
-        }
</del><ins>+    return @joins;
+}
+
+sub _sql_from {
+    my ($self, $joins_input) = @_;
+    my @joins = ($self-&gt;_standard_joins, $self-&gt;_select_order_joins,
+                 @$joins_input);
+    @joins = $self-&gt;_extract_then_to(\@joins);
+    @joins = $self-&gt;_combine_joins(\@joins);
+    my @join_sql = map { $self-&gt;_translate_join($_) } @joins;
+    return &quot;bugs\n&quot; . join(&quot;\n&quot;, @join_sql);
+}
+
+# This takes a join data structure and turns it into actual JOIN SQL.
+sub _translate_join {
+    my ($self, $join_info) = @_;
+    
+    die &quot;join with no table: &quot; . Dumper($join_info) if !$join_info-&gt;{table};
+    die &quot;join with no 'as': &quot; . Dumper($join_info) if !$join_info-&gt;{as};
+        
+    my $from_table = &quot;bugs&quot;;
+    my $from  = $join_info-&gt;{from} || &quot;bug_id&quot;;
+    if ($from =~ /^(\w+)\.(\w+)$/) {
+        ($from_table, $from) = ($1, $2);
</ins><span class="cx">     }
</span><ins>+    my $table = $join_info-&gt;{table};
+    my $name  = $join_info-&gt;{as};
+    my $to    = $join_info-&gt;{to}    || &quot;bug_id&quot;;
+    my $join  = $join_info-&gt;{join}  || 'LEFT';
+    my @extra = @{ $join_info-&gt;{extra} || [] };
+    $name =~ s/\./_/g;
</ins><span class="cx">     
</span><del>-    my @legal_fields = (&quot;product&quot;, &quot;version&quot;, &quot;rep_platform&quot;, &quot;op_sys&quot;,
-                        &quot;bug_status&quot;, &quot;resolution&quot;, &quot;priority&quot;, &quot;bug_severity&quot;,
-                        &quot;assigned_to&quot;, &quot;reporter&quot;, &quot;component&quot;, &quot;classification&quot;,
-                        &quot;target_milestone&quot;, &quot;bug_group&quot;);
</del><ins>+    # If a term contains ORs, we need to put parens around the condition.
+    # This is a pretty weak test, but it's actually OK to put parens
+    # around too many things.
+    @extra = map { $_ =~ /\bOR\b/i ? &quot;($_)&quot; : $_ } @extra;
+    my $extra_condition = join(' AND ', uniq @extra);
+    if ($extra_condition) {
+        $extra_condition = &quot; AND $extra_condition&quot;;
+    }
</ins><span class="cx"> 
</span><del>-    # Include custom select fields.
-    push(@legal_fields, map { $_-&gt;name } @select_fields);
-    push(@legal_fields, map { $_-&gt;name } @multi_select_fields);
</del><ins>+    my @join_sql = &quot;$join JOIN $table AS $name&quot;
+                        . &quot; ON $from_table.$from = $name.$to$extra_condition&quot;;
+    return @join_sql;
+}
</ins><span class="cx"> 
</span><del>-    foreach my $field ($params-&gt;param()) {
-        if (lsearch(\@legal_fields, $field) != -1) {
-            push(@specialchart, [$field, &quot;anyexact&quot;,
-                                 join(',', $params-&gt;param($field))]);
</del><ins>+#############################
+# Internal Accessors: WHERE #
+#############################
+
+# Note: There's also quite a bit of stuff that affects the WHERE clause
+# in the &quot;Internal Accessors: Boolean Charts&quot; section.
+
+# The terms that are always in the WHERE clause. These implement bug
+# group security.
+sub _standard_where {
+    my ($self) = @_;
+    # If replication lags badly between the shadow db and the main DB,
+    # it's possible for bugs to show up in searches before their group
+    # controls are properly set. To prevent this, when initially creating
+    # bugs we set their creation_ts to NULL, and don't give them a creation_ts
+    # until their group controls are set. So if a bug has a NULL creation_ts,
+    # it shouldn't show up in searches at all.
+    my @where = ('bugs.creation_ts IS NOT NULL');
+    
+    my $security_term = 'security_map.group_id IS NULL';
+
+    my $user = $self-&gt;_user;
+    if ($user-&gt;id) {
+        my $userid = $user-&gt;id;
+        # This indentation makes the resulting SQL more readable.
+        $security_term .= &lt;&lt;END;
+
+        OR (bugs.reporter_accessible = 1 AND bugs.reporter = $userid)
+        OR (bugs.cclist_accessible = 1 AND security_cc.who IS NOT NULL)
+        OR bugs.assigned_to = $userid
+END
+        if (Bugzilla-&gt;params-&gt;{'useqacontact'}) {
+            $security_term.= &quot;        OR bugs.qa_contact = $userid&quot;;
</ins><span class="cx">         }
</span><ins>+        $security_term = &quot;($security_term)&quot;;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if ($params-&gt;param('keywords')) {
-        my $t = $params-&gt;param('keywords_type');
-        if (!$t || $t eq &quot;or&quot;) {
-            $t = &quot;anywords&quot;;
-        }
-        push(@specialchart, [&quot;keywords&quot;, $t, $params-&gt;param('keywords')]);
</del><ins>+    push(@where, $security_term);
+
+    return @where;
+}
+
+sub _sql_where {
+    my ($self, $main_clause) = @_;
+    # The newline and this particular spacing makes the resulting
+    # SQL a bit more readable for debugging.
+    my $where = join(&quot;\n   AND &quot;, $self-&gt;_standard_where);
+    my $clause_sql = $main_clause-&gt;as_string;
+    if ($clause_sql) {
+        $where .= &quot;\n   AND &quot; . $clause_sql;
</ins><span class="cx">     }
</span><ins>+    elsif (!Bugzilla-&gt;params-&gt;{'search_allow_no_criteria'}
+           &amp;&amp; !$self-&gt;{allow_unlimited})
+    {
+        ThrowUserError('buglist_parameters_required');
+    }
+    return $where;
+}
</ins><span class="cx"> 
</span><del>-    foreach my $id (&quot;1&quot;, &quot;2&quot;) {
-        if (!defined ($params-&gt;param(&quot;email$id&quot;))) {
-            next;
-        }
-        my $email = trim($params-&gt;param(&quot;email$id&quot;));
-        if ($email eq &quot;&quot;) {
-            next;
-        }
-        my $type = $params-&gt;param(&quot;emailtype$id&quot;);
-        if ($type eq &quot;exact&quot;) {
-            $type = &quot;anyexact&quot;;
-            foreach my $name (split(',', $email)) {
-                $name = trim($name);
-                if ($name) {
-                    login_to_id($name, THROW_ERROR);
-                }
-            }
-        }
</del><ins>+################################
+# Internal Accessors: GROUP BY #
+################################
</ins><span class="cx"> 
</span><del>-        my @clist;
-        foreach my $field (&quot;assigned_to&quot;, &quot;reporter&quot;, &quot;cc&quot;, &quot;qa_contact&quot;) {
-            if ($params-&gt;param(&quot;email$field$id&quot;)) {
-                push(@clist, $field, $type, $email);
-            }
-        }
-        if ($params-&gt;param(&quot;emaillongdesc$id&quot;)) {
-                push(@clist, &quot;commenter&quot;, $type, $email);
-        }
-        if (@clist) {
-            push(@specialchart, \@clist);
-        } else {
-            ThrowUserError(&quot;missing_email_type&quot;,
-                           { email =&gt; $email });
-        }
</del><ins>+# And these are the fields that we have to do GROUP BY for in DBs
+# that are more strict about putting everything into GROUP BY.
+sub _sql_group_by {
+    my ($self) = @_;
+
+    # Strict DBs require every element from the SELECT to be in the GROUP BY,
+    # unless that element is being used in an aggregate function.
+    my @extra_group_by;
+    foreach my $column ($self-&gt;_select_columns) {
+        next if $self-&gt;_skip_group_by-&gt;{$column};
+        my $sql = $self-&gt;COLUMNS-&gt;{$column}-&gt;{name};
+        push(@extra_group_by, $sql);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    my $chfieldfrom = trim(lc($params-&gt;param('chfieldfrom'))) || '';
-    my $chfieldto = trim(lc($params-&gt;param('chfieldto'))) || '';
-    $chfieldfrom = '' if ($chfieldfrom eq 'now');
-    $chfieldto = '' if ($chfieldto eq 'now');
-    my @chfield = $params-&gt;param('chfield');
-    my $chvalue = trim($params-&gt;param('chfieldvalue')) || '';
</del><ins>+    # And all items from ORDER BY must be in the GROUP BY. The above loop 
+    # doesn't catch items that were put into the ORDER BY from SPECIAL_ORDER.
+    foreach my $column ($self-&gt;_input_order_columns) {
+        my $special_order = $self-&gt;_special_order-&gt;{$column}-&gt;{order};
+        next if !$special_order;
+        push(@extra_group_by, @$special_order);
+    }
+    
+    @extra_group_by = uniq @extra_group_by;
+    
+    # bug_id is the only field we actually group by.
+    return ('bugs.bug_id', join(',', @extra_group_by));
+}
</ins><span class="cx"> 
</span><del>-    # 2003-05-20: The 'changedin' field is no longer in the UI, but we continue
-    # to process it because it will appear in stored queries and bookmarks.
-    my $changedin = trim($params-&gt;param('changedin')) || '';
-    if ($changedin) {
-        if ($changedin !~ /^[0-9]*$/) {
-            ThrowUserError(&quot;illegal_changed_in_last_x_days&quot;,
-                              { value =&gt; $changedin });
</del><ins>+# A helper for _sql_group_by.
+sub _skip_group_by {
+    my ($self) = @_;
+    return $self-&gt;{skip_group_by} if $self-&gt;{skip_group_by};
+    my @skip_list = GROUP_BY_SKIP;
+    push(@skip_list, keys %{ $self-&gt;_multi_select_fields });
+    my %skip_hash = map { $_ =&gt; 1 } @skip_list;
+    $self-&gt;{skip_group_by} = \%skip_hash;
+    return $self-&gt;{skip_group_by};
+}
+
+##############################################
+# Internal Accessors: Special Params Parsing #
+##############################################
+
+# Backwards compatibility for old field names.
+sub _convert_old_params {
+    my ($self) = @_;
+    my $params = $self-&gt;_params;
+    
+    # bugidtype has different values in modern Search.pm.
+    if (defined $params-&gt;{'bugidtype'}) {
+        my $value = $params-&gt;{'bugidtype'};
+        $params-&gt;{'bugidtype'} = $value eq 'exclude' ? 'nowords' : 'anyexact';
+    }
+    
+    foreach my $old_name (keys %{ FIELD_MAP() }) {
+        if (defined $params-&gt;{$old_name}) {
+            my $new_name = FIELD_MAP-&gt;{$old_name};
+            $params-&gt;{$new_name} = delete $params-&gt;{$old_name};
</ins><span class="cx">         }
</span><ins>+    }
+}
</ins><span class="cx"> 
</span><del>-        if (!$chfieldfrom
-            &amp;&amp; !$chfieldto
-            &amp;&amp; scalar(@chfield) == 1
-            &amp;&amp; $chfield[0] eq &quot;[Bug creation]&quot;)
</del><ins>+# This parses all the standard search parameters except for the boolean
+# charts.
+sub _special_charts {
+    my ($self) = @_;
+    $self-&gt;_convert_old_params();
+    $self-&gt;_special_parse_bug_status();
+    $self-&gt;_special_parse_resolution();
+    my $clause = new Bugzilla::Search::Clause();
+    $clause-&gt;add( $self-&gt;_parse_basic_fields()     );
+    $clause-&gt;add( $self-&gt;_special_parse_email()    );
+    $clause-&gt;add( $self-&gt;_special_parse_chfield()  );
+    $clause-&gt;add( $self-&gt;_special_parse_deadline() );
+    return $clause;
+}
+
+sub _parse_basic_fields {
+    my ($self) = @_;
+    my $params = $self-&gt;_params;
+    my $chart_fields = $self-&gt;_chart_fields;
+    
+    my $clause = new Bugzilla::Search::Clause();
+    foreach my $field_name (keys %$chart_fields) {
+        # CGI params shouldn't have periods in them, so we only accept
+        # period-separated fields with underscores where the periods go.
+        my $param_name = $field_name;
+        $param_name =~ s/\./_/g;
+        my @values = $self-&gt;_param_array($param_name);
+        next if !@values;
+        my $default_op = $param_name eq 'content' ? 'matches' : 'anyexact';
+        my $operator = $params-&gt;{&quot;${param_name}_type&quot;} || $default_op;
+        # Fields that are displayed as multi-selects are passed as arrays,
+        # so that they can properly search values that contain commas.
+        # However, other fields are sent as strings, so that they are properly
+        # split on commas if required.
+        my $field = $chart_fields-&gt;{$field_name};
+        my $pass_value;
+        if ($field-&gt;is_select or $field-&gt;name eq 'version'
+            or $field-&gt;name eq 'target_milestone')
</ins><span class="cx">         {
</span><del>-            # Deal with the special case where the query is using changedin
-            # to get bugs created in the last n days by converting the value
-            # into its equivalent for the chfieldfrom parameter.
-            $chfieldfrom = &quot;-&quot; . ($changedin - 1) . &quot;d&quot;;
</del><ins>+            $pass_value = \@values;
</ins><span class="cx">         }
</span><span class="cx">         else {
</span><del>-            # Oh boy, the general case.  Who knows why the user included
-            # the changedin parameter, but do our best to comply.
-            push(@specialchart, [&quot;changedin&quot;, &quot;lessthan&quot;, $changedin + 1]);
</del><ins>+            $pass_value = join(',', @values);
</ins><span class="cx">         }
</span><ins>+        $clause-&gt;add($field_name, $operator, $pass_value);
</ins><span class="cx">     }
</span><ins>+    return $clause;
+}
</ins><span class="cx"> 
</span><del>-    if ($chfieldfrom ne '' || $chfieldto ne '') {
-        my $sql_chfrom = $chfieldfrom ? $dbh-&gt;quote(SqlifyDate($chfieldfrom)):'';
-        my $sql_chto   = $chfieldto   ? $dbh-&gt;quote(SqlifyDate($chfieldto))  :'';
-        my $sql_chvalue = $chvalue ne '' ? $dbh-&gt;quote($chvalue) : '';
-        trick_taint($sql_chvalue);
-        if(!@chfield) {
-            push(@wherepart, &quot;bugs.delta_ts &gt;= $sql_chfrom&quot;) if ($sql_chfrom);
-            push(@wherepart, &quot;bugs.delta_ts &lt;= $sql_chto&quot;) if ($sql_chto);
-        } else {
-            my $bug_creation_clause;
-            my @list;
-            my @actlist;
-            foreach my $f (@chfield) {
-                if ($f eq &quot;[Bug creation]&quot;) {
-                    # Treat [Bug creation] differently because we need to look
-                    # at bugs.creation_ts rather than the bugs_activity table.
-                    my @l;
-                    push(@l, &quot;bugs.creation_ts &gt;= $sql_chfrom&quot;) if($sql_chfrom);
-                    push(@l, &quot;bugs.creation_ts &lt;= $sql_chto&quot;) if($sql_chto);
-                    $bug_creation_clause = &quot;(&quot; . join(' AND ', @l) . &quot;)&quot;;
-                } else {
-                    push(@actlist, get_field_id($f));
-                }
-            }
</del><ins>+sub _special_parse_bug_status {
+    my ($self) = @_;
+    my $params = $self-&gt;_params;
+    return if !defined $params-&gt;{'bug_status'};
+    # We want to allow the bug_status_type parameter to work normally,
+    # meaning that this special code should only be activated if we are
+    # doing the normal &quot;anyexact&quot; search on bug_status.
+    return if (defined $params-&gt;{'bug_status_type'}
+               and $params-&gt;{'bug_status_type'} ne 'anyexact');
</ins><span class="cx"> 
</span><del>-            # @actlist won't have any elements if the only field being searched
-            # is [Bug creation] (in which case we don't need bugs_activity).
-            if(@actlist) {
-                my $extra = &quot; actcheck.bug_id = bugs.bug_id&quot;;
-                push(@list, &quot;(actcheck.bug_when IS NOT NULL)&quot;);
-                if($sql_chfrom) {
-                    $extra .= &quot; AND actcheck.bug_when &gt;= $sql_chfrom&quot;;
-                }
-                if($sql_chto) {
-                    $extra .= &quot; AND actcheck.bug_when &lt;= $sql_chto&quot;;
-                }
-                if($sql_chvalue) {
-                    $extra .= &quot; AND actcheck.added = $sql_chvalue&quot;;
-                }
-                push(@supptables, &quot;LEFT JOIN bugs_activity AS actcheck &quot; .
-                                  &quot;ON $extra AND &quot; 
-                                 . $dbh-&gt;sql_in('actcheck.fieldid', \@actlist));
-            }
</del><ins>+    my @bug_status = $self-&gt;_param_array('bug_status');
+    # Also include inactive bug statuses, as you can query them.
+    my $legal_statuses = $self-&gt;_chart_fields-&gt;{'bug_status'}-&gt;legal_values;
</ins><span class="cx"> 
</span><del>-            # Now that we're done using @list to determine if there are any
-            # regular fields to search (and thus we need bugs_activity),
-            # add the [Bug creation] criterion to the list so we can OR it
-            # together with the others.
-            push(@list, $bug_creation_clause) if $bug_creation_clause;
</del><ins>+    # If the status contains __open__ or __closed__, translate those
+    # into their equivalent lists of open and closed statuses.
+    if (grep { $_ eq '__open__' } @bug_status) {
+        my @open = grep { $_-&gt;is_open } @$legal_statuses;
+        @open = map { $_-&gt;name } @open;
+        push(@bug_status, @open);
+    }
+    if (grep { $_ eq '__closed__' } @bug_status) {
+        my @closed = grep { not $_-&gt;is_open } @$legal_statuses;
+        @closed = map { $_-&gt;name } @closed;
+        push(@bug_status, @closed);
+    }
</ins><span class="cx"> 
</span><del>-            push(@wherepart, &quot;(&quot; . join(&quot; OR &quot;, @list) . &quot;)&quot;);
</del><ins>+    @bug_status = uniq @bug_status;
+    my $all = grep { $_ eq &quot;__all__&quot; } @bug_status;
+    # This will also handle removing __open__ and __closed__ for us
+    # (__all__ too, which is why we check for it above, first).
+    @bug_status = _valid_values(\@bug_status, $legal_statuses);
+
+    # If the user has selected every status, change to selecting none.
+    # This is functionally equivalent, but quite a lot faster.
+    if ($all or scalar(@bug_status) == scalar(@$legal_statuses)) {
+        delete $params-&gt;{'bug_status'};
+    }
+    else {
+        $params-&gt;{'bug_status'} = \@bug_status;
+    }
+}
+
+sub _special_parse_chfield {
+    my ($self) = @_;
+    my $params = $self-&gt;_params;
+    
+    my $date_from = trim(lc($params-&gt;{'chfieldfrom'} || ''));
+    my $date_to = trim(lc($params-&gt;{'chfieldto'} || ''));
+    $date_from = '' if $date_from eq 'now';
+    $date_to = '' if $date_to eq 'now';
+    my @fields = $self-&gt;_param_array('chfield');
+    my $value_to = $params-&gt;{'chfieldvalue'};
+    $value_to = '' if !defined $value_to;
+
+    @fields = map { $_ eq '[Bug creation]' ? 'creation_ts' : $_ } @fields;
+
+    my $clause = new Bugzilla::Search::Clause();
+
+    # It is always safe and useful to push delta_ts into the charts
+    # if there is a &quot;from&quot; date specified. It doesn't conflict with
+    # searching [Bug creation], because a bug's delta_ts is set to
+    # its creation_ts when it is created. So this just gives the
+    # database an additional index to possibly choose, on a table that
+    # is smaller than bugs_activity.
+    if ($date_from ne '') {
+        $clause-&gt;add('delta_ts', 'greaterthaneq', $date_from);
+    }
+    # It's not normally safe to do it for &quot;to&quot; dates, though--&quot;chfieldto&quot; means
+    # &quot;a field that changed before this date&quot;, and delta_ts could be either
+    # later or earlier than that, if we're searching for the time that a field
+    # changed. However, chfieldto all by itself, without any chfieldvalue or
+    # chfield, means &quot;just search delta_ts&quot;, and so we still want that to
+    # work.
+    if ($date_to ne '' and !@fields and $value_to eq '') {
+        $clause-&gt;add('delta_ts', 'lessthaneq', $date_to);
+    }
+
+    # Basically, we construct the chart like:
+    #
+    # (added_for_field1 = value OR added_for_field2 = value)
+    # AND (date_field1_changed &gt;= date_from OR date_field2_changed &gt;= date_from)
+    # AND (date_field1_changed &lt;= date_to OR date_field2_changed &lt;= date_to)
+    #
+    # Theoretically, all we *really* would need to do is look for the field id
+    # in the bugs_activity table, because we've already limited the search
+    # by delta_ts above, but there's no chart to do that, so we check the
+    # change date of the fields.
+    
+    if ($value_to ne '') {
+        my $value_clause = new Bugzilla::Search::Clause('OR');
+        foreach my $field (@fields) {
+            $value_clause-&gt;add($field, 'changedto', $value_to);
</ins><span class="cx">         }
</span><ins>+        $clause-&gt;add($value_clause);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    my $sql_deadlinefrom;
-    my $sql_deadlineto;
-    if ($user-&gt;in_group(Bugzilla-&gt;params-&gt;{'timetrackinggroup'})) {
-      my $deadlinefrom;
-      my $deadlineto;
-            
-      if ($params-&gt;param('deadlinefrom')){
-        $deadlinefrom = $params-&gt;param('deadlinefrom');
-        validate_date($deadlinefrom)
-          || ThrowUserError('illegal_date', {date =&gt; $deadlinefrom,
-                                             format =&gt; 'YYYY-MM-DD'});
-        $sql_deadlinefrom = $dbh-&gt;quote($deadlinefrom);
-        trick_taint($sql_deadlinefrom);
-        push(@wherepart, &quot;bugs.deadline &gt;= $sql_deadlinefrom&quot;);
-      }
-      
-      if ($params-&gt;param('deadlineto')){
-        $deadlineto = $params-&gt;param('deadlineto');
-        validate_date($deadlineto)
-          || ThrowUserError('illegal_date', {date =&gt; $deadlineto,
-                                             format =&gt; 'YYYY-MM-DD'});
-        $sql_deadlineto = $dbh-&gt;quote($deadlineto);
-        trick_taint($sql_deadlineto);
-        push(@wherepart, &quot;bugs.deadline &lt;= $sql_deadlineto&quot;);
-      }
-    }  
</del><ins>+    if ($date_from ne '') {
+        my $from_clause = new Bugzilla::Search::Clause('OR');
+        foreach my $field (@fields) {
+            $from_clause-&gt;add($field, 'changedafter', $date_from);
+        }
+        $clause-&gt;add($from_clause);
+    }
+    if ($date_to ne '') {
+        # chfieldto is supposed to be a relative date or a date of the form
+        # YYYY-MM-DD, i.e. without the time appended to it. We append the
+        # time ourselves so that the end date is correctly taken into account.
+        $date_to .= ' 23:59:59' if $date_to =~ /^\d{4}-\d{1,2}-\d{1,2}$/;
</ins><span class="cx"> 
</span><del>-    foreach my $f (&quot;short_desc&quot;, &quot;long_desc&quot;, &quot;bug_file_loc&quot;,
-                   &quot;status_whiteboard&quot;) {
-        if (defined $params-&gt;param($f)) {
-            my $s = trim($params-&gt;param($f));
-            if ($s ne &quot;&quot;) {
-                my $n = $f;
-                my $q = $dbh-&gt;quote($s);
-                trick_taint($q);
-                my $type = $params-&gt;param($f . &quot;_type&quot;);
-                push(@specialchart, [$f, $type, $s]);
-            }
</del><ins>+        my $to_clause = new Bugzilla::Search::Clause('OR');
+        foreach my $field (@fields) {
+            $to_clause-&gt;add($field, 'changedbefore', $date_to);
</ins><span class="cx">         }
</span><ins>+        $clause-&gt;add($to_clause);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (defined $params-&gt;param('content')) {
-        push(@specialchart, ['content', 'matches', $params-&gt;param('content')]);
</del><ins>+    return $clause;
+}
+
+sub _special_parse_deadline {
+    my ($self) = @_;
+    return if !$self-&gt;_user-&gt;is_timetracker;
+    my $params = $self-&gt;_params;
+    
+    my $clause = new Bugzilla::Search::Clause();
+    if (my $from = $params-&gt;{'deadlinefrom'}) {
+        $clause-&gt;add('deadline', 'greaterthaneq', $from);
</ins><span class="cx">     }
</span><ins>+    if (my $to = $params-&gt;{'deadlineto'}) {
+        $clause-&gt;add('deadline', 'lessthaneq', $to);
+    }
+    
+    return $clause;
+}
</ins><span class="cx"> 
</span><del>-    my $multi_fields = join('|', map($_-&gt;name, @multi_select_fields));
</del><ins>+sub _special_parse_email {
+    my ($self) = @_;
+    my $params = $self-&gt;_params;
+    
+    my @email_params = grep { $_ =~ /^email\d+$/ } keys %$params;
+    
+    my $clause = new Bugzilla::Search::Clause();
+    foreach my $param (@email_params) {
+        $param =~ /(\d+)$/;
+        my $id = $1;
+        my $email = trim($params-&gt;{&quot;email$id&quot;});
+        next if !$email;
+        my $type = $params-&gt;{&quot;emailtype$id&quot;} || 'anyexact';
+        $type = &quot;anyexact&quot; if $type eq &quot;exact&quot;;
</ins><span class="cx"> 
</span><del>-    my $chartid;
-    my $sequence = 0;
-    # $type_id is used by the code that queries for attachment flags.
-    my $type_id = 0;
-    my $f;
-    my $ff;
-    my $t;
-    my $q;
-    my $v;
-    my $term;
-    my %funcsbykey;
-    my %func_args = (
-        'chartid' =&gt; \$chartid,
-        'sequence' =&gt; \$sequence,
-        'f' =&gt; \$f,
-        'ff' =&gt; \$ff,
-        't' =&gt; \$t,
-        'v' =&gt; \$v,
-        'q' =&gt; \$q,
-        'term' =&gt; \$term,
-        'funcsbykey' =&gt; \%funcsbykey,
-        'supptables' =&gt; \@supptables,
-        'wherepart' =&gt; \@wherepart,
-        'having' =&gt; \@having,
-        'groupby' =&gt; \@groupby,
-        'chartfields' =&gt; \%chartfields,
-        'fields' =&gt; \@fields,
-    );
-    my @funcdefs = (
-        &quot;^(?:assigned_to|reporter|qa_contact),(?:notequals|equals|anyexact),%group\\.([^%]+)%&quot; =&gt; \&amp;_contact_exact_group,
-        &quot;^(?:assigned_to|reporter|qa_contact),(?:equals|anyexact),(%\\w+%)&quot; =&gt; \&amp;_contact_exact,
-        &quot;^(?:assigned_to|reporter|qa_contact),(?:notequals),(%\\w+%)&quot; =&gt; \&amp;_contact_notequals,
-        &quot;^(assigned_to|reporter),(?!changed)&quot; =&gt; \&amp;_assigned_to_reporter_nonchanged,
-        &quot;^qa_contact,(?!changed)&quot; =&gt; \&amp;_qa_contact_nonchanged,
-        &quot;^(?:cc),(?:notequals|equals|anyexact),%group\\.([^%]+)%&quot; =&gt; \&amp;_cc_exact_group,
-        &quot;^cc,(?:equals|anyexact),(%\\w+%)&quot; =&gt; \&amp;_cc_exact,
-        &quot;^cc,(?:notequals),(%\\w+%)&quot; =&gt; \&amp;_cc_notequals,
-        &quot;^cc,(?!changed)&quot; =&gt; \&amp;_cc_nonchanged,
-        &quot;^long_?desc,changedby&quot; =&gt; \&amp;_long_desc_changedby,
-        &quot;^long_?desc,changedbefore&quot; =&gt; \&amp;_long_desc_changedbefore_after,
-        &quot;^long_?desc,changedafter&quot; =&gt; \&amp;_long_desc_changedbefore_after,
-        &quot;^content,matches&quot; =&gt; \&amp;_content_matches,
-        &quot;^content,&quot; =&gt; sub { ThrowUserError(&quot;search_content_without_matches&quot;); },
-        &quot;^(?:deadline|creation_ts|delta_ts),(?:lessthan|greaterthan|equals|notequals),(?:-|\\+)?(?:\\d+)(?:[dDwWmMyY])\$&quot; =&gt; \&amp;_timestamp_compare,
-        &quot;^commenter,(?:equals|anyexact),(%\\w+%)&quot; =&gt; \&amp;_commenter_exact,
-        &quot;^commenter,&quot; =&gt; \&amp;_commenter,
-        &quot;^long_?desc,&quot; =&gt; \&amp;_long_desc,
-        &quot;^longdescs\.isprivate,&quot; =&gt; \&amp;_longdescs_isprivate,
-        &quot;^work_time,changedby&quot; =&gt; \&amp;_work_time_changedby,
-        &quot;^work_time,changedbefore&quot; =&gt; \&amp;_work_time_changedbefore_after,
-        &quot;^work_time,changedafter&quot; =&gt; \&amp;_work_time_changedbefore_after,
-        &quot;^work_time,&quot; =&gt; \&amp;_work_time,
-        &quot;^percentage_complete,&quot; =&gt; \&amp;_percentage_complete,
-        &quot;^bug_group,(?!changed)&quot; =&gt; \&amp;_bug_group_nonchanged,
-        &quot;^attach_data\.thedata,changed&quot; =&gt; \&amp;_attach_data_thedata_changed,
-        &quot;^attach_data\.thedata,&quot; =&gt; \&amp;_attach_data_thedata,
-        &quot;^attachments\.submitter,&quot; =&gt; \&amp;_attachments_submitter,
-        &quot;^attachments\..*,&quot; =&gt; \&amp;_attachments,
-        &quot;^flagtypes.name,&quot; =&gt; \&amp;_flagtypes_name,
-        &quot;^requestees.login_name,&quot; =&gt; \&amp;_requestees_login_name,
-        &quot;^setters.login_name,&quot; =&gt; \&amp;_setters_login_name,
-        &quot;^(changedin|days_elapsed),&quot; =&gt; \&amp;_changedin_days_elapsed,
-        &quot;^component,(?!changed)&quot; =&gt; \&amp;_component_nonchanged,
-        &quot;^product,(?!changed)&quot; =&gt; \&amp;_product_nonchanged,
-        &quot;^classification,(?!changed)&quot; =&gt; \&amp;_classification_nonchanged,
-        &quot;^keywords,(?!changed)&quot; =&gt; \&amp;_keywords_nonchanged,
-        &quot;^dependson,(?!changed)&quot; =&gt; \&amp;_dependson_nonchanged,
-        &quot;^blocked,(?!changed)&quot; =&gt; \&amp;_blocked_nonchanged,
-        &quot;^alias,(?!changed)&quot; =&gt; \&amp;_alias_nonchanged,
-        &quot;^owner_idle_time,(greaterthan|lessthan)&quot; =&gt; \&amp;_owner_idle_time_greater_less,
-        &quot;^($multi_fields),(?:notequals|notregexp|notsubstring|nowords|nowordssubstr)&quot; =&gt; \&amp;_multiselect_negative,
-        &quot;^($multi_fields),(?:allwords|allwordssubstr|anyexact)&quot; =&gt; \&amp;_multiselect_multiple,
-        &quot;^($multi_fields),(?!changed)&quot; =&gt; \&amp;_multiselect_nonchanged,
-        &quot;,equals&quot; =&gt; \&amp;_equals,
-        &quot;,notequals&quot; =&gt; \&amp;_notequals,
-        &quot;,casesubstring&quot; =&gt; \&amp;_casesubstring,
-        &quot;,substring&quot; =&gt; \&amp;_substring,
-        &quot;,substr&quot; =&gt; \&amp;_substring,
-        &quot;,notsubstring&quot; =&gt; \&amp;_notsubstring,
-        &quot;,regexp&quot; =&gt; \&amp;_regexp,
-        &quot;,notregexp&quot; =&gt; \&amp;_notregexp,
-        &quot;,lessthan&quot; =&gt; \&amp;_lessthan,
-        &quot;,matches&quot; =&gt; sub { ThrowUserError(&quot;search_content_without_matches&quot;); },
-        &quot;,greaterthan&quot; =&gt; \&amp;_greaterthan,
-        &quot;,anyexact&quot; =&gt; \&amp;_anyexact,
-        &quot;,anywordssubstr&quot; =&gt; \&amp;_anywordsubstr,
-        &quot;,allwordssubstr&quot; =&gt; \&amp;_allwordssubstr,
-        &quot;,nowordssubstr&quot; =&gt; \&amp;_nowordssubstr,
-        &quot;,anywords&quot; =&gt; \&amp;_anywords,
-        &quot;,allwords&quot; =&gt; \&amp;_allwords,
-        &quot;,nowords&quot; =&gt; \&amp;_nowords,
-        &quot;,(changedbefore|changedafter)&quot; =&gt; \&amp;_changedbefore_changedafter,
-        &quot;,(changedfrom|changedto)&quot; =&gt; \&amp;_changedfrom_changedto,
-        &quot;,changedby&quot; =&gt; \&amp;_changedby,
-    );
-    my @funcnames;
-    while (@funcdefs) {
-        my $key = shift(@funcdefs);
-        my $value = shift(@funcdefs);
-        if ($key =~ /^[^,]*$/) {
-            die &quot;All defs in %funcs must have a comma in their name: $key&quot;;
</del><ins>+        my $or_clause = new Bugzilla::Search::Clause('OR');
+        foreach my $field (qw(assigned_to reporter cc qa_contact)) {
+            if ($params-&gt;{&quot;email$field$id&quot;}) {
+                $or_clause-&gt;add($field, $type, $email);
+            }
</ins><span class="cx">         }
</span><del>-        if (exists $funcsbykey{$key}) {
-            die &quot;Duplicate key in %funcs: $key&quot;;
</del><ins>+        if ($params-&gt;{&quot;emaillongdesc$id&quot;}) {
+            $or_clause-&gt;add(&quot;commenter&quot;, $type, $email);
</ins><span class="cx">         }
</span><del>-        $funcsbykey{$key} = $value;
-        push(@funcnames, $key);
</del><ins>+        
+        $clause-&gt;add($or_clause);
</ins><span class="cx">     }
</span><ins>+    
+    return $clause;
+}
</ins><span class="cx"> 
</span><del>-    # first we delete any sign of &quot;Chart #-1&quot; from the HTML form hash
-    # since we want to guarantee the user didn't hide something here
-    my @badcharts = grep /^(field|type|value)-1-/, $params-&gt;param();
-    foreach my $field (@badcharts) {
-        $params-&gt;delete($field);
</del><ins>+sub _special_parse_resolution {
+    my ($self) = @_;
+    my $params = $self-&gt;_params;
+    return if !defined $params-&gt;{'resolution'};
+
+    my @resolution = $self-&gt;_param_array('resolution');
+    my $legal_resolutions = $self-&gt;_chart_fields-&gt;{resolution}-&gt;legal_values;
+    @resolution = _valid_values(\@resolution, $legal_resolutions, '---');
+    if (scalar(@resolution) == scalar(@$legal_resolutions)) {
+        delete $params-&gt;{'resolution'};
</ins><span class="cx">     }
</span><ins>+}
</ins><span class="cx"> 
</span><del>-    # now we take our special chart and stuff it into the form hash
-    my $chart = -1;
-    my $row = 0;
-    foreach my $ref (@specialchart) {
-        my $col = 0;
-        while (@$ref) {
-            $params-&gt;param(&quot;field$chart-$row-$col&quot;, shift(@$ref));
-            $params-&gt;param(&quot;type$chart-$row-$col&quot;, shift(@$ref));
-            $params-&gt;param(&quot;value$chart-$row-$col&quot;, shift(@$ref));
-            if ($debug) {
-                push(@debugdata, &quot;$row-$col = &quot; .
-                               $params-&gt;param(&quot;field$chart-$row-$col&quot;) . ' | ' .
-                               $params-&gt;param(&quot;type$chart-$row-$col&quot;) . ' | ' .
-                               $params-&gt;param(&quot;value$chart-$row-$col&quot;) . ' *');
-            }
-            $col++;
-
</del><ins>+sub _valid_values {
+    my ($input, $valid, $extra_value) = @_;
+    my @result;
+    foreach my $item (@$input) {
+        $item = trim($item);
+        if (defined $extra_value and $item eq $extra_value) {
+            push(@result, $item);
</ins><span class="cx">         }
</span><del>-        $row++;
</del><ins>+        elsif (grep { $_-&gt;name eq $item } @$valid) {
+            push(@result, $item);
+        }
</ins><span class="cx">     }
</span><ins>+    return @result;
+}
</ins><span class="cx"> 
</span><ins>+######################################
+# Internal Accessors: Boolean Charts #
+######################################
</ins><span class="cx"> 
</span><del>-# A boolean chart is a way of representing the terms in a logical
-# expression.  Bugzilla builds SQL queries depending on how you enter
-# terms into the boolean chart. Boolean charts are represented in
-# urls as tree-tuples of (chart id, row, column). The query form
-# (query.cgi) may contain an arbitrary number of boolean charts where
-# each chart represents a clause in a SQL query.
-#
-# The query form starts out with one boolean chart containing one
-# row and one column.  Extra rows can be created by pressing the
-# AND button at the bottom of the chart.  Extra columns are created
-# by pressing the OR button at the right end of the chart. Extra
-# charts are created by pressing &quot;Add another boolean chart&quot;.
-#
-# Each chart consists of an arbitrary number of rows and columns.
-# The terms within a row are ORed together. The expressions represented
-# by each row are ANDed together. The expressions represented by each
-# chart are ANDed together.
-#
-#        ----------------------
-#        | col2 | col2 | col3 |
-# --------------|------|------|
-# | row1 |  a1  |  a2  |      |
-# |------|------|------|------|  =&gt; ((a1 OR a2) AND (b1 OR b2 OR b3) AND (c1))
-# | row2 |  b1  |  b2  |  b3  |
-# |------|------|------|------|
-# | row3 |  c1  |      |      |
-# -----------------------------
-#
-#        --------
-#        | col2 |
-# --------------|
-# | row1 |  d1  | =&gt; (d1)
-# ---------------
-#
-# Together, these two charts represent a SQL expression like this
-# SELECT blah FROM blah WHERE ( (a1 OR a2)AND(b1 OR b2 OR b3)AND(c1)) AND (d1)
-#
-# The terms within a single row of a boolean chart are all constraints
-# on a single piece of data.  If you're looking for a bug that has two
-# different people cc'd on it, then you need to use two boolean charts.
-# This will find bugs with one CC matching 'foo@blah.org' and and another
-# CC matching 'bar@blah.org'.
-#
-# --------------------------------------------------------------
-# CC    | equal to
-# foo@blah.org
-# --------------------------------------------------------------
-# CC    | equal to
-# bar@blah.org
-#
-# If you try to do this query by pressing the AND button in the
-# original boolean chart then what you'll get is an expression that
-# looks for a single CC where the login name is both &quot;foo@blah.org&quot;,
-# and &quot;bar@blah.org&quot;. This is impossible.
-#
-# --------------------------------------------------------------
-# CC    | equal to
-# foo@blah.org
-# AND
-# CC    | equal to
-# bar@blah.org
-# --------------------------------------------------------------
</del><ins>+sub _charts_to_conditions {
+    my ($self) = @_;
+    
+    my $clause = $self-&gt;_charts;
+    my @joins;
+    $clause-&gt;walk_conditions(sub {
+        my ($condition) = @_;
+        return if !$condition-&gt;translated;
+        push(@joins, @{ $condition-&gt;translated-&gt;{joins} });
+    });
+    return (\@joins, $clause);
+}
</ins><span class="cx"> 
</span><del>-# $chartid is the number of the current chart whose SQL we're constructing
-# $row is the current row of the current chart
</del><ins>+sub _charts {
+    my ($self) = @_;
+    
+    my $clause = $self-&gt;_params_to_data_structure();
+    my $chart_id = 0;
+    $clause-&gt;walk_conditions(sub { $self-&gt;_handle_chart($chart_id++, @_) });
+    return $clause;
+}
</ins><span class="cx"> 
</span><del>-# names for table aliases are constructed using $chartid and $row
-#   SELECT blah  FROM $table &quot;$table_$chartid_$row&quot; WHERE ....
</del><ins>+sub _params_to_data_structure {
+    my ($self) = @_;
+    
+    # First we get the &quot;special&quot; charts, representing all the normal
+    # field son the search page. This may modify _params, so it needs to
+    # happen first.
+    my $clause = $self-&gt;_special_charts;
</ins><span class="cx"> 
</span><del>-# $f  = field of table in bug db (e.g. bug_id, reporter, etc)
-# $ff = qualified field name (field name prefixed by table)
-#       e.g. bugs_activity.bug_id
-# $t  = type of query. e.g. &quot;equal to&quot;, &quot;changed after&quot;, case sensitive substr&quot;
-# $v  = value - value the user typed in to the form
-# $q  = sanitized version of user input trick_taint(($dbh-&gt;quote($v)))
-# @supptables = Tables and/or table aliases used in query
-# %suppseen   = A hash used to store all the tables in supptables to weed
-#               out duplicates.
-# @supplist   = A list used to accumulate all the JOIN clauses for each
-#               chart to merge the ON sections of each.
-# $suppstring = String which is pasted into query containing all table names
</del><ins>+    # Then we process the old Boolean Charts input format.
+    $clause-&gt;add( $self-&gt;_boolean_charts );
+    
+    # And then process the modern &quot;custom search&quot; format.
+    $clause-&gt;add( $self-&gt;_custom_search );
+   
+    return $clause;
+}
</ins><span class="cx"> 
</span><del>-    # get a list of field names to verify the user-submitted chart fields against
-    %chartfields = @{$dbh-&gt;selectcol_arrayref(
-        q{SELECT name, id FROM fielddefs}, { Columns=&gt;[1,2] })};
</del><ins>+sub _boolean_charts {
+    my ($self) = @_;
+    
+    my $params = $self-&gt;_params;
+    my @param_list = keys %$params;
+    
+    my @all_field_params = grep { /^field-?\d+/ } @param_list;
+    my @chart_ids = map { /^field(-?\d+)/; $1 } @all_field_params;
+    @chart_ids = sort { $a &lt;=&gt; $b } uniq @chart_ids;
+    
+    my $clause = new Bugzilla::Search::Clause();
+    foreach my $chart_id (@chart_ids) {
+        my @all_and = grep { /^field$chart_id-\d+/ } @param_list;
+        my @and_ids = map { /^field$chart_id-(\d+)/; $1 } @all_and;
+        @and_ids = sort { $a &lt;=&gt; $b } uniq @and_ids;
+        
+        my $and_clause = new Bugzilla::Search::Clause();
+        foreach my $and_id (@and_ids) {
+            my @all_or = grep { /^field$chart_id-$and_id-\d+/ } @param_list;
+            my @or_ids = map { /^field$chart_id-$and_id-(\d+)/; $1 } @all_or;
+            @or_ids = sort { $a &lt;=&gt; $b } uniq @or_ids;
+            
+            my $or_clause = new Bugzilla::Search::Clause('OR');
+            foreach my $or_id (@or_ids) {
+                my $identifier = &quot;$chart_id-$and_id-$or_id&quot;;
+                my $field = $params-&gt;{&quot;field$identifier&quot;};
+                my $operator = $params-&gt;{&quot;type$identifier&quot;};
+                my $value = $params-&gt;{&quot;value$identifier&quot;};                
+                $or_clause-&gt;add($field, $operator, $value);
+            }
+            $and_clause-&gt;add($or_clause);
+            $and_clause-&gt;negate(1) if $params-&gt;{&quot;negate$chart_id&quot;};
+        }
+        $clause-&gt;add($and_clause);
+    }
+    
+    return $clause;
+}
</ins><span class="cx"> 
</span><del>-    $row = 0;
-    for ($chart=-1 ;
-         $chart &lt; 0 || $params-&gt;param(&quot;field$chart-0-0&quot;) ;
-         $chart++) {
-        $chartid = $chart &gt;= 0 ? $chart : &quot;&quot;;
-        my @chartandlist = ();
-        for ($row = 0 ;
-             $params-&gt;param(&quot;field$chart-$row-0&quot;) ;
-             $row++) {
-            my @orlist;
-            for (my $col = 0 ;
-                 $params-&gt;param(&quot;field$chart-$row-$col&quot;) ;
-                 $col++) {
-                $f = $params-&gt;param(&quot;field$chart-$row-$col&quot;) || &quot;noop&quot;;
-                $t = $params-&gt;param(&quot;type$chart-$row-$col&quot;) || &quot;noop&quot;;
-                $v = $params-&gt;param(&quot;value$chart-$row-$col&quot;);
-                $v = &quot;&quot; if !defined $v;
-                $v = trim($v);
-                if ($f eq &quot;noop&quot; || $t eq &quot;noop&quot; || $v eq &quot;&quot;) {
-                    next;
-                }
-                # chart -1 is generated by other code above, not from the user-
-                # submitted form, so we'll blindly accept any values in chart -1
-                if ((!$chartfields{$f}) &amp;&amp; ($chart != -1)) {
-                    ThrowCodeError(&quot;invalid_field_name&quot;, {field =&gt; $f});
-                }
</del><ins>+sub _custom_search {
+    my ($self) = @_;
+    my $params = $self-&gt;_params;
</ins><span class="cx"> 
</span><del>-                # This is either from the internal chart (in which case we
-                # already know about it), or it was in %chartfields, so it is
-                # a valid field name, which means that it's ok.
-                trick_taint($f);
-                $q = $dbh-&gt;quote($v);
-                trick_taint($q);
-                my $rhs = $v;
-                $rhs =~ tr/,//;
-                my $func;
-                $term = undef;
-                foreach my $key (@funcnames) {
-                    if (&quot;$f,$t,$rhs&quot; =~ m/$key/) {
-                        my $ref = $funcsbykey{$key};
-                        if ($debug) {
-                            push(@debugdata, &quot;$key ($f / $t / $rhs) =&gt;&quot;);
-                        }
-                        $ff = $f;
-                        if ($f !~ /\./) {
-                            $ff = &quot;bugs.$f&quot;;
-                        }
-                        $self-&gt;$ref(%func_args);
-                        if ($debug) {
-                            push(@debugdata, &quot;$f / $t / $v / &quot; .
-                                             ($term || &quot;undef&quot;) . &quot; *&quot;);
-                        }
-                        if ($term) {
-                            last;
-                        }
-                    }
-                }
-                if ($term) {
-                    push(@orlist, $term);
-                }
-                else {
-                    # This field and this type don't work together.
-                    ThrowCodeError(&quot;field_type_mismatch&quot;,
-                                   { field =&gt; $params-&gt;param(&quot;field$chart-$row-$col&quot;),
-                                     type =&gt; $params-&gt;param(&quot;type$chart-$row-$col&quot;),
-                                   });
-                }
-            }
-            if (@orlist) {
-                @orlist = map(&quot;($_)&quot;, @orlist) if (scalar(@orlist) &gt; 1);
-                push(@chartandlist, &quot;(&quot; . join(&quot; OR &quot;, @orlist) . &quot;)&quot;);
-            }
</del><ins>+    my $current_clause = new Bugzilla::Search::Clause($params-&gt;{j_top});
+    my @clause_stack;
+    foreach my $id ($self-&gt;_field_ids) {
+        my $field = $params-&gt;{&quot;f$id&quot;};
+        if ($field eq 'OP') {
+            my $joiner = $params-&gt;{&quot;j$id&quot;};
+            my $new_clause = new Bugzilla::Search::Clause($joiner);
+            $new_clause-&gt;negate($params-&gt;{&quot;n$id&quot;});
+            $current_clause-&gt;add($new_clause);
+            push(@clause_stack, $current_clause);
+            $current_clause = $new_clause;
+            next;
</ins><span class="cx">         }
</span><del>-        if (@chartandlist) {
-            if ($params-&gt;param(&quot;negate$chart&quot;)) {
-                push(@andlist, &quot;NOT(&quot; . join(&quot; AND &quot;, @chartandlist) . &quot;)&quot;);
-            } else {
-                push(@andlist, &quot;(&quot; . join(&quot; AND &quot;, @chartandlist) . &quot;)&quot;);
-            }
</del><ins>+        if ($field eq 'CP') {
+            $current_clause = pop @clause_stack;
+            ThrowCodeError('search_cp_without_op', { id =&gt; $id })
+                if !$current_clause;
+            next;
</ins><span class="cx">         }
</span><ins>+        
+        my $operator = $params-&gt;{&quot;o$id&quot;};
+        my $value = $params-&gt;{&quot;v$id&quot;};
+        my $condition = condition($field, $operator, $value);
+        $condition-&gt;negate($params-&gt;{&quot;n$id&quot;});
+        $current_clause-&gt;add($condition);
</ins><span class="cx">     }
</span><ins>+    
+    # We allow people to specify more OPs than CPs, so at the end of the
+    # loop our top clause may be still in the stack instead of being
+    # $current_clause.
+    return $clause_stack[0] || $current_clause;
+}
</ins><span class="cx"> 
</span><del>-    # The ORDER BY clause goes last, but can require modifications
-    # to other parts of the query, so we want to create it before we
-    # write the FROM clause.
-    foreach my $orderitem (@inputorder) {
-        # Some fields have 'AS' aliases. The aliases go in the ORDER BY,
-        # not the whole fields.
-        # XXX - Ideally, we would get just the aliases in @inputorder,
-        # and we'd never have to deal with this.
-        if ($orderitem =~ /\s+AS\s+(.+)$/i) {
-            $orderitem = $1;
-        }
-        BuildOrderBy(\%special_order, $orderitem, \@orderby);
</del><ins>+sub _field_ids {
+    my ($self) = @_;
+    my $params = $self-&gt;_params;
+    my @param_list = keys %$params;
+    
+    my @field_params = grep { /^f\d+$/ } @param_list;
+    my @field_ids = map { /(\d+)/; $1 } @field_params;
+    @field_ids = sort { $a &lt;=&gt; $b } @field_ids;
+    return @field_ids;
+}
+
+sub _handle_chart {
+    my ($self, $chart_id, $condition) = @_;
+    my $dbh = Bugzilla-&gt;dbh;
+    my $params = $self-&gt;_params;
+    my ($field, $operator, $value) = $condition-&gt;fov;
+
+    $field = FIELD_MAP-&gt;{$field} || $field;
+
+    return if (!defined $field or !defined $operator or !defined $value);
+    
+    my $string_value;
+    if (ref $value eq 'ARRAY') {
+        # Trim input and ignore blank values.
+        @$value = map { trim($_) } @$value;
+        @$value = grep { defined $_ and $_ ne '' } @$value;
+        return if !@$value;
+        $string_value = join(',', @$value);
</ins><span class="cx">     }
</span><del>-    # Now JOIN the correct tables in the FROM clause.
-    # This is done separately from the above because it's
-    # cleaner to do it this way.
-    foreach my $orderitem (@inputorder) {
-        # Grab the part without ASC or DESC.
-        my @splitfield = split(/\s+/, $orderitem);
-        if ($special_order_join{$splitfield[0]}) {
-            push(@supptables, $special_order_join{$splitfield[0]});
-        }
</del><ins>+    else {
+        return if $value eq '';
+        $string_value = $value;
</ins><span class="cx">     }
</span><ins>+    
+    $self-&gt;_chart_fields-&gt;{$field}
+        or ThrowCodeError(&quot;invalid_field_name&quot;, { field =&gt; $field });
+    trick_taint($field);
+    
+    # This is the field as you'd reference it in a SQL statement.
+    my $full_field = $field =~ /\./ ? $field : &quot;bugs.$field&quot;;
</ins><span class="cx"> 
</span><del>-    my %suppseen = (&quot;bugs&quot; =&gt; 1);
-    my $suppstring = &quot;bugs&quot;;
-    my @supplist = (&quot; &quot;);
-    foreach my $str (@supptables) {
</del><ins>+    # &quot;value&quot; and &quot;quoted&quot; are for search functions that always operate
+    # on a scalar string and never care if they were passed multiple
+    # parameters. If the user does pass multiple parameters, they will
+    # become a space-separated string for those search functions.
+    #
+    # all_values is for search functions that do operate
+    # on multiple values, like anyexact.
+    
+    my %search_args = (
+        chart_id   =&gt; $chart_id,
+        sequence   =&gt; $chart_id,
+        field      =&gt; $field,
+        full_field =&gt; $full_field,
+        operator   =&gt; $operator,
+        value      =&gt; $string_value,
+        all_values =&gt; $value,
+        joins      =&gt; [],
+    );
+    $search_args{quoted} = $self-&gt;_quote_unless_numeric(\%search_args);
+    # This should add a &quot;term&quot; selement to %search_args.
+    $self-&gt;do_search_function(\%search_args);
</ins><span class="cx"> 
</span><del>-        if ($str =~ /^(LEFT|INNER|RIGHT)\s+JOIN/i) {
-            $str =~ /^(.*?)\s+ON\s+(.*)$/i;
-            my ($leftside, $rightside) = ($1, $2);
-            if (defined $suppseen{$leftside}) {
-                $supplist[$suppseen{$leftside}] .= &quot; AND ($rightside)&quot;;
-            } else {
-                $suppseen{$leftside} = scalar @supplist;
-                push @supplist, &quot; $leftside ON ($rightside)&quot;;
-            }
-        } else {
-            # Do not accept implicit joins using comma operator
-            # as they are not DB agnostic
-            ThrowCodeError(&quot;comma_operator_deprecated&quot;);
-        }
</del><ins>+    # If term is left empty, then this means the criteria
+    # has no effect and can be ignored.
+    return unless $search_args{term};
+
+    # All the things here that don't get pulled out of
+    # %search_args are their original values before
+    # do_search_function modified them.   
+    $self-&gt;search_description({
+        field =&gt; $field, type =&gt; $operator,
+        value =&gt; $string_value, term =&gt; $search_args{term},
+    });
+    
+    $condition-&gt;translated(\%search_args);
+}
+
+##################################
+# do_search_function And Helpers #
+##################################
+
+# This takes information about the current boolean chart and translates
+# it into SQL, using the constants at the top of this file.
+sub do_search_function {
+    my ($self, $args) = @_;
+    my ($field, $operator) = @$args{qw(field operator)};
+    
+    if (my $parse_func = SPECIAL_PARSING-&gt;{$field}) {
+        $self-&gt;$parse_func($args);
+        # Some parsing functions set $term, though most do not.
+        # For the ones that set $term, we don't need to do any further
+        # parsing.
+        return if $args-&gt;{term};
</ins><span class="cx">     }
</span><del>-    $suppstring .= join('', @supplist);
</del><span class="cx">     
</span><del>-    # Make sure we create a legal SQL query.
-    @andlist = (&quot;1 = 1&quot;) if !@andlist;
</del><ins>+    my $operator_field_override = $self-&gt;_get_operator_field_override();
+    my $override = $operator_field_override-&gt;{$field};
+    # Attachment fields get special handling, if they don't have a specific
+    # individual override.
+    if (!$override and $field =~ /^attachments\./) {
+        $override = $operator_field_override-&gt;{attachments};
+    }
+    # If there's still no override, check for an override on the field's type.
+    if (!$override) {
+        my $field_obj = $self-&gt;_chart_fields-&gt;{$field};
+        $override = $operator_field_override-&gt;{$field_obj-&gt;type};
+    }
+    
+    if ($override) {
+        my $search_func = $self-&gt;_pick_override_function($override, $operator);
+        $self-&gt;$search_func($args) if $search_func;
+    }
</ins><span class="cx"> 
</span><del>-    my $query = &quot;SELECT &quot; . join(', ', @fields) .
-                &quot; FROM $suppstring&quot; .
-                &quot; LEFT JOIN bug_group_map &quot; .
-                &quot; ON bug_group_map.bug_id = bugs.bug_id &quot;;
</del><ins>+    # Some search functions set $term, and some don't. For the ones that
+    # don't (or for fields that don't have overrides) we now call the
+    # direct operator function from OPERATORS.
+    if (!defined $args-&gt;{term}) {
+        $self-&gt;_do_operator_function($args);
+    }
+    
+    if (!defined $args-&gt;{term}) {
+        # This field and this type don't work together. Generally,
+        # this should never be reached, because it should be handled
+        # explicitly by OPERATOR_FIELD_OVERRIDE.
+        ThrowUserError(&quot;search_field_operator_invalid&quot;,
+                       { field =&gt; $field, operator =&gt; $operator });
+    }
+}
</ins><span class="cx"> 
</span><del>-    if ($user-&gt;id) {
-        if (%{$user-&gt;groups}) {
-            $query .= &quot; AND bug_group_map.group_id NOT IN (&quot; . join(',', values(%{$user-&gt;groups})) . &quot;) &quot;;
-        }
</del><ins>+# A helper for various search functions that need to run operator
+# functions directly.
+sub _do_operator_function {
+    my ($self, $func_args) = @_;
+    my $operator = $func_args-&gt;{operator};
+    my $operator_func = OPERATORS-&gt;{$operator};
+    $self-&gt;$operator_func($func_args);
+}
</ins><span class="cx"> 
</span><del>-        $query .= &quot; LEFT JOIN cc ON cc.bug_id = bugs.bug_id AND cc.who = &quot; . $user-&gt;id;
</del><ins>+sub _reverse_operator {
+    my ($self, $operator) = @_;
+    my $reverse = OPERATOR_REVERSE-&gt;{$operator};
+    return $reverse if $reverse;
+    if ($operator =~ s/^not//) {
+        return $operator;
</ins><span class="cx">     }
</span><ins>+    return &quot;not$operator&quot;;
+}
</ins><span class="cx"> 
</span><del>-    $query .= &quot; WHERE &quot; . join(' AND ', (@wherepart, @andlist)) .
-              &quot; AND bugs.creation_ts IS NOT NULL AND ((bug_group_map.group_id IS NULL)&quot;;
</del><ins>+sub _pick_override_function {
+    my ($self, $override, $operator) = @_;
+    my $search_func = $override-&gt;{$operator};
</ins><span class="cx"> 
</span><del>-    if ($user-&gt;id) {
-        my $userid = $user-&gt;id;
-        $query .= &quot;    OR (bugs.reporter_accessible = 1 AND bugs.reporter = $userid) &quot; .
-              &quot;    OR (bugs.cclist_accessible = 1 AND cc.who IS NOT NULL) &quot; .
-              &quot;    OR (bugs.assigned_to = $userid) &quot;;
-        if (Bugzilla-&gt;params-&gt;{'useqacontact'}) {
-            $query .= &quot;OR (bugs.qa_contact = $userid) &quot;;
</del><ins>+    if (!$search_func) {
+        # If we don't find an override for one specific operator,
+        # then there are some special override types:
+        # _non_changed: For any operator that doesn't have the word
+        #               &quot;changed&quot; in it
+        # _default: Overrides all operators that aren't explicitly specified.
+        if ($override-&gt;{_non_changed} and $operator !~ /changed/) {
+            $search_func = $override-&gt;{_non_changed};
</ins><span class="cx">         }
</span><ins>+        elsif ($override-&gt;{_default}) {
+            $search_func = $override-&gt;{_default};
+        }
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    foreach my $field (@fields, @orderby) {
-        next if ($field =~ /(AVG|SUM|COUNT|MAX|MIN|VARIANCE)\s*\(/i ||
-                 $field =~ /^\d+$/ || $field eq &quot;bugs.bug_id&quot; ||
-                 $field =~ /^(relevance|actual_time|percentage_complete)/);
-        # The structure of fields is of the form:
-        # [foo AS] {bar | bar.baz} [ASC | DESC]
-        # Only the mandatory part bar OR bar.baz is of interest.
-        # But for Oracle, it needs the real name part instead.
-        my $regexp = $dbh-&gt;GROUPBY_REGEXP;
-        if ($field =~ /$regexp/i) {
-            push(@groupby, $1) if !grep($_ eq $1, @groupby);
-        }
</del><ins>+    return $search_func;
+}
+
+sub _get_operator_field_override {
+    my $self = shift;
+    my $cache = Bugzilla-&gt;request_cache;
+
+    return $cache-&gt;{operator_field_override} 
+        if defined $cache-&gt;{operator_field_override};
+
+    my %operator_field_override = %{ OPERATOR_FIELD_OVERRIDE() };
+    Bugzilla::Hook::process('search_operator_field_override',
+                            { search =&gt; $self, 
+                              operators =&gt; \%operator_field_override });
+
+    $cache-&gt;{operator_field_override} = \%operator_field_override;
+    return $cache-&gt;{operator_field_override};
+}
+
+sub _get_column_joins {
+    my $self = shift;
+    my $cache = Bugzilla-&gt;request_cache;
+
+    return $cache-&gt;{column_joins} if defined $cache-&gt;{column_joins};
+
+    my %column_joins = %{ COLUMN_JOINS() };
+    Bugzilla::Hook::process('buglist_column_joins',
+                            { column_joins =&gt; \%column_joins });
+
+    $cache-&gt;{column_joins} = \%column_joins;
+    return $cache-&gt;{column_joins};
+}
+
+###########################
+# Search Function Helpers #
+###########################
+
+# When we're doing a numeric search against a numeric column, we want to
+# just put a number into the SQL instead of a string. On most DBs, this
+# is just a performance optimization, but on SQLite it actually changes
+# the behavior of some searches.
+sub _quote_unless_numeric {
+    my ($self, $args, $value) = @_;
+    if (!defined $value) {
+        $value = $args-&gt;{value};
</ins><span class="cx">     }
</span><del>-    $query .= &quot;) &quot; . $dbh-&gt;sql_group_by(&quot;bugs.bug_id&quot;, join(', ', @groupby));
</del><ins>+    my ($field, $operator) = @$args{qw(field operator)};
+    
+    my $numeric_operator = !grep { $_ eq $operator } NON_NUMERIC_OPERATORS;
+    my $numeric_field = $self-&gt;_chart_fields-&gt;{$field}-&gt;is_numeric;
+    my $numeric_value = ($value =~ NUMBER_REGEX) ? 1 : 0;
+    my $is_numeric = $numeric_operator &amp;&amp; $numeric_field &amp;&amp; $numeric_value;
+    if ($is_numeric) {
+        my $quoted = $value;
+        trick_taint($quoted);
+        return $quoted;
+    }
+    return Bugzilla-&gt;dbh-&gt;quote($value);
+}
</ins><span class="cx"> 
</span><ins>+sub build_subselect {
+    my ($outer, $inner, $table, $cond) = @_;
+    return &quot;$outer IN (SELECT $inner FROM $table WHERE $cond)&quot;;
+}
</ins><span class="cx"> 
</span><del>-    if (@having) {
-        $query .= &quot; HAVING &quot; . join(&quot; AND &quot;, @having);
</del><ins>+# Used by anyexact to get the list of input values. This allows us to
+# support values with commas inside of them in the standard charts, and
+# still accept string values for the boolean charts (and split them on
+# commas).
+sub _all_values {
+    my ($self, $args, $split_on) = @_;
+    $split_on ||= qr/[\s,]+/;
+    my $dbh = Bugzilla-&gt;dbh;
+    my $all_values = $args-&gt;{all_values};
+    
+    my @array;
+    if (ref $all_values eq 'ARRAY') {
+        @array = @$all_values;
</ins><span class="cx">     }
</span><ins>+    else {
+        @array = split($split_on, $all_values);
+        @array = map { trim($_) } @array;
+        @array = grep { defined $_ and $_ ne '' } @array;
+    }
+    
+    if ($args-&gt;{field} eq 'resolution') {
+        @array = map { $_ eq '---' ? '' : $_ } @array;
+    }
+    
+    return @array;
+}
</ins><span class="cx"> 
</span><del>-    if (@orderby) {
-        $query .= &quot; ORDER BY &quot; . join(',', @orderby);
</del><ins>+# Support for &quot;any/all/nowordssubstr&quot; comparison type (&quot;words as substrings&quot;)
+sub _substring_terms {
+    my ($self, $args) = @_;
+    my $dbh = Bugzilla-&gt;dbh;
+
+    # We don't have to (or want to) use _all_values, because we'd just
+    # split each term on spaces and commas anyway.
+    my @words = split(/[\s,]+/, $args-&gt;{value});
+    @words = grep { defined $_ and $_ ne '' } @words;
+    @words = map { $dbh-&gt;quote($_) } @words;
+    my @terms = map { $dbh-&gt;sql_iposition($_, $args-&gt;{full_field}) . &quot; &gt; 0&quot; }
+                    @words;
+    return @terms;
+}
+
+sub _word_terms {
+    my ($self, $args) = @_;
+    my $dbh = Bugzilla-&gt;dbh;
+    
+    my @values = split(/[\s,]+/, $args-&gt;{value});
+    @values = grep { defined $_ and $_ ne '' } @values;
+    my @substring_terms = $self-&gt;_substring_terms($args);
+    
+    my @terms;
+    my $start = $dbh-&gt;WORD_START;
+    my $end   = $dbh-&gt;WORD_END;
+    foreach my $word (@values) {
+        my $regex  = $start . quotemeta($word) . $end;
+        my $quoted = $dbh-&gt;quote($regex);
+        # We don't have to check the regexp, because we escaped it, so we're
+        # sure it's valid.
+        my $regex_term = $dbh-&gt;sql_regexp($args-&gt;{full_field}, $quoted,
+                                          'no check');
+        # Regular expressions are slow--substring searches are faster.
+        # If we're searching for a word, we're also certain that the
+        # substring will appear in the value. So we limit first by
+        # substring and then by a regex that will match just words.
+        my $substring_term = shift @substring_terms;
+        push(@terms, &quot;$substring_term AND $regex_term&quot;);
</ins><span class="cx">     }
</span><ins>+    
+    return @terms;
+}
</ins><span class="cx"> 
</span><del>-    $self-&gt;{'sql'} = $query;
-    $self-&gt;{'debugdata'} = \@debugdata;
</del><ins>+#####################################
+# &quot;Special Parsing&quot; Functions: Date #
+#####################################
+
+sub _timestamp_translate {
+    my ($self, $args) = @_;
+    my $value = $args-&gt;{value};
+    my $dbh = Bugzilla-&gt;dbh;
+
+    return if $value !~ /^(?:[\+\-]?\d+[hdwmy]s?|now)$/i;
+
+    # By default, the time is appended to the date, which we don't want
+    # for deadlines.
+    $value = SqlifyDate($value);
+    if ($args-&gt;{field} eq 'deadline') {
+        ($value) = split(/\s/, $value);
+    }
+    $args-&gt;{value} = $value;
+    $args-&gt;{quoted} = $dbh-&gt;quote($value);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-###############################################################################
-# Helper functions for the init() method.
-###############################################################################
</del><span class="cx"> sub SqlifyDate {
</span><span class="cx">     my ($str) = @_;
</span><del>-    $str = &quot;&quot; if !defined $str;
</del><ins>+    my $fmt = &quot;%Y-%m-%d %H:%M:%S&quot;;
+    $str = &quot;&quot; if (!defined $str || lc($str) eq 'now');
</ins><span class="cx">     if ($str eq &quot;&quot;) {
</span><span class="cx">         my ($sec, $min, $hour, $mday, $month, $year, $wday) = localtime(time());
</span><span class="cx">         return sprintf(&quot;%4d-%02d-%02d 00:00:00&quot;, $year+1900, $month+1, $mday);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-
-    if ($str =~ /^(-|\+)?(\d+)([hHdDwWmMyY])$/) {   # relative date
-        my ($sign, $amount, $unit, $date) = ($1, $2, lc $3, time);
</del><ins>+    if ($str =~ /^(-|\+)?(\d+)([hdwmy])(s?)$/i) {   # relative date
+        my ($sign, $amount, $unit, $startof, $date) = ($1, $2, lc $3, lc $4, time);
</ins><span class="cx">         my ($sec, $min, $hour, $mday, $month, $year, $wday)  = localtime($date);
</span><span class="cx">         if ($sign &amp;&amp; $sign eq '+') { $amount = -$amount; }
</span><ins>+        $startof = 1 if $amount == 0;
</ins><span class="cx">         if ($unit eq 'w') {                  # convert weeks to days
</span><del>-            $amount = 7*$amount + $wday;
</del><ins>+            $amount = 7*$amount;
+            $amount += $wday if $startof;
</ins><span class="cx">             $unit = 'd';
</span><span class="cx">         }
</span><span class="cx">         if ($unit eq 'd') {
</span><del>-            $date -= $sec + 60*$min + 3600*$hour + 24*3600*$amount;
-            return time2str(&quot;%Y-%m-%d %H:%M:%S&quot;, $date);
</del><ins>+            if ($startof) {
+              $fmt = &quot;%Y-%m-%d 00:00:00&quot;;
+              $date -= $sec + 60*$min + 3600*$hour;
+            }
+            $date -= 24*3600*$amount;
+            return time2str($fmt, $date);
</ins><span class="cx">         }
</span><span class="cx">         elsif ($unit eq 'y') {
</span><del>-            return sprintf(&quot;%4d-01-01 00:00:00&quot;, $year+1900-$amount);
</del><ins>+            if ($startof) {
+                return sprintf(&quot;%4d-01-01 00:00:00&quot;, $year+1900-$amount);
+            } 
+            else {
+                return sprintf(&quot;%4d-%02d-%02d %02d:%02d:%02d&quot;, 
+                               $year+1900-$amount, $month+1, $mday, $hour, $min, $sec);
+            }
</ins><span class="cx">         }
</span><span class="cx">         elsif ($unit eq 'm') {
</span><span class="cx">             $month -= $amount;
</span><span class="cx">             while ($month&lt;0) { $year--; $month += 12; }
</span><del>-            return sprintf(&quot;%4d-%02d-01 00:00:00&quot;, $year+1900, $month+1);
</del><ins>+            if ($startof) {
+                return sprintf(&quot;%4d-%02d-01 00:00:00&quot;, $year+1900, $month+1);
+            }
+            else {
+                return sprintf(&quot;%4d-%02d-%02d %02d:%02d:%02d&quot;, 
+                               $year+1900, $month+1, $mday, $hour, $min, $sec);
+            }
</ins><span class="cx">         }
</span><span class="cx">         elsif ($unit eq 'h') {
</span><del>-            # Special case 0h for 'beginning of this hour'
-            if ($amount == 0) {
-                $date -= $sec + 60*$min;
-            } else {
-                $date -= 3600*$amount;
-            }
-            return time2str(&quot;%Y-%m-%d %H:%M:%S&quot;, $date);
</del><ins>+            # Special case for 'beginning of an hour'
+            if ($startof) {
+                $fmt = &quot;%Y-%m-%d %H:00:00&quot;;
+            } 
+            $date -= 3600*$amount;
+            return time2str($fmt, $date);
</ins><span class="cx">         }
</span><span class="cx">         return undef;                      # should not happen due to regexp at top
</span><span class="cx">     }
</span><span class="lines">@@ -870,64 +1997,13 @@
</span><span class="cx">     if (!defined($date)) {
</span><span class="cx">         ThrowUserError(&quot;illegal_date&quot;, { date =&gt; $str });
</span><span class="cx">     }
</span><del>-    return time2str(&quot;%Y-%m-%d %H:%M:%S&quot;, $date);
</del><ins>+    return time2str($fmt, $date);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub build_subselect {
-    my ($outer, $inner, $table, $cond) = @_;
-    my $q = &quot;SELECT $inner FROM $table WHERE $cond&quot;;
-    #return &quot;$outer IN ($q)&quot;;
-    my $dbh = Bugzilla-&gt;dbh;
-    my $list = $dbh-&gt;selectcol_arrayref($q);
-    return &quot;1=2&quot; unless @$list; # Could use boolean type on dbs which support it
-    return $dbh-&gt;sql_in($outer, $list);}
</del><ins>+######################################
+# &quot;Special Parsing&quot; Functions: Users #
+######################################
</ins><span class="cx"> 
</span><del>-sub GetByWordList {
-    my ($field, $strs) = (@_);
-    my @list;
-    my $dbh = Bugzilla-&gt;dbh;
-
-    foreach my $w (split(/[\s,]+/, $strs)) {
-        my $word = $w;
-        if ($word ne &quot;&quot;) {
-            $word =~ tr/A-Z/a-z/;
-            $word = $dbh-&gt;quote('(^|[^a-z0-9])' . quotemeta($word) . '($|[^a-z0-9])');
-            trick_taint($word);
-            push(@list, $dbh-&gt;sql_regexp($field, $word));
-        }
-    }
-
-    return \@list;
-}
-
-# Support for &quot;any/all/nowordssubstr&quot; comparison type (&quot;words as substrings&quot;)
-sub GetByWordListSubstr {
-    my ($field, $strs) = (@_);
-    my @list;
-    my $dbh = Bugzilla-&gt;dbh;
-    my $sql_word;
-
-    foreach my $word (split(/[\s,]+/, $strs)) {
-        if ($word ne &quot;&quot;) {
-            $sql_word = $dbh-&gt;quote($word);
-            trick_taint($sql_word);
-            push(@list, $dbh-&gt;sql_iposition($sql_word, $field) . &quot; &gt; 0&quot;);
-        }
-    }
-
-    return \@list;
-}
-
-sub getSQL {
-    my $self = shift;
-    return $self-&gt;{'sql'};
-}
-
-sub getDebugData {
-    my $self = shift;
-    return $self-&gt;{'debugdata'};
-}
-
</del><span class="cx"> sub pronoun {
</span><span class="cx">     my ($noun, $user) = (@_);
</span><span class="cx">     if ($noun eq &quot;%user%&quot;) {
</span><span class="lines">@@ -944,283 +2020,284 @@
</span><span class="cx">         return &quot;bugs.assigned_to&quot;;
</span><span class="cx">     }
</span><span class="cx">     if ($noun eq &quot;%qacontact%&quot;) {
</span><del>-        return &quot;bugs.qa_contact&quot;;
</del><ins>+        return &quot;COALESCE(bugs.qa_contact,0)&quot;;
</ins><span class="cx">     }
</span><span class="cx">     return 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-# Validate that the query type is one we can deal with
-sub IsValidQueryType
-{
-    my ($queryType) = @_;
-    if (grep { $_ eq $queryType } qw(specific advanced)) {
-        return 1;
</del><ins>+sub _contact_pronoun {
+    my ($self, $args) = @_;
+    my $value = $args-&gt;{value};
+    my $user = $self-&gt;_user;
+    
+    if ($value =~ /^\%group/) {
+        $self-&gt;_contact_exact_group($args);
</ins><span class="cx">     }
</span><del>-    return 0;
</del><ins>+    elsif ($value =~ /^(%\w+%)$/) {
+        $args-&gt;{value} = pronoun($1, $user);
+        $args-&gt;{quoted} = $args-&gt;{value};
+        $args-&gt;{value_is_id} = 1;
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-# BuildOrderBy - Private Subroutine
-# This function converts the input order to an &quot;output&quot; order,
-# suitable for concatenation to form an ORDER BY clause. Basically,
-# it just handles fields that have non-standard sort orders from
-# %specialorder.
-# Arguments:
-#  $orderitem - A string. The next value to append to the ORDER BY clause,
-#      in the format of an item in the 'order' parameter to
-#      Bugzilla::Search.
-#  $stringlist - A reference to the list of strings that will be join()'ed
-#      to make ORDER BY. This is what the subroutine modifies.
-#  $reverseorder - (Optional) A boolean. TRUE if we should reverse the order
-#      of the field that we are given (from ASC to DESC or vice-versa).
-#
-# Explanation of $reverseorder
-# ----------------------------
-# The role of $reverseorder is to handle things like sorting by
-# &quot;target_milestone DESC&quot;.
-# Let's say that we had a field &quot;A&quot; that normally translates to a sort 
-# order of &quot;B ASC, C DESC&quot;. If we sort by &quot;A DESC&quot;, what we really then
-# mean is &quot;B DESC, C ASC&quot;. So $reverseorder is only used if we call 
-# BuildOrderBy recursively, to let it know that we're &quot;reversing&quot; the 
-# order. That is, that we wanted &quot;A DESC&quot;, not &quot;A&quot;.
-sub BuildOrderBy {
-    my ($special_order, $orderitem, $stringlist, $reverseorder) = (@_);
</del><ins>+sub _contact_exact_group {
+    my ($self, $args) = @_;
+    my ($value, $operator, $field, $chart_id, $joins) =
+        @$args{qw(value operator field chart_id joins)};
+    my $dbh = Bugzilla-&gt;dbh;
+    my $user = $self-&gt;_user;
+    
+    $value =~ /\%group\.([^%]+)%/;
+    my $group = Bugzilla::Group-&gt;check({ name =&gt; $1, _error =&gt; 'invalid_group_name' });
+    $group-&gt;check_members_are_visible();
+    $user-&gt;in_group($group)
+      || ThrowUserError('invalid_group_name', {name =&gt; $group-&gt;name});
</ins><span class="cx"> 
</span><del>-    my @twopart = split(/\s+/, $orderitem);
-    my $orderfield = $twopart[0];
-    my $orderdirection = $twopart[1] || &quot;&quot;;
-
-    if ($reverseorder) {
-        # If orderdirection is empty or ASC...
-        if (!$orderdirection || $orderdirection =~ m/asc/i) {
-            $orderdirection = &quot;DESC&quot;;
-        } else {
-            # This has the minor side-effect of making any reversed invalid
-            # direction into ASC.
-            $orderdirection = &quot;ASC&quot;;
-        }
</del><ins>+    my $group_ids = Bugzilla::Group-&gt;flatten_group_membership($group-&gt;id);
+    my $table = &quot;user_group_map_$chart_id&quot;;
+    my $join = {
+        table =&gt; 'user_group_map',
+        as    =&gt; $table,
+        from  =&gt; $field,
+        to    =&gt; 'user_id',
+        extra =&gt; [$dbh-&gt;sql_in(&quot;$table.group_id&quot;, $group_ids),
+                  &quot;$table.isbless = 0&quot;],
+    };
+    push(@$joins, $join);
+    if ($operator =~ /^not/) {
+        $args-&gt;{term} = &quot;$table.group_id IS NULL&quot;;
</ins><span class="cx">     }
</span><del>-
-    # Handle fields that have non-standard sort orders, from $specialorder.
-    if ($special_order-&gt;{$orderfield}) {
-        foreach my $subitem (@{$special_order-&gt;{$orderfield}}) {
-            # DESC on a field with non-standard sort order means
-            # &quot;reverse the normal order for each field that we map to.&quot;
-            BuildOrderBy($special_order, $subitem, $stringlist,
-                         $orderdirection =~ m/desc/i);
-        }
-        return;
</del><ins>+    else {
+        $args-&gt;{term} = &quot;$table.group_id IS NOT NULL&quot;;
</ins><span class="cx">     }
</span><del>-
-    push(@$stringlist, trim($orderfield . ' ' . $orderdirection));
</del><span class="cx"> }
</span><span class="cx"> 
</span><del>-#####################################################################
-# Search Functions
-#####################################################################
</del><ins>+sub _cc_pronoun {
+    my ($self, $args) = @_;
+    my ($full_field, $value) = @$args{qw(full_field value)};
+    my $user = $self-&gt;_user;
</ins><span class="cx"> 
</span><del>-sub _contact_exact_group {
-    my $self = shift;
-    my %func_args = @_;
-    my ($chartid, $supptables, $f, $t, $v, $term) =
-        @func_args{qw(chartid supptables f t v term)};
-    my $user = $self-&gt;{'user'};
-    
-    $$v =~ m/%group\\.([^%]+)%/;
-    my $group = $1;
-    my $groupid = Bugzilla::Group::ValidateGroupName( $group, ($user));
-    $groupid || ThrowUserError('invalid_group_name',{name =&gt; $group});
-    my @childgroups = @{$user-&gt;flatten_group_membership($groupid)};
-    my $table = &quot;user_group_map_$$chartid&quot;;
-    push (@$supptables, &quot;LEFT JOIN user_group_map AS $table &quot; .
-                        &quot;ON $table.user_id = bugs.$$f &quot; .
-                        &quot;AND $table.group_id IN(&quot; .
-                        join(',', @childgroups) . &quot;) &quot; .
-                        &quot;AND $table.isbless = 0 &quot; .
-                        &quot;AND $table.grant_type IN(&quot; .
-                        GRANT_DIRECT . &quot;,&quot; . GRANT_REGEXP . &quot;)&quot;
-         );
-    if ($$t =~ /^not/) {
-        $$term = &quot;$table.group_id IS NULL&quot;;
-    } else {
-        $$term = &quot;$table.group_id IS NOT NULL&quot;;
</del><ins>+    if ($value =~ /\%group/) {
+        return $self-&gt;_cc_exact_group($args);
</ins><span class="cx">     }
</span><ins>+    elsif ($value =~ /^(%\w+%)$/) {
+        $args-&gt;{value} = pronoun($1, $user);
+        $args-&gt;{quoted} = $args-&gt;{value};
+        $args-&gt;{value_is_id} = 1;
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _contact_exact {
-    my $self = shift;
-    my %func_args = @_;
-    my ($term, $f, $v) = @func_args{qw(term f v)};
-    my $user = $self-&gt;{'user'};
</del><ins>+sub _cc_exact_group {
+    my ($self, $args) = @_;
+    my ($chart_id, $sequence, $joins, $operator, $value) =
+        @$args{qw(chart_id sequence joins operator value)};
+    my $user = $self-&gt;_user;
+    my $dbh = Bugzilla-&gt;dbh;
</ins><span class="cx">     
</span><del>-    $$v =~ m/(%\\w+%)/;
-    $$term = &quot;bugs.$$f = &quot; . pronoun($1, $user);
-}
</del><ins>+    $value =~ m/%group\.([^%]+)%/;
+    my $group = Bugzilla::Group-&gt;check({ name =&gt; $1, _error =&gt; 'invalid_group_name' });
+    $group-&gt;check_members_are_visible();
+    $user-&gt;in_group($group)
+      || ThrowUserError('invalid_group_name', {name =&gt; $group-&gt;name});
</ins><span class="cx"> 
</span><del>-sub _contact_notequals {
-    my $self = shift;
-    my %func_args = @_;
-    my ($term, $f, $v) = @func_args{qw(term f v)};
-    my $user = $self-&gt;{'user'};
-    
-    $$v =~ m/(%\\w+%)/;
-    $$term = &quot;bugs.$$f &lt;&gt; &quot; . pronoun($1, $user);
-}
</del><ins>+    my $all_groups = Bugzilla::Group-&gt;flatten_group_membership($group-&gt;id);
</ins><span class="cx"> 
</span><del>-sub _assigned_to_reporter_nonchanged {
-    my $self = shift;
-    my %func_args = @_;
-    my ($f, $ff, $funcsbykey, $t, $term) =
-        @func_args{qw(f ff funcsbykey t term)};
</del><ins>+    # This is for the email1, email2, email3 fields from query.cgi.
+    if ($chart_id eq &quot;&quot;) {
+        $chart_id = &quot;CC$$sequence&quot;;
+        $args-&gt;{sequence}++;
+    }
</ins><span class="cx">     
</span><del>-    my $real_f = $$f;
-    $$f = &quot;login_name&quot;;
-    $$ff = &quot;profiles.login_name&quot;;
-    $$funcsbykey{&quot;,$$t&quot;}($self, %func_args);
-    $$term = &quot;bugs.$real_f IN (SELECT userid FROM profiles WHERE $$term)&quot;;
-}
</del><ins>+    my $cc_table = &quot;cc_$chart_id&quot;;
+    push(@$joins, { table =&gt; 'cc', as =&gt; $cc_table });
+    my $group_table = &quot;user_group_map_$chart_id&quot;;
+    my $group_join = {
+        table =&gt; 'user_group_map',
+        as    =&gt; $group_table,
+        from  =&gt; &quot;$cc_table.who&quot;,
+        to    =&gt; 'user_id',
+        extra =&gt; [$dbh-&gt;sql_in(&quot;$group_table.group_id&quot;, $all_groups),
+                  &quot;$group_table.isbless = 0&quot;],
+    };
+    push(@$joins, $group_join);
</ins><span class="cx"> 
</span><del>-sub _qa_contact_nonchanged {
-    my $self = shift;
-    my %func_args = @_;
-    my ($supptables, $f) =
-        @func_args{qw(supptables f)};
-    
-    push(@$supptables, &quot;LEFT JOIN profiles AS map_qa_contact &quot; .
-                       &quot;ON bugs.qa_contact = map_qa_contact.userid&quot;);
-    $$f = &quot;COALESCE(map_$$f.login_name,'')&quot;;
-}
-
-sub _cc_exact_group {
-    my $self = shift;
-    my %func_args = @_;
-    my ($chartid, $sequence, $supptables, $t, $v, $term) =
-        @func_args{qw(chartid sequence supptables t v term)};
-    my $user = $self-&gt;{'user'};
-    
-    $$v =~ m/%group\\.([^%]+)%/;
-    my $group = $1;
-    my $groupid = Bugzilla::Group::ValidateGroupName( $group, ($user));
-    $groupid || ThrowUserError('invalid_group_name',{name =&gt; $group});
-    my @childgroups = @{$user-&gt;flatten_group_membership($groupid)};
-    my $chartseq = $$chartid;
-    if ($$chartid eq &quot;&quot;) {
-        $chartseq = &quot;CC$$sequence&quot;;
-        $$sequence++;
</del><ins>+    if ($operator =~ /^not/) {
+        $args-&gt;{term} = &quot;$group_table.group_id IS NULL&quot;;
</ins><span class="cx">     }
</span><del>-    my $table = &quot;user_group_map_$chartseq&quot;;
-    push(@$supptables, &quot;LEFT JOIN cc AS cc_$chartseq &quot; .
-                       &quot;ON bugs.bug_id = cc_$chartseq.bug_id&quot;);
-    push(@$supptables, &quot;LEFT JOIN user_group_map AS $table &quot; .
-                        &quot;ON $table.user_id = cc_$chartseq.who &quot; .
-                        &quot;AND $table.group_id IN(&quot; .
-                        join(',', @childgroups) . &quot;) &quot; .
-                        &quot;AND $table.isbless = 0 &quot; .
-                        &quot;AND $table.grant_type IN(&quot; .
-                        GRANT_DIRECT . &quot;,&quot; . GRANT_REGEXP . &quot;)&quot;
-         );
-    if ($$t =~ /^not/) {
-        $$term = &quot;$table.group_id IS NULL&quot;;
-    } else {
-        $$term = &quot;$table.group_id IS NOT NULL&quot;;
</del><ins>+    else {
+        $args-&gt;{term} = &quot;$group_table.group_id IS NOT NULL&quot;;
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _cc_exact {
-    my $self = shift;
-    my %func_args = @_;
-    my ($chartid, $sequence, $supptables, $term, $v) =
-        @func_args{qw(chartid sequence supptables term v)};
-    my $user = $self-&gt;{'user'};
-    
-    $$v =~ m/(%\\w+%)/;
-    my $match = pronoun($1, $user);
-    my $chartseq = $$chartid;
-    if ($$chartid eq &quot;&quot;) {
-        $chartseq = &quot;CC$$sequence&quot;;
-        $$sequence++;
</del><ins>+# XXX This should probably be merged with cc_pronoun.
+sub _commenter_pronoun {
+    my ($self, $args) = @_;
+    my $value = $args-&gt;{value};
+    my $user = $self-&gt;_user;
+
+    if ($value =~ /^(%\w+%)$/) {
+        $args-&gt;{value} = pronoun($1, $user);
+        $args-&gt;{quoted} = $args-&gt;{value};
+        $args-&gt;{value_is_id} = 1;
</ins><span class="cx">     }
</span><del>-    push(@$supptables, &quot;LEFT JOIN cc AS cc_$chartseq &quot; .
-                       &quot;ON bugs.bug_id = cc_$chartseq.bug_id &quot; .
-                       &quot;AND cc_$chartseq.who = $match&quot;);
-    $$term = &quot;cc_$chartseq.who IS NOT NULL&quot;;
</del><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _cc_notequals {
-    my $self = shift;
-    my %func_args = @_;
-    my ($chartid, $sequence, $supptables, $term, $v) =
-        @func_args{qw(chartid sequence supptables term v)};
-    my $user = $self-&gt;{'user'};
-    
-    $$v =~ m/(%\\w+%)/;
-    my $match = pronoun($1, $user);
-    my $chartseq = $$chartid;
-    if ($$chartid eq &quot;&quot;) {
-        $chartseq = &quot;CC$$sequence&quot;;
-        $$sequence++;
-    }
-    push(@$supptables, &quot;LEFT JOIN cc AS cc_$chartseq &quot; .
-                       &quot;ON bugs.bug_id = cc_$chartseq.bug_id &quot; .
-                       &quot;AND cc_$chartseq.who = $match&quot;);
-    $$term = &quot;cc_$chartseq.who IS NULL&quot;;
</del><ins>+#####################################################################
+# Search Functions
+#####################################################################
+
+sub _invalid_combination {
+    my ($self, $args) = @_;
+    my ($field, $operator) = @$args{qw(field operator)};
+    ThrowUserError('search_field_operator_invalid',
+                   { field =&gt; $field, operator =&gt; $operator });
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _cc_nonchanged {
-    my $self = shift;
-    my %func_args = @_;
-    my ($chartid, $sequence, $f, $ff, $t, $funcsbykey, $supptables, $term, $v) =
-        @func_args{qw(chartid sequence f ff t funcsbykey supptables term v)};
</del><ins>+# For all the &quot;user&quot; fields--assigned_to, reporter, qa_contact,
+# cc, commenter, requestee, etc.
+sub _user_nonchanged {
+    my ($self, $args) = @_;
+    my ($field, $operator, $chart_id, $sequence, $joins) =
+        @$args{qw(field operator chart_id sequence joins)};
</ins><span class="cx"> 
</span><del>-    my $chartseq = $$chartid;
-    if ($$chartid eq &quot;&quot;) {
-        $chartseq = &quot;CC$$sequence&quot;;
-        $$sequence++;
</del><ins>+    my $is_in_other_table;
+    if (my $join = USER_FIELDS-&gt;{$field}-&gt;{join}) {
+        $is_in_other_table = 1;
+        my $as = &quot;${field}_$chart_id&quot;;
+        # Needed for setters.login_name and requestees.login_name.
+        # Otherwise when we try to join &quot;profiles&quot; below, we'd get
+        # something like &quot;setters.login_name.login_name&quot; in the &quot;from&quot;.
+        $as =~ s/\./_/g;        
+        # This helps implement the email1, email2, etc. parameters.
+        if ($chart_id =~ /default/) {
+            $as .= &quot;_$sequence&quot;;
+        }
+        my $isprivate = USER_FIELDS-&gt;{$field}-&gt;{isprivate};
+        my $extra = ($isprivate and !$self-&gt;_user-&gt;is_insider)
+                    ? [&quot;$as.isprivate = 0&quot;] : [];
+        # We want to copy $join so as not to modify USER_FIELDS.
+        push(@$joins, { %$join, as =&gt; $as, extra =&gt; $extra });
+        my $search_field = USER_FIELDS-&gt;{$field}-&gt;{field};
+        $args-&gt;{full_field} = &quot;$as.$search_field&quot;;
</ins><span class="cx">     }
</span><del>-    $$f = &quot;login_name&quot;;
-    $$ff = &quot;profiles.login_name&quot;;
-    $$funcsbykey{&quot;,$$t&quot;}($self, %func_args);
-    push(@$supptables, &quot;LEFT JOIN cc AS cc_$chartseq &quot; .
-                       &quot;ON bugs.bug_id = cc_$chartseq.bug_id &quot; .
-                       &quot;AND cc_$chartseq.who IN&quot; .
-                       &quot;(SELECT userid FROM profiles WHERE $$term)&quot;
-                       );
-    $$term = &quot;cc_$chartseq.who IS NOT NULL&quot;;
</del><ins>+
+    my $is_nullable = USER_FIELDS-&gt;{$field}-&gt;{nullable};
+    my $null_alternate = &quot;''&quot;;
+    # When using a pronoun, we use the userid, and we don't have to
+    # join the profiles table.
+    if ($args-&gt;{value_is_id}) {
+        $null_alternate = 0;
+    }
+    else {
+        my $as = &quot;name_${field}_$chart_id&quot;;
+        # For fields with periods in their name.
+        $as =~ s/\./_/;
+        my $join = {
+            table =&gt; 'profiles',
+            as    =&gt; $as,
+            from  =&gt; $args-&gt;{full_field},
+            to    =&gt; 'userid',
+            join  =&gt; (!$is_in_other_table and !$is_nullable) ? 'INNER' : undef,
+        };
+        push(@$joins, $join);
+        $args-&gt;{full_field} = &quot;$as.login_name&quot;;
+    }
+    
+    # We COALESCE fields that can be NULL, to make &quot;not&quot;-style operators
+    # continue to work properly. For example, &quot;qa_contact is not equal to bob&quot;
+    # should also show bugs where the qa_contact is NULL. With COALESCE,
+    # it does.
+    if ($is_nullable) {
+        $args-&gt;{full_field} = &quot;COALESCE($args-&gt;{full_field}, $null_alternate)&quot;;
+    }
+    
+    # For fields whose values are stored in other tables, negation (NOT)
+    # only works properly if we put the condition into the JOIN instead
+    # of the WHERE.
+    if ($is_in_other_table) {
+        # Using the last join works properly whether we're searching based
+        # on userid or login_name.
+        my $last_join = $joins-&gt;[-1];
+        
+        # For negative operators, the system we're using here
+        # only works properly if we reverse the operator and check IS NULL
+        # in the WHERE.
+        my $is_negative = $operator =~ /^no/ ? 1 : 0;
+        if ($is_negative) {
+            $args-&gt;{operator} = $self-&gt;_reverse_operator($operator);
+        }
+        $self-&gt;_do_operator_function($args);
+        push(@{ $last_join-&gt;{extra} }, $args-&gt;{term});
+        
+        # For login_name searches, we only want a single join.
+        # So we create a subselect table out of our two joins. This makes
+        # negation (NOT) work properly for values that are in other
+        # tables.
+        if ($last_join-&gt;{table} eq 'profiles') {
+            pop @$joins;
+            $last_join-&gt;{join} = 'INNER';
+            my ($join_sql) = $self-&gt;_translate_join($last_join);
+            my $first_join = $joins-&gt;[-1];
+            my $as = $first_join-&gt;{as};            
+            my $table = $first_join-&gt;{table};
+            my $columns = &quot;bug_id&quot;;
+            $columns .= &quot;,isprivate&quot; if @{ $first_join-&gt;{extra} };
+            my $new_table = &quot;SELECT $columns FROM $table AS $as $join_sql&quot;;
+            $first_join-&gt;{table} = &quot;($new_table)&quot;;
+            # We always want to LEFT JOIN the generated table.
+            delete $first_join-&gt;{join};
+            # To support OR charts, we need multiple tables.
+            my $new_as = $first_join-&gt;{as} . &quot;_$sequence&quot;;
+            $_ =~ s/\Q$as\E/$new_as/ foreach @{ $first_join-&gt;{extra} };
+            $first_join-&gt;{as} = $new_as;
+            $last_join = $first_join;
+        }
+        
+        # If we're joining the first table (we're using a pronoun and
+        # searching by user id) then we need to check $other_table-&gt;{field}.
+        my $check_field = $last_join-&gt;{as} . '.bug_id';
+        if ($is_negative) {
+            $args-&gt;{term} = &quot;$check_field IS NULL&quot;;
+        }
+        else {
+            $args-&gt;{term} = &quot;$check_field IS NOT NULL&quot;;
+        }
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# XXX This duplicates having Commenter as a search field.
</ins><span class="cx"> sub _long_desc_changedby {
</span><del>-    my $self = shift;
-    my %func_args = @_;
-    my ($chartid, $supptables, $term, $v) =
-        @func_args{qw(chartid supptables term v)};
</del><ins>+    my ($self, $args) = @_;
+    my ($chart_id, $joins, $value) = @$args{qw(chart_id joins value)};
</ins><span class="cx">     
</span><del>-    my $table = &quot;longdescs_$$chartid&quot;;
-    push(@$supptables, &quot;LEFT JOIN longdescs AS $table &quot; .
-                       &quot;ON $table.bug_id = bugs.bug_id&quot;);
-    my $id = login_to_id($$v, THROW_ERROR);
-    $$term = &quot;$table.who = $id&quot;;
</del><ins>+    my $table = &quot;longdescs_$chart_id&quot;;
+    push(@$joins, { table =&gt; 'longdescs', as =&gt; $table });
+    my $user_id = login_to_id($value, THROW_ERROR);
+    $args-&gt;{term} = &quot;$table.who = $user_id&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _long_desc_changedbefore_after {
</span><del>-    my $self = shift;
-    my %func_args = @_;
-    my ($chartid, $t, $v, $supptables, $term) =
-        @func_args{qw(chartid t v supptables term)};
</del><ins>+    my ($self, $args) = @_;
+    my ($chart_id, $operator, $value, $joins) =
+        @$args{qw(chart_id operator value joins)};
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx">     
</span><del>-    my $operator = ($$t =~ /before/) ? '&lt;' : '&gt;';
-    my $table = &quot;longdescs_$$chartid&quot;;
-    push(@$supptables, &quot;LEFT JOIN longdescs AS $table &quot; .
-                              &quot;ON $table.bug_id = bugs.bug_id &quot; .
-                                 &quot;AND $table.bug_when $operator &quot; .
-                                  $dbh-&gt;quote(SqlifyDate($$v)) );
-    $$term = &quot;($table.bug_when IS NOT NULL)&quot;;
</del><ins>+    my $sql_operator = ($operator =~ /before/) ? '&lt;=' : '&gt;=';
+    my $table = &quot;longdescs_$chart_id&quot;;
+    my $sql_date = $dbh-&gt;quote(SqlifyDate($value));
+    my $join = {
+        table =&gt; 'longdescs',
+        as    =&gt; $table,
+        extra =&gt; [&quot;$table.bug_when $sql_operator $sql_date&quot;],
+    };
+    push(@$joins, $join);
+    $args-&gt;{term} = &quot;$table.bug_when IS NOT NULL&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _content_matches {
</span><del>-    my $self = shift;
-    my %func_args = @_;
-    my ($chartid, $supptables, $term, $groupby, $fields, $v) =
-        @func_args{qw(chartid supptables term groupby fields v)};
</del><ins>+    my ($self, $args) = @_;
+    my ($chart_id, $joins, $fields, $operator, $value) =
+        @$args{qw(chart_id joins fields operator value)};
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx">     
</span><span class="cx">     # &quot;content&quot; is an alias for columns containing text for which we
</span><span class="lines">@@ -1231,838 +2308,562 @@
</span><span class="cx">     # index searches.
</span><span class="cx"> 
</span><span class="cx">     # Add the fulltext table to the query so we can search on it.
</span><del>-    my $table = &quot;bugs_fulltext_$$chartid&quot;;
</del><ins>+    my $table = &quot;bugs_fulltext_$chart_id&quot;;
</ins><span class="cx">     my $comments_col = &quot;comments&quot;;
</span><del>-    $comments_col = &quot;comments_noprivate&quot; unless $self-&gt;{'user'}-&gt;is_insider;
-    push(@$supptables, &quot;LEFT JOIN bugs_fulltext AS $table &quot; .
-                       &quot;ON bugs.bug_id = $table.bug_id&quot;);
</del><ins>+    $comments_col = &quot;comments_noprivate&quot; unless $self-&gt;_user-&gt;is_insider;
+    push(@$joins, { table =&gt; 'bugs_fulltext', as =&gt; $table });
</ins><span class="cx">     
</span><span class="cx">     # Create search terms to add to the SELECT and WHERE clauses.
</span><del>-    my ($term1, $rterm1) = $dbh-&gt;sql_fulltext_search(&quot;$table.$comments_col&quot;, 
-                                                        $$v, 1);
-    my ($term2, $rterm2) = $dbh-&gt;sql_fulltext_search(&quot;$table.short_desc&quot;, 
-                                                        $$v, 2);
</del><ins>+    my ($term1, $rterm1) =
+        $dbh-&gt;sql_fulltext_search(&quot;$table.$comments_col&quot;, $value, 1);
+    my ($term2, $rterm2) =
+        $dbh-&gt;sql_fulltext_search(&quot;$table.short_desc&quot;, $value, 2);
</ins><span class="cx">     $rterm1 = $term1 if !$rterm1;
</span><span class="cx">     $rterm2 = $term2 if !$rterm2;
</span><span class="cx"> 
</span><span class="cx">     # The term to use in the WHERE clause.
</span><del>-    $$term = &quot;$term1 &gt; 0 OR $term2 &gt; 0&quot;;
</del><ins>+    my $term = &quot;$term1 OR $term2&quot;;
+    if ($operator =~ /not/i) {
+        $term = &quot;NOT($term)&quot;;
+    }
+    $args-&gt;{term} = $term;
</ins><span class="cx">     
</span><span class="cx">     # In order to sort by relevance (in case the user requests it),
</span><del>-    # we SELECT the relevance value and give it an alias so we can
-    # add it to the SORT BY clause when we build it in buglist.cgi.
-    my $select_term = &quot;($rterm1 + $rterm2) AS relevance&quot;;
-
-    # Users can specify to display the relevance field, in which case
-    # it'll show up in the list of fields being selected, and we need
-    # to replace that occurrence with our select term.  Otherwise
-    # we can just add the term to the list of fields being selected.
-    if (grep($_ eq &quot;relevance&quot;, @$fields)) {
-        @$fields = map($_ eq &quot;relevance&quot; ? $select_term : $_ , @$fields);
-    }
-    else {
-        push(@$fields, $select_term);
-    }
</del><ins>+    # we SELECT the relevance value so we can add it to the ORDER BY
+    # clause. Every time a new fulltext chart isadded, this adds more 
+    # terms to the relevance sql.
+    #
+    # We build the relevance SQL by modifying the COLUMNS list directly,
+    # which is kind of a hack but works.
+    my $current = $self-&gt;COLUMNS-&gt;{'relevance'}-&gt;{name};
+    $current = $current ? &quot;$current + &quot; : '';
+    # For NOT searches, we just add 0 to the relevance.
+    my $select_term = $operator =~ /not/ ? 0 : &quot;($current$rterm1 + $rterm2)&quot;;
+    $self-&gt;COLUMNS-&gt;{'relevance'}-&gt;{name} = $select_term;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _timestamp_compare {
-    my $self = shift;
-    my %func_args = @_;
-    my ($v, $q) = @func_args{qw(v q)};
-    my $dbh = Bugzilla-&gt;dbh;
-    
-    $$v = SqlifyDate($$v);
-    $$q = $dbh-&gt;quote($$v);
</del><ins>+sub _long_descs_count {
+    my ($self, $args) = @_;
+    my ($chart_id, $joins) = @$args{qw(chart_id joins)};
+    my $table = &quot;longdescs_count_$chart_id&quot;;
+    my $extra =  $self-&gt;_user-&gt;is_insider ? &quot;&quot; : &quot;WHERE isprivate = 0&quot;;
+    my $join = {
+        table =&gt; &quot;(SELECT bug_id, COUNT(*) AS num&quot;
+                 . &quot; FROM longdescs $extra GROUP BY bug_id)&quot;,
+        as    =&gt; $table,
+    };
+    push(@$joins, $join);
+    $args-&gt;{full_field} = &quot;${table}.num&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _commenter_exact {
-    my $self = shift;
-    my %func_args = @_;
-    my ($chartid, $sequence, $supptables, $term, $v) =
-        @func_args{qw(chartid sequence supptables term v)};
-    my $user = $self-&gt;{'user'};
-    
-    $$v =~ m/(%\\w+%)/;
-    my $match = pronoun($1, $user);
-    my $chartseq = $$chartid;
-    if ($$chartid eq &quot;&quot;) {
-        $chartseq = &quot;LD$$sequence&quot;;
-        $$sequence++;
-    }
-    my $table = &quot;longdescs_$chartseq&quot;;
-    my $extra = $user-&gt;is_insider ? &quot;&quot; : &quot;AND $table.isprivate &lt; 1&quot;;
-    push(@$supptables, &quot;LEFT JOIN longdescs AS $table &quot; .
-                       &quot;ON $table.bug_id = bugs.bug_id $extra &quot; .
-                       &quot;AND $table.who IN ($match)&quot;);
-    $$term = &quot;$table.who IS NOT NULL&quot;;
-}
-
-sub _commenter {
-    my $self = shift;
-    my %func_args = @_;
-    my ($chartid, $sequence, $supptables, $f, $ff, $t, $funcsbykey, $term) =
-        @func_args{qw(chartid sequence supptables f ff t funcsbykey term)};
-
-    my $chartseq = $$chartid;
-    if ($$chartid eq &quot;&quot;) {
-        $chartseq = &quot;LD$$sequence&quot;;
-        $$sequence++;
-    }
-    my $table = &quot;longdescs_$chartseq&quot;;
-    my $extra = $self-&gt;{'user'}-&gt;is_insider ? &quot;&quot; : &quot;AND $table.isprivate &lt; 1&quot;;
-    $$f = &quot;login_name&quot;;
-    $$ff = &quot;profiles.login_name&quot;;
-    $$funcsbykey{&quot;,$$t&quot;}($self, %func_args);
-    push(@$supptables, &quot;LEFT JOIN longdescs AS $table &quot; .
-                       &quot;ON $table.bug_id = bugs.bug_id $extra &quot; .
-                       &quot;AND $table.who IN&quot; .
-                       &quot;(SELECT userid FROM profiles WHERE $$term)&quot;
-                       );
-    $$term = &quot;$table.who IS NOT NULL&quot;;
-}
-
-sub _long_desc {
-    my $self = shift;
-    my %func_args = @_;
-    my ($chartid, $supptables, $f) =
-        @func_args{qw(chartid supptables f)};
-    
-    my $table = &quot;longdescs_$$chartid&quot;;
-    my $extra = $self-&gt;{'user'}-&gt;is_insider ? &quot;&quot; : &quot;AND $table.isprivate &lt; 1&quot;;
-    push(@$supptables, &quot;LEFT JOIN longdescs AS $table &quot; .
-                       &quot;ON $table.bug_id = bugs.bug_id $extra&quot;);
-    $$f = &quot;$table.thetext&quot;;
-}
-
-sub _longdescs_isprivate {
-    my $self = shift;
-    my %func_args = @_;
-    my ($chartid, $supptables, $f) =
-        @func_args{qw(chartid supptables f)};
-    
-    my $table = &quot;longdescs_$$chartid&quot;;
-    my $extra = $self-&gt;{'user'}-&gt;is_insider ? &quot;&quot; : &quot;AND $table.isprivate &lt; 1&quot;;
-    push(@$supptables, &quot;LEFT JOIN longdescs AS $table &quot; .
-                      &quot;ON $table.bug_id = bugs.bug_id $extra&quot;);
-    $$f = &quot;$table.isprivate&quot;;
-}
-
</del><span class="cx"> sub _work_time_changedby {
</span><del>-    my $self = shift;
-    my %func_args = @_;
-    my ($chartid, $supptables, $v, $term) =
-        @func_args{qw(chartid supptables v term)};
</del><ins>+    my ($self, $args) = @_;
+    my ($chart_id, $joins, $value) = @$args{qw(chart_id joins value)};
</ins><span class="cx">     
</span><del>-    my $table = &quot;longdescs_$$chartid&quot;;
-    push(@$supptables, &quot;LEFT JOIN longdescs AS $table &quot; .
-                       &quot;ON $table.bug_id = bugs.bug_id&quot;);
-    my $id = login_to_id($$v, THROW_ERROR);
-    $$term = &quot;(($table.who = $id&quot;;
-    $$term .= &quot;) AND ($table.work_time &lt;&gt; 0))&quot;;
</del><ins>+    my $table = &quot;longdescs_$chart_id&quot;;
+    push(@$joins, { table =&gt; 'longdescs', as =&gt; $table });
+    my $user_id = login_to_id($value, THROW_ERROR);
+    $args-&gt;{term} = &quot;$table.who = $user_id AND $table.work_time != 0&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _work_time_changedbefore_after {
</span><del>-    my $self = shift;
-    my %func_args = @_;
-    my ($chartid, $t, $v, $supptables, $term) =
-        @func_args{qw(chartid t v supptables term)};
</del><ins>+    my ($self, $args) = @_;
+    my ($chart_id, $operator, $value, $joins) =
+        @$args{qw(chart_id operator value joins)};
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx">     
</span><del>-    my $operator = ($$t =~ /before/) ? '&lt;' : '&gt;';
-    my $table = &quot;longdescs_$$chartid&quot;;
-    push(@$supptables, &quot;LEFT JOIN longdescs AS $table &quot; .
-                              &quot;ON $table.bug_id = bugs.bug_id &quot; .
-                                 &quot;AND $table.work_time &lt;&gt; 0 &quot; .
-                                 &quot;AND $table.bug_when $operator &quot; .
-                                  $dbh-&gt;quote(SqlifyDate($$v)) );
-    $$term = &quot;($table.bug_when IS NOT NULL)&quot;;
</del><ins>+    my $table = &quot;longdescs_$chart_id&quot;;
+    my $sql_operator = ($operator =~ /before/) ? '&lt;=' : '&gt;=';
+    my $sql_date = $dbh-&gt;quote(SqlifyDate($value));
+    my $join = {
+        table =&gt; 'longdescs',
+        as    =&gt; $table,
+        extra =&gt; [&quot;$table.work_time != 0&quot;,
+                  &quot;$table.bug_when $sql_operator $sql_date&quot;],
+    };
+    push(@$joins, $join);
+    
+    $args-&gt;{term} = &quot;$table.bug_when IS NOT NULL&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _work_time {
</span><del>-    my $self = shift;
-    my %func_args = @_;
-    my ($chartid, $supptables, $f) =
-        @func_args{qw(chartid supptables f)};
-    
-    my $table = &quot;longdescs_$$chartid&quot;;
-    push(@$supptables, &quot;LEFT JOIN longdescs AS $table &quot; .
-                      &quot;ON $table.bug_id = bugs.bug_id&quot;);
-    $$f = &quot;$table.work_time&quot;;
</del><ins>+    my ($self, $args) = @_;
+    $self-&gt;_add_extra_column('actual_time');
+    $args-&gt;{full_field} = $self-&gt;COLUMNS-&gt;{actual_time}-&gt;{name};
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _percentage_complete {
</span><del>-    my $self = shift;
-    my %func_args = @_;
-    my ($t, $chartid, $supptables, $fields, $q, $v, $having, $groupby, $term) =
-        @func_args{qw(t chartid supptables fields q v having groupby term)};
-    my $dbh = Bugzilla-&gt;dbh;
</del><ins>+    my ($self, $args) = @_;
</ins><span class="cx">     
</span><del>-    my $oper;
-    if ($$t eq &quot;equals&quot;) {
-        $oper = &quot;=&quot;;
-    } elsif ($$t eq &quot;greaterthan&quot;) {
-        $oper = &quot;&gt;&quot;;
-    } elsif ($$t eq &quot;lessthan&quot;) {
-        $oper = &quot;&lt;&quot;;
-    } elsif ($$t eq &quot;notequal&quot;) {
-        $oper = &quot;&lt;&gt;&quot;;
-    } elsif ($$t eq &quot;regexp&quot;) {
-        # This is just a dummy to help catch bugs- $oper won't be used
-        # since &quot;regexp&quot; is treated as a special case below.  But
-        # leaving $oper uninitialized seems risky...
-        $oper = &quot;sql_regexp&quot;;
-    } elsif ($$t eq &quot;notregexp&quot;) {
-        # This is just a dummy to help catch bugs- $oper won't be used
-        # since &quot;notregexp&quot; is treated as a special case below.  But
-        # leaving $oper uninitialized seems risky...
-        $oper = &quot;sql_not_regexp&quot;;
-    } else {
-        $oper = &quot;noop&quot;;
-    }
-    if ($oper ne &quot;noop&quot;) {
-        my $table = &quot;longdescs_$$chartid&quot;;
-        if(lsearch($fields, &quot;bugs.remaining_time&quot;) == -1) {
-            push(@$fields, &quot;bugs.remaining_time&quot;);                  
-        }
-        push(@$supptables, &quot;LEFT JOIN longdescs AS $table &quot; .
-                           &quot;ON $table.bug_id = bugs.bug_id&quot;);
-        my $expression = &quot;(100 * ((SUM($table.work_time) *
-                                    COUNT(DISTINCT $table.bug_when) /
-                                    COUNT(bugs.bug_id)) /
-                                   ((SUM($table.work_time) *
-                                     COUNT(DISTINCT $table.bug_when) /
-                                     COUNT(bugs.bug_id)) +
-                                    bugs.remaining_time)))&quot;;
-        $$q = $dbh-&gt;quote($$v);
-        trick_taint($$q);
-        if ($$t eq &quot;regexp&quot;) {
-            push(@$having, $dbh-&gt;sql_regexp($expression, $$q));
-        } elsif ($$t eq &quot;notregexp&quot;) {
-            push(@$having, $dbh-&gt;sql_not_regexp($expression, $$q));
-        } else {
-            push(@$having, &quot;$expression $oper &quot; . $$q);
-        }
-        push(@$groupby, &quot;bugs.remaining_time&quot;);
-    }
-    $$term = &quot;0=0&quot;;
-}
</del><ins>+    $args-&gt;{full_field} = $self-&gt;COLUMNS-&gt;{percentage_complete}-&gt;{name};
</ins><span class="cx"> 
</span><del>-sub _bug_group_nonchanged {
-    my $self = shift;
-    my %func_args = @_;
-    my ($supptables, $chartid, $ff, $f, $t, $funcsbykey, $term) =
-        @func_args{qw(supptables chartid ff f t funcsbykey term)};
-    
-    push(@$supptables,
-            &quot;LEFT JOIN bug_group_map AS bug_group_map_$$chartid &quot; .
-            &quot;ON bugs.bug_id = bug_group_map_$$chartid.bug_id&quot;);
-    $$ff = $$f = &quot;groups_$$chartid.name&quot;;
-    $$funcsbykey{&quot;,$$t&quot;}($self, %func_args);
-    push(@$supptables,
-            &quot;LEFT JOIN groups AS groups_$$chartid &quot; .
-            &quot;ON groups_$$chartid.id = bug_group_map_$$chartid.group_id &quot; .
-            &quot;AND $$term&quot;);
-    $$term = &quot;$$ff IS NOT NULL&quot;;
</del><ins>+    # We need actual_time in _select_columns, otherwise we can't use
+    # it in the expression for searching percentage_complete.
+    $self-&gt;_add_extra_column('actual_time');
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _attach_data_thedata_changed {
-    my $self = shift;
-    my %func_args = @_;
-    my ($f) = @func_args{qw(f)};
-    
-    # Searches for attachment data's change must search
-    # the creation timestamp of the attachment instead.
-    $$f = &quot;attachments.whocares&quot;;
-}
-
-sub _attach_data_thedata {
-    my $self = shift;
-    my %func_args = @_;
-    my ($chartid, $supptables, $f) =
-        @func_args{qw(chartid supptables f)};
-    
-    my $atable = &quot;attachments_$$chartid&quot;;
-    my $dtable = &quot;attachdata_$$chartid&quot;;
-    my $extra = $self-&gt;{'user'}-&gt;is_insider ? &quot;&quot; : &quot;AND $atable.isprivate = 0&quot;;
-    push(@$supptables, &quot;INNER JOIN attachments AS $atable &quot; .
-                       &quot;ON bugs.bug_id = $atable.bug_id $extra&quot;);
-    push(@$supptables, &quot;INNER JOIN attach_data AS $dtable &quot; .
-                       &quot;ON $dtable.id = $atable.attach_id&quot;);
-    $$f = &quot;$dtable.thedata&quot;;
-}
-
-sub _attachments_submitter {
-    my $self = shift;
-    my %func_args = @_;
-    my ($chartid, $supptables, $f) =
-        @func_args{qw(chartid supptables f)};
-    
-    my $atable = &quot;map_attachment_submitter_$$chartid&quot;;
-    my $extra = $self-&gt;{'user'}-&gt;is_insider ? &quot;&quot; : &quot;AND $atable.isprivate = 0&quot;;
-    push(@$supptables, &quot;INNER JOIN attachments AS $atable &quot; .
-                       &quot;ON bugs.bug_id = $atable.bug_id $extra&quot;);
-    push(@$supptables, &quot;LEFT JOIN profiles AS attachers_$$chartid &quot; .
-                       &quot;ON $atable.submitter_id = attachers_$$chartid.userid&quot;);
-    $$f = &quot;attachers_$$chartid.login_name&quot;;
-}
-
-sub _attachments {
-    my $self = shift;
-    my %func_args = @_;
-    my ($chartid, $supptables, $f, $t, $v, $q) =
-        @func_args{qw(chartid supptables f t v q)};
</del><ins>+sub _days_elapsed {
+    my ($self, $args) = @_;
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx">     
</span><del>-    my $table = &quot;attachments_$$chartid&quot;;
-    my $extra = $self-&gt;{'user'}-&gt;is_insider ? &quot;&quot; : &quot;AND $table.isprivate = 0&quot;;
-    push(@$supptables, &quot;INNER JOIN attachments AS $table &quot; .
-                       &quot;ON bugs.bug_id = $table.bug_id $extra&quot;);
-    $$f =~ m/^attachments\.(.*)$/;
-    my $field = $1;
-    if ($$t eq &quot;changedby&quot;) {
-        $$v = login_to_id($$v, THROW_ERROR);
-        $$q = $dbh-&gt;quote($$v);
-        $field = &quot;submitter_id&quot;;
-        $$t = &quot;equals&quot;;
-    } elsif ($$t eq &quot;changedbefore&quot;) {
-        $$v = SqlifyDate($$v);
-        $$q = $dbh-&gt;quote($$v);
-        $field = &quot;creation_ts&quot;;
-        $$t = &quot;lessthan&quot;;
-    } elsif ($$t eq &quot;changedafter&quot;) {
-        $$v = SqlifyDate($$v);
-        $$q = $dbh-&gt;quote($$v);
-        $field = &quot;creation_ts&quot;;
-        $$t = &quot;greaterthan&quot;;
-    }
-    if ($field eq &quot;ispatch&quot; &amp;&amp; $$v ne &quot;0&quot; &amp;&amp; $$v ne &quot;1&quot;) {
-        ThrowUserError(&quot;illegal_attachment_is_patch&quot;);
-    }
-    if ($field eq &quot;isobsolete&quot; &amp;&amp; $$v ne &quot;0&quot; &amp;&amp; $$v ne &quot;1&quot;) {
-        ThrowUserError(&quot;illegal_is_obsolete&quot;);
-    }
-    $$f = &quot;$table.$field&quot;;
</del><ins>+    $args-&gt;{full_field} = &quot;(&quot; . $dbh-&gt;sql_to_days('NOW()') . &quot; - &quot; .
+                                $dbh-&gt;sql_to_days('bugs.delta_ts') . &quot;)&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _flagtypes_name {
-    my $self = shift;
-    my %func_args = @_;
-    my ($t, $chartid, $supptables, $ff, $funcsbykey, $having, $term) =
-        @func_args{qw(t chartid supptables ff funcsbykey having term)};
-    my $dbh = Bugzilla-&gt;dbh;
</del><ins>+sub _component_nonchanged {
+    my ($self, $args) = @_;
</ins><span class="cx">     
</span><del>-    # Matches bugs by flag name/status.
-    # Note that--for the purposes of querying--a flag comprises
-    # its name plus its status (i.e. a flag named &quot;review&quot; 
-    # with a status of &quot;+&quot; can be found by searching for &quot;review+&quot;).
-    
-    # Don't do anything if this condition is about changes to flags,
-    # as the generic change condition processors can handle those.
-    return if ($$t =~ m/^changed/);
-    
-    # Add the flags and flagtypes tables to the query.  We do 
-    # a left join here so bugs without any flags still match 
-    # negative conditions (f.e. &quot;flag isn't review+&quot;).
-    my $flags = &quot;flags_$$chartid&quot;;
-    push(@$supptables, &quot;LEFT JOIN flags AS $flags &quot; . 
-                       &quot;ON bugs.bug_id = $flags.bug_id &quot;);
-    my $flagtypes = &quot;flagtypes_$$chartid&quot;;
-    push(@$supptables, &quot;LEFT JOIN flagtypes AS $flagtypes &quot; . 
-                       &quot;ON $flags.type_id = $flagtypes.id&quot;);
-    
-    # Generate the condition by running the operator-specific
-    # function. Afterwards the condition resides in the global $term
-    # variable.
-    $$ff = $dbh-&gt;sql_string_concat(&quot;${flagtypes}.name&quot;,
-                                   &quot;$flags.status&quot;);
-    $$funcsbykey{&quot;,$$t&quot;}($self, %func_args);
-    
-    # If this is a negative condition (f.e. flag isn't &quot;review+&quot;),
-    # we only want bugs where all flags match the condition, not 
-    # those where any flag matches, which needs special magic.
-    # Instead of adding the condition to the WHERE clause, we select
-    # the number of flags matching the condition and the total number
-    # of flags on each bug, then compare them in a HAVING clause.
-    # If the numbers are the same, all flags match the condition,
-    # so this bug should be included.
-    if ($$t =~ m/not/) {
-       push(@$having,
-            &quot;SUM(CASE WHEN $$ff IS NOT NULL THEN 1 ELSE 0 END) = &quot; .
-            &quot;SUM(CASE WHEN $$term THEN 1 ELSE 0 END)&quot;);
-       $$term = &quot;0=0&quot;;
-    }
</del><ins>+    $args-&gt;{full_field} = &quot;components.name&quot;;
+    $self-&gt;_do_operator_function($args);
+    my $term = $args-&gt;{term};
+    $args-&gt;{term} = build_subselect(&quot;bugs.component_id&quot;,
+        &quot;components.id&quot;, &quot;components&quot;, $args-&gt;{term});
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _requestees_login_name {
-    my $self = shift;
-    my %func_args = @_;
-    my ($f, $chartid, $supptables) = @func_args{qw(f chartid supptables)};
-    
-    my $flags = &quot;flags_$$chartid&quot;;
-    push(@$supptables, &quot;LEFT JOIN flags AS $flags &quot; .
-                       &quot;ON bugs.bug_id = $flags.bug_id &quot;);
-    push(@$supptables, &quot;LEFT JOIN profiles AS requestees_$$chartid &quot; .
-                       &quot;ON $flags.requestee_id = requestees_$$chartid.userid&quot;);
-    $$f = &quot;requestees_$$chartid.login_name&quot;;
-}
-
-sub _setters_login_name {
-    my $self = shift;
-    my %func_args = @_;
-    my ($f, $chartid, $supptables) = @func_args{qw(f chartid supptables)};
-    
-    my $flags = &quot;flags_$$chartid&quot;;
-    push(@$supptables, &quot;LEFT JOIN flags AS $flags &quot; .
-                       &quot;ON bugs.bug_id = $flags.bug_id &quot;);
-    push(@$supptables, &quot;LEFT JOIN profiles AS setters_$$chartid &quot; .
-                       &quot;ON $flags.setter_id = setters_$$chartid.userid&quot;);
-    $$f = &quot;setters_$$chartid.login_name&quot;;
-}
-
-sub _changedin_days_elapsed {
-    my $self = shift;
-    my %func_args = @_;
-    my ($f) = @func_args{qw(f)};
-    my $dbh = Bugzilla-&gt;dbh;
-    
-    $$f = &quot;(&quot; . $dbh-&gt;sql_to_days('NOW()') . &quot; - &quot; .
-                $dbh-&gt;sql_to_days('bugs.delta_ts') . &quot;)&quot;;
-}
-
-sub _component_nonchanged {
-    my $self = shift;
-    my %func_args = @_;
-    my ($f, $ff, $t, $funcsbykey, $term) =
-        @func_args{qw(f ff t funcsbykey term)};
-    
-    $$f = $$ff = &quot;components.name&quot;;
-    $$funcsbykey{&quot;,$$t&quot;}($self, %func_args);
-    $$term = build_subselect(&quot;bugs.component_id&quot;,
-                             &quot;components.id&quot;,
-                             &quot;components&quot;,
-                             $$term);
-}
</del><span class="cx"> sub _product_nonchanged {
</span><del>-    my $self = shift;
-    my %func_args = @_;
-    my ($f, $ff, $t, $funcsbykey, $term) =
-        @func_args{qw(f ff t funcsbykey term)};
</del><ins>+    my ($self, $args) = @_;
</ins><span class="cx">     
</span><span class="cx">     # Generate the restriction condition
</span><del>-    $$f = $$ff = &quot;products.name&quot;;
-    $$funcsbykey{&quot;,$$t&quot;}($self, %func_args);
-    $$term = build_subselect(&quot;bugs.product_id&quot;,
-                             &quot;products.id&quot;,
-                             &quot;products&quot;,
-                             $$term);
</del><ins>+    $args-&gt;{full_field} = &quot;products.name&quot;;
+    $self-&gt;_do_operator_function($args);
+    my $term = $args-&gt;{term};
+    $args-&gt;{term} = build_subselect(&quot;bugs.product_id&quot;,
+        &quot;products.id&quot;, &quot;products&quot;, $term);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _classification_nonchanged {
</span><del>-    my $self = shift;
-    my %func_args = @_;
-    my ($chartid, $v, $ff, $f, $funcsbykey, $t, $supptables, $term) =
-        @func_args{qw(chartid v ff f funcsbykey t supptables term)};
</del><ins>+    my ($self, $args) = @_;
+    my $joins = $args-&gt;{joins};
</ins><span class="cx">     
</span><del>-    # Generate the restriction condition
-    push @$supptables, &quot;INNER JOIN products AS map_products &quot; .
-                      &quot;ON bugs.product_id = map_products.id&quot;;
-    $$f = $$ff = &quot;classifications.name&quot;;
-    $$funcsbykey{&quot;,$$t&quot;}($self, %func_args);
-    $$term = build_subselect(&quot;map_products.classification_id&quot;,
-                             &quot;classifications.id&quot;,
-                             &quot;classifications&quot;,
-                              $$term);
</del><ins>+    # This joins the right tables for us.
+    $self-&gt;_add_extra_column('product');
+    
+    # Generate the restriction condition    
+    $args-&gt;{full_field} = &quot;classifications.name&quot;;
+    $self-&gt;_do_operator_function($args);
+    my $term = $args-&gt;{term};
+    $args-&gt;{term} = build_subselect(&quot;map_product.classification_id&quot;,
+        &quot;classifications.id&quot;, &quot;classifications&quot;, $term);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _keywords_nonchanged {
-    my $self = shift;
-    my %func_args = @_;
-    my ($chartid, $v, $ff, $f, $t, $term, $supptables) =
-        @func_args{qw(chartid v ff f t term supptables)};
-    
-    my @list;
-    my $table = &quot;keywords_$$chartid&quot;;
-    foreach my $value (split(/[\s,]+/, $$v)) {
-        if ($value eq '') {
-            next;
-        }
-        my $keyword = new Bugzilla::Keyword({name =&gt; $value});
-        if ($keyword) {
-            push(@list, &quot;$table.keywordid = &quot; . $keyword-&gt;id);
-        }
-        else {
-            ThrowUserError(&quot;unknown_keyword&quot;,
-                           { keyword =&gt; $$v });
-        }
-    }
-    my $haveawordterm;
-    if (@list) {
-        $haveawordterm = &quot;(&quot; . join(' OR ', @list) . &quot;)&quot;;
-        if ($$t eq &quot;anywords&quot;) {
-            $$term = $haveawordterm;
-        } elsif ($$t eq &quot;allwords&quot;) {
-            $self-&gt;_allwords;
-            if ($$term &amp;&amp; $haveawordterm) {
-                $$term = &quot;(($$term) AND $haveawordterm)&quot;;
-            }
-        }
-    }
-    if ($$term) {
-        push(@$supptables, &quot;LEFT JOIN keywords AS $table &quot; .
-                           &quot;ON $table.bug_id = bugs.bug_id&quot;);
-    }
</del><ins>+sub _nullable {
+    my ($self, $args) = @_;
+    my $field = $args-&gt;{full_field};
+    $args-&gt;{full_field} = &quot;COALESCE($field, '')&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _dependson_nonchanged {
-    my $self = shift;
-    my %func_args = @_;
-    my ($chartid, $ff, $f, $funcsbykey, $t, $term, $supptables) =
-        @func_args{qw(chartid ff f funcsbykey t term supptables)};
-    
-    my $table = &quot;dependson_&quot; . $$chartid;
-    $$ff = &quot;$table.$$f&quot;;
-    $$funcsbykey{&quot;,$$t&quot;}($self, %func_args);
-    push(@$supptables, &quot;LEFT JOIN dependencies AS $table &quot; .
-                       &quot;ON $table.blocked = bugs.bug_id &quot; .
-                       &quot;AND ($$term)&quot;);
-    $$term = &quot;$$ff IS NOT NULL&quot;;
</del><ins>+sub _nullable_int {
+    my ($self, $args) = @_;
+    my $field = $args-&gt;{full_field};
+    $args-&gt;{full_field} = &quot;COALESCE($field, 0)&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _blocked_nonchanged {
-    my $self = shift;
-    my %func_args = @_;
-    my ($chartid, $ff, $f, $funcsbykey, $t, $term, $supptables) =
-        @func_args{qw(chartid ff f funcsbykey t term supptables)};
-
-    my $table = &quot;blocked_&quot; . $$chartid;
-    $$ff = &quot;$table.$$f&quot;;
-    $$funcsbykey{&quot;,$$t&quot;}($self, %func_args);
-    push(@$supptables, &quot;LEFT JOIN dependencies AS $table &quot; .
-                       &quot;ON $table.dependson = bugs.bug_id &quot; .
-                       &quot;AND ($$term)&quot;);
-    $$term = &quot;$$ff IS NOT NULL&quot;;
</del><ins>+sub _nullable_datetime {
+    my ($self, $args) = @_;
+    my $field = $args-&gt;{full_field};
+    my $empty = Bugzilla-&gt;dbh-&gt;quote(EMPTY_DATETIME);
+    $args-&gt;{full_field} = &quot;COALESCE($field, $empty)&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _alias_nonchanged {
-    my $self = shift;
-    my %func_args = @_;
-    my ($ff, $funcsbykey, $t, $term) =
-        @func_args{qw(ff funcsbykey t term)};
-    
-    $$ff = &quot;COALESCE(bugs.alias, '')&quot;;
-    
-    $$funcsbykey{&quot;,$$t&quot;}($self, %func_args);
</del><ins>+sub _deadline {
+    my ($self, $args) = @_;
+    my $field = $args-&gt;{full_field};
+    # This makes &quot;equals&quot; searches work on all DBs (even on MySQL, which
+    # has a bug: http://bugs.mysql.com/bug.php?id=60324).
+    $args-&gt;{full_field} = Bugzilla-&gt;dbh-&gt;sql_date_format($field, '%Y-%m-%d');
+    $self-&gt;_nullable_datetime($args);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _owner_idle_time_greater_less {
</span><del>-    my $self = shift;
-    my %func_args = @_;
-    my ($chartid, $v, $supptables, $t, $wherepart, $term) =
-        @func_args{qw(chartid v supptables t wherepart term)};
</del><ins>+    my ($self, $args) = @_;
+    my ($chart_id, $joins, $value, $operator) =
+        @$args{qw(chart_id joins value operator)};
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx">     
</span><del>-    my $table = &quot;idle_&quot; . $$chartid;
-    $$v =~ /^(\d+)\s*([hHdDwWmMyY])?$/;
-    my $quantity = $1;
-    my $unit = lc $2;
-    my $unitinterval = 'DAY';
-    if ($unit eq 'h') {
-        $unitinterval = 'HOUR';
-    } elsif ($unit eq 'w') {
-        $unitinterval = ' * 7 DAY';
-    } elsif ($unit eq 'm') {
-        $unitinterval = 'MONTH';
-    } elsif ($unit eq 'y') {
-        $unitinterval = 'YEAR';
-    }
-    my $cutoff = &quot;NOW() - &quot; .
-                 $dbh-&gt;sql_interval($quantity, $unitinterval);
-    my $assigned_fieldid = get_field_id('assigned_to');
-    push(@$supptables, &quot;LEFT JOIN longdescs AS comment_$table &quot; .
-                       &quot;ON comment_$table.who = bugs.assigned_to &quot; .
-                       &quot;AND comment_$table.bug_id = bugs.bug_id &quot; .
-                       &quot;AND comment_$table.bug_when &gt; $cutoff&quot;);
-    push(@$supptables, &quot;LEFT JOIN bugs_activity AS activity_$table &quot; .
-                       &quot;ON (activity_$table.who = bugs.assigned_to &quot; .
-                       &quot;OR activity_$table.fieldid = $assigned_fieldid) &quot; .
-                       &quot;AND activity_$table.bug_id = bugs.bug_id &quot; .
-                       &quot;AND activity_$table.bug_when &gt; $cutoff&quot;);
-    if ($$t =~ /greater/) {
-        push(@$wherepart, &quot;(comment_$table.who IS NULL &quot; .
-                          &quot;AND activity_$table.who IS NULL)&quot;);
</del><ins>+    my $table = &quot;idle_$chart_id&quot;;
+    my $quoted = $dbh-&gt;quote(SqlifyDate($value));
+    
+    my $ld_table = &quot;comment_$table&quot;;
+    my $act_table = &quot;activity_$table&quot;;    
+    my $comments_join = {
+        table =&gt; 'longdescs',
+        as    =&gt; $ld_table,
+        from  =&gt; 'assigned_to',
+        to    =&gt; 'who',
+        extra =&gt; [&quot;$ld_table.bug_when &gt; $quoted&quot;],
+    };
+    my $activity_join = {
+        table =&gt; 'bugs_activity',
+        as    =&gt; $act_table,
+        from  =&gt; 'assigned_to',
+        to    =&gt; 'who',
+        extra =&gt; [&quot;$act_table.bug_when &gt; $quoted&quot;]
+    };
+    
+    push(@$joins, $comments_join, $activity_join);
+    
+    if ($operator =~ /greater/) {
+        $args-&gt;{term} =
+            &quot;$ld_table.who IS NULL AND $act_table.who IS NULL&quot;;
</ins><span class="cx">     } else {
</span><del>-        push(@$wherepart, &quot;(comment_$table.who IS NOT NULL &quot; .
-                          &quot;OR activity_$table.who IS NOT NULL)&quot;);
</del><ins>+         $args-&gt;{term} =
+            &quot;$ld_table.who IS NOT NULL OR $act_table.who IS NOT NULL&quot;;
</ins><span class="cx">     }
</span><del>-    $$term = &quot;0=0&quot;;
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _multiselect_negative {
</span><del>-    my $self = shift;
-    my %func_args = @_;
-    my ($f, $ff, $t, $funcsbykey, $term) = @func_args{qw(f ff t funcsbykey term)};
-    
-    my %map = (
-        notequals =&gt; 'equals',
-        notregexp =&gt; 'regexp',
-        notsubstring =&gt; 'substring',
-        nowords =&gt; 'anywords',
-        nowordssubstr =&gt; 'anywordssubstr',
-    );
</del><ins>+    my ($self, $args) = @_;
+    my ($field, $operator) = @$args{qw(field operator)};
</ins><span class="cx"> 
</span><del>-    my $table = &quot;bug_$$f&quot;;
-    $$ff = &quot;$table.value&quot;;
-    
-    $$funcsbykey{&quot;,&quot;.$map{$$t}}($self, %func_args);
-    $$term = &quot;bugs.bug_id NOT IN (SELECT bug_id FROM $table WHERE $$term)&quot;;
</del><ins>+    $args-&gt;{operator} = $self-&gt;_reverse_operator($operator);
+    $args-&gt;{term} = $self-&gt;_multiselect_term($args, 1);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _multiselect_multiple {
</span><del>-    my $self = shift;
-    my %func_args = @_;
-    my ($f, $ff, $t, $v, $funcsbykey, $term) = @func_args{qw(f ff t v funcsbykey term)};
</del><ins>+    my ($self, $args) = @_;
+    my ($chart_id, $field, $operator, $value)
+        = @$args{qw(chart_id field operator value)};
+    my $dbh = Bugzilla-&gt;dbh;
</ins><span class="cx">     
</span><ins>+    # We want things like &quot;cf_multi_select=two+words&quot; to still be
+    # considered a search for two separate words, unless we're using
+    # anyexact. (_all_values would consider that to be one &quot;word&quot; with a
+    # space in it, because it's not in the Boolean Charts).
+    my @words = $operator eq 'anyexact' ? $self-&gt;_all_values($args)
+                                        : split(/[\s,]+/, $value);
+    
</ins><span class="cx">     my @terms;
</span><del>-    my $table = &quot;bug_$$f&quot;;
-    $$ff = &quot;$table.value&quot;;
-    
-    foreach my $word (split(/[\s,]+/, $$v)) {
-        $$v = $word;
-        $$funcsbykey{&quot;,&quot;.$$t}($self, %func_args);
-        push(@terms, &quot;bugs.bug_id IN
-                      (SELECT bug_id FROM $table WHERE $$term)&quot;);
</del><ins>+    foreach my $word (@words) {
+        $args-&gt;{value} = $word;
+        $args-&gt;{quoted} = $dbh-&gt;quote($word);
+        push(@terms, $self-&gt;_multiselect_term($args));
</ins><span class="cx">     }
</span><span class="cx">     
</span><del>-    if ($$t eq 'anyexact') {
-        $$term = &quot;(&quot; . join(&quot; OR &quot;, @terms) . &quot;)&quot;;
</del><ins>+    # The spacing in the joins helps make the resulting SQL more readable.
+    if ($operator =~ /^any/) {
+        $args-&gt;{term} = join(&quot;\n        OR &quot;, @terms);
</ins><span class="cx">     }
</span><span class="cx">     else {
</span><del>-        $$term = &quot;(&quot; . join(&quot; AND &quot;, @terms) . &quot;)&quot;;
</del><ins>+        $args-&gt;{term} = join(&quot;\n        AND &quot;, @terms);
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _multiselect_nonchanged {
</span><del>-    my $self = shift;
-    my %func_args = @_;
-    my ($chartid, $f, $ff, $t, $funcsbykey, $supptables) =
-        @func_args{qw(chartid f ff t funcsbykey supptables)};
</del><ins>+    my ($self, $args) = @_;
+    my ($chart_id, $joins, $field, $operator) =
+        @$args{qw(chart_id joins field operator)};
+    $args-&gt;{term} = $self-&gt;_multiselect_term($args)
+}
</ins><span class="cx"> 
</span><del>-    my $table = $$f.&quot;_&quot;.$$chartid;
-    $$ff = &quot;$table.value&quot;;
</del><ins>+sub _multiselect_table {
+    my ($self, $args) = @_;
+    my ($field, $chart_id) = @$args{qw(field chart_id)};
+    my $dbh = Bugzilla-&gt;dbh;
</ins><span class="cx">     
</span><del>-    $$funcsbykey{&quot;,$$t&quot;}($self, %func_args);
-    push(@$supptables, &quot;LEFT JOIN bug_$$f AS $table &quot; .
-                       &quot;ON $table.bug_id = bugs.bug_id &quot;);
</del><ins>+    if ($field eq 'keywords') {
+        $args-&gt;{full_field} = 'keyworddefs.name';
+        return &quot;keywords INNER JOIN keyworddefs&quot;.
+                               &quot; ON keywords.keywordid = keyworddefs.id&quot;;
+    }
+    elsif ($field eq 'tag') {
+        $args-&gt;{full_field} = 'tag.name';
+        return &quot;bug_tag INNER JOIN tag ON bug_tag.tag_id = tag.id AND user_id = &quot;
+               . ($self-&gt;_sharer_id || $self-&gt;_user-&gt;id);
+    }
+    elsif ($field eq 'bug_group') {
+        $args-&gt;{full_field} = 'groups.name';
+        return &quot;bug_group_map INNER JOIN groups
+                                      ON bug_group_map.group_id = groups.id&quot;;
+    }
+    elsif ($field eq 'blocked' or $field eq 'dependson') {
+        my $select = $field eq 'blocked' ? 'dependson' : 'blocked';
+        $args-&gt;{_select_field} = $select;
+        $args-&gt;{full_field} = $field;
+        return &quot;dependencies&quot;;
+    }
+    elsif ($field eq 'longdesc') {
+        $args-&gt;{_extra_where} = &quot; AND isprivate = 0&quot;
+            if !$self-&gt;_user-&gt;is_insider;
+        $args-&gt;{full_field} = 'thetext';
+        return &quot;longdescs&quot;;
+    }
+    elsif ($field eq 'longdescs.isprivate') {
+        ThrowUserError('auth_failure', { action =&gt; 'search',
+                                         object =&gt; 'bug_fields',
+                                         field =&gt; 'longdescs.isprivate' })
+            if !$self-&gt;_user-&gt;is_insider;
+        $args-&gt;{full_field} = 'isprivate';
+        return &quot;longdescs&quot;;
+    }
+    elsif ($field =~ /^attachments/) {
+        $args-&gt;{_extra_where} = &quot; AND isprivate = 0&quot;
+            if !$self-&gt;_user-&gt;is_insider;
+        $field =~ /^attachments\.(.+)$/;
+        $args-&gt;{full_field} = $1;
+        return &quot;attachments&quot;;
+    }
+    elsif ($field eq 'attach_data.thedata') {
+        $args-&gt;{_extra_where} = &quot; AND attachments.isprivate = 0&quot;
+            if !$self-&gt;_user-&gt;is_insider;
+        return &quot;attachments INNER JOIN attach_data &quot;
+               . &quot; ON attachments.attach_id = attach_data.id&quot;
+    }
+    elsif ($field eq 'flagtypes.name') {
+        $args-&gt;{full_field} = $dbh-&gt;sql_string_concat(&quot;flagtypes.name&quot;,
+                                                      &quot;flags.status&quot;);
+        return &quot;flags INNER JOIN flagtypes ON flags.type_id = flagtypes.id&quot;;
+    }
+    my $table = &quot;bug_$field&quot;;
+    $args-&gt;{full_field} = &quot;bug_$field.value&quot;;
+    return $table;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _equals {
-    my $self = shift;
-    my %func_args = @_;
-    my ($ff, $q, $term) = @func_args{qw(ff q term)};
-    
-    $$term = &quot;$$ff = $$q&quot;;
</del><ins>+sub _multiselect_term {
+    my ($self, $args, $not) = @_;
+    my $table = $self-&gt;_multiselect_table($args);
+    $self-&gt;_do_operator_function($args);
+    my $term = $args-&gt;{term};
+    $term .= $args-&gt;{_extra_where} || '';
+    my $select = $args-&gt;{_select_field} || 'bug_id';
+    my $not_sql = $not ? &quot;NOT &quot; : '';
+    return &quot;bugs.bug_id ${not_sql}IN (SELECT $select FROM $table WHERE $term)&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _notequals {
-    my $self = shift;
-    my %func_args = @_;
-    my ($ff, $q, $term) = @func_args{qw(ff q term)};
-    
-    $$term = &quot;$$ff != $$q&quot;;
</del><ins>+###############################
+# Standard Operator Functions #
+###############################
+
+sub _simple_operator {
+    my ($self, $args) = @_;
+    my ($full_field, $quoted, $operator) =
+        @$args{qw(full_field quoted operator)};
+    my $sql_operator = SIMPLE_OPERATORS-&gt;{$operator};
+    $args-&gt;{term} = &quot;$full_field $sql_operator $quoted&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _casesubstring {
</span><del>-    my $self = shift;
-    my %func_args = @_;
-    my ($ff, $q, $term) = @func_args{qw(ff q term)};
</del><ins>+    my ($self, $args) = @_;
+    my ($full_field, $quoted) = @$args{qw(full_field quoted)};
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx">     
</span><del>-    $$term = $dbh-&gt;sql_position($$q, $$ff) . &quot; &gt; 0&quot;;
</del><ins>+    $args-&gt;{term} = $dbh-&gt;sql_position($quoted, $full_field) . &quot; &gt; 0&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _substring {
</span><del>-    my $self = shift;
-    my %func_args = @_;
-    my ($ff, $q, $term) = @func_args{qw(ff q term)};
</del><ins>+    my ($self, $args) = @_;
+    my ($full_field, $quoted) = @$args{qw(full_field quoted)};
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx">     
</span><del>-    $$term = $dbh-&gt;sql_iposition($$q, $$ff) . &quot; &gt; 0&quot;;
</del><ins>+    # XXX This should probably be changed to just use LIKE
+    $args-&gt;{term} = $dbh-&gt;sql_iposition($quoted, $full_field) . &quot; &gt; 0&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _notsubstring {
</span><del>-    my $self = shift;
-    my %func_args = @_;
-    my ($ff, $q, $term) = @func_args{qw(ff q term)};
</del><ins>+    my ($self, $args) = @_;
+    my ($full_field, $quoted) = @$args{qw(full_field quoted)};
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx">     
</span><del>-    $$term = $dbh-&gt;sql_iposition($$q, $$ff) . &quot; = 0&quot;;
</del><ins>+    # XXX This should probably be changed to just use NOT LIKE
+    $args-&gt;{term} = $dbh-&gt;sql_iposition($quoted, $full_field) . &quot; = 0&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _regexp {
</span><del>-    my $self = shift;
-    my %func_args = @_;
-    my ($ff, $q, $term) = @func_args{qw(ff q term)};
</del><ins>+    my ($self, $args) = @_;
+    my ($full_field, $quoted) = @$args{qw(full_field quoted)};
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx">     
</span><del>-    $$term = $dbh-&gt;sql_regexp($$ff, $$q);
</del><ins>+    $args-&gt;{term} = $dbh-&gt;sql_regexp($full_field, $quoted);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _notregexp {
</span><del>-    my $self = shift;
-    my %func_args = @_;
-    my ($ff, $q, $term) = @func_args{qw(ff q term)};
</del><ins>+    my ($self, $args) = @_;
+    my ($full_field, $quoted) = @$args{qw(full_field quoted)};
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx">     
</span><del>-    $$term = $dbh-&gt;sql_not_regexp($$ff, $$q);
</del><ins>+    $args-&gt;{term} = $dbh-&gt;sql_not_regexp($full_field, $quoted);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _lessthan {
-    my $self = shift;
-    my %func_args = @_;
-    my ($ff, $q, $term) = @func_args{qw(ff q term)};
-
-    $$term = &quot;$$ff &lt; $$q&quot;;
-}
-
-sub _greaterthan {
-    my $self = shift;
-    my %func_args = @_;
-    my ($ff, $q, $term) = @func_args{qw(ff q term)};
-    
-    $$term = &quot;$$ff &gt; $$q&quot;;
-}
-
</del><span class="cx"> sub _anyexact {
</span><del>-    my $self = shift;
-    my %func_args = @_;
-    my ($f, $ff, $v, $q, $term) = @func_args{qw(f ff v q term)};
</del><ins>+    my ($self, $args) = @_;
+    my ($field, $full_field) = @$args{qw(field full_field)};
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx">     
</span><del>-    my @list;
-    foreach my $w (split(/,/, $$v)) {
-        if ($w eq &quot;---&quot; &amp;&amp; $$f =~ /resolution/) {
-            $w = &quot;&quot;;
-        }
-        $$q = $dbh-&gt;quote($w);
-        trick_taint($$q);
-        push(@list, $$q);
-    }
</del><ins>+    my @list = $self-&gt;_all_values($args, ',');
+    @list = map { $self-&gt;_quote_unless_numeric($args, $_) } @list;
+    
</ins><span class="cx">     if (@list) {
</span><del>-        $$term = $dbh-&gt;sql_in($$ff, \@list);
</del><ins>+        $args-&gt;{term} = $dbh-&gt;sql_in($full_field, \@list);
</ins><span class="cx">     }
</span><ins>+    else {
+        $args-&gt;{term} = '';
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _anywordsubstr {
</span><del>-    my $self = shift;
-    my %func_args = @_;
-    my ($ff, $v, $term) = @func_args{qw(ff v term)};
</del><ins>+    my ($self, $args) = @_;
+    my ($full_field, $value) = @$args{qw(full_field value)};
</ins><span class="cx">     
</span><del>-    $$term = join(&quot; OR &quot;, @{GetByWordListSubstr($$ff, $$v)});
</del><ins>+    my @terms = $self-&gt;_substring_terms($args);
+    $args-&gt;{term} = join(&quot;\n\tOR &quot;, @terms);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _allwordssubstr {
</span><del>-    my $self = shift;
-    my %func_args = @_;
-    my ($ff, $v, $term) = @func_args{qw(ff v term)};
</del><ins>+    my ($self, $args) = @_;
</ins><span class="cx">     
</span><del>-    $$term = join(&quot; AND &quot;, @{GetByWordListSubstr($$ff, $$v)});
</del><ins>+    my @terms = $self-&gt;_substring_terms($args);
+    $args-&gt;{term} = join(&quot;\n\tAND &quot;, @terms);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _nowordssubstr {
</span><del>-    my $self = shift;
-    my %func_args = @_;
-    my ($ff, $v, $term) = @func_args{qw(ff v term)};
-    
-    my @list = @{GetByWordListSubstr($$ff, $$v)};
-    if (@list) {
-        $$term = &quot;NOT (&quot; . join(&quot; OR &quot;, @list) . &quot;)&quot;;
-    }
</del><ins>+    my ($self, $args) = @_;
+    $self-&gt;_anywordsubstr($args);
+    my $term = $args-&gt;{term};
+    $args-&gt;{term} = &quot;NOT($term)&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _anywords {
</span><del>-    my $self = shift;
-    my %func_args = @_;
-    my ($ff, $v, $term) = @func_args{qw(ff v term)};
</del><ins>+    my ($self, $args) = @_;
</ins><span class="cx">     
</span><del>-    $$term = join(&quot; OR &quot;, @{GetByWordList($$ff, $$v)});
</del><ins>+    my @terms = $self-&gt;_word_terms($args);
+    # Because _word_terms uses AND, we need to parenthesize its terms
+    # if there are more than one.
+    @terms = map(&quot;($_)&quot;, @terms) if scalar(@terms) &gt; 1;
+    $args-&gt;{term} = join(&quot;\n\tOR &quot;, @terms);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _allwords {
</span><del>-    my $self = shift;
-    my %func_args = @_;
-    my ($ff, $v, $term) = @func_args{qw(ff v term)};
</del><ins>+    my ($self, $args) = @_;
</ins><span class="cx">     
</span><del>-    $$term = join(&quot; AND &quot;, @{GetByWordList($$ff, $$v)});
</del><ins>+    my @terms = $self-&gt;_word_terms($args);
+    $args-&gt;{term} = join(&quot;\n\tAND &quot;, @terms);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _nowords {
</span><del>-    my $self = shift;
-    my %func_args = @_;
-    my ($ff, $v, $term) = @func_args{qw(ff v term)};
-    
-    my @list = @{GetByWordList($$ff, $$v)};
-    if (@list) {
-        $$term = &quot;NOT (&quot; . join(&quot; OR &quot;, @list) . &quot;)&quot;;
-    }
</del><ins>+    my ($self, $args) = @_;
+    $self-&gt;_anywords($args);
+    my $term = $args-&gt;{term};
+    $args-&gt;{term} = &quot;NOT($term)&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _changedbefore_changedafter {
</span><del>-    my $self = shift;
-    my %func_args = @_;
-    my ($chartid, $f, $ff, $t, $v, $chartfields, $supptables, $term) =
-        @func_args{qw(chartid f ff t v chartfields supptables term)};
</del><ins>+    my ($self, $args) = @_;
+    my ($chart_id, $joins, $field, $operator, $value) =
+        @$args{qw(chart_id joins field operator value)};
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><ins>+
+    my $field_object = $self-&gt;_chart_fields-&gt;{$field}
+        || ThrowCodeError(&quot;invalid_field_name&quot;, { field =&gt; $field });
</ins><span class="cx">     
</span><del>-    my $operator = ($$t =~ /before/) ? '&lt;' : '&gt;';
-    my $table = &quot;act_$$chartid&quot;;
-    my $fieldid = $$chartfields{$$f};
-    if (!$fieldid) {
-        ThrowCodeError(&quot;invalid_field_name&quot;, {field =&gt; $$f});
</del><ins>+    # Asking when creation_ts changed is just asking when the bug was created.
+    if ($field_object-&gt;name eq 'creation_ts') {
+        $args-&gt;{operator} =
+            $operator eq 'changedbefore' ? 'lessthaneq' : 'greaterthaneq';
+        return $self-&gt;_do_operator_function($args);
</ins><span class="cx">     }
</span><del>-    push(@$supptables, &quot;LEFT JOIN bugs_activity AS $table &quot; .
-                      &quot;ON $table.bug_id = bugs.bug_id &quot; .
-                      &quot;AND $table.fieldid = $fieldid &quot; .
-                      &quot;AND $table.bug_when $operator &quot; . 
-                      $dbh-&gt;quote(SqlifyDate($$v)) );
-    $$term = &quot;($table.bug_when IS NOT NULL)&quot;;
</del><ins>+    
+    my $sql_operator = ($operator =~ /before/) ? '&lt;=' : '&gt;=';
+    my $field_id = $field_object-&gt;id;
+    # Charts on changed* fields need to be field-specific. Otherwise,
+    # OR chart rows make no sense if they contain multiple fields.
+    my $table = &quot;act_${field_id}_$chart_id&quot;;
+
+    my $sql_date = $dbh-&gt;quote(SqlifyDate($value));
+    my $join = {
+        table =&gt; 'bugs_activity',
+        as    =&gt; $table,
+        extra =&gt; [&quot;$table.fieldid = $field_id&quot;,
+                  &quot;$table.bug_when $sql_operator $sql_date&quot;],
+    };
+    push(@$joins, $join);
+    $args-&gt;{term} = &quot;$table.bug_when IS NOT NULL&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _changedfrom_changedto {
</span><del>-    my $self = shift;
-    my %func_args = @_;
-    my ($chartid, $chartfields, $f, $t, $v, $q, $supptables, $term) =
-        @func_args{qw(chartid chartfields f t v q supptables term)};
</del><ins>+    my ($self, $args) = @_;
+    my ($chart_id, $joins, $field, $operator, $quoted) =
+        @$args{qw(chart_id joins field operator quoted)};
</ins><span class="cx">     
</span><del>-    my $operator = ($$t =~ /from/) ? 'removed' : 'added';
-    my $table = &quot;act_$$chartid&quot;;
-    my $fieldid = $$chartfields{$$f};
-    if (!$fieldid) {
-        ThrowCodeError(&quot;invalid_field_name&quot;, {field =&gt; $$f});
-    }
-    push(@$supptables, &quot;LEFT JOIN bugs_activity AS $table &quot; .
-                      &quot;ON $table.bug_id = bugs.bug_id &quot; .
-                      &quot;AND $table.fieldid = $fieldid &quot; .
-                      &quot;AND $table.$operator = $$q&quot;);
-    $$term = &quot;($table.bug_when IS NOT NULL)&quot;;
</del><ins>+    my $column = ($operator =~ /from/) ? 'removed' : 'added';
+    my $field_object = $self-&gt;_chart_fields-&gt;{$field}
+        || ThrowCodeError(&quot;invalid_field_name&quot;, { field =&gt; $field });
+    my $field_id = $field_object-&gt;id;
+    my $table = &quot;act_${field_id}_$chart_id&quot;;
+    my $join = {
+        table =&gt; 'bugs_activity',
+        as    =&gt; $table,
+        extra =&gt; [&quot;$table.fieldid = $field_id&quot;,
+                  &quot;$table.$column = $quoted&quot;],
+    };
+    push(@$joins, $join);
+
+    $args-&gt;{term} = &quot;$table.bug_when IS NOT NULL&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _changedby {
</span><del>-    my $self = shift;
-    my %func_args = @_;
-    my ($chartid, $chartfields, $f, $v, $supptables, $term) =
-        @func_args{qw(chartid chartfields f v supptables term)};
</del><ins>+    my ($self, $args) = @_;
+    my ($chart_id, $joins, $field, $operator, $value) =
+        @$args{qw(chart_id joins field operator value)};
</ins><span class="cx">     
</span><del>-    my $table = &quot;act_$$chartid&quot;;
-    my $fieldid = $$chartfields{$$f};
-    if (!$fieldid) {
-        ThrowCodeError(&quot;invalid_field_name&quot;, {field =&gt; $$f});
</del><ins>+    my $field_object = $self-&gt;_chart_fields-&gt;{$field}
+        || ThrowCodeError(&quot;invalid_field_name&quot;, { field =&gt; $field });
+    my $field_id = $field_object-&gt;id;
+    my $table = &quot;act_${field_id}_$chart_id&quot;;
+    my $user_id  = login_to_id($value, THROW_ERROR);
+    my $join = {
+        table =&gt; 'bugs_activity',
+        as    =&gt; $table,
+        extra =&gt; [&quot;$table.fieldid = $field_id&quot;,
+                  &quot;$table.who = $user_id&quot;],
+    };
+    push(@$joins, $join);
+    $args-&gt;{term} = &quot;$table.bug_when IS NOT NULL&quot;;
+}
+
+######################
+# Public Subroutines #
+######################
+
+# Validate that the query type is one we can deal with
+sub IsValidQueryType
+{
+    my ($queryType) = @_;
+    if (grep { $_ eq $queryType } qw(specific advanced)) {
+        return 1;
</ins><span class="cx">     }
</span><del>-    my $id = login_to_id($$v, THROW_ERROR);
-    push(@$supptables, &quot;LEFT JOIN bugs_activity AS $table &quot; .
-                      &quot;ON $table.bug_id = bugs.bug_id &quot; .
-                      &quot;AND $table.fieldid = $fieldid &quot; .
-                      &quot;AND $table.who = $id&quot;);
-    $$term = &quot;($table.bug_when IS NOT NULL)&quot;;
</del><ins>+    return 0;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# Splits out &quot;asc|desc&quot; from a sort order item.
+sub split_order_term {
+    my $fragment = shift;
+    $fragment =~ /^(.+?)(?:\s+(ASC|DESC))?$/i;
+    my ($column_name, $direction) = (lc($1), uc($2 || ''));
+    return wantarray ? ($column_name, $direction) : $column_name;
+}
+
+# Used to translate old SQL fragments from buglist.cgi's &quot;order&quot; argument
+# into our modern field IDs.
+sub translate_old_column {
+    my ($column) = @_;
+    # All old SQL fragments have a period in them somewhere.
+    return $column if $column !~ /\./;
+
+    if ($column =~ /\bAS\s+(\w+)$/i) {
+        return $1;
+    }
+    # product, component, classification, assigned_to, qa_contact, reporter
+    elsif ($column =~ /map_(\w+?)s?\.(login_)?name/i) {
+        return $1;
+    }
+    
+    # If it doesn't match the regexps above, check to see if the old 
+    # SQL fragment matches the SQL of an existing column
+    foreach my $key (%{ COLUMNS() }) {
+        next unless exists COLUMNS-&gt;{$key}-&gt;{name};
+        return $key if COLUMNS-&gt;{$key}-&gt;{name} eq $column;
+    }
+
+    return $column;
+}
+
</ins><span class="cx"> 1;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaSeriespm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Series.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Series.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Series.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -33,8 +33,12 @@
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla::Error;
</span><span class="cx"> use Bugzilla::Util;
</span><del>-use Bugzilla::User;
</del><span class="cx"> 
</span><ins>+# This is a hack so that we can re-use the rename_field_value
+# code from Bugzilla::Search::Saved.
+use constant DB_TABLE =&gt; 'series';
+use constant ID_FIELD =&gt; 'series_id';
+
</ins><span class="cx"> sub new {
</span><span class="cx">     my $invocant = shift;
</span><span class="cx">     my $class = ref($invocant) || $invocant;
</span><span class="lines">@@ -69,7 +73,8 @@
</span><span class="cx">     elsif ($arg_count &gt;= 6 &amp;&amp; $arg_count &lt;= 8) {
</span><span class="cx">         # We've been given a load of parameters to create a new Series from.
</span><span class="cx">         # Currently, undef is always passed as the first parameter; this allows
</span><del>-        # you to call writeToDatabase() unconditionally. 
</del><ins>+        # you to call writeToDatabase() unconditionally.
+        # XXX - You cannot set category_id and subcategory_id from here.
</ins><span class="cx">         $self-&gt;initFromParameters(@_);
</span><span class="cx">     }
</span><span class="cx">     else {
</span><span class="lines">@@ -80,34 +85,30 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub initFromDatabase {
</span><del>-    my $self = shift;
-    my $series_id = shift;
-    
</del><ins>+    my ($self, $series_id) = @_;
+    my $dbh = Bugzilla-&gt;dbh;
+    my $user = Bugzilla-&gt;user;
+
</ins><span class="cx">     detaint_natural($series_id) 
</span><span class="cx">       || ThrowCodeError(&quot;invalid_series_id&quot;, { 'series_id' =&gt; $series_id });
</span><del>-    
-    my $dbh = Bugzilla-&gt;dbh;
</del><ins>+
+    my $grouplist = $user-&gt;groups_as_string;
+
</ins><span class="cx">     my @series = $dbh-&gt;selectrow_array(&quot;SELECT series.series_id, cc1.name, &quot; .
</span><span class="cx">         &quot;cc2.name, series.name, series.creator, series.frequency, &quot; .
</span><del>-        &quot;series.query, series.is_public &quot; .
</del><ins>+        &quot;series.query, series.is_public, series.category, series.subcategory &quot; .
</ins><span class="cx">         &quot;FROM series &quot; .
</span><del>-        &quot;LEFT JOIN series_categories AS cc1 &quot; .
</del><ins>+        &quot;INNER JOIN series_categories AS cc1 &quot; .
</ins><span class="cx">         &quot;    ON series.category = cc1.id &quot; .
</span><del>-        &quot;LEFT JOIN series_categories AS cc2 &quot; .
</del><ins>+        &quot;INNER JOIN series_categories AS cc2 &quot; .
</ins><span class="cx">         &quot;    ON series.subcategory = cc2.id &quot; .
</span><span class="cx">         &quot;LEFT JOIN category_group_map AS cgm &quot; .
</span><span class="cx">         &quot;    ON series.category = cgm.category_id &quot; .
</span><del>-        &quot;LEFT JOIN user_group_map AS ugm &quot; .
-        &quot;    ON cgm.group_id = ugm.group_id &quot; .
-        &quot;    AND ugm.user_id = &quot; . Bugzilla-&gt;user-&gt;id .
-        &quot;    AND isbless = 0 &quot; .
-        &quot;WHERE series.series_id = $series_id AND &quot; .
-        &quot;(is_public = 1 OR creator = &quot; . Bugzilla-&gt;user-&gt;id . &quot; OR &quot; .
-        &quot;(ugm.group_id IS NOT NULL)) &quot; . 
-        $dbh-&gt;sql_group_by('series.series_id', 'cc1.name, cc2.name, ' .
-                           'series.name, series.creator, series.frequency, ' .
-                           'series.query, series.is_public'));
-    
</del><ins>+        &quot;    AND cgm.group_id NOT IN($grouplist) &quot; .
+        &quot;WHERE series.series_id = ? &quot; .
+        &quot;    AND (creator = ? OR (is_public = 1 AND cgm.category_id IS NULL))&quot;,
+        undef, ($series_id, $user-&gt;id));
+
</ins><span class="cx">     if (@series) {
</span><span class="cx">         $self-&gt;initFromParameters(@series);
</span><span class="cx">         return $self;
</span><span class="lines">@@ -122,8 +123,9 @@
</span><span class="cx">     my $self = shift;
</span><span class="cx"> 
</span><span class="cx">     ($self-&gt;{'series_id'}, $self-&gt;{'category'},  $self-&gt;{'subcategory'},
</span><del>-     $self-&gt;{'name'}, $self-&gt;{'creator'}, $self-&gt;{'frequency'},
-     $self-&gt;{'query'}, $self-&gt;{'public'}) = @_;
</del><ins>+     $self-&gt;{'name'}, $self-&gt;{'creator_id'}, $self-&gt;{'frequency'},
+     $self-&gt;{'query'}, $self-&gt;{'public'}, $self-&gt;{'category_id'},
+     $self-&gt;{'subcategory_id'}) = @_;
</ins><span class="cx"> 
</span><span class="cx">     # If the first parameter is undefined, check if this series already
</span><span class="cx">     # exists and update it series_id accordingly
</span><span class="lines">@@ -152,7 +154,7 @@
</span><span class="cx">     $self-&gt;{'name'} = $cgi-&gt;param('name')
</span><span class="cx">       || ThrowUserError(&quot;missing_name&quot;);
</span><span class="cx"> 
</span><del>-    $self-&gt;{'creator'} = Bugzilla-&gt;user-&gt;id;
</del><ins>+    $self-&gt;{'creator_id'} = Bugzilla-&gt;user-&gt;id;
</ins><span class="cx"> 
</span><span class="cx">     $self-&gt;{'frequency'} = $cgi-&gt;param('frequency');
</span><span class="cx">     detaint_natural($self-&gt;{'frequency'})
</span><span class="lines">@@ -203,7 +205,7 @@
</span><span class="cx">         $dbh-&gt;do(&quot;INSERT INTO series (creator, category, subcategory, &quot; .
</span><span class="cx">                  &quot;name, frequency, query, is_public) VALUES &quot; . 
</span><span class="cx">                  &quot;(?, ?, ?, ?, ?, ?, ?)&quot;, undef,
</span><del>-                 $self-&gt;{'creator'}, $category_id, $subcategory_id, $self-&gt;{'name'},
</del><ins>+                 $self-&gt;{'creator_id'}, $category_id, $subcategory_id, $self-&gt;{'name'},
</ins><span class="cx">                  $self-&gt;{'frequency'}, $self-&gt;{'query'}, $self-&gt;{'public'});
</span><span class="cx"> 
</span><span class="cx">         # Retrieve series_id
</span><span class="lines">@@ -258,4 +260,27 @@
</span><span class="cx">     return $category_id;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+##########
+# Methods
+##########
+sub id   { return $_[0]-&gt;{'series_id'}; }
+sub name { return $_[0]-&gt;{'name'}; }
+
+sub creator {
+    my $self = shift;
+
+    if (!$self-&gt;{creator} &amp;&amp; $self-&gt;{creator_id}) {
+        require Bugzilla::User;
+        $self-&gt;{creator} = new Bugzilla::User($self-&gt;{creator_id});
+    }
+    return $self-&gt;{creator};
+}
+
+sub remove_from_db {
+    my $self = shift;
+    my $dbh = Bugzilla-&gt;dbh;
+
+    $dbh-&gt;do('DELETE FROM series WHERE series_id = ?', undef, $self-&gt;id);
+}
+
</ins><span class="cx"> 1;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaStatuspm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Status.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Status.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Status.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -22,43 +22,115 @@
</span><span class="cx"> 
</span><span class="cx"> package Bugzilla::Status;
</span><span class="cx"> 
</span><del>-use base qw(Bugzilla::Object Exporter);
-@Bugzilla::Status::EXPORT = qw(BUG_STATE_OPEN is_open_state closed_bug_statuses);
</del><ins>+use Bugzilla::Error;
+# This subclasses Bugzilla::Field::Choice instead of implementing 
+# ChoiceInterface, because a bug status literally is a special type
+# of Field::Choice, not just an object that happens to have the same
+# methods.
+use base qw(Bugzilla::Field::Choice Exporter);
+@Bugzilla::Status::EXPORT = qw(
+    BUG_STATE_OPEN
+    SPECIAL_STATUS_WORKFLOW_ACTIONS
</ins><span class="cx"> 
</span><ins>+    is_open_state 
+    closed_bug_statuses
+);
+
</ins><span class="cx"> ################################
</span><span class="cx"> #####   Initialization     #####
</span><span class="cx"> ################################
</span><span class="cx"> 
</span><ins>+use constant SPECIAL_STATUS_WORKFLOW_ACTIONS =&gt; qw(
+    none
+    duplicate
+    change_resolution
+    clearresolution
+);
+
</ins><span class="cx"> use constant DB_TABLE =&gt; 'bug_status';
</span><span class="cx"> 
</span><del>-use constant DB_COLUMNS =&gt; qw(
-    id
-    value
-    sortkey
-    isactive
-    is_open
-);
</del><ins>+# This has all the standard Bugzilla::Field::Choice columns plus &quot;is_open&quot;
+sub DB_COLUMNS {
+    return ($_[0]-&gt;SUPER::DB_COLUMNS, 'is_open');
+}
</ins><span class="cx"> 
</span><del>-use constant NAME_FIELD =&gt; 'value';
-use constant LIST_ORDER =&gt; 'sortkey, value';
</del><ins>+sub VALIDATORS {
+    my $invocant = shift;
+    my $validators = $invocant-&gt;SUPER::VALIDATORS;
+    $validators-&gt;{is_open} = \&amp;Bugzilla::Object::check_boolean;
+    $validators-&gt;{value} = \&amp;_check_value;
+    return $validators;
+}
</ins><span class="cx"> 
</span><ins>+#########################
+# Database Manipulation #
+#########################
+
+sub create {
+    my $class = shift;
+    my $self = $class-&gt;SUPER::create(@_);
+    delete Bugzilla-&gt;request_cache-&gt;{status_bug_state_open};
+    add_missing_bug_status_transitions();
+    return $self;
+}
+
+sub remove_from_db {
+    my $self = shift;
+    my $dbh = Bugzilla-&gt;dbh;
+    my $id = $self-&gt;id;
+    $dbh-&gt;bz_start_transaction();
+    $self-&gt;SUPER::remove_from_db();
+    $dbh-&gt;do('DELETE FROM status_workflow
+               WHERE old_status = ? OR new_status = ?',
+              undef, $id, $id);
+    $dbh-&gt;bz_commit_transaction();
+    delete Bugzilla-&gt;request_cache-&gt;{status_bug_state_open};
+}
+
</ins><span class="cx"> ###############################
</span><span class="cx"> #####     Accessors        ####
</span><span class="cx"> ###############################
</span><span class="cx"> 
</span><del>-sub name      { return $_[0]-&gt;{'value'};    }
-sub sortkey   { return $_[0]-&gt;{'sortkey'};  }
</del><span class="cx"> sub is_active { return $_[0]-&gt;{'isactive'}; }
</span><span class="cx"> sub is_open   { return $_[0]-&gt;{'is_open'};  }
</span><span class="cx"> 
</span><ins>+sub is_static {
+    my $self = shift;
+    if ($self-&gt;name eq 'UNCONFIRMED'
+        || $self-&gt;name eq Bugzilla-&gt;params-&gt;{'duplicate_or_move_bug_status'}) 
+    {
+        return 1;
+    }
+    return 0;
+}
+
+##############
+# Validators #
+##############
+
+sub _check_value {
+    my $invocant = shift;
+    my $value = $invocant-&gt;SUPER::_check_value(@_);
+
+    if (grep { lc($value) eq lc($_) } SPECIAL_STATUS_WORKFLOW_ACTIONS) {
+        ThrowUserError('fieldvalue_reserved_word',
+                       { field =&gt; $invocant-&gt;field, value =&gt; $value });
+    }
+    return $value;
+}
+
+
</ins><span class="cx"> ###############################
</span><span class="cx"> #####       Methods        ####
</span><span class="cx"> ###############################
</span><span class="cx"> 
</span><span class="cx"> sub BUG_STATE_OPEN {
</span><del>-    # XXX - We should cache this list.
</del><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><del>-    return @{$dbh-&gt;selectcol_arrayref('SELECT value FROM bug_status WHERE is_open = 1')};
</del><ins>+    my $cache = Bugzilla-&gt;request_cache;
+    $cache-&gt;{status_bug_state_open} ||=
+        $dbh-&gt;selectcol_arrayref('SELECT value FROM bug_status 
+                                   WHERE is_open = 1');
+    return @{ $cache-&gt;{status_bug_state_open} };
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> # Tells you whether or not the argument is a valid &quot;open&quot; state.
</span><span class="lines">@@ -107,28 +179,6 @@
</span><span class="cx">     return $self-&gt;{'can_change_to'};
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub can_change_from {
-    my $self = shift;
-    my $dbh = Bugzilla-&gt;dbh;
-
-    if (!defined $self-&gt;{'can_change_from'}) {
-        my $old_status_ids = $dbh-&gt;selectcol_arrayref('SELECT old_status
-                                                         FROM status_workflow
-                                                   INNER JOIN bug_status
-                                                           ON id = old_status
-                                                        WHERE isactive = 1
-                                                          AND new_status = ?
-                                                          AND old_status IS NOT NULL',
-                                                        undef, $self-&gt;id);
-
-        # Allow the bug status to remain unchanged.
-        push(@$old_status_ids, $self-&gt;id);
-        $self-&gt;{'can_change_from'} = Bugzilla::Status-&gt;new_from_list($old_status_ids);
-    }
-
-    return $self-&gt;{'can_change_from'};
-}
-
</del><span class="cx"> sub comment_required_on_change_from {
</span><span class="cx">     my ($self, $old_status) = @_;
</span><span class="cx">     my ($cond, $values) = $self-&gt;_status_condition($old_status);
</span><span class="lines">@@ -191,7 +241,7 @@
</span><span class="cx"> 
</span><span class="cx">     use Bugzilla::Status;
</span><span class="cx"> 
</span><del>-    my $bug_status = new Bugzilla::Status({name =&gt; 'ASSIGNED'});
</del><ins>+    my $bug_status = new Bugzilla::Status({ name =&gt; 'IN_PROGRESS' });
</ins><span class="cx">     my $bug_status = new Bugzilla::Status(4);
</span><span class="cx"> 
</span><span class="cx">     my @closed_bug_statuses = closed_bug_statuses();
</span><span class="lines">@@ -231,17 +281,6 @@
</span><span class="cx"> 
</span><span class="cx">  Returns:     A list of Bugzilla::Status objects.
</span><span class="cx"> 
</span><del>-=item C&lt;can_change_from&gt;
-
- Description: Returns the list of active statuses a bug can be changed from
-              given the new bug status. If the bug status is available on
-              bug creation, this method doesn't return this information.
-              You have to call C&lt;can_change_to&gt; instead.
-
- Params:      none.
-
- Returns:     A list of Bugzilla::Status objects.
-
</del><span class="cx"> =item C&lt;comment_required_on_change_from&gt;
</span><span class="cx"> 
</span><span class="cx"> =over
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaTemplateContextpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/Template/Context.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Template/Context.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Template/Context.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,104 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is ITA Software.
+# Portions created by the Initial Developer are Copyright (C) 2009 
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+# This exists to implement the template-before_process hook.
+package Bugzilla::Template::Context;
+use strict;
+use base qw(Template::Context);
+
+use Bugzilla::Hook;
+use Scalar::Util qw(blessed);
+
+sub process {
+    my $self = shift;
+    # We don't want to run the template_before_process hook for
+    # template hooks (but we do want it to run if a hook calls
+    # PROCESS inside itself). The problem is that the {component}-&gt;{name} of
+    # hooks is unreliable--sometimes it starts with ./ and it's the
+    # full path to the hook template, and sometimes it's just the relative
+    # name (like hook/global/field-descs-end.none.tmpl). Also, calling
+    # template_before_process for hook templates doesn't seem too useful,
+    # because that's already part of the extension and they should be able
+    # to modify their hook if they want (or just modify the variables in the
+    # calling template).
+    if (not delete $self-&gt;{bz_in_hook}) {
+        $self-&gt;{bz_in_process} = 1;
+    }
+    my $result = $self-&gt;SUPER::process(@_);
+    delete $self-&gt;{bz_in_process};
+    return $result;
+}
+
+# This method is called by Template-Toolkit exactly once per template or
+# block (look at a compiled template) so this is an ideal place for us to
+# modify the variables before a template or block runs.
+#
+# We don't do it during Context::process because at that time
+# our stash hasn't been set correctly--the parameters we were passed
+# in the PROCESS or INCLUDE directive haven't been set, and if we're
+# in an INCLUDE, the stash is not yet localized during process().
+sub stash {
+    my $self = shift;
+    my $stash = $self-&gt;SUPER::stash(@_);
+
+    my $name = $stash-&gt;{component}-&gt;{name};
+    my $pre_process = $self-&gt;config-&gt;{PRE_PROCESS};
+
+    # Checking bz_in_process tells us that we were indeed called as part of a
+    # Context::process, and not at some other point. 
+    #
+    # Checking $name makes sure that we're processing a file, and not just a
+    # block, by checking that the name has a period in it. We don't allow
+    # blocks because their names are too unreliable--an extension could have
+    # a block with the same name, or multiple files could have a same-named
+    # block, and then your extension would malfunction.
+    #
+    # We also make sure that we don't run, ever, during the PRE_PROCESS
+    # templates, because if somebody calls Throw*Error globally inside of
+    # template_before_process, that causes an infinite recursion into
+    # the PRE_PROCESS templates (because Bugzilla, while inside 
+    # global/intialize.none.tmpl, loads the template again to create the
+    # template object for Throw*Error).
+    #
+    # Checking Bugzilla::Hook::in prevents infinite recursion on this hook.
+    if ($self-&gt;{bz_in_process} and $name =~ /\./
+        and !grep($_ eq $name, @$pre_process)
+        and !Bugzilla::Hook::in('template_before_process'))
+    {
+        Bugzilla::Hook::process(&quot;template_before_process&quot;,
+                                { vars =&gt; $stash, context =&gt; $self,
+                                  file =&gt; $name });
+    }
+
+    # This prevents other calls to stash() that might somehow happen
+    # later in the file from also triggering the hook.
+    delete $self-&gt;{bz_in_process};
+
+    return $stash;
+}
+
+# We need a DESTROY sub for the same reason that Bugzilla::CGI does.
+sub DESTROY {
+    my $self = shift;
+    $self-&gt;SUPER::DESTROY(@_);
+};
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaTemplateParserpm"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/Bugzilla/Template/Parser.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Template/Parser.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Template/Parser.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,66 +0,0 @@
</span><del>-# -*- Mode: perl; indent-tabs-mode: nil -*-
-#
-# The contents of this file are subject to the Mozilla Public
-# License Version 1.1 (the &quot;License&quot;); you may not use this file
-# except in compliance with the License. You may obtain a copy of
-# the License at http://www.mozilla.org/MPL/
-#
-# Software distributed under the License is distributed on an &quot;AS
-# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
-# implied. See the License for the specific language governing
-# rights and limitations under the License.
-#
-# The Original Code is the Bugzilla Bug Tracking System.
-#
-# The Initial Developer of the Original Code is Marc Schumann.
-# Portions created by Marc Schumann are Copyright (C) 2008 Marc Schumann.
-# All Rights Reserved.
-#
-# Contributor(s): Marc Schumann &lt;wurblzap@gmail.com&gt;
-
-
-package Bugzilla::Template::Parser;
-
-use strict;
-
-use base qw(Template::Parser);
-
-sub parse {
-    my ($self, $text, @params) = @_;
-    if (Bugzilla-&gt;params-&gt;{'utf8'}) {
-        utf8::is_utf8($text) || utf8::decode($text);
-    }
-    return $self-&gt;SUPER::parse($text, @params);
-}
-
-1;
-
-__END__
-
-=head1 NAME
-
-Bugzilla::Template::Parser - Wrapper around the Template Toolkit
-C&lt;Template::Parser&gt; object
-
-=head1 DESCRIPTION
-
-This wrapper makes the Template Toolkit aware of UTF-8 templates.
-
-=head1 SUBROUTINES
-
-=over
-
-=item C&lt;parse($options)&gt;
-
-Description: Parses template text using Template::Parser::parse(),
-converting the text to UTF-8 encoding before, if necessary.
-
-Params:      C&lt;$text&gt; - Text to pass to Template::Parser::parse().
-
-Returns:     Parsed text as returned by Template::Parser::parse().
-
-=back
-
-=head1 SEE ALSO
-
-L&lt;Template&gt;
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaTemplatePluginHookpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Template/Plugin/Hook.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Template/Plugin/Hook.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Template/Plugin/Hook.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -20,93 +20,90 @@
</span><span class="cx"> # Contributor(s): Myk Melez &lt;myk@mozilla.org&gt;
</span><span class="cx"> #                 Zach Lipton &lt;zach@zachlipton.com&gt;
</span><span class="cx"> #                 Elliotte Martin &lt;everythingsolved.com&gt;
</span><del>-#
</del><ins>+#                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
</ins><span class="cx"> 
</span><span class="cx"> package Bugzilla::Template::Plugin::Hook;
</span><del>-
</del><span class="cx"> use strict;
</span><ins>+use base qw(Template::Plugin);
</ins><span class="cx"> 
</span><span class="cx"> use Bugzilla::Constants;
</span><del>-use Bugzilla::Install::Util qw(include_languages);
-use Bugzilla::Template;
</del><ins>+use Bugzilla::Install::Util qw(template_include_path); 
</ins><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> use Bugzilla::Error;
</span><ins>+
</ins><span class="cx"> use File::Spec;
</span><span class="cx"> 
</span><del>-use base qw(Template::Plugin);
-
-sub load {
-    my ($class, $context) = @_;
-    return $class;
-}
-
</del><span class="cx"> sub new {
</span><span class="cx">     my ($class, $context) = @_;
</span><span class="cx">     return bless { _CONTEXT =&gt; $context }, $class;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub _context { return $_[0]-&gt;{_CONTEXT} }
+
</ins><span class="cx"> sub process {
</span><span class="cx">     my ($self, $hook_name, $template) = @_;
</span><del>-    $template ||= $self-&gt;{_CONTEXT}-&gt;stash-&gt;{component}-&gt;{name};
</del><ins>+    my $context = $self-&gt;_context();
+    $template ||= $context-&gt;stash-&gt;{component}-&gt;{name};
</ins><span class="cx"> 
</span><del>-    my @hooks;
-
</del><span class="cx">     # sanity check:
</span><span class="cx">     if (!$template =~ /[\w\.\/\-_\\]+/) {
</span><del>-        ThrowCodeError('template_invalid', { name =&gt; $template});
</del><ins>+        ThrowCodeError('template_invalid', { name =&gt; $template });
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    # also get extension hook files that live in extensions/:
-    # parse out the parts of the template name
-    my ($vol, $subpath, $filename) = File::Spec-&gt;splitpath($template);
-    $subpath = $subpath || '';
-    $filename =~ m/(.*)\.(.*)\.tmpl/;
-    my $templatename = $1;
</del><ins>+    my (undef, $path, $filename) = File::Spec-&gt;splitpath($template);
+    $path ||= '';
+    $filename =~ m/(.+)\.(.+)\.tmpl$/;
+    my $template_name = $1;
</ins><span class="cx">     my $type = $2;
</span><del>-    # munge the filename to create the extension hook filename:
-    my $extensiontemplate = $subpath.'/'.$templatename.'-'.$hook_name.'.'.$type.'.tmpl';
-    my @extensions = glob(bz_locations()-&gt;{'extensionsdir'} . &quot;/*&quot;);
-    my @usedlanguages = include_languages({use_languages =&gt; Bugzilla-&gt;languages});
-    foreach my $extension (@extensions) {
-        next if -e &quot;$extension/disabled&quot;;
-        foreach my $language (@usedlanguages) {
-            my $file = $extension.'/template/'.$language.'/'.$extensiontemplate;
-            if (-e $file) {
-                # tt is stubborn and won't take a template file not in its
-                # include path, so we open a filehandle and give it to process()
-                # so the hook gets invoked:
-                open (my $fh, $file);
-                push(@hooks, $fh);
-            }
-        }
-    }
</del><span class="cx"> 
</span><del>-    my $paths = $self-&gt;{_CONTEXT}-&gt;{LOAD_TEMPLATES}-&gt;[0]-&gt;paths;
-    
-    # we keep this too since you can still put hook templates in 
-    # template/en/custom/hook
-    foreach my $path (@$paths) {
-        my @files = glob(&quot;$path/hook/$template/$hook_name/*.tmpl&quot;);
</del><ins>+    # Hooks are named like this:
+    my $extension_template = &quot;$path$template_name-$hook_name.$type.tmpl&quot;;
</ins><span class="cx"> 
</span><del>-        # Have to remove the templates path (INCLUDE_PATH) from the
-        # file path since the template processor auto-adds it back.
-        @files = map($_ =~ /^$path\/(.*)$/ ? $1 : {}, @files);
</del><ins>+    # Get the hooks out of the cache if they exist. Otherwise, read them
+    # from the disk.
+    my $cache = Bugzilla-&gt;request_cache-&gt;{template_plugin_hook_cache} ||= {};
+    my $lang = $context-&gt;{bz_language} || '';
+    $cache-&gt;{&quot;${lang}__$extension_template&quot;} 
+        ||= $self-&gt;_get_hooks($extension_template);
</ins><span class="cx"> 
</span><del>-        # Add found files to the list of hooks, but removing duplicates,
-        # which can happen when there are identical hooks or duplicate
-        # directories in the INCLUDE_PATH (the latter probably being a TT bug).
-        foreach my $file (@files) {
-            push(@hooks, $file) unless grep($file eq $_, @hooks);
</del><ins>+    # process() accepts an arrayref of templates, so we just pass the whole
+    # arrayref.
+    $context-&gt;{bz_in_hook} = 1; # See Bugzilla::Template::Context
+    return $context-&gt;process($cache-&gt;{&quot;${lang}__$extension_template&quot;});
+}
+
+sub _get_hooks {
+    my ($self, $extension_template) = @_;
+
+    my $template_sets = $self-&gt;_template_hook_include_path();
+    my @hooks;
+    foreach my $dir_set (@$template_sets) {
+        foreach my $template_dir (@$dir_set) {
+            my $file = &quot;$template_dir/hook/$extension_template&quot;;
+            if (-e $file) {
+                my $template = $self-&gt;_context-&gt;template($file);
+                push(@hooks, $template);
+                # Don't run the hook for more than one language.
+                last;
+            }
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    my $output;
-    foreach my $hook (@hooks) {
-        $output .= $self-&gt;{_CONTEXT}-&gt;process($hook);
-    }
-    return $output;
</del><ins>+    return \@hooks;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub _template_hook_include_path {
+    my $self = shift;
+    my $cache = Bugzilla-&gt;request_cache;
+    my $language = $self-&gt;_context-&gt;{bz_language} || '';
+    my $cache_key = &quot;template_plugin_hook_include_path_$language&quot;;
+    $cache-&gt;{$cache_key} ||= template_include_path({
+        language =&gt; $language,
+        hook     =&gt; 1,
+    });
+    return $cache-&gt;{$cache_key};
+}
+
</ins><span class="cx"> 1;
</span><span class="cx"> 
</span><span class="cx"> __END__
</span><span class="lines">@@ -165,8 +162,4 @@
</span><span class="cx"> 
</span><span class="cx"> L&lt;Template::Plugin&gt;
</span><span class="cx"> 
</span><del>-L&lt;http://www.bugzilla.org/docs/tip/html/customization.html&gt;
-
-L&lt;http://bugzilla.mozilla.org/show_bug.cgi?id=229658&gt;
-
-L&lt;http://bugzilla.mozilla.org/show_bug.cgi?id=298341&gt;
</del><ins>+L&lt;http://wiki.mozilla.org/Bugzilla:Writing_Extensions&gt;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaTemplatepm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Template.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Template.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Template.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -34,48 +34,42 @@
</span><span class="cx"> 
</span><span class="cx"> use strict;
</span><span class="cx"> 
</span><ins>+use Bugzilla::Bug;
</ins><span class="cx"> use Bugzilla::Constants;
</span><ins>+use Bugzilla::Hook;
</ins><span class="cx"> use Bugzilla::Install::Requirements;
</span><del>-use Bugzilla::Install::Util qw(install_string template_include_path include_languages);
</del><ins>+use Bugzilla::Install::Util qw(install_string template_include_path 
+                               include_languages);
+use Bugzilla::Keyword;
</ins><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> use Bugzilla::User;
</span><span class="cx"> use Bugzilla::Error;
</span><ins>+use Bugzilla::Search;
</ins><span class="cx"> use Bugzilla::Status;
</span><span class="cx"> use Bugzilla::Token;
</span><del>-use Bugzilla::Template::Parser;
</del><span class="cx"> 
</span><span class="cx"> use Cwd qw(abs_path);
</span><span class="cx"> use MIME::Base64;
</span><del>-# for time2str - replace by TT Date plugin??
</del><span class="cx"> use Date::Format ();
</span><del>-use File::Basename qw(dirname);
</del><ins>+use File::Basename qw(basename dirname);
</ins><span class="cx"> use File::Find;
</span><span class="cx"> use File::Path qw(rmtree mkpath);
</span><span class="cx"> use File::Spec;
</span><span class="cx"> use IO::Dir;
</span><ins>+use List::MoreUtils qw(firstidx);
+use Scalar::Util qw(blessed);
</ins><span class="cx"> 
</span><span class="cx"> use base qw(Template);
</span><span class="cx"> 
</span><del>-# As per the Template::Base documentation, the _init() method is being called 
-# by the new() constructor. We take advantage of this in order to plug our
-# UTF-8-aware Parser object in neatly after the original _init() method has
-# happened, in particular, after having set up the constants namespace.
-# See bug 413121 for details.
-sub _init {
-    my $self = shift;
-    my $config = $_[0];
</del><ins>+use constant FORMAT_TRIPLE =&gt; '%19s|%-28s|%-28s';
+use constant FORMAT_3_SIZE =&gt; [19,28,28];
+use constant FORMAT_DOUBLE =&gt; '%19s %-55s';
+use constant FORMAT_2_SIZE =&gt; [19,55];
</ins><span class="cx"> 
</span><del>-    $self-&gt;SUPER::_init(@_) || return undef;
-
-    $self-&gt;{PARSER} = $config-&gt;{PARSER}
-        = new Bugzilla::Template::Parser($config);
-
-    # Now we need to re-create the default Service object, making it aware
-    # of our Parser object.
-    $self-&gt;{SERVICE} = $config-&gt;{SERVICE}
-        = Template::Config-&gt;service($config);
-
-    return $self;
</del><ins>+# Pseudo-constant.
+sub SAFE_URL_REGEXP {
+    my $safe_protocols = join('|', SAFE_PROTOCOLS);
+    return qr/($safe_protocols):[^\s&lt;&gt;\&quot;]+[\w\/]/i;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> # Convert the constants in the Bugzilla::Constants module into a hash we can
</span><span class="lines">@@ -103,12 +97,11 @@
</span><span class="cx"> # settings of the user and of the available languages
</span><span class="cx"> # If no Accept-Language is present it uses the defined default
</span><span class="cx"> # Templates may also be found in the extensions/ tree
</span><del>-sub getTemplateIncludePath {
</del><ins>+sub _include_path {
+    my $lang = shift || '';
</ins><span class="cx">     my $cache = Bugzilla-&gt;request_cache;
</span><del>-    my $lang  = $cache-&gt;{'language'} || '';
-    $cache-&gt;{&quot;template_include_path_$lang&quot;} ||= template_include_path({
-        use_languages =&gt; Bugzilla-&gt;languages,
-        only_language =&gt; $lang });
</del><ins>+    $cache-&gt;{&quot;template_include_path_$lang&quot;} ||= 
+        template_include_path({ language =&gt; $lang });
</ins><span class="cx">     return $cache-&gt;{&quot;template_include_path_$lang&quot;};
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -161,7 +154,7 @@
</span><span class="cx"> # If you want to modify this routine, read the comments carefully
</span><span class="cx"> 
</span><span class="cx"> sub quoteUrls {
</span><del>-    my ($text, $curr_bugid) = (@_);
</del><ins>+    my ($text, $bug, $comment) = (@_);
</ins><span class="cx">     return $text unless $text;
</span><span class="cx"> 
</span><span class="cx">     # We use /g for speed, but uris can have other things inside them
</span><span class="lines">@@ -189,22 +182,38 @@
</span><span class="cx">     my $count = 0;
</span><span class="cx">     my $tmp;
</span><span class="cx"> 
</span><ins>+    my @hook_regexes;
+    Bugzilla::Hook::process('bug_format_comment',
+        { text =&gt; \$text, bug =&gt; $bug, regexes =&gt; \@hook_regexes,
+          comment =&gt; $comment });
+
+    foreach my $re (@hook_regexes) {
+        my ($match, $replace) = @$re{qw(match replace)};
+        if (ref($replace) eq 'CODE') {
+            $text =~ s/$match/($things[$count++] = $replace-&gt;({matches =&gt; [
+                                                               $1, $2, $3, $4,
+                                                               $5, $6, $7, $8, 
+                                                               $9, $10]}))
+                               &amp;&amp; (&quot;\0\0&quot; . ($count-1) . &quot;\0\0&quot;)/egx;
+        }
+        else {
+            $text =~ s/$match/($things[$count++] = $replace) 
+                              &amp;&amp; (&quot;\0\0&quot; . ($count-1) . &quot;\0\0&quot;)/egx;
+        }
+    }
+
</ins><span class="cx">     # Provide tooltips for full bug links (Bug 74355)
</span><span class="cx">     my $urlbase_re = '(' . join('|',
</span><span class="cx">         map { qr/$_/ } grep($_, Bugzilla-&gt;params-&gt;{'urlbase'}, 
</span><span class="cx">                             Bugzilla-&gt;params-&gt;{'sslbase'})) . ')';
</span><span class="cx">     $text =~ s~\b(${urlbase_re}\Qshow_bug.cgi?id=\E([0-9]+)(\#c([0-9]+))?)\b
</span><del>-              ~($things[$count++] = get_bug_link($3, $1, $5)) &amp;&amp;
</del><ins>+              ~($things[$count++] = get_bug_link($3, $1, { comment_num =&gt; $5 })) &amp;&amp;
</ins><span class="cx">                (&quot;\0\0&quot; . ($count-1) . &quot;\0\0&quot;)
</span><span class="cx">               ~egox;
</span><span class="cx"> 
</span><span class="cx">     # non-mailto protocols
</span><del>-    my $safe_protocols = join('|', SAFE_PROTOCOLS);
-    my $protocol_re = qr/($safe_protocols)/i;
-
-    $text =~ s~\b(${protocol_re}:  # The protocol:
-                  [^\s&lt;&gt;\&quot;]+       # Any non-whitespace
-                  [\w\/])          # so that we end in \w or /
</del><ins>+    my $safe_protocols = SAFE_URL_REGEXP();
+    $text =~ s~\b($safe_protocols)
</ins><span class="cx">               ~($tmp = html_quote($1)) &amp;&amp;
</span><span class="cx">                ($things[$count++] = &quot;&lt;a href=\&quot;$tmp\&quot;&gt;$tmp&lt;/a&gt;&quot;) &amp;&amp;
</span><span class="cx">                (&quot;\0\0&quot; . ($count-1) . &quot;\0\0&quot;)
</span><span class="lines">@@ -221,34 +230,30 @@
</span><span class="cx"> 
</span><span class="cx">     # mailto:
</span><span class="cx">     # Use |&lt;nothing&gt; so that $1 is defined regardless
</span><del>-    $text =~ s~\b(mailto:|)?([\w\.\-\+\=]+\@[\w\-]+(?:\.[\w\-]+)+)\b
</del><ins>+    # &amp;#64; is the encoded '@' character.
+    $text =~ s~\b(mailto:|)?([\w\.\-\+\=]+&amp;\#64;[\w\-]+(?:\.[\w\-]+)+)\b
</ins><span class="cx">               ~&lt;a href=\&quot;mailto:$2\&quot;&gt;$1$2&lt;/a&gt;~igx;
</span><span class="cx"> 
</span><del>-    # attachment links - handle both cases separately for simplicity
-    $text =~ s~((?:^Created\ an\ |\b)attachment\s*\(id=(\d+)\)(\s\[edit\])?)
</del><ins>+    # attachment links
+    $text =~ s~\b(attachment\s*\#?\s*(\d+)(?:\s+\[details\])?)
</ins><span class="cx">               ~($things[$count++] = get_attachment_link($2, $1)) &amp;&amp;
</span><span class="cx">                (&quot;\0\0&quot; . ($count-1) . &quot;\0\0&quot;)
</span><del>-              ~egmx;
-
-    $text =~ s~\b(attachment\s*\#?\s*(\d+))
-              ~($things[$count++] = get_attachment_link($2, $1)) &amp;&amp;
-               (&quot;\0\0&quot; . ($count-1) . &quot;\0\0&quot;)
</del><span class="cx">               ~egmxi;
</span><span class="cx"> 
</span><span class="cx">     # Current bug ID this comment belongs to
</span><del>-    my $current_bugurl = $curr_bugid ? &quot;show_bug.cgi?id=$curr_bugid&quot; : &quot;&quot;;
</del><ins>+    my $current_bugurl = $bug ? (&quot;show_bug.cgi?id=&quot; . $bug-&gt;id) : &quot;&quot;;
</ins><span class="cx"> 
</span><span class="cx">     # This handles bug a, comment b type stuff. Because we're using /g
</span><span class="cx">     # we have to do this in one pattern, and so this is semi-messy.
</span><span class="cx">     # Also, we can't use $bug_re?$comment_re? because that will match the
</span><span class="cx">     # empty string
</span><del>-    my $bug_word = get_text('term', { term =&gt; 'bug' });
</del><ins>+    my $bug_word = template_var('terms')-&gt;{bug};
</ins><span class="cx">     my $bug_re = qr/\Q$bug_word\E\s*\#?\s*(\d+)/i;
</span><span class="cx">     my $comment_re = qr/comment\s*\#?\s*(\d+)/i;
</span><span class="cx">     $text =~ s~\b($bug_re(?:\s*,?\s*$comment_re)?|$comment_re)
</span><span class="cx">               ~ # We have several choices. $1 here is the link, and $2-4 are set
</span><span class="cx">                 # depending on which part matched
</span><del>-               (defined($2) ? get_bug_link($2,$1,$3) :
</del><ins>+               (defined($2) ? get_bug_link($2, $1, { comment_num =&gt; $3 }) :
</ins><span class="cx">                               &quot;&lt;a href=\&quot;$current_bugurl#c$4\&quot;&gt;$1&lt;/a&gt;&quot;)
</span><span class="cx">               ~egox;
</span><span class="cx"> 
</span><span class="lines">@@ -260,8 +265,10 @@
</span><span class="cx">               ~get_bug_link($1, $1)
</span><span class="cx">               ~egmx;
</span><span class="cx"> 
</span><del>-    # Now remove the encoding hacks
-    $text =~ s/\0\0(\d+)\0\0/$things[$1]/eg;
</del><ins>+    # Now remove the encoding hacks in reverse order
+    for (my $i = $#things; $i &gt;= 0; $i--) {
+        $text =~ s/\0\0($i)\0\0/$things[$i]/eg;
+    }
</ins><span class="cx">     $text =~ s/$chr1\0/\0/g;
</span><span class="cx"> 
</span><span class="cx">     return $text;
</span><span class="lines">@@ -272,21 +279,15 @@
</span><span class="cx">     my ($attachid, $link_text) = @_;
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx"> 
</span><del>-    detaint_natural($attachid)
-      || die &quot;get_attachment_link() called with non-integer attachment number&quot;;
</del><ins>+    my $attachment = new Bugzilla::Attachment($attachid);
</ins><span class="cx"> 
</span><del>-    my ($bugid, $isobsolete, $desc) =
-        $dbh-&gt;selectrow_array('SELECT bug_id, isobsolete, description
-                               FROM attachments WHERE attach_id = ?',
-                               undef, $attachid);
-
-    if ($bugid) {
</del><ins>+    if ($attachment) {
</ins><span class="cx">         my $title = &quot;&quot;;
</span><span class="cx">         my $className = &quot;&quot;;
</span><del>-        if (Bugzilla-&gt;user-&gt;can_see_bug($bugid)) {
-            $title = $desc;
</del><ins>+        if (Bugzilla-&gt;user-&gt;can_see_bug($attachment-&gt;bug_id)) {
+            $title = $attachment-&gt;description;
</ins><span class="cx">         }
</span><del>-        if ($isobsolete) {
</del><ins>+        if ($attachment-&gt;isobsolete) {
</ins><span class="cx">             $className = &quot;bz_obsolete&quot;;
</span><span class="cx">         }
</span><span class="cx">         # Prevent code injection in the title.
</span><span class="lines">@@ -294,9 +295,17 @@
</span><span class="cx"> 
</span><span class="cx">         $link_text =~ s/ \[details\]$//;
</span><span class="cx">         my $linkval = &quot;attachment.cgi?id=$attachid&quot;;
</span><ins>+
+        # If the attachment is a patch, try to link to the diff rather
+        # than the text, by default.
+        my $patchlink = &quot;&quot;;
+        if ($attachment-&gt;ispatch and Bugzilla-&gt;feature('patch_viewer')) {
+            $patchlink = '&amp;amp;action=diff';
+        }
+
</ins><span class="cx">         # Whitespace matters here because these links are in &lt;pre&gt; tags.
</span><span class="cx">         return qq|&lt;span class=&quot;$className&quot;&gt;|
</span><del>-               . qq|&lt;a href=&quot;${linkval}&quot; name=&quot;attach_${attachid}&quot; title=&quot;$title&quot;&gt;$link_text&lt;/a&gt;|
</del><ins>+               . qq|&lt;a href=&quot;${linkval}${patchlink}&quot; name=&quot;attach_${attachid}&quot; title=&quot;$title&quot;&gt;$link_text&lt;/a&gt;|
</ins><span class="cx">                . qq| &lt;a href=&quot;${linkval}&amp;amp;action=edit&quot; title=&quot;$title&quot;&gt;[details]&lt;/a&gt;|
</span><span class="cx">                . qq|&lt;/span&gt;|;
</span><span class="cx">     }
</span><span class="lines">@@ -313,52 +322,174 @@
</span><span class="cx"> #    comment in the bug
</span><span class="cx"> 
</span><span class="cx"> sub get_bug_link {
</span><del>-    my ($bug_num, $link_text, $comment_num) = @_;
</del><ins>+    my ($bug, $link_text, $options) = @_;
+    $options ||= {};
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx"> 
</span><del>-    if (!defined($bug_num) || ($bug_num eq &quot;&quot;)) {
-        return &quot;&amp;lt;missing bug number&amp;gt;&quot;;
</del><ins>+    if (defined $bug) {
+        $bug = blessed($bug) ? $bug : new Bugzilla::Bug($bug);
+        return $link_text if $bug-&gt;{error};
</ins><span class="cx">     }
</span><del>-    my $quote_bug_num = html_quote($bug_num);
-    detaint_natural($bug_num) || return &quot;&amp;lt;invalid bug number: $quote_bug_num&amp;gt;&quot;;
</del><span class="cx"> 
</span><del>-    my ($bug_state, $bug_res, $bug_desc) =
-        $dbh-&gt;selectrow_array('SELECT bugs.bug_status, resolution, short_desc
-                               FROM bugs WHERE bugs.bug_id = ?',
-                               undef, $bug_num);
</del><ins>+    my $template = Bugzilla-&gt;template_inner;
+    my $linkified;
+    $template-&gt;process('bug/link.html.tmpl', 
+        { bug =&gt; $bug, link_text =&gt; $link_text, %$options }, \$linkified);
+    return $linkified;
+}
</ins><span class="cx"> 
</span><del>-    if ($bug_state) {
-        # Initialize these variables to be &quot;&quot; so that we don't get warnings
-        # if we don't change them below (which is highly likely).
-        my ($pre, $title, $post) = (&quot;&quot;, &quot;&quot;, &quot;&quot;);
</del><ins>+# We use this instead of format because format doesn't deal well with
+# multi-byte languages.
+sub multiline_sprintf {
+    my ($format, $args, $sizes) = @_;
+    my @parts;
+    my @my_sizes = @$sizes; # Copy this so we don't modify the input array.
+    foreach my $string (@$args) {
+        my $size = shift @my_sizes;
+        my @pieces = split(&quot;\n&quot;, wrap_hard($string, $size));
+        push(@parts, \@pieces);
+    }
</ins><span class="cx"> 
</span><del>-        $title = get_text('get_status', {status =&gt; $bug_state});
-        if ($bug_state eq 'UNCONFIRMED') {
-            $pre = &quot;&lt;i&gt;&quot;;
-            $post = &quot;&lt;/i&gt;&quot;;
</del><ins>+    my $formatted;
+    while (1) {
+        # Get the first item of each part.
+        my @line = map { shift @$_ } @parts;
+        # If they're all undef, we're done.
+        last if !grep { defined $_ } @line;
+        # Make any single undef item into ''
+        @line = map { defined $_ ? $_ : '' } @line;
+        # And append a formatted line
+        $formatted .= sprintf($format, @line);
+        # Remove trailing spaces, or they become lots of =20's in
+        # quoted-printable emails.
+        $formatted =~ s/\s+$//;
+        $formatted .= &quot;\n&quot;;
+    }
+    return $formatted;
+}
+
+#####################
+# Header Generation #
+#####################
+
+# Returns the last modification time of a file, as an integer number of
+# seconds since the epoch.
+sub _mtime { return (stat($_[0]))[9] }
+
+sub mtime_filter {
+    my ($file_url, $mtime) = @_;
+    # This environment var is set in the .htaccess if we have mod_headers
+    # and mod_expires installed, to make sure that JS and CSS with &quot;?&quot;
+    # after them will still be cached by clients.
+    return $file_url if !$ENV{BZ_CACHE_CONTROL};
+    if (!$mtime) {
+        my $cgi_path = bz_locations()-&gt;{'cgi_path'};
+        my $file_path = &quot;$cgi_path/$file_url&quot;;
+        $mtime = _mtime($file_path);
+    }
+    return &quot;$file_url?$mtime&quot;;
+}
+
+# Set up the skin CSS cascade:
+#
+#  1. YUI CSS
+#  2. Standard Bugzilla stylesheet set (persistent)
+#  3. Standard Bugzilla stylesheet set (selectable)
+#  4. All third-party &quot;skin&quot; stylesheet sets (selectable)
+#  5. Page-specific styles
+#  6. Custom Bugzilla stylesheet set (persistent)
+#
+# &quot;Selectable&quot; skin file sets may be either preferred or alternate.
+# Exactly one is preferred, determined by the &quot;skin&quot; user preference.
+sub css_files {
+    my ($style_urls, $yui, $yui_css) = @_;
+    
+    # global.css goes on every page, and so does IE-fixes.css.
+    my @requested_css = ('skins/standard/global.css', @$style_urls,
+                         'skins/standard/IE-fixes.css');
+
+    my @yui_required_css;
+    foreach my $yui_name (@$yui) {
+        next if !$yui_css-&gt;{$yui_name};
+        push(@yui_required_css, &quot;js/yui/assets/skins/sam/$yui_name.css&quot;);
+    }
+    unshift(@requested_css, @yui_required_css);
+    
+    my @css_sets = map { _css_link_set($_) } @requested_css;
+    
+    my %by_type = (standard =&gt; [], alternate =&gt; {}, skin =&gt; [], custom =&gt; []);
+    foreach my $set (@css_sets) {
+        foreach my $key (keys %$set) {
+            if ($key eq 'alternate') {
+                foreach my $alternate_skin (keys %{ $set-&gt;{alternate} }) {
+                    my $files = $by_type{alternate}-&gt;{$alternate_skin} ||= [];
+                    push(@$files, $set-&gt;{alternate}-&gt;{$alternate_skin});
+                }
+            }
+            else {
+                push(@{ $by_type{$key} }, $set-&gt;{$key});
+            }
</ins><span class="cx">         }
</span><del>-        elsif (!is_open_state($bug_state)) {
-            $pre = '&lt;span class=&quot;bz_closed&quot;&gt;';
-            $title .= ' ' . get_text('get_resolution', {resolution =&gt; $bug_res});
-            $post = '&lt;/span&gt;';
-        }
-        if (Bugzilla-&gt;user-&gt;can_see_bug($bug_num)) {
-            $title .= &quot; - $bug_desc&quot;;
-        }
-        # Prevent code injection in the title.
-        $title = html_quote(clean_text($title));
</del><ins>+    }
+    
+    return \%by_type;
+}
</ins><span class="cx"> 
</span><del>-        my $linkval = &quot;show_bug.cgi?id=$bug_num&quot;;
-        if (defined $comment_num) {
-            $linkval .= &quot;#c$comment_num&quot;;
</del><ins>+sub _css_link_set {
+    my ($file_name) = @_;
+
+    my %set = (standard =&gt; mtime_filter($file_name));
+    
+    # We use (^|/) to allow Extensions to use the skins system if they
+    # want.
+    if ($file_name !~ m{(^|/)skins/standard/}) {
+        return \%set;
+    }
+    
+    my $skin_user_prefs = Bugzilla-&gt;user-&gt;settings-&gt;{skin};
+    my $cgi_path = bz_locations()-&gt;{'cgi_path'};
+    # If the DB is not accessible, user settings are not available.
+    my $all_skins = $skin_user_prefs ? $skin_user_prefs-&gt;legal_values : [];
+    my %skin_urls;
+    foreach my $option (@$all_skins) {
+        next if $option eq 'standard';
+        my $skin_file_name = $file_name;
+        $skin_file_name =~ s{(^|/)skins/standard/}{skins/contrib/$option/};
+        if (my $mtime = _mtime(&quot;$cgi_path/$skin_file_name&quot;)) {
+            $skin_urls{$option} = mtime_filter($skin_file_name, $mtime);
</ins><span class="cx">         }
</span><del>-        return qq{$pre&lt;a href=&quot;$linkval&quot; title=&quot;$title&quot;&gt;$link_text&lt;/a&gt;$post};
</del><span class="cx">     }
</span><del>-    else {
-        return qq{$link_text};
</del><ins>+    $set{alternate} = \%skin_urls;
+    
+    my $skin = $skin_user_prefs-&gt;{'value'};
+    if ($skin ne 'standard' and defined $set{alternate}-&gt;{$skin}) {
+        $set{skin} = delete $set{alternate}-&gt;{$skin};
</ins><span class="cx">     }
</span><ins>+    
+    my $custom_file_name = $file_name;
+    $custom_file_name =~ s{(^|/)skins/standard/}{skins/custom/};
+    if (my $custom_mtime = _mtime(&quot;$cgi_path/$custom_file_name&quot;)) {
+        $set{custom} = mtime_filter($custom_file_name, $custom_mtime);
+    }
+    
+    return \%set;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# YUI dependency resolution
+sub yui_resolve_deps {
+    my ($yui, $yui_deps) = @_;
+    
+    my @yui_resolved;
+    foreach my $yui_name (@$yui) {
+        my $deps = $yui_deps-&gt;{$yui_name} || [];
+        foreach my $dep (reverse @$deps) {
+            push(@yui_resolved, $dep) if !grep { $_ eq $dep } @yui_resolved;
+        }
+        push(@yui_resolved, $yui_name) if !grep { $_ eq $yui_name } @yui_resolved;
+    }
+    return \@yui_resolved;
+}
+
</ins><span class="cx"> ###############################################################################
</span><span class="cx"> # Templatization Code
</span><span class="cx"> 
</span><span class="lines">@@ -372,20 +503,31 @@
</span><span class="cx"> # to template variables.
</span><span class="cx"> use Template::Stash;
</span><span class="cx"> 
</span><ins>+# Allow keys to start with an underscore or a dot.
+$Template::Stash::PRIVATE = undef;
+
</ins><span class="cx"> # Add &quot;contains***&quot; methods to list variables that search for one or more 
</span><span class="cx"> # items in a list and return boolean values representing whether or not 
</span><span class="cx"> # one/all/any item(s) were found.
</span><span class="cx"> $Template::Stash::LIST_OPS-&gt;{ contains } =
</span><span class="cx">   sub {
</span><span class="cx">       my ($list, $item) = @_;
</span><del>-      return grep($_ eq $item, @$list);
</del><ins>+      if (ref $item &amp;&amp; $item-&gt;isa('Bugzilla::Object')) {
+          return grep($_-&gt;id == $item-&gt;id, @$list);
+      } else {
+          return grep($_ eq $item, @$list);
+      }
</ins><span class="cx">   };
</span><span class="cx"> 
</span><span class="cx"> $Template::Stash::LIST_OPS-&gt;{ containsany } =
</span><span class="cx">   sub {
</span><span class="cx">       my ($list, $items) = @_;
</span><span class="cx">       foreach my $item (@$items) { 
</span><del>-          return 1 if grep($_ eq $item, @$list);
</del><ins>+          if (ref $item &amp;&amp; $item-&gt;isa('Bugzilla::Object')) {
+              return 1 if grep($_-&gt;id == $item-&gt;id, @$list);
+          } else {
+              return 1 if grep($_ eq $item, @$list);
+          }
</ins><span class="cx">       }
</span><span class="cx">       return 0;
</span><span class="cx">   };
</span><span class="lines">@@ -404,14 +546,6 @@
</span><span class="cx">       return $_[0];
</span><span class="cx">   };
</span><span class="cx"> 
</span><del>-# Add a &quot;substr&quot; method to the Template Toolkit's &quot;scalar&quot; object
-# that returns a substring of a string.
-$Template::Stash::SCALAR_OPS-&gt;{ substr } = 
-  sub {
-      my ($scalar, $offset, $length) = @_;
-      return substr($scalar, $offset, $length);
-  };
-
</del><span class="cx"> # Add a &quot;truncate&quot; method to the Template Toolkit's &quot;scalar&quot; object
</span><span class="cx"> # that truncates a string to a certain length.
</span><span class="cx"> $Template::Stash::SCALAR_OPS-&gt;{ truncate } = 
</span><span class="lines">@@ -431,6 +565,17 @@
</span><span class="cx"> 
</span><span class="cx"> ###############################################################################
</span><span class="cx"> 
</span><ins>+sub process {
+    my $self = shift;
+    # All of this current_langs stuff allows template_inner to correctly
+    # determine what-language Template object it should instantiate.
+    my $current_langs = Bugzilla-&gt;request_cache-&gt;{template_current_lang} ||= [];
+    unshift(@$current_langs, $self-&gt;context-&gt;{bz_language});
+    my $retval = $self-&gt;SUPER::process(@_);
+    shift @$current_langs;
+    return $retval;
+}
+
</ins><span class="cx"> # Construct the Template object
</span><span class="cx"> 
</span><span class="cx"> # Note that all of the failure cases here can't use templateable errors,
</span><span class="lines">@@ -440,19 +585,13 @@
</span><span class="cx">     my $class = shift;
</span><span class="cx">     my %opts = @_;
</span><span class="cx"> 
</span><del>-    # checksetup.pl will call us once for any template/lang directory.
-    # We need a possibility to reset the cache, so that no files from
-    # the previous language pollute the action.
-    if ($opts{'clean_cache'}) {
-        delete Bugzilla-&gt;request_cache-&gt;{template_include_path_};
-    }
</del><ins>+    # IMPORTANT - If you make any FILTER changes here, make sure to
+    # make them in t/004.template.t also, if required.
</ins><span class="cx"> 
</span><del>-    # IMPORTANT - If you make any configuration changes here, make sure to
-    # make them in t/004.template.t and checksetup.pl.
-
-    return $class-&gt;new({
</del><ins>+    my $config = {
</ins><span class="cx">         # Colon-separated list of directories containing templates.
</span><del>-        INCLUDE_PATH =&gt; [\&amp;getTemplateIncludePath],
</del><ins>+        INCLUDE_PATH =&gt; $opts{'include_path'} 
+                        || _include_path($opts{'language'}),
</ins><span class="cx"> 
</span><span class="cx">         # Remove white-space before template directives (PRE_CHOMP) and at the
</span><span class="cx">         # beginning and end of templates and template blocks (TRIM) for better
</span><span class="lines">@@ -461,11 +600,21 @@
</span><span class="cx">         PRE_CHOMP =&gt; 1,
</span><span class="cx">         TRIM =&gt; 1,
</span><span class="cx"> 
</span><del>-        COMPILE_DIR =&gt; bz_locations()-&gt;{'datadir'} . &quot;/template&quot;,
</del><ins>+        # Bugzilla::Template::Plugin::Hook uses the absolute (in mod_perl)
+        # or relative (in mod_cgi) paths of hook files to explicitly compile
+        # a specific file. Also, these paths may be absolute at any time
+        # if a packager has modified bz_locations() to contain absolute
+        # paths.
+        ABSOLUTE =&gt; 1,
+        RELATIVE =&gt; $ENV{MOD_PERL} ? 0 : 1,
</ins><span class="cx"> 
</span><ins>+        COMPILE_DIR =&gt; bz_locations()-&gt;{'template_cache'},
+
</ins><span class="cx">         # Initialize templates (f.e. by loading plugins like Hook).
</span><del>-        PRE_PROCESS =&gt; &quot;global/initialize.none.tmpl&quot;,
</del><ins>+        PRE_PROCESS =&gt; [&quot;global/initialize.none.tmpl&quot;],
</ins><span class="cx"> 
</span><ins>+        ENCODING =&gt; Bugzilla-&gt;params-&gt;{'utf8'} ? 'UTF-8' : undef,
+
</ins><span class="cx">         # Functions for processing text within templates in various ways.
</span><span class="cx">         # IMPORTANT!  When adding a filter here that does not override a
</span><span class="cx">         # built-in filter, please also add a stub filter to t/004template.t.
</span><span class="lines">@@ -508,6 +657,8 @@
</span><span class="cx">                 $var =~ s/\n/\\n/g;
</span><span class="cx">                 $var =~ s/\r/\\r/g;
</span><span class="cx">                 $var =~ s/\@/\\x40/g; # anti-spam for email addresses
</span><ins>+                $var =~ s/&lt;/\\x3c/g;
+                $var =~ s/&gt;/\\x3e/g;
</ins><span class="cx">                 return $var;
</span><span class="cx">             },
</span><span class="cx">             
</span><span class="lines">@@ -523,6 +674,7 @@
</span><span class="cx">             # See bugs 4928, 22983 and 32000 for more details
</span><span class="cx">             html_linebreak =&gt; sub {
</span><span class="cx">                 my ($var) = @_;
</span><ins>+                $var = html_quote($var);
</ins><span class="cx">                 $var =~ s/\r\n/\&amp;#013;/g;
</span><span class="cx">                 $var =~ s/\n\r/\&amp;#013;/g;
</span><span class="cx">                 $var =~ s/\r/\&amp;#013;/g;
</span><span class="lines">@@ -540,31 +692,28 @@
</span><span class="cx"> 
</span><span class="cx">             xml =&gt; \&amp;Bugzilla::Util::xml_quote ,
</span><span class="cx"> 
</span><del>-            # This filter escapes characters in a variable or value string for
-            # use in a query string.  It escapes all characters NOT in the
-            # regex set: [a-zA-Z0-9_\-.].  The 'uri' filter should be used for
-            # a full URL that may have characters that need encoding.
-            url_quote =&gt; \&amp;Bugzilla::Util::url_quote ,
-
</del><span class="cx">             # This filter is similar to url_quote but used a \ instead of a %
</span><span class="cx">             # as prefix. In addition it replaces a ' ' by a '_'.
</span><span class="cx">             css_class_quote =&gt; \&amp;Bugzilla::Util::css_class_quote ,
</span><span class="cx"> 
</span><ins>+            # Removes control characters and trims extra whitespace.
+            clean_text =&gt; \&amp;Bugzilla::Util::clean_text ,
+
</ins><span class="cx">             quoteUrls =&gt; [ sub {
</span><del>-                               my ($context, $bug) = @_;
</del><ins>+                               my ($context, $bug, $comment) = @_;
</ins><span class="cx">                                return sub {
</span><span class="cx">                                    my $text = shift;
</span><del>-                                   return quoteUrls($text, $bug);
</del><ins>+                                   return quoteUrls($text, $bug, $comment);
</ins><span class="cx">                                };
</span><span class="cx">                            },
</span><span class="cx">                            1
</span><span class="cx">                          ],
</span><span class="cx"> 
</span><span class="cx">             bug_link =&gt; [ sub {
</span><del>-                              my ($context, $bug) = @_;
</del><ins>+                              my ($context, $bug, $options) = @_;
</ins><span class="cx">                               return sub {
</span><span class="cx">                                   my $text = shift;
</span><del>-                                  return get_bug_link($bug, $text);
</del><ins>+                                  return get_bug_link($bug, $text, $options);
</ins><span class="cx">                               };
</span><span class="cx">                           },
</span><span class="cx">                           1
</span><span class="lines">@@ -613,44 +762,24 @@
</span><span class="cx">             },
</span><span class="cx"> 
</span><span class="cx">             # Format a time for display (more info in Bugzilla::Util)
</span><del>-            time =&gt; \&amp;Bugzilla::Util::format_time,
</del><ins>+            time =&gt; [ sub {
+                          my ($context, $format, $timezone) = @_;
+                          return sub {
+                              my $time = shift;
+                              return format_time($time, $format, $timezone);
+                          };
+                      },
+                      1
+                    ],
</ins><span class="cx"> 
</span><del>-            # Bug 120030: Override html filter to obscure the '@' in user
-            #             visible strings.
-            # Bug 319331: Handle BiDi disruptions.
-            html =&gt; sub {
-                my ($var) = Template::Filters::html_filter(@_);
-                # Obscure '@'.
-                $var =~ s/\@/\&amp;#64;/g;
-                if (Bugzilla-&gt;params-&gt;{'utf8'}) {
-                    # Remove the following characters because they're
-                    # influencing BiDi:
-                    # --------------------------------------------------------
-                    # |Code  |Name                      |UTF-8 representation|
-                    # |------|--------------------------|--------------------|
-                    # |U+202a|Left-To-Right Embedding   |0xe2 0x80 0xaa      |
-                    # |U+202b|Right-To-Left Embedding   |0xe2 0x80 0xab      |
-                    # |U+202c|Pop Directional Formatting|0xe2 0x80 0xac      |
-                    # |U+202d|Left-To-Right Override    |0xe2 0x80 0xad      |
-                    # |U+202e|Right-To-Left Override    |0xe2 0x80 0xae      |
-                    # --------------------------------------------------------
-                    #
-                    # The following are characters influencing BiDi, too, but
-                    # they can be spared from filtering because they don't
-                    # influence more than one character right or left:
-                    # --------------------------------------------------------
-                    # |Code  |Name                      |UTF-8 representation|
-                    # |------|--------------------------|--------------------|
-                    # |U+200e|Left-To-Right Mark        |0xe2 0x80 0x8e      |
-                    # |U+200f|Right-To-Left Mark        |0xe2 0x80 0x8f      |
-                    # --------------------------------------------------------
-                    $var =~ s/[\x{202a}-\x{202e}]//g;
-                }
-                return $var;
-            },
</del><ins>+            html =&gt; \&amp;Bugzilla::Util::html_quote,
</ins><span class="cx"> 
</span><span class="cx">             html_light =&gt; \&amp;Bugzilla::Util::html_light_quote,
</span><span class="cx"> 
</span><ins>+            email =&gt; \&amp;Bugzilla::Util::email_filter,
+            
+            mtime =&gt; \&amp;mtime_filter,
+
</ins><span class="cx">             # iCalendar contentline filter
</span><span class="cx">             ics =&gt; [ sub {
</span><span class="cx">                          my ($context, @args) = @_;
</span><span class="lines">@@ -689,6 +818,20 @@
</span><span class="cx">                 $var =~ s/\&amp;gt;/&gt;/g;
</span><span class="cx">                 $var =~ s/\&amp;quot;/\&quot;/g;
</span><span class="cx">                 $var =~ s/\&amp;amp;/\&amp;/g;
</span><ins>+                # Now remove extra whitespace...
+                my $collapse_filter = $Template::Filters::FILTERS-&gt;{collapse};
+                $var = $collapse_filter-&gt;($var);
+                # And if we're not in the WebService, wrap the message.
+                # (Wrapping the message in the WebService is unnecessary
+                # and causes awkward things like \n's appearing in error
+                # messages in JSON-RPC.)
+                unless (Bugzilla-&gt;usage_mode == USAGE_MODE_JSON
+                        or Bugzilla-&gt;usage_mode == USAGE_MODE_XMLRPC)
+                {
+                    $var = wrap_comment($var, 72);
+                }
+                $var =~ s/\&amp;nbsp;/ /g;
+
</ins><span class="cx">                 return $var;
</span><span class="cx">             },
</span><span class="cx"> 
</span><span class="lines">@@ -717,24 +860,36 @@
</span><span class="cx">             # Function to create date strings
</span><span class="cx">             'time2str' =&gt; \&amp;Date::Format::time2str,
</span><span class="cx"> 
</span><ins>+            # Fixed size column formatting for bugmail.
+            'format_columns' =&gt; sub {
+                my $cols = shift;
+                my $format = ($cols == 3) ? FORMAT_TRIPLE : FORMAT_DOUBLE;
+                my $col_size = ($cols == 3) ? FORMAT_3_SIZE : FORMAT_2_SIZE;
+                return multiline_sprintf($format, \@_, $col_size);
+            },
+
</ins><span class="cx">             # Generic linear search function
</span><del>-            'lsearch' =&gt; \&amp;Bugzilla::Util::lsearch,
</del><ins>+            'lsearch' =&gt; sub {
+                my ($array, $item) = @_;
+                return firstidx { $_ eq $item } @$array;
+            },
</ins><span class="cx"> 
</span><span class="cx">             # Currently logged in user, if any
</span><span class="cx">             # If an sudo session is in progress, this is the user we're faking
</span><span class="cx">             'user' =&gt; sub { return Bugzilla-&gt;user; },
</span><ins>+           
+            # Currenly active language
+            # XXX Eventually this should probably be replaced with something
+            # like Bugzilla-&gt;language.
+            'current_language' =&gt; sub {
+                my ($language) = include_languages();
+                return $language;
+            },
</ins><span class="cx"> 
</span><span class="cx">             # If an sudo session is in progress, this is the user who
</span><span class="cx">             # started the session.
</span><span class="cx">             'sudoer' =&gt; sub { return Bugzilla-&gt;sudoer; },
</span><span class="cx"> 
</span><del>-            # SendBugMail - sends mail about a bug, using Bugzilla::BugMail.pm
-            'SendBugMail' =&gt; sub {
-                my ($id, $mailrecipients) = (@_);
-                require Bugzilla::BugMail;
-                Bugzilla::BugMail::Send($id, $mailrecipients);
-            },
-
</del><span class="cx">             # Allow templates to access the &quot;corect&quot; URLBase value
</span><span class="cx">             'urlbase' =&gt; sub { return Bugzilla::Util::correct_urlbase(); },
</span><span class="cx"> 
</span><span class="lines">@@ -746,78 +901,136 @@
</span><span class="cx">                 return $docs_urlbase;
</span><span class="cx">             },
</span><span class="cx"> 
</span><ins>+            # Check whether the URL is safe.
+            'is_safe_url' =&gt; sub {
+                my $url = shift;
+                return 0 unless $url;
+
+                my $safe_url_regexp = SAFE_URL_REGEXP();
+                return 1 if $url =~ /^$safe_url_regexp$/;
+                # Pointing to a local file with no colon in its name is fine.
+                return 1 if $url =~ /^[^\s&lt;&gt;\&quot;:]+[\w\/]$/i;
+                # If we come here, then we cannot guarantee it's safe.
+                return 0;
+            },
+
</ins><span class="cx">             # Allow templates to generate a token themselves.
</span><span class="cx">             'issue_hash_token' =&gt; \&amp;Bugzilla::Token::issue_hash_token,
</span><span class="cx"> 
</span><ins>+            # A way for all templates to get at Field data, cached.
+            'bug_fields' =&gt; sub {
+                my $cache = Bugzilla-&gt;request_cache;
+                $cache-&gt;{template_bug_fields} ||=
+                    Bugzilla-&gt;fields({ by_name =&gt; 1 });
+                return $cache-&gt;{template_bug_fields};
+            },
+            
+            'css_files' =&gt; \&amp;css_files,
+            yui_resolve_deps =&gt; \&amp;yui_resolve_deps,
+
+            # Whether or not keywords are enabled, in this Bugzilla.
+            'use_keywords' =&gt; sub { return Bugzilla::Keyword-&gt;any_exist; },
+
+            # All the keywords.
+            'all_keywords' =&gt; sub { return Bugzilla::Keyword-&gt;get_all(); },
+
+            'feature_enabled' =&gt; sub { return Bugzilla-&gt;feature(@_); },
+
+            # field_descs can be somewhat slow to generate, so we generate
+            # it only once per-language no matter how many times
+            # $template-&gt;process() is called.
+            'field_descs' =&gt; sub { return template_var('field_descs') },
+
+            # Calling bug/field-help.none.tmpl once per label is very
+            # expensive, so we generate it once per-language.
+            'help_html' =&gt; sub { return template_var('help_html') },
+
+            # This way we don't have to load field-descs.none.tmpl in
+            # many templates.
+            'display_value' =&gt; \&amp;Bugzilla::Util::display_value,
+
+            'install_string' =&gt; \&amp;Bugzilla::Install::Util::install_string,
+
+            'report_columns' =&gt; \&amp;Bugzilla::Search::REPORT_COLUMNS,
+
</ins><span class="cx">             # These don't work as normal constants.
</span><span class="cx">             DB_MODULE        =&gt; \&amp;Bugzilla::Constants::DB_MODULE,
</span><span class="cx">             REQUIRED_MODULES =&gt; 
</span><span class="cx">                 \&amp;Bugzilla::Install::Requirements::REQUIRED_MODULES,
</span><span class="cx">             OPTIONAL_MODULES =&gt; sub {
</span><span class="cx">                 my @optional = @{OPTIONAL_MODULES()};
</span><del>-                @optional    = sort {$a-&gt;{feature} cmp $b-&gt;{feature}} 
-                                    @optional;
</del><ins>+                foreach my $item (@optional) {
+                    my @features;
+                    foreach my $feat_id (@{ $item-&gt;{feature} }) {
+                        push(@features, install_string(&quot;feature_$feat_id&quot;));
+                    }
+                    $item-&gt;{feature} = \@features;
+                }
</ins><span class="cx">                 return \@optional;
</span><span class="cx">             },
</span><ins>+            'default_authorizer' =&gt; new Bugzilla::Auth(),
</ins><span class="cx">         },
</span><ins>+    };
</ins><span class="cx"> 
</span><del>-   }) || die(&quot;Template creation failed: &quot; . $class-&gt;error());
</del><ins>+    local $Template::Config::CONTEXT = 'Bugzilla::Template::Context';
+
+    Bugzilla::Hook::process('template_before_create', { config =&gt; $config });
+    my $template = $class-&gt;new($config) 
+        || die(&quot;Template creation failed: &quot; . $class-&gt;error());
+
+    # Pass on our current language to any template hooks or inner templates
+    # called by this Template object.
+    $template-&gt;context-&gt;{bz_language} = $opts{language} || '';
+
+    return $template;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> # Used as part of the two subroutines below.
</span><del>-our (%_templates_to_precompile, $_current_path);
-
</del><ins>+our %_templates_to_precompile;
</ins><span class="cx"> sub precompile_templates {
</span><span class="cx">     my ($output) = @_;
</span><span class="cx"> 
</span><span class="cx">     # Remove the compiled templates.
</span><ins>+    my $cache_dir = bz_locations()-&gt;{'template_cache'};
</ins><span class="cx">     my $datadir = bz_locations()-&gt;{'datadir'};
</span><del>-    if (-e &quot;$datadir/template&quot;) {
</del><ins>+    if (-e $cache_dir) {
</ins><span class="cx">         print install_string('template_removing_dir') . &quot;\n&quot; if $output;
</span><span class="cx"> 
</span><del>-        # XXX This frequently fails if the webserver made the files, because
-        # then the webserver owns the directories. We could fix that by
-        # doing a chmod/chown on all the directories here.
-        rmtree(&quot;$datadir/template&quot;);
</del><ins>+        # This frequently fails if the webserver made the files, because
+        # then the webserver owns the directories.
+        rmtree($cache_dir);
</ins><span class="cx"> 
</span><del>-        # Check that the directory was really removed
-        if(-e &quot;$datadir/template&quot;) {
-            print &quot;\n\n&quot;;
-            print &quot;The directory '$datadir/template' could not be removed.\n&quot;;
-            print &quot;Please remove it manually and rerun checksetup.pl.\n\n&quot;;
-            exit;
</del><ins>+        # Check that the directory was really removed, and if not, move it
+        # into data/deleteme/.
+        if (-e $cache_dir) {
+            my $deleteme = &quot;$datadir/deleteme&quot;;
+            
+            print STDERR &quot;\n\n&quot;,
+                install_string('template_removal_failed', 
+                               { deleteme =&gt; $deleteme, 
+                                 template_cache =&gt; $cache_dir }), &quot;\n\n&quot;;
+            mkpath($deleteme);
+            my $random = generate_random_password();
+            rename($cache_dir, &quot;$deleteme/$random&quot;)
+              or die &quot;move failed: $!&quot;;
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     print install_string('template_precompile') if $output;
</span><span class="cx"> 
</span><del>-    my $templatedir = bz_locations()-&gt;{'templatedir'};
-    # Don't hang on templates which use the CGI library
-    eval(&quot;use CGI qw(-no_debug)&quot;);
-    
-    my $dir_reader    = new IO::Dir($templatedir) || die &quot;$templatedir: $!&quot;;
-    my @language_dirs = grep { /^[a-z-]+$/i } $dir_reader-&gt;read;
-    $dir_reader-&gt;close;
</del><ins>+    # Pre-compile all available languages.
+    my $paths = template_include_path({ language =&gt; Bugzilla-&gt;languages });
</ins><span class="cx"> 
</span><del>-    foreach my $dir (@language_dirs) {
-        next if ($dir eq 'CVS');
-        -d &quot;$templatedir/$dir/default&quot; || -d &quot;$templatedir/$dir/custom&quot; 
-            || next;
-        local $ENV{'HTTP_ACCEPT_LANGUAGE'} = $dir;
-        my $template = Bugzilla::Template-&gt;create(clean_cache =&gt; 1);
</del><ins>+    foreach my $dir (@$paths) {
+        my $template = Bugzilla::Template-&gt;create(include_path =&gt; [$dir]);
</ins><span class="cx"> 
</span><del>-        # Precompile all the templates found in all the directories.
</del><span class="cx">         %_templates_to_precompile = ();
</span><del>-        foreach my $subdir (qw(custom extension default), bz_locations()-&gt;{'project'}) {
-            next unless $subdir; # If 'project' is empty.
-            $_current_path = File::Spec-&gt;catdir($templatedir, $dir, $subdir);
-            next unless -d $_current_path;
-            # Traverse the template hierarchy.
-            find({ wanted =&gt; \&amp;_precompile_push, no_chdir =&gt; 1 }, $_current_path);
-        }
</del><ins>+        # Traverse the template hierarchy.
+        find({ wanted =&gt; \&amp;_precompile_push, no_chdir =&gt; 1 }, $dir);
</ins><span class="cx">         # The sort isn't totally necessary, but it makes debugging easier
</span><span class="cx">         # by making the templates always be compiled in the same order.
</span><span class="cx">         foreach my $file (sort keys %_templates_to_precompile) {
</span><ins>+            $file =~ s{^\Q$dir\E/}{};
</ins><span class="cx">             # Compile the template but throw away the result. This has the side-
</span><span class="cx">             # effect of writing the compiled version to disk.
</span><span class="cx">             $template-&gt;context-&gt;template($file);
</span><span class="lines">@@ -827,28 +1040,17 @@
</span><span class="cx">     # Under mod_perl, we look for templates using the absolute path of the
</span><span class="cx">     # template directory, which causes Template Toolkit to look for their 
</span><span class="cx">     # *compiled* versions using the full absolute path under the data/template
</span><del>-    # directory. (Like data/template/var/www/html/mod_perl/.) To avoid
</del><ins>+    # directory. (Like data/template/var/www/html/bugzilla/.) To avoid
</ins><span class="cx">     # re-compiling templates under mod_perl, we symlink to the
</span><span class="cx">     # already-compiled templates. This doesn't work on Windows.
</span><span class="cx">     if (!ON_WINDOWS) {
</span><del>-        my $abs_root = dirname(abs_path($templatedir));
-        my $todir    = &quot;$datadir/template$abs_root&quot;;
-        mkpath($todir);
-        # We use abs2rel so that the symlink will look like 
-        # &quot;../../../../template&quot; which works, while just 
-        # &quot;data/template/template/&quot; doesn't work.
-        my $fromdir = File::Spec-&gt;abs2rel(&quot;$datadir/template/template&quot;, $todir);
-        # We eval for systems that can't symlink at all, where &quot;symlink&quot; 
-        # throws a fatal error.
-        eval { symlink($fromdir, &quot;$todir/template&quot;) 
-                   or warn &quot;Failed to symlink from $fromdir to $todir: $!&quot; };
</del><ins>+        # We do these separately in case they're in different locations.
+        _do_template_symlink(bz_locations()-&gt;{'templatedir'});
+        _do_template_symlink(bz_locations()-&gt;{'extensionsdir'});
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # If anything created a Template object before now, clear it out.
</span><span class="cx">     delete Bugzilla-&gt;request_cache-&gt;{template};
</span><del>-    # This is the single variable used to precompile templates,
-    # which needs to be cleared as well.
-    delete Bugzilla-&gt;request_cache-&gt;{template_include_path_};
</del><span class="cx"> 
</span><span class="cx">     print install_string('done') . &quot;\n&quot; if $output;
</span><span class="cx"> }
</span><span class="lines">@@ -859,11 +1061,40 @@
</span><span class="cx">     return if (-d $name);
</span><span class="cx">     return if ($name =~ /\/CVS\//);
</span><span class="cx">     return if ($name !~ /\.tmpl$/);
</span><del>-   
-    $name =~ s/\Q$_current_path\E\///;
</del><span class="cx">     $_templates_to_precompile{$name} = 1;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# Helper for precompile_templates
+sub _do_template_symlink {
+    my $dir_to_symlink = shift;
+
+    my $abs_path = abs_path($dir_to_symlink);
+
+    # If $dir_to_symlink is already an absolute path (as might happen
+    # with packagers who set $libpath to an absolute path), then we don't
+    # need to do this symlink.
+    return if ($abs_path eq $dir_to_symlink);
+
+    my $abs_root  = dirname($abs_path);
+    my $dir_name  = basename($abs_path);
+    my $cache_dir   = bz_locations()-&gt;{'template_cache'};
+    my $container = &quot;$cache_dir$abs_root&quot;;
+    mkpath($container);
+    my $target = &quot;$cache_dir/$dir_name&quot;;
+    # Check if the directory exists, because if there are no extensions,
+    # there won't be an &quot;data/template/extensions&quot; directory to link to.
+    if (-d $target) {
+        # We use abs2rel so that the symlink will look like 
+        # &quot;../../../../template&quot; which works, while just 
+        # &quot;data/template/template/&quot; doesn't work.
+        my $relative_target = File::Spec-&gt;abs2rel($target, $container);
+
+        my $link_name = &quot;$container/$dir_name&quot;;
+        symlink($relative_target, $link_name)
+          or warn &quot;Could not make $link_name a symlink to $relative_target: $!&quot;;
+    }
+}
+
</ins><span class="cx"> 1;
</span><span class="cx"> 
</span><span class="cx"> __END__
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaTokenpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Token.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Token.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Token.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -63,20 +63,21 @@
</span><span class="cx">     # But to prevent using this way to mailbomb an email address, make sure
</span><span class="cx">     # the last request is at least 10 minutes old before sending a new email.
</span><span class="cx"> 
</span><del>-    my $pending_requests =
-        $dbh-&gt;selectrow_array('SELECT COUNT(*)
-                                 FROM tokens
-                                WHERE tokentype = ?
-                                  AND ' . $dbh-&gt;sql_istrcmp('eventdata', '?') . '
-                                  AND issuedate &gt; NOW() - ' . $dbh-&gt;sql_interval(10, 'MINUTE'),
-                               undef, ('account', $login_name));
</del><ins>+    my $pending_requests = $dbh-&gt;selectrow_array(
+        'SELECT COUNT(*)
+           FROM tokens
+          WHERE tokentype = ?
+                AND ' . $dbh-&gt;sql_istrcmp('eventdata', '?') . '
+                AND issuedate &gt; '
+                    . $dbh-&gt;sql_date_math('NOW()', '-', 10, 'MINUTE'),
+        undef, ('account', $login_name));
</ins><span class="cx"> 
</span><span class="cx">     ThrowUserError('too_soon_for_new_token', {'type' =&gt; 'account'}) if $pending_requests;
</span><span class="cx"> 
</span><span class="cx">     my ($token, $token_ts) = _create_token(undef, 'account', $login_name);
</span><span class="cx"> 
</span><span class="cx">     $vars-&gt;{'email'} = $login_name . Bugzilla-&gt;params-&gt;{'emailsuffix'};
</span><del>-    $vars-&gt;{'token_ts'} = $token_ts;
</del><ins>+    $vars-&gt;{'expiration_ts'} = ctime($token_ts + MAX_TOKEN_AGE * 86400);
</ins><span class="cx">     $vars-&gt;{'token'} = $token;
</span><span class="cx"> 
</span><span class="cx">     my $message;
</span><span class="lines">@@ -91,8 +92,9 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub IssueEmailChangeToken {
</span><del>-    my ($user, $old_email, $new_email) = @_;
</del><ins>+    my ($user, $new_email) = @_;
</ins><span class="cx">     my $email_suffix = Bugzilla-&gt;params-&gt;{'emailsuffix'};
</span><ins>+    my $old_email = $user-&gt;login;
</ins><span class="cx"> 
</span><span class="cx">     my ($token, $token_ts) = _create_token($user-&gt;id, 'emailold', $old_email . &quot;:&quot; . $new_email);
</span><span class="cx"> 
</span><span class="lines">@@ -100,15 +102,12 @@
</span><span class="cx"> 
</span><span class="cx">     # Mail the user the token along with instructions for using it.
</span><span class="cx"> 
</span><del>-    my $template = Bugzilla-&gt;template_inner($user-&gt;settings-&gt;{'lang'}-&gt;{'value'});
</del><ins>+    my $template = Bugzilla-&gt;template_inner($user-&gt;setting('lang'));
</ins><span class="cx">     my $vars = {};
</span><span class="cx"> 
</span><span class="cx">     $vars-&gt;{'oldemailaddress'} = $old_email . $email_suffix;
</span><span class="cx">     $vars-&gt;{'newemailaddress'} = $new_email . $email_suffix;
</span><del>-    
-    $vars-&gt;{'max_token_age'} = MAX_TOKEN_AGE;
-    $vars-&gt;{'token_ts'} = $token_ts;
-
</del><ins>+    $vars-&gt;{'expiration_ts'} = ctime($token_ts + MAX_TOKEN_AGE * 86400);
</ins><span class="cx">     $vars-&gt;{'token'} = $token;
</span><span class="cx">     $vars-&gt;{'emailaddress'} = $old_email . $email_suffix;
</span><span class="cx"> 
</span><span class="lines">@@ -125,7 +124,6 @@
</span><span class="cx">     $template-&gt;process(&quot;account/email/change-new.txt.tmpl&quot;, $vars, \$message)
</span><span class="cx">       || ThrowTemplateError($template-&gt;error());
</span><span class="cx"> 
</span><del>-    Bugzilla-&gt;template_inner(&quot;&quot;);
</del><span class="cx">     MessageToMTA($message);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -135,33 +133,33 @@
</span><span class="cx">     my $user = shift;
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx"> 
</span><del>-    my $too_soon =
-        $dbh-&gt;selectrow_array('SELECT 1 FROM tokens
-                                WHERE userid = ?
-                                  AND tokentype = ?
-                                  AND issuedate &gt; NOW() - ' .
-                                      $dbh-&gt;sql_interval(10, 'MINUTE'),
-                                undef, ($user-&gt;id, 'password'));
</del><ins>+    my $too_soon = $dbh-&gt;selectrow_array(
+        'SELECT 1 FROM tokens
+          WHERE userid = ? AND tokentype = ?
+                AND issuedate &gt; ' 
+                    . $dbh-&gt;sql_date_math('NOW()', '-', 10, 'MINUTE'),
+        undef, ($user-&gt;id, 'password'));
</ins><span class="cx"> 
</span><span class="cx">     ThrowUserError('too_soon_for_new_token', {'type' =&gt; 'password'}) if $too_soon;
</span><span class="cx"> 
</span><del>-    my ($token, $token_ts) = _create_token($user-&gt;id, 'password', $::ENV{'REMOTE_ADDR'});
</del><ins>+    my ($token, $token_ts) = _create_token($user-&gt;id, 'password', remote_ip());
</ins><span class="cx"> 
</span><span class="cx">     # Mail the user the token along with instructions for using it.
</span><del>-    my $template = Bugzilla-&gt;template_inner($user-&gt;settings-&gt;{'lang'}-&gt;{'value'});
</del><ins>+    my $template = Bugzilla-&gt;template_inner($user-&gt;setting('lang'));
</ins><span class="cx">     my $vars = {};
</span><span class="cx"> 
</span><span class="cx">     $vars-&gt;{'token'} = $token;
</span><span class="cx">     $vars-&gt;{'emailaddress'} = $user-&gt;email;
</span><del>-    $vars-&gt;{'max_token_age'} = MAX_TOKEN_AGE;
-    $vars-&gt;{'token_ts'} = $token_ts;
</del><ins>+    $vars-&gt;{'expiration_ts'} = ctime($token_ts + MAX_TOKEN_AGE * 86400);
+    # The user is not logged in (else he wouldn't request a new password).
+    # So we have to pass this information to the template.
+    $vars-&gt;{'timezone'} = $user-&gt;timezone;
</ins><span class="cx"> 
</span><span class="cx">     my $message = &quot;&quot;;
</span><span class="cx">     $template-&gt;process(&quot;account/password/forgotten-password.txt.tmpl&quot;, 
</span><span class="cx">                                                                $vars, \$message)
</span><span class="cx">       || ThrowTemplateError($template-&gt;error());
</span><span class="cx"> 
</span><del>-    Bugzilla-&gt;template_inner(&quot;&quot;);
</del><span class="cx">     MessageToMTA($message);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -178,9 +176,14 @@
</span><span class="cx">     $data ||= [];
</span><span class="cx">     $time ||= time();
</span><span class="cx"> 
</span><ins>+    # For the user ID, use the actual ID if the user is logged in.
+    # Otherwise, use the remote IP, in case this is for something
+    # such as creating an account or logging in.
+    my $user_id = Bugzilla-&gt;user-&gt;id || remote_ip();
+
</ins><span class="cx">     # The concatenated string is of the form
</span><del>-    # token creation time + site-wide secret + user ID + data
-    my @args = ($time, Bugzilla-&gt;localconfig-&gt;{'site_wide_secret'}, Bugzilla-&gt;user-&gt;id, @$data);
</del><ins>+    # token creation time + site-wide secret + user ID (either ID or remote IP) + data
+    my @args = ($time, Bugzilla-&gt;localconfig-&gt;{'site_wide_secret'}, $user_id, @$data);
</ins><span class="cx"> 
</span><span class="cx">     my $token = join('*', @args);
</span><span class="cx">     # Wide characters cause md5_hex() to die.
</span><span class="lines">@@ -248,7 +251,7 @@
</span><span class="cx">     $column ||= &quot;token&quot;;
</span><span class="cx"> 
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><del>-    my $sth = $dbh-&gt;prepare(&quot;SELECT userid FROM $table WHERE $column = ?&quot;);
</del><ins>+    my $sth = $dbh-&gt;prepare(&quot;SELECT 1 FROM $table WHERE $column = ?&quot;);
</ins><span class="cx"> 
</span><span class="cx">     while ($duplicate) {
</span><span class="cx">         ++$tries;
</span><span class="lines">@@ -284,21 +287,23 @@
</span><span class="cx">     my $user = new Bugzilla::User($userid);
</span><span class="cx"> 
</span><span class="cx">     $vars-&gt;{'emailaddress'} = $userid ? $user-&gt;email : $eventdata;
</span><del>-    $vars-&gt;{'remoteaddress'} = $::ENV{'REMOTE_ADDR'};
</del><ins>+    $vars-&gt;{'remoteaddress'} = remote_ip();
</ins><span class="cx">     $vars-&gt;{'token'} = $token;
</span><span class="cx">     $vars-&gt;{'tokentype'} = $tokentype;
</span><span class="cx">     $vars-&gt;{'issuedate'} = $issuedate;
</span><ins>+    # The user is probably not logged in.
+    # So we have to pass this information to the template.
+    $vars-&gt;{'timezone'} = $user-&gt;timezone;
</ins><span class="cx">     $vars-&gt;{'eventdata'} = $eventdata;
</span><span class="cx">     $vars-&gt;{'cancelaction'} = $cancelaction;
</span><span class="cx"> 
</span><span class="cx">     # Notify the user via email about the cancellation.
</span><del>-    my $template = Bugzilla-&gt;template_inner($user-&gt;settings-&gt;{'lang'}-&gt;{'value'});
</del><ins>+    my $template = Bugzilla-&gt;template_inner($user-&gt;setting('lang'));
</ins><span class="cx"> 
</span><span class="cx">     my $message;
</span><span class="cx">     $template-&gt;process(&quot;account/cancel-token.txt.tmpl&quot;, $vars, \$message)
</span><span class="cx">       || ThrowTemplateError($template-&gt;error());
</span><span class="cx"> 
</span><del>-    Bugzilla-&gt;template_inner(&quot;&quot;);
</del><span class="cx">     MessageToMTA($message);
</span><span class="cx"> 
</span><span class="cx">     # Delete the token from the database.
</span><span class="lines">@@ -448,7 +453,7 @@
</span><span class="cx">     use Bugzilla::Token;
</span><span class="cx"> 
</span><span class="cx">     Bugzilla::Token::issue_new_user_account_token($login_name);
</span><del>-    Bugzilla::Token::IssueEmailChangeToken($user, $old_email, $new_email);
</del><ins>+    Bugzilla::Token::IssueEmailChangeToken($user, $new_email);
</ins><span class="cx">     Bugzilla::Token::IssuePasswordToken($user);
</span><span class="cx">     Bugzilla::Token::DeletePasswordTokens($user_id, $reason);
</span><span class="cx">     Bugzilla::Token::Cancel($token, $cancelaction, $vars);
</span><span class="lines">@@ -479,7 +484,7 @@
</span><span class="cx">  Returns:     Nothing. It throws an error if the same user made the same
</span><span class="cx">               request in the last few minutes.
</span><span class="cx"> 
</span><del>-=item C&lt;sub IssueEmailChangeToken($user, $old_email, $new_email)&gt;
</del><ins>+=item C&lt;sub IssueEmailChangeToken($user, $new_email)&gt;
</ins><span class="cx"> 
</span><span class="cx">  Description: Sends two distinct tokens per email to the old and new email
</span><span class="cx">               addresses to confirm the email address change for the given
</span><span class="lines">@@ -487,7 +492,6 @@
</span><span class="cx"> 
</span><span class="cx">  Params:      $user      - User object of the user requesting a new
</span><span class="cx">                            email address.
</span><del>-              $old_email - The current (old) email address of the user.
</del><span class="cx">               $new_email - The new email address of the user.
</span><span class="cx"> 
</span><span class="cx">  Returns:     Nothing.
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaUpdatepm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Update.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Update.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Update.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -20,45 +20,33 @@
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla::Constants;
</span><span class="cx"> 
</span><del>-use constant REMOTE_FILE   =&gt; 'http://updates.bugzilla.org/bugzilla-update.xml';
-use constant LOCAL_FILE    =&gt; &quot;/bugzilla-update.xml&quot;; # Relative to datadir.
</del><span class="cx"> use constant TIME_INTERVAL =&gt; 86400; # Default is one day, in seconds.
</span><span class="cx"> use constant TIMEOUT       =&gt; 5; # Number of seconds before timeout.
</span><span class="cx"> 
</span><span class="cx"> # Look for new releases and notify logged in administrators about them.
</span><span class="cx"> sub get_notifications {
</span><ins>+    return if !Bugzilla-&gt;feature('updates');
</ins><span class="cx">     return if (Bugzilla-&gt;params-&gt;{'upgrade_notification'} eq 'disabled');
</span><span class="cx"> 
</span><del>-    # If the XML::Twig module is missing, we won't be able to parse
-    # the XML file. So there is no need to go further.
-    eval(&quot;require XML::Twig&quot;);
-    return if $@;
-
-    my $local_file = bz_locations()-&gt;{'datadir'} . LOCAL_FILE;
</del><ins>+    my $local_file = bz_locations()-&gt;{'datadir'} . '/' . LOCAL_FILE;
</ins><span class="cx">     # Update the local XML file if this one doesn't exist or if
</span><span class="cx">     # the last modification time (stat[9]) is older than TIME_INTERVAL.
</span><span class="cx">     if (!-e $local_file || (time() - (stat($local_file))[9] &gt; TIME_INTERVAL)) {
</span><del>-        # Are we sure we didn't try to refresh this file already
-        # but we failed because we cannot modify its timestamp?
-        my $can_alter = (-e $local_file) ? utime(undef, undef, $local_file) : 1;
-        if ($can_alter) {
-            unlink $local_file; # Make sure the old copy is away.
-            my $error = _synchronize_data();
-            # If an error is returned, leave now.
-            return $error if $error;
-        }
-        else {
-            return {'error' =&gt; 'no_update', 'xml_file' =&gt; $local_file};
-        }
</del><ins>+        unlink $local_file; # Make sure the old copy is away.
+        return { 'error' =&gt; 'no_update' } if (-e $local_file);
+
+        my $error = _synchronize_data();
+        # If an error is returned, leave now.
+        return $error if $error;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # If we cannot access the local XML file, ignore it.
</span><del>-    return {'error' =&gt; 'no_access', 'xml_file' =&gt; $local_file} unless (-r $local_file);
</del><ins>+    return { 'error' =&gt; 'no_access' } unless (-r $local_file);
</ins><span class="cx"> 
</span><span class="cx">     my $twig = XML::Twig-&gt;new();
</span><span class="cx">     $twig-&gt;safe_parsefile($local_file);
</span><span class="cx">     # If the XML file is invalid, return.
</span><del>-    return {'error' =&gt; 'corrupted', 'xml_file' =&gt; $local_file} if $@;
</del><ins>+    return { 'error' =&gt; 'corrupted' } if $@;
</ins><span class="cx">     my $root = $twig-&gt;root;
</span><span class="cx"> 
</span><span class="cx">     my @releases;
</span><span class="lines">@@ -128,11 +116,8 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub _synchronize_data {
</span><del>-    eval(&quot;require LWP::UserAgent&quot;);
-    return {'error' =&gt; 'missing_package', 'package' =&gt; 'LWP::UserAgent'} if $@;
</del><ins>+    my $local_file = bz_locations()-&gt;{'datadir'} . '/' . LOCAL_FILE;
</ins><span class="cx"> 
</span><del>-    my $local_file = bz_locations()-&gt;{'datadir'} . LOCAL_FILE;
-
</del><span class="cx">     my $ua = LWP::UserAgent-&gt;new();
</span><span class="cx">     $ua-&gt;timeout(TIMEOUT);
</span><span class="cx">     $ua-&gt;protocols_allowed(['http', 'https']);
</span><span class="lines">@@ -145,7 +130,7 @@
</span><span class="cx">     else {
</span><span class="cx">         $ua-&gt;env_proxy;
</span><span class="cx">     }
</span><del>-    $ua-&gt;mirror(REMOTE_FILE, $local_file);
</del><ins>+    my $response = eval { $ua-&gt;mirror(REMOTE_FILE, $local_file) };
</ins><span class="cx"> 
</span><span class="cx">     # $ua-&gt;mirror() forces the modification time of the local XML file
</span><span class="cx">     # to match the modification time of the remote one.
</span><span class="lines">@@ -156,12 +141,15 @@
</span><span class="cx">         # Try to alter its last modification time.
</span><span class="cx">         my $can_alter = utime(undef, undef, $local_file);
</span><span class="cx">         # This error should never happen.
</span><del>-        $can_alter || return {'error' =&gt; 'no_update', 'xml_file' =&gt; $local_file};
</del><ins>+        $can_alter || return { 'error' =&gt; 'no_update' };
</ins><span class="cx">     }
</span><del>-    else {
</del><ins>+    elsif ($response &amp;&amp; $response-&gt;is_error) {
</ins><span class="cx">         # We have been unable to download the file.
</span><del>-        return {'error' =&gt; 'cannot_download', 'xml_file' =&gt; $local_file};
</del><ins>+        return { 'error' =&gt; 'cannot_download', 'reason' =&gt; $response-&gt;status_line };
</ins><span class="cx">     }
</span><ins>+    else {
+        return { 'error' =&gt; 'no_write', 'reason' =&gt; $@ };
+    }
</ins><span class="cx"> 
</span><span class="cx">     # Everything went well.
</span><span class="cx">     return 0;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaUserSettingTimezonepm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/User/Setting/Timezone.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/User/Setting/Timezone.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/User/Setting/Timezone.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,72 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Frédéric Buclin.
+# Portions created by Frédéric Buclin are Copyright (c) 2008 Frédéric Buclin.
+# All rights reserved.
+#
+# Contributor(s): Frédéric Buclin &lt;LpSolit@gmail.com&gt;
+
+package Bugzilla::User::Setting::Timezone;
+
+use strict;
+
+use DateTime::TimeZone;
+
+use base qw(Bugzilla::User::Setting);
+
+use Bugzilla::Constants;
+
+sub legal_values {
+    my ($self) = @_;
+
+    return $self-&gt;{'legal_values'} if defined $self-&gt;{'legal_values'};
+
+    my @timezones = DateTime::TimeZone-&gt;all_names;
+    # Remove old formats, such as CST6CDT, EST, EST5EDT.
+    @timezones = grep { $_ =~ m#.+/.+#} @timezones;
+    # Append 'local' to the list, which will use the timezone
+    # given by the server.
+    push(@timezones, 'local');
+    push(@timezones, 'UTC');
+
+    return $self-&gt;{'legal_values'} = \@timezones;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::User::Setting::Timezone - Object for a user preference setting for desired timezone
+
+=head1 DESCRIPTION
+
+Timezone.pm extends Bugzilla::User::Setting and implements a class specialized for
+setting the desired timezone.
+
+=head1 METHODS
+
+=over
+
+=item C&lt;legal_values()&gt;
+
+Description: Returns all legal timezones
+
+Params:      none
+
+Returns:     A reference to an array containing the names of all legal timezones
+
+=back
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaUserSettingpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/User/Setting.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/User/Setting.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/User/Setting.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -125,7 +125,8 @@
</span><span class="cx"> ###############################
</span><span class="cx"> 
</span><span class="cx"> sub add_setting {
</span><del>-    my ($name, $values, $default_value, $subclass, $force_check) = @_;
</del><ins>+    my ($name, $values, $default_value, $subclass, $force_check,
+        $silently) = @_;
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx"> 
</span><span class="cx">     my $exists = _setting_exists($name);
</span><span class="lines">@@ -146,7 +147,7 @@
</span><span class="cx">                       undef, $name);
</span><span class="cx">         }
</span><span class="cx">     }
</span><del>-    else {
</del><ins>+    elsif (!$silently) {
</ins><span class="cx">         print get_text('install_setting_new', { name =&gt; $name }) . &quot;\n&quot;;
</span><span class="cx">     }
</span><span class="cx">     $dbh-&gt;do(q{INSERT INTO setting (name, default_value, is_enabled, subclass)
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaUserpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/User.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/User.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/User.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -44,11 +44,20 @@
</span><span class="cx"> use Bugzilla::Error;
</span><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> use Bugzilla::Constants;
</span><ins>+use Bugzilla::Search::Recent;
</ins><span class="cx"> use Bugzilla::User::Setting;
</span><span class="cx"> use Bugzilla::Product;
</span><span class="cx"> use Bugzilla::Classification;
</span><span class="cx"> use Bugzilla::Field;
</span><ins>+use Bugzilla::Group;
</ins><span class="cx"> 
</span><ins>+use DateTime::TimeZone;
+use List::Util qw(max);
+use Scalar::Util qw(blessed);
+use Storable qw(dclone);
+use URI;
+use URI::QueryParam;
+
</ins><span class="cx"> use base qw(Bugzilla::Object Exporter);
</span><span class="cx"> @Bugzilla::User::EXPORT = qw(is_available_username
</span><span class="cx">     login_to_id user_id_to_login validate_password
</span><span class="lines">@@ -73,6 +82,7 @@
</span><span class="cx">     'showmybugslink' =&gt; 0,
</span><span class="cx">     'disabledtext'   =&gt; '',
</span><span class="cx">     'disable_mail'   =&gt; 0,
</span><ins>+    'is_enabled'     =&gt; 1, 
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> use constant DB_TABLE =&gt; 'profiles';
</span><span class="lines">@@ -88,19 +98,21 @@
</span><span class="cx">     'profiles.mybugslink AS showmybugslink',
</span><span class="cx">     'profiles.disabledtext',
</span><span class="cx">     'profiles.disable_mail',
</span><ins>+    'profiles.extern_id',
+    'profiles.is_enabled', 
</ins><span class="cx"> );
</span><span class="cx"> use constant NAME_FIELD =&gt; 'login_name';
</span><span class="cx"> use constant ID_FIELD   =&gt; 'userid';
</span><span class="cx"> use constant LIST_ORDER =&gt; NAME_FIELD;
</span><span class="cx"> 
</span><del>-use constant REQUIRED_CREATE_FIELDS =&gt; qw(login_name cryptpassword);
-
</del><span class="cx"> use constant VALIDATORS =&gt; {
</span><span class="cx">     cryptpassword =&gt; \&amp;_check_password,
</span><span class="cx">     disable_mail  =&gt; \&amp;_check_disable_mail,
</span><span class="cx">     disabledtext  =&gt; \&amp;_check_disabledtext,
</span><span class="cx">     login_name    =&gt; \&amp;check_login_name_for_creation,
</span><span class="cx">     realname      =&gt; \&amp;_check_realname,
</span><ins>+    extern_id     =&gt; \&amp;_check_extern_id,
+    is_enabled    =&gt; \&amp;_check_is_enabled, 
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> sub UPDATE_COLUMNS {
</span><span class="lines">@@ -110,11 +122,19 @@
</span><span class="cx">         disabledtext
</span><span class="cx">         login_name
</span><span class="cx">         realname
</span><ins>+        extern_id
+        is_enabled
</ins><span class="cx">     );
</span><span class="cx">     push(@cols, 'cryptpassword') if exists $self-&gt;{cryptpassword};
</span><span class="cx">     return @cols;
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+use constant VALIDATOR_DEPENDENCIES =&gt; {
+    is_enabled =&gt; ['disabledtext'], 
+};
+
+use constant EXTRA_REQUIRED_FIELDS =&gt; qw(is_enabled);
+
</ins><span class="cx"> ################################################################################
</span><span class="cx"> # Functions
</span><span class="cx"> ################################################################################
</span><span class="lines">@@ -128,9 +148,27 @@
</span><span class="cx">     bless ($user, $class);
</span><span class="cx">     return $user unless $param;
</span><span class="cx"> 
</span><ins>+    if (ref($param) eq 'HASH') {
+        if (defined $param-&gt;{extern_id}) {
+            $param = { condition =&gt; 'extern_id = ?' , values =&gt; [$param-&gt;{extern_id}] };
+            $_[0] = $param;
+        }
+    }
</ins><span class="cx">     return $class-&gt;SUPER::new(@_);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub super_user {
+    my $invocant = shift;
+    my $class = ref($invocant) || $invocant;
+    my ($param) = @_;
+
+    my $user = dclone(DEFAULT_USER);
+    $user-&gt;{groups} = [Bugzilla::Group-&gt;get_all];
+    $user-&gt;{bless_groups} = [Bugzilla::Group-&gt;get_all];
+    bless $user, $class;
+    return $user;
+}
+
</ins><span class="cx"> sub update {
</span><span class="cx">     my $self = shift;
</span><span class="cx">     my $changes = $self-&gt;SUPER::update(@_);
</span><span class="lines">@@ -150,7 +188,7 @@
</span><span class="cx"> 
</span><span class="cx">     # XXX Can update profiles_activity here as soon as it understands
</span><span class="cx">     #     field names like login_name.
</span><del>-
</del><ins>+    
</ins><span class="cx">     return $changes;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -161,6 +199,22 @@
</span><span class="cx"> sub _check_disable_mail { return $_[1] ? 1 : 0; }
</span><span class="cx"> sub _check_disabledtext { return trim($_[1]) || ''; }
</span><span class="cx"> 
</span><ins>+# Check whether the extern_id is unique.
+sub _check_extern_id {
+    my ($invocant, $extern_id) = @_;
+    $extern_id = trim($extern_id);
+    return undef unless defined($extern_id) &amp;&amp; $extern_id ne &quot;&quot;;
+    if (!ref($invocant) || $invocant-&gt;extern_id ne $extern_id) {
+        my $existing_login = $invocant-&gt;new({ extern_id =&gt; $extern_id });
+        if ($existing_login) {
+            ThrowUserError( 'extern_id_exists',
+                            { extern_id =&gt; $extern_id,
+                              existing_login_name =&gt; $existing_login-&gt;login });
+        }
+    }
+    return $extern_id;
+}
+
</ins><span class="cx"> # This is public since createaccount.cgi needs to use it before issuing
</span><span class="cx"> # a token for account creation.
</span><span class="cx"> sub check_login_name_for_creation {
</span><span class="lines">@@ -194,12 +248,22 @@
</span><span class="cx"> 
</span><span class="cx"> sub _check_realname { return trim($_[1]) || ''; }
</span><span class="cx"> 
</span><ins>+sub _check_is_enabled {
+    my ($invocant, $is_enabled, undef, $params) = @_;
+    # is_enabled is set automatically on creation depending on whether 
+    # disabledtext is empty (enabled) or not empty (disabled).
+    # When updating the user, is_enabled is set by calling set_disabledtext().
+    # Any value passed into this validator is ignored.
+    my $disabledtext = ref($invocant) ? $invocant-&gt;disabledtext : $params-&gt;{disabledtext};
+    return $disabledtext ? 0 : 1;
+}
+
</ins><span class="cx"> ################################################################################
</span><span class="cx"> # Mutators
</span><span class="cx"> ################################################################################
</span><span class="cx"> 
</span><del>-sub set_disabledtext { $_[0]-&gt;set('disabledtext', $_[1]); }
</del><span class="cx"> sub set_disable_mail { $_[0]-&gt;set('disable_mail', $_[1]); }
</span><ins>+sub set_extern_id    { $_[0]-&gt;set('extern_id', $_[1]); }
</ins><span class="cx"> 
</span><span class="cx"> sub set_login {
</span><span class="cx">     my ($self, $login) = @_;
</span><span class="lines">@@ -216,6 +280,10 @@
</span><span class="cx"> 
</span><span class="cx"> sub set_password { $_[0]-&gt;set('cryptpassword', $_[1]); }
</span><span class="cx"> 
</span><ins>+sub set_disabledtext {
+    $_[0]-&gt;set('disabledtext', $_[1]);
+    $_[0]-&gt;set('is_enabled', $_[1] ? 0 : 1);
+}
</ins><span class="cx"> 
</span><span class="cx"> ################################################################################
</span><span class="cx"> # Methods
</span><span class="lines">@@ -224,12 +292,22 @@
</span><span class="cx"> # Accessors for user attributes
</span><span class="cx"> sub name  { $_[0]-&gt;{realname};   }
</span><span class="cx"> sub login { $_[0]-&gt;{login_name}; }
</span><ins>+sub extern_id { $_[0]-&gt;{extern_id}; }
</ins><span class="cx"> sub email { $_[0]-&gt;login . Bugzilla-&gt;params-&gt;{'emailsuffix'}; }
</span><span class="cx"> sub disabledtext { $_[0]-&gt;{'disabledtext'}; }
</span><del>-sub is_disabled { $_[0]-&gt;disabledtext ? 1 : 0; }
</del><ins>+sub is_enabled { $_[0]-&gt;{'is_enabled'} ? 1 : 0; }
</ins><span class="cx"> sub showmybugslink { $_[0]-&gt;{showmybugslink}; }
</span><span class="cx"> sub email_disabled { $_[0]-&gt;{disable_mail}; }
</span><span class="cx"> sub email_enabled { !($_[0]-&gt;{disable_mail}); }
</span><ins>+sub cryptpassword {
+    my $self = shift;
+    # We don't store it because we never want it in the object (we
+    # don't want to accidentally dump even the hash somewhere).
+    my ($pw) = Bugzilla-&gt;dbh-&gt;selectrow_array(
+        'SELECT cryptpassword FROM profiles WHERE userid = ?',
+        undef, $self-&gt;id);
+    return $pw;
+}
</ins><span class="cx"> 
</span><span class="cx"> sub set_authorizer {
</span><span class="cx">     my ($self, $authorizer) = @_;
</span><span class="lines">@@ -308,7 +386,7 @@
</span><span class="cx">                 ON ngm.namedquery_id = lif.namedquery_id
</span><span class="cx">           WHERE lif.user_id = ? 
</span><span class="cx">                 AND lif.namedquery_id NOT IN ($query_id_string)
</span><del>-                AND ngm.group_id IN (&quot; . $self-&gt;groups_as_string . &quot;)&quot;,
</del><ins>+                AND &quot; . $self-&gt;groups_in_sql,
</ins><span class="cx">           undef, $self-&gt;id);
</span><span class="cx">     require Bugzilla::Search::Saved;
</span><span class="cx">     $self-&gt;{queries_subscribed} =
</span><span class="lines">@@ -327,7 +405,7 @@
</span><span class="cx"> 
</span><span class="cx">     my $avail_query_ids = Bugzilla-&gt;dbh-&gt;selectcol_arrayref(
</span><span class="cx">         'SELECT namedquery_id FROM namedquery_group_map
</span><del>-          WHERE group_id IN (' . $self-&gt;groups_as_string . &quot;)
</del><ins>+          WHERE '  . $self-&gt;groups_in_sql . &quot;
</ins><span class="cx">                 AND namedquery_id NOT IN ($query_id_string)&quot;);
</span><span class="cx">     require Bugzilla::Search::Saved;
</span><span class="cx">     $self-&gt;{queries_available} =
</span><span class="lines">@@ -335,6 +413,168 @@
</span><span class="cx">     return $self-&gt;{queries_available};
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub tags {
+    my $self = shift;
+    my $dbh = Bugzilla-&gt;dbh;
+
+    if (!defined $self-&gt;{tags}) {
+        # We must use LEFT JOIN instead of INNER JOIN as we may be
+        # in the process of inserting a new tag to some bugs,
+        # in which case there are no bugs with this tag yet.
+        $self-&gt;{tags} = $dbh-&gt;selectall_hashref(
+            'SELECT name, id, COUNT(bug_id) AS bug_count
+               FROM tag
+          LEFT JOIN bug_tag ON bug_tag.tag_id = tag.id
+              WHERE user_id = ? ' . $dbh-&gt;sql_group_by('id', 'name'),
+            'name', undef, $self-&gt;id);
+    }
+    return $self-&gt;{tags};
+}
+
+##########################
+# Saved Recent Bug Lists #
+##########################
+
+sub recent_searches {
+    my $self = shift;
+    $self-&gt;{recent_searches} ||= 
+        Bugzilla::Search::Recent-&gt;match({ user_id =&gt; $self-&gt;id });
+    return $self-&gt;{recent_searches};
+}
+
+sub recent_search_containing {
+    my ($self, $bug_id) = @_;
+    my $searches = $self-&gt;recent_searches;
+
+    foreach my $search (@$searches) {
+        return $search if grep($_ == $bug_id, @{ $search-&gt;bug_list });
+    }
+
+    return undef;
+}
+
+sub recent_search_for {
+    my ($self, $bug) = @_;
+    my $params = Bugzilla-&gt;input_params;
+    my $cgi = Bugzilla-&gt;cgi;
+
+    if ($self-&gt;id) {
+        # First see if there's a list_id parameter in the query string.
+        my $list_id = $params-&gt;{list_id};
+        if (!$list_id) {
+            # If not, check for &quot;list_id&quot; in the query string of the referer.
+            my $referer = $cgi-&gt;referer;
+            if ($referer) {
+                my $uri = URI-&gt;new($referer);
+                if ($uri-&gt;path =~ /buglist\.cgi$/) {
+                    $list_id = $uri-&gt;query_param('list_id')
+                               || $uri-&gt;query_param('regetlastlist');
+                }
+            }
+        }
+
+        if ($list_id &amp;&amp; $list_id ne 'cookie') {
+            # If we got a bad list_id (either some other user's or an expired
+            # one) don't crash, just don't return that list.
+            my $search = Bugzilla::Search::Recent-&gt;check_quietly(
+                { id =&gt; $list_id });
+            return $search if $search;
+        }
+
+        # If there's no list_id, see if the current bug's id is contained
+        # in any of the user's saved lists.
+        my $search = $self-&gt;recent_search_containing($bug-&gt;id);
+        return $search if $search;
+    }
+
+    # Finally (or always, if we're logged out), if there's a BUGLIST cookie
+    # and the selected bug is in the list, then return the cookie as a fake
+    # Search::Recent object.
+    if (my $list = $cgi-&gt;cookie('BUGLIST')) {
+        # Also split on colons, which was used as a separator in old cookies.
+        my @bug_ids = split(/[:-]/, $list);
+        if (grep { $_ == $bug-&gt;id } @bug_ids) {
+            my $search = Bugzilla::Search::Recent-&gt;new_from_cookie(\@bug_ids);
+            return $search;
+        }
+    }
+
+    return undef;
+}
+
+sub save_last_search {
+    my ($self, $params) = @_;
+    my ($bug_ids, $order, $vars, $list_id) = 
+        @$params{qw(bugs order vars list_id)};
+
+    my $cgi = Bugzilla-&gt;cgi;
+    if ($order) {
+        $cgi-&gt;send_cookie(-name =&gt; 'LASTORDER',
+                          -value =&gt; $order,
+                          -expires =&gt; 'Fri, 01-Jan-2038 00:00:00 GMT');
+    }
+
+    return if !@$bug_ids;
+
+    my $search;
+    if ($self-&gt;id) {
+        on_main_db {
+            if ($list_id) {
+                $search = Bugzilla::Search::Recent-&gt;check_quietly({ id =&gt; $list_id });
+            }
+
+            if ($search) {
+                if (join(',', @{$search-&gt;bug_list}) ne join(',', @$bug_ids)) {
+                    $search-&gt;set_bug_list($bug_ids);
+                }
+                if (!$search-&gt;list_order || $order ne $search-&gt;list_order) {
+                    $search-&gt;set_list_order($order);
+                }
+                $search-&gt;update();
+            }
+            else {
+                # If we already have an existing search with a totally
+                # identical bug list, then don't create a new one. This
+                # prevents people from writing over their whole 
+                # recent-search list by just refreshing a saved search
+                # (which doesn't have list_id in the header) over and over.
+                my $list_string = join(',', @$bug_ids);
+                my $existing_search = Bugzilla::Search::Recent-&gt;match({
+                    user_id =&gt; $self-&gt;id, bug_list =&gt; $list_string });
+           
+                if (!scalar(@$existing_search)) {
+                    $search = Bugzilla::Search::Recent-&gt;create({
+                        user_id    =&gt; $self-&gt;id,
+                        bug_list   =&gt; $bug_ids,
+                        list_order =&gt; $order });
+                }
+                else {
+                    $search = $existing_search-&gt;[0];
+                }
+            }
+        };
+        delete $self-&gt;{recent_searches};
+    }
+    # Logged-out users use a cookie to store a single last search. We don't
+    # override that cookie with the logged-in user's latest search, because
+    # if they did one search while logged out and another while logged in,
+    # they may still want to navigate through the search they made while
+    # logged out.
+    else {
+        my $bug_list = join('-', @$bug_ids);
+        if (length($bug_list) &lt; 4000) {
+            $cgi-&gt;send_cookie(-name =&gt; 'BUGLIST',
+                              -value =&gt; $bug_list,
+                              -expires =&gt; 'Fri, 01-Jan-2038 00:00:00 GMT');
+        }
+        else {
+            $cgi-&gt;remove_cookie('BUGLIST');
+            $vars-&gt;{'toolong'} = 1;
+        }
+    }
+    return $search;
+}
+
</ins><span class="cx"> sub settings {
</span><span class="cx">     my ($self) = @_;
</span><span class="cx"> 
</span><span class="lines">@@ -352,6 +592,27 @@
</span><span class="cx">     return $self-&gt;{'settings'};
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub setting {
+    my ($self, $name) = @_;
+    return $self-&gt;settings-&gt;{$name}-&gt;{'value'};
+}
+
+sub timezone {
+    my $self = shift;
+
+    if (!defined $self-&gt;{timezone}) {
+        my $tz = $self-&gt;setting('timezone');
+        if ($tz eq 'local') {
+            # The user wants the local timezone of the server.
+            $self-&gt;{timezone} = Bugzilla-&gt;local_timezone;
+        }
+        else {
+            $self-&gt;{timezone} = DateTime::TimeZone-&gt;new(name =&gt; $tz);
+        }
+    }
+    return $self-&gt;{timezone};
+}
+
</ins><span class="cx"> sub flush_queries_cache {
</span><span class="cx">     my $self = shift;
</span><span class="cx"> 
</span><span class="lines">@@ -364,131 +625,128 @@
</span><span class="cx">     my $self = shift;
</span><span class="cx"> 
</span><span class="cx">     return $self-&gt;{groups} if defined $self-&gt;{groups};
</span><del>-    return {} unless $self-&gt;id;
</del><ins>+    return [] unless $self-&gt;id;
</ins><span class="cx"> 
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><del>-    my $groups = $dbh-&gt;selectcol_arrayref(q{SELECT DISTINCT groups.name, group_id
-                                              FROM groups, user_group_map
-                                             WHERE groups.id=user_group_map.group_id
-                                               AND user_id=?
-                                               AND isbless=0},
-                                          { Columns=&gt;[1,2] },
-                                          $self-&gt;id);
</del><ins>+    my $groups_to_check = $dbh-&gt;selectcol_arrayref(
+        q{SELECT DISTINCT group_id
+            FROM user_group_map
+           WHERE user_id = ? AND isbless = 0}, undef, $self-&gt;id);
</ins><span class="cx"> 
</span><del>-    # The above gives us an arrayref [name, id, name, id, ...]
-    # Convert that into a hashref
-    my %groups = @$groups;
-    my @groupidstocheck = values(%groups);
-    my %groupidschecked = ();
</del><span class="cx">     my $rows = $dbh-&gt;selectall_arrayref(
</span><del>-                &quot;SELECT DISTINCT groups.name, groups.id, member_id
-                            FROM group_group_map
-                      INNER JOIN groups
-                              ON groups.id = grantor_id
-                           WHERE grant_type = &quot; . GROUP_MEMBERSHIP);
-    my %group_names = ();
-    my %group_membership = ();
</del><ins>+        &quot;SELECT DISTINCT grantor_id, member_id
+           FROM group_group_map
+          WHERE grant_type = &quot; . GROUP_MEMBERSHIP);
+
+    my %group_membership;
</ins><span class="cx">     foreach my $row (@$rows) {
</span><del>-        my ($member_name, $grantor_id, $member_id) = @$row; 
-        # Just save the group names
-        $group_names{$grantor_id} = $member_name;
-        
-        # And group membership
-        push (@{$group_membership{$member_id}}, $grantor_id);
</del><ins>+        my ($grantor_id, $member_id) = @$row; 
+        push (@{ $group_membership{$member_id} }, $grantor_id);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     # Let's walk the groups hierarchy tree (using FIFO)
</span><span class="cx">     # On the first iteration it's pre-filled with direct groups 
</span><span class="cx">     # membership. Later on, each group can add its own members into the
</span><span class="cx">     # FIFO. Circular dependencies are eliminated by checking
</span><del>-    # $groupidschecked{$member_id} hash values.
</del><ins>+    # $checked_groups{$member_id} hash values.
</ins><span class="cx">     # As a result, %groups will have all the groups we are the member of.
</span><del>-    while ($#groupidstocheck &gt;= 0) {
</del><ins>+    my %checked_groups;
+    my %groups;
+    while (scalar(@$groups_to_check) &gt; 0) {
</ins><span class="cx">         # Pop the head group from FIFO
</span><del>-        my $member_id = shift @groupidstocheck;
</del><ins>+        my $member_id = shift @$groups_to_check;
</ins><span class="cx">         
</span><span class="cx">         # Skip the group if we have already checked it
</span><del>-        if (!$groupidschecked{$member_id}) {
</del><ins>+        if (!$checked_groups{$member_id}) {
</ins><span class="cx">             # Mark group as checked
</span><del>-            $groupidschecked{$member_id} = 1;
</del><ins>+            $checked_groups{$member_id} = 1;
</ins><span class="cx">             
</span><span class="cx">             # Add all its members to the FIFO check list
</span><span class="cx">             # %group_membership contains arrays of group members 
</span><span class="cx">             # for all groups. Accessible by group number.
</span><del>-            foreach my $newgroupid (@{$group_membership{$member_id}}) {
-                push @groupidstocheck, $newgroupid 
-                    if (!$groupidschecked{$newgroupid});
-            }
-            # Note on if clause: we could have group in %groups from 1st
-            # query and do not have it in second one
-            $groups{$group_names{$member_id}} = $member_id 
-                if $group_names{$member_id} &amp;&amp; $member_id;
</del><ins>+            my $members = $group_membership{$member_id};
+            my @new_to_check = grep(!$checked_groups{$_}, @$members);
+            push(@$groups_to_check, @new_to_check);
+
+            $groups{$member_id} = 1;
</ins><span class="cx">         }
</span><span class="cx">     }
</span><del>-    $self-&gt;{groups} = \%groups;
</del><span class="cx"> 
</span><ins>+    $self-&gt;{groups} = Bugzilla::Group-&gt;new_from_list([keys %groups]);
+
</ins><span class="cx">     return $self-&gt;{groups};
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# It turns out that calling -&gt;id on objects a few hundred thousand
+# times is pretty slow. (It showed up as a significant time contributor
+# when profiling xt/search.t.) So we cache the group ids separately from
+# groups for functions that need the group ids.
+sub _group_ids {
+    my ($self) = @_;
+    $self-&gt;{group_ids} ||= [map { $_-&gt;id } @{ $self-&gt;groups }];
+    return $self-&gt;{group_ids};
+}
+
</ins><span class="cx"> sub groups_as_string {
</span><span class="cx">     my $self = shift;
</span><del>-    return (join(',',values(%{$self-&gt;groups})) || '-1');
</del><ins>+    my $ids = $self-&gt;_group_ids;
+    return scalar(@$ids) ? join(',', @$ids) : '-1';
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub groups_in_sql {
+    my ($self, $field) = @_;
+    $field ||= 'group_id';
+    my $ids = $self-&gt;_group_ids;
+    $ids = [-1] if !scalar @$ids;
+    return Bugzilla-&gt;dbh-&gt;sql_in($field, $ids);
+}
+
</ins><span class="cx"> sub bless_groups {
</span><span class="cx">     my $self = shift;
</span><span class="cx"> 
</span><span class="cx">     return $self-&gt;{'bless_groups'} if defined $self-&gt;{'bless_groups'};
</span><span class="cx">     return [] unless $self-&gt;id;
</span><span class="cx"> 
</span><del>-    my $dbh = Bugzilla-&gt;dbh;
-    my $query;
-    my $connector;
-    my @bindValues;
-
</del><span class="cx">     if ($self-&gt;in_group('editusers')) {
</span><span class="cx">         # Users having editusers permissions may bless all groups.
</span><del>-        $query = 'SELECT DISTINCT id, name, description FROM groups';
-        $connector = 'WHERE';
</del><ins>+        $self-&gt;{'bless_groups'} = [Bugzilla::Group-&gt;get_all];
+        return $self-&gt;{'bless_groups'};
</ins><span class="cx">     }
</span><del>-    else {
-        # Get all groups for the user where:
-        #    + They have direct bless privileges
-        #    + They are a member of a group that inherits bless privs.
-        $query = q{
-            SELECT DISTINCT groups.id, groups.name, groups.description
-                       FROM groups, user_group_map, group_group_map AS ggm
-                      WHERE user_group_map.user_id = ?
-                        AND ((user_group_map.isbless = 1
-                              AND groups.id=user_group_map.group_id)
-                             OR (groups.id = ggm.grantor_id
-                                 AND ggm.grant_type = ?
-                                 AND ggm.member_id IN(} .
-                                 $self-&gt;groups_as_string . 
-                               q{)))};
-        $connector = 'AND';
-        @bindValues = ($self-&gt;id, GROUP_BLESS);
-    }
</del><span class="cx"> 
</span><ins>+    my $dbh = Bugzilla-&gt;dbh;
+
+    # Get all groups for the user where:
+    #    + They have direct bless privileges
+    #    + They are a member of a group that inherits bless privs.
+    my @group_ids = map {$_-&gt;id} @{ $self-&gt;groups };
+    @group_ids = (-1) if !@group_ids;
+    my $query =
+        'SELECT DISTINCT groups.id
+           FROM groups, user_group_map, group_group_map AS ggm
+          WHERE user_group_map.user_id = ?
+                AND ( (user_group_map.isbless = 1
+                       AND groups.id=user_group_map.group_id)
+                     OR (groups.id = ggm.grantor_id
+                         AND ggm.grant_type = ' . GROUP_BLESS . '
+                         AND ' . $dbh-&gt;sql_in('ggm.member_id', \@group_ids)
+                     . ') )';
+
</ins><span class="cx">     # If visibilitygroups are used, restrict the set of groups.
</span><del>-    if (!$self-&gt;in_group('editusers')
-        &amp;&amp; Bugzilla-&gt;params-&gt;{'usevisibilitygroups'}) 
-    {
</del><ins>+    if (Bugzilla-&gt;params-&gt;{'usevisibilitygroups'}) {
+        return [] if !$self-&gt;visible_groups_as_string;
</ins><span class="cx">         # Users need to see a group in order to bless it.
</span><del>-        my $visibleGroups = join(', ', @{$self-&gt;visible_groups_direct()})
-            || return $self-&gt;{'bless_groups'} = [];
-        $query .= &quot; $connector id in ($visibleGroups)&quot;;
</del><ins>+        $query .= &quot; AND &quot;
+            . $dbh-&gt;sql_in('groups.id', $self-&gt;visible_groups_inherited);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    $query .= ' ORDER BY name';
-
-    return $self-&gt;{'bless_groups'} =
-        $dbh-&gt;selectall_arrayref($query, {'Slice' =&gt; {}}, @bindValues);
</del><ins>+    my $ids = $dbh-&gt;selectcol_arrayref($query, undef, $self-&gt;id);
+    return $self-&gt;{'bless_groups'} = Bugzilla::Group-&gt;new_from_list($ids);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub in_group {
</span><span class="cx">     my ($self, $group, $product_id) = @_;
</span><del>-    if (exists $self-&gt;groups-&gt;{$group}) {
</del><ins>+    $group = $group-&gt;name if blessed $group;
+    if (scalar grep($_-&gt;name eq $group, @{ $self-&gt;groups })) {
</ins><span class="cx">         return 1;
</span><span class="cx">     }
</span><span class="cx">     elsif ($product_id &amp;&amp; detaint_natural($product_id)) {
</span><span class="lines">@@ -503,7 +761,7 @@
</span><span class="cx">                               FROM group_control_map
</span><span class="cx">                              WHERE product_id = ?
</span><span class="cx">                                    AND $group != 0
</span><del>-                                   AND group_id IN (&quot; . $self-&gt;groups_as_string . &quot;) &quot; .
</del><ins>+                                   AND &quot; . $self-&gt;groups_in_sql . ' ' .
</ins><span class="cx">                               $dbh-&gt;sql_limit(1),
</span><span class="cx">                              undef, $product_id);
</span><span class="cx"> 
</span><span class="lines">@@ -517,8 +775,7 @@
</span><span class="cx"> 
</span><span class="cx"> sub in_group_id {
</span><span class="cx">     my ($self, $id) = @_;
</span><del>-    my %j = reverse(%{$self-&gt;groups});
-    return exists $j{$id} ? 1 : 0;
</del><ins>+    return grep($_-&gt;id == $id, @{ $self-&gt;groups }) ? 1 : 0;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub get_products_by_permission {
</span><span class="lines">@@ -530,14 +787,15 @@
</span><span class="cx">                           &quot;SELECT DISTINCT product_id
</span><span class="cx">                              FROM group_control_map
</span><span class="cx">                             WHERE $group != 0
</span><del>-                              AND group_id IN(&quot; . $self-&gt;groups_as_string . &quot;)&quot;);
</del><ins>+                              AND &quot; . $self-&gt;groups_in_sql);
</ins><span class="cx"> 
</span><span class="cx">     # No need to go further if the user has no &quot;special&quot; privs.
</span><span class="cx">     return [] unless scalar(@$product_ids);
</span><ins>+    my %product_map = map { $_ =&gt; 1 } @$product_ids;
</ins><span class="cx"> 
</span><span class="cx">     # We will restrict the list to products the user can see.
</span><span class="cx">     my $selectable_products = $self-&gt;get_selectable_products;
</span><del>-    my @products = grep {lsearch($product_ids, $_-&gt;id) &gt; -1} @$selectable_products;
</del><ins>+    my @products = grep { $product_map{$_-&gt;id} } @$selectable_products;
</ins><span class="cx">     return \@products;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -580,55 +838,80 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub can_see_bug {
</span><del>-    my ($self, $bugid) = @_;
-    my $dbh = Bugzilla-&gt;dbh;
</del><ins>+    my ($self, $bug_id) = @_;
+    return @{ $self-&gt;visible_bugs([$bug_id]) } ? 1 : 0;
+}
</ins><span class="cx"> 
</span><del>-    #if WEBKIT_CHANGES
-    # FIXME: disable memoization since it results in stale handle
-    my $sth;
-    #my $sth  = $self-&gt;{sthCanSeeBug};
-    #endif WEBKIT_CHANGES 
</del><ins>+sub visible_bugs {
+    my ($self, $bugs) = @_;
+    # Allow users to pass in Bug objects and bug ids both.
+    my @bug_ids = map { blessed $_ ? $_-&gt;id : $_ } @$bugs;
</ins><span class="cx"> 
</span><del>-    my $userid  = $self-&gt;id;
-    # Get fields from bug, presence of user on cclist, and determine if
-    # the user is missing any groups required by the bug. The prepared query
-    # is cached because this may be called for every row in buglists or
-    # every bug in a dependency list.
-    unless ($sth) {
-        $sth = $dbh-&gt;prepare(&quot;SELECT 1, reporter, assigned_to, qa_contact,
-                             reporter_accessible, cclist_accessible,
-                             COUNT(cc.who), COUNT(bug_group_map.bug_id)
-                             FROM bugs
-                             LEFT JOIN cc 
-                               ON cc.bug_id = bugs.bug_id
-                               AND cc.who = $userid
-                             LEFT JOIN bug_group_map 
-                               ON bugs.bug_id = bug_group_map.bug_id
-                               AND bug_group_map.group_ID NOT IN(&quot; .
-                               $self-&gt;groups_as_string .
-                               &quot;) WHERE bugs.bug_id = ? 
-                               AND creation_ts IS NOT NULL &quot; .
-                             $dbh-&gt;sql_group_by('bugs.bug_id', 'reporter, ' .
-                             'assigned_to, qa_contact, reporter_accessible, ' .
-                             'cclist_accessible'));
</del><ins>+    # We only check the visibility of bugs that we haven't
+    # checked yet.
+    # Bugzilla::Bug-&gt;update automatically removes updated bugs
+    # from the cache to force them to be checked again.
+    my $visible_cache = $self-&gt;{_visible_bugs_cache} ||= {};
+    my @check_ids = grep(!exists $visible_cache-&gt;{$_}, @bug_ids);
+
+    if (@check_ids) {
+        my $dbh = Bugzilla-&gt;dbh;
+        my $user_id = $self-&gt;id;
+        my $sth;
+        # Speed up the can_see_bug case.
+        if (scalar(@check_ids) == 1) {
+            $sth = $self-&gt;{_sth_one_visible_bug};
+        }
+        $sth ||= $dbh-&gt;prepare(
+            # This checks for groups that the bug is in that the user
+            # *isn't* in. Then, in the Perl code below, we check if
+            # the user can otherwise access the bug (for example, by being
+            # the assignee or QA Contact).
+            #
+            # The DISTINCT exists because the bug could be in *several*
+            # groups that the user isn't in, but they will all return the
+            # same result for bug_group_map.bug_id (so DISTINCT filters
+            # out duplicate rows).
+            &quot;SELECT DISTINCT bugs.bug_id, reporter, assigned_to, qa_contact,
+                    reporter_accessible, cclist_accessible, cc.who,
+                    bug_group_map.bug_id
+               FROM bugs
+                    LEFT JOIN cc
+                              ON cc.bug_id = bugs.bug_id
+                                 AND cc.who = $user_id
+                    LEFT JOIN bug_group_map 
+                              ON bugs.bug_id = bug_group_map.bug_id
+                                 AND bug_group_map.group_id NOT IN (&quot;
+                                     . $self-&gt;groups_as_string . ')
+              WHERE bugs.bug_id IN (' . join(',', ('?') x @check_ids) . ')
+                    AND creation_ts IS NOT NULL ');
+        if (scalar(@check_ids) == 1) {
+            $self-&gt;{_sth_one_visible_bug} = $sth;
+        }
+
+        $sth-&gt;execute(@check_ids);
+        my $use_qa_contact = Bugzilla-&gt;params-&gt;{'useqacontact'};
+        while (my $row = $sth-&gt;fetchrow_arrayref) {
+            my ($bug_id, $reporter, $owner, $qacontact, $reporter_access, 
+                $cclist_access, $isoncclist, $missinggroup) = @$row;
+            $visible_cache-&gt;{$bug_id} ||= 
+                ((($reporter == $user_id) &amp;&amp; $reporter_access)
+                 || ($use_qa_contact
+                     &amp;&amp; $qacontact &amp;&amp; ($qacontact == $user_id))
+                 || ($owner == $user_id)
+                 || ($isoncclist &amp;&amp; $cclist_access)
+                 || !$missinggroup) ? 1 : 0;
+        }
</ins><span class="cx">     }
</span><del>-    $sth-&gt;execute($bugid);
-    my ($ready, $reporter, $owner, $qacontact, $reporter_access, $cclist_access,
-        $isoncclist, $missinggroup) = $sth-&gt;fetchrow_array();
-    $sth-&gt;finish;
</del><span class="cx"> 
</span><del>-    #if WEBKIT_CHANGES
-    # FIXME: disable memoization since it results in stale handle
-    #$self-&gt;{sthCanSeeBug} = $sth;
-    #endif WEBKIT_CHANGES 
</del><ins>+    return [grep { $visible_cache-&gt;{blessed $_ ? $_-&gt;id : $_} } @$bugs];
+}
</ins><span class="cx"> 
</span><del>-    return ($ready
-            &amp;&amp; ((($reporter == $userid) &amp;&amp; $reporter_access)
-                || (Bugzilla-&gt;params-&gt;{'useqacontact'} 
-                    &amp;&amp; $qacontact &amp;&amp; ($qacontact == $userid))
-                || ($owner == $userid)
-                || ($isoncclist &amp;&amp; $cclist_access)
-                || (!$missinggroup)));
</del><ins>+sub clear_product_cache {
+    my $self = shift;
+    delete $self-&gt;{enterable_products};
+    delete $self-&gt;{selectable_products};
+    delete $self-&gt;{selectable_classifications};
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub can_see_product {
</span><span class="lines">@@ -646,13 +929,9 @@
</span><span class="cx">         my $query = &quot;SELECT id &quot; .
</span><span class="cx">                     &quot;  FROM products &quot; .
</span><span class="cx">                  &quot;LEFT JOIN group_control_map &quot; .
</span><del>-                    &quot;    ON group_control_map.product_id = products.id &quot;;
-        if (Bugzilla-&gt;params-&gt;{'useentrygroupdefault'}) {
-            $query .= &quot; AND group_control_map.entry != 0 &quot;;
-        } else {
-            $query .= &quot; AND group_control_map.membercontrol = &quot; . CONTROLMAPMANDATORY;
-        }
-        $query .= &quot;     AND group_id NOT IN(&quot; . $self-&gt;groups_as_string . &quot;) &quot; .
</del><ins>+                        &quot;ON group_control_map.product_id = products.id &quot; .
+                      &quot; AND group_control_map.membercontrol = &quot; . CONTROLMAPMANDATORY .
+                      &quot; AND group_id NOT IN(&quot; . $self-&gt;groups_as_string . &quot;) &quot; .
</ins><span class="cx">                   &quot;   WHERE group_id IS NULL &quot; .
</span><span class="cx">                   &quot;ORDER BY name&quot;;
</span><span class="cx"> 
</span><span class="lines">@@ -671,58 +950,69 @@
</span><span class="cx"> sub get_selectable_classifications {
</span><span class="cx">     my ($self) = @_;
</span><span class="cx"> 
</span><del>-    if (defined $self-&gt;{selectable_classifications}) {
-        return $self-&gt;{selectable_classifications};
-    }
</del><ins>+    if (!defined $self-&gt;{selectable_classifications}) {
+        my $products = $self-&gt;get_selectable_products;
+        my %class_ids = map { $_-&gt;classification_id =&gt; 1 } @$products;
</ins><span class="cx"> 
</span><del>-    my $products = $self-&gt;get_selectable_products;
-
-    my $class;
-    foreach my $product (@$products) {
-        $class-&gt;{$product-&gt;classification_id} ||= 
-            new Bugzilla::Classification($product-&gt;classification_id);
</del><ins>+        $self-&gt;{selectable_classifications} = Bugzilla::Classification-&gt;new_from_list([keys %class_ids]);
</ins><span class="cx">     }
</span><del>-    my @sorted_class = sort {$a-&gt;sortkey &lt;=&gt; $b-&gt;sortkey 
-                             || lc($a-&gt;name) cmp lc($b-&gt;name)} (values %$class);
-    $self-&gt;{selectable_classifications} = \@sorted_class;
</del><span class="cx">     return $self-&gt;{selectable_classifications};
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub can_enter_product {
</span><del>-    my ($self, $product_name, $warn) = @_;
</del><ins>+    my ($self, $input, $warn) = @_;
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><ins>+    $warn ||= 0;
</ins><span class="cx"> 
</span><del>-    if (!defined($product_name)) {
</del><ins>+    $input = trim($input) if !ref $input;
+    if (!defined $input or $input eq '') {
</ins><span class="cx">         return unless $warn == THROW_ERROR;
</span><ins>+        ThrowUserError('object_not_specified',
+                       { class =&gt; 'Bugzilla::Product' });
+    }
+
+    if (!scalar @{ $self-&gt;get_enterable_products }) {
+        return unless $warn == THROW_ERROR;
</ins><span class="cx">         ThrowUserError('no_products');
</span><span class="cx">     }
</span><del>-    my $product = new Bugzilla::Product({name =&gt; $product_name});
</del><span class="cx"> 
</span><ins>+    my $product = blessed($input) ? $input 
+                                  : new Bugzilla::Product({ name =&gt; $input });
</ins><span class="cx">     my $can_enter =
</span><del>-      $product &amp;&amp; grep($_-&gt;name eq $product-&gt;name, @{$self-&gt;get_enterable_products});
</del><ins>+      $product &amp;&amp; grep($_-&gt;name eq $product-&gt;name,
+                       @{ $self-&gt;get_enterable_products });
</ins><span class="cx"> 
</span><del>-    return 1 if $can_enter;
</del><ins>+    return $product if $can_enter;
</ins><span class="cx"> 
</span><span class="cx">     return 0 unless $warn == THROW_ERROR;
</span><span class="cx"> 
</span><span class="cx">     # Check why access was denied. These checks are slow,
</span><span class="cx">     # but that's fine, because they only happen if we fail.
</span><span class="cx"> 
</span><ins>+    # We don't just use $product-&gt;name for error messages, because if it
+    # changes case from $input, then that's a clue that the product does
+    # exist but is hidden.
+    my $name = blessed($input) ? $input-&gt;name : $input;
+
</ins><span class="cx">     # The product could not exist or you could be denied...
</span><span class="cx">     if (!$product || !$product-&gt;user_has_access($self)) {
</span><del>-        ThrowUserError('entry_access_denied', {product =&gt; $product_name});
</del><ins>+        ThrowUserError('entry_access_denied', { product =&gt; $name });
</ins><span class="cx">     }
</span><span class="cx">     # It could be closed for bug entry...
</span><del>-    elsif ($product-&gt;disallow_new) {
-        ThrowUserError('product_disabled', {product =&gt; $product});
</del><ins>+    elsif (!$product-&gt;is_active) {
+        ThrowUserError('product_disabled', { product =&gt; $product });
</ins><span class="cx">     }
</span><span class="cx">     # It could have no components...
</span><del>-    elsif (!@{$product-&gt;components}) {
-        ThrowUserError('missing_component', {product =&gt; $product});
</del><ins>+    elsif (!@{$product-&gt;components}
+           || !grep { $_-&gt;is_active } @{$product-&gt;components})
+    {
+        ThrowUserError('missing_component', { product =&gt; $product });
</ins><span class="cx">     }
</span><span class="cx">     # It could have no versions...
</span><del>-    elsif (!@{$product-&gt;versions}) {
-        ThrowUserError ('missing_version', {product =&gt; $product});
</del><ins>+    elsif (!@{$product-&gt;versions}
+           || !grep { $_-&gt;is_active } @{$product-&gt;versions})
+    {
+        ThrowUserError ('missing_version', { product =&gt; $product });
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     die &quot;can_enter_product reached an unreachable location.&quot;;
</span><span class="lines">@@ -737,31 +1027,40 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">      # All products which the user has &quot;Entry&quot; access to.
</span><del>-     my @enterable_ids =@{$dbh-&gt;selectcol_arrayref(
</del><ins>+     my $enterable_ids = $dbh-&gt;selectcol_arrayref(
</ins><span class="cx">            'SELECT products.id FROM products
</span><span class="cx">          LEFT JOIN group_control_map
</span><span class="cx">                    ON group_control_map.product_id = products.id
</span><span class="cx">                       AND group_control_map.entry != 0
</span><span class="cx">                       AND group_id NOT IN (' . $self-&gt;groups_as_string . ')
</span><span class="cx">             WHERE group_id IS NULL
</span><del>-                  AND products.disallownew = 0') || []};
</del><ins>+                  AND products.isactive = 1');
</ins><span class="cx"> 
</span><del>-    if (@enterable_ids) {
</del><ins>+    if (scalar @$enterable_ids) {
</ins><span class="cx">         # And all of these products must have at least one component
</span><span class="cx">         # and one version.
</span><del>-        @enterable_ids = @{$dbh-&gt;selectcol_arrayref(
-               'SELECT DISTINCT products.id FROM products
-            INNER JOIN components ON components.product_id = products.id
-            INNER JOIN versions ON versions.product_id = products.id
-                 WHERE products.id IN (' . (join(',', @enterable_ids)) .
-            ')') || []};
</del><ins>+        $enterable_ids = $dbh-&gt;selectcol_arrayref(
+            'SELECT DISTINCT products.id FROM products
+              WHERE ' . $dbh-&gt;sql_in('products.id', $enterable_ids) .
+              ' AND products.id IN (SELECT DISTINCT components.product_id
+                                      FROM components
+                                     WHERE components.isactive = 1)
+                AND products.id IN (SELECT DISTINCT versions.product_id
+                                      FROM versions
+                                     WHERE versions.isactive = 1)');
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     $self-&gt;{enterable_products} =
</span><del>-         Bugzilla::Product-&gt;new_from_list(\@enterable_ids);
</del><ins>+         Bugzilla::Product-&gt;new_from_list($enterable_ids);
</ins><span class="cx">     return $self-&gt;{enterable_products};
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub can_access_product {
+    my ($self, $product) = @_;
+    my $product_name = blessed($product) ? $product-&gt;name : $product;
+    return scalar(grep {$_-&gt;name eq $product_name} @{$self-&gt;get_accessible_products});
+}
+
</ins><span class="cx"> sub get_accessible_products {
</span><span class="cx">     my $self = shift;
</span><span class="cx">     
</span><span class="lines">@@ -777,7 +1076,7 @@
</span><span class="cx">     my ($self, $product_name) = @_;
</span><span class="cx"> 
</span><span class="cx">     # First make sure the product name is valid.
</span><del>-    my $product = Bugzilla::Product::check_product($product_name);
</del><ins>+    my $product = Bugzilla::Product-&gt;check($product_name);
</ins><span class="cx"> 
</span><span class="cx">     ($self-&gt;in_group('editcomponents', $product-&gt;id)
</span><span class="cx">        &amp;&amp; $self-&gt;can_see_product($product-&gt;name))
</span><span class="lines">@@ -787,6 +1086,49 @@
</span><span class="cx">     return $product;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub check_can_admin_flagtype {
+    my ($self, $flagtype_id) = @_;
+
+    my $flagtype = Bugzilla::FlagType-&gt;check({ id =&gt; $flagtype_id });
+    my $can_fully_edit = 1;
+
+    if (!$self-&gt;in_group('editcomponents')) {
+        my $products = $self-&gt;get_products_by_permission('editcomponents');
+        # You need editcomponents privs for at least one product to have
+        # a chance to edit the flagtype.
+        scalar(@$products)
+          || ThrowUserError('auth_failure', {group  =&gt; 'editcomponents',
+                                             action =&gt; 'edit',
+                                             object =&gt; 'flagtypes'});
+        my $can_admin = 0;
+        my $i = $flagtype-&gt;inclusions_as_hash;
+        my $e = $flagtype-&gt;exclusions_as_hash;
+
+        # If there is at least one product for which the user doesn't have
+        # editcomponents privs, then don't allow him to do everything with
+        # this flagtype, independently of whether this product is in the
+        # exclusion list or not.
+        my %product_ids;
+        map { $product_ids{$_-&gt;id} = 1 } @$products;
+        $can_fully_edit = 0 if grep { !$product_ids{$_} } keys %$i;
+
+        unless ($e-&gt;{0}-&gt;{0}) {
+            foreach my $product (@$products) {
+                my $id = $product-&gt;id;
+                next if $e-&gt;{$id}-&gt;{0};
+                # If we are here, the product has not been explicitly excluded.
+                # Check whether it's explicitly included, or at least one of
+                # its components.
+                $can_admin = ($i-&gt;{0}-&gt;{0} || $i-&gt;{$id}-&gt;{0}
+                              || scalar(grep { !$e-&gt;{$id}-&gt;{$_} } keys %{$i-&gt;{$id}}));
+                last if $can_admin;
+            }
+        }
+        $can_admin || ThrowUserError('flag_type_not_editable', { flagtype =&gt; $flagtype });
+    }
+    return wantarray ? ($flagtype, $can_fully_edit) : $flagtype;
+}
+
</ins><span class="cx"> sub can_request_flag {
</span><span class="cx">     my ($self, $flag_type) = @_;
</span><span class="cx"> 
</span><span class="lines">@@ -827,7 +1169,7 @@
</span><span class="cx">     return $self-&gt;{visible_groups_inherited} if defined $self-&gt;{visible_groups_inherited};
</span><span class="cx">     return [] unless $self-&gt;id;
</span><span class="cx">     my @visgroups = @{$self-&gt;visible_groups_direct};
</span><del>-    @visgroups = @{$self-&gt;flatten_group_membership(@visgroups)};
</del><ins>+    @visgroups = @{Bugzilla::Group-&gt;flatten_group_membership(@visgroups)};
</ins><span class="cx">     $self-&gt;{visible_groups_inherited} = \@visgroups;
</span><span class="cx">     return $self-&gt;{visible_groups_inherited};
</span><span class="cx"> }
</span><span class="lines">@@ -844,10 +1186,9 @@
</span><span class="cx">     my $sth;
</span><span class="cx">    
</span><span class="cx">     if (Bugzilla-&gt;params-&gt;{'usevisibilitygroups'}) {
</span><del>-        my $glist = join(',',(-1,values(%{$self-&gt;groups})));
</del><span class="cx">         $sth = $dbh-&gt;prepare(&quot;SELECT DISTINCT grantor_id
</span><span class="cx">                                  FROM group_group_map
</span><del>-                                WHERE member_id IN($glist)
</del><ins>+                                WHERE &quot; . $self-&gt;groups_in_sql('member_id') . &quot;
</ins><span class="cx">                                   AND grant_type=&quot; . GROUP_VISIBLE);
</span><span class="cx">     }
</span><span class="cx">     else {
</span><span class="lines">@@ -889,7 +1230,7 @@
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">         else {
</span><del>-            @queryshare_groups = values(%{$self-&gt;groups});
</del><ins>+            @queryshare_groups = @{ $self-&gt;_group_ids };
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -945,11 +1286,14 @@
</span><span class="cx">     return $self-&gt;{'product_resp'} if defined $self-&gt;{'product_resp'};
</span><span class="cx">     return [] unless $self-&gt;id;
</span><span class="cx"> 
</span><del>-    my $list = $dbh-&gt;selectall_arrayref('SELECT product_id, id
</del><ins>+    my $list = $dbh-&gt;selectall_arrayref('SELECT components.product_id, components.id
</ins><span class="cx">                                            FROM components
</span><del>-                                          WHERE initialowner = ?
-                                             OR initialqacontact = ?',
-                                  {Slice =&gt; {}}, ($self-&gt;id, $self-&gt;id));
</del><ins>+                                           LEFT JOIN component_cc
+                                           ON components.id = component_cc.component_id
+                                          WHERE components.initialowner = ?
+                                             OR components.initialqacontact = ?
+                                             OR component_cc.user_id = ?',
+                                  {Slice =&gt; {}}, ($self-&gt;id, $self-&gt;id, $self-&gt;id));
</ins><span class="cx"> 
</span><span class="cx">     unless ($list) {
</span><span class="cx">         $self-&gt;{'product_resp'} = [];
</span><span class="lines">@@ -981,38 +1325,14 @@
</span><span class="cx">     if (!scalar(@_)) {
</span><span class="cx">         # If we're called without an argument, just return 
</span><span class="cx">         # whether or not we can bless at all.
</span><del>-        return scalar(@{$self-&gt;bless_groups}) ? 1 : 0;
</del><ins>+        return scalar(@{ $self-&gt;bless_groups }) ? 1 : 0;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # Otherwise, we're checking a specific group
</span><span class="cx">     my $group_id = shift;
</span><del>-    return (grep {$$_{'id'} eq $group_id} (@{$self-&gt;bless_groups})) ? 1 : 0;
</del><ins>+    return grep($_-&gt;id == $group_id, @{ $self-&gt;bless_groups }) ? 1 : 0;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub flatten_group_membership {
-    my ($self, @groups) = @_;
-
-    my $dbh = Bugzilla-&gt;dbh;
-    my $sth;
-    my @groupidstocheck = @groups;
-    my %groupidschecked = ();
-    $sth = $dbh-&gt;prepare(&quot;SELECT member_id FROM group_group_map
-                             WHERE grantor_id = ? 
-                               AND grant_type = &quot; . GROUP_MEMBERSHIP);
-    while (my $node = shift @groupidstocheck) {
-        $sth-&gt;execute($node);
-        my $member;
-        while (($member) = $sth-&gt;fetchrow_array) {
-            if (!$groupidschecked{$member}) {
-                $groupidschecked{$member} = 1;
-                push @groupidstocheck, $member;
-                push @groups, $member unless grep $_ == $member, @groups;
-            }
-        }
-    }
-    return \@groups;
-}
-
</del><span class="cx"> sub match {
</span><span class="cx">     # Generates a list of users whose login name (email address) or real name
</span><span class="cx">     # matches a substring or wildcard.
</span><span class="lines">@@ -1025,6 +1345,8 @@
</span><span class="cx">     my $user = Bugzilla-&gt;user;
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx"> 
</span><ins>+    $str = trim($str);
+
</ins><span class="cx">     my @users = ();
</span><span class="cx">     return \@users if $str =~ /^\s*$/;
</span><span class="cx"> 
</span><span class="lines">@@ -1036,14 +1358,11 @@
</span><span class="cx">     # first try wildcards
</span><span class="cx">     my $wildstr = $str;
</span><span class="cx"> 
</span><del>-    if ($wildstr =~ s/\*/\%/g # don't do wildcards if no '*' in the string
-        # or if we only want exact matches
-        &amp;&amp; Bugzilla-&gt;params-&gt;{'usermatchmode'} ne 'off') 
-    {
-
</del><ins>+    # Do not do wildcards if there is no '*' in the string.
+    if ($wildstr =~ s/\*/\%/g &amp;&amp; $user-&gt;id) {
</ins><span class="cx">         # Build the query.
</span><span class="cx">         trick_taint($wildstr);
</span><del>-        my $query  = &quot;SELECT DISTINCT login_name FROM profiles &quot;;
</del><ins>+        my $query  = &quot;SELECT DISTINCT userid FROM profiles &quot;;
</ins><span class="cx">         if (Bugzilla-&gt;params-&gt;{'usevisibilitygroups'}) {
</span><span class="cx">             $query .= &quot;INNER JOIN user_group_map
</span><span class="cx">                                ON user_group_map.user_id = profiles.userid &quot;;
</span><span class="lines">@@ -1056,16 +1375,13 @@
</span><span class="cx">                       &quot;AND group_id IN(&quot; .
</span><span class="cx">                       join(', ', (-1, @{$user-&gt;visible_groups_inherited})) . &quot;) &quot;;
</span><span class="cx">         }
</span><del>-        $query    .= &quot; AND disabledtext = '' &quot; if $exclude_disabled;
-        $query    .= &quot; ORDER BY login_name &quot;;
</del><ins>+        $query    .= &quot; AND is_enabled = 1 &quot; if $exclude_disabled;
</ins><span class="cx">         $query    .= $dbh-&gt;sql_limit($limit) if $limit;
</span><span class="cx"> 
</span><span class="cx">         # Execute the query, retrieve the results, and make them into
</span><span class="cx">         # User objects.
</span><del>-        my $user_logins = $dbh-&gt;selectcol_arrayref($query, undef, ($wildstr, $wildstr));
-        foreach my $login_name (@$user_logins) {
-            push(@users, new Bugzilla::User({ name =&gt; $login_name }));
-        }
</del><ins>+        my $user_ids = $dbh-&gt;selectcol_arrayref($query, undef, ($wildstr, $wildstr));
+        @users = @{Bugzilla::User-&gt;new_from_list($user_ids)};
</ins><span class="cx">     }
</span><span class="cx">     else {    # try an exact match
</span><span class="cx">         # Exact matches don't care if a user is disabled.
</span><span class="lines">@@ -1078,89 +1394,39 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # then try substring search
</span><del>-    if ((scalar(@users) == 0)
-        &amp;&amp; (Bugzilla-&gt;params-&gt;{'usermatchmode'} eq 'search')
-        &amp;&amp; (length($str) &gt;= 3))
-    {
-        $str = lc($str);
</del><ins>+    if (!scalar(@users) &amp;&amp; length($str) &gt;= 3 &amp;&amp; $user-&gt;id) {
</ins><span class="cx">         trick_taint($str);
</span><span class="cx"> 
</span><del>-        my $query   = &quot;SELECT DISTINCT login_name FROM profiles &quot;;
</del><ins>+        my $query   = &quot;SELECT DISTINCT userid FROM profiles &quot;;
</ins><span class="cx">         if (Bugzilla-&gt;params-&gt;{'usevisibilitygroups'}) {
</span><span class="cx">             $query .= &quot;INNER JOIN user_group_map
</span><span class="cx">                                ON user_group_map.user_id = profiles.userid &quot;;
</span><span class="cx">         }
</span><span class="cx">         $query     .= &quot; WHERE (&quot; .
</span><del>-                $dbh-&gt;sql_position('?', 'LOWER(login_name)') . &quot; &gt; 0&quot; . &quot; OR &quot; .
-                $dbh-&gt;sql_position('?', 'LOWER(realname)') . &quot; &gt; 0) &quot;;
</del><ins>+                $dbh-&gt;sql_iposition('?', 'login_name') . &quot; &gt; 0&quot; . &quot; OR &quot; .
+                $dbh-&gt;sql_iposition('?', 'realname') . &quot; &gt; 0) &quot;;
</ins><span class="cx">         if (Bugzilla-&gt;params-&gt;{'usevisibilitygroups'}) {
</span><span class="cx">             $query .= &quot; AND isbless = 0&quot; .
</span><span class="cx">                       &quot; AND group_id IN(&quot; .
</span><span class="cx">                 join(', ', (-1, @{$user-&gt;visible_groups_inherited})) . &quot;) &quot;;
</span><span class="cx">         }
</span><del>-        $query     .= &quot; AND disabledtext = '' &quot; if $exclude_disabled;
-        $query    .= &quot; ORDER BY login_name &quot;;
</del><ins>+        $query     .= &quot; AND is_enabled = 1 &quot; if $exclude_disabled;
</ins><span class="cx">         $query     .= $dbh-&gt;sql_limit($limit) if $limit;
</span><del>-
-        my $user_logins = $dbh-&gt;selectcol_arrayref($query, undef, ($str, $str));
-        foreach my $login_name (@$user_logins) {
-            push(@users, new Bugzilla::User({ name =&gt; $login_name }));
-        }
</del><ins>+        my $user_ids = $dbh-&gt;selectcol_arrayref($query, undef, ($str, $str));
+        @users = @{Bugzilla::User-&gt;new_from_list($user_ids)};
</ins><span class="cx">     }
</span><span class="cx">     return \@users;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-# match_field() is a CGI wrapper for the match() function.
-#
-# Here's what it does:
-#
-# 1. Accepts a list of fields along with whether they may take multiple values
-# 2. Takes the values of those fields from the first parameter, a $cgi object 
-#    and passes them to match()
-# 3. Checks the results of the match and displays confirmation or failure
-#    messages as appropriate.
-#
-# The confirmation screen functions the same way as verify-new-product and
-# confirm-duplicate, by rolling all of the state information into a
-# form which is passed back, but in this case the searched fields are
-# replaced with the search results.
-#
-# The act of displaying the confirmation or failure messages means it must
-# throw a template and terminate.  When confirmation is sent, all of the
-# searchable fields have been replaced by exact fields and the calling script
-# is executed as normal.
-#
-# You also have the choice of *never* displaying the confirmation screen.
-# In this case, match_field will return one of the three USER_MATCH 
-# constants described in the POD docs. To make match_field behave this
-# way, pass in MATCH_SKIP_CONFIRM as the third argument.
-#
-# match_field must be called early in a script, before anything external is
-# done with the form data.
-#
-# In order to do a simple match without dealing with templates, confirmation,
-# or globals, simply calling Bugzilla::User::match instead will be
-# sufficient.
-
-# How to call it:
-#
-# Bugzilla::User::match_field($cgi, {
-#   'field_name'    =&gt; { 'type' =&gt; fieldtype },
-#   'field_name2'   =&gt; { 'type' =&gt; fieldtype },
-#   [...]
-# });
-#
-# fieldtype can be either 'single' or 'multi'.
-#
-
</del><span class="cx"> sub match_field {
</span><del>-    my $cgi          = shift;   # CGI object to look up fields in
</del><span class="cx">     my $fields       = shift;   # arguments as a hash
</span><ins>+    my $data         = shift || Bugzilla-&gt;input_params; # hash to look up fields in
</ins><span class="cx">     my $behavior     = shift || 0; # A constant that tells us how to act
</span><span class="cx">     my $matches      = {};      # the values sent to the template
</span><span class="cx">     my $matchsuccess = 1;       # did the match fail?
</span><span class="cx">     my $need_confirm = 0;       # whether to display confirmation screen
</span><span class="cx">     my $match_multiple = 0;     # whether we ever matched more than one user
</span><ins>+    my @non_conclusive_fields;  # fields which don't have a unique user.
</ins><span class="cx"> 
</span><span class="cx">     my $params = Bugzilla-&gt;params;
</span><span class="cx"> 
</span><span class="lines">@@ -1178,7 +1444,8 @@
</span><span class="cx">             $expanded_fields-&gt;{$field_pattern} = $fields-&gt;{$field_pattern};
</span><span class="cx">         }
</span><span class="cx">         else {
</span><del>-            my @field_names = grep(/$field_pattern/, $cgi-&gt;param());
</del><ins>+            my @field_names = grep(/$field_pattern/, keys %$data);
+
</ins><span class="cx">             foreach my $field_name (@field_names) {
</span><span class="cx">                 $expanded_fields-&gt;{$field_name} = 
</span><span class="cx">                   { type =&gt; $fields-&gt;{$field_pattern}-&gt;{'type'} };
</span><span class="lines">@@ -1204,7 +1471,7 @@
</span><span class="cx">                         # No need to look for a valid requestee if the flag(type)
</span><span class="cx">                         # has been deleted (may occur in race conditions).
</span><span class="cx">                         delete $expanded_fields-&gt;{$field_name};
</span><del>-                        $cgi-&gt;delete($field_name);
</del><ins>+                        delete $data-&gt;{$field_name};
</ins><span class="cx">                     }
</span><span class="cx">                 }
</span><span class="cx">             }
</span><span class="lines">@@ -1212,54 +1479,34 @@
</span><span class="cx">     }
</span><span class="cx">     $fields = $expanded_fields;
</span><span class="cx"> 
</span><del>-    for my $field (keys %{$fields}) {
</del><ins>+    foreach my $field (keys %{$fields}) {
+        next unless defined $data-&gt;{$field};
</ins><span class="cx"> 
</span><del>-        # Tolerate fields that do not exist.
-        #
-        # This is so that fields like qa_contact can be specified in the code
-        # and it won't break if the CGI object does not know about them.
-        #
-        # It has the side-effect that if a bad field name is passed it will be
-        # quietly ignored rather than raising a code error.
</del><ins>+        #Concatenate login names, so that we have a common way to handle them.
+        my $raw_field;
+        if (ref $data-&gt;{$field}) {
+            $raw_field = join(&quot;,&quot;, @{$data-&gt;{$field}});
+        }
+        else {
+            $raw_field = $data-&gt;{$field};
+        }
+        $raw_field = clean_text($raw_field || '');
</ins><span class="cx"> 
</span><del>-        next if !defined $cgi-&gt;param($field);
-
-        # We need to move the query to $raw_field, where it will be split up,
-        # modified by the search, and put back into the CGI environment
-        # incrementally.
-
-        my $raw_field = join(&quot; &quot;, $cgi-&gt;param($field));
-
-        # When we add back in values later, it matters that we delete
-        # the field here, and not set it to '', so that we will add
-        # things to an empty list, and not to a list containing one
-        # empty string.
-        # If the field accepts only one match (type eq &quot;single&quot;) and
-        # no match or more than one match is found for this field,
-        # we will set it back to '' so that the field remains defined
-        # outside this function (it was if we came here; else we would
-        # have returned earlier above).
-        # If the field accepts several matches (type eq &quot;multi&quot;) and no match
-        # is found, we leave this field undefined (= empty array).
-        $cgi-&gt;delete($field);
-
-        my @queries = ();
-
</del><span class="cx">         # Now we either split $raw_field by spaces/commas and put the list
</span><span class="cx">         # into @queries, or in the case of fields which only accept single
</span><span class="cx">         # entries, we simply use the verbatim text.
</span><del>-
-        $raw_field =~ s/^\s+|\s+$//sg;  # trim leading/trailing space
-
-        # single field
</del><ins>+        my @queries;
</ins><span class="cx">         if ($fields-&gt;{$field}-&gt;{'type'} eq 'single') {
</span><del>-            @queries = ($raw_field) unless $raw_field =~ /^\s*$/;
-
-        # multi-field
</del><ins>+            @queries = ($raw_field);
+            # We will repopulate it later if a match is found, else it must
+            # be set to an empty string so that the field remains defined.
+            $data-&gt;{$field} = '';
</ins><span class="cx">         }
</span><span class="cx">         elsif ($fields-&gt;{$field}-&gt;{'type'} eq 'multi') {
</span><del>-            @queries =  split(/[\s,]+/, $raw_field);
-
</del><ins>+            @queries =  split(/[,;]+/, $raw_field);
+            # We will repopulate it later if a match is found, else it must
+            # be undefined.
+            delete $data-&gt;{$field};
</ins><span class="cx">         }
</span><span class="cx">         else {
</span><span class="cx">             # bad argument
</span><span class="lines">@@ -1269,40 +1516,32 @@
</span><span class="cx">                            });
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        # Tolerate fields that do not exist (in case you specify
+        # e.g. the QA contact, and it's currently not in use).
+        next unless (defined $raw_field &amp;&amp; $raw_field ne '');
+
</ins><span class="cx">         my $limit = 0;
</span><span class="cx">         if ($params-&gt;{'maxusermatches'}) {
</span><span class="cx">             $limit = $params-&gt;{'maxusermatches'} + 1;
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        my @logins;
</ins><span class="cx">         for my $query (@queries) {
</span><del>-
</del><ins>+            $query = trim($query);
</ins><span class="cx">             my $users = match(
</span><span class="cx">                 $query,   # match string
</span><span class="cx">                 $limit,   # match limit
</span><span class="cx">                 1         # exclude_disabled
</span><span class="cx">             );
</span><span class="cx"> 
</span><del>-            # skip confirmation for exact matches
-            if ((scalar(@{$users}) == 1)
-                &amp;&amp; (lc(@{$users}[0]-&gt;login) eq lc($query)))
-
-            {
-                $cgi-&gt;append(-name=&gt;$field,
-                             -values=&gt;[@{$users}[0]-&gt;login]);
-
-                next;
-            }
-
-            $matches-&gt;{$field}-&gt;{$query}-&gt;{'users'}  = $users;
-            $matches-&gt;{$field}-&gt;{$query}-&gt;{'status'} = 'success';
-
</del><span class="cx">             # here is where it checks for multiple matches
</span><del>-
</del><span class="cx">             if (scalar(@{$users}) == 1) { # exactly one match
</span><ins>+                push(@logins, @{$users}[0]-&gt;login);
</ins><span class="cx"> 
</span><del>-                $cgi-&gt;append(-name=&gt;$field,
-                             -values=&gt;[@{$users}[0]-&gt;login]);
</del><ins>+                # skip confirmation for exact matches
+                next if (lc(@{$users}[0]-&gt;login) eq lc($query));
</ins><span class="cx"> 
</span><ins>+                $matches-&gt;{$field}-&gt;{$query}-&gt;{'status'} = 'success';
</ins><span class="cx">                 $need_confirm = 1 if $params-&gt;{'confirmuniqueusermatch'};
</span><span class="cx"> 
</span><span class="cx">             }
</span><span class="lines">@@ -1310,6 +1549,7 @@
</span><span class="cx">                     &amp;&amp; ($params-&gt;{'maxusermatches'} != 1)) {
</span><span class="cx">                 $need_confirm = 1;
</span><span class="cx">                 $match_multiple = 1;
</span><ins>+                push(@non_conclusive_fields, $field);
</ins><span class="cx"> 
</span><span class="cx">                 if (($params-&gt;{'maxusermatches'})
</span><span class="cx">                    &amp;&amp; (scalar(@{$users}) &gt; $params-&gt;{'maxusermatches'}))
</span><span class="lines">@@ -1317,24 +1557,32 @@
</span><span class="cx">                     $matches-&gt;{$field}-&gt;{$query}-&gt;{'status'} = 'trunc';
</span><span class="cx">                     pop @{$users};  # take the last one out
</span><span class="cx">                 }
</span><ins>+                else {
+                    $matches-&gt;{$field}-&gt;{$query}-&gt;{'status'} = 'success';
+                }
</ins><span class="cx"> 
</span><span class="cx">             }
</span><span class="cx">             else {
</span><span class="cx">                 # everything else fails
</span><span class="cx">                 $matchsuccess = 0; # fail
</span><ins>+                push(@non_conclusive_fields, $field);
</ins><span class="cx">                 $matches-&gt;{$field}-&gt;{$query}-&gt;{'status'} = 'fail';
</span><span class="cx">                 $need_confirm = 1;  # confirmation screen shows failures
</span><span class="cx">             }
</span><ins>+
+            $matches-&gt;{$field}-&gt;{$query}-&gt;{'users'}  = $users;
</ins><span class="cx">         }
</span><del>-        # Above, we deleted the field before adding matches. If no match
-        # or more than one match has been found for a field expecting only
-        # one match (type eq &quot;single&quot;), we set it back to '' so
-        # that the caller of this function can still check whether this
</del><ins>+
+        # If no match or more than one match has been found for a field
+        # expecting only one match (type eq &quot;single&quot;), we set it back to ''
+        # so that the caller of this function can still check whether this
</ins><span class="cx">         # field was defined or not (and it was if we came here).
</span><del>-        if (!defined $cgi-&gt;param($field)
-            &amp;&amp; $fields-&gt;{$field}-&gt;{'type'} eq 'single') {
-            $cgi-&gt;param($field, '');
</del><ins>+        if ($fields-&gt;{$field}-&gt;{'type'} eq 'single') {
+            $data-&gt;{$field} = $logins[0] || '';
</ins><span class="cx">         }
</span><ins>+        elsif (scalar @logins) {
+            $data-&gt;{$field} = \@logins;
+        }
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     my $retval;
</span><span class="lines">@@ -1349,55 +1597,55 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # Skip confirmation if we were told to, or if we don't need to confirm.
</span><del>-    return $retval if ($behavior == MATCH_SKIP_CONFIRM || !$need_confirm);
</del><ins>+    if ($behavior == MATCH_SKIP_CONFIRM || !$need_confirm) {
+        return wantarray ? ($retval, \@non_conclusive_fields) : $retval;
+    }
</ins><span class="cx"> 
</span><span class="cx">     my $template = Bugzilla-&gt;template;
</span><ins>+    my $cgi = Bugzilla-&gt;cgi;
</ins><span class="cx">     my $vars = {};
</span><span class="cx"> 
</span><del>-    $vars-&gt;{'script'}        = Bugzilla-&gt;cgi-&gt;url(-relative =&gt; 1); # for self-referencing URLs
</del><ins>+    $vars-&gt;{'script'}        = $cgi-&gt;url(-relative =&gt; 1); # for self-referencing URLs
</ins><span class="cx">     $vars-&gt;{'fields'}        = $fields; # fields being matched
</span><span class="cx">     $vars-&gt;{'matches'}       = $matches; # matches that were made
</span><span class="cx">     $vars-&gt;{'matchsuccess'}  = $matchsuccess; # continue or fail
</span><span class="cx">     $vars-&gt;{'matchmultiple'} = $match_multiple;
</span><span class="cx"> 
</span><del>-    print Bugzilla-&gt;cgi-&gt;header();
</del><ins>+    print $cgi-&gt;header();
</ins><span class="cx"> 
</span><span class="cx">     $template-&gt;process(&quot;global/confirm-user-match.html.tmpl&quot;, $vars)
</span><span class="cx">       || ThrowTemplateError($template-&gt;error());
</span><del>-
</del><span class="cx">     exit;
</span><span class="cx"> 
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-# Changes in some fields automatically trigger events. The 'field names' are
-# from the fielddefs table. We really should be using proper field names 
-# throughout.
</del><ins>+# Changes in some fields automatically trigger events. The field names are
+# from the fielddefs table.
</ins><span class="cx"> our %names_to_events = (
</span><del>-    'Resolution'             =&gt; EVT_OPENED_CLOSED,
-    'Keywords'               =&gt; EVT_KEYWORD,
-    'CC'                     =&gt; EVT_CC,
-    'Severity'               =&gt; EVT_PROJ_MANAGEMENT,
-    'Priority'               =&gt; EVT_PROJ_MANAGEMENT,
-    'Status'                 =&gt; EVT_PROJ_MANAGEMENT,
-    'Target Milestone'       =&gt; EVT_PROJ_MANAGEMENT,
-    'Attachment description' =&gt; EVT_ATTACHMENT_DATA,
-    'Attachment mime type'   =&gt; EVT_ATTACHMENT_DATA,
-    'Attachment is patch'    =&gt; EVT_ATTACHMENT_DATA,
-    'Depends on'             =&gt; EVT_DEPEND_BLOCK,
-    'Blocks'                 =&gt; EVT_DEPEND_BLOCK);
</del><ins>+    'resolution'              =&gt; EVT_OPENED_CLOSED,
+    'keywords'                =&gt; EVT_KEYWORD,
+    'cc'                      =&gt; EVT_CC,
+    'bug_severity'            =&gt; EVT_PROJ_MANAGEMENT,
+    'priority'                =&gt; EVT_PROJ_MANAGEMENT,
+    'bug_status'              =&gt; EVT_PROJ_MANAGEMENT,
+    'target_milestone'        =&gt; EVT_PROJ_MANAGEMENT,
+    'attachments.description' =&gt; EVT_ATTACHMENT_DATA,
+    'attachments.mimetype'    =&gt; EVT_ATTACHMENT_DATA,
+    'attachments.ispatch'     =&gt; EVT_ATTACHMENT_DATA,
+    'dependson'               =&gt; EVT_DEPEND_BLOCK,
+    'blocked'                 =&gt; EVT_DEPEND_BLOCK);
</ins><span class="cx"> 
</span><span class="cx"> # Returns true if the user wants mail for a given bug change.
</span><span class="cx"> # Note: the &quot;+&quot; signs before the constants suppress bareword quoting.
</span><span class="cx"> sub wants_bug_mail {
</span><span class="cx">     my $self = shift;
</span><del>-    my ($bug_id, $relationship, $fieldDiffs, $commentField, $dependencyText,
-        $changer, $bug_is_new) = @_;
</del><ins>+    my ($bug, $relationship, $fieldDiffs, $comments, $dep_mail, $changer) = @_;
</ins><span class="cx"> 
</span><span class="cx">     # Make a list of the events which have happened during this bug change,
</span><span class="cx">     # from the point of view of this user.    
</span><span class="cx">     my %events;    
</span><del>-    foreach my $ref (@$fieldDiffs) {
-        my ($who, $whoname, $fieldName, $when, $old, $new) = @$ref;
</del><ins>+    foreach my $change (@$fieldDiffs) {
+        my $fieldName = $change-&gt;{field_name};
</ins><span class="cx">         # A change to any of the above fields sets the corresponding event
</span><span class="cx">         if (defined($names_to_events{$fieldName})) {
</span><span class="cx">             $events{$names_to_events{$fieldName}} = 1;
</span><span class="lines">@@ -1409,16 +1657,16 @@
</span><span class="cx"> 
</span><span class="cx">         # If the user is in a particular role and the value of that role
</span><span class="cx">         # changed, we need the ADDED_REMOVED event.
</span><del>-        if (($fieldName eq &quot;AssignedTo&quot; &amp;&amp; $relationship == REL_ASSIGNEE) ||
-            ($fieldName eq &quot;QAContact&quot; &amp;&amp; $relationship == REL_QA)) 
</del><ins>+        if (($fieldName eq &quot;assigned_to&quot; &amp;&amp; $relationship == REL_ASSIGNEE) ||
+            ($fieldName eq &quot;qa_contact&quot; &amp;&amp; $relationship == REL_QA))
</ins><span class="cx">         {
</span><span class="cx">             $events{+EVT_ADDED_REMOVED} = 1;
</span><span class="cx">         }
</span><span class="cx">         
</span><del>-        if ($fieldName eq &quot;CC&quot;) {
</del><ins>+        if ($fieldName eq &quot;cc&quot;) {
</ins><span class="cx">             my $login = $self-&gt;login;
</span><del>-            my $inold = ($old =~ /^(.*,\s*)?\Q$login\E(,.*)?$/);
-            my $innew = ($new =~ /^(.*,\s*)?\Q$login\E(,.*)?$/);
</del><ins>+            my $inold = ($change-&gt;{old} =~ /^(.*,\s*)?\Q$login\E(,.*)?$/);
+            my $innew = ($change-&gt;{new} =~ /^(.*,\s*)?\Q$login\E(,.*)?$/);
</ins><span class="cx">             if ($inold != $innew)
</span><span class="cx">             {
</span><span class="cx">                 $events{+EVT_ADDED_REMOVED} = 1;
</span><span class="lines">@@ -1426,26 +1674,30 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    # You role is new if the bug itself is.
-    # Only makes sense for the assignee, QA contact and the CC list.
-    if ($bug_is_new
-        &amp;&amp; ($relationship == REL_ASSIGNEE
</del><ins>+    if (!$bug-&gt;lastdiffed) {
+        # Notify about new bugs.
+        $events{+EVT_BUG_CREATED} = 1;
+
+        # You role is new if the bug itself is.
+        # Only makes sense for the assignee, QA contact and the CC list.
+        if ($relationship == REL_ASSIGNEE
</ins><span class="cx">             || $relationship == REL_QA
</span><del>-            || $relationship == REL_CC))
-    {
-        $events{+EVT_ADDED_REMOVED} = 1;
</del><ins>+            || $relationship == REL_CC)
+        {
+            $events{+EVT_ADDED_REMOVED} = 1;
+        }
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if ($commentField =~ /Created an attachment \(/) {
</del><ins>+    if (grep { $_-&gt;type == CMT_ATTACHMENT_CREATED } @$comments) {
</ins><span class="cx">         $events{+EVT_ATTACHMENT} = 1;
</span><span class="cx">     }
</span><del>-    elsif ($commentField ne '') {
</del><ins>+    elsif (defined($$comments[0])) {
</ins><span class="cx">         $events{+EVT_COMMENT} = 1;
</span><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     # Dependent changed bugmails must have an event to ensure the bugmail is
</span><span class="cx">     # emailed.
</span><del>-    if ($dependencyText ne '') {
</del><ins>+    if ($dep_mail) {
</ins><span class="cx">         $events{+EVT_DEPEND_BLOCK} = 1;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -1458,23 +1710,12 @@
</span><span class="cx">     # 
</span><span class="cx">     # We do them separately because if _any_ of them are set, we don't want
</span><span class="cx">     # the mail.
</span><del>-    if ($wants_mail &amp;&amp; $changer &amp;&amp; ($self-&gt;login eq $changer)) {
</del><ins>+    if ($wants_mail &amp;&amp; $changer &amp;&amp; ($self-&gt;id == $changer-&gt;id)) {
</ins><span class="cx">         $wants_mail &amp;= $self-&gt;wants_mail([EVT_CHANGED_BY_ME], $relationship);
</span><span class="cx">     }    
</span><span class="cx">     
</span><del>-    if ($wants_mail) {
-        my $dbh = Bugzilla-&gt;dbh;
-        # We don't create a Bug object from the bug_id here because we only
-        # need one piece of information, and doing so (as of 2004-11-23) slows
-        # down bugmail sending by a factor of 2. If Bug creation was more
-        # lazy, this might not be so bad.
-        my $bug_status = $dbh-&gt;selectrow_array('SELECT bug_status
-                                                FROM bugs WHERE bug_id = ?',
-                                                undef, $bug_id);
-
-        if ($bug_status eq &quot;UNCONFIRMED&quot;) {
-            $wants_mail &amp;= $self-&gt;wants_mail([EVT_UNCONFIRMED], $relationship);
-        }
</del><ins>+    if ($wants_mail &amp;&amp; $bug-&gt;bug_status eq 'UNCONFIRMED') {
+        $wants_mail &amp;= $self-&gt;wants_mail([EVT_UNCONFIRMED], $relationship);
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     return $wants_mail;
</span><span class="lines">@@ -1502,29 +1743,37 @@
</span><span class="cx">     # Skip DB query if relationship is explicit
</span><span class="cx">     return 1 if $relationship == REL_GLOBAL_WATCHER;
</span><span class="cx"> 
</span><ins>+    my $wants_mail = grep { $self-&gt;mail_settings-&gt;{$relationship}{$_} } @$events;
+    return $wants_mail ? 1 : 0;
+}
+
+sub mail_settings {
+    my $self = shift;
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx"> 
</span><del>-    my $wants_mail = 
-        $dbh-&gt;selectrow_array('SELECT 1
-                                 FROM email_setting
-                                WHERE user_id = ?
-                                  AND relationship = ?
-                                  AND event IN (' . join(',', @$events) . ') ' .
-                                      $dbh-&gt;sql_limit(1),
-                              undef, ($self-&gt;id, $relationship));
</del><ins>+    if (!defined $self-&gt;{'mail_settings'}) {
+        my $data =
+          $dbh-&gt;selectall_arrayref('SELECT relationship, event FROM email_setting
+                                    WHERE user_id = ?', undef, $self-&gt;id);
+        my %mail;
+        # The hash is of the form $mail{$relationship}{$event} = 1.
+        $mail{$_-&gt;[0]}{$_-&gt;[1]} = 1 foreach @$data;
</ins><span class="cx"> 
</span><del>-    return defined($wants_mail) ? 1 : 0;
</del><ins>+        $self-&gt;{'mail_settings'} = \%mail;
+    }
+    return $self-&gt;{'mail_settings'};
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub is_mover {
</del><ins>+sub has_audit_entries {
</ins><span class="cx">     my $self = shift;
</span><ins>+    my $dbh = Bugzilla-&gt;dbh;
</ins><span class="cx"> 
</span><del>-    if (!defined $self-&gt;{'is_mover'}) {
-        my @movers = map { trim($_) } split(',', Bugzilla-&gt;params-&gt;{'movers'});
-        $self-&gt;{'is_mover'} = ($self-&gt;id
-                               &amp;&amp; lsearch(\@movers, $self-&gt;login) != -1);
</del><ins>+    if (!exists $self-&gt;{'has_audit_entries'}) {
+        $self-&gt;{'has_audit_entries'} =
+            $dbh-&gt;selectrow_array('SELECT 1 FROM audit_log WHERE user_id = ? ' .
+                                   $dbh-&gt;sql_limit(1), undef, $self-&gt;id);
</ins><span class="cx">     }
</span><del>-    return $self-&gt;{'is_mover'};
</del><ins>+    return $self-&gt;{'has_audit_entries'};
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub is_insider {
</span><span class="lines">@@ -1542,12 +1791,23 @@
</span><span class="cx">     my $self = shift;
</span><span class="cx"> 
</span><span class="cx">     if (!defined $self-&gt;{'is_global_watcher'}) {
</span><del>-        my @watchers = split(/[,\s]+/, Bugzilla-&gt;params-&gt;{'globalwatchers'});
</del><ins>+        my @watchers = split(/[,;]+/, Bugzilla-&gt;params-&gt;{'globalwatchers'});
</ins><span class="cx">         $self-&gt;{'is_global_watcher'} = scalar(grep { $_ eq $self-&gt;login } @watchers) ? 1 : 0;
</span><span class="cx">     }
</span><span class="cx">     return  $self-&gt;{'is_global_watcher'};
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub is_timetracker {
+    my $self = shift;
+
+    if (!defined $self-&gt;{'is_timetracker'}) {
+        my $tt_group = Bugzilla-&gt;params-&gt;{'timetrackinggroup'};
+        $self-&gt;{'is_timetracker'} =
+            ($tt_group &amp;&amp; $self-&gt;in_group($tt_group)) ? 1 : 0;
+    }
+    return $self-&gt;{'is_timetracker'};
+}
+
</ins><span class="cx"> sub get_userlist {
</span><span class="cx">     my $self = shift;
</span><span class="cx"> 
</span><span class="lines">@@ -1567,7 +1827,7 @@
</span><span class="cx">                   &quot;AND group_id IN(&quot; .
</span><span class="cx">                   join(', ', (-1, @{$self-&gt;visible_groups_inherited})) . &quot;)&quot;;
</span><span class="cx">     }
</span><del>-    $query    .= &quot; WHERE disabledtext = '' &quot;;
</del><ins>+    $query    .= &quot; WHERE is_enabled = 1 &quot;;
</ins><span class="cx">     $query    .= $dbh-&gt;sql_group_by('userid', 'login_name, realname');
</span><span class="cx"> 
</span><span class="cx">     my $sth = $dbh-&gt;prepare($query);
</span><span class="lines">@@ -1597,7 +1857,9 @@
</span><span class="cx">     my $user = $class-&gt;SUPER::create(@_);
</span><span class="cx"> 
</span><span class="cx">     # Turn on all email for the new user
</span><del>-    foreach my $rel (RELATIONSHIPS) {
</del><ins>+    require Bugzilla::BugMail;
+    my %relationships = Bugzilla::BugMail::relationships();
+    foreach my $rel (keys %relationships) {
</ins><span class="cx">         foreach my $event (POS_EVENTS, NEG_EVENTS) {
</span><span class="cx">             # These &quot;exceptions&quot; define the default email preferences.
</span><span class="cx">             # 
</span><span class="lines">@@ -1635,6 +1897,55 @@
</span><span class="cx">     return $user;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+###########################
+# Account Lockout Methods #
+###########################
+
+sub account_is_locked_out {
+    my $self = shift;
+    my $login_failures = scalar @{ $self-&gt;account_ip_login_failures };
+    return $login_failures &gt;= MAX_LOGIN_ATTEMPTS ? 1 : 0;
+}
+
+sub note_login_failure {
+    my $self = shift;
+    my $ip_addr = remote_ip();
+    trick_taint($ip_addr);
+    Bugzilla-&gt;dbh-&gt;do(&quot;INSERT INTO login_failure (user_id, ip_addr, login_time)
+                       VALUES (?, ?, LOCALTIMESTAMP(0))&quot;,
+                      undef, $self-&gt;id, $ip_addr);
+    delete $self-&gt;{account_ip_login_failures};
+}
+
+sub clear_login_failures {
+    my $self = shift;
+    my $ip_addr = remote_ip();
+    trick_taint($ip_addr);
+    Bugzilla-&gt;dbh-&gt;do(
+        'DELETE FROM login_failure WHERE user_id = ? AND ip_addr = ?',
+        undef, $self-&gt;id, $ip_addr);
+    delete $self-&gt;{account_ip_login_failures};
+}
+
+sub account_ip_login_failures {
+    my $self = shift;
+    my $dbh = Bugzilla-&gt;dbh;
+    my $time = $dbh-&gt;sql_date_math('LOCALTIMESTAMP(0)', '-', 
+                                   LOGIN_LOCKOUT_INTERVAL, 'MINUTE');
+    my $ip_addr = remote_ip();
+    trick_taint($ip_addr);
+    $self-&gt;{account_ip_login_failures} ||= Bugzilla-&gt;dbh-&gt;selectall_arrayref(
+        &quot;SELECT login_time, ip_addr, user_id FROM login_failure
+          WHERE user_id = ? AND login_time &gt; $time
+                AND ip_addr = ?
+       ORDER BY login_time&quot;, {Slice =&gt; {}}, $self-&gt;id, $ip_addr);
+    return $self-&gt;{account_ip_login_failures};
+}
+
+###############
+# Subroutines #
+###############
+
</ins><span class="cx"> sub is_available_username {
</span><span class="cx">     my ($username, $old_username) = @_;
</span><span class="cx"> 
</span><span class="lines">@@ -1660,7 +1971,7 @@
</span><span class="cx">                     $dbh-&gt;sql_position(q{':'}, 'eventdata') . &quot;-  1)) = ?)
</span><span class="cx">              OR (tokentype = 'emailnew'
</span><span class="cx">                 AND SUBSTRING(eventdata, (&quot; .
</span><del>-                    $dbh-&gt;sql_position(q{':'}, 'eventdata') . &quot;+ 1)) = ?)&quot;,
</del><ins>+                    $dbh-&gt;sql_position(q{':'}, 'eventdata') . &quot;+ 1), LENGTH(eventdata)) = ?)&quot;,
</ins><span class="cx">          undef, ($username, $username));
</span><span class="cx"> 
</span><span class="cx">     if ($eventdata) {
</span><span class="lines">@@ -1674,15 +1985,57 @@
</span><span class="cx">     return 1;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub check_account_creation_enabled {
+    my $self = shift;
+
+    # If we're using e.g. LDAP for login, then we can't create a new account.
+    $self-&gt;authorizer-&gt;user_can_create_account
+      || ThrowUserError('auth_cant_create_account');
+
+    Bugzilla-&gt;params-&gt;{'createemailregexp'}
+      || ThrowUserError('account_creation_disabled');
+}
+
+sub check_and_send_account_creation_confirmation {
+    my ($self, $login) = @_;
+
+    $login = $self-&gt;check_login_name_for_creation($login);
+    my $creation_regexp = Bugzilla-&gt;params-&gt;{'createemailregexp'};
+
+    if ($login !~ /$creation_regexp/i) {
+        ThrowUserError('account_creation_restricted');
+    }
+
+    # Create and send a token for this new account.
+    require Bugzilla::Token;
+    Bugzilla::Token::issue_new_user_account_token($login);
+}
+
+# This is used in a few performance-critical areas where we don't want to
+# do check() and pull all the user data from the database.
</ins><span class="cx"> sub login_to_id {
</span><span class="cx">     my ($login, $throw_error) = @_;
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><del>-    # No need to validate $login -- it will be used by the following SELECT
-    # statement only, so it's safe to simply trick_taint.
-    trick_taint($login);
-    my $user_id = $dbh-&gt;selectrow_array(&quot;SELECT userid FROM profiles WHERE &quot; .
-                                        $dbh-&gt;sql_istrcmp('login_name', '?'),
-                                        undef, $login);
</del><ins>+    my $cache = Bugzilla-&gt;request_cache-&gt;{user_login_to_id} ||= {};
+
+    # We cache lookups because this function showed up as taking up a 
+    # significant amount of time in profiles of xt/search.t. However,
+    # for users that don't exist, we re-do the check every time, because
+    # otherwise we break is_available_username.
+    my $user_id;
+    if (defined $cache-&gt;{$login}) {
+        $user_id = $cache-&gt;{$login};
+    }
+    else {
+        # No need to validate $login -- it will be used by the following SELECT
+        # statement only, so it's safe to simply trick_taint.
+        trick_taint($login);
+        $user_id = $dbh-&gt;selectrow_array(
+            &quot;SELECT userid FROM profiles 
+              WHERE &quot; . $dbh-&gt;sql_istrcmp('login_name', '?'), undef, $login);
+        $cache-&gt;{$login} = $user_id;
+    }
+
</ins><span class="cx">     if ($user_id) {
</span><span class="cx">         return $user_id;
</span><span class="cx">     } elsif ($throw_error) {
</span><span class="lines">@@ -1708,11 +2061,22 @@
</span><span class="cx"> 
</span><span class="cx">     if (length($password) &lt; USER_PASSWORD_MIN_LENGTH) {
</span><span class="cx">         ThrowUserError('password_too_short');
</span><del>-    } elsif (length($password) &gt; USER_PASSWORD_MAX_LENGTH) {
-        ThrowUserError('password_too_long');
</del><span class="cx">     } elsif ((defined $matchpassword) &amp;&amp; ($password ne $matchpassword)) {
</span><span class="cx">         ThrowUserError('passwords_dont_match');
</span><span class="cx">     }
</span><ins>+    
+    my $complexity_level = Bugzilla-&gt;params-&gt;{password_complexity};
+    if ($complexity_level eq 'letters_numbers_specialchars') {
+        ThrowUserError('password_not_complex')
+          if ($password !~ /\w/ || $password !~ /\d/ || $password !~ /[[:punct:]]/);
+    } elsif ($complexity_level eq 'letters_numbers') {
+        ThrowUserError('password_not_complex')
+          if ($password !~ /[[:lower:]]/ || $password !~ /[[:upper:]]/ || $password !~ /\d/);
+    } elsif ($complexity_level eq 'mixed_letters') {
+        ThrowUserError('password_not_complex')
+          if ($password !~ /[[:lower:]]/ || $password !~ /[[:upper:]]/);
+    }
+
</ins><span class="cx">     # Having done these checks makes us consider the password untainted.
</span><span class="cx">     trick_taint($_[0]);
</span><span class="cx">     return 1;
</span><span class="lines">@@ -1784,6 +2148,18 @@
</span><span class="cx"> 
</span><span class="cx"> =head1 METHODS
</span><span class="cx"> 
</span><ins>+=head2 Constructors
+
+=over
+
+=item C&lt;super_user&gt;
+
+Returns a user who is in all groups, but who does not really exist in the
+database. Used for non-web scripts like L&lt;checksetup&gt; that need to make 
+database changes and so on.
+
+=back
+
</ins><span class="cx"> =head2 Saved and Shared Queries
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="lines">@@ -1816,8 +2192,36 @@
</span><span class="cx"> An arrayref of group ids. The user can share their own queries with these
</span><span class="cx"> groups.
</span><span class="cx"> 
</span><ins>+=item C&lt;tags&gt;
+
+Returns a hashref with tag IDs as key, and a hashref with tag 'id',
+'name' and 'bug_count' as value.
+
</ins><span class="cx"> =back
</span><span class="cx"> 
</span><ins>+=head2 Account Lockout
+
+=over
+
+=item C&lt;account_is_locked_out&gt;
+
+Returns C&lt;1&gt; if the account has failed to log in too many times recently,
+and thus is locked out for a period of time. Returns C&lt;0&gt; otherwise.
+
+=item C&lt;account_ip_login_failures&gt;
+
+Returns an arrayref of hashrefs, that contains information about the recent
+times that this account has failed to log in from the current remote IP.
+The hashes contain C&lt;ip_addr&gt;, C&lt;login_time&gt;, and C&lt;user_id&gt;.
+
+=item C&lt;note_login_failure&gt;
+
+This notes that this account has failed to log in, and stores the fact
+in the database. The storing happens immediately, it does not wait for
+you to call C&lt;update&gt;.
+
+=back
+
</ins><span class="cx"> =head2 Other Methods
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="lines">@@ -1886,12 +2290,19 @@
</span><span class="cx"> is_default     - a boolean to indicate whether the user has chosen to make
</span><span class="cx">                  a preference for themself or use the site default.
</span><span class="cx"> 
</span><ins>+=item C&lt;setting(name)&gt;
+
+Returns the value for the specified setting.
+
+=item C&lt;timezone&gt;
+
+Returns the timezone used to display dates and times to the user,
+as a DateTime::TimeZone object.
+
</ins><span class="cx"> =item C&lt;groups&gt;
</span><span class="cx"> 
</span><del>-Returns a hashref of group names for groups the user is a member of. The keys
-are the names of the groups, whilst the values are the respective group ids.
-(This is so that a set of all groupids for groups the user is in can be
-obtained by C&lt;values(%{$user-E&lt;gt&gt;groups})&gt;.)
</del><ins>+Returns an arrayref of L&lt;Bugzilla::Group&gt; objects representing
+groups that this user is a member of.
</ins><span class="cx"> 
</span><span class="cx"> =item C&lt;groups_as_string&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -1899,6 +2310,13 @@
</span><span class="cx"> the user is not a member of any groups, returns &quot;-1&quot;. This is most often used
</span><span class="cx"> within an SQL IN() function.
</span><span class="cx"> 
</span><ins>+=item C&lt;groups_in_sql&gt;
+
+This returns an C&lt;IN&gt; clause for SQL, containing either all of the groups
+the user is in, or C&lt;-1&gt; if the user is in no groups. This takes one
+argument--the name of the SQL field that should be on the left-hand-side
+of the C&lt;IN&gt; statement, which defaults to C&lt;group_id&gt; if not specified.
+
</ins><span class="cx"> =item C&lt;in_group($group_name, $product_id)&gt;
</span><span class="cx"> 
</span><span class="cx"> Determines whether or not a user is in the given group by name.
</span><span class="lines">@@ -1911,12 +2329,11 @@
</span><span class="cx"> 
</span><span class="cx"> =item C&lt;bless_groups&gt;
</span><span class="cx"> 
</span><del>-Returns an arrayref of hashes of C&lt;groups&gt; entries, where the keys of each hash
-are the names of C&lt;id&gt;, C&lt;name&gt; and C&lt;description&gt; columns of the C&lt;groups&gt;
-table.
</del><ins>+Returns an arrayref of L&lt;Bugzilla::Group&gt; objects.
+
</ins><span class="cx"> The arrayref consists of the groups the user can bless, taking into account
</span><span class="cx"> that having editusers permissions means that you can bless all groups, and
</span><del>-that you need to be aware of a group in order to bless a group.
</del><ins>+that you need to be able to see a group in order to bless it.
</ins><span class="cx"> 
</span><span class="cx"> =item C&lt;get_products_by_permission($group)&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -1951,6 +2368,12 @@
</span><span class="cx"> user may be placed into different groups, based on a new email regexp. This
</span><span class="cx"> method should be called in such a case to force reresolution of these groups.
</span><span class="cx"> 
</span><ins>+=item C&lt;clear_product_cache&gt;
+
+Clears the stored values for L&lt;/get_selectable_products&gt;, 
+L&lt;/get_enterable_products&gt;, etc. so that their data will be read from
+the database again. Used mostly by L&lt;Bugzilla::Product&gt;.
+
</ins><span class="cx"> =item C&lt;get_selectable_products&gt;
</span><span class="cx"> 
</span><span class="cx">  Description: Returns all products the user is allowed to access. This list
</span><span class="lines">@@ -1998,6 +2421,21 @@
</span><span class="cx"> 
</span><span class="cx">  Returns:     an array of product objects.
</span><span class="cx"> 
</span><ins>+=item C&lt;can_access_product($product)&gt;
+
+Returns 1 if the user can search or enter bugs into the specified product
+(either a L&lt;Bugzilla::Product&gt; or a product name), and 0 if the user should
+not be aware of the existence of the product.
+
+=item C&lt;get_accessible_products&gt;
+
+ Description: Returns an array of product objects the user can search
+              or enter bugs against.
+
+ Params:      none
+
+ Returns:     an array of product objects.
+
</ins><span class="cx"> =item C&lt;check_can_admin_product($product_name)&gt;
</span><span class="cx"> 
</span><span class="cx">  Description: Checks whether the user is allowed to administrate the product.
</span><span class="lines">@@ -2006,6 +2444,21 @@
</span><span class="cx"> 
</span><span class="cx">  Returns:     On success, a product object. On failure, an error is thrown.
</span><span class="cx"> 
</span><ins>+=item C&lt;check_can_admin_flagtype($flagtype_id)&gt;
+
+ Description: Checks whether the user is allowed to edit properties of the flag type.
+              If the flag type is also used by some products for which the user
+              hasn't editcomponents privs, then the user is only allowed to edit
+              the inclusion and exclusion lists for products he can administrate.
+
+ Params:      $flagtype_id - a flag type ID.
+
+ Returns:     On success, a flag type object. On failure, an error is thrown.
+              In list context, a boolean indicating whether the user can edit
+              all properties of the flag type is also returned. The boolean
+              is false if the user can only edit the inclusion and exclusions
+              lists.
+
</ins><span class="cx"> =item C&lt;can_request_flag($flag_type)&gt;
</span><span class="cx"> 
</span><span class="cx">  Description: Checks whether the user can request flags of the given type.
</span><span class="lines">@@ -2030,14 +2483,6 @@
</span><span class="cx"> containing the login, identity and visibility.  Users that are not visible to this
</span><span class="cx"> user will have 'visible' set to zero.
</span><span class="cx"> 
</span><del>-=item C&lt;flatten_group_membership&gt;
-
-Accepts a list of groups and returns a list of all the groups whose members 
-inherit membership in any group on the list.  So, we can determine if a user
-is in any of the groups input to flatten_group_membership by querying the
-user_group_map for any user with DIRECT or REGEXP membership IN() the list
-of groups returned.
-
</del><span class="cx"> =item C&lt;direct_group_membership&gt;
</span><span class="cx"> 
</span><span class="cx"> Returns a reference to an array of group objects. Groups the user belong to
</span><span class="lines">@@ -2082,12 +2527,6 @@
</span><span class="cx"> more general than C&lt;wants_bug_mail&gt;, allowing you to check e.g. permissions
</span><span class="cx"> for flag mail.
</span><span class="cx"> 
</span><del>-=item C&lt;is_mover&gt;
-
-Returns true if the user is in the list of users allowed to move bugs
-to another database. Note that this method doesn't check whether bug
-moving is enabled.
-
</del><span class="cx"> =item C&lt;is_insider&gt;
</span><span class="cx"> 
</span><span class="cx"> Returns true if the user can access private comments and attachments,
</span><span class="lines">@@ -2128,6 +2567,17 @@
</span><span class="cx"> Takes a username as its only argument. Throws an error if there is no
</span><span class="cx"> user with that username. Returns a C&lt;Bugzilla::User&gt; object.
</span><span class="cx"> 
</span><ins>+=item C&lt;check_account_creation_enabled&gt;
+
+Checks that users can create new user accounts, and throws an error
+if user creation is disabled.
+
+=item C&lt;check_and_send_account_creation_confirmation($login)&gt;
+
+If the user request for a new account passes validation checks, an email
+is sent to this user for confirmation. Otherwise an error is thrown
+indicating why the request has been rejected.
+
</ins><span class="cx"> =item C&lt;is_available_username&gt;
</span><span class="cx"> 
</span><span class="cx"> Returns a boolean indicating whether or not the supplied username is
</span><span class="lines">@@ -2172,8 +2622,51 @@
</span><span class="cx"> If a second password is passed in, this function also verifies that
</span><span class="cx"> the two passwords match.
</span><span class="cx"> 
</span><ins>+=item C&lt;match_field($data, $fields, $behavior)&gt;
+
+=over
+
+=item B&lt;Description&gt;
+
+Wrapper for the C&lt;match()&gt; function.
+
+=item B&lt;Params&gt;
+
+=over
+
+=item C&lt;$fields&gt; - A hashref with field names as keys and a hash as values.
+Each hash is of the form { 'type' =&gt; 'single|multi' }, which specifies
+whether the field can take a single login name only or several.
+
+=item C&lt;$data&gt; (optional) - A hashref with field names as keys and field values
+as values. If undefined, C&lt;Bugzilla-E&lt;gt&gt;input_params&gt; is used.
+
+=item C&lt;$behavior&gt; (optional) - If set to C&lt;MATCH_SKIP_CONFIRM&gt;, no confirmation
+screen is displayed. In that case, the fields which don't match a unique user
+are left undefined. If not set, a confirmation screen is displayed if at
+least one field doesn't match any login name or match more than one.
+
</ins><span class="cx"> =back
</span><span class="cx"> 
</span><ins>+=item B&lt;Returns&gt;
+
+If the third parameter is set to C&lt;MATCH_SKIP_CONFIRM&gt;, the function returns
+either C&lt;USER_MATCH_SUCCESS&gt; if all fields can be set unambiguously,
+C&lt;USER_MATCH_FAILED&gt; if at least one field doesn't match any user account,
+or C&lt;USER_MATCH_MULTIPLE&gt; if some fields match more than one user account.
+
+If the third parameter is not set, then if all fields could be set
+unambiguously, nothing is returned, else a confirmation page is displayed.
+
+=item B&lt;Note&gt;
+
+This function must be called early in a script, before anything external
+is done with the data.
+
+=back
+
+=back
+
</ins><span class="cx"> =head1 SEE ALSO
</span><span class="cx"> 
</span><span class="cx"> L&lt;Bugzilla|Bugzilla&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaUtilpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Util.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Util.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Util.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -31,37 +31,37 @@
</span><span class="cx"> use strict;
</span><span class="cx"> 
</span><span class="cx"> use base qw(Exporter);
</span><del>-@Bugzilla::Util::EXPORT = qw(is_tainted trick_taint detaint_natural
</del><ins>+@Bugzilla::Util::EXPORT = qw(trick_taint detaint_natural
</ins><span class="cx">                              detaint_signed
</span><span class="cx">                              html_quote url_quote xml_quote
</span><del>-                             css_class_quote html_light_quote url_decode
-                             i_am_cgi get_netaddr correct_urlbase
-                             lsearch ssl_require_redirect use_attachbase
-                             diff_arrays diff_strings
</del><ins>+                             css_class_quote html_light_quote
+                             i_am_cgi correct_urlbase remote_ip validate_ip
+                             do_ssl_redirect_if_required use_attachbase
+                             diff_arrays on_main_db
</ins><span class="cx">                              trim wrap_hard wrap_comment find_wrap_point
</span><del>-                             format_time format_time_decimal validate_date
-                             validate_time
</del><ins>+                             format_time validate_date validate_time datetime_from
</ins><span class="cx">                              file_mod_time is_7bit_clean
</span><span class="cx">                              bz_crypt generate_random_password
</span><span class="cx">                              validate_email_syntax clean_text
</span><del>-                             get_text disable_utf8);
</del><ins>+                             get_text template_var disable_utf8
+                             detect_encoding);
</ins><span class="cx"> 
</span><span class="cx"> use Bugzilla::Constants;
</span><ins>+use Bugzilla::RNG qw(irand);
</ins><span class="cx"> 
</span><span class="cx"> use Date::Parse;
</span><span class="cx"> use Date::Format;
</span><ins>+use DateTime;
+use DateTime::TimeZone;
+use Digest;
+use Email::Address;
+use List::Util qw(first);
+use Scalar::Util qw(tainted blessed);
+use Template::Filters;
</ins><span class="cx"> use Text::Wrap;
</span><ins>+use Encode qw(encode decode resolve_alias);
+use Encode::Guess;
</ins><span class="cx"> 
</span><del>-# This is from the perlsec page, slightly modified to remove a warning
-# From that page:
-#      This function makes use of the fact that the presence of
-#      tainted data anywhere within an expression renders the
-#      entire expression tainted.
-# Don't ask me how it works...
-sub is_tainted {
-    return not eval { my $foo = join('',@_), kill 0; 1; };
-}
-
</del><span class="cx"> sub trick_taint {
</span><span class="cx">     require Carp;
</span><span class="cx">     Carp::confess(&quot;Undef to trick_taint&quot;) unless defined $_[0];
</span><span class="lines">@@ -72,26 +72,48 @@
</span><span class="cx"> 
</span><span class="cx"> sub detaint_natural {
</span><span class="cx">     my $match = $_[0] =~ /^(\d+)$/;
</span><del>-    $_[0] = $match ? $1 : undef;
</del><ins>+    $_[0] = $match ? int($1) : undef;
</ins><span class="cx">     return (defined($_[0]));
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub detaint_signed {
</span><span class="cx">     my $match = $_[0] =~ /^([-+]?\d+)$/;
</span><del>-    $_[0] = $match ? $1 : undef;
-    # Remove any leading plus sign.
-    if (defined($_[0]) &amp;&amp; $_[0] =~ /^\+(\d+)$/) {
-        $_[0] = $1;
-    }
</del><ins>+    # The &quot;int()&quot; call removes any leading plus sign.
+    $_[0] = $match ? int($1) : undef;
</ins><span class="cx">     return (defined($_[0]));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# Bug 120030: Override html filter to obscure the '@' in user
+#             visible strings.
+# Bug 319331: Handle BiDi disruptions.
</ins><span class="cx"> sub html_quote {
</span><del>-    my ($var) = (@_);
-    $var =~ s/\&amp;/\&amp;amp;/g;
-    $var =~ s/&lt;/\&amp;lt;/g;
-    $var =~ s/&gt;/\&amp;gt;/g;
-    $var =~ s/\&quot;/\&amp;quot;/g;
</del><ins>+    my ($var) = Template::Filters::html_filter(@_);
+    # Obscure '@'.
+    $var =~ s/\@/\&amp;#64;/g;
+    if (Bugzilla-&gt;params-&gt;{'utf8'}) {
+        # Remove the following characters because they're
+        # influencing BiDi:
+        # --------------------------------------------------------
+        # |Code  |Name                      |UTF-8 representation|
+        # |------|--------------------------|--------------------|
+        # |U+202a|Left-To-Right Embedding   |0xe2 0x80 0xaa      |
+        # |U+202b|Right-To-Left Embedding   |0xe2 0x80 0xab      |
+        # |U+202c|Pop Directional Formatting|0xe2 0x80 0xac      |
+        # |U+202d|Left-To-Right Override    |0xe2 0x80 0xad      |
+        # |U+202e|Right-To-Left Override    |0xe2 0x80 0xae      |
+        # --------------------------------------------------------
+        #
+        # The following are characters influencing BiDi, too, but
+        # they can be spared from filtering because they don't
+        # influence more than one character right or left:
+        # --------------------------------------------------------
+        # |Code  |Name                      |UTF-8 representation|
+        # |------|--------------------------|--------------------|
+        # |U+200e|Left-To-Right Mark        |0xe2 0x80 0x8e      |
+        # |U+200f|Right-To-Left Mark        |0xe2 0x80 0x8f      |
+        # --------------------------------------------------------
+        $var =~ s/[\x{202a}-\x{202e}]//g;
+    }
</ins><span class="cx">     return $var;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -103,12 +125,7 @@
</span><span class="cx">                    dfn samp kbd big small sub sup tt dd dt dl ul li ol
</span><span class="cx">                    fieldset legend);
</span><span class="cx"> 
</span><del>-    # Are HTML::Scrubber and HTML::Parser installed?
-    eval { require HTML::Scrubber;
-           require HTML::Parser;
-    };
-
-    if ($@) { # Package(s) not installed.
</del><ins>+    if (!Bugzilla-&gt;feature('html_desc')) {
</ins><span class="cx">         my $safe = join('|', @allow);
</span><span class="cx">         my $chr = chr(1);
</span><span class="cx"> 
</span><span class="lines">@@ -123,7 +140,7 @@
</span><span class="cx">         $text =~ s#$chr($safe)$chr#&lt;$1&gt;#go;
</span><span class="cx">         return $text;
</span><span class="cx">     }
</span><del>-    else { # Packages installed.
</del><ins>+    else {
</ins><span class="cx">         # We can be less restrictive. We can accept elements with attributes.
</span><span class="cx">         push(@allow, qw(a blockquote q span));
</span><span class="cx"> 
</span><span class="lines">@@ -176,6 +193,20 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub email_filter {
+    my ($toencode) = @_;
+    if (!Bugzilla-&gt;user-&gt;id) {
+        my @emails = Email::Address-&gt;parse($toencode);
+        if (scalar @emails) {
+            my @hosts = map { quotemeta($_-&gt;host) } @emails;
+            my $hosts_re = join('|', @hosts);
+            $toencode =~ s/\@(?:$hosts_re)//g;
+            return $toencode;
+        }
+    }
+    return $toencode;
+}
+
</ins><span class="cx"> # This originally came from CGI.pm, by Lincoln D. Stein
</span><span class="cx"> sub url_quote {
</span><span class="cx">     my ($toencode) = (@_);
</span><span class="lines">@@ -187,7 +218,7 @@
</span><span class="cx"> 
</span><span class="cx"> sub css_class_quote {
</span><span class="cx">     my ($toencode) = (@_);
</span><del>-    $toencode =~ s/ /_/g;
</del><ins>+    $toencode =~ s#[ /]#_#g;
</ins><span class="cx">     $toencode =~ s/([^a-zA-Z0-9_\-.])/uc sprintf(&quot;&amp;#x%x;&quot;,ord($1))/eg;
</span><span class="cx">     return $toencode;
</span><span class="cx"> }
</span><span class="lines">@@ -212,79 +243,145 @@
</span><span class="cx">     return $var;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-# This function must not be relied upon to return a valid string to pass to
-# the DB or the user in UTF-8 situations. The only thing you  can rely upon
-# it for is that if you url_decode a string, it will url_encode back to the 
-# exact same thing.
-sub url_decode {
-    my ($todecode) = (@_);
-    $todecode =~ tr/+/ /;       # pluses become spaces
-    $todecode =~ s/%([0-9a-fA-F]{2})/pack(&quot;c&quot;,hex($1))/ge;
-    return $todecode;
-}
-
</del><span class="cx"> sub i_am_cgi {
</span><span class="cx">     # I use SERVER_SOFTWARE because it's required to be
</span><span class="cx">     # defined for all requests in the CGI spec.
</span><span class="cx">     return exists $ENV{'SERVER_SOFTWARE'} ? 1 : 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub ssl_require_redirect {
-    my $method = shift;
</del><ins>+# This exists as a separate function from Bugzilla::CGI::redirect_to_https
+# because we don't want to create a CGI object during XML-RPC calls
+# (doing so can mess up XML-RPC).
+sub do_ssl_redirect_if_required {
+    return if !i_am_cgi();
+    return if !Bugzilla-&gt;params-&gt;{'ssl_redirect'};
</ins><span class="cx"> 
</span><del>-    # If currently not in a protected SSL 
-    # connection, determine if a redirection is 
-    # needed based on value in Bugzilla-&gt;params-&gt;{ssl}.
-    # If we are already in a protected connection or
-    # sslbase is not set then no action is required.
-    if (uc($ENV{'HTTPS'}) ne 'ON' 
-        &amp;&amp; $ENV{'SERVER_PORT'} != 443 
-        &amp;&amp; Bugzilla-&gt;params-&gt;{'sslbase'} ne '')
-    {
-        # System is configured to never require SSL 
-        # so no redirection is needed.
-        return 0 
-            if Bugzilla-&gt;params-&gt;{'ssl'} eq 'never';
-            
-        # System is configured to always require a SSL
-        # connection so we need to redirect.
-        return 1
-            if Bugzilla-&gt;params-&gt;{'ssl'} eq 'always';
</del><ins>+    my $sslbase = Bugzilla-&gt;params-&gt;{'sslbase'};
+    
+    # If we're already running under SSL, never redirect.
+    return if uc($ENV{HTTPS} || '') eq 'ON';
+    # Never redirect if there isn't an sslbase.
+    return if !$sslbase;
+    Bugzilla-&gt;cgi-&gt;redirect_to_https();
+}
</ins><span class="cx"> 
</span><del>-        # System is configured such that if we are inside
-        # of an authenticated session, then we need to make
-        # sure that all of the connections are over SSL. Non
-        # authenticated sessions SSL is not mandatory.
-        # For XMLRPC requests, if the method is User.login
-        # then we always want the connection to be over SSL
-        # if the system is configured for authenticated
-        # sessions since the user's username and password
-        # will be passed before the user is logged in.
-        return 1 
-            if Bugzilla-&gt;params-&gt;{'ssl'} eq 'authenticated sessions'
-                &amp;&amp; (Bugzilla-&gt;user-&gt;id 
-                    || (defined $method &amp;&amp; $method eq 'User.login'));
</del><ins>+sub correct_urlbase {
+    my $ssl = Bugzilla-&gt;params-&gt;{'ssl_redirect'};
+    my $urlbase = Bugzilla-&gt;params-&gt;{'urlbase'};
+    my $sslbase = Bugzilla-&gt;params-&gt;{'sslbase'};
+
+    if (!$sslbase) {
+        return $urlbase;
</ins><span class="cx">     }
</span><ins>+    elsif ($ssl) {
+        return $sslbase;
+    }
+    else {
+        # Return what the user currently uses.
+        return (uc($ENV{HTTPS} || '') eq 'ON') ? $sslbase : $urlbase;
+    }
+}
</ins><span class="cx"> 
</span><del>-    return 0;
</del><ins>+sub remote_ip {
+    my $ip = $ENV{'REMOTE_ADDR'} || '127.0.0.1';
+    my @proxies = split(/[\s,]+/, Bugzilla-&gt;params-&gt;{'inbound_proxies'});
+
+    # If the IP address is one of our trusted proxies, then we look at
+    # the X-Forwarded-For header to determine the real remote IP address.
+    if ($ENV{'HTTP_X_FORWARDED_FOR'} &amp;&amp; first { $_ eq $ip } @proxies) {
+        my @ips = split(/[\s,]+/, $ENV{'HTTP_X_FORWARDED_FOR'});
+        # This header can contain several IP addresses. We want the
+        # IP address of the machine which connected to our proxies as
+        # all other IP addresses may be fake or internal ones.
+        # Note that this may block a whole external proxy, but we have
+        # no way to determine if this proxy is malicious or trustable.
+        foreach my $remote_ip (reverse @ips) {
+            if (!first { $_ eq $remote_ip } @proxies) {
+                # Keep the original IP address if the remote IP is invalid.
+                $ip = validate_ip($remote_ip) || $ip;
+                last;
+            }
+        }
+    }
+    return $ip;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub correct_urlbase {
-    my $ssl = Bugzilla-&gt;params-&gt;{'ssl'};
-    return Bugzilla-&gt;params-&gt;{'urlbase'} if $ssl eq 'never';
</del><ins>+sub validate_ip {
+    my $ip = shift;
+    return is_ipv4($ip) || is_ipv6($ip);
+}
</ins><span class="cx"> 
</span><del>-    my $sslbase = Bugzilla-&gt;params-&gt;{'sslbase'};
-    if ($sslbase) {
-        return $sslbase if $ssl eq 'always';
-        # Authenticated Sessions
-        return $sslbase if Bugzilla-&gt;user-&gt;id;
</del><ins>+# Copied from Data::Validate::IP::is_ipv4().
+sub is_ipv4 {
+    my $ip = shift;
+    return unless defined $ip;
+
+    my @octets = $ip =~ /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
+    return unless scalar(@octets) == 4;
+
+    foreach my $octet (@octets) {
+        return unless ($octet &gt;= 0 &amp;&amp; $octet &lt;= 255 &amp;&amp; $octet !~ /^0\d{1,2}$/);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    # Set to &quot;authenticated sessions&quot; but nobody's logged in, or
-    # sslbase isn't set.
-    return Bugzilla-&gt;params-&gt;{'urlbase'};
</del><ins>+    # The IP address is valid and can now be detainted.
+    return join('.', @octets);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# Copied from Data::Validate::IP::is_ipv6().
+sub is_ipv6 {
+    my $ip = shift;
+    return unless defined $ip;
+
+    # If there is a :: then there must be only one :: and the length
+    # can be variable. Without it, the length must be 8 groups.
+    my @chunks = split(':', $ip);
+
+    # Need to check if the last chunk is an IPv4 address, if it is we
+    # pop it off and exempt it from the normal IPv6 checking and stick
+    # it back on at the end. If there is only one chunk and it's an IPv4
+    # address, then it isn't an IPv6 address.
+    my $ipv4;
+    my $expected_chunks = 8;
+    if (@chunks &gt; 1 &amp;&amp; is_ipv4($chunks[$#chunks])) {
+        $ipv4 = pop(@chunks);
+        $expected_chunks--;
+    }
+
+    my $empty = 0;
+    # Workaround to handle trailing :: being valid.
+    if ($ip =~ /[0-9a-f]{1,4}::$/) {
+        $empty++;
+    # Single trailing ':' is invalid.
+    } elsif ($ip =~ /:$/) {
+        return;
+    }
+
+    foreach my $chunk (@chunks) {
+        return unless $chunk =~ /^[0-9a-f]{0,4}$/i;
+        $empty++ if $chunk eq '';
+    }
+    # More than one :: block is bad, but if it starts with :: it will
+    # look like two, so we need an exception.
+    if ($empty == 2 &amp;&amp; $ip =~ /^::/) {
+        # This is ok
+    } elsif ($empty &gt; 1) {
+        return;
+    }
+
+    push(@chunks, $ipv4) if $ipv4;
+    # Need 8 chunks, or we need an empty section that could be filled
+    # to represent the missing '0' sections.
+    return unless (@chunks == $expected_chunks || @chunks &lt; $expected_chunks &amp;&amp; $empty);
+
+    my $ipv6 = join(':', @chunks);
+    # The IP address is valid and can now be detainted.
+    trick_taint($ipv6);
+
+    # Need to handle the exception of trailing :: being valid.
+    return &quot;${ipv6}::&quot; if $ip =~ /::$/;
+    return $ipv6;
+}
+
</ins><span class="cx"> sub use_attachbase {
</span><span class="cx">     my $attachbase = Bugzilla-&gt;params-&gt;{'attachment_base'};
</span><span class="cx">     return ($attachbase ne ''
</span><span class="lines">@@ -292,38 +389,41 @@
</span><span class="cx">             &amp;&amp; $attachbase ne Bugzilla-&gt;params-&gt;{'sslbase'}) ? 1 : 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub lsearch {
-    my ($list,$item) = (@_);
-    my $count = 0;
-    foreach my $i (@$list) {
-        if ($i eq $item) {
-            return $count;
-        }
-        $count++;
-    }
-    return -1;
-}
-
</del><span class="cx"> sub diff_arrays {
</span><del>-    my ($old_ref, $new_ref) = @_;
</del><ins>+    my ($old_ref, $new_ref, $attrib) = @_;
+    $attrib ||= 'name';
</ins><span class="cx"> 
</span><ins>+    my (%counts, %pos);
+    # We are going to alter the old array.
</ins><span class="cx">     my @old = @$old_ref;
</span><del>-    my @new = @$new_ref;
</del><ins>+    my $i = 0;
</ins><span class="cx"> 
</span><del>-    # For each pair of (old, new) entries:
-    # If they're equal, set them to empty. When done, @old contains entries
-    # that were removed; @new contains ones that got added.
-    foreach my $oldv (@old) {
-        foreach my $newv (@new) {
-            next if ($newv eq '');
-            if ($oldv eq $newv) {
-                $newv = $oldv = '';
-            }
</del><ins>+    # $counts{foo}-- means old, $counts{foo}++ means new.
+    # If $counts{foo} becomes positive, then we are adding new items,
+    # else we simply cancel one old existing item. Remaining items
+    # in the old list have been removed.
+    foreach (@old) {
+        next unless defined $_;
+        my $value = blessed($_) ? $_-&gt;$attrib : $_;
+        $counts{$value}--;
+        push @{$pos{$value}}, $i++;
+    }
+    my @added;
+    foreach (@$new_ref) {
+        next unless defined $_;
+        my $value = blessed($_) ? $_-&gt;$attrib : $_;
+        if (++$counts{$value} &gt; 0) {
+            # Ignore empty strings, but objects having an empty string
+            # as attribute are fine.
+            push(@added, $_) unless ($value eq '' &amp;&amp; !blessed($_));
</ins><span class="cx">         }
</span><ins>+        else {
+            my $old_pos = shift @{$pos{$value}};
+            $old[$old_pos] = undef;
+        }
</ins><span class="cx">     }
</span><del>-
-    my @removed = grep { $_ ne '' } @old;
-    my @added = grep { $_ ne '' } @new;
</del><ins>+    # Ignore canceled items as well as empty strings.
+    my @removed = grep { defined $_ &amp;&amp; $_ ne '' } @old;
</ins><span class="cx">     return (\@removed, \@added);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -336,30 +436,15 @@
</span><span class="cx">     return $str;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub diff_strings {
-    my ($oldstr, $newstr) = @_;
-
-    # Split the old and new strings into arrays containing their values.
-    $oldstr =~ s/[\s,]+/ /g;
-    $newstr =~ s/[\s,]+/ /g;
-    my @old = split(&quot; &quot;, $oldstr);
-    my @new = split(&quot; &quot;, $newstr);
-
-    my ($rem, $add) = diff_arrays(\@old, \@new);
-
-    my $removed = join (&quot;, &quot;, @$rem);
-    my $added = join (&quot;, &quot;, @$add);
-
-    return ($removed, $added);
-}
-
</del><span class="cx"> sub wrap_comment {
</span><span class="cx">     my ($comment, $cols) = @_;
</span><span class="cx">     my $wrappedcomment = &quot;&quot;;
</span><span class="cx"> 
</span><span class="cx">     # Use 'local', as recommended by Text::Wrap's perldoc.
</span><ins>+#if WEBKIT_CHANGES
</ins><span class="cx">     local $Text::Wrap::columns = $cols || COMMENT_COLS_WRAP;
</span><span class="cx">     # Make words that are longer than COMMENT_COLS_WRAP not wrap.
</span><ins>+#endif // WEBKIT_CHANGES
</ins><span class="cx">     local $Text::Wrap::huge    = 'overflow';
</span><span class="cx">     # Don't mess with tabs.
</span><span class="cx">     local $Text::Wrap::unexpand = 0;
</span><span class="lines">@@ -414,56 +499,80 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub format_time {
</span><del>-    my ($date, $format) = @_;
</del><ins>+    my ($date, $format, $timezone) = @_;
</ins><span class="cx"> 
</span><del>-    # If $format is undefined, try to guess the correct date format.    
-    my $show_timezone;
-    if (!defined($format)) {
-        if ($date =~ m/^(\d{4})[-\.](\d{2})[-\.](\d{2}) (\d{2}):(\d{2})(:(\d{2}))?$/) {
</del><ins>+    # If $format is not set, try to guess the correct date format.
+    if (!$format) {
+        if (!ref $date
+            &amp;&amp; $date =~ /^(\d{4})[-\.](\d{2})[-\.](\d{2}) (\d{2}):(\d{2})(:(\d{2}))?$/) 
+        {
</ins><span class="cx">             my $sec = $7;
</span><span class="cx">             if (defined $sec) {
</span><del>-                $format = &quot;%Y-%m-%d %T&quot;;
</del><ins>+                $format = &quot;%Y-%m-%d %T %Z&quot;;
</ins><span class="cx">             } else {
</span><del>-                $format = &quot;%Y-%m-%d %R&quot;;
</del><ins>+                $format = &quot;%Y-%m-%d %R %Z&quot;;
</ins><span class="cx">             }
</span><span class="cx">         } else {
</span><del>-            # Default date format. See Date::Format for other formats available.
-            $format = &quot;%Y-%m-%d %R&quot;;
</del><ins>+            # Default date format. See DateTime for other formats available.
+            $format = &quot;%Y-%m-%d %R %Z&quot;;
</ins><span class="cx">         }
</span><del>-        # By default, we want the timezone to be displayed.
-        $show_timezone = 1;
</del><span class="cx">     }
</span><del>-    else {
-        # Search for %Z or %z, meaning we want the timezone to be displayed.
-        # Till bug 182238 gets fixed, we assume Bugzilla-&gt;params-&gt;{'timezone'}
-        # is used.
-        $show_timezone = ($format =~ s/\s?%Z$//i);
-    }
</del><span class="cx"> 
</span><del>-    # str2time($date) is undefined if $date has an invalid date format.
-    my $time = str2time($date);
-
-    if (defined $time) {
-        $date = time2str($format, $time);
-        $date .= &quot; &quot; . Bugzilla-&gt;params-&gt;{'timezone'} if $show_timezone;
-    }
-    else {
-        # Don't let invalid (time) strings to be passed to templates!
-        $date = '';
-    }
</del><ins>+    my $dt = ref $date ? $date : datetime_from($date, $timezone);
+    $date = defined $dt ? $dt-&gt;strftime($format) : '';
</ins><span class="cx">     return trim($date);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub format_time_decimal {
-    my ($time) = (@_);
</del><ins>+sub datetime_from {
+    my ($date, $timezone) = @_;
</ins><span class="cx"> 
</span><del>-    my $newtime = sprintf(&quot;%.2f&quot;, $time);
</del><ins>+    # In the database, this is the &quot;0&quot; date.
+    return undef if $date =~ /^0000/;
</ins><span class="cx"> 
</span><del>-    if ($newtime =~ /0\Z/) {
-        $newtime = sprintf(&quot;%.1f&quot;, $time);
</del><ins>+    # strptime($date) returns an empty array if $date has an invalid
+    # date format.
+    my @time = strptime($date);
+
+    unless (scalar @time) {
+        # If an unknown timezone is passed (such as MSK, for Moskow),
+        # strptime() is unable to parse the date. We try again, but we first
+        # remove the timezone.
+        $date =~ s/\s+\S+$//;
+        @time = strptime($date);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    return $newtime;
</del><ins>+    return undef if !@time;
+
+    # strptime() counts years from 1900, and months from 0 (January).
+    # We have to fix both values.
+    my %args = (
+        year   =&gt; $time[5] + 1900,
+        month  =&gt; $time[4] + 1,
+        day    =&gt; $time[3],
+        hour   =&gt; $time[2],
+        minute =&gt; $time[1],
+        # DateTime doesn't like fractional seconds.
+        # Also, sometimes seconds are undef.
+        second =&gt; defined($time[0]) ? int($time[0]) : undef,
+        # If a timezone was specified, use it. Otherwise, use the
+        # local timezone.
+        time_zone =&gt; Bugzilla-&gt;local_timezone-&gt;offset_as_string($time[6]) 
+                     || Bugzilla-&gt;local_timezone,
+    );
+
+    # If something wasn't specified in the date, it's best to just not
+    # pass it to DateTime at all. (This is important for doing datetime_from
+    # on the deadline field, which is usually just a date with no time.)
+    foreach my $arg (keys %args) {
+        delete $args{$arg} if !defined $args{$arg};
+    }
+
+    my $dt = new DateTime(\%args);
+
+    # Now display the date using the given timezone,
+    # or the user's timezone if none is given.
+    $dt-&gt;set_time_zone($timezone || Bugzilla-&gt;user-&gt;timezone);
+    return $dt;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub file_mod_time {
</span><span class="lines">@@ -475,33 +584,56 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub bz_crypt {
</span><del>-    my ($password) = @_;
</del><ins>+    my ($password, $salt) = @_;
</ins><span class="cx"> 
</span><del>-    # The list of characters that can appear in a salt.  Salts and hashes
-    # are both encoded as a sequence of characters from a set containing
-    # 64 characters, each one of which represents 6 bits of the salt/hash.
-    # The encoding is similar to BASE64, the difference being that the
-    # BASE64 plus sign (+) is replaced with a forward slash (/).
-    my @saltchars = (0..9, 'A'..'Z', 'a'..'z', '.', '/');
</del><ins>+    my $algorithm;
+    if (!defined $salt) {
+        # If you don't use a salt, then people can create tables of
+        # hashes that map to particular passwords, and then break your
+        # hashing very easily if they have a large-enough table of common
+        # (or even uncommon) passwords. So we generate a unique salt for
+        # each password in the database, and then just prepend it to
+        # the hash.
+        $salt = generate_random_password(PASSWORD_SALT_LENGTH);
+        $algorithm = PASSWORD_DIGEST_ALGORITHM;
+    }
</ins><span class="cx"> 
</span><del>-    # Generate the salt.  We use an 8 character (48 bit) salt for maximum
-    # security on systems whose crypt uses MD5.  Systems with older
-    # versions of crypt will just use the first two characters of the salt.
-    my $salt = '';
-    for ( my $i=0 ; $i &lt; 8 ; ++$i ) {
-        $salt .= $saltchars[rand(64)];
</del><ins>+    # We append the algorithm used to the string. This is good because then
+    # we can change the algorithm being used, in the future, without 
+    # disrupting the validation of existing passwords. Also, this tells
+    # us if a password is using the old &quot;crypt&quot; method of hashing passwords,
+    # because the algorithm will be missing from the string.
+    if ($salt =~ /{([^}]+)}$/) {
+        $algorithm = $1;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    # Wide characters cause crypt to die
-    if (Bugzilla-&gt;params-&gt;{'utf8'}) {
-        utf8::encode($password) if utf8::is_utf8($password);
-    }
</del><ins>+    my $crypted_password;
+    if (!$algorithm) {
+        # Wide characters cause crypt to die
+        if (Bugzilla-&gt;params-&gt;{'utf8'}) {
+            utf8::encode($password) if utf8::is_utf8($password);
+        }
</ins><span class="cx">     
</span><del>-    # Crypt the password.
-    my $cryptedpassword = crypt($password, $salt);
</del><ins>+        # Crypt the password.
+        $crypted_password = crypt($password, $salt);
</ins><span class="cx"> 
</span><ins>+        # HACK: Perl has bug where returned crypted password is considered
+        # tainted. See http://rt.perl.org/rt3/Public/Bug/Display.html?id=59998
+        unless(tainted($password) || tainted($salt)) {
+            trick_taint($crypted_password);
+        } 
+    }
+    else {
+        my $hasher = Digest-&gt;new($algorithm);
+        # We only want to use the first characters of the salt, no
+        # matter how long of a salt we may have been passed.
+        $salt = substr($salt, 0, PASSWORD_SALT_LENGTH);
+        $hasher-&gt;add($password, $salt);
+        $crypted_password = $salt . $hasher-&gt;b64digest . &quot;{$algorithm}&quot;;
+    }
+
</ins><span class="cx">     # Return the crypted password.
</span><del>-    return $cryptedpassword;
</del><ins>+    return $crypted_password;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> # If you want to understand the security of strings generated by this
</span><span class="lines">@@ -512,54 +644,13 @@
</span><span class="cx"> # strength of the string in bits.
</span><span class="cx"> sub generate_random_password {
</span><span class="cx">     my $size = shift || 10; # default to 10 chars if nothing specified
</span><del>-    my $rand;
-    if (eval { require Math::Random::Secure; 1; }) {
-        $rand = \&amp;Math::Random::Secure::irand;
-    }
-    else {
-        # For details on why this block works the way it does, see bug 619594.
-        # (Note that we don't do this if Math::Random::Secure is installed,
-        # because we don't need to.)
-        my $counter = 0;
-        $rand = sub {
-            # If we regenerate the seed every 5 characters, our seed is roughly
-            # as strong (in terms of bit size) as our randomly-generated
-            # string itself.
-            _do_srand() if ($counter % 5) == 0;
-            $counter++;
-            return int(rand $_[0]);
-        };
-    }
-    return join(&quot;&quot;, map{ ('0'..'9','a'..'z','A'..'Z')[$rand-&gt;(62)] } 
-                       (1..$size));
</del><ins>+    return join(&quot;&quot;, map{ ('0'..'9','a'..'z','A'..'Z')[irand 62] } (1..$size));
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub _do_srand {
-    # On Windows, calling srand over and over in the same process produces
-    # very bad results. We need a stronger seed.
-    if (ON_WINDOWS) {
-        require Win32;
-        # GuidGen generates random data via Windows's CryptGenRandom
-        # interface, which is documented as being cryptographically secure.
-        my $guid = Win32::GuidGen();
-        # GUIDs look like:
-        # {09531CF1-D0C7-4860-840C-1C8C8735E2AD}
-        $guid =~ s/[-{}]+//g;
-        # Get a 32-bit integer using the first eight hex digits.
-        my $seed = hex(substr($guid, 0, 8));
-        srand($seed);
-        return;
-    }
-
-    # On *nix-like platforms, this uses /dev/urandom, so the seed changes
-    # enough on every invocation.
-    srand();
-}
-
</del><span class="cx"> sub validate_email_syntax {
</span><span class="cx">     my ($addr) = @_;
</span><span class="cx">     my $match = Bugzilla-&gt;params-&gt;{'emailregexp'};
</span><del>-    my $ret = ($addr =~ /$match/ &amp;&amp; $addr !~ /[\\\(\)&lt;&gt;&amp;,;:&quot;\[\] \t\r\n]/);
</del><ins>+    my $ret = ($addr =~ /$match/ &amp;&amp; $addr !~ /[\\\(\)&lt;&gt;&amp;,;:&quot;\[\] \t\r\n\P{ASCII}]/);
</ins><span class="cx">     if ($ret) {
</span><span class="cx">         # We assume these checks to suffice to consider the address untainted.
</span><span class="cx">         trick_taint($_[0]);
</span><span class="lines">@@ -604,50 +695,127 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub clean_text {
</span><del>-    my ($dtext) = shift;
-    $dtext =~  s/[\x00-\x1F\x7F]+/ /g;   # change control characters into a space
</del><ins>+    my $dtext = shift;
+    if ($dtext) {
+        # change control characters into a space
+        $dtext =~ s/[\x00-\x1F\x7F]+/ /g;
+    }
</ins><span class="cx">     return trim($dtext);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub on_main_db (&amp;) {
+    my $code = shift;
+    my $original_dbh = Bugzilla-&gt;dbh;
+    Bugzilla-&gt;request_cache-&gt;{dbh} = Bugzilla-&gt;dbh_main;
+    $code-&gt;();
+    Bugzilla-&gt;request_cache-&gt;{dbh} = $original_dbh;
+}
+
</ins><span class="cx"> sub get_text {
</span><span class="cx">     my ($name, $vars) = @_;
</span><span class="cx">     my $template = Bugzilla-&gt;template_inner;
</span><span class="cx">     $vars ||= {};
</span><span class="cx">     $vars-&gt;{'message'} = $name;
</span><span class="cx">     my $message;
</span><del>-    $template-&gt;process('global/message.txt.tmpl', $vars, \$message)
-        || ThrowTemplateError($template-&gt;error());
</del><ins>+    if (!$template-&gt;process('global/message.txt.tmpl', $vars, \$message)) {
+        require Bugzilla::Error;
+        Bugzilla::Error::ThrowTemplateError($template-&gt;error());
+    }
</ins><span class="cx">     # Remove the indenting that exists in messages.html.tmpl.
</span><span class="cx">     $message =~ s/^    //gm;
</span><span class="cx">     return $message;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub template_var {
+    my $name = shift;
+    my $cache = Bugzilla-&gt;request_cache-&gt;{util_template_var} ||= {};
+    my $template = Bugzilla-&gt;template_inner;
+    my $lang = $template-&gt;context-&gt;{bz_language};
+    return $cache-&gt;{$lang}-&gt;{$name} if defined $cache-&gt;{$lang};
+    my %vars;
+    # Note: If we suddenly start needing a lot of template_var variables,
+    # they should move into their own template, not field-descs.
+    my $result = $template-&gt;process('global/field-descs.none.tmpl', 
+                                    { vars =&gt; \%vars, in_template_var =&gt; 1 });
+    # Bugzilla::Error can't be &quot;use&quot;d in Bugzilla::Util.
+    if (!$result) {
+        require Bugzilla::Error;
+        Bugzilla::Error::ThrowTemplateError($template-&gt;error);
+    }
+    $cache-&gt;{$lang} = \%vars;
+    return $vars{$name};
+}
</ins><span class="cx"> 
</span><del>-sub get_netaddr {
-    my $ipaddr = shift;
</del><ins>+sub display_value {
+    my ($field, $value) = @_;
+    my $value_descs = template_var('value_descs');
+    if (defined $value_descs-&gt;{$field}-&gt;{$value}) {
+        return $value_descs-&gt;{$field}-&gt;{$value};
+    }
+    return $value;
+}
</ins><span class="cx"> 
</span><del>-    # Check for a valid IPv4 addr which we know how to parse
-    if (!$ipaddr || $ipaddr !~ /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) {
-        return undef;
</del><ins>+sub disable_utf8 {
+    if (Bugzilla-&gt;params-&gt;{'utf8'}) {
+        binmode STDOUT, ':bytes'; # Turn off UTF8 encoding.
</ins><span class="cx">     }
</span><ins>+}
</ins><span class="cx"> 
</span><del>-    my $addr = unpack(&quot;N&quot;, pack(&quot;CCCC&quot;, split(/\./, $ipaddr)));
</del><ins>+use constant UTF8_ACCIDENTAL =&gt; qw(shiftjis big5-eten euc-kr euc-jp);
</ins><span class="cx"> 
</span><del>-    my $maskbits = Bugzilla-&gt;params-&gt;{'loginnetmask'};
</del><ins>+sub detect_encoding {
+    my $data = shift;
</ins><span class="cx"> 
</span><del>-    # Make Bugzilla ignore the IP address if loginnetmask is set to 0
-    return &quot;0.0.0.0&quot; if ($maskbits == 0);
</del><ins>+    if (!Bugzilla-&gt;feature('detect_charset')) {
+        require Bugzilla::Error;
+        Bugzilla::Error::ThrowCodeError('feature_disabled',
+            { feature =&gt; 'detect_charset' });
+    }
</ins><span class="cx"> 
</span><del>-    $addr &gt;&gt;= (32-$maskbits);
</del><ins>+    require Encode::Detect::Detector;
+    import Encode::Detect::Detector 'detect';
</ins><span class="cx"> 
</span><del>-    $addr &lt;&lt;= (32-$maskbits);
-    return join(&quot;.&quot;, unpack(&quot;CCCC&quot;, pack(&quot;N&quot;, $addr)));
</del><ins>+    my $encoding = detect($data);
+    $encoding = resolve_alias($encoding) if $encoding;
+
+    # Encode::Detect is bad at detecting certain charsets, but Encode::Guess
+    # is better at them. Here's the details:
+
+    # shiftjis, big5-eten, euc-kr, and euc-jp: (Encode::Detect
+    # tends to accidentally mis-detect UTF-8 strings as being
+    # these encodings.)
+    if ($encoding &amp;&amp; grep($_ eq $encoding, UTF8_ACCIDENTAL)) {
+        $encoding = undef;
+        my $decoder = guess_encoding($data, UTF8_ACCIDENTAL);
+        $encoding = $decoder-&gt;name if ref $decoder;
+    }
+
+    # Encode::Detect sometimes mis-detects various ISO encodings as iso-8859-8,
+    # but Encode::Guess can usually tell which one it is.
+    if ($encoding &amp;&amp; $encoding eq 'iso-8859-8') {
+        my $decoded_as = _guess_iso($data, 'iso-8859-8', 
+            # These are ordered this way because it gives the most 
+            # accurate results.
+            qw(iso-8859-7 iso-8859-2));
+        $encoding = $decoded_as if $decoded_as;
+    }
+
+    return $encoding;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub disable_utf8 {
-    if (Bugzilla-&gt;params-&gt;{'utf8'}) {
-        binmode STDOUT, ':bytes'; # Turn off UTF8 encoding.
</del><ins>+# A helper for detect_encoding.
+sub _guess_iso {
+    my ($data, $versus, @isos) = (shift, shift, shift);
+
+    my $encoding;
+    foreach my $iso (@isos) {
+        my $decoder = guess_encoding($data, ($iso, $versus));
+        if (ref $decoder) {
+            $encoding = $decoder-&gt;name if ref $decoder;
+            last;
+        }
</ins><span class="cx">     }
</span><ins>+    return $encoding;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> 1;
</span><span class="lines">@@ -663,7 +831,6 @@
</span><span class="cx">   use Bugzilla::Util;
</span><span class="cx"> 
</span><span class="cx">   # Functions for dealing with variable tainting
</span><del>-  $rv = is_tainted($var);
</del><span class="cx">   trick_taint($var);
</span><span class="cx">   detaint_natural($var);
</span><span class="cx">   detaint_signed($var);
</span><span class="lines">@@ -672,28 +839,22 @@
</span><span class="cx">   html_quote($var);
</span><span class="cx">   url_quote($var);
</span><span class="cx">   xml_quote($var);
</span><ins>+  email_filter($var);
</ins><span class="cx"> 
</span><del>-  # Functions for decoding
-  $rv = url_decode($var);
-
</del><span class="cx">   # Functions that tell you about your environment
</span><span class="cx">   my $is_cgi   = i_am_cgi();
</span><del>-  my $net_addr = get_netaddr($ip_addr);
</del><span class="cx">   my $urlbase  = correct_urlbase();
</span><span class="cx"> 
</span><del>-  # Functions for searching
-  $loc = lsearch(\@arr, $val);
-
</del><span class="cx">   # Data manipulation
</span><span class="cx">   ($removed, $added) = diff_arrays(\@old, \@new);
</span><span class="cx"> 
</span><span class="cx">   # Functions for manipulating strings
</span><span class="cx">   $val = trim(&quot; abc &quot;);
</span><del>-  ($removed, $added) = diff_strings($old, $new);
</del><span class="cx">   $wrapped = wrap_comment($comment);
</span><span class="cx"> 
</span><span class="cx">   # Functions for formatting time
</span><span class="cx">   format_time($time);
</span><ins>+  datetime_from($time, $timezone);
</ins><span class="cx"> 
</span><span class="cx">   # Functions for dealing with files
</span><span class="cx">   $time = file_mod_time($filename);
</span><span class="lines">@@ -706,6 +867,11 @@
</span><span class="cx">   validate_email_syntax($email);
</span><span class="cx">   validate_date($date);
</span><span class="cx"> 
</span><ins>+  # DB-related functions
+  on_main_db {
+     ... code here ...
+  };
+
</ins><span class="cx"> =head1 DESCRIPTION
</span><span class="cx"> 
</span><span class="cx"> This package contains various utility functions which do not belong anywhere
</span><span class="lines">@@ -727,10 +893,6 @@
</span><span class="cx"> 
</span><span class="cx"> =over 4
</span><span class="cx"> 
</span><del>-=item C&lt;is_tainted&gt;
-
-Determines whether a particular variable is tainted
-
</del><span class="cx"> =item C&lt;trick_taint($val)&gt;
</span><span class="cx"> 
</span><span class="cx"> Tricks perl into untainting a particular variable.
</span><span class="lines">@@ -765,8 +927,9 @@
</span><span class="cx"> 
</span><span class="cx"> =item C&lt;html_quote($val)&gt;
</span><span class="cx"> 
</span><del>-Returns a value quoted for use in HTML, with &amp;, E&lt;lt&gt;, E&lt;gt&gt;, and E&lt;34&gt; being
-replaced with their appropriate HTML entities.
</del><ins>+Returns a value quoted for use in HTML, with &amp;, E&lt;lt&gt;, E&lt;gt&gt;, E&lt;34&gt; and @ being
+replaced with their appropriate HTML entities.  Also, Unicode BiDi controls are
+deleted.
</ins><span class="cx"> 
</span><span class="cx"> =item C&lt;html_light_quote($val)&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -781,7 +944,7 @@
</span><span class="cx"> =item C&lt;css_class_quote($val)&gt;
</span><span class="cx"> 
</span><span class="cx"> Quotes characters so that they may be used as CSS class names. Spaces
</span><del>-are replaced by underscores.
</del><ins>+and forward slashes are replaced by underscores.
</ins><span class="cx"> 
</span><span class="cx"> =item C&lt;xml_quote($val)&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -789,9 +952,11 @@
</span><span class="cx"> is kept separate from html_quote partly for compatibility with previous code
</span><span class="cx"> (for &amp;apos;) and partly for future handling of non-ASCII characters.
</span><span class="cx"> 
</span><del>-=item C&lt;url_decode($val)&gt;
</del><ins>+=item C&lt;email_filter&gt;
</ins><span class="cx"> 
</span><del>-Converts the %xx encoding from the given URL back to its original form.
</del><ins>+Removes the hostname from email addresses in the string, if the user
+currently viewing Bugzilla is logged out. If the user is logged-in,
+this filter just returns the input string.
</ins><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><span class="lines">@@ -807,38 +972,27 @@
</span><span class="cx"> server. For example, it would return false if the caller is running
</span><span class="cx"> in a command-line script.
</span><span class="cx"> 
</span><del>-=item C&lt;get_netaddr($ipaddr)&gt;
-
-Given an IP address, this returns the associated network address, using
-C&lt;Bugzilla-&gt;params-&gt;{'loginnetmask'}&gt; as the netmask. This can be used
-to obtain data in order to restrict weak authentication methods (such as
-cookies) to only some addresses.
-
</del><span class="cx"> =item C&lt;correct_urlbase()&gt;
</span><span class="cx"> 
</span><span class="cx"> Returns either the C&lt;sslbase&gt; or C&lt;urlbase&gt; parameter, depending on the
</span><del>-current setting for the C&lt;ssl&gt; parameter.
</del><ins>+current setting for the C&lt;ssl_redirect&gt; parameter.
</ins><span class="cx"> 
</span><del>-=item C&lt;use_attachbase()&gt;
</del><ins>+=item C&lt;remote_ip()&gt;
</ins><span class="cx"> 
</span><del>-Returns true if an alternate host is used to display attachments; false
-otherwise.
</del><ins>+Returns the IP address of the remote client. If Bugzilla is behind
+a trusted proxy, it will get the remote IP address by looking at the
+X-Forwarded-For header.
</ins><span class="cx"> 
</span><del>-=back
</del><ins>+=item C&lt;validate_ip($ip)&gt;
</ins><span class="cx"> 
</span><del>-=head2 Searching
</del><ins>+Returns the sanitized IP address if it is a valid IPv4 or IPv6 address,
+else returns undef.
</ins><span class="cx"> 
</span><del>-Functions for searching within a set of values.
</del><ins>+=item C&lt;use_attachbase()&gt;
</ins><span class="cx"> 
</span><del>-=over 4
</del><ins>+Returns true if an alternate host is used to display attachments; false
+otherwise.
</ins><span class="cx"> 
</span><del>-=item C&lt;lsearch($list, $item)&gt;
-
-Returns the position of C&lt;$item&gt; in C&lt;$list&gt;. C&lt;$list&gt; must be a list
-reference.
-
-If the item is not in the list, returns -1.
-
</del><span class="cx"> =back
</span><span class="cx"> 
</span><span class="cx"> =head2 Data Manipulation
</span><span class="lines">@@ -868,14 +1022,6 @@
</span><span class="cx"> Removes any leading or trailing whitespace from a string. This routine does not
</span><span class="cx"> modify the existing string.
</span><span class="cx"> 
</span><del>-=item C&lt;diff_strings($oldstr, $newstr)&gt;
-
-Takes two strings containing a list of comma- or space-separated items
-and returns what items were removed from or added to the new one, 
-compared to the old one. Returns a list, where the first entry is a scalar
-containing removed items, and the second entry is a scalar containing added
-items.
-
</del><span class="cx"> =item C&lt;wrap_hard($string, $size)&gt;
</span><span class="cx"> 
</span><span class="cx"> Wraps a string, so that a line is I&lt;never&gt; longer than C&lt;$size&gt;.
</span><span class="lines">@@ -906,6 +1052,12 @@
</span><span class="cx"> 
</span><span class="cx"> Disable utf8 on STDOUT (and display raw data instead).
</span><span class="cx"> 
</span><ins>+=item C&lt;detect_encoding($str)&gt;
+
+Guesses what encoding a given data is encoded in, returning the canonical name
+of the detected encoding (which may be different from the MIME charset 
+specification).
+
</ins><span class="cx"> =item C&lt;clean_text($str)&gt;
</span><span class="cx"> Returns the parameter &quot;cleaned&quot; by exchanging non-printable characters with spaces.
</span><span class="cx"> Specifically characters (ASCII 0 through 31) and (ASCII 127) will become ASCII 32 (Space).
</span><span class="lines">@@ -938,6 +1090,14 @@
</span><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><ins>+
+=item C&lt;template_var&gt;
+
+This is a method of getting the value of a variable from a template in
+Perl code. The available variables are in the C&lt;global/field-descs.none.tmpl&gt;
+template. Just pass in the name of the variable that you want the value of.
+
+
</ins><span class="cx"> =back
</span><span class="cx"> 
</span><span class="cx"> =head2 Formatting Time
</span><span class="lines">@@ -946,20 +1106,22 @@
</span><span class="cx"> 
</span><span class="cx"> =item C&lt;format_time($time)&gt;
</span><span class="cx"> 
</span><del>-Takes a time, converts it to the desired format and appends the timezone
-as defined in editparams.cgi, if desired. This routine will be expanded
-in the future to adjust for user preferences regarding what timezone to
-display times in.
</del><ins>+Takes a time and converts it to the desired format and timezone.
+If no format is given, the routine guesses the correct one and returns
+an empty array if it cannot. If no timezone is given, the user's timezone
+is used, as defined in his preferences.
</ins><span class="cx"> 
</span><span class="cx"> This routine is mainly called from templates to filter dates, see
</span><del>-&quot;FILTER time&quot; in Templates.pm. In this case, $format is undefined and
-the routine has to &quot;guess&quot; the date format that was passed to $dbh-&gt;sql_date_format().
</del><ins>+&quot;FILTER time&quot; in L&lt;Bugzilla::Template&gt;.
</ins><span class="cx"> 
</span><ins>+=item C&lt;datetime_from($time, $timezone)&gt;
</ins><span class="cx"> 
</span><del>-=item C&lt;format_time_decimal($time)&gt;
</del><ins>+Returns a DateTime object given a date string. If the string is not in some
+valid date format that C&lt;strptime&gt; understands, we return C&lt;undef&gt;.
</ins><span class="cx"> 
</span><del>-Returns a number with 2 digit precision, unless the last digit is a 0. Then it 
-returns only 1 digit precision.
</del><ins>+You can optionally specify a timezone for the returned date. If not
+specified, defaults to the currently-logged-in user's timezone, or
+the Bugzilla server's local timezone if there isn't a logged-in user.
</ins><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><span class="lines">@@ -979,12 +1141,14 @@
</span><span class="cx"> 
</span><span class="cx"> =over 4
</span><span class="cx"> 
</span><del>-=item C&lt;bz_crypt($password)&gt;
</del><ins>+=item C&lt;bz_crypt($password, $salt)&gt;
</ins><span class="cx"> 
</span><del>-Takes a string and returns a C&lt;crypt&gt;ed value for it, using a random salt.
</del><ins>+Takes a string and returns a hashed (encrypted) value for it, using a
+random salt. An optional salt string may also be passed in.
</ins><span class="cx"> 
</span><del>-Please always use this function instead of the built-in perl &quot;crypt&quot;
-when initially encrypting a password.
</del><ins>+Please always use this function instead of the built-in perl C&lt;crypt&gt;
+function, when checking or setting a password. Bugzilla does not use
+C&lt;crypt&gt;.
</ins><span class="cx"> 
</span><span class="cx"> =begin undocumented
</span><span class="cx"> 
</span><span class="lines">@@ -1020,3 +1184,20 @@
</span><span class="cx"> the check is successful, else returns 0.
</span><span class="cx"> 
</span><span class="cx"> =back
</span><ins>+
+=head2 Database
+
+=over
+
+=item C&lt;on_main_db&gt;
+
+Runs a block of code always on the main DB. Useful for when you're inside
+a subroutine and need to do some writes to the database, but don't know
+if Bugzilla is currently using the shadowdb or not. Used like:
+
+ on_main_db {
+     my $dbh = Bugzilla-&gt;dbh;
+     $dbh-&gt;do(&quot;INSERT ...&quot;);
+ }
+
+=back
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaVersionpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/Version.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Version.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Version.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -14,6 +14,7 @@
</span><span class="cx"> #
</span><span class="cx"> # Contributor(s): Tiago R. Mello &lt;timello@async.com.br&gt;
</span><span class="cx"> #                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
</span><ins>+#                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
</ins><span class="cx"> 
</span><span class="cx"> use strict;
</span><span class="cx"> 
</span><span class="lines">@@ -25,6 +26,8 @@
</span><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> use Bugzilla::Error;
</span><span class="cx"> 
</span><ins>+use Scalar::Util qw(blessed);
+
</ins><span class="cx"> ################################
</span><span class="cx"> #####   Initialization     #####
</span><span class="cx"> ################################
</span><span class="lines">@@ -32,18 +35,41 @@
</span><span class="cx"> use constant DEFAULT_VERSION =&gt; 'unspecified';
</span><span class="cx"> 
</span><span class="cx"> use constant DB_TABLE =&gt; 'versions';
</span><ins>+use constant NAME_FIELD =&gt; 'value';
+# This is &quot;id&quot; because it has to be filled in and id is probably the fastest.
+# We do a custom sort in new_from_list below.
+use constant LIST_ORDER =&gt; 'id';
</ins><span class="cx"> 
</span><span class="cx"> use constant DB_COLUMNS =&gt; qw(
</span><span class="cx">     id
</span><span class="cx">     value
</span><span class="cx">     product_id
</span><ins>+    isactive
</ins><span class="cx"> );
</span><span class="cx"> 
</span><del>-use constant NAME_FIELD =&gt; 'value';
-# This is &quot;id&quot; because it has to be filled in and id is probably the fastest.
-# We do a custom sort in new_from_list below.
-use constant LIST_ORDER =&gt; 'id';
</del><ins>+use constant REQUIRED_FIELD_MAP =&gt; {
+    product_id =&gt; 'product',
+};
</ins><span class="cx"> 
</span><ins>+use constant UPDATE_COLUMNS =&gt; qw(
+    value
+    isactive
+);
+
+use constant VALIDATORS =&gt; {
+    product  =&gt; \&amp;_check_product,
+    value    =&gt; \&amp;_check_value,
+    isactive =&gt; \&amp;Bugzilla::Object::check_boolean,
+};
+
+use constant VALIDATOR_DEPENDENCIES =&gt; {
+    value =&gt; ['product'],
+};
+
+################################
+# Methods
+################################
+
</ins><span class="cx"> sub new {
</span><span class="cx">     my $class = shift;
</span><span class="cx">     my $param = shift;
</span><span class="lines">@@ -79,6 +105,14 @@
</span><span class="cx">     return [sort { vers_cmp(lc($a-&gt;name), lc($b-&gt;name)) } @$list];
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub run_create_validators {
+    my $class  = shift;
+    my $params = $class-&gt;SUPER::run_create_validators(@_);
+    my $product = delete $params-&gt;{product};
+    $params-&gt;{product_id} = $product-&gt;id;
+    return $params;
+}
+
</ins><span class="cx"> sub bug_count {
</span><span class="cx">     my $self = shift;
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="lines">@@ -92,6 +126,19 @@
</span><span class="cx">     return $self-&gt;{'bug_count'};
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub update {
+    my $self = shift;
+    my ($changes, $old_self) = $self-&gt;SUPER::update(@_);
+
+    if (exists $changes-&gt;{value}) {
+        my $dbh = Bugzilla-&gt;dbh;
+        $dbh-&gt;do('UPDATE bugs SET version = ?
+                  WHERE version = ? AND product_id = ?',
+                  undef, ($self-&gt;name, $old_self-&gt;name, $self-&gt;product_id));
+    }
+    return $changes;
+}
+
</ins><span class="cx"> sub remove_from_db {
</span><span class="cx">     my $self = shift;
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="lines">@@ -101,78 +148,53 @@
</span><span class="cx">     if ($self-&gt;bug_count) {
</span><span class="cx">         ThrowUserError(&quot;version_has_bugs&quot;, { nb =&gt; $self-&gt;bug_count });
</span><span class="cx">     }
</span><del>-
-    $dbh-&gt;do(q{DELETE FROM versions WHERE product_id = ? AND value = ?},
-              undef, ($self-&gt;product_id, $self-&gt;name));
</del><ins>+    $self-&gt;SUPER::remove_from_db();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub update {
-    my $self = shift;
-    my ($name, $product) = @_;
-    my $dbh = Bugzilla-&gt;dbh;
-
-    $name || ThrowUserError('version_not_specified');
-
-    # Remove unprintable characters
-    $name = clean_text($name);
-
-    return 0 if ($name eq $self-&gt;name);
-    my $version = new Bugzilla::Version({ product =&gt; $product, name =&gt; $name });
-
-    if ($version) {
-        ThrowUserError('version_already_exists',
-                       {'name' =&gt; $version-&gt;name,
-                        'product' =&gt; $product-&gt;name});
-    }
-
-    trick_taint($name);
-    $dbh-&gt;do(&quot;UPDATE bugs SET version = ?
-              WHERE version = ? AND product_id = ?&quot;, undef,
-              ($name, $self-&gt;name, $self-&gt;product_id));
-
-    $dbh-&gt;do(&quot;UPDATE versions SET value = ?
-              WHERE product_id = ? AND value = ?&quot;, undef,
-              ($name, $self-&gt;product_id, $self-&gt;name));
-
-    $self-&gt;{'value'} = $name;
-
-    return 1;
-}
-
</del><span class="cx"> ###############################
</span><span class="cx"> #####     Accessors        ####
</span><span class="cx"> ###############################
</span><span class="cx"> 
</span><del>-sub name       { return $_[0]-&gt;{'value'};      }
</del><span class="cx"> sub product_id { return $_[0]-&gt;{'product_id'}; }
</span><ins>+sub is_active  { return $_[0]-&gt;{'isactive'};   }
</ins><span class="cx"> 
</span><del>-###############################
-#####     Subroutines       ###
-###############################
</del><ins>+sub product {
+    my $self = shift;
</ins><span class="cx"> 
</span><del>-sub create {
-    my ($name, $product) = @_;
-    my $dbh = Bugzilla-&gt;dbh;
</del><ins>+    require Bugzilla::Product;
+    $self-&gt;{'product'} ||= new Bugzilla::Product($self-&gt;product_id);
+    return $self-&gt;{'product'};
+}
</ins><span class="cx"> 
</span><del>-    # Cleanups and validity checks
-    $name || ThrowUserError('version_blank_name');
</del><ins>+################################
+# Validators
+################################
</ins><span class="cx"> 
</span><ins>+sub set_name      { $_[0]-&gt;set('value', $_[1]);    }
+sub set_is_active { $_[0]-&gt;set('isactive', $_[1]); }
+
+sub _check_value {
+    my ($invocant, $name, undef, $params) = @_;
+    my $product = blessed($invocant) ? $invocant-&gt;product : $params-&gt;{product};
+
+    $name = trim($name);
+    $name || ThrowUserError('version_blank_name');
</ins><span class="cx">     # Remove unprintable characters
</span><span class="cx">     $name = clean_text($name);
</span><span class="cx"> 
</span><span class="cx">     my $version = new Bugzilla::Version({ product =&gt; $product, name =&gt; $name });
</span><del>-    if ($version) {
-        ThrowUserError('version_already_exists',
-                       {'name' =&gt; $version-&gt;name,
-                        'product' =&gt; $product-&gt;name});
</del><ins>+    if ($version &amp;&amp; (!ref $invocant || $version-&gt;id != $invocant-&gt;id)) {
+        ThrowUserError('version_already_exists', { name    =&gt; $version-&gt;name,
+                                                   product =&gt; $product-&gt;name });
</ins><span class="cx">     }
</span><ins>+    return $name;
+}
</ins><span class="cx"> 
</span><del>-    # Add the new version
-    trick_taint($name);
-    $dbh-&gt;do(q{INSERT INTO versions (value, product_id)
-               VALUES (?, ?)}, undef, ($name, $product-&gt;id));
-
-    return new Bugzilla::Version($dbh-&gt;bz_last_key('versions', 'id'));
</del><ins>+sub _check_product {
+    my ($invocant, $product) = @_;
+    $product || ThrowCodeError('param_required',
+                    { function =&gt; &quot;$invocant-&gt;create&quot;, param =&gt; 'product' });
+    return Bugzilla-&gt;user-&gt;check_can_admin_product($product-&gt;name);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> 1;
</span><span class="lines">@@ -187,37 +209,33 @@
</span><span class="cx"> 
</span><span class="cx">     use Bugzilla::Version;
</span><span class="cx"> 
</span><del>-    my $version = new Bugzilla::Version(1, 'version_value');
</del><ins>+    my $version = new Bugzilla::Version({ name =&gt; $name, product =&gt; $product });
</ins><span class="cx"> 
</span><ins>+    my $value = $version-&gt;name;
</ins><span class="cx">     my $product_id = $version-&gt;product_id;
</span><del>-    my $value = $version-&gt;value;
</del><ins>+    my $product = $version-&gt;product;
</ins><span class="cx"> 
</span><del>-    $version-&gt;remove_from_db;
</del><ins>+    my $version = Bugzilla::Version-&gt;create(
+        { value =&gt; $name, product =&gt; $product });
</ins><span class="cx"> 
</span><del>-    my $updated = $version-&gt;update($version_name, $product);
</del><ins>+    $version-&gt;set_name($new_name);
+    $version-&gt;update();
</ins><span class="cx"> 
</span><del>-    my $version = $hash_ref-&gt;{'version_value'};
</del><ins>+    $version-&gt;remove_from_db;
</ins><span class="cx"> 
</span><del>-    my $version = Bugzilla::Version::create($version_name, $product);
-
</del><span class="cx"> =head1 DESCRIPTION
</span><span class="cx"> 
</span><del>-Version.pm represents a Product Version object.
</del><ins>+Version.pm represents a Product Version object. It is an implementation
+of L&lt;Bugzilla::Object&gt;, and thus provides all methods that
+L&lt;Bugzilla::Object&gt; provides.
</ins><span class="cx"> 
</span><ins>+The methods that are specific to C&lt;Bugzilla::Version&gt; are listed
+below.
+
</ins><span class="cx"> =head1 METHODS
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><del>-=item C&lt;new($product_id, $value)&gt;
-
- Description: The constructor is used to load an existing version
-              by passing a product id and a version value.
-
- Params:      $product_id - Integer with a product id.
-              $value - String with a version value.
-
- Returns:     A Bugzilla::Version object.
-
</del><span class="cx"> =item C&lt;bug_count()&gt;
</span><span class="cx"> 
</span><span class="cx">  Description: Returns the total of bugs that belong to the version.
</span><span class="lines">@@ -226,38 +244,6 @@
</span><span class="cx"> 
</span><span class="cx">  Returns:     Integer with the number of bugs.
</span><span class="cx"> 
</span><del>-=item C&lt;remove_from_db()&gt;
-
- Description: Removes the version from the database.
-
- Params:      none.
-
- Retruns:     none.
-
-=item C&lt;update($name, $product)&gt;
-
- Description: Update the value of the version.
-
- Params:      $name - String with the new version value.
-              $product - Bugzilla::Product object the version belongs to.
-
- Returns:     An integer - 1 if the version has been updated, else 0.
-
</del><span class="cx"> =back
</span><span class="cx"> 
</span><del>-=head1 SUBROUTINES
-
-=over
-
-=item C&lt;create($version_name, $product)&gt;
-
- Description: Create a new version for the given product.
-
- Params:      $version_name - String with a version value.
-              $product - A Bugzilla::Product object.
-
- Returns:     A Bugzilla::Version object.
-
-=back
-
</del><span class="cx"> =cut
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaWebServiceBugpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Bug.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Bug.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Bug.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -16,93 +16,379 @@
</span><span class="cx"> #                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
</span><span class="cx"> #                 Mads Bondo Dydensborg &lt;mbd@dbc.dk&gt;
</span><span class="cx"> #                 Tsahi Asher &lt;tsahi_75@yahoo.com&gt;
</span><ins>+#                 Noura Elhawary &lt;nelhawar@redhat.com&gt;
+#                 Frank Becker &lt;Frank@Frank-Becker.de&gt;
+#                 Dave Lawrence &lt;dkl@redhat.com&gt;
</ins><span class="cx"> 
</span><span class="cx"> package Bugzilla::WebService::Bug;
</span><span class="cx"> 
</span><span class="cx"> use strict;
</span><span class="cx"> use base qw(Bugzilla::WebService);
</span><del>-import SOAP::Data qw(type);
</del><span class="cx"> 
</span><ins>+use Bugzilla::Comment;
</ins><span class="cx"> use Bugzilla::Constants;
</span><span class="cx"> use Bugzilla::Error;
</span><span class="cx"> use Bugzilla::Field;
</span><span class="cx"> use Bugzilla::WebService::Constants;
</span><ins>+use Bugzilla::WebService::Util qw(filter filter_wants validate);
</ins><span class="cx"> use Bugzilla::Bug;
</span><span class="cx"> use Bugzilla::BugMail;
</span><del>-use Bugzilla::Util qw(trim);
</del><ins>+use Bugzilla::Util qw(trick_taint trim);
+use Bugzilla::Version;
+use Bugzilla::Milestone;
+use Bugzilla::Status;
+use Bugzilla::Token qw(issue_hash_token);
</ins><span class="cx"> 
</span><span class="cx"> #############
</span><span class="cx"> # Constants #
</span><span class="cx"> #############
</span><span class="cx"> 
</span><del>-# This maps the names of internal Bugzilla bug fields to things that would
-# make sense to somebody who's not intimately familiar with the inner workings
-# of Bugzilla. (These are the field names that the WebService uses.)
-use constant FIELD_MAP =&gt; {
-    status      =&gt; 'bug_status',
-    severity    =&gt; 'bug_severity',
-    description =&gt; 'comment',
-    summary     =&gt; 'short_desc',
-    platform    =&gt; 'rep_platform',
</del><ins>+use constant PRODUCT_SPECIFIC_FIELDS =&gt; qw(version target_milestone component);
+
+use constant DATE_FIELDS =&gt; {
+    comments =&gt; ['new_since'],
+    search   =&gt; ['last_change_time', 'creation_time'],
</ins><span class="cx"> };
</span><span class="cx"> 
</span><del>-use constant GLOBAL_SELECT_FIELDS =&gt; qw(
-    bug_severity
-    bug_status
-    op_sys
-    priority
-    rep_platform
-    resolution
</del><ins>+use constant BASE64_FIELDS =&gt; {
+    add_attachment =&gt; ['data'],
+};
+
+use constant READ_ONLY =&gt; qw(
+    attachments
+    comments
+    fields
+    get
+    history
+    legal_values
+    search
</ins><span class="cx"> );
</span><span class="cx"> 
</span><del>-use constant PRODUCT_SPECIFIC_FIELDS =&gt; qw(version target_milestone component);
-
</del><span class="cx"> ######################################################
</span><span class="cx"> # Add aliases here for old method name compatibility #
</span><span class="cx"> ######################################################
</span><span class="cx"> 
</span><del>-BEGIN { *get_bugs = \&amp;get }
</del><ins>+BEGIN { 
+  # In 3.0, get was called get_bugs
+  *get_bugs = \&amp;get;
+  # Before 3.4rc1, &quot;history&quot; was get_history.
+  *get_history = \&amp;history;
+}
</ins><span class="cx"> 
</span><span class="cx"> ###########
</span><span class="cx"> # Methods #
</span><span class="cx"> ###########
</span><span class="cx"> 
</span><ins>+sub fields {
+    my ($self, $params) = validate(@_, 'ids', 'names');
+
+    my @fields;
+    if (defined $params-&gt;{ids}) {
+        my $ids = $params-&gt;{ids};
+        foreach my $id (@$ids) {
+            my $loop_field = Bugzilla::Field-&gt;check({ id =&gt; $id });
+            push(@fields, $loop_field);
+        }
+    }
+
+    if (defined $params-&gt;{names}) {
+        my $names = $params-&gt;{names};
+        foreach my $field_name (@$names) {
+            my $loop_field = Bugzilla::Field-&gt;check($field_name);
+            # Don't push in duplicate fields if we also asked for this field
+            # in &quot;ids&quot;.
+            if (!grep($_-&gt;id == $loop_field-&gt;id, @fields)) {
+                push(@fields, $loop_field);
+            }
+        }
+    }
+
+    if (!defined $params-&gt;{ids} and !defined $params-&gt;{names}) {
+        @fields = @{ Bugzilla-&gt;fields({ obsolete =&gt; 0 }) };
+    }
+
+    my @fields_out;
+    foreach my $field (@fields) {
+        my $visibility_field = $field-&gt;visibility_field
+                               ? $field-&gt;visibility_field-&gt;name : undef;
+        my $vis_values = $field-&gt;visibility_values;
+        my $value_field = $field-&gt;value_field
+                          ? $field-&gt;value_field-&gt;name : undef;
+
+        my (@values, $has_values);
+        if ( ($field-&gt;is_select and $field-&gt;name ne 'product')
+             or grep($_ eq $field-&gt;name, PRODUCT_SPECIFIC_FIELDS))
+        {
+             $has_values = 1;
+             @values = @{ $self-&gt;_legal_field_values({ field =&gt; $field }) };
+        }
+
+        if (grep($_ eq $field-&gt;name, PRODUCT_SPECIFIC_FIELDS)) {
+             $value_field = 'product';
+        }
+
+        my %field_data = (
+           id                =&gt; $self-&gt;type('int', $field-&gt;id),
+           type              =&gt; $self-&gt;type('int', $field-&gt;type),
+           is_custom         =&gt; $self-&gt;type('boolean', $field-&gt;custom),
+           name              =&gt; $self-&gt;type('string', $field-&gt;name),
+           display_name      =&gt; $self-&gt;type('string', $field-&gt;description),
+           is_mandatory      =&gt; $self-&gt;type('boolean', $field-&gt;is_mandatory),
+           is_on_bug_entry   =&gt; $self-&gt;type('boolean', $field-&gt;enter_bug),
+           visibility_field  =&gt; $self-&gt;type('string', $visibility_field),
+           visibility_values =&gt;
+              [ map { $self-&gt;type('string', $_-&gt;name) } @$vis_values ],
+        );
+        if ($has_values) {
+           $field_data{value_field} = $self-&gt;type('string', $value_field);
+           $field_data{values}      = \@values;
+        };
+        push(@fields_out, filter $params, \%field_data);
+    }
+
+    return { fields =&gt; \@fields_out };
+}
+
+sub _legal_field_values {
+    my ($self, $params) = @_;
+    my $field = $params-&gt;{field};
+    my $field_name = $field-&gt;name;
+    my $user = Bugzilla-&gt;user;
+
+    my @result;
+    if (grep($_ eq $field_name, PRODUCT_SPECIFIC_FIELDS)) {
+        my @list;
+        if ($field_name eq 'version') {
+            @list = Bugzilla::Version-&gt;get_all;
+        }
+        elsif ($field_name eq 'component') {
+            @list = Bugzilla::Component-&gt;get_all;
+        }
+        else {
+            @list = Bugzilla::Milestone-&gt;get_all;
+        }
+
+        foreach my $value (@list) {
+            my $sortkey = $field_name eq 'target_milestone'
+                          ? $value-&gt;sortkey : 0;
+            # XXX This is very slow for large numbers of values.
+            my $product_name = $value-&gt;product-&gt;name;
+            if ($user-&gt;can_see_product($product_name)) {
+                push(@result, {
+                    name     =&gt; $self-&gt;type('string', $value-&gt;name),
+                    sort_key =&gt; $self-&gt;type('int', $sortkey),
+                    sortkey  =&gt; $self-&gt;type('int', $sortkey), # deprecated
+                    visibility_values =&gt; [$self-&gt;type('string', $product_name)],
+                });
+            }
+        }
+    }
+
+    elsif ($field_name eq 'bug_status') {
+        my @status_all = Bugzilla::Status-&gt;get_all;
+        foreach my $status (@status_all) {
+            my @can_change_to;
+            foreach my $change_to (@{ $status-&gt;can_change_to }) {
+                # There's no need to note that a status can transition
+                # to itself.
+                next if $change_to-&gt;id == $status-&gt;id;
+                my %change_to_hash = (
+                    name =&gt; $self-&gt;type('string', $change_to-&gt;name),
+                    comment_required =&gt; $self-&gt;type('boolean', 
+                        $change_to-&gt;comment_required_on_change_from($status)),
+                );
+                push(@can_change_to, \%change_to_hash);
+            }
+
+            push (@result, {
+               name     =&gt; $self-&gt;type('string', $status-&gt;name),
+               is_open  =&gt; $self-&gt;type('boolean', $status-&gt;is_open),
+               sort_key =&gt; $self-&gt;type('int', $status-&gt;sortkey),
+               sortkey  =&gt; $self-&gt;type('int', $status-&gt;sortkey), # deprecated
+               can_change_to =&gt; \@can_change_to,
+               visibility_values =&gt; [],
+            });
+        }
+    }
+
+    else {
+        my @values = Bugzilla::Field::Choice-&gt;type($field)-&gt;get_all();
+        foreach my $value (@values) {
+            my $vis_val = $value-&gt;visibility_value;
+            push(@result, {
+                name     =&gt; $self-&gt;type('string', $value-&gt;name),
+                sort_key =&gt; $self-&gt;type('int'   , $value-&gt;sortkey),
+                sortkey  =&gt; $self-&gt;type('int'   , $value-&gt;sortkey), # deprecated
+                visibility_values =&gt; [
+                    defined $vis_val ? $self-&gt;type('string', $vis_val-&gt;name) 
+                                     : ()
+                ],
+            });
+        }
+    }
+
+    return \@result;
+}
+
+sub comments {
+    my ($self, $params) = validate(@_, 'ids', 'comment_ids');
+
+    if (!(defined $params-&gt;{ids} || defined $params-&gt;{comment_ids})) {
+        ThrowCodeError('params_required',
+                       { function =&gt; 'Bug.comments',
+                         params   =&gt; ['ids', 'comment_ids'] });
+    }
+
+    my $bug_ids = $params-&gt;{ids} || [];
+    my $comment_ids = $params-&gt;{comment_ids} || [];
+
+    my $dbh  = Bugzilla-&gt;dbh;
+    my $user = Bugzilla-&gt;user;
+
+    my %bugs;
+    foreach my $bug_id (@$bug_ids) {
+        my $bug = Bugzilla::Bug-&gt;check($bug_id);
+        # We want the API to always return comments in the same order.
+   
+        my $comments = $bug-&gt;comments({ order =&gt; 'oldest_to_newest',
+                                        after =&gt; $params-&gt;{new_since} });
+        my @result;
+        foreach my $comment (@$comments) {
+            next if $comment-&gt;is_private &amp;&amp; !$user-&gt;is_insider;
+            push(@result, $self-&gt;_translate_comment($comment, $params));
+        }
+        $bugs{$bug-&gt;id}{'comments'} = \@result;
+    }
+
+    my %comments;
+    if (scalar @$comment_ids) {
+        my @ids = map { trim($_) } @$comment_ids;
+        my $comment_data = Bugzilla::Comment-&gt;new_from_list(\@ids);
+
+        # See if we were passed any invalid comment ids.
+        my %got_ids = map { $_-&gt;id =&gt; 1 } @$comment_data;
+        foreach my $comment_id (@ids) {
+            if (!$got_ids{$comment_id}) {
+                ThrowUserError('comment_id_invalid', { id =&gt; $comment_id });
+            }
+        }

+        # Now make sure that we can see all the associated bugs.
+        my %got_bug_ids = map { $_-&gt;bug_id =&gt; 1 } @$comment_data;
+        Bugzilla::Bug-&gt;check($_) foreach (keys %got_bug_ids);
+
+        foreach my $comment (@$comment_data) {
+            if ($comment-&gt;is_private &amp;&amp; !$user-&gt;is_insider) {
+                ThrowUserError('comment_is_private', { id =&gt; $comment-&gt;id });
+            }
+            $comments{$comment-&gt;id} =
+                $self-&gt;_translate_comment($comment, $params);
+        }
+    }
+
+    return { bugs =&gt; \%bugs, comments =&gt; \%comments };
+}
+
+# Helper for Bug.comments
+sub _translate_comment {
+    my ($self, $comment, $filters) = @_;
+    my $attach_id = $comment-&gt;is_about_attachment ? $comment-&gt;extra_data
+                                                  : undef;
+    return filter $filters, {
+        id         =&gt; $self-&gt;type('int', $comment-&gt;id),
+        bug_id     =&gt; $self-&gt;type('int', $comment-&gt;bug_id),
+        creator    =&gt; $self-&gt;type('string', $comment-&gt;author-&gt;login),
+        author     =&gt; $self-&gt;type('string', $comment-&gt;author-&gt;login),
+        time       =&gt; $self-&gt;type('dateTime', $comment-&gt;creation_ts),
+        is_private =&gt; $self-&gt;type('boolean', $comment-&gt;is_private),
+        text       =&gt; $self-&gt;type('string', $comment-&gt;body_full),
+        attachment_id =&gt; $self-&gt;type('int', $attach_id),
+    };
+}
+
</ins><span class="cx"> sub get {
</span><del>-    my ($self, $params) = @_;
</del><ins>+    my ($self, $params) = validate(@_, 'ids');
+
</ins><span class="cx">     my $ids = $params-&gt;{ids};
</span><span class="cx">     defined $ids || ThrowCodeError('param_required', { param =&gt; 'ids' });
</span><span class="cx"> 
</span><ins>+    my @bugs;
+    my @faults;
+    foreach my $bug_id (@$ids) {
+        my $bug;
+        if ($params-&gt;{permissive}) {
+            eval { $bug = Bugzilla::Bug-&gt;check($bug_id); };
+            if ($@) {
+                push(@faults, {id =&gt; $bug_id,
+                               faultString =&gt; $@-&gt;faultstring,
+                               faultCode =&gt; $@-&gt;faultcode,
+                              }
+                    );
+                undef $@;
+                next;
+            }
+        }
+        else {
+            $bug = Bugzilla::Bug-&gt;check($bug_id);
+        }
+        push(@bugs, $self-&gt;_bug_to_hash($bug, $params));
+    }
+
+    return { bugs =&gt; \@bugs, faults =&gt; \@faults };
+}
+
+# this is a function that gets bug activity for list of bug ids 
+# it can be called as the following:
+# $call = $rpc-&gt;call( 'Bug.history', { ids =&gt; [1,2] });
+sub history {
+    my ($self, $params) = validate(@_, 'ids');
+
+    my $ids = $params-&gt;{ids};
+    defined $ids || ThrowCodeError('param_required', { param =&gt; 'ids' });
+
</ins><span class="cx">     my @return;
</span><ins>+
</ins><span class="cx">     foreach my $bug_id (@$ids) {
</span><del>-        ValidateBugID($bug_id);
-        my $bug = new Bugzilla::Bug($bug_id);
</del><ins>+        my %item;
+        my $bug = Bugzilla::Bug-&gt;check($bug_id);
+        $bug_id = $bug-&gt;id;
+        $item{id} = $self-&gt;type('int', $bug_id);
</ins><span class="cx"> 
</span><del>-        # Timetracking fields are deleted if the user doesn't belong to
-        # the corresponding group.
-        unless (Bugzilla-&gt;user-&gt;in_group(Bugzilla-&gt;params-&gt;{'timetrackinggroup'})) {
-            delete $bug-&gt;{'estimated_time'};
-            delete $bug-&gt;{'remaining_time'};
-            delete $bug-&gt;{'deadline'};
</del><ins>+        my ($activity) = Bugzilla::Bug::GetBugActivity($bug_id);
+
+        my @history;
+        foreach my $changeset (@$activity) {
+            my %bug_history;
+            $bug_history{when} = $self-&gt;type('dateTime', $changeset-&gt;{when});
+            $bug_history{who}  = $self-&gt;type('string', $changeset-&gt;{who});
+            $bug_history{changes} = [];
+            foreach my $change (@{ $changeset-&gt;{changes} }) {
+                my $attach_id = delete $change-&gt;{attachid};
+                if ($attach_id) {
+                    $change-&gt;{attachment_id} = $self-&gt;type('int', $attach_id);
+                }
+                $change-&gt;{removed} = $self-&gt;type('string', $change-&gt;{removed});
+                $change-&gt;{added}   = $self-&gt;type('string', $change-&gt;{added});
+                $change-&gt;{field_name} = $self-&gt;type('string',
+                    delete $change-&gt;{fieldname});
+                push (@{$bug_history{changes}}, $change);
+            }
+            
+            push (@history, \%bug_history);
</ins><span class="cx">         }
</span><del>-        # This is done in this fashion in order to produce a stable API.
-        # The internals of Bugzilla::Bug are not stable enough to just
-        # return them directly.
-        my $creation_ts = $self-&gt;datetime_format($bug-&gt;creation_ts);
-        my $delta_ts    = $self-&gt;datetime_format($bug-&gt;delta_ts);
-        my %item;
-        $item{'creation_time'}    = type('dateTime')-&gt;value($creation_ts);
-        $item{'last_change_time'} = type('dateTime')-&gt;value($delta_ts);
-        $item{'internals'}        = $bug;
-        $item{'id'}               = type('int')-&gt;value($bug-&gt;bug_id);
-        $item{'summary'}          = type('string')-&gt;value($bug-&gt;short_desc);
</del><span class="cx"> 
</span><ins>+        $item{history} = \@history;
+
+        # alias is returned in case users passes a mixture of ids and aliases
+        # then they get to know which bug activity relates to which value  
+        # they passed
</ins><span class="cx">         if (Bugzilla-&gt;params-&gt;{'usebugaliases'}) {
</span><del>-            $item{'alias'} = type('string')-&gt;value($bug-&gt;alias);
</del><ins>+            $item{alias} = $self-&gt;type('string', $bug-&gt;alias);
</ins><span class="cx">         }
</span><span class="cx">         else {
</span><span class="cx">             # For API reasons, we always want the value to appear, we just
</span><span class="cx">             # don't want it to have a value if aliases are turned off.
</span><del>-            $item{'alias'} = undef;
</del><ins>+            $item{alias} = undef;
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         push(@return, \%item);
</span><span class="lines">@@ -111,39 +397,195 @@
</span><span class="cx">     return { bugs =&gt; \@return };
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-
-sub create {
</del><ins>+sub search {
</ins><span class="cx">     my ($self, $params) = @_;
</span><ins>+    
+    if ( defined($params-&gt;{offset}) and !defined($params-&gt;{limit}) ) {
+        ThrowCodeError('param_required', 
+                       { param =&gt; 'limit', function =&gt; 'Bug.search()' });
+    }
+    
+    $params = Bugzilla::Bug::map_fields($params);
+    delete $params-&gt;{WHERE};
</ins><span class="cx"> 
</span><del>-    Bugzilla-&gt;login(LOGIN_REQUIRED);
</del><ins>+    unless (Bugzilla-&gt;user-&gt;is_timetracker) {
+        delete $params-&gt;{$_} foreach qw(estimated_time remaining_time deadline);
+    }
</ins><span class="cx"> 
</span><del>-    my %field_values;
-    foreach my $field (keys %$params) {
-        my $field_name = FIELD_MAP-&gt;{$field} || $field;
-        $field_values{$field_name} = $params-&gt;{$field}; 
</del><ins>+    # Do special search types for certain fields.
+    if ( my $bug_when = delete $params-&gt;{delta_ts} ) {
+        $params-&gt;{WHERE}-&gt;{'delta_ts &gt;= ?'} = $bug_when;
</ins><span class="cx">     }
</span><ins>+    if (my $when = delete $params-&gt;{creation_ts}) {
+        $params-&gt;{WHERE}-&gt;{'creation_ts &gt;= ?'} = $when;
+    }
+    if (my $summary = delete $params-&gt;{short_desc}) {
+        my @strings = ref $summary ? @$summary : ($summary);
+        my @likes = (&quot;short_desc LIKE ?&quot;) x @strings;
+        my $clause = join(' OR ', @likes);
+        $params-&gt;{WHERE}-&gt;{&quot;($clause)&quot;} = [map { &quot;\%$_\%&quot; } @strings];
+    }
+    if (my $whiteboard = delete $params-&gt;{status_whiteboard}) {
+        my @strings = ref $whiteboard ? @$whiteboard : ($whiteboard);
+        my @likes = (&quot;status_whiteboard LIKE ?&quot;) x @strings;
+        my $clause = join(' OR ', @likes);
+        $params-&gt;{WHERE}-&gt;{&quot;($clause)&quot;} = [map { &quot;\%$_\%&quot; } @strings];
+    }
+   
+    # We want include_fields and exclude_fields to be passed to
+    # _bug_to_hash but not to Bugzilla::Bug-&gt;match so we copy the 
+    # params and delete those before passing to Bugzilla::Bug-&gt;match.
+    my %match_params = %{ $params };
+    delete $match_params{'include_fields'};
+    delete $match_params{'exclude_fields'};
</ins><span class="cx"> 
</span><del>-    # WebService users can't set the creation date of a bug.
-    delete $field_values{'creation_ts'};
</del><ins>+    my $bugs = Bugzilla::Bug-&gt;match(\%match_params);
+    my $visible = Bugzilla-&gt;user-&gt;visible_bugs($bugs);
+    my @hashes = map { $self-&gt;_bug_to_hash($_, $params) } @$visible;
+    return { bugs =&gt; \@hashes };
+}
</ins><span class="cx"> 
</span><del>-    my $bug = Bugzilla::Bug-&gt;create(\%field_values);
</del><ins>+sub possible_duplicates {
+    my ($self, $params) = validate(@_, 'product');
+    my $user = Bugzilla-&gt;user;
</ins><span class="cx"> 
</span><del>-    Bugzilla::BugMail::Send($bug-&gt;bug_id, { changer =&gt; $bug-&gt;reporter-&gt;login });
</del><ins>+    # Undo the array-ification that validate() does, for &quot;summary&quot;.
+    $params-&gt;{summary} || ThrowCodeError('param_required',
+        { function =&gt; 'Bug.possible_duplicates', param =&gt; 'summary' });
</ins><span class="cx"> 
</span><del>-    return { id =&gt; type('int')-&gt;value($bug-&gt;bug_id) };
</del><ins>+    my @products;
+    foreach my $name (@{ $params-&gt;{'product'} || [] }) {
+        my $object = $user-&gt;can_enter_product($name, THROW_ERROR);
+        push(@products, $object);
+    }
+
+    my $possible_dupes = Bugzilla::Bug-&gt;possible_duplicates(
+        { summary =&gt; $params-&gt;{summary}, products =&gt; \@products,
+          limit   =&gt; $params-&gt;{limit} });
+    my @hashes = map { $self-&gt;_bug_to_hash($_, $params) } @$possible_dupes;
+    return { bugs =&gt; \@hashes };
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub update {
+    my ($self, $params) = validate(@_, 'ids');
+
+    my $user = Bugzilla-&gt;login(LOGIN_REQUIRED);
+    my $dbh = Bugzilla-&gt;dbh;
+
+    # We skip certain fields because their set_ methods actually use
+    # the external names instead of the internal names.
+    $params = Bugzilla::Bug::map_fields($params, 
+        { summary =&gt; 1, platform =&gt; 1, severity =&gt; 1, url =&gt; 1 });
+
+    my $ids = delete $params-&gt;{ids};
+    defined $ids || ThrowCodeError('param_required', { param =&gt; 'ids' });
+
+    my @bugs = map { Bugzilla::Bug-&gt;check($_) } @$ids;
+
+    my %values = %$params;
+    $values{other_bugs} = \@bugs;
+
+    if (exists $values{comment} and exists $values{comment}{comment}) {
+        $values{comment}{body} = delete $values{comment}{comment};
+    }
+
+    # Prevent bugs that could be triggered by specifying fields that
+    # have valid &quot;set_&quot; functions in Bugzilla::Bug, but shouldn't be
+    # called using those field names.
+    delete $values{dependencies};
+    delete $values{flags};
+
+    foreach my $bug (@bugs) {
+        if (!$user-&gt;can_edit_product($bug-&gt;product_obj-&gt;id) ) {
+            ThrowUserError(&quot;product_edit_denied&quot;,
+                          { product =&gt; $bug-&gt;product });
+        }
+
+        $bug-&gt;set_all(\%values);
+    }
+
+    my %all_changes;
+    $dbh-&gt;bz_start_transaction();
+    foreach my $bug (@bugs) {
+        $all_changes{$bug-&gt;id} = $bug-&gt;update();
+    }
+    $dbh-&gt;bz_commit_transaction();
+    
+    foreach my $bug (@bugs) {
+        $bug-&gt;send_changes($all_changes{$bug-&gt;id});
+    }
+
+    my %api_name = reverse %{ Bugzilla::Bug::FIELD_MAP() };
+    # This doesn't normally belong in FIELD_MAP, but we do want to translate
+    # &quot;bug_group&quot; back into &quot;groups&quot;.
+    $api_name{'bug_group'} = 'groups';
+
+    my @result;
+    foreach my $bug (@bugs) {
+        my %hash = (
+            id               =&gt; $self-&gt;type('int', $bug-&gt;id),
+            last_change_time =&gt; $self-&gt;type('dateTime', $bug-&gt;delta_ts),
+            changes          =&gt; {},
+        );
+
+        # alias is returned in case users pass a mixture of ids and aliases,
+        # so that they can know which set of changes relates to which value
+        # they passed.
+        if (Bugzilla-&gt;params-&gt;{'usebugaliases'}) {
+            $hash{alias} = $self-&gt;type('string', $bug-&gt;alias);
+        }
+        else {
+            # For API reasons, we always want the alias field to appear, we
+            # just don't want it to have a value if aliases are turned off.
+            $hash{alias} = $self-&gt;type('string', '');
+        }
+
+        my %changes = %{ $all_changes{$bug-&gt;id} };
+        foreach my $field (keys %changes) {
+            my $change = $changes{$field};
+            my $api_field = $api_name{$field} || $field;
+            # We normalize undef to an empty string, so that the API
+            # stays consistent for things like Deadline that can become
+            # empty.
+            $change-&gt;[0] = '' if !defined $change-&gt;[0];
+            $change-&gt;[1] = '' if !defined $change-&gt;[1];
+            $hash{changes}-&gt;{$api_field} = {
+                removed =&gt; $self-&gt;type('string', $change-&gt;[0]),
+                added   =&gt; $self-&gt;type('string', $change-&gt;[1]) 
+            };
+        }
+
+        push(@result, \%hash);
+    }
+
+    return { bugs =&gt; \@result };
+}
+
+sub create {
+    my ($self, $params) = @_;
+    Bugzilla-&gt;login(LOGIN_REQUIRED);
+    $params = Bugzilla::Bug::map_fields($params);
+    my $bug = Bugzilla::Bug-&gt;create($params);
+    Bugzilla::BugMail::Send($bug-&gt;bug_id, { changer =&gt; $bug-&gt;reporter });
+    return { id =&gt; $self-&gt;type('int', $bug-&gt;bug_id) };
+}
+
</ins><span class="cx"> sub legal_values {
</span><span class="cx">     my ($self, $params) = @_;
</span><del>-    my $field = FIELD_MAP-&gt;{$params-&gt;{field}} || $params-&gt;{field};
</del><span class="cx"> 
</span><del>-    my @custom_select = Bugzilla-&gt;get_fields(
-        {custom =&gt; 1, type =&gt; [FIELD_TYPE_SINGLE_SELECT, FIELD_TYPE_MULTI_SELECT]});
-    # We only want field names.
-    @custom_select = map {$_-&gt;name} @custom_select;
</del><ins>+    defined $params-&gt;{field} 
+        or ThrowCodeError('param_required', { param =&gt; 'field' });
</ins><span class="cx"> 
</span><ins>+    my $field = Bugzilla::Bug::FIELD_MAP-&gt;{$params-&gt;{field}} 
+                || $params-&gt;{field};
+
+    my @global_selects =
+        @{ Bugzilla-&gt;fields({ is_select =&gt; 1, is_abnormal =&gt; 0 }) };
+
</ins><span class="cx">     my $values;
</span><del>-    if (grep($_ eq $field, GLOBAL_SELECT_FIELDS, @custom_select)) {
</del><ins>+    if (grep($_-&gt;name eq $field, @global_selects)) {
+        # The field is a valid one.
+        trick_taint($field);
</ins><span class="cx">         $values = get_legal_field_values($field);
</span><span class="cx">     }
</span><span class="cx">     elsif (grep($_ eq $field, PRODUCT_SPECIFIC_FIELDS)) {
</span><span class="lines">@@ -151,7 +593,7 @@
</span><span class="cx">         defined $id || ThrowCodeError('param_required',
</span><span class="cx">             { function =&gt; 'Bug.legal_values', param =&gt; 'product_id' });
</span><span class="cx">         grep($_-&gt;id eq $id, @{Bugzilla-&gt;user-&gt;get_accessible_products})
</span><del>-            || ThrowUserError('product_access_denied', { product =&gt; $id });
</del><ins>+            || ThrowUserError('product_access_denied', { id =&gt; $id });
</ins><span class="cx"> 
</span><span class="cx">         my $product = new Bugzilla::Product($id);
</span><span class="cx">         my @objects;
</span><span class="lines">@@ -173,12 +615,61 @@
</span><span class="cx"> 
</span><span class="cx">     my @result;
</span><span class="cx">     foreach my $val (@$values) {
</span><del>-        push(@result, type('string')-&gt;value($val));
</del><ins>+        push(@result, $self-&gt;type('string', $val));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     return { values =&gt; \@result };
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub add_attachment {
+    my ($self, $params) = validate(@_, 'ids');
+    my $dbh = Bugzilla-&gt;dbh;
+
+    Bugzilla-&gt;login(LOGIN_REQUIRED);
+    defined $params-&gt;{ids}
+        || ThrowCodeError('param_required', { param =&gt; 'ids' });
+    defined $params-&gt;{data}
+        || ThrowCodeError('param_required', { param =&gt; 'data' });
+
+    my @bugs = map { Bugzilla::Bug-&gt;check($_) } @{ $params-&gt;{ids} };
+    foreach my $bug (@bugs) {
+        Bugzilla-&gt;user-&gt;can_edit_product($bug-&gt;product_id)
+          || ThrowUserError(&quot;product_edit_denied&quot;, {product =&gt; $bug-&gt;product});
+    }
+
+    my @created;
+    $dbh-&gt;bz_start_transaction();
+    my $timestamp = $dbh-&gt;selectrow_array('SELECT LOCALTIMESTAMP(0)');
+
+    foreach my $bug (@bugs) {
+        my $attachment = Bugzilla::Attachment-&gt;create({
+            bug         =&gt; $bug,
+            creation_ts =&gt; $timestamp,
+            data        =&gt; $params-&gt;{data},
+            description =&gt; $params-&gt;{summary},
+            filename    =&gt; $params-&gt;{file_name},
+            mimetype    =&gt; $params-&gt;{content_type},
+            ispatch     =&gt; $params-&gt;{is_patch},
+            isprivate   =&gt; $params-&gt;{is_private},
+        });
+        my $comment = $params-&gt;{comment} || '';
+        $attachment-&gt;bug-&gt;add_comment($comment, 
+            { isprivate  =&gt; $attachment-&gt;isprivate,
+              type       =&gt; CMT_ATTACHMENT_CREATED,
+              extra_data =&gt; $attachment-&gt;id });
+        push(@created, $attachment);
+    }
+    $_-&gt;bug-&gt;update($timestamp) foreach @created;
+    $dbh-&gt;bz_commit_transaction();
+
+    $_-&gt;send_changes() foreach @bugs;
+
+    my %attachments = map { $_-&gt;id =&gt; $self-&gt;_attachment_to_hash($_, $params) }
+                          @created;
+
+    return { attachments =&gt; \%attachments };
+}
+
</ins><span class="cx"> sub add_comment {
</span><span class="cx">     my ($self, $params) = @_;
</span><span class="cx">     
</span><span class="lines">@@ -187,28 +678,292 @@
</span><span class="cx">     
</span><span class="cx">     # Check parameters
</span><span class="cx">     defined $params-&gt;{id} 
</span><del>-        || ThrowCodeError('param_required', { param =&gt; 'id' });
-    ValidateBugID($params-&gt;{id});
-    
</del><ins>+        || ThrowCodeError('param_required', { param =&gt; 'id' }); 
</ins><span class="cx">     my $comment = $params-&gt;{comment}; 
</span><span class="cx">     (defined $comment &amp;&amp; trim($comment) ne '')
</span><span class="cx">         || ThrowCodeError('param_required', { param =&gt; 'comment' });
</span><span class="cx">     
</span><del>-    my $bug = new Bugzilla::Bug($params-&gt;{id});
</del><ins>+    my $bug = Bugzilla::Bug-&gt;check($params-&gt;{id});
</ins><span class="cx">     
</span><span class="cx">     Bugzilla-&gt;user-&gt;can_edit_product($bug-&gt;product_id)
</span><span class="cx">         || ThrowUserError(&quot;product_edit_denied&quot;, {product =&gt; $bug-&gt;product});
</span><del>-        
</del><ins>+    
+    # Backwards-compatibility for versions before 3.6    
+    if (defined $params-&gt;{private}) {
+        $params-&gt;{is_private} = delete $params-&gt;{private};
+    }
</ins><span class="cx">     # Append comment
</span><del>-    $bug-&gt;add_comment($comment, { isprivate =&gt; $params-&gt;{private},
</del><ins>+    $bug-&gt;add_comment($comment, { isprivate =&gt; $params-&gt;{is_private},
</ins><span class="cx">                                   work_time =&gt; $params-&gt;{work_time} });
</span><ins>+    
+    # Capture the call to bug-&gt;update (which creates the new comment) in 
+    # a transaction so we're sure to get the correct comment_id.
+    
+    my $dbh = Bugzilla-&gt;dbh;
+    $dbh-&gt;bz_start_transaction();
+    
</ins><span class="cx">     $bug-&gt;update();
</span><span class="cx">     
</span><ins>+    my $new_comment_id = $dbh-&gt;bz_last_key('longdescs', 'comment_id');
+    
+    $dbh-&gt;bz_commit_transaction();
+    
</ins><span class="cx">     # Send mail.
</span><del>-    Bugzilla::BugMail::Send($bug-&gt;bug_id, { changer =&gt; Bugzilla-&gt;user-&gt;login });
-    return undef;
</del><ins>+    Bugzilla::BugMail::Send($bug-&gt;bug_id, { changer =&gt; Bugzilla-&gt;user });
+    
+    return { id =&gt; $self-&gt;type('int', $new_comment_id) };
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub update_see_also {
+    my ($self, $params) = @_;
+
+    my $user = Bugzilla-&gt;login(LOGIN_REQUIRED);
+
+    # Check parameters
+    $params-&gt;{ids}
+        || ThrowCodeError('param_required', { param =&gt; 'id' });
+    my ($add, $remove) = @$params{qw(add remove)};
+    ($add || $remove)
+        or ThrowCodeError('params_required', { params =&gt; ['add', 'remove'] });
+
+    my @bugs;
+    foreach my $id (@{ $params-&gt;{ids} }) {
+        my $bug = Bugzilla::Bug-&gt;check($id);
+        $user-&gt;can_edit_product($bug-&gt;product_id)
+            || ThrowUserError(&quot;product_edit_denied&quot;, 
+                              { product =&gt; $bug-&gt;product });
+        push(@bugs, $bug);
+        if ($remove) {
+            $bug-&gt;remove_see_also($_) foreach @$remove;
+        }
+        if ($add) {
+            $bug-&gt;add_see_also($_) foreach @$add;
+        }
+    }
+    
+    my %changes;
+    foreach my $bug (@bugs) {
+        my $change = $bug-&gt;update();
+        if (my $see_also = $change-&gt;{see_also}) {
+            $changes{$bug-&gt;id}-&gt;{see_also} = {
+                removed =&gt; [split(', ', $see_also-&gt;[0])],
+                added   =&gt; [split(', ', $see_also-&gt;[1])],
+            };
+        }
+        else {
+            # We still want a changes entry, for API consistency.
+            $changes{$bug-&gt;id}-&gt;{see_also} = { added =&gt; [], removed =&gt; [] };
+        }
+
+        Bugzilla::BugMail::Send($bug-&gt;id, { changer =&gt; $user });
+    }
+
+    return { changes =&gt; \%changes };
+}
+
+sub attachments {
+    my ($self, $params) = validate(@_, 'ids', 'attachment_ids');
+
+    if (!(defined $params-&gt;{ids}
+          or defined $params-&gt;{attachment_ids}))
+    {
+        ThrowCodeError('param_required',
+                       { function =&gt; 'Bug.attachments', 
+                         params   =&gt; ['ids', 'attachment_ids'] });
+    }
+
+    my $ids = $params-&gt;{ids} || [];
+    my $attach_ids = $params-&gt;{attachment_ids} || [];
+
+    my %bugs;
+    foreach my $bug_id (@$ids) {
+        my $bug = Bugzilla::Bug-&gt;check($bug_id);
+        $bugs{$bug-&gt;id} = [];
+        foreach my $attach (@{$bug-&gt;attachments}) {
+            push @{$bugs{$bug-&gt;id}},
+                $self-&gt;_attachment_to_hash($attach, $params);
+        }
+    }
+
+    my %attachments;
+    foreach my $attach (@{Bugzilla::Attachment-&gt;new_from_list($attach_ids)}) {
+        Bugzilla::Bug-&gt;check($attach-&gt;bug_id);
+        if ($attach-&gt;isprivate &amp;&amp; !Bugzilla-&gt;user-&gt;is_insider) {
+            ThrowUserError('auth_failure', {action    =&gt; 'access',
+                                            object    =&gt; 'attachment',
+                                            attach_id =&gt; $attach-&gt;id});
+        }
+        $attachments{$attach-&gt;id} =
+            $self-&gt;_attachment_to_hash($attach, $params);
+    }
+
+    return { bugs =&gt; \%bugs, attachments =&gt; \%attachments };
+}
+
+##############################
+# Private Helper Subroutines #
+##############################
+
+# A helper for get() and search(). This is done in this fashion in order
+# to produce a stable API and to explicitly type return values.
+# The internals of Bugzilla::Bug are not stable enough to just
+# return them directly.
+
+sub _bug_to_hash {
+    my ($self, $bug, $params) = @_;
+
+    # All the basic bug attributes are here, in alphabetical order.
+    # A bug attribute is &quot;basic&quot; if it doesn't require an additional
+    # database call to get the info.
+    my %item = (
+        alias            =&gt; $self-&gt;type('string', $bug-&gt;alias),
+        classification   =&gt; $self-&gt;type('string', $bug-&gt;classification),
+        component        =&gt; $self-&gt;type('string', $bug-&gt;component),
+        creation_time    =&gt; $self-&gt;type('dateTime', $bug-&gt;creation_ts),
+        id               =&gt; $self-&gt;type('int', $bug-&gt;bug_id),
+        is_confirmed     =&gt; $self-&gt;type('boolean', $bug-&gt;everconfirmed),
+        last_change_time =&gt; $self-&gt;type('dateTime', $bug-&gt;delta_ts),
+        op_sys           =&gt; $self-&gt;type('string', $bug-&gt;op_sys),
+        platform         =&gt; $self-&gt;type('string', $bug-&gt;rep_platform),
+        priority         =&gt; $self-&gt;type('string', $bug-&gt;priority),
+        product          =&gt; $self-&gt;type('string', $bug-&gt;product),
+        resolution       =&gt; $self-&gt;type('string', $bug-&gt;resolution),
+        severity         =&gt; $self-&gt;type('string', $bug-&gt;bug_severity),
+        status           =&gt; $self-&gt;type('string', $bug-&gt;bug_status),
+        summary          =&gt; $self-&gt;type('string', $bug-&gt;short_desc),
+        target_milestone =&gt; $self-&gt;type('string', $bug-&gt;target_milestone),
+        url              =&gt; $self-&gt;type('string', $bug-&gt;bug_file_loc),
+        version          =&gt; $self-&gt;type('string', $bug-&gt;version),
+        whiteboard       =&gt; $self-&gt;type('string', $bug-&gt;status_whiteboard),
+    );
+
+
+    # First we handle any fields that require extra SQL calls.
+    # We don't do the SQL calls at all if the filter would just
+    # eliminate them anyway.
+    if (filter_wants $params, 'assigned_to') {
+        $item{'assigned_to'} = $self-&gt;type('string', $bug-&gt;assigned_to-&gt;login);
+    }
+    if (filter_wants $params, 'blocks') {
+        my @blocks = map { $self-&gt;type('int', $_) } @{ $bug-&gt;blocked };
+        $item{'blocks'} = \@blocks;
+    }
+    if (filter_wants $params, 'cc') {
+        my @cc = map { $self-&gt;type('string', $_) } @{ $bug-&gt;cc || [] };
+        $item{'cc'} = \@cc;
+    }
+    if (filter_wants $params, 'creator') {
+        $item{'creator'} = $self-&gt;type('string', $bug-&gt;reporter-&gt;login);
+    }
+    if (filter_wants $params, 'depends_on') {
+        my @depends_on = map { $self-&gt;type('int', $_) } @{ $bug-&gt;dependson };
+        $item{'depends_on'} = \@depends_on;
+    }
+    if (filter_wants $params, 'dupe_of') {
+        $item{'dupe_of'} = $self-&gt;type('int', $bug-&gt;dup_id);
+    }
+    if (filter_wants $params, 'groups') {
+        my @groups = map { $self-&gt;type('string', $_-&gt;name) }
+                     @{ $bug-&gt;groups_in };
+        $item{'groups'} = \@groups;
+    }
+    if (filter_wants $params, 'is_open') {
+        $item{'is_open'} = $self-&gt;type('boolean', $bug-&gt;status-&gt;is_open);
+    }
+    if (filter_wants $params, 'keywords') {
+        my @keywords = map { $self-&gt;type('string', $_-&gt;name) }
+                       @{ $bug-&gt;keyword_objects };
+        $item{'keywords'} = \@keywords;
+    }
+    if (filter_wants $params, 'qa_contact') {
+        my $qa_login = $bug-&gt;qa_contact ? $bug-&gt;qa_contact-&gt;login : '';
+        $item{'qa_contact'} = $self-&gt;type('string', $qa_login);
+    }
+    if (filter_wants $params, 'see_also') {
+        my @see_also = map { $self-&gt;type('string', $_-&gt;name) }
+                       @{ $bug-&gt;see_also };
+        $item{'see_also'} = \@see_also;
+    }
+
+    # And now custom fields
+    my @custom_fields = Bugzilla-&gt;active_custom_fields;
+    foreach my $field (@custom_fields) {
+        my $name = $field-&gt;name;
+        next if !filter_wants $params, $name;
+        if ($field-&gt;type == FIELD_TYPE_BUG_ID) {
+            $item{$name} = $self-&gt;type('int', $bug-&gt;$name);
+        }
+        elsif ($field-&gt;type == FIELD_TYPE_DATETIME) {
+            $item{$name} = $self-&gt;type('dateTime', $bug-&gt;$name);
+        }
+        elsif ($field-&gt;type == FIELD_TYPE_MULTI_SELECT) {
+            my @values = map { $self-&gt;type('string', $_) } @{ $bug-&gt;$name };
+            $item{$name} = \@values;
+        }
+        else {
+            $item{$name} = $self-&gt;type('string', $bug-&gt;$name);
+        }
+    }
+
+    # Timetracking fields are only sent if the user can see them.
+    if (Bugzilla-&gt;user-&gt;is_timetracker) {
+        $item{'estimated_time'} = $self-&gt;type('double', $bug-&gt;estimated_time);
+        $item{'remaining_time'} = $self-&gt;type('double', $bug-&gt;remaining_time);
+        # No need to format $bug-&gt;deadline specially, because Bugzilla::Bug
+        # already does it for us.
+        $item{'deadline'} = $self-&gt;type('string', $bug-&gt;deadline);
+    }
+
+    if (Bugzilla-&gt;user-&gt;id) {
+        my $token = issue_hash_token([$bug-&gt;id, $bug-&gt;delta_ts]);
+        $item{'update_token'} = $self-&gt;type('string', $token);
+    }
+
+    # The &quot;accessible&quot; bits go here because they have long names and it
+    # makes the code look nicer to separate them out.
+    $item{'is_cc_accessible'} = $self-&gt;type('boolean', 
+                                            $bug-&gt;cclist_accessible);
+    $item{'is_creator_accessible'} = $self-&gt;type('boolean',
+                                                 $bug-&gt;reporter_accessible);
+
+    return filter $params, \%item;
+}
+
+sub _attachment_to_hash {
+    my ($self, $attach, $filters) = @_;
+
+    # Skipping attachment flags for now.
+    delete $attach-&gt;{flags};
+
+    my $item = filter $filters, {
+        creation_time    =&gt; $self-&gt;type('dateTime', $attach-&gt;attached),
+        last_change_time =&gt; $self-&gt;type('dateTime', $attach-&gt;modification_time),
+        id               =&gt; $self-&gt;type('int', $attach-&gt;id),
+        bug_id           =&gt; $self-&gt;type('int', $attach-&gt;bug_id),
+        file_name        =&gt; $self-&gt;type('string', $attach-&gt;filename),
+        summary          =&gt; $self-&gt;type('string', $attach-&gt;description),
+        description      =&gt; $self-&gt;type('string', $attach-&gt;description),
+        content_type     =&gt; $self-&gt;type('string', $attach-&gt;contenttype),
+        is_private       =&gt; $self-&gt;type('int', $attach-&gt;isprivate),
+        is_obsolete      =&gt; $self-&gt;type('int', $attach-&gt;isobsolete),
+        is_patch         =&gt; $self-&gt;type('int', $attach-&gt;ispatch),
+    };
+
+    # creator/attacher require an extra lookup, so we only send them if
+    # the filter wants them.
+    foreach my $field (qw(creator attacher)) {
+        if (filter_wants $filters, $field) {
+            $item-&gt;{$field} = $self-&gt;type('string', $attach-&gt;attacher-&gt;login);
+        }
+    }
+
+    if (filter_wants $filters, 'data') {
+        $item-&gt;{'data'} = $self-&gt;type('base64', $attach-&gt;data);
+    }
+
+    return $item;
+}
+
</ins><span class="cx"> 1;
</span><span class="cx"> 
</span><span class="cx"> __END__
</span><span class="lines">@@ -228,16 +983,217 @@
</span><span class="cx"> See L&lt;Bugzilla::WebService&gt; for a description of how parameters are passed,
</span><span class="cx"> and what B&lt;STABLE&gt;, B&lt;UNSTABLE&gt;, and B&lt;EXPERIMENTAL&gt; mean.
</span><span class="cx"> 
</span><del>-=head2 Utility Functions
</del><ins>+=head1 Utility Functions
</ins><span class="cx"> 
</span><ins>+=head2 fields
+
+B&lt;UNSTABLE&gt;
+
</ins><span class="cx"> =over
</span><span class="cx"> 
</span><del>-=item C&lt;legal_values&gt; 
</del><ins>+=item B&lt;Description&gt;
</ins><span class="cx"> 
</span><del>-B&lt;EXPERIMENTAL&gt;
</del><ins>+Get information about valid bug fields, including the lists of legal values
+for each field.
</ins><span class="cx"> 
</span><ins>+=item B&lt;Params&gt;
+
+You can pass either field ids or field names.
+
+B&lt;Note&gt;: If neither C&lt;ids&gt; nor C&lt;names&gt; is specified, then all 
+non-obsolete fields will be returned.
+
+In addition to the parameters below, this method also accepts the
+standard L&lt;include_fields|Bugzilla::WebService/include_fields&gt; and
+L&lt;exclude_fields|Bugzilla::WebService/exclude_fields&gt; arguments.
+
</ins><span class="cx"> =over
</span><span class="cx"> 
</span><ins>+=item C&lt;ids&gt;   (array) - An array of integer field ids.
+
+=item C&lt;names&gt; (array) - An array of strings representing field names.
+
+=back
+
+=item B&lt;Returns&gt;
+
+A hash containing a single element, C&lt;fields&gt;. This is an array of hashes,
+containing the following keys:
+
+=over
+
+=item C&lt;id&gt;
+
+C&lt;int&gt; An integer id uniquely identifying this field in this installation only.
+
+=item C&lt;type&gt;
+
+C&lt;int&gt; The number of the fieldtype. The following values are defined:
+
+=over
+
+=item C&lt;0&gt; Unknown
+
+=item C&lt;1&gt; Free Text
+
+=item C&lt;2&gt; Drop Down
+
+=item C&lt;3&gt; Multiple-Selection Box
+
+=item C&lt;4&gt; Large Text Box
+
+=item C&lt;5&gt; Date/Time
+
+=item C&lt;6&gt; Bug Id
+
+=item C&lt;7&gt; Bug URLs (&quot;See Also&quot;)
+
+=back
+
+=item C&lt;is_custom&gt;
+
+C&lt;boolean&gt; True when this is a custom field, false otherwise.
+
+=item C&lt;name&gt;
+
+C&lt;string&gt; The internal name of this field. This is a unique identifier for
+this field. If this is not a custom field, then this name will be the same
+across all Bugzilla installations.
+
+=item C&lt;display_name&gt;
+
+C&lt;string&gt; The name of the field, as it is shown in the user interface.
+
+=item C&lt;is_mandatory&gt;
+
+C&lt;boolean&gt; True if the field must have a value when filing new bugs.
+Also, mandatory fields cannot have their value cleared when updating
+bugs.
+
+=item C&lt;is_on_bug_entry&gt;
+
+C&lt;boolean&gt; For custom fields, this is true if the field is shown when you
+enter a new bug. For standard fields, this is currently always false,
+even if the field shows up when entering a bug. (To know whether or not
+a standard field is valid on bug entry, see L&lt;/create&gt;.)
+
+=item C&lt;visibility_field&gt;
+
+C&lt;string&gt;  The name of a field that controls the visibility of this field
+in the user interface. This field only appears in the user interface when
+the named field is equal to one of the values in C&lt;visibility_values&gt;.
+Can be null.
+
+=item C&lt;visibility_values&gt;
+
+C&lt;array&gt; of C&lt;string&gt;s This field is only shown when C&lt;visibility_field&gt;
+matches one of these values. When C&lt;visibility_field&gt; is null,
+then this is an empty array.
+
+=item C&lt;value_field&gt;
+
+C&lt;string&gt;  The name of the field that controls whether or not particular
+values of the field are shown in the user interface. Can be null.
+
+=item C&lt;values&gt;
+
+This is an array of hashes, representing the legal values for
+select-type (drop-down and multiple-selection) fields. This is also
+populated for the C&lt;component&gt;, C&lt;version&gt;, and C&lt;target_milestone&gt;
+fields, but not for the C&lt;product&gt; field (you must use
+L&lt;Product.get_accessible_products|Bugzilla::WebService::Product/get_accessible_products&gt;
+for that.
+
+For fields that aren't select-type fields, this will simply be an empty
+array.
+
+Each hash has the following keys:
+
+=over 
+
+=item C&lt;name&gt;
+
+C&lt;string&gt; The actual value--this is what you would specify for this
+field in L&lt;/create&gt;, etc.
+
+=item C&lt;sort_key&gt;
+
+C&lt;int&gt; Values, when displayed in a list, are sorted first by this integer
+and then secondly by their name.
+
+=item C&lt;sortkey&gt;
+
+B&lt;DEPRECATED&gt; - Use C&lt;sort_key&gt; instead.
+
+=item C&lt;visibility_values&gt;
+
+If C&lt;value_field&gt; is defined for this field, then this value is only shown
+if the C&lt;value_field&gt; is set to one of the values listed in this array.
+Note that for per-product fields, C&lt;value_field&gt; is set to C&lt;'product'&gt;
+and C&lt;visibility_values&gt; will reflect which product(s) this value appears in.
+
+=item C&lt;is_open&gt;
+
+C&lt;boolean&gt; For C&lt;bug_status&gt; values, determines whether this status
+specifies that the bug is &quot;open&quot; (true) or &quot;closed&quot; (false). This item
+is only included for the C&lt;bug_status&gt; field.
+
+=item C&lt;can_change_to&gt;
+
+For C&lt;bug_status&gt; values, this is an array of hashes that determines which
+statuses you can transition to from this status. (This item is only included
+for the C&lt;bug_status&gt; field.)
+
+Each hash contains the following items:
+
+=over
+
+=item C&lt;name&gt;
+
+the name of the new status
+
+=item C&lt;comment_required&gt;
+
+this C&lt;boolean&gt; True if a comment is required when you change a bug into
+this status using this transition.
+
+=back
+
+=back
+
+=back
+
+=item B&lt;Errors&gt;
+
+=over
+
+=item 51 (Invalid Field Name or Id)
+
+You specified an invalid field name or id.
+
+=back
+
+=item B&lt;History&gt;
+
+=over
+
+=item Added in Bugzilla B&lt;3.6&gt;.
+
+=item The C&lt;is_mandatory&gt; return value was added in Bugzilla B&lt;4.0&gt;.
+
+=item C&lt;sortkey&gt; was renamed to C&lt;sort_key&gt; in Bugzilla B&lt;4.2&gt;.
+
+=back
+
+=back
+
+
+=head2 legal_values
+
+B&lt;DEPRECATED&gt; - Use L&lt;/fields&gt; instead.
+
+=over
+
</ins><span class="cx"> =item B&lt;Description&gt;
</span><span class="cx"> 
</span><span class="cx"> Tells you what values are allowed for a particular field.
</span><span class="lines">@@ -276,27 +1232,337 @@
</span><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><ins>+=head1 Bug Information
</ins><span class="cx"> 
</span><ins>+=head2 attachments
+
+B&lt;EXPERIMENTAL&gt;
+
+=over
+
+=item B&lt;Description&gt;
+
+It allows you to get data about attachments, given a list of bugs
+and/or attachment ids.
+
+B&lt;Note&gt;: Private attachments will only be returned if you are in the 
+insidergroup or if you are the submitter of the attachment.
+
+=item B&lt;Params&gt;
+
+B&lt;Note&gt;: At least one of C&lt;ids&gt; or C&lt;attachment_ids&gt; is required.
+
+=over
+
+=item C&lt;ids&gt;
+
+See the description of the C&lt;ids&gt; parameter in the L&lt;/get&gt; method.
+
+=item C&lt;attachment_ids&gt;
+
+C&lt;array&gt; An array of integer attachment ids.
+
</ins><span class="cx"> =back
</span><span class="cx"> 
</span><del>-=head2 Bug Information
</del><ins>+Also accepts the L&lt;include_fields|Bugzilla::WebService/include_fields&gt;,
+and L&lt;exclude_fields|Bugzilla::WebService/exclude_fields&gt; arguments.
</ins><span class="cx"> 
</span><ins>+=item B&lt;Returns&gt;
+
+A hash containing two elements: C&lt;bugs&gt; and C&lt;attachments&gt;. The return
+value looks like this:
+
+ {
+     bugs =&gt; {
+         1345 =&gt; [
+             { (attachment) },
+             { (attachment) }
+         ],
+         9874 =&gt; [
+             { (attachment) },
+             { (attachment) }
+         ],
+     },
+
+     attachments =&gt; {
+         234 =&gt; { (attachment) },
+         123 =&gt; { (attachment) },
+     }
+ }
+
+The attachments of any bugs that you specified in the C&lt;ids&gt; argument in
+input are returned in C&lt;bugs&gt; on output. C&lt;bugs&gt; is a hash that has integer
+bug IDs for keys and the values are arrayrefs that contain hashes as attachments.
+(Fields for attachments are described below.)
+
+For any attachments that you specified directly in C&lt;attachment_ids&gt;, they
+are returned in C&lt;attachments&gt; on output. This is a hash where the attachment
+ids point directly to hashes describing the individual attachment.
+
+The fields for each attachment (where it says C&lt;(attachment)&gt; in the
+diagram above) are:
+
</ins><span class="cx"> =over
</span><span class="cx"> 
</span><del>-=item C&lt;get&gt; 
</del><ins>+=item C&lt;data&gt;
</ins><span class="cx"> 
</span><del>-B&lt;EXPERIMENTAL&gt;
</del><ins>+C&lt;base64&gt; The raw data of the attachment, encoded as Base64.
</ins><span class="cx"> 
</span><ins>+=item C&lt;creation_time&gt;
+
+C&lt;dateTime&gt; The time the attachment was created.
+
+=item C&lt;last_change_time&gt;
+
+C&lt;dateTime&gt; The last time the attachment was modified.
+
+=item C&lt;id&gt;
+
+C&lt;int&gt; The numeric id of the attachment.
+
+=item C&lt;bug_id&gt;
+
+C&lt;int&gt; The numeric id of the bug that the attachment is attached to.
+
+=item C&lt;file_name&gt;
+
+C&lt;string&gt; The file name of the attachment.
+
+=item C&lt;summary&gt;
+
+C&lt;string&gt; A short string describing the attachment.
+
+Also returned as C&lt;description&gt;, for backwards-compatibility with older
+Bugzillas. (However, this backwards-compatibility will go away in Bugzilla
+5.0.)
+
+=item C&lt;content_type&gt;
+
+C&lt;string&gt; The MIME type of the attachment.
+
+=item C&lt;is_private&gt;
+
+C&lt;boolean&gt; True if the attachment is private (only visible to a certain
+group called the &quot;insidergroup&quot;), False otherwise.
+
+=item C&lt;is_obsolete&gt;
+
+C&lt;boolean&gt; True if the attachment is obsolete, False otherwise.
+
+=item C&lt;is_patch&gt;
+
+C&lt;boolean&gt; True if the attachment is a patch, False otherwise.
+
+=item C&lt;creator&gt;
+
+C&lt;string&gt; The login name of the user that created the attachment.
+
+Also returned as C&lt;attacher&gt;, for backwards-compatibility with older
+Bugzillas. (However, this backwards-compatibility will go away in Bugzilla
+5.0.)
+
+=back
+
+=item B&lt;Errors&gt;
+
+This method can throw all the same errors as L&lt;/get&gt;. In addition,
+it can also throw the following error:
+
</ins><span class="cx"> =over
</span><span class="cx"> 
</span><ins>+=item 304 (Auth Failure, Attachment is Private)
+
+You specified the id of a private attachment in the C&lt;attachment_ids&gt;
+argument, and you are not in the &quot;insider group&quot; that can see
+private attachments.
+
+=back
+
+=item B&lt;History&gt;
+
+=over
+
+=item Added in Bugzilla B&lt;3.6&gt;.
+
+=item In Bugzilla B&lt;4.0&gt;, the C&lt;attacher&gt; return value was renamed to
+C&lt;creator&gt;.
+
+=item In Bugzilla B&lt;4.0&gt;, the C&lt;description&gt; return value was renamed to
+C&lt;summary&gt;.
+
+=item The C&lt;data&gt; return value was added in Bugzilla B&lt;4.0&gt;.
+
+=item In Bugzilla B&lt;4.2&gt;, the C&lt;is_url&gt; return value was removed
+(this attribute no longer exists for attachments).
+
+=back
+
+=back
+
+
+=head2 comments
+
+B&lt;STABLE&gt;
+
+=over
+
</ins><span class="cx"> =item B&lt;Description&gt;
</span><span class="cx"> 
</span><ins>+This allows you to get data about comments, given a list of bugs 
+and/or comment ids.
+
+=item B&lt;Params&gt;
+
+B&lt;Note&gt;: At least one of C&lt;ids&gt; or C&lt;comment_ids&gt; is required.
+
+In addition to the parameters below, this method also accepts the
+standard L&lt;include_fields|Bugzilla::WebService/include_fields&gt; and
+L&lt;exclude_fields|Bugzilla::WebService/exclude_fields&gt; arguments.
+
+=over
+
+=item C&lt;ids&gt;
+
+C&lt;array&gt; An array that can contain both bug IDs and bug aliases.
+All of the comments (that are visible to you) will be returned for the
+specified bugs.
+
+=item C&lt;comment_ids&gt; 
+
+C&lt;array&gt; An array of integer comment_ids. These comments will be
+returned individually, separate from any other comments in their
+respective bugs.
+
+=item C&lt;new_since&gt;
+
+C&lt;dateTime&gt; If specified, the method will only return comments I&lt;newer&gt;
+than this time. This only affects comments returned from the C&lt;ids&gt;
+argument. You will always be returned all comments you request in the
+C&lt;comment_ids&gt; argument, even if they are older than this date.
+
+=back
+
+=item B&lt;Returns&gt;
+
+Two items are returned:
+
+=over
+
+=item C&lt;bugs&gt;
+
+This is used for bugs specified in C&lt;ids&gt;. This is a hash,
+where the keys are the numeric ids of the bugs, and the value is
+a hash with a single key, C&lt;comments&gt;, which is an array of comments.
+(The format of comments is described below.)
+
+Note that any individual bug will only be returned once, so if you
+specify an id multiple times in C&lt;ids&gt;, it will still only be
+returned once.
+
+=item C&lt;comments&gt;
+
+Each individual comment requested in C&lt;comment_ids&gt; is returned here,
+in a hash where the numeric comment id is the key, and the value
+is the comment. (The format of comments is described below.) 
+
+=back
+
+A &quot;comment&quot; as described above is a hash that contains the following
+keys:
+
+=over
+
+=item id
+
+C&lt;int&gt; The globally unique ID for the comment.
+
+=item bug_id
+
+C&lt;int&gt; The ID of the bug that this comment is on.
+
+=item attachment_id
+
+C&lt;int&gt; If the comment was made on an attachment, this will be the
+ID of that attachment. Otherwise it will be null.
+
+=item text
+
+C&lt;string&gt; The actual text of the comment.
+
+=item creator
+
+C&lt;string&gt; The login name of the comment's author.
+
+Also returned as C&lt;author&gt;, for backwards-compatibility with older
+Bugzillas. (However, this backwards-compatibility will go away in Bugzilla
+5.0.)
+
+=item time
+
+C&lt;dateTime&gt; The time (in Bugzilla's timezone) that the comment was added.
+
+=item is_private
+
+C&lt;boolean&gt; True if this comment is private (only visible to a certain
+group called the &quot;insidergroup&quot;), False otherwise.
+
+=back
+
+=item B&lt;Errors&gt;
+
+This method can throw all the same errors as L&lt;/get&gt;. In addition,
+it can also throw the following errors:
+
+=over
+
+=item 110 (Comment Is Private)
+
+You specified the id of a private comment in the C&lt;comment_ids&gt;
+argument, and you are not in the &quot;insider group&quot; that can see
+private comments.
+
+=item 111 (Invalid Comment ID)
+
+You specified an id in the C&lt;comment_ids&gt; argument that is invalid--either
+you specified something that wasn't a number, or there is no comment with
+that id.
+
+=back
+
+=item B&lt;History&gt;
+
+=over
+
+=item Added in Bugzilla B&lt;3.4&gt;.
+
+=item C&lt;attachment_id&gt; was added to the return value in Bugzilla B&lt;3.6&gt;.
+
+=item In Bugzilla B&lt;4.0&gt;, the C&lt;author&gt; return value was renamed to
+C&lt;creator&gt;.
+
+=back
+
+=back
+
+
+=head2 get
+
+B&lt;STABLE&gt;
+
+=over
+
+=item B&lt;Description&gt;
+
</ins><span class="cx"> Gets information about particular bugs in the database.
</span><span class="cx"> 
</span><span class="cx"> Note: Can also be called as &quot;get_bugs&quot; for compatibilty with Bugzilla 3.0 API.
</span><span class="cx"> 
</span><span class="cx"> =item B&lt;Params&gt;
</span><span class="cx"> 
</span><ins>+In addition to the parameters below, this method also accepts the
+standard L&lt;include_fields|Bugzilla::WebService/include_fields&gt; and
+L&lt;exclude_fields|Bugzilla::WebService/exclude_fields&gt; arguments.
+
</ins><span class="cx"> =over
</span><span class="cx"> 
</span><span class="cx"> =item C&lt;ids&gt;
</span><span class="lines">@@ -312,44 +1578,248 @@
</span><span class="cx"> case you will be told that you have specified an invalid bug_id if you
</span><span class="cx"> try to specify an alias. (It will be error 100.)
</span><span class="cx"> 
</span><ins>+=item C&lt;permissive&gt; B&lt;EXPERIMENTAL&gt;
+
+C&lt;boolean&gt; Normally, if you request any inaccessible or invalid bug ids,
+Bug.get will throw an error. If this parameter is True, instead of throwing an
+error we return an array of hashes with a C&lt;id&gt;, C&lt;faultString&gt; and C&lt;faultCode&gt; 
+for each bug that fails, and return normal information for the other bugs that 
+were accessible.
+
</ins><span class="cx"> =back
</span><span class="cx"> 
</span><span class="cx"> =item B&lt;Returns&gt;
</span><span class="cx"> 
</span><del>-A hash containing a single element, C&lt;bugs&gt;. This is an array of hashes. 
-Each hash contains the following items:
</del><ins>+Two items are returned:
</ins><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><del>-=item id
</del><ins>+=item C&lt;bugs&gt;
</ins><span class="cx"> 
</span><del>-C&lt;int&gt; The numeric bug_id of this bug.
</del><ins>+An array of hashes that contains information about the bugs with 
+the valid ids. Each hash contains the following items:
</ins><span class="cx"> 
</span><del>-=item alias
</del><ins>+=over
</ins><span class="cx"> 
</span><del>-C&lt;string&gt; The alias of this bug. If there is no alias or aliases are 
-disabled in this Bugzilla, this will be an empty string.
</del><ins>+=item C&lt;alias&gt;
</ins><span class="cx"> 
</span><del>-=item summary
</del><ins>+C&lt;string&gt; The unique alias of this bug.
</ins><span class="cx"> 
</span><del>-C&lt;string&gt; The summary of this bug.
</del><ins>+=item C&lt;assigned_to&gt;
</ins><span class="cx"> 
</span><del>-=item creation_time
</del><ins>+C&lt;string&gt; The login name of the user to whom the bug is assigned.
</ins><span class="cx"> 
</span><ins>+=item C&lt;blocks&gt;
+
+C&lt;array&gt; of C&lt;int&gt;s. The ids of bugs that are &quot;blocked&quot; by this bug.
+
+=item C&lt;cc&gt;
+
+C&lt;array&gt; of C&lt;string&gt;s. The login names of users on the CC list of this
+bug.
+
+=item C&lt;classification&gt;
+
+C&lt;string&gt; The name of the current classification the bug is in.
+
+=item C&lt;component&gt;
+
+C&lt;string&gt; The name of the current component of this bug.
+
+=item C&lt;creation_time&gt;
+
</ins><span class="cx"> C&lt;dateTime&gt; When the bug was created.
</span><span class="cx"> 
</span><del>-=item last_change_time
</del><ins>+=item C&lt;creator&gt;
</ins><span class="cx"> 
</span><ins>+C&lt;string&gt; The login name of the person who filed this bug (the reporter).
+
+=item C&lt;deadline&gt;
+
+C&lt;string&gt; The day that this bug is due to be completed, in the format
+C&lt;YYYY-MM-DD&gt;.
+
+If you are not in the time-tracking group, this field will not be included
+in the return value.
+
+=item C&lt;depends_on&gt;
+
+C&lt;array&gt; of C&lt;int&gt;s. The ids of bugs that this bug &quot;depends on&quot;.
+
+=item C&lt;dupe_of&gt;
+
+C&lt;int&gt; The bug ID of the bug that this bug is a duplicate of. If this bug 
+isn't a duplicate of any bug, this will be null.
+
+=item C&lt;estimated_time&gt;
+
+C&lt;double&gt; The number of hours that it was estimated that this bug would
+take.
+
+If you are not in the time-tracking group, this field will not be included
+in the return value.
+
+=item C&lt;groups&gt;
+
+C&lt;array&gt; of C&lt;string&gt;s. The names of all the groups that this bug is in.
+
+=item C&lt;id&gt;
+
+C&lt;int&gt; The unique numeric id of this bug.
+
+=item C&lt;is_cc_accessible&gt;
+
+C&lt;boolean&gt; If true, this bug can be accessed by members of the CC list,
+even if they are not in the groups the bug is restricted to.
+
+=item C&lt;is_confirmed&gt;
+
+C&lt;boolean&gt; True if the bug has been confirmed. Usually this means that
+the bug has at some point been moved out of the C&lt;UNCONFIRMED&gt; status
+and into another open status.
+
+=item C&lt;is_open&gt;
+
+C&lt;boolean&gt; True if this bug is open, false if it is closed.
+
+=item C&lt;is_creator_accessible&gt;
+
+C&lt;boolean&gt; If true, this bug can be accessed by the creator (reporter)
+of the bug, even if he or she is not a member of the groups the bug
+is restricted to.
+
+=item C&lt;keywords&gt;
+
+C&lt;array&gt; of C&lt;string&gt;s. Each keyword that is on this bug.
+
+=item C&lt;last_change_time&gt;
+
</ins><span class="cx"> C&lt;dateTime&gt; When the bug was last changed.
</span><span class="cx"> 
</span><del>-=item internals B&lt;UNSTABLE&gt;
</del><ins>+=item C&lt;op_sys&gt;
</ins><span class="cx"> 
</span><del>-A hash. The internals of a L&lt;Bugzilla::Bug&gt; object. This is extremely
-unstable, and you should only rely on this if you absolutely have to. The
-structure of the hash may even change between point releases of Bugzilla.
</del><ins>+C&lt;string&gt; The name of the operating system that the bug was filed against.
</ins><span class="cx"> 
</span><ins>+=item C&lt;platform&gt;
+
+C&lt;string&gt; The name of the platform (hardware) that the bug was filed against.
+
+=item C&lt;priority&gt;
+
+C&lt;string&gt; The priority of the bug.
+
+=item C&lt;product&gt;
+
+C&lt;string&gt; The name of the product this bug is in.
+
+=item C&lt;qa_contact&gt;
+
+C&lt;string&gt; The login name of the current QA Contact on the bug.
+
+=item C&lt;remaining_time&gt;
+
+C&lt;double&gt; The number of hours of work remaining until work on this bug
+is complete.
+
+If you are not in the time-tracking group, this field will not be included
+in the return value.
+
+=item C&lt;resolution&gt;
+
+C&lt;string&gt; The current resolution of the bug, or an empty string if the bug
+is open.
+
+=item C&lt;see_also&gt;
+
+B&lt;UNSTABLE&gt;
+
+C&lt;array&gt; of C&lt;string&gt;s. The URLs in the See Also field on the bug.
+
+=item C&lt;severity&gt;
+
+C&lt;string&gt; The current severity of the bug.
+
+=item C&lt;status&gt;
+
+C&lt;string&gt; The current status of the bug.
+
+=item C&lt;summary&gt;
+
+C&lt;string&gt; The summary of this bug.
+
+=item C&lt;target_milestone&gt;
+
+C&lt;string&gt; The milestone that this bug is supposed to be fixed by, or for
+closed bugs, the milestone that it was fixed for.
+
+=item C&lt;update_token&gt;
+
+C&lt;string&gt; The token that you would have to pass to the F&lt;process_bug.cgi&gt;
+page in order to update this bug. This changes every time the bug is
+updated.
+
+This field is not returned to logged-out users.
+
+=item C&lt;url&gt;
+
+B&lt;UNSTABLE&gt;
+
+C&lt;string&gt; A URL that demonstrates the problem described in
+the bug, or is somehow related to the bug report.
+
+=item C&lt;version&gt;
+
+C&lt;string&gt; The version the bug was reported against.
+
+=item C&lt;whiteboard&gt;
+
+C&lt;string&gt; The value of the &quot;status whiteboard&quot; field on the bug.
+
+=item I&lt;custom fields&gt;
+
+Every custom field in this installation will also be included in the
+return value. Most fields are returned as C&lt;string&gt;s. However, some
+field types have different return values:
+
+=over
+
+=item Bug ID Fields - C&lt;int&gt;
+
+=item Multiple-Selection Fields - C&lt;array&gt; of C&lt;string&gt;s.
+
+=item Date/Time Fields - C&lt;dateTime&gt;
+
+=back 
+
</ins><span class="cx"> =back
</span><span class="cx"> 
</span><ins>+=item C&lt;faults&gt; B&lt;EXPERIMENTAL&gt;
+
+An array of hashes that contains invalid bug ids with error messages
+returned for them. Each hash contains the following items:
+
+=over
+
+=item id
+
+C&lt;int&gt; The numeric bug_id of this bug.
+
+=item faultString 
+
+c&lt;string&gt; This will only be returned for invalid bugs if the C&lt;permissive&gt;
+argument was set when calling Bug.get, and it is an error indicating that 
+the bug id was invalid.
+
+=item faultCode
+
+c&lt;int&gt; This will only be returned for invalid bugs if the C&lt;permissive&gt;
+argument was set when calling Bug.get, and it is the error code for the 
+invalid bug error.
+
+=back
+
+=back
+
</ins><span class="cx"> =item B&lt;Errors&gt;
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="lines">@@ -369,21 +1839,364 @@
</span><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><ins>+=item B&lt;History&gt;
+
+=over
+
+=item C&lt;permissive&gt; argument added to this method's params in Bugzilla B&lt;3.4&gt;. 
+
+=item The following properties were added to this method's return values
+in Bugzilla B&lt;3.4&gt;:
+
+=over
+
+=item For C&lt;bugs&gt;
+
+=over
+
+=item assigned_to
+
+=item component 
+
+=item dupe_of
+
+=item is_open
+
+=item priority
+
+=item product
+
+=item resolution
+
+=item severity
+
+=item status
+
+=back 
+
+=item C&lt;faults&gt;
+
+=back 
+
+=item In Bugzilla B&lt;4.0&gt;, the following items were added to the C&lt;bugs&gt;
+return value: C&lt;blocks&gt;, C&lt;cc&gt;, C&lt;classification&gt;, C&lt;creator&gt;,
+C&lt;deadline&gt;, C&lt;depends_on&gt;, C&lt;estimated_time&gt;, C&lt;is_cc_accessible&gt;, 
+C&lt;is_confirmed&gt;, C&lt;is_creator_accessible&gt;, C&lt;groups&gt;, C&lt;keywords&gt;,
+C&lt;op_sys&gt;, C&lt;platform&gt;, C&lt;qa_contact&gt;, C&lt;remaining_time&gt;, C&lt;see_also&gt;,
+C&lt;target_milestone&gt;, C&lt;update_token&gt;, C&lt;url&gt;, C&lt;version&gt;, C&lt;whiteboard&gt;,
+and all custom fields.
+
</ins><span class="cx"> =back
</span><span class="cx"> 
</span><ins>+
</ins><span class="cx"> =back
</span><span class="cx"> 
</span><ins>+=head2 history
</ins><span class="cx"> 
</span><del>-=head2 Bug Creation and Modification
</del><ins>+B&lt;EXPERIMENTAL&gt;
</ins><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><del>-=item C&lt;create&gt; B&lt;EXPERIMENTAL&gt;
</del><ins>+=item B&lt;Description&gt;
</ins><span class="cx"> 
</span><ins>+Gets the history of changes for particular bugs in the database.
+
+=item B&lt;Params&gt;
+
</ins><span class="cx"> =over
</span><span class="cx"> 
</span><ins>+=item C&lt;ids&gt;
+
+An array of numbers and strings.
+
+If an element in the array is entirely numeric, it represents a bug_id 
+from the Bugzilla database to fetch. If it contains any non-numeric 
+characters, it is considered to be a bug alias instead, and the data bug 
+with that alias will be loaded. 
+
+Note that it's possible for aliases to be disabled in Bugzilla, in which
+case you will be told that you have specified an invalid bug_id if you
+try to specify an alias. (It will be error 100.)
+
+=back
+
+=item B&lt;Returns&gt;
+
+A hash containing a single element, C&lt;bugs&gt;. This is an array of hashes,
+containing the following keys:
+
+=over
+
+=item id
+
+C&lt;int&gt; The numeric id of the bug.
+
+=item alias
+
+C&lt;string&gt; The alias of this bug. If there is no alias or aliases are 
+disabled in this Bugzilla, this will be undef.
+
+=item history
+
+C&lt;array&gt; An array of hashes, each hash having the following keys:
+
+=over
+
+=item when
+
+C&lt;dateTime&gt; The date the bug activity/change happened.
+
+=item who
+
+C&lt;string&gt; The login name of the user who performed the bug change.
+
+=item changes
+
+C&lt;array&gt; An array of hashes which contain all the changes that happened
+to the bug at this time (as specified by C&lt;when&gt;). Each hash contains 
+the following items:
+
+=over
+
+=item field_name
+
+C&lt;string&gt; The name of the bug field that has changed.
+
+=item removed
+
+C&lt;string&gt; The previous value of the bug field which has been deleted 
+by the change.
+
+=item added
+
+C&lt;string&gt; The new value of the bug field which has been added by the change.
+
+=item attachment_id
+
+C&lt;int&gt; The id of the attachment that was changed. This only appears if 
+the change was to an attachment, otherwise C&lt;attachment_id&gt; will not be
+present in this hash.
+
+=back
+
+=back
+
+=back
+
+=item B&lt;Errors&gt;
+
+The same as L&lt;/get&gt;.
+
+=item B&lt;History&gt;
+
+=over
+
+=item Added in Bugzilla B&lt;3.4&gt;.
+
+=back
+
+=back
+
+
+=head2 search
+
+B&lt;UNSTABLE&gt;
+
+=over
+
</ins><span class="cx"> =item B&lt;Description&gt;
</span><span class="cx"> 
</span><ins>+Allows you to search for bugs based on particular criteria.
+
+=item B&lt;Params&gt;
+
+Unless otherwise specified in the description of a parameter, bugs are
+returned if they match I&lt;exactly&gt; the criteria you specify in these 
+parameters. That is, we don't match against substrings--if a bug is in
+the &quot;Widgets&quot; product and you ask for bugs in the &quot;Widg&quot; product, you
+won't get anything.
+
+Criteria are joined in a logical AND. That is, you will be returned
+bugs that match I&lt;all&gt; of the criteria, not bugs that match I&lt;any&gt; of
+the criteria.
+
+Each parameter can be either the type it says, or an array of the types
+it says. If you pass an array, it means &quot;Give me bugs with I&lt;any&gt; of
+these values.&quot; For example, if you wanted bugs that were in either
+the &quot;Foo&quot; or &quot;Bar&quot; products, you'd pass:
+
+ product =&gt; ['Foo', 'Bar']
+
+Some Bugzillas may treat your arguments case-sensitively, depending
+on what database system they are using. Most commonly, though, Bugzilla is 
+not case-sensitive with the arguments passed (because MySQL is the 
+most-common database to use with Bugzilla, and MySQL is not case sensitive).
+
+=over
+
+=item C&lt;alias&gt;
+
+C&lt;string&gt; The unique alias for this bug. Note that you can search
+by alias even if the alias field is disabled in this Bugzilla, but
+it's likely that there won't be any aliases set on bugs, in that case.
+
+=item C&lt;assigned_to&gt;
+
+C&lt;string&gt; The login name of a user that a bug is assigned to.
+
+=item C&lt;component&gt;
+
+C&lt;string&gt; The name of the Component that the bug is in. Note that
+if there are multiple Components with the same name, and you search
+for that name, bugs in I&lt;all&gt; those Components will be returned. If you
+don't want this, be sure to also specify the C&lt;product&gt; argument.
+
+=item C&lt;creation_time&gt;
+
+C&lt;dateTime&gt; Searches for bugs that were created at this time or later.
+May not be an array.
+
+=item C&lt;creator&gt;
+
+C&lt;string&gt; The login name of the user who created the bug.
+
+You can also pass this argument with the name C&lt;reporter&gt;, for
+backwards compatibility with older Bugzillas.
+
+=item C&lt;id&gt;
+
+C&lt;int&gt; The numeric id of the bug.
+
+=item C&lt;last_change_time&gt;
+
+C&lt;dateTime&gt; Searches for bugs that were modified at this time or later.
+May not be an array.
+
+=item C&lt;limit&gt;
+
+C&lt;int&gt; Limit the number of results returned to C&lt;int&gt; records.
+
+=item C&lt;offset&gt;
+
+C&lt;int&gt; Used in conjunction with the C&lt;limit&gt; argument, C&lt;offset&gt; defines 
+the starting position for the search. For example, given a search that 
+would return 100 bugs, setting C&lt;limit&gt; to 10 and C&lt;offset&gt; to 10 would return 
+bugs 11 through 20 from the set of 100.
+
+=item C&lt;op_sys&gt;
+
+C&lt;string&gt; The &quot;Operating System&quot; field of a bug.
+
+=item C&lt;platform&gt;
+
+C&lt;string&gt; The Platform (sometimes called &quot;Hardware&quot;) field of a bug.
+
+=item C&lt;priority&gt;
+
+C&lt;string&gt; The Priority field on a bug.
+
+=item C&lt;product&gt;
+
+C&lt;string&gt; The name of the Product that the bug is in.
+
+=item C&lt;resolution&gt;
+
+C&lt;string&gt; The current resolution--only set if a bug is closed. You can
+find open bugs by searching for bugs with an empty resolution.
+
+=item C&lt;severity&gt;
+
+C&lt;string&gt; The Severity field on a bug.
+
+=item C&lt;status&gt;
+
+C&lt;string&gt; The current status of a bug (not including its resolution,
+if it has one, which is a separate field above).
+
+=item C&lt;summary&gt;
+
+C&lt;string&gt; Searches for substrings in the single-line Summary field on
+bugs. If you specify an array, then bugs whose summaries match I&lt;any&gt; of the
+passed substrings will be returned.
+
+Note that unlike searching in the Bugzilla UI, substrings are not split
+on spaces. So searching for C&lt;foo bar&gt; will match &quot;This is a foo bar&quot;
+but not &quot;This foo is a bar&quot;. C&lt;['foo', 'bar']&gt;, would, however, match
+the second item.
+
+=item C&lt;target_milestone&gt;
+
+C&lt;string&gt; The Target Milestone field of a bug. Note that even if this
+Bugzilla does not have the Target Milestone field enabled, you can
+still search for bugs by Target Milestone. However, it is likely that
+in that case, most bugs will not have a Target Milestone set (it
+defaults to &quot;---&quot; when the field isn't enabled).
+
+=item C&lt;qa_contact&gt;
+
+C&lt;string&gt; The login name of the bug's QA Contact. Note that even if
+this Bugzilla does not have the QA Contact field enabled, you can
+still search for bugs by QA Contact (though it is likely that no bug
+will have a QA Contact set, if the field is disabled).
+
+=item C&lt;url&gt;
+
+C&lt;string&gt; The &quot;URL&quot; field of a bug.
+
+=item C&lt;version&gt;
+
+C&lt;string&gt; The Version field of a bug.
+
+=item C&lt;whiteboard&gt;
+
+C&lt;string&gt; Search the &quot;Status Whiteboard&quot; field on bugs for a substring.
+Works the same as the C&lt;summary&gt; field described above, but searches the
+Status Whiteboard field.
+
+=back
+
+=item B&lt;Returns&gt;
+
+The same as L&lt;/get&gt;.
+
+Note that you will only be returned information about bugs that you
+can see. Bugs that you can't see will be entirely excluded from the
+results. So, if you want to see private bugs, you will have to first 
+log in and I&lt;then&gt; call this method.
+
+=item B&lt;Errors&gt;
+
+Currently, this function doesn't throw any special errors (other than
+the ones that all webservice functions can throw). If you specify
+an invalid value for a particular field, you just won't get any results
+for that value.
+
+=item B&lt;History&gt;
+
+=over
+
+=item Added in Bugzilla B&lt;3.4&gt;.
+
+=item Searching by C&lt;votes&gt; was removed in Bugzilla B&lt;4.0&gt;.
+
+=item The C&lt;reporter&gt; input parameter was renamed to C&lt;creator&gt;
+in Bugzilla B&lt;4.0&gt;.
+
+=back
+
+=back
+
+
+=head1 Bug Creation and Modification
+
+=head2 create
+
+B&lt;STABLE&gt;
+
+=over
+
+=item B&lt;Description&gt;
+
</ins><span class="cx"> This allows you to create a new bug in Bugzilla. If you specify any
</span><span class="cx"> invalid fields, they will be ignored. If you specify any fields you
</span><span class="cx"> are not allowed to set, they will just be set to their defaults or ignored.
</span><span class="lines">@@ -450,6 +2263,17 @@
</span><span class="cx"> 
</span><span class="cx"> =item C&lt;cc&gt; (array) - An array of usernames to CC on this bug.
</span><span class="cx"> 
</span><ins>+=item C&lt;comment_is_private&gt; (boolean) - If set to true, the description
+is private, otherwise it is assumed to be public.
+
+=item C&lt;groups&gt; (array) - An array of group names to put this
+bug into. You can see valid group names on the Permissions
+tab of the Preferences screen, or, if you are an administrator,
+in the Groups control panel.
+If you don't specify this argument, then the bug will be added into
+all the groups that are set as being &quot;Default&quot; for this product. (If
+you want to avoid that, you should specify C&lt;groups&gt; as an empty array.)
+
</ins><span class="cx"> =item C&lt;qa_contact&gt; (username) - If this installation has QA Contacts
</span><span class="cx"> enabled, you can set the QA Contact here if you don't want to use
</span><span class="cx"> the component's default QA Contact.
</span><span class="lines">@@ -476,7 +2300,8 @@
</span><span class="cx"> 
</span><span class="cx"> =item 51 (Invalid Object)
</span><span class="cx"> 
</span><del>-The component you specified is not valid for this Product.
</del><ins>+You specified a field value that is invalid. The error message will have
+more details.
</ins><span class="cx"> 
</span><span class="cx"> =item 103 (Invalid Alias)
</span><span class="cx"> 
</span><span class="lines">@@ -501,6 +2326,16 @@
</span><span class="cx"> 
</span><span class="cx"> You didn't specify a summary for the bug.
</span><span class="cx"> 
</span><ins>+=item 116 (Dependency Loop)
+
+You specified values in the C&lt;blocks&gt; or C&lt;depends_on&gt; fields
+that would cause a circular dependency between bugs.
+
+=item 120 (Group Restriction Denied)
+
+You tried to restrict the bug to a group which does not exist, or which
+you cannot use with this product.
+
</ins><span class="cx"> =item 504 (Invalid User)
</span><span class="cx"> 
</span><span class="cx"> Either the QA Contact, Assignee, or CC lists have some invalid user
</span><span class="lines">@@ -515,33 +2350,156 @@
</span><span class="cx"> =item Before B&lt;3.0.4&gt;, parameters marked as B&lt;Defaulted&gt; were actually
</span><span class="cx"> B&lt;Required&gt;, due to a bug in Bugzilla.
</span><span class="cx"> 
</span><ins>+=item The C&lt;groups&gt; argument was added in Bugzilla B&lt;4.0&gt;. Before
+Bugzilla 4.0, bugs were only added into Mandatory groups by this
+method. Since Bugzilla B&lt;4.0.2&gt;, passing an illegal group name will
+throw an error. In Bugzilla 4.0 and 4.0.1, illegal group names were
+silently ignored.
+
+=item The C&lt;comment_is_private&gt; argument was added in Bugzilla B&lt;4.0&gt;.
+Before Bugzilla 4.0, you had to use the undocumented C&lt;commentprivacy&gt;
+argument.
+
+=item Error 116 was added in Bugzilla B&lt;4.0&gt;. Before that, dependency
+loop errors had a generic code of C&lt;32000&gt;.
+
</ins><span class="cx"> =back
</span><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><del>-=item C&lt;add_comment&gt; 
</del><span class="cx"> 
</span><del>-B&lt;EXPERIMENTAL&gt;
</del><ins>+=head2 add_attachment
</ins><span class="cx"> 
</span><ins>+B&lt;UNSTABLE&gt;
+
</ins><span class="cx"> =over
</span><span class="cx"> 
</span><span class="cx"> =item B&lt;Description&gt;
</span><span class="cx"> 
</span><ins>+This allows you to add an attachment to a bug in Bugzilla.
+
+=item B&lt;Params&gt;
+
+=over
+
+=item C&lt;ids&gt;
+
+B&lt;Required&gt; C&lt;array&gt; An array of ints and/or strings--the ids
+or aliases of bugs that you want to add this attachment to.
+The same attachment and comment will be added to all
+these bugs.
+
+=item C&lt;data&gt;
+
+B&lt;Required&gt; C&lt;base64&gt; The content of the attachment.
+
+=item C&lt;file_name&gt;
+
+B&lt;Required&gt; C&lt;string&gt; The &quot;file name&quot; that will be displayed
+in the UI for this attachment.
+
+=item C&lt;summary&gt;
+
+B&lt;Required&gt; C&lt;string&gt; A short string describing the
+attachment.
+
+=item C&lt;content_type&gt;
+
+B&lt;Required&gt; C&lt;string&gt; The MIME type of the attachment, like
+C&lt;text/plain&gt; or C&lt;image/png&gt;.
+
+=item C&lt;comment&gt;
+
+C&lt;string&gt; A comment to add along with this attachment.
+
+=item C&lt;is_patch&gt;
+
+C&lt;boolean&gt; True if Bugzilla should treat this attachment as a patch.
+If you specify this, you do not need to specify a C&lt;content_type&gt;.
+The C&lt;content_type&gt; of the attachment will be forced to C&lt;text/plain&gt;.
+
+Defaults to False if not specified.
+
+=item C&lt;is_private&gt;
+
+C&lt;boolean&gt; True if the attachment should be private (restricted
+to the &quot;insidergroup&quot;), False if the attachment should be public.
+
+Defaults to False if not specified.
+
+=back
+
+=item B&lt;Returns&gt;
+
+A single item C&lt;attachments&gt;, which contains the created
+attachments in the same format as the C&lt;attachments&gt; return
+value from L&lt;/attachments&gt;.
+
+=item B&lt;Errors&gt;
+
+This method can throw all the same errors as L&lt;/get&gt;, plus:
+
+=over
+
+=item 600 (Attachment Too Large)
+
+You tried to attach a file that was larger than Bugzilla will accept.
+
+=item 601 (Invalid MIME Type)
+
+You specified a C&lt;content_type&gt; argument that was blank, not a valid
+MIME type, or not a MIME type that Bugzilla accepts for attachments.
+
+=item 603 (File Name Not Specified)
+
+You did not specify a valid for the C&lt;file_name&gt; argument.
+
+=item 604 (Summary Required)
+
+You did not specify a value for the C&lt;summary&gt; argument.
+
+=item 606 (Empty Data)
+
+You set the &quot;data&quot; field to an empty string.
+
+=back
+
+=item B&lt;History&gt;
+
+=over
+
+=item Added in Bugzilla B&lt;4.0&gt;.
+
+=item The C&lt;is_url&gt; parameter was removed in Bugzilla B&lt;4.2&gt;.
+
+=back
+
+=back
+
+
+=head2 add_comment
+
+B&lt;STABLE&gt;
+
+=over
+
+=item B&lt;Description&gt;
+
</ins><span class="cx"> This allows you to add a comment to a bug in Bugzilla.
</span><span class="cx"> 
</span><span class="cx"> =item B&lt;Params&gt;
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><del>-=item C&lt;id&gt; (int) B&lt;Required&gt; - The id or alias of the bug to append a 
</del><ins>+=item C&lt;id&gt; (int or string) B&lt;Required&gt; - The id or alias of the bug to append a 
</ins><span class="cx"> comment to.
</span><span class="cx"> 
</span><span class="cx"> =item C&lt;comment&gt; (string) B&lt;Required&gt; - The comment to append to the bug.
</span><span class="cx"> If this is empty or all whitespace, an error will be thrown saying that
</span><span class="cx"> you did not set the C&lt;comment&gt; parameter.
</span><span class="cx"> 
</span><del>-=item C&lt;private&gt; (boolean) - If set to true, the comment is private, otherwise
-it is assumed to be public.
</del><ins>+=item C&lt;is_private&gt; (boolean) - If set to true, the comment is private, 
+otherwise it is assumed to be public.
</ins><span class="cx"> 
</span><span class="cx"> =item C&lt;work_time&gt; (double) - Adds this many hours to the &quot;Hours Worked&quot;
</span><span class="cx"> on the bug. If you are not in the time tracking group, this value will
</span><span class="lines">@@ -550,10 +2508,19 @@
</span><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><ins>+=item B&lt;Returns&gt;
+
+A hash with one element, C&lt;id&gt; whose value is the id of the newly-created comment.
+
</ins><span class="cx"> =item B&lt;Errors&gt;
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><ins>+=item 54 (Hours Worked Too Large)
+
+You specified a C&lt;work_time&gt; larger than the maximum allowed value of
+C&lt;99999.99&gt;.
+
</ins><span class="cx"> =item 100 (Invalid Bug Alias) 
</span><span class="cx"> 
</span><span class="cx"> If you specified an alias and either: (a) the Bugzilla you're querying
</span><span class="lines">@@ -563,10 +2530,19 @@
</span><span class="cx"> 
</span><span class="cx"> The id you specified doesn't exist in the database.
</span><span class="cx"> 
</span><del>-=item 108 (Bug Edit Denied)
</del><ins>+=item 109 (Bug Edit Denied)
</ins><span class="cx"> 
</span><span class="cx"> You did not have the necessary rights to edit the bug.
</span><span class="cx"> 
</span><ins>+=item 113 (Can't Make Private Comments)
+
+You tried to add a private comment, but don't have the necessary rights.
+
+=item 114 (Comment Too Long)
+
+You tried to add a comment longer than the maximum allowed length
+(65,535 characters).
+
</ins><span class="cx"> =back
</span><span class="cx"> 
</span><span class="cx"> =item B&lt;History&gt;
</span><span class="lines">@@ -575,9 +2551,592 @@
</span><span class="cx"> 
</span><span class="cx"> =item Added in Bugzilla B&lt;3.2&gt;.
</span><span class="cx"> 
</span><ins>+=item Modified to return the new comment's id in Bugzilla B&lt;3.4&gt;
+
+=item Modified to throw an error if you try to add a private comment
+but can't, in Bugzilla B&lt;3.4&gt;.
+
+=item Before Bugzilla B&lt;3.6&gt;, the C&lt;is_private&gt; argument was called
+C&lt;private&gt;, and you can still call it C&lt;private&gt; for backwards-compatibility
+purposes if you wish.
+
+=item Before Bugzilla B&lt;3.6&gt;, error 54 and error 114 had a generic error
+code of 32000.
+
</ins><span class="cx"> =back
</span><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><span class="cx"> 
</span><ins>+=head2 update
+
+B&lt;UNSTABLE&gt;
+
+=over
+
+=item B&lt;Description&gt;
+
+Allows you to update the fields of a bug. Automatically sends emails
+out about the changes.
+
+=item B&lt;Params&gt;
+
+=over
+
+=item C&lt;ids&gt;
+
+Array of C&lt;int&gt;s or C&lt;string&gt;s. The ids or aliases of the bugs that
+you want to modify.
+
</ins><span class="cx"> =back
</span><ins>+
+B&lt;Note&gt;: All following fields specify the values you want to set on the
+bugs you are updating.
+
+=over
+
+=item C&lt;alias&gt;
+
+(string) The alias of the bug. You can only set this if you are modifying 
+a single bug. If there is more than one bug specified in C&lt;ids&gt;, passing in
+a value for C&lt;alias&gt; will cause an error to be thrown.
+
+=item C&lt;assigned_to&gt;
+
+C&lt;string&gt; The full login name of the user this bug is assigned to.
+
+=item C&lt;blocks&gt;
+
+=item C&lt;depends_on&gt;
+
+C&lt;hash&gt; These specify the bugs that this bug blocks or depends on,
+respectively. To set these, you should pass a hash as the value. The hash
+may contain the following fields:
+
+=over
+
+=item C&lt;add&gt; An array of C&lt;int&gt;s. Bug ids to add to this field.
+
+=item C&lt;remove&gt; An array of C&lt;int&gt;s. Bug ids to remove from this field.
+If the bug ids are not already in the field, they will be ignored.
+
+=item C&lt;set&gt; An array of C&lt;int&gt;s. An exact set of bug ids to set this
+field to, overriding the current value. If you specify C&lt;set&gt;, then C&lt;add&gt;
+and  C&lt;remove&gt; will be ignored.
+
+=back
+
+=item C&lt;cc&gt;
+
+C&lt;hash&gt; The users on the cc list. To modify this field, pass a hash, which
+may have the following fields:
+
+=over
+
+=item C&lt;add&gt; Array of C&lt;string&gt;s. User names to add to the CC list.
+They must be full user names, and an error will be thrown if you pass
+in an invalid user name.
+
+=item C&lt;remove&gt; Array of C&lt;string&gt;s. User names to remove from the CC
+list. They must be full user names, and an error will be thrown if you
+pass in an invalid user name.
+
+=back
+
+=item C&lt;is_cc_accessible&gt;
+
+C&lt;boolean&gt; Whether or not users in the CC list are allowed to access
+the bug, even if they aren't in a group that can normally access the bug.
+
+=item C&lt;comment&gt;
+
+C&lt;hash&gt;. A comment on the change. The hash may contain the following fields:
+
+=over
+
+=item C&lt;body&gt; C&lt;string&gt; The actual text of the comment.
+B&lt;Note&gt;: For compatibility with the parameters to L&lt;/add_comment&gt;,
+you can also call this field C&lt;comment&gt;, if you want.
+
+=item C&lt;is_private&gt; C&lt;boolean&gt; Whether the comment is private or not.
+If you try to make a comment private and you don't have the permission
+to, an error will be thrown.
+
+=back
+
+=item C&lt;comment_is_private&gt;
+
+C&lt;hash&gt; This is how you update the privacy of comments that are already
+on a bug. This is a hash, where the keys are the C&lt;int&gt; id of comments (not
+their count on a bug, like #1, #2, #3, but their globally-unique id,
+as returned by L&lt;/comments&gt;) and the value is a C&lt;boolean&gt; which specifies
+whether that comment should become private (C&lt;true&gt;) or public (C&lt;false&gt;).
+
+The comment ids must be valid for the bug being updated. Thus, it is not
+practical to use this while updating multiple bugs at once, as a single
+comment id will never be valid on multiple bugs.
+
+=item C&lt;component&gt;
+
+C&lt;string&gt; The Component the bug is in.
+
+=item C&lt;deadline&gt;
+
+C&lt;string&gt; The Deadline field--a date specifying when the bug must
+be completed by, in the format C&lt;YYYY-MM-DD&gt;.
+
+=item C&lt;dupe_of&gt;
+
+C&lt;int&gt; The bug that this bug is a duplicate of. If you want to mark
+a bug as a duplicate, the safest thing to do is to set this value
+and I&lt;not&gt; set the C&lt;status&gt; or C&lt;resolution&gt; fields. They will
+automatically be set by Bugzilla to the appropriate values for
+duplicate bugs.
+
+=item C&lt;estimated_time&gt;
+
+C&lt;double&gt; The total estimate of time required to fix the bug, in hours.
+This is the I&lt;total&gt; estimate, not the amount of time remaining to fix it.
+
+=item C&lt;groups&gt;
+
+C&lt;hash&gt; The groups a bug is in. To modify this field, pass a hash, which
+may have the following fields:
+
+=over
+
+=item C&lt;add&gt; Array of C&lt;string&gt;s. The names of groups to add. Passing
+in an invalid group name or a group that you cannot add to this bug will
+cause an error to be thrown.
+
+=item C&lt;remove&gt; Array of C&lt;string&gt;s. The names of groups to remove. Passing
+in an invalid group name or a group that you cannot remove from this bug
+will cause an error to be thrown.
+
+=back
+
+=item C&lt;keywords&gt;
+
+C&lt;hash&gt; Keywords on the bug. To modify this field, pass a hash, which
+may have the following fields:
+
+=over
+
+=item C&lt;add&gt; An array of C&lt;strings&gt;s. The names of keywords to add to
+the field on the bug. Passing something that isn't a valid keyword name
+will cause an error to be thrown. 
+
+=item C&lt;remove&gt; An array of C&lt;string&gt;s. The names of keywords to remove
+from the field on the bug. Passing something that isn't a valid keyword
+name will cause an error to be thrown.
+
+=item C&lt;set&gt; An array of C&lt;strings&gt;s. An exact set of keywords to set the
+field to, on the bug. Passing something that isn't a valid keyword name
+will cause an error to be thrown. Specifying C&lt;set&gt; overrides C&lt;add&gt; and
+C&lt;remove&gt;.
+
+=back
+
+=item C&lt;op_sys&gt;
+
+C&lt;string&gt; The Operating System (&quot;OS&quot;) field on the bug.
+
+=item C&lt;platform&gt;
+
+C&lt;string&gt; The Platform or &quot;Hardware&quot; field on the bug.
+
+=item C&lt;priority&gt;
+
+C&lt;string&gt; The Priority field on the bug.
+
+=item C&lt;product&gt;
+
+C&lt;string&gt; The name of the product that the bug is in. If you change
+this, you will probably also want to change C&lt;target_milestone&gt;,
+C&lt;version&gt;, and C&lt;component&gt;, since those have different legal
+values in every product. 
+
+If you cannot change the C&lt;target_milestone&gt; field, it will be reset to
+the default for the product, when you move a bug to a new product.
+
+You may also wish to add or remove groups, as which groups are
+valid on a bug depends on the product. Groups that are not valid
+in the new product will be automatically removed, and groups which
+are mandatory in the new product will be automaticaly added, but no
+other automatic group changes will be done.
+
+Note that users can only move a bug into a product if they would
+normally have permission to file new bugs in that product.
+
+=item C&lt;qa_contact&gt;
+
+C&lt;string&gt; The full login name of the bug's QA Contact.
+
+=item C&lt;is_creator_accessible&gt;
+
+C&lt;boolean&gt; Whether or not the bug's reporter is allowed to access
+the bug, even if he or she isn't in a group that can normally access
+the bug.
+
+=item C&lt;remaining_time&gt;
+
+C&lt;double&gt; How much work time is remaining to fix the bug, in hours.
+If you set C&lt;work_time&gt; but don't explicitly set C&lt;remaining_time&gt;,
+then the C&lt;work_time&gt; will be deducted from the bug's C&lt;remaining_time&gt;.
+
+=item C&lt;reset_assigned_to&gt;
+
+C&lt;boolean&gt; If true, the C&lt;assigned_to&gt; field will be reset to the
+default for the component that the bug is in. (If you have set the
+component at the same time as using this, then the component used
+will be the new component, not the old one.)
+
+=item C&lt;reset_qa_contact&gt;
+
+C&lt;boolean&gt; If true, the C&lt;qa_contact&gt; field will be reset  to the
+default for the component that the bug is in. (If you have set the
+component at the same time as using this, then the component used
+will be the new component, not the old one.)
+
+=item C&lt;resolution&gt;
+
+C&lt;string&gt; The current resolution. May only be set if you are closing
+a bug or if you are modifying an already-closed bug. Attempting to set
+the resolution to I&lt;any&gt; value (even an empty or null string) on an
+open bug will cause an error to be thrown.
+
+If you change the C&lt;status&gt; field to an open status, the resolution
+field will automatically be cleared, so you don't have to clear it
+manually.
+
+=item C&lt;see_also&gt;
+
+C&lt;hash&gt; The See Also field on a bug, specifying URLs to bugs in other
+bug trackers. To modify this field, pass a hash, which may have the
+following fields:
+
+=over
+
+=item C&lt;add&gt; An array of C&lt;strings&gt;s. URLs to add to the field.
+Each URL must be a valid URL to a bug-tracker, or an error will
+be thrown.
+
+=item C&lt;remove&gt; An array of C&lt;string&gt;s. URLs to remove from the field.
+Invalid URLs will be ignored.
+
+=back
+
+=item C&lt;severity&gt;
+
+C&lt;string&gt; The Severity field of a bug.
+
+=item C&lt;status&gt;
+
+C&lt;string&gt; The status you want to change the bug to. Note that if
+a bug is changing from open to closed, you should also specify
+a C&lt;resolution&gt;.
+
+=item C&lt;summary&gt;
+
+C&lt;string&gt; The Summary field of the bug.
+
+=item C&lt;target_milestone&gt;
+
+C&lt;string&gt; The bug's Target Milestone.
+
+=item C&lt;url&gt;
+
+C&lt;string&gt; The &quot;URL&quot; field of a bug.
+
+=item C&lt;version&gt;
+
+C&lt;string&gt; The bug's Version field.
+
+=item C&lt;whiteboard&gt;
+
+C&lt;string&gt; The Status Whiteboard field of a bug.
+
+=item C&lt;work_time&gt;
+
+C&lt;double&gt; The number of hours worked on this bug as part of this change.
+If you set C&lt;work_time&gt; but don't explicitly set C&lt;remaining_time&gt;,
+then the C&lt;work_time&gt; will be deducted from the bug's C&lt;remaining_time&gt;.
+
+=back
+
+You can also set the value of any custom field by passing its name as
+a parameter, and the value to set the field to. For multiple-selection
+fields, the value should be an array of strings.
+
+=item B&lt;Returns&gt;
+
+A C&lt;hash&gt; with a single field, &quot;bugs&quot;. This points to an array of hashes
+with the following fields:
+
+=over
+
+=item C&lt;id&gt;
+
+C&lt;int&gt; The id of the bug that was updated.
+
+=item C&lt;alias&gt;
+
+C&lt;string&gt; The alias of the bug that was updated, if aliases are enabled and
+this bug has an alias.
+
+=item C&lt;last_change_time&gt;
+
+C&lt;dateTime&gt; The exact time that this update was done at, for this bug.
+If no update was done (that is, no fields had their values changed and
+no comment was added) then this will instead be the last time the bug
+was updated.
+
+=item C&lt;changes&gt;
+
+C&lt;hash&gt; The changes that were actually done on this bug. The keys are
+the names of the fields that were changed, and the values are a hash
+with two keys:
+
+=over
+
+=item C&lt;added&gt; (C&lt;string&gt;) The values that were added to this field,
+possibly a comma-and-space-separated list if multiple values were added.
+
+=item C&lt;removed&gt; (C&lt;string&gt;) The values that were removed from this
+field, possibly a comma-and-space-separated list if multiple values were
+removed.
+
+=back
+
+=back
+
+Here's an example of what a return value might look like:
+
+ { 
+   bugs =&gt; [
+     {
+       id    =&gt; 123,
+       alias =&gt; 'foo',
+       last_change_time =&gt; '2010-01-01T12:34:56',
+       changes =&gt; {
+         status =&gt; {
+           removed =&gt; 'NEW',
+           added   =&gt; 'ASSIGNED'
+         },
+         keywords =&gt; {
+           removed =&gt; 'bar',
+           added   =&gt; 'qux, quo, qui', 
+         }
+       },
+     }
+   ]
+ }
+
+Currently, some fields are not tracked in changes: C&lt;comment&gt;,
+C&lt;comment_is_private&gt;, and C&lt;work_time&gt;. This means that they will not
+show up in the return value even if they were successfully updated.
+This may change in a future version of Bugzilla.
+
+=item B&lt;Errors&gt;
+
+This function can throw all of the errors that L&lt;/get&gt;, L&lt;/create&gt;,
+and L&lt;/add_comment&gt; can throw, plus:
+
+=over
+
+=item 50 (Empty Field)
+
+You tried to set some field to be empty, but that field cannot be empty.
+The error message will have more details.
+
+=item 52 (Input Not A Number)
+
+You tried to set a numeric field to a value that wasn't numeric.
+
+=item 54 (Number Too Large)
+
+You tried to set a numeric field to a value larger than that field can
+accept.
+
+=item 55 (Number Too Small)
+
+You tried to set a negative value in a numeric field that does not accept
+negative values.
+
+=item 56 (Bad Date/Time)
+
+You specified an invalid date or time in a date/time field (such as
+the C&lt;deadline&gt; field or a custom date/time field).
+
+=item 112 (See Also Invalid)
+
+You attempted to add an invalid value to the C&lt;see_also&gt; field.
+
+=item 115 (Permission Denied)
+
+You don't have permission to change a particular field to a particular value.
+The error message will have more detail.
+
+=item 116 (Dependency Loop)
+
+You specified a value in the C&lt;blocks&gt; or C&lt;depends_on&gt; fields that causes
+a dependency loop.
+
+=item 117 (Invalid Comment ID)
+
+You specified a comment id in C&lt;comment_is_private&gt; that isn't on this bug.
+
+=item 118 (Duplicate Loop)
+
+You specified a value for C&lt;dupe_of&gt; that causes an infinite loop of
+duplicates.
+
+=item 119 (dupe_of Required)
+
+You changed the resolution to C&lt;DUPLICATE&gt; but did not specify a value
+for the C&lt;dupe_of&gt; field.
+
+=item 120 (Group Add/Remove Denied)
+
+You tried to add or remove a group that you don't have permission to modify
+for this bug, or you tried to add a group that isn't valid in this product.
+
+=item 121 (Resolution Required)
+
+You tried to set the C&lt;status&gt; field to a closed status, but you didn't
+specify a resolution.
+
+=item 122 (Resolution On Open Status)
+
+This bug has an open status, but you specified a value for the C&lt;resolution&gt;
+field.
+
+=item 123 (Invalid Status Transition)
+
+You tried to change from one status to another, but the status workflow
+rules don't allow that change.
+
+=back
+
+=item B&lt;History&gt;
+
+=over
+
+=item Added in Bugzilla B&lt;4.0&gt;.
+
+=back
+
+=back
+
+
+=head2 update_see_also
+
+B&lt;EXPERIMENTAL&gt;
+
+=over
+
+=item B&lt;Description&gt;
+
+Adds or removes URLs for the &quot;See Also&quot; field on bugs. These URLs must
+point to some valid bug in some Bugzilla installation or in Launchpad.
+
+=item B&lt;Params&gt;
+
+=over
+
+=item C&lt;ids&gt;
+
+Array of C&lt;int&gt;s or C&lt;string&gt;s. The ids or aliases of bugs that you want
+to modify.
+
+=item C&lt;add&gt;
+
+Array of C&lt;string&gt;s. URLs to Bugzilla bugs. These URLs will be added to
+the See Also field. They must be valid URLs to C&lt;show_bug.cgi&gt; in a
+Bugzilla installation or to a bug filed at launchpad.net.
+
+If the URLs don't start with C&lt;http://&gt; or C&lt;https://&gt;, it will be assumed
+that C&lt;http://&gt; should be added to the beginning of the string.
+
+It is safe to specify URLs that are already in the &quot;See Also&quot; field on
+a bug--they will just be silently ignored.
+
+=item C&lt;remove&gt;
+
+Array of C&lt;string&gt;s. These URLs will be removed from the See Also field.
+You must specify the full URL that you want removed. However, matching
+is done case-insensitively, so you don't have to specify the URL in
+exact case, if you don't want to.
+
+If you specify a URL that is not in the See Also field of a particular bug,
+it will just be silently ignored. Invaild URLs are currently silently ignored,
+though this may change in some future version of Bugzilla.
+
+=back
+
+NOTE: If you specify the same URL in both C&lt;add&gt; and C&lt;remove&gt;, it will
+be I&lt;added&gt;. (That is, C&lt;add&gt; overrides C&lt;remove&gt;.)
+
+=item B&lt;Returns&gt;
+
+C&lt;changes&gt;, a hash where the keys are numeric bug ids and the contents
+are a hash with one key, C&lt;see_also&gt;. C&lt;see_also&gt; points to a hash, which
+contains two keys, C&lt;added&gt; and C&lt;removed&gt;. These are arrays of strings,
+representing the actual changes that were made to the bug.
+
+Here's a diagram of what the return value looks like for updating
+bug ids 1 and 2:
+
+ {
+   changes =&gt; {
+       1 =&gt; {
+           see_also =&gt; {
+               added   =&gt; (an array of bug URLs),
+               removed =&gt; (an array of bug URLs),
+           }
+       },
+       2 =&gt; {
+           see_also =&gt; {
+               added   =&gt; (an array of bug URLs),
+               removed =&gt; (an array of bug URLs),
+           }
+       }
+   }
+ }
+
+This return value allows you to tell what this method actually did. It is in
+this format to be compatible with the return value of a future C&lt;Bug.update&gt;
+method.
+
+=item B&lt;Errors&gt;
+
+This method can throw all of the errors that L&lt;/get&gt; throws, plus:
+
+=over
+
+=item 109 (Bug Edit Denied)
+
+You did not have the necessary rights to edit the bug.
+
+=item 112 (Invalid Bug URL)
+
+One of the URLs you provided did not look like a valid bug URL.
+
+=item 115 (See Also Edit Denied)
+
+You did not have the necessary rights to edit the See Also field for
+this bug.
+
+=back
+
+=item B&lt;History&gt;
+
+=over
+
+=item Added in Bugzilla B&lt;3.4&gt;.
+
+=item Before Bugzilla B&lt;3.6&gt;, error 115 had a generic error code of 32000.
+
+=back
+
+=back
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaWebServiceBugzillapm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Bugzilla.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Bugzilla.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Bugzilla.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -21,10 +21,9 @@
</span><span class="cx"> use strict;
</span><span class="cx"> use base qw(Bugzilla::WebService);
</span><span class="cx"> use Bugzilla::Constants;
</span><del>-use Bugzilla::Hook;
-import SOAP::Data qw(type);
</del><ins>+use Bugzilla::Util qw(datetime_from);
</ins><span class="cx"> 
</span><del>-use Time::Zone;
</del><ins>+use DateTime;
</ins><span class="cx"> 
</span><span class="cx"> # Basic info that is needed before logins
</span><span class="cx"> use constant LOGIN_EXEMPT =&gt; {
</span><span class="lines">@@ -32,29 +31,56 @@
</span><span class="cx">     version =&gt; 1,
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+use constant READ_ONLY =&gt; qw(
+    extensions
+    timezone
+    time
+    version
+);
+
</ins><span class="cx"> sub version {
</span><del>-    return { version =&gt; type('string')-&gt;value(BUGZILLA_VERSION) };
</del><ins>+    my $self = shift;
+    return { version =&gt; $self-&gt;type('string', BUGZILLA_VERSION) };
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub extensions {
</span><del>-    my $extensions = Bugzilla::Hook::enabled_plugins();
-    foreach my $name (keys %$extensions) {
-        my $info = $extensions-&gt;{$name};
-        foreach my $data (keys %$info)
-        {
-            $extensions-&gt;{$name}-&gt;{$data} = type('string')-&gt;value($info-&gt;{$data});
-        }
</del><ins>+    my $self = shift;
+
+    my %retval;
+    foreach my $extension (@{ Bugzilla-&gt;extensions }) {
+        my $version = $extension-&gt;VERSION || 0;
+        my $name    = $extension-&gt;NAME;
+        $retval{$name}-&gt;{version} = $self-&gt;type('string', $version);
</ins><span class="cx">     }
</span><del>-    return { extensions =&gt; $extensions };
</del><ins>+    return { extensions =&gt; \%retval };
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub timezone {
</span><del>-    my $offset = tz_offset();
-    $offset = (($offset / 60) / 60) * 100;
-    $offset = sprintf('%+05d', $offset);
-    return { timezone =&gt; type('string')-&gt;value($offset) };
</del><ins>+    my $self = shift;
+    # All Webservices return times in UTC; Use UTC here for backwards compat.
+    return { timezone =&gt; $self-&gt;type('string', &quot;+0000&quot;) };
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub time {
+    my ($self) = @_;
+    # All Webservices return times in UTC; Use UTC here for backwards compat.
+    # Hardcode values where appropriate
+    my $dbh = Bugzilla-&gt;dbh;
+
+    my $db_time = $dbh-&gt;selectrow_array('SELECT LOCALTIMESTAMP(0)');
+    $db_time = datetime_from($db_time, 'UTC');
+    my $now_utc = DateTime-&gt;now();
+
+    return {
+        db_time       =&gt; $self-&gt;type('dateTime', $db_time),
+        web_time      =&gt; $self-&gt;type('dateTime', $now_utc),
+        web_time_utc  =&gt; $self-&gt;type('dateTime', $now_utc),
+        tz_name       =&gt; $self-&gt;type('string', 'UTC'),
+        tz_offset     =&gt; $self-&gt;type('string', '+0000'),
+        tz_short_name =&gt; $self-&gt;type('string', 'UTC'),
+    };
+}
+
</ins><span class="cx"> 1;
</span><span class="cx"> 
</span><span class="cx"> __END__
</span><span class="lines">@@ -72,10 +98,8 @@
</span><span class="cx"> See L&lt;Bugzilla::WebService&gt; for a description of how parameters are passed,
</span><span class="cx"> and what B&lt;STABLE&gt;, B&lt;UNSTABLE&gt;, and B&lt;EXPERIMENTAL&gt; mean.
</span><span class="cx"> 
</span><del>-=over
</del><ins>+=head2 version
</ins><span class="cx"> 
</span><del>-=item C&lt;version&gt;
-
</del><span class="cx"> B&lt;STABLE&gt;
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="lines">@@ -95,7 +119,7 @@
</span><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><del>-=item C&lt;extensions&gt;
</del><ins>+=head2 extensions
</ins><span class="cx"> 
</span><span class="cx"> B&lt;EXPERIMENTAL&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -110,32 +134,46 @@
</span><span class="cx"> 
</span><span class="cx"> =item B&lt;Returns&gt;
</span><span class="cx"> 
</span><del>-A hash with a single item, C&lt;extesions&gt;. This points to a hash. I&lt;That&gt; hash
-contains the names of extensions as keys, and information about the extension
-as values. One of the values that must be returned is the 'version' of the
-extension
</del><ins>+A hash with a single item, C&lt;extensions&gt;. This points to a hash. I&lt;That&gt; hash
+contains the names of extensions as keys, and the values are a hash.
+That hash contains a single key C&lt;version&gt;, which is the version of the
+extension, or C&lt;0&gt; if the extension hasn't defined a version.
</ins><span class="cx"> 
</span><ins>+The return value looks something like this:
+
+ extensions =&gt; {
+     Example =&gt; {
+         version =&gt; '3.6',
+     },
+     BmpConvert =&gt; {
+         version =&gt; '1.0',
+     },
+ }
+
</ins><span class="cx"> =item B&lt;History&gt;
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><span class="cx"> =item Added in Bugzilla B&lt;3.2&gt;.
</span><span class="cx"> 
</span><ins>+=item As of Bugzilla B&lt;3.6&gt;, the names of extensions are canonical names
+that the extensions define themselves. Before 3.6, the names of the
+extensions depended on the directory they were in on the Bugzilla server.
+
</ins><span class="cx"> =back
</span><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><del>-=item C&lt;timezone&gt;
</del><ins>+=head2 timezone
</ins><span class="cx"> 
</span><del>-B&lt;STABLE&gt;
</del><ins>+B&lt;DEPRECATED&gt; This method may be removed in a future version of Bugzilla.
+Use L&lt;/time&gt; instead.
</ins><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><span class="cx"> =item B&lt;Description&gt;
</span><span class="cx"> 
</span><del>-Returns the timezone of the server Bugzilla is running on. This is
-important because all dates/times that the webservice interface
-returns will be in this timezone.
</del><ins>+Returns the timezone that Bugzilla expects dates and times in.
</ins><span class="cx"> 
</span><span class="cx"> =item B&lt;Params&gt; (none)
</span><span class="cx"> 
</span><span class="lines">@@ -144,6 +182,89 @@
</span><span class="cx"> A hash with a single item, C&lt;timezone&gt;, that is the timezone offset as a
</span><span class="cx"> string in (+/-)XXXX (RFC 2822) format.
</span><span class="cx"> 
</span><ins>+=item B&lt;History&gt;
+
+=over
+
+=item As of Bugzilla B&lt;3.6&gt;, the timezone returned is always C&lt;+0000&gt;
+(the UTC timezone).
+
</ins><span class="cx"> =back
</span><span class="cx"> 
</span><span class="cx"> =back
</span><ins>+
+
+=head2 time
+
+B&lt;STABLE&gt;
+
+=over
+
+=item B&lt;Description&gt;
+
+Gets information about what time the Bugzilla server thinks it is, and
+what timezone it's running in.
+
+=item B&lt;Params&gt; (none)
+
+=item B&lt;Returns&gt;
+
+A struct with the following items:
+
+=over
+
+=item C&lt;db_time&gt;
+
+C&lt;dateTime&gt; The current time in UTC, according to the Bugzilla 
+I&lt;database server&gt;.
+
+Note that Bugzilla assumes that the database and the webserver are running
+in the same time zone. However, if the web server and the database server
+aren't synchronized for some reason, I&lt;this&gt; is the time that you should
+rely on for doing searches and other input to the WebService.
+
+=item C&lt;web_time&gt;
+
+C&lt;dateTime&gt; This is the current time in UTC, according to Bugzilla's 
+I&lt;web server&gt;.
+
+This might be different by a second from C&lt;db_time&gt; since this comes from
+a different source. If it's any more different than a second, then there is
+likely some problem with this Bugzilla instance. In this case you should
+rely on the C&lt;db_time&gt;, not the C&lt;web_time&gt;.
+
+=item C&lt;web_time_utc&gt;
+
+Identical to C&lt;web_time&gt;. (Exists only for backwards-compatibility with
+versions of Bugzilla before 3.6.)
+
+=item C&lt;tz_name&gt;
+
+C&lt;string&gt; The literal string C&lt;UTC&gt;. (Exists only for backwards-compatibility
+with versions of Bugzilla before 3.6.) 
+
+=item C&lt;tz_short_name&gt;
+
+C&lt;string&gt; The literal string C&lt;UTC&gt;. (Exists only for backwards-compatibility
+with versions of Bugzilla before 3.6.)
+
+=item C&lt;tz_offset&gt;
+
+C&lt;string&gt; The literal string C&lt;+0000&gt;. (Exists only for backwards-compatibility
+with versions of Bugzilla before 3.6.)
+
+=back
+
+=item B&lt;History&gt;
+
+=over
+
+=item Added in Bugzilla B&lt;3.4&gt;.
+
+=item As of Bugzilla B&lt;3.6&gt;, this method returns all data as though the server
+were in the UTC timezone, instead of returning information in the server's
+local timezone.
+
+=back
+
+=back
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaWebServiceConstantspm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Constants.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Constants.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Constants.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -20,13 +20,13 @@
</span><span class="cx"> use strict;
</span><span class="cx"> use base qw(Exporter);
</span><span class="cx"> 
</span><del>-@Bugzilla::WebService::Constants::EXPORT = qw(
</del><ins>+our @EXPORT = qw(
</ins><span class="cx">     WS_ERROR_CODE
</span><span class="cx">     ERROR_UNKNOWN_FATAL
</span><span class="cx">     ERROR_UNKNOWN_TRANSIENT
</span><ins>+    XMLRPC_CONTENT_TYPE_WHITELIST
</ins><span class="cx"> 
</span><del>-    ERROR_AUTH_NODATA
-    ERROR_UNIMPLEMENTED
</del><ins>+    WS_DISPATCH
</ins><span class="cx"> );
</span><span class="cx"> 
</span><span class="cx"> # This maps the error names in global/*-error.html.tmpl to numbers.
</span><span class="lines">@@ -48,12 +48,19 @@
</span><span class="cx"> # comment that it was retired. Also, if an error changes its name, you'll
</span><span class="cx"> # have to fix it here.
</span><span class="cx"> use constant WS_ERROR_CODE =&gt; {
</span><del>-    # Generic Bugzilla::Object errors are 50-99.
-    object_name_not_specified   =&gt; 50,
</del><ins>+    # Generic errors (Bugzilla::Object and others) are 50-99.    
+    object_not_specified        =&gt; 50,
+    reassign_to_empty           =&gt; 50,
</ins><span class="cx">     param_required              =&gt; 50,
</span><ins>+    params_required             =&gt; 50,
+    undefined_field             =&gt; 50,
</ins><span class="cx">     object_does_not_exist       =&gt; 51,
</span><del>-    # Error 52 exists only in later releases.
</del><ins>+    param_must_be_numeric       =&gt; 52,
+    number_not_numeric          =&gt; 52,
</ins><span class="cx">     param_invalid               =&gt; 53,
</span><ins>+    number_too_large            =&gt; 54,
+    number_too_small            =&gt; 55,
+    illegal_date                =&gt; 56,
</ins><span class="cx">     # Bug errors usually occupy the 100-200 range.
</span><span class="cx">     improper_bug_id_field_value =&gt; 100,
</span><span class="cx">     bug_id_does_not_exist       =&gt; 101,
</span><span class="lines">@@ -64,6 +71,7 @@
</span><span class="cx">     alias_in_use             =&gt; 103,
</span><span class="cx">     alias_is_numeric         =&gt; 103,
</span><span class="cx">     alias_has_comma_or_space =&gt; 103,
</span><ins>+    multiple_alias_not_allowed =&gt; 103,
</ins><span class="cx">     # Misc. bug field errors
</span><span class="cx">     illegal_field =&gt; 104,
</span><span class="cx">     freetext_too_long =&gt; 104,
</span><span class="lines">@@ -81,32 +89,120 @@
</span><span class="cx">     invalid_field_name =&gt; 108,
</span><span class="cx">     # Not authorized to edit the bug
</span><span class="cx">     product_edit_denied =&gt; 109,
</span><ins>+    # Comment-related errors
+    comment_is_private =&gt; 110,
+    comment_id_invalid =&gt; 111,
+    comment_too_long =&gt; 114,
+    comment_invalid_isprivate =&gt; 117, 
+    # See Also errors
+    bug_url_invalid =&gt; 112,
+    bug_url_too_long =&gt; 112,
+    # Insidergroup Errors
+    user_not_insider =&gt; 113,
+    # Note: 114 is above in the Comment-related section.
+    # Bug update errors
+    illegal_change =&gt; 115,
+    # Dependency errors
+    dependency_loop_single =&gt; 116,
+    dependency_loop_multi  =&gt; 116,
+    # Note: 117 is above in the Comment-related section.
+    # Dup errors
+    dupe_loop_detected =&gt; 118,
+    dupe_id_required =&gt; 119,
+    # Bug-related group errors
+    group_invalid_removal =&gt; 120,
+    group_restriction_not_allowed =&gt; 120,
+    # Status/Resolution errors
+    missing_resolution =&gt; 121,
+    resolution_not_allowed =&gt; 122,
+    illegal_bug_status_transition =&gt; 123,
</ins><span class="cx"> 
</span><span class="cx">     # Authentication errors are usually 300-400.
</span><span class="cx">     invalid_username_or_password =&gt; 300,
</span><span class="cx">     account_disabled             =&gt; 301,
</span><span class="cx">     auth_invalid_email           =&gt; 302,
</span><span class="cx">     extern_id_conflict           =&gt; -303,
</span><ins>+    auth_failure                 =&gt; 304,
+    password_current_too_short   =&gt; 305,
</ins><span class="cx"> 
</span><ins>+    # Except, historically, AUTH_NODATA, which is 410.
+    login_required               =&gt; 410,
+
</ins><span class="cx">     # User errors are 500-600.
</span><span class="cx">     account_exists        =&gt; 500,
</span><span class="cx">     illegal_email_address =&gt; 501,
</span><ins>+    auth_cant_create_account    =&gt; 501,
</ins><span class="cx">     account_creation_disabled   =&gt; 501,
</span><span class="cx">     account_creation_restricted =&gt; 501,
</span><span class="cx">     password_too_short    =&gt; 502,
</span><del>-    password_too_long     =&gt; 503,
</del><ins>+    # Error 503 password_too_long no longer exists.
</ins><span class="cx">     invalid_username      =&gt; 504,
</span><span class="cx">     # This is from strict_isolation, but it also basically means 
</span><span class="cx">     # &quot;invalid user.&quot;
</span><span class="cx">     invalid_user_group    =&gt; 504,
</span><ins>+    user_access_by_id_denied    =&gt; 505,
+    user_access_by_match_denied =&gt; 505,
+
+    # Attachment errors are 600-700.
+    file_too_large         =&gt; 600,
+    invalid_content_type   =&gt; 601,
+    # Error 602 attachment_illegal_url no longer exists.
+    file_not_specified     =&gt; 603,
+    missing_attachment_description =&gt; 604,
+    # Error 605 attachment_url_disabled no longer exists.
+    zero_length_file       =&gt; 606,
+
+    # Product erros are 700-800
+    product_blank_name =&gt; 700,
+    product_name_too_long =&gt; 701,
+    product_name_already_in_use =&gt; 702,
+    product_name_diff_in_case =&gt; 702,
+    product_must_have_description =&gt; 703,
+    product_must_have_version =&gt; 704,
+    product_must_define_defaultmilestone =&gt; 705,
+
+    # Group errors are 800-900
+    empty_group_name =&gt; 800,
+    group_exists =&gt; 801,
+    empty_group_description =&gt; 802,
+    invalid_regexp =&gt; 803,
+
+    # Errors thrown by the WebService itself. The ones that are negative 
+    # conform to http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php
+    xmlrpc_invalid_value =&gt; -32600,
+    unknown_method       =&gt; -32601,
+    json_rpc_post_only   =&gt; 32610,
+    json_rpc_invalid_callback =&gt; 32611,
+    xmlrpc_illegal_content_type   =&gt; 32612, 
+    json_rpc_illegal_content_type =&gt; 32613, 
</ins><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> # These are the fallback defaults for errors not in ERROR_CODE.
</span><span class="cx"> use constant ERROR_UNKNOWN_FATAL     =&gt; -32000;
</span><span class="cx"> use constant ERROR_UNKNOWN_TRANSIENT =&gt; 32000;
</span><span class="cx"> 
</span><del>-use constant ERROR_AUTH_NODATA   =&gt; 410;
-use constant ERROR_UNIMPLEMENTED =&gt; 910;
</del><span class="cx"> use constant ERROR_GENERAL       =&gt; 999;
</span><span class="cx"> 
</span><ins>+use constant XMLRPC_CONTENT_TYPE_WHITELIST =&gt; qw(
+    text/xml
+    application/xml
+);
+
+sub WS_DISPATCH {
+    # We &quot;require&quot; here instead of &quot;use&quot; above to avoid a dependency loop.
+    require Bugzilla::Hook;
+    my %hook_dispatch;
+    Bugzilla::Hook::process('webservice', { dispatch =&gt; \%hook_dispatch });
+
+    my $dispatch = {
+        'Bugzilla' =&gt; 'Bugzilla::WebService::Bugzilla',
+        'Bug'      =&gt; 'Bugzilla::WebService::Bug',
+        'User'     =&gt; 'Bugzilla::WebService::User',
+        'Product'  =&gt; 'Bugzilla::WebService::Product',
+        'Group'    =&gt; 'Bugzilla::WebService::Group',
+        %hook_dispatch
+    };
+    return $dispatch;
+};
+
</ins><span class="cx"> 1;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaWebServiceGrouppm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Group.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Group.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Group.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,141 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# Contributor(s): 
+#   Carole Pryfer &lt;carole.pryfer@dgfip.finances.gouv.fr&gt;
+
+package Bugzilla::WebService::Group;
+
+use strict;
+use base qw(Bugzilla::WebService);
+use Bugzilla::Constants;
+use Bugzilla::Error;
+
+sub create {
+    my ($self, $params) = @_;
+
+    Bugzilla-&gt;login(LOGIN_REQUIRED);
+    Bugzilla-&gt;user-&gt;in_group('creategroups') 
+        || ThrowUserError(&quot;auth_failure&quot;, { group  =&gt; &quot;creategroups&quot;,
+                                            action =&gt; &quot;add&quot;,
+                                            object =&gt; &quot;group&quot;});
+    # Create group
+    my $group = Bugzilla::Group-&gt;create({
+        name               =&gt; $params-&gt;{name},
+        description        =&gt; $params-&gt;{description},
+        userregexp         =&gt; $params-&gt;{user_regexp},
+        isactive           =&gt; $params-&gt;{is_active},
+        isbuggroup         =&gt; 1,
+        icon_url           =&gt; $params-&gt;{icon_url}
+    });
+    return { id =&gt; $self-&gt;type('int', $group-&gt;id) };
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::Webservice::Group - The API for creating, changing, and getting
+information about Groups.
+
+=head1 DESCRIPTION
+
+This part of the Bugzilla API allows you to create Groups and
+get information about them.
+
+=head1 METHODS
+
+See L&lt;Bugzilla::WebService&gt; for a description of how parameters are passed,
+and what B&lt;STABLE&gt;, B&lt;UNSTABLE&gt;, and B&lt;EXPERIMENTAL&gt; mean.
+
+=head1 Group Creation
+
+=head2 create
+
+B&lt;UNSTABLE&gt;
+
+=over
+
+=item B&lt;Description&gt;
+
+This allows you to create a new group in Bugzilla.
+
+=item B&lt;Params&gt; 
+
+Some params must be set, or an error will be thrown. These params are 
+marked B&lt;Required&gt;.
+
+=over
+
+=item C&lt;name&gt;
+
+B&lt;Required&gt; C&lt;string&gt; A short name for this group. Must be unique. This
+is not usually displayed in the user interface, except in a few places.
+
+=item C&lt;description&gt;
+
+B&lt;Required&gt; C&lt;string&gt; A human-readable name for this group. Should be
+relatively short. This is what will normally appear in the UI as the
+name of the group.
+
+=item C&lt;user_regexp&gt;
+
+C&lt;string&gt; A regular expression. Any user whose Bugzilla username matches
+this regular expression will automatically be granted membership in this group.
+
+=item C&lt;is_active&gt; 
+
+C&lt;boolean&gt; C&lt;True&gt; if new group can be used for bugs, C&lt;False&gt; if this
+is a group that will only contain users and no bugs will be restricted
+to it.
+
+=item C&lt;icon_url&gt;
+
+C&lt;string&gt; A URL pointing to a small icon used to identify the group.
+This icon will show up next to users' names in various parts of Bugzilla
+if they are in this group.
+
+=back
+
+=item B&lt;Returns&gt;    
+
+A hash with one element, C&lt;id&gt;. This is the id of the newly-created group.
+
+=item B&lt;Errors&gt;
+
+=over
+
+=item 800 (Empty Group Name)
+
+You must specify a value for the C&lt;name&gt; field.
+
+=item 801 (Group Exists)
+
+There is already another group with the same C&lt;name&gt;.
+
+=item 802 (Group Missing Description)
+
+You must specify a value for the C&lt;description&gt; field.
+
+=item 803 (Group Regexp Invalid)
+
+You specified an invalid regular expression in the C&lt;user_regexp&gt; field.
+
+=back
+
+=back 
+
+=cut
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaWebServiceProductpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Product.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Product.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Product.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -14,6 +14,7 @@
</span><span class="cx"> #
</span><span class="cx"> # Contributor(s): Marc Schumann &lt;wurblzap@gmail.com&gt;
</span><span class="cx"> #                 Mads Bondo Dydensborg &lt;mbd@dbc.dk&gt;
</span><ins>+#                 Byron Jones &lt;glob@mozilla.com&gt;
</ins><span class="cx"> 
</span><span class="cx"> package Bugzilla::WebService::Product;
</span><span class="cx"> 
</span><span class="lines">@@ -21,8 +22,23 @@
</span><span class="cx"> use base qw(Bugzilla::WebService);
</span><span class="cx"> use Bugzilla::Product;
</span><span class="cx"> use Bugzilla::User;
</span><del>-import SOAP::Data qw(type);
</del><ins>+use Bugzilla::Error;
+use Bugzilla::Constants;
+use Bugzilla::WebService::Constants;
+use Bugzilla::WebService::Util qw(validate filter filter_wants);
</ins><span class="cx"> 
</span><ins>+use constant READ_ONLY =&gt; qw(
+    get
+    get_accessible_products
+    get_enterable_products
+    get_selectable_products
+);
+
+use constant FIELD_MAP =&gt; {
+    has_unconfirmed =&gt; 'allows_unconfirmed',
+    is_open         =&gt; 'isactive',
+};
+
</ins><span class="cx"> ##################################################
</span><span class="cx"> # Add aliases here for method name compatibility #
</span><span class="cx"> ##################################################
</span><span class="lines">@@ -44,34 +60,153 @@
</span><span class="cx">     return {ids =&gt; [map {$_-&gt;id} @{Bugzilla-&gt;user-&gt;get_accessible_products}]}; 
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-# Get a list of actual products, based on list of ids
</del><ins>+# Get a list of actual products, based on list of ids or names
</ins><span class="cx"> sub get {
</span><del>-    my ($self, $params) = @_;
</del><ins>+    my ($self, $params) = validate(@_, 'ids', 'names');
</ins><span class="cx">     
</span><span class="cx">     # Only products that are in the users accessible products, 
</span><span class="cx">     # can be allowed to be returned
</span><span class="cx">     my $accessible_products = Bugzilla-&gt;user-&gt;get_accessible_products;
</span><span class="cx"> 
</span><del>-    # Create a hash with the ids the user wants
-    my %ids = map { $_ =&gt; 1 } @{$params-&gt;{ids}};
-    
-    # Return the intersection of this, by grepping the ids from 
-    # accessible products.
-    my @requested_accessible = grep { $ids{$_-&gt;id} } @$accessible_products;
</del><ins>+    my @requested_accessible;
</ins><span class="cx"> 
</span><ins>+    if (defined $params-&gt;{ids}) {
+        # Create a hash with the ids the user wants
+        my %ids = map { $_ =&gt; 1 } @{$params-&gt;{ids}};
+        
+        # Return the intersection of this, by grepping the ids from 
+        # accessible products.
+        push(@requested_accessible,
+            grep { $ids{$_-&gt;id} } @$accessible_products);
+    }
+
+    if (defined $params-&gt;{names}) {
+        # Create a hash with the names the user wants
+        my %names = map { lc($_) =&gt; 1 } @{$params-&gt;{names}};
+        
+        # Return the intersection of this, by grepping the names from 
+        # accessible products, union'ed with products found by ID to
+        # avoid duplicates
+        foreach my $product (grep { $names{lc $_-&gt;name} }
+                                  @$accessible_products) {
+            next if grep { $_-&gt;id == $product-&gt;id }
+                         @requested_accessible;
+            push @requested_accessible, $product;
+        }
+    }
+
</ins><span class="cx">     # Now create a result entry for each.
</span><del>-    my @products = 
-        map {{
-               internals   =&gt; $_,
-               id          =&gt; type('int')-&gt;value($_-&gt;id),
-               name        =&gt; type('string')-&gt;value($_-&gt;name),
-               description =&gt; type('string')-&gt;value($_-&gt;description), 
-             }
-        } @requested_accessible;
-
</del><ins>+    my @products = map { $self-&gt;_product_to_hash($params, $_) }
+                       @requested_accessible;
</ins><span class="cx">     return { products =&gt; \@products };
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub create {
+    my ($self, $params) = @_;
+
+    Bugzilla-&gt;login(LOGIN_REQUIRED);
+    Bugzilla-&gt;user-&gt;in_group('editcomponents') 
+        || ThrowUserError(&quot;auth_failure&quot;, { group  =&gt; &quot;editcomponents&quot;,
+                                            action =&gt; &quot;add&quot;,
+                                            object =&gt; &quot;products&quot;});
+    # Create product
+    my $args = {
+        name             =&gt; $params-&gt;{name},
+        description      =&gt; $params-&gt;{description},
+        version          =&gt; $params-&gt;{version},
+        defaultmilestone =&gt; $params-&gt;{default_milestone},
+        # create_series has no default value.
+        create_series    =&gt; defined $params-&gt;{create_series} ?
+                              $params-&gt;{create_series} : 1
+    };
+    foreach my $field (qw(has_unconfirmed is_open classification)) {
+        if (defined $params-&gt;{$field}) {
+            my $name = FIELD_MAP-&gt;{$field} || $field;
+            $args-&gt;{$name} = $params-&gt;{$field};
+        }
+    }
+    my $product = Bugzilla::Product-&gt;create($args);
+    return { id =&gt; $self-&gt;type('int', $product-&gt;id) };
+}
+
+sub _product_to_hash {
+    my ($self, $params, $product) = @_;
+
+    my $field_data = {
+        id          =&gt; $self-&gt;type('int', $product-&gt;id),
+        name        =&gt; $self-&gt;type('string', $product-&gt;name),
+        description =&gt; $self-&gt;type('string', $product-&gt;description),
+        is_active   =&gt; $self-&gt;type('boolean', $product-&gt;is_active),
+        default_milestone =&gt; $self-&gt;type('string', $product-&gt;default_milestone),
+        has_unconfirmed   =&gt; $self-&gt;type('boolean', $product-&gt;allows_unconfirmed),
+        classification =&gt; $self-&gt;type('string', $product-&gt;classification-&gt;name),
+    };
+    if (filter_wants($params, 'components')) {
+        $field_data-&gt;{components} = [map {
+            $self-&gt;_component_to_hash($_)
+        } @{$product-&gt;components}];
+    }
+    if (filter_wants($params, 'versions')) {
+        $field_data-&gt;{versions} = [map {
+            $self-&gt;_version_to_hash($_)
+        } @{$product-&gt;versions}];
+    }
+    if (filter_wants($params, 'milestones')) {
+        $field_data-&gt;{milestones} = [map {
+            $self-&gt;_milestone_to_hash($_)
+        } @{$product-&gt;milestones}];
+    }
+    return filter($params, $field_data);
+}
+
+sub _component_to_hash {
+    my ($self, $component) = @_;
+    return {
+        id =&gt;
+            $self-&gt;type('int', $component-&gt;id),
+        name =&gt;
+            $self-&gt;type('string', $component-&gt;name),
+        description =&gt;
+            $self-&gt;type('string' , $component-&gt;description),
+        default_assigned_to =&gt;
+            $self-&gt;type('string' , $component-&gt;default_assignee-&gt;login),
+        default_qa_contact =&gt;
+            $self-&gt;type('string' , $component-&gt;default_qa_contact-&gt;login),
+        sort_key =&gt;  # sort_key is returned to match Bug.fields
+            0,
+        is_active =&gt;
+            $self-&gt;type('boolean', $component-&gt;is_active),
+    };
+}
+
+sub _version_to_hash {
+    my ($self, $version) = @_;
+    return {
+        id =&gt;
+            $self-&gt;type('int', $version-&gt;id),
+        name =&gt;
+            $self-&gt;type('string', $version-&gt;name),
+        sort_key =&gt;  # sort_key is returened to match Bug.fields
+            0,
+        is_active =&gt;
+            $self-&gt;type('boolean', $version-&gt;is_active),
+    };
+}
+
+sub _milestone_to_hash {
+    my ($self, $milestone) = @_;
+    return {
+        id =&gt;
+            $self-&gt;type('int', $milestone-&gt;id),
+        name =&gt;
+            $self-&gt;type('string', $milestone-&gt;name),
+        sort_key =&gt;
+            $self-&gt;type('int', $milestone-&gt;sortkey),
+        is_active =&gt;
+            $self-&gt;type('boolean', $milestone-&gt;is_active),
+    };
+}
+
</ins><span class="cx"> 1;
</span><span class="cx"> 
</span><span class="cx"> __END__
</span><span class="lines">@@ -90,12 +225,10 @@
</span><span class="cx"> See L&lt;Bugzilla::WebService&gt; for a description of how parameters are passed,
</span><span class="cx"> and what B&lt;STABLE&gt;, B&lt;UNSTABLE&gt;, and B&lt;EXPERIMENTAL&gt; mean.
</span><span class="cx"> 
</span><del>-=head2 List Products
</del><ins>+=head1 List Products
</ins><span class="cx"> 
</span><del>-=over
</del><ins>+=head2 get_selectable_products
</ins><span class="cx"> 
</span><del>-=item C&lt;get_selectable_products&gt; 
-
</del><span class="cx"> B&lt;EXPERIMENTAL&gt;
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="lines">@@ -115,7 +248,7 @@
</span><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><del>-=item C&lt;get_enterable_products&gt; 
</del><ins>+=head2 get_enterable_products
</ins><span class="cx"> 
</span><span class="cx"> B&lt;EXPERIMENTAL&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -137,7 +270,7 @@
</span><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><del>-=item C&lt;get_accessible_products&gt; 
</del><ins>+=head2 get_accessible_products
</ins><span class="cx"> 
</span><span class="cx"> B&lt;UNSTABLE&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -159,7 +292,7 @@
</span><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><del>-=item C&lt;get&gt; 
</del><ins>+=head2 get
</ins><span class="cx"> 
</span><span class="cx"> B&lt;EXPERIMENTAL&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -173,18 +306,114 @@
</span><span class="cx"> 
</span><span class="cx"> =item B&lt;Params&gt;
</span><span class="cx"> 
</span><del>-A hash containing one item, C&lt;ids&gt;, that is an array of product ids. 
</del><ins>+In addition to the parameters below, this method also accepts the
+standard L&lt;include_fields|Bugzilla::WebService/include_fields&gt; and
+L&lt;exclude_fields|Bugzilla::WebService/exclude_fields&gt; arguments.
</ins><span class="cx"> 
</span><ins>+=over
+
+=item C&lt;ids&gt;
+
+An array of product ids
+
+=item C&lt;names&gt;
+
+An array of product names
+
+=back
+
</ins><span class="cx"> =item B&lt;Returns&gt; 
</span><span class="cx"> 
</span><span class="cx"> A hash containing one item, C&lt;products&gt;, that is an array of
</span><span class="cx"> hashes. Each hash describes a product, and has the following items:
</span><del>-C&lt;id&gt;, C&lt;name&gt;, C&lt;description&gt;, and C&lt;internals&gt;. The C&lt;id&gt; item is
-the id of the product. The C&lt;name&gt; item is the name of the
-product. The C&lt;description&gt; is the description of the
-product. Finally, the C&lt;internals&gt; is an internal representation of
-the product.
</del><span class="cx"> 
</span><ins>+=over
+
+=item C&lt;id&gt;
+
+C&lt;int&gt; An integer id uniquely identifying the product in this installation only.
+
+=item C&lt;name&gt;
+
+C&lt;string&gt; The name of the product.  This is a unique identifier for the
+product.
+
+=item C&lt;description&gt;
+
+C&lt;string&gt; A description of the product, which may contain HTML.
+
+=item C&lt;is_active&gt;
+
+C&lt;boolean&gt; A boolean indicating if the product is active.
+
+=item C&lt;default_milestone&gt;
+
+C&lt;string&gt; The name of the default milestone for the product.
+
+=item C&lt;has_unconfirmed&gt;
+
+C&lt;boolean&gt; Indicates whether the UNCONFIRMED bug status is available
+for this product.
+
+=item C&lt;classification&gt;
+
+C&lt;string&gt; The classification name for the product.
+
+=item C&lt;components&gt;
+
+C&lt;array&gt; An array of hashes, where each hash describes a component, and has the
+following items:
+
+=over
+
+=item C&lt;id&gt;
+
+C&lt;int&gt; An integer id uniquely identifying the component in this installation
+only.
+
+=item C&lt;name&gt;
+
+C&lt;string&gt; The name of the component.  This is a unique identifier for this
+component.
+
+=item C&lt;description&gt;
+
+C&lt;string&gt; A description of the component, which may contain HTML.
+
+=item C&lt;default_assigned_to&gt;
+
+C&lt;string&gt; The login name of the user to whom new bugs will be assigned by
+default.
+
+=item C&lt;default_qa_contact&gt;
+
+C&lt;string&gt; The login name of the user who will be set as the QA Contact for
+new bugs by default.
+
+=item C&lt;sort_key&gt;
+
+C&lt;int&gt; Components, when displayed in a list, are sorted first by this integer
+and then secondly by their name.
+
+=item C&lt;is_active&gt;
+
+C&lt;boolean&gt; A boolean indicating if the component is active.  Inactive
+components are not enabled for new bugs.
+
+=back
+
+=item C&lt;versions&gt;
+
+C&lt;array&gt; An array of hashes, where each hash describes a version, and has the
+following items: C&lt;name&gt;, C&lt;sort_key&gt; and C&lt;is_active&gt;.
+
+=item C&lt;milestones&gt;
+
+C&lt;array&gt; An array of hashes, where each hash describes a milestone, and has the
+following items: C&lt;name&gt;, C&lt;sort_key&gt; and C&lt;is_active&gt;.
+
+=back
+
</ins><span class="cx"> Note, that if the user tries to access a product that is not in the
</span><span class="cx"> list of accessible products for the user, or a product that does not
</span><span class="cx"> exist, that is silently ignored, and no information about that product
</span><span class="lines">@@ -192,7 +421,112 @@
</span><span class="cx"> 
</span><span class="cx"> =item B&lt;Errors&gt; (none)
</span><span class="cx"> 
</span><ins>+=item B&lt;History&gt;
+
+=over
+
+=item In Bugzilla B&lt;4.2&gt;, C&lt;names&gt; was added as an input parameter.
+
+=item In Bugzilla B&lt;4.2&gt;, C&lt;classification&gt;, C&lt;components&gt;, C&lt;versions&gt;,
+C&lt;milestones&gt;, C&lt;default_milestone&gt; and C&lt;has_unconfirmed&gt; were added to
+the fields returned by C&lt;get&gt; as a replacement for C&lt;internals&gt;, which has
+been removed.
+
</ins><span class="cx"> =back
</span><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><ins>+=head1 Product Creation
+
+=head2 create
+
+B&lt;EXPERIMENTAL&gt;
+
+=over
+
+=item B&lt;Description&gt;
+
+This allows you to create a new product in Bugzilla.
+
+=item B&lt;Params&gt; 
+
+Some params must be set, or an error will be thrown. These params are 
+marked B&lt;Required&gt;.
+
+=over
+
+=item C&lt;name&gt;
+
+B&lt;Required&gt; C&lt;string&gt; The name of this product. Must be globally unique
+within Bugzilla.
+
+=item C&lt;description&gt;
+
+B&lt;Required&gt; C&lt;string&gt; A description for this product. Allows some simple HTML.
+
+=item C&lt;version&gt; 
+
+B&lt;Required&gt; C&lt;string&gt; The default version for this product.
+
+=item C&lt;has_unconfirmed&gt; 
+
+C&lt;boolean&gt; Allow the UNCONFIRMED status to be set on bugs in this product.
+Default: true.
+
+=item C&lt;classification&gt;
+
+C&lt;string&gt; The name of the Classification which contains this product.
+
+=item C&lt;default_milestone&gt; 
+
+C&lt;string&gt; The default milestone for this product. Default: '---'.
+
+=item C&lt;is_open&gt; 
+
+C&lt;boolean&gt; True if the product is currently allowing bugs to be entered
+into it. Default: true.
+
+=item C&lt;create_series&gt;
+
+C&lt;boolean&gt; True if you want series for New Charts to be created for this
+new product. Default: true.
+
+=back
+
+=item B&lt;Returns&gt;    
+
+A hash with one element, id. This is the id of the newly-filed product.
+
+=item B&lt;Errors&gt;
+
+=over
+
+=item 51 (Classification does not exist)
+
+You must specify an existing classification name.
+
+=item 700 (Product blank name)
+
+You must specify a non-blank name for this product.
+
+=item 701 (Product name too long)
+
+The name specified for this product was longer than the maximum
+allowed length.
+
+=item 702 (Product name already exists)
+
+You specified the name of a product that already exists.
+(Product names must be globally unique in Bugzilla.)
+
+=item 703 (Product must have description)
+
+You must specify a description for this product.
+
+=item 704 (Product must have version)
+
+You must specify a version for this product.
+
+=back
+
+=back
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaWebServiceREADME"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/WebService/README (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/WebService/README                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/WebService/README        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,18 @@
</span><ins>+The class structure of these files is a little strange, and this README
+explains it.
+
+Our goal is to make JSON::RPC and XMLRPC::Lite both work with the same code.
+(That is, we want to have one WebService API, and have two frontends for it.)
+
+The problem is that these both pass different things for $self to WebService
+methods.
+
+When XMLRPC::Lite calls a method, $self is the name of the *class* the 
+method is in. For example, if we call Bugzilla.version(), the first argument
+is Bugzilla::WebService::Bugzilla. So in order to have $self
+(our first argument) act correctly in XML-RPC, we make all WebService
+classes use base qw(Bugzilla::WebService). 
+
+When JSON::RPC calls a method, $self is the JSON-RPC *server object*. In other
+words, it's an instance of Bugzilla::WebService::Server::JSONRPC. So we have
+Bugzilla::WebService::Server::JSONRPC inherit from Bugzilla::WebService.
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaWebServiceServerJSONRPCpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Server/JSONRPC.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Server/JSONRPC.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Server/JSONRPC.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,582 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla JSON Webservices Interface.
+#
+# The Initial Developer of the Original Code is the San Jose State
+# University Foundation. Portions created by the Initial Developer
+# are Copyright (C) 2008 the Initial Developer. All Rights Reserved.
+#
+# Contributor(s): 
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+package Bugzilla::WebService::Server::JSONRPC;
+
+use strict;
+use Bugzilla::WebService::Server;
+BEGIN {
+    our @ISA = qw(Bugzilla::WebService::Server);
+
+    if (eval { require JSON::RPC::Server::CGI }) {
+        unshift(@ISA, 'JSON::RPC::Server::CGI');
+    }
+    else {
+        require JSON::RPC::Legacy::Server::CGI;
+        unshift(@ISA, 'JSON::RPC::Legacy::Server::CGI');
+    }
+}
+
+use Bugzilla::Error;
+use Bugzilla::WebService::Constants;
+use Bugzilla::WebService::Util qw(taint_data);
+use Bugzilla::Util qw(correct_urlbase trim disable_utf8);
+
+use HTTP::Message;
+use MIME::Base64 qw(decode_base64 encode_base64);
+
+#####################################
+# Public JSON::RPC Method Overrides #
+#####################################
+
+sub new {
+    my $class = shift;
+    my $self = $class-&gt;SUPER::new(@_);
+    Bugzilla-&gt;_json_server($self);
+    $self-&gt;dispatch(WS_DISPATCH);
+    $self-&gt;return_die_message(1);
+    return $self;
+}
+
+sub create_json_coder {
+    my $self = shift;
+    my $json = $self-&gt;SUPER::create_json_coder(@_);
+    $json-&gt;allow_blessed(1);
+    $json-&gt;convert_blessed(1);
+    # This may seem a little backwards, but what this really means is
+    # &quot;don't convert our utf8 into byte strings, just leave it as a
+    # utf8 string.&quot;
+    $json-&gt;utf8(0) if Bugzilla-&gt;params-&gt;{'utf8'};
+    return $json;
+}
+
+# Override the JSON::RPC method to return our CGI object instead of theirs.
+sub cgi { return Bugzilla-&gt;cgi; }
+
+sub response_header {
+    my $self = shift;
+    # The HTTP body needs to be bytes (not a utf8 string) for recent
+    # versions of HTTP::Message, but JSON::RPC::Server doesn't handle this
+    # properly. $_[1] is the HTTP body content we're going to be sending.
+    if (utf8::is_utf8($_[1])) {
+        utf8::encode($_[1]);
+        # Since we're going to just be sending raw bytes, we need to
+        # set STDOUT to not expect utf8.
+        disable_utf8();
+    }
+    return $self-&gt;SUPER::response_header(@_);
+}
+
+sub response {
+    my ($self, $response) = @_;
+
+    # Implement JSONP.
+    if (my $callback = $self-&gt;_bz_callback) {
+        my $content = $response-&gt;content;
+        $response-&gt;content(&quot;$callback($content)&quot;);
+
+    }
+
+    # Use $cgi-&gt;header properly instead of just printing text directly.
+    # This fixes various problems, including sending Bugzilla's cookies
+    # properly.
+    my $headers = $response-&gt;headers;
+    my @header_args;
+    foreach my $name ($headers-&gt;header_field_names) {
+        my @values = $headers-&gt;header($name);
+        $name =~ s/-/_/g;
+        foreach my $value (@values) {
+            push(@header_args, &quot;-$name&quot;, $value);
+        }
+    }
+    my $cgi = $self-&gt;cgi;
+    print $cgi-&gt;header(-status =&gt; $response-&gt;code, @header_args);
+    print $response-&gt;content;
+}
+
+# The JSON-RPC 1.1 GET specification is not so great--you can't specify
+# data structures as parameters. However, the JSON-RPC 2.0 &quot;JSON-RPC over
+# HTTP&quot; spec is excellent, so we are using that for GET requests, instead.
+# Spec: http://groups.google.com/group/json-rpc/web/json-rpc-over-http
+#
+# The one exception is that we don't require the &quot;params&quot; argument to be
+# Base64 encoded, because that is ridiculous and obnoxious for JavaScript
+# clients.
+sub retrieve_json_from_get {
+    my $self = shift;
+    my $cgi = $self-&gt;cgi;
+
+    my %input;
+
+    # Both version and id must be set before any errors are thrown.
+    if ($cgi-&gt;param('version')) {
+        $self-&gt;version(scalar $cgi-&gt;param('version'));
+        $input{version} = $cgi-&gt;param('version');
+    }
+    else {
+        $self-&gt;version('1.0');
+    }
+
+    # The JSON-RPC 2.0 spec says that any request that omits an id doesn't
+    # want a response. However, in an HTTP GET situation, it's stupid to
+    # expect all clients to specify some id parameter just to get a response,
+    # so we don't require it.
+    my $id;
+    if (defined $cgi-&gt;param('id')) {
+        $id = $cgi-&gt;param('id');
+    }
+    # However, JSON::RPC does require that an id exist in most cases, in
+    # order to throw proper errors. We use the installation's urlbase as
+    # the id, in this case.
+    else {
+        $id = correct_urlbase();
+    }
+    # Setting _bz_request_id here is required in case we throw errors early,
+    # before _handle.
+    $self-&gt;{_bz_request_id} = $input{id} = $id;
+
+    # _bz_callback can throw an error, so we have to set it here, after we're
+    # ready to throw errors.
+    $self-&gt;_bz_callback(scalar $cgi-&gt;param('callback'));
+
+    if (!$cgi-&gt;param('method')) {
+        ThrowUserError('json_rpc_get_method_required');
+    }
+    $input{method} = $cgi-&gt;param('method');
+
+    my $params;
+    if (defined $cgi-&gt;param('params')) {
+        local $@;
+        $params = eval { 
+            $self-&gt;json-&gt;decode(scalar $cgi-&gt;param('params')) 
+        };
+        if ($@) {
+            ThrowUserError('json_rpc_invalid_params',
+                           { params =&gt; scalar $cgi-&gt;param('params'),
+                             err_msg  =&gt; $@ });
+        }
+    }
+    elsif (!$self-&gt;version or $self-&gt;version ne '1.1') {
+        $params = [];
+    }
+    else {
+        $params = {};
+    }
+
+    $input{params} = $params;
+
+    my $json = $self-&gt;json-&gt;encode(\%input);
+    return $json;
+}
+
+#######################################
+# Bugzilla::WebService Implementation #
+#######################################
+
+sub type {
+    my ($self, $type, $value) = @_;
+    
+    # This is the only type that does something special with undef.
+    if ($type eq 'boolean') {
+        return $value ? JSON::true : JSON::false;
+    }
+    
+    return JSON::null if !defined $value;
+
+    my $retval = $value;
+
+    if ($type eq 'int') {
+        $retval = int($value);
+    }
+    if ($type eq 'double') {
+        $retval = 0.0 + $value;
+    }
+    elsif ($type eq 'string') {
+        # Forces string context, so that JSON will make it a string.
+        $retval = &quot;$value&quot;;
+    }
+    elsif ($type eq 'dateTime') {
+        # ISO-8601 &quot;YYYYMMDDTHH:MM:SS&quot; with a literal T
+        $retval = $self-&gt;datetime_format_outbound($value);
+    }
+    elsif ($type eq 'base64') {
+        utf8::encode($value) if utf8::is_utf8($value);
+        $retval = encode_base64($value, '');
+    }
+
+    return $retval;
+}
+
+sub datetime_format_outbound {
+    my $self = shift;
+    # YUI expects ISO8601 in UTC time; including TZ specifier
+    return $self-&gt;SUPER::datetime_format_outbound(@_) . 'Z';
+}
+
+sub handle_login {
+    my $self = shift;
+
+    # If we're being called using GET, we don't allow cookie-based or Env
+    # login, because GET requests can be done cross-domain, and we don't
+    # want private data showing up on another site unless the user
+    # explicitly gives that site their username and password. (This is
+    # particularly important for JSONP, which would allow a remote site
+    # to use private data without the user's knowledge, unless we had this
+    # protection in place.)
+    if ($self-&gt;request-&gt;method ne 'POST') {
+        # XXX There's no particularly good way for us to get a parameter
+        # to Bugzilla-&gt;login at this point, so we pass this information
+        # around using request_cache, which is a bit of a hack. The
+        # implementation of it is in Bugzilla::Auth::Login::Stack.
+        Bugzilla-&gt;request_cache-&gt;{auth_no_automatic_login} = 1;
+    }
+
+    my $path = $self-&gt;path_info;
+    my $class = $self-&gt;{dispatch_path}-&gt;{$path};
+    my $full_method = $self-&gt;_bz_method_name;
+    $full_method =~ /^\S+\.(\S+)/;
+    my $method = $1;
+    $self-&gt;SUPER::handle_login($class, $method, $full_method);
+}
+
+######################################
+# Private JSON::RPC Method Overrides #
+######################################
+
+# Store the ID of the current call, because Bugzilla::Error will need it.
+sub _handle {
+    my $self = shift;
+    my ($obj) = @_;
+    $self-&gt;{_bz_request_id} = $obj-&gt;{id};
+    return $self-&gt;SUPER::_handle(@_);
+}
+
+# Make all error messages returned by JSON::RPC go into the 100000
+# range, and bring down all our errors into the normal range.
+sub _error {
+    my ($self, $id, $code) = (shift, shift, shift);
+    # All JSON::RPC errors are less than 1000.
+    if ($code &lt; 1000) {
+        $code += 100000;
+    }
+    # Bugzilla::Error adds 100,000 to all *our* errors, so
+    # we know they came from us.
+    elsif ($code &gt; 100000) {
+        $code -= 100000;
+    }
+
+    # We can't just set $_[1] because it's not always settable,
+    # in JSON::RPC::Server.
+    unshift(@_, $id, $code);
+    my $json = $self-&gt;SUPER::_error(@_);
+
+    # We want to always send the JSON-RPC 1.1 error format, although
+    # If we're not in JSON-RPC 1.1, we don't need the silly &quot;name&quot; parameter.
+    if (!$self-&gt;version or $self-&gt;version ne '1.1') {
+        my $object = $self-&gt;json-&gt;decode($json);
+        my $message = $object-&gt;{error};
+        # Just assure that future versions of JSON::RPC don't change the
+        # JSON-RPC 1.0 error format.
+        if (!ref $message) {
+            $object-&gt;{error} = {
+                code    =&gt; $code,
+                message =&gt; $message,
+            };
+            $json = $self-&gt;json-&gt;encode($object);
+        }
+    }
+    return $json;
+}
+
+# This handles dispatching our calls to the appropriate class based on
+# the name of the method.
+sub _find_procedure {
+    my $self = shift;
+
+    my $method = shift;
+    $self-&gt;{_bz_method_name} = $method;
+
+    # This tricks SUPER::_find_procedure into finding the right class.
+    $method =~ /^(\S+)\.(\S+)$/;
+    $self-&gt;path_info($1);
+    unshift(@_, $2);
+
+    return $self-&gt;SUPER::_find_procedure(@_);
+}
+
+# This is a hacky way to do something right before methods are called.
+# This is the last thing that JSON::RPC::Server::_handle calls right before
+# the method is actually called.
+sub _argument_type_check {
+    my $self = shift;
+    my $params = $self-&gt;SUPER::_argument_type_check(@_);
+
+    # JSON-RPC 1.0 requires all parameters to be passed as an array, so
+    # we just pull out the first item and assume it's an object.
+    my $params_is_array;
+    if (ref $params eq 'ARRAY') {
+        $params = $params-&gt;[0];
+        $params_is_array = 1;
+    }
+
+    taint_data($params);
+
+    # Now, convert dateTime fields on input.
+    $self-&gt;_bz_method_name =~ /^(\S+)\.(\S+)$/;
+    my ($class, $method) = ($1, $2);
+    my $pkg = $self-&gt;{dispatch_path}-&gt;{$class};
+    my @date_fields = @{ $pkg-&gt;DATE_FIELDS-&gt;{$method} || [] };
+    foreach my $field (@date_fields) {
+        if (defined $params-&gt;{$field}) {
+            my $value = $params-&gt;{$field};
+            if (ref $value eq 'ARRAY') {
+                $params-&gt;{$field} = 
+                    [ map { $self-&gt;datetime_format_inbound($_) } @$value ];
+            }
+            else {
+                $params-&gt;{$field} = $self-&gt;datetime_format_inbound($value);
+            }
+        }
+    }
+    my @base64_fields = @{ $pkg-&gt;BASE64_FIELDS-&gt;{$method} || [] };
+    foreach my $field (@base64_fields) {
+        if (defined $params-&gt;{$field}) {
+            $params-&gt;{$field} = decode_base64($params-&gt;{$field});
+        }
+    }
+
+    Bugzilla-&gt;input_params($params);
+
+    if ($self-&gt;request-&gt;method eq 'POST') {
+        # CSRF is possible via XMLHttpRequest when the Content-Type header
+        # is not application/json (for example: text/plain or
+        # application/x-www-form-urlencoded).
+        # application/json is the single official MIME type, per RFC 4627.
+        my $content_type = $self-&gt;cgi-&gt;content_type;
+        # The charset can be appended to the content type, so we use a regexp.
+        if ($content_type !~ m{^application/json(-rpc)?(;.*)?$}i) {
+            ThrowUserError('json_rpc_illegal_content_type',
+                            { content_type =&gt; $content_type });
+        }
+    }
+    else {
+        # When being called using GET, we don't allow calling
+        # methods that can change data. This protects us against cross-site
+        # request forgeries.
+        if (!grep($_ eq $method, $pkg-&gt;READ_ONLY)) {
+            ThrowUserError('json_rpc_post_only', 
+                           { method =&gt; $self-&gt;_bz_method_name });
+        }
+    }
+
+    # This is the best time to do login checks.
+    $self-&gt;handle_login();
+
+    # Bugzilla::WebService packages call internal methods like
+    # $self-&gt;_some_private_method. So we have to inherit from 
+    # that class as well as this Server class.
+    my $new_class = ref($self) . '::' . $pkg;
+    my $isa_string = 'our @ISA = qw(' . ref($self) . &quot; $pkg)&quot;;
+    eval &quot;package $new_class;$isa_string;&quot;;
+    bless $self, $new_class;
+
+    if ($params_is_array) {
+        $params = [$params];
+    }
+
+    return $params;
+}
+
+##########################
+# Private Custom Methods #
+##########################
+
+# _bz_method_name is stored by _find_procedure for later use.
+sub _bz_method_name {
+    return $_[0]-&gt;{_bz_method_name}; 
+}
+
+sub _bz_callback {
+    my ($self, $value) = @_;
+    if (defined $value) {
+        $value = trim($value);
+        # We don't use \w because we don't want to allow Unicode here.
+        if ($value !~ /^[A-Za-z0-9_\.\[\]]+$/) {
+            ThrowUserError('json_rpc_invalid_callback', { callback =&gt; $value });
+        }
+        $self-&gt;{_bz_callback} = $value;
+        # JSONP needs to be parsed by a JS parser, not by a JSON parser.
+        $self-&gt;content_type('text/javascript');
+    }
+    return $self-&gt;{_bz_callback};
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::WebService::Server::JSONRPC - The JSON-RPC Interface to Bugzilla
+
+=head1 DESCRIPTION
+
+This documentation describes things about the Bugzilla WebService that
+are specific to JSON-RPC. For a general overview of the Bugzilla WebServices,
+see L&lt;Bugzilla::WebService&gt;.
+
+Please note that I&lt;everything&gt; about this JSON-RPC interface is
+B&lt;EXPERIMENTAL&gt;. If you want a fully stable API, please use the
+C&lt;Bugzilla::WebService::Server::XMLRPC|XML-RPC&gt; interface.
+
+=head1 JSON-RPC
+
+Bugzilla supports both JSON-RPC 1.0 and 1.1. We recommend that you use
+JSON-RPC 1.0 instead of 1.1, though, because 1.1 is deprecated.
+
+At some point in the future, Bugzilla may also support JSON-RPC 2.0.
+
+The JSON-RPC standards are described at L&lt;http://json-rpc.org/&gt;.
+
+=head1 CONNECTING
+
+The endpoint for the JSON-RPC interface is the C&lt;jsonrpc.cgi&gt; script in
+your Bugzilla installation. For example, if your Bugzilla is at
+C&lt;bugzilla.yourdomain.com&gt;, then your JSON-RPC client would access the
+API via: C&lt;http://bugzilla.yourdomain.com/jsonrpc.cgi&gt;
+
+=head2 Connecting via GET
+
+The most powerful way to access the JSON-RPC interface is by HTTP POST.
+However, for convenience, you can also access certain methods by using GET
+(a normal webpage load). Methods that modify the database or cause some
+action to happen in Bugzilla cannot be called over GET. Only methods that
+simply return data can be used over GET.
+
+For security reasons, when you connect over GET, cookie authentication
+is not accepted. If you want to authenticate using GET, you have to
+use the C&lt;Bugzilla_login&gt; and C&lt;Bugzilla_password&gt; method described at
+L&lt;Bugzilla::WebService/LOGGING IN&gt;.
+
+To connect over GET, simply send the values that you'd normally send for
+each JSON-RPC argument as URL parameters, with the C&lt;params&gt; item being
+a JSON string. 
+
+The simplest example is a call to C&lt;Bugzilla.time&gt;:
+
+ jsonrpc.cgi?method=Bugzilla.time
+
+Here's a call to C&lt;User.get&gt;, with several parameters:
+
+ jsonrpc.cgi?method=User.get&amp;params=[ { &quot;ids&quot;: [1,2], &quot;names&quot;: [&quot;user@domain.com&quot;] } ]
+
+Although in reality you would url-encode the C&lt;params&gt; argument, so it would
+look more like this:
+
+ jsonrpc.cgi?method=User.get&amp;params=%5B+%7B+%22ids%22%3A+%5B1%2C2%5D%2C+%22names%22%3A+%5B%22user%40domain.com%22%5D+%7D+%5D
+
+You can also specify C&lt;version&gt; as a URL parameter, if you want to specify
+what version of the JSON-RPC protocol you're using, and C&lt;id&gt; as a URL
+parameter if you want there to be a specific C&lt;id&gt; value in the returned
+JSON-RPC response.
+
+=head2 JSONP
+
+When calling the JSON-RPC WebService over GET, you can use the &quot;JSONP&quot;
+method of doing cross-domain requests, if you want to access the WebService
+directly on a web page from another site. JSONP is described at
+L&lt;http://bob.pythonmac.org/archives/2005/12/05/remote-json-jsonp/&gt;.
+
+To use JSONP with Bugzilla's JSON-RPC WebService, simply specify a
+C&lt;callback&gt; parameter to jsonrpc.cgi when using it via GET as described above.
+For example, here's some HTML you could use to get the data from 
+C&lt;Bugzilla.time&gt; on a remote website, using JSONP:
+
+ &lt;script type=&quot;text/javascript&quot; 
+         src=&quot;http://bugzilla.example.com/jsonrpc.cgi?method=Bugzilla.time&amp;amp;callback=foo&quot;&gt;
+
+That would call the C&lt;Bugzilla.time&gt; method and pass its value to a function
+called C&lt;foo&gt; as the only argument. All the other URL parameters (such as
+C&lt;params&gt;, for passing in arguments to methods) that can be passed to
+C&lt;jsonrpc.cgi&gt; during GET requests are also available, of course. The above
+is just the simplest possible example.
+
+The values returned when using JSONP are identical to the values returned
+when not using JSONP, so you will also get error messages if there is an
+error.
+
+The C&lt;callback&gt; URL parameter may only contain letters, numbers, periods, and
+the underscore (C&lt;_&gt;) character. Including any other characters will cause
+Bugzilla to throw an error. (This error will be a normal JSON-RPC response,
+not JSONP.)
+
+=head1 PARAMETERS
+
+For JSON-RPC 1.0, the very first parameter should be an object containing
+the named parameters. For example, if you were passing two named parameters,
+one called C&lt;foo&gt; and the other called C&lt;bar&gt;, the C&lt;params&gt; element of
+your JSON-RPC call would look like:
+
+ &quot;params&quot;: [{ &quot;foo&quot;: 1, &quot;bar&quot;: &quot;something&quot; }]
+
+For JSON-RPC 1.1, you can pass parameters either in the above fashion
+or using the standard named-parameters mechanism of JSON-RPC 1.1.
+
+C&lt;dateTime&gt; fields are strings in the standard ISO-8601 format:
+C&lt;YYYY-MM-DDTHH:MM:SSZ&gt;, where C&lt;T&gt; and C&lt;Z&gt; are a literal T and Z,
+respectively. The &quot;Z&quot; means that all times are in UTC timezone--times are
+always returned in UTC, and should be passed in as UTC. (Note: The JSON-RPC
+interface currently also accepts non-UTC times for any values passed in, if
+they include a time-zone specifier that follows the ISO-8601 standard, instead
+of &quot;Z&quot; at the end. This behavior is expected to continue into the future, but
+to be fully safe for forward-compatibility with all future versions of
+Bugzilla, it is safest to pass in all times as UTC with the &quot;Z&quot; timezone
+specifier.)
+
+C&lt;base64&gt; fields are strings that have been base64 encoded. Note that
+although normal base64 encoding includes newlines to break up the data,
+newlines within a string are not valid JSON, so you should not insert
+newlines into your base64-encoded string.
+
+All other types are standard JSON types.
+
+=head1 ERRORS
+
+JSON-RPC 1.0 and JSON-RPC 1.1 both return an C&lt;error&gt; element when they
+throw an error. In Bugzilla, the error contents look like:
+
+ { message: 'Some message here', code: 123 }
+
+So, for example, in JSON-RPC 1.0, an error response would look like:
+
+ { 
+   result: null, 
+   error: { message: 'Some message here', code: 123 }, 
+   id: 1
+ }
+
+Every error has a &quot;code&quot;, as described in L&lt;Bugzilla::WebService/ERRORS&gt;.
+Errors with a numeric C&lt;code&gt; higher than 100000 are errors thrown by
+the JSON-RPC library that Bugzilla uses, not by Bugzilla.
+
+=head1 SEE ALSO
+
+L&lt;Bugzilla::WebService&gt;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaWebServiceServerXMLRPCpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Server/XMLRPC.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Server/XMLRPC.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Server/XMLRPC.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,376 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# Contributor(s): Marc Schumann &lt;wurblzap@gmail.com&gt;
+#                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+#                 Rosie Clarkson &lt;rosie.clarkson@planningportal.gov.uk&gt;
+#                 
+# Portions Â© Crown copyright 2009 - Rosie Clarkson (development@planningportal.gov.uk) for the Planning Portal
+
+package Bugzilla::WebService::Server::XMLRPC;
+
+use strict;
+use XMLRPC::Transport::HTTP;
+use Bugzilla::WebService::Server;
+if ($ENV{MOD_PERL}) {
+    our @ISA = qw(XMLRPC::Transport::HTTP::Apache Bugzilla::WebService::Server);
+} else {
+    our @ISA = qw(XMLRPC::Transport::HTTP::CGI Bugzilla::WebService::Server);
+}
+
+use Bugzilla::WebService::Constants;
+
+# Allow WebService methods to call XMLRPC::Lite's type method directly
+BEGIN {
+    *Bugzilla::WebService::type = sub {
+        my ($self, $type, $value) = @_;
+        if ($type eq 'dateTime') {
+            # This is the XML-RPC implementation,  see the README in Bugzilla/WebService/.
+            # Our &quot;base&quot; implementation is in Bugzilla::WebService::Server.
+            $value = Bugzilla::WebService::Server-&gt;datetime_format_outbound($value);
+            $value =~ s/-//g;
+        }
+        return XMLRPC::Data-&gt;type($type)-&gt;value($value);
+    };
+}
+
+sub initialize {
+    my $self = shift;
+    my %retval = $self-&gt;SUPER::initialize(@_);
+    $retval{'serializer'}   = Bugzilla::XMLRPC::Serializer-&gt;new;
+    $retval{'deserializer'} = Bugzilla::XMLRPC::Deserializer-&gt;new;
+    $retval{'dispatch_with'} = WS_DISPATCH;
+    return %retval;
+}
+
+sub make_response {
+    my $self = shift;
+
+    $self-&gt;SUPER::make_response(@_);
+
+    # XMLRPC::Transport::HTTP::CGI doesn't know about Bugzilla carrying around
+    # its cookies in Bugzilla::CGI, so we need to copy them over.
+    foreach (@{Bugzilla-&gt;cgi-&gt;{'Bugzilla_cookie_list'}}) {
+        $self-&gt;response-&gt;headers-&gt;push_header('Set-Cookie', $_);
+    }
+}
+
+sub handle_login {
+    my ($self, $classes, $action, $uri, $method) = @_;
+    my $class = $classes-&gt;{$uri};
+    my $full_method = $uri . &quot;.&quot; . $method;
+    $self-&gt;SUPER::handle_login($class, $method, $full_method);
+    return;
+}
+
+1;
+
+# This exists to validate input parameters (which XMLRPC::Lite doesn't do)
+# and also, in some cases, to more-usefully decode them.
+package Bugzilla::XMLRPC::Deserializer;
+use strict;
+# We can't use &quot;use base&quot; because XMLRPC::Serializer doesn't return
+# a true value.
+use XMLRPC::Lite;
+our @ISA = qw(XMLRPC::Deserializer);
+
+use Bugzilla::Error;
+use Bugzilla::WebService::Constants qw(XMLRPC_CONTENT_TYPE_WHITELIST);
+use Scalar::Util qw(tainted);
+
+sub deserialize {
+    my $self = shift;
+
+    # Only allow certain content types to protect against CSRF attacks
+    my $content_type = lc($ENV{'CONTENT_TYPE'});
+    # Remove charset, etc, if provided
+    $content_type =~ s/^([^;]+);.*/$1/;
+    if (!grep($_ eq $content_type, XMLRPC_CONTENT_TYPE_WHITELIST)) {
+        ThrowUserError('xmlrpc_illegal_content_type',
+                       { content_type =&gt; $ENV{'CONTENT_TYPE'} });
+    }
+
+    my ($xml) = @_;
+    my $som = $self-&gt;SUPER::deserialize(@_);
+    if (tainted($xml)) {
+        $som-&gt;{_bz_do_taint} = 1;
+    }
+    bless $som, 'Bugzilla::XMLRPC::SOM';
+    my $params = $som-&gt;paramsin;
+    # This allows positional parameters for Testopia.
+    $params = {} if ref $params ne 'HASH';
+    Bugzilla-&gt;input_params($params);
+    return $som;
+}
+
+# Some method arguments need to be converted in some way, when they are input.
+sub decode_value {
+    my $self = shift;
+    my ($type) = @{ $_[0] };
+    my $value = $self-&gt;SUPER::decode_value(@_);
+    
+    # We only validate/convert certain types here.
+    return $value if $type !~ /^(?:int|i4|boolean|double|dateTime\.iso8601)$/;
+    
+    # Though the XML-RPC standard doesn't allow an empty &lt;int&gt;,
+    # &lt;double&gt;,or &lt;dateTime.iso8601&gt;,  we do, and we just say
+    # &quot;that's undef&quot;.
+    if (grep($type eq $_, qw(int double dateTime))) {
+        return undef if $value eq '';
+    }
+    
+    my $validator = $self-&gt;_validation_subs-&gt;{$type};
+    if (!$validator-&gt;($value)) {
+        ThrowUserError('xmlrpc_invalid_value',
+                       { type =&gt; $type, value =&gt; $value });
+    }
+    
+    # We convert dateTimes to a DB-friendly date format.
+    if ($type eq 'dateTime.iso8601') {
+        if ($value !~ /T.*[\-+Z]/i) {
+           # The caller did not specify a timezone, so we assume UTC.
+           # pass 'Z' specifier to datetime_from to force it
+           $value = $value . 'Z';
+        }
+        $value = Bugzilla::WebService::Server::XMLRPC-&gt;datetime_format_inbound($value);
+    }
+
+    return $value;
+}
+
+sub _validation_subs {
+    my $self = shift;
+    return $self-&gt;{_validation_subs} if $self-&gt;{_validation_subs};
+    # The only place that XMLRPC::Lite stores any sort of validation
+    # regex is in XMLRPC::Serializer. We want to re-use those regexes here.
+    my $lookup = Bugzilla::XMLRPC::Serializer-&gt;new-&gt;typelookup;
+    
+    # $lookup is a hash whose values are arrayrefs, and whose keys are the
+    # names of types. The second item of each arrayref is a subroutine
+    # that will do our validation for us.
+    my %validators = map { $_ =&gt; $lookup-&gt;{$_}-&gt;[1] } (keys %$lookup);
+    # Add a boolean validator
+    $validators{'boolean'} = sub {$_[0] =~ /^[01]$/};
+    # Some types have multiple names, or have a different name in
+    # XMLRPC::Serializer than their standard XML-RPC name.
+    $validators{'dateTime.iso8601'} = $validators{'dateTime'};
+    $validators{'i4'} = $validators{'int'};
+    
+    $self-&gt;{_validation_subs} = \%validators;
+    return \%validators;
+}
+
+1;
+
+package Bugzilla::XMLRPC::SOM;
+use strict;
+use XMLRPC::Lite;
+our @ISA = qw(XMLRPC::SOM);
+use Bugzilla::WebService::Util qw(taint_data);
+
+sub paramsin {
+    my $self = shift;
+    if (!$self-&gt;{bz_params_in}) {
+        my @params = $self-&gt;SUPER::paramsin(@_); 
+        if ($self-&gt;{_bz_do_taint}) {
+            taint_data(@params);
+        }
+        $self-&gt;{bz_params_in} = \@params;
+    }
+    my $params = $self-&gt;{bz_params_in};
+    return wantarray ? @$params : $params-&gt;[0];
+}
+
+1;
+
+# This package exists to fix a UTF-8 bug in SOAP::Lite.
+# See http://rt.cpan.org/Public/Bug/Display.html?id=32952.
+package Bugzilla::XMLRPC::Serializer;
+use Scalar::Util qw(blessed);
+use strict;
+# We can't use &quot;use base&quot; because XMLRPC::Serializer doesn't return
+# a true value.
+use XMLRPC::Lite;
+our @ISA = qw(XMLRPC::Serializer);
+
+sub new {
+    my $class = shift;
+    my $self = $class-&gt;SUPER::new(@_);
+    # This fixes UTF-8.
+    $self-&gt;{'_typelookup'}-&gt;{'base64'} =
+        [10, sub { !utf8::is_utf8($_[0]) &amp;&amp; $_[0] =~ /[^\x09\x0a\x0d\x20-\x7f]/},
+        'as_base64'];
+    # This makes arrays work right even though we're a subclass.
+    # (See http://rt.cpan.org//Ticket/Display.html?id=34514)
+    $self-&gt;{'_encodingStyle'} = '';
+    return $self;
+}
+
+# Here the XMLRPC::Serializer is extended to use the XMLRPC nil extension.
+sub encode_object {
+    my $self = shift;
+    my @encoded = $self-&gt;SUPER::encode_object(@_);
+
+    return $encoded[0]-&gt;[0] eq 'nil'
+        ? ['value', {}, [@encoded]]
+        : @encoded;
+}
+
+# Removes undefined values so they do not produce invalid XMLRPC.
+sub envelope {
+    my $self = shift;
+    my ($type, $method, $data) = @_;
+    # If the type isn't a successful response we don't want to change the values.
+    if ($type eq 'response'){
+        $data = _strip_undefs($data);
+    }
+    return $self-&gt;SUPER::envelope($type, $method, $data);
+}
+
+# In an XMLRPC response we have to handle hashes of arrays, hashes, scalars,
+# Bugzilla objects (reftype = 'HASH') and XMLRPC::Data objects.
+# The whole XMLRPC::Data object must be removed if its value key is undefined
+# so it cannot be recursed like the other hash type objects.
+sub _strip_undefs {
+    my ($initial) = @_;
+    if (ref $initial eq &quot;HASH&quot; || (blessed $initial &amp;&amp; $initial-&gt;isa(&quot;HASH&quot;))) {
+        while (my ($key, $value) = each(%$initial)) {
+            if ( !defined $value
+                 || (blessed $value &amp;&amp; $value-&gt;isa('XMLRPC::Data') &amp;&amp; !defined $value-&gt;value) )
+            {
+                # If the value is undefined remove it from the hash.
+                delete $initial-&gt;{$key};
+            }
+            else {
+                $initial-&gt;{$key} = _strip_undefs($value);
+            }
+        }
+    }
+    if (ref $initial eq &quot;ARRAY&quot; || (blessed $initial &amp;&amp; $initial-&gt;isa(&quot;ARRAY&quot;))) {
+        for (my $count = 0; $count &lt; scalar @{$initial}; $count++) {
+            my $value = $initial-&gt;[$count];
+            if ( !defined $value
+                 || (blessed $value &amp;&amp; $value-&gt;isa('XMLRPC::Data') &amp;&amp; !defined $value-&gt;value) )
+            {
+                # If the value is undefined remove it from the array.
+                splice(@$initial, $count, 1);
+                $count--;
+            }
+            else {
+                $initial-&gt;[$count] = _strip_undefs($value);
+            }
+        }
+    }
+    return $initial;
+}
+
+sub BEGIN {
+    no strict 'refs';
+    for my $type (qw(double i4 int dateTime)) {
+        my $method = 'as_' . $type;
+        *$method = sub {
+            my ($self, $value) = @_;
+            if (!defined($value)) {
+                return as_nil();
+            }
+            else {
+                my $super_method = &quot;SUPER::$method&quot;; 
+                return $self-&gt;$super_method($value);
+            }
+        }
+    }
+}
+
+sub as_nil {
+    return ['nil', {}];
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::WebService::Server::XMLRPC - The XML-RPC Interface to Bugzilla
+
+=head1 DESCRIPTION
+
+This documentation describes things about the Bugzilla WebService that
+are specific to XML-RPC. For a general overview of the Bugzilla WebServices,
+see L&lt;Bugzilla::WebService&gt;.
+
+=head1 XML-RPC
+
+The XML-RPC standard is described here: L&lt;http://www.xmlrpc.com/spec&gt;
+
+=head1 CONNECTING
+
+The endpoint for the XML-RPC interface is the C&lt;xmlrpc.cgi&gt; script in
+your Bugzilla installation. For example, if your Bugzilla is at
+C&lt;bugzilla.yourdomain.com&gt;, then your XML-RPC client would access the
+API via: C&lt;http://bugzilla.yourdomain.com/xmlrpc.cgi&gt;
+
+=head1 PARAMETERS
+
+C&lt;dateTime&gt; fields are the standard C&lt;dateTime.iso8601&gt; XML-RPC field. They
+should be in C&lt;YYYY-MM-DDTHH:MM:SS&gt; format (where C&lt;T&gt; is a literal T). As
+of Bugzilla B&lt;3.6&gt;, Bugzilla always expects C&lt;dateTime&gt; fields to be in the
+UTC timezone, and all returned C&lt;dateTime&gt; values are in the UTC timezone.
+
+All other fields are standard XML-RPC types.
+
+=head2 How XML-RPC WebService Methods Take Parameters
+
+All functions take a single argument, a C&lt;&lt; &lt;struct&gt; &gt;&gt; that contains all parameters.
+The names of the parameters listed in the API docs for each function are the
+C&lt;&lt; &lt;name&gt; &gt;&gt; element for the struct C&lt;&lt; &lt;member&gt; &gt;&gt;s.
+
+=head1 EXTENSIONS TO THE XML-RPC STANDARD
+
+=head2 Undefined Values
+
+Normally, XML-RPC does not allow empty values for C&lt;int&gt;, C&lt;double&gt;, or
+C&lt;dateTime.iso8601&gt; fields. Bugzilla does--it treats empty values as
+C&lt;undef&gt; (called C&lt;NULL&gt; or C&lt;None&gt; in some programming languages).
+
+Bugzilla accepts a timezone specifier at the end of C&lt;dateTime.iso8601&gt;
+fields that are specified as method arguments. The format of the timezone
+specifier is specified in the ISO-8601 standard. If no timezone specifier
+is included, the passed-in time is assumed to be in the UTC timezone.
+Bugzilla will never output a timezone specifier on returned data, because
+doing so would violate the XML-RPC specification. All returned times are in
+the UTC timezone.
+
+Bugzilla also accepts an element called C&lt;&lt; &lt;nil&gt; &gt;&gt;, as specified by the
+XML-RPC extension here: L&lt;http://ontosys.com/xml-rpc/extensions.php&gt;, which
+is always considered to be C&lt;undef&gt;, no matter what it contains.
+
+Bugzilla does not use C&lt;&lt; &lt;nil&gt; &gt;&gt; values in returned data, because currently
+most clients do not support C&lt;&lt; &lt;nil&gt; &gt;&gt;. Instead, any fields with C&lt;undef&gt;
+values will be stripped from the response completely. Therefore
+B&lt;the client must handle the fact that some expected fields may not be 
+returned&gt;.
+
+=begin private
+
+nil is implemented by XMLRPC::Lite, in XMLRPC::Deserializer::decode_value
+in the CPAN SVN since 14th Dec 2008
+L&lt;http://rt.cpan.org/Public/Bug/Display.html?id=20569&gt; and in Fedora's
+perl-SOAP-Lite package in versions 0.68-1 and above.
+
+=end private
+
+=head1 SEE ALSO
+
+L&lt;Bugzilla::WebService&gt;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaWebServiceServerpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Server.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Server.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Server.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,63 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# Contributor(s): Marc Schumann &lt;wurblzap@gmail.com&gt;
+#                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+package Bugzilla::WebService::Server;
+use strict;
+
+use Bugzilla::Error;
+use Bugzilla::Util qw(datetime_from);
+
+use Scalar::Util qw(blessed);
+
+sub handle_login {
+    my ($self, $class, $method, $full_method) = @_;
+    eval &quot;require $class&quot;;
+    ThrowCodeError('unknown_method', {method =&gt; $full_method}) if $@;
+    return if ($class-&gt;login_exempt($method) 
+               and !defined Bugzilla-&gt;input_params-&gt;{Bugzilla_login});
+    Bugzilla-&gt;login();
+}
+
+sub datetime_format_inbound {
+    my ($self, $time) = @_;
+    
+    my $converted = datetime_from($time, Bugzilla-&gt;local_timezone);
+    if (!defined $converted) {
+        ThrowUserError('illegal_date', { date =&gt; $time });
+    }
+    $time = $converted-&gt;ymd() . ' ' . $converted-&gt;hms();
+    return $time
+}
+
+sub datetime_format_outbound {
+    my ($self, $date) = @_;
+
+    return undef if (!defined $date or $date eq '');
+
+    my $time = $date;
+    if (blessed($date)) {
+        # We expect this to mean we were sent a datetime object
+        $time-&gt;set_time_zone('UTC');
+    } else {
+        # We always send our time in UTC, for consistency.
+        # passed in value is likely a string, create a datetime object
+        $time = datetime_from($date, 'UTC');
+    }
+    return $time-&gt;iso8601();
+}
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaWebServiceUserpm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/WebService/User.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/WebService/User.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/WebService/User.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -15,20 +15,20 @@
</span><span class="cx"> # Contributor(s): Marc Schumann &lt;wurblzap@gmail.com&gt;
</span><span class="cx"> #                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
</span><span class="cx"> #                 Mads Bondo Dydensborg &lt;mbd@dbc.dk&gt;
</span><ins>+#                 Noura Elhawary &lt;nelhawar@redhat.com&gt;
</ins><span class="cx"> 
</span><span class="cx"> package Bugzilla::WebService::User;
</span><span class="cx"> 
</span><span class="cx"> use strict;
</span><span class="cx"> use base qw(Bugzilla::WebService);
</span><span class="cx"> 
</span><del>-import SOAP::Data qw(type); 
-
</del><span class="cx"> use Bugzilla;
</span><span class="cx"> use Bugzilla::Constants;
</span><span class="cx"> use Bugzilla::Error;
</span><ins>+use Bugzilla::Group;
</ins><span class="cx"> use Bugzilla::User;
</span><span class="cx"> use Bugzilla::Util qw(trim);
</span><del>-use Bugzilla::Token;
</del><ins>+use Bugzilla::WebService::Util qw(filter validate);
</ins><span class="cx"> 
</span><span class="cx"> # Don't need auth to login
</span><span class="cx"> use constant LOGIN_EXEMPT =&gt; {
</span><span class="lines">@@ -36,6 +36,10 @@
</span><span class="cx">     offer_account_by_email =&gt; 1,
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+use constant READ_ONLY =&gt; qw(
+    get
+);
+
</ins><span class="cx"> ##############
</span><span class="cx"> # User Login #
</span><span class="cx"> ##############
</span><span class="lines">@@ -61,13 +65,13 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # Make sure the CGI user info class works if necessary.
</span><del>-    my $cgi = Bugzilla-&gt;cgi;
-    $cgi-&gt;param('Bugzilla_login', $params-&gt;{login});
-    $cgi-&gt;param('Bugzilla_password', $params-&gt;{password});
-    $cgi-&gt;param('Bugzilla_remember', $remember);
</del><ins>+    my $input_params = Bugzilla-&gt;input_params;
+    $input_params-&gt;{'Bugzilla_login'} =  $params-&gt;{login};
+    $input_params-&gt;{'Bugzilla_password'} = $params-&gt;{password};
+    $input_params-&gt;{'Bugzilla_remember'} = $remember;
</ins><span class="cx"> 
</span><del>-    Bugzilla-&gt;login;
-    return { id =&gt; type('int')-&gt;value(Bugzilla-&gt;user-&gt;id) };
</del><ins>+    Bugzilla-&gt;login();
+    return { id =&gt; $self-&gt;type('int', Bugzilla-&gt;user-&gt;id) };
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub logout {
</span><span class="lines">@@ -86,19 +90,8 @@
</span><span class="cx">     my $email = trim($params-&gt;{email})
</span><span class="cx">         || ThrowCodeError('param_required', { param =&gt; 'email' });
</span><span class="cx"> 
</span><del>-    my $createexp = Bugzilla-&gt;params-&gt;{'createemailregexp'};
-    if (!$createexp) {
-        ThrowUserError(&quot;account_creation_disabled&quot;);
-    }
-    elsif ($email !~ /$createexp/) {
-        ThrowUserError(&quot;account_creation_restricted&quot;);
-    }
-
-    $email = Bugzilla::User-&gt;check_login_name_for_creation($email);
-
-    # Create and send a token for this new account.
-    Bugzilla::Token::issue_new_user_account_token($email);
-
</del><ins>+    Bugzilla-&gt;user-&gt;check_account_creation_enabled;
+    Bugzilla-&gt;user-&gt;check_and_send_account_creation_confirmation($email);
</ins><span class="cx">     return undef;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -122,9 +115,144 @@
</span><span class="cx">         cryptpassword =&gt; $password
</span><span class="cx">     });
</span><span class="cx"> 
</span><del>-    return { id =&gt; type('int')-&gt;value($user-&gt;id) };
</del><ins>+    return { id =&gt; $self-&gt;type('int', $user-&gt;id) };
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+
+# function to return user information by passing either user ids or 
+# login names or both together:
+# $call = $rpc-&gt;call( 'User.get', { ids =&gt; [1,2,3], 
+#         names =&gt; ['testusera@redhat.com', 'testuserb@redhat.com'] });
+sub get {
+    my ($self, $params) = validate(@_, 'names', 'ids');
+
+    defined($params-&gt;{names}) || defined($params-&gt;{ids})
+        || defined($params-&gt;{match})
+        || ThrowCodeError('params_required', 
+               { function =&gt; 'User.get', params =&gt; ['ids', 'names', 'match'] });
+
+    my @user_objects;
+    @user_objects = map { Bugzilla::User-&gt;check($_) } @{ $params-&gt;{names} }
+                    if $params-&gt;{names};
+
+    # start filtering to remove duplicate user ids
+    my %unique_users = map { $_-&gt;id =&gt; $_ } @user_objects;
+    @user_objects = values %unique_users;
+      
+    my @users;
+
+    # If the user is not logged in: Return an error if they passed any user ids.
+    # Otherwise, return a limited amount of information based on login names.
+    if (!Bugzilla-&gt;user-&gt;id){
+        if ($params-&gt;{ids}){
+            ThrowUserError(&quot;user_access_by_id_denied&quot;);
+        }
+        if ($params-&gt;{match}) {
+            ThrowUserError('user_access_by_match_denied');
+        }
+        my $in_group = $self-&gt;_filter_users_by_group(
+            \@user_objects, $params);
+        @users = map {filter $params, {
+                     id        =&gt; $self-&gt;type('int', $_-&gt;id),
+                     real_name =&gt; $self-&gt;type('string', $_-&gt;name), 
+                     name      =&gt; $self-&gt;type('string', $_-&gt;login),
+                 }} @$in_group;
+
+        return { users =&gt; \@users };
+    }
+
+    my $obj_by_ids;
+    $obj_by_ids = Bugzilla::User-&gt;new_from_list($params-&gt;{ids}) if $params-&gt;{ids};
+
+    # obj_by_ids are only visible to the user if he can see 
+    # the otheruser, for non visible otheruser throw an error
+    foreach my $obj (@$obj_by_ids) {
+        if (Bugzilla-&gt;user-&gt;can_see_user($obj)){
+            if (!$unique_users{$obj-&gt;id}) {
+                push (@user_objects, $obj);
+                $unique_users{$obj-&gt;id} = $obj;
+            }
+        }
+        else {
+            ThrowUserError('auth_failure', {reason =&gt; &quot;not_visible&quot;,
+                                            action =&gt; &quot;access&quot;,
+                                            object =&gt; &quot;user&quot;,
+                                            userid =&gt; $obj-&gt;id});
+        }
+    }
+    
+    # User Matching
+    my $limit;
+    if ($params-&gt;{'maxusermatches'}) {
+        $limit = $params-&gt;{'maxusermatches'} + 1;
+    }
+    my $exclude_disabled = $params-&gt;{'include_disabled'} ? 0 : 1;
+    foreach my $match_string (@{ $params-&gt;{'match'} || [] }) {
+        my $matched = Bugzilla::User::match($match_string, $limit, $exclude_disabled);
+        foreach my $user (@$matched) {
+            if (!$unique_users{$user-&gt;id}) {
+                push(@user_objects, $user);
+                $unique_users{$user-&gt;id} = $user;
+            }
+        }
+    }
+   
+    my $in_group = $self-&gt;_filter_users_by_group(
+        \@user_objects, $params); 
+    if (Bugzilla-&gt;user-&gt;in_group('editusers')) {
+        @users =
+            map {filter $params, {
+                id        =&gt; $self-&gt;type('int', $_-&gt;id),
+                real_name =&gt; $self-&gt;type('string', $_-&gt;name),
+                name      =&gt; $self-&gt;type('string', $_-&gt;login),
+                email     =&gt; $self-&gt;type('string', $_-&gt;email),
+                can_login =&gt; $self-&gt;type('boolean', $_-&gt;is_enabled ? 1 : 0),
+                email_enabled     =&gt; $self-&gt;type('boolean', $_-&gt;email_enabled),
+                login_denied_text =&gt; $self-&gt;type('string', $_-&gt;disabledtext),
+            }} @$in_group;
+
+    }    
+    else {
+        @users =
+            map {filter $params, {
+                id        =&gt; $self-&gt;type('int', $_-&gt;id),
+                real_name =&gt; $self-&gt;type('string', $_-&gt;name),
+                name      =&gt; $self-&gt;type('string', $_-&gt;login),
+                email     =&gt; $self-&gt;type('string', $_-&gt;email),
+                can_login =&gt; $self-&gt;type('boolean', $_-&gt;is_enabled ? 1 : 0),
+            }} @$in_group;
+    }
+
+    return { users =&gt; \@users };
+}
+
+sub _filter_users_by_group {
+    my ($self, $users, $params) = @_;
+    my ($group_ids, $group_names) = @$params{qw(group_ids groups)};
+
+    # If no groups are specified, we return all users.
+    return $users if (!$group_ids and !$group_names);
+
+    my @groups = map { Bugzilla::Group-&gt;check({ id =&gt; $_ }) } 
+                     @{ $group_ids || [] };
+    my @name_groups = map { Bugzilla::Group-&gt;check($_) } 
+                          @{ $group_names || [] };
+    push(@groups, @name_groups);
+    
+
+    my @in_group = grep { $self-&gt;_user_in_any_group($_, \@groups) }
+                        @$users;
+    return \@in_group;
+}
+
+sub _user_in_any_group {
+    my ($self, $user, $groups) = @_;
+    foreach my $group (@$groups) {
+        return 1 if $user-&gt;in_group($group);
+    }
+    return 0;
+}
+
</ins><span class="cx"> 1;
</span><span class="cx"> 
</span><span class="cx"> __END__
</span><span class="lines">@@ -143,12 +271,10 @@
</span><span class="cx"> See L&lt;Bugzilla::WebService&gt; for a description of how parameters are passed,
</span><span class="cx"> and what B&lt;STABLE&gt;, B&lt;UNSTABLE&gt;, and B&lt;EXPERIMENTAL&gt; mean.
</span><span class="cx"> 
</span><del>-=head2 Logging In and Out
</del><ins>+=head1 Logging In and Out
</ins><span class="cx"> 
</span><del>-=over
</del><ins>+=head2 login
</ins><span class="cx"> 
</span><del>-=item C&lt;login&gt; 
-
</del><span class="cx"> B&lt;STABLE&gt;
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="lines">@@ -197,6 +323,11 @@
</span><span class="cx"> The account has been disabled.  A reason may be specified with the
</span><span class="cx"> error.
</span><span class="cx"> 
</span><ins>+=item 305 (New Password Required)
+
+The current password is correct, but the user is asked to change
+his password.
+
</ins><span class="cx"> =item 50 (Param Required)
</span><span class="cx"> 
</span><span class="cx"> A login or password parameter was not provided.
</span><span class="lines">@@ -205,7 +336,7 @@
</span><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><del>-=item C&lt;logout&gt; 
</del><ins>+=head2 logout
</ins><span class="cx"> 
</span><span class="cx"> B&lt;STABLE&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -223,14 +354,10 @@
</span><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><del>-=back
</del><ins>+=head1 Account Creation
</ins><span class="cx"> 
</span><del>-=head2 Account Creation
</del><ins>+=head2 offer_account_by_email
</ins><span class="cx"> 
</span><del>-=over
-
-=item C&lt;offer_account_by_email&gt; 
-
</del><span class="cx"> B&lt;STABLE&gt;
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="lines">@@ -257,22 +384,22 @@
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><del>-=item 500 (Illegal Email Address)
</del><ins>+=item 500 (Account Already Exists)
</ins><span class="cx"> 
</span><ins>+An account with that email address already exists in Bugzilla.
+
+=item 501 (Illegal Email Address)
+
</ins><span class="cx"> This Bugzilla does not allow you to create accounts with the format of
</span><span class="cx"> email address you specified. Account creation may be entirely disabled.
</span><span class="cx"> 
</span><del>-=item 501 (Account Already Exists)
-
-An account with that email address already exists in Bugzilla.
-
</del><span class="cx"> =back
</span><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><del>-=item C&lt;create&gt; 
</del><ins>+=head2 create
</ins><span class="cx"> 
</span><del>-B&lt;EXPERIMENTAL&gt;
</del><ins>+B&lt;STABLE&gt;
</ins><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><span class="lines">@@ -321,21 +448,172 @@
</span><span class="cx"> The password specified is too short. (Usually, this means the
</span><span class="cx"> password is under three characters.)
</span><span class="cx"> 
</span><del>-=item 503 (Password Too Long)
</del><ins>+=back
</ins><span class="cx"> 
</span><del>-The password specified is too long. (Usually, this means the
-password is over ten characters.)
</del><ins>+=item B&lt;History&gt;
</ins><span class="cx"> 
</span><ins>+=over
+
+=item Error 503 (Password Too Long) removed in Bugzilla B&lt;3.6&gt;.
+
</ins><span class="cx"> =back
</span><span class="cx"> 
</span><ins>+=back
+
+=head1 User Info
+
+=head2 get
+
+B&lt;STABLE&gt;
+
+=over
+
+=item B&lt;Description&gt;
+
+Gets information about user accounts in Bugzilla.
+
+=item B&lt;Params&gt;
+
+B&lt;Note&gt;: At least one of C&lt;ids&gt;, C&lt;names&gt;, or C&lt;match&gt; must be specified.
+
+B&lt;Note&gt;: Users will not be returned more than once, so even if a user 
+is matched by more than one argument, only one user will be returned.
+
+In addition to the parameters below, this method also accepts the
+standard L&lt;include_fields|Bugzilla::WebService/include_fields&gt; and
+L&lt;exclude_fields|Bugzilla::WebService/exclude_fields&gt; arguments.
+
+=over
+
+=item C&lt;ids&gt; (array) 
+
+An array of integers, representing user ids.
+
+Logged-out users cannot pass this parameter to this function. If they try,
+they will get an error. Logged-in users will get an error if they specify
+the id of a user they cannot see.
+
+=item C&lt;names&gt; (array)
+
+An array of login names (strings).
+
+=item C&lt;match&gt; (array)
+
+An array of strings. This works just like &quot;user matching&quot; in
+Bugzilla itself. Users will be returned whose real name or login name
+contains any one of the specified strings. Users that you cannot see will
+not be included in the returned list.
+
+Some Bugzilla installations have user-matching turned off, in which
+case you will only be returned exact matches.
+
+Most installations have a limit on how many matches are returned for
+each string, which defaults to 1000 but can be changed by the Bugzilla
+administrator.
+
+Logged-out users cannot use this argument, and an error will be thrown
+if they try. (This is to make it harder for spammers to harvest email
+addresses from Bugzilla, and also to enforce the user visibility
+restrictions that are implemented on some Bugzillas.)
+
+=item C&lt;group_ids&gt; (array)
+
+=item C&lt;groups&gt; (array)
+
+C&lt;group_ids&gt; is an array of numeric ids for groups that a user can be in.
+C&lt;groups&gt; is an array of names of groups that a user can be in.
+If these are specified, they limit the return value to users who are
+in I&lt;any&gt; of the groups specified.
+
+=item C&lt;include_disabled&gt; (boolean)
+
+By default, when using the C&lt;match&gt; parameter, disabled users are excluded
+from the returned results unless their full username is identical to the
+match string. Setting C&lt;include_disabled&gt; to C&lt;true&gt; will include disabled
+users in the returned results even if their username doesn't fully match
+the input string.
+
+=back
+
+=item B&lt;Returns&gt; 
+
+A hash containing one item, C&lt;users&gt;, that is an array of
+hashes. Each hash describes a user, and has the following items:
+
+=over
+
+=item id
+
+C&lt;int&gt; The unique integer ID that Bugzilla uses to represent this user. 
+Even if the user's login name changes, this will not change.
+
+=item real_name
+
+C&lt;string&gt; The actual name of the user. May be blank.
+
+=item email
+
+C&lt;string&gt; The email address of the user.
+
+=item name
+
+C&lt;string&gt; The login name of the user. Note that in some situations this is 
+different than their email.
+
+=item can_login
+
+C&lt;boolean&gt; A boolean value to indicate if the user can login into bugzilla. 
+
+=item email_enabled
+
+C&lt;boolean&gt; A boolean value to indicate if bug-related mail will be sent
+to the user or not.
+
+=item login_denied_text
+
+C&lt;string&gt; A text field that holds the reason for disabling a user from logging
+into bugzilla, if empty then the user account is enabled. Otherwise it is 
+disabled/closed.
+
+B&lt;Note&gt;: If you are not logged in to Bugzilla when you call this function, you
+will only be returned the C&lt;id&gt;, C&lt;name&gt;, and C&lt;real_name&gt; items. If you are
+logged in and not in editusers group, you will only be returned the C&lt;id&gt;, C&lt;name&gt;, 
+C&lt;real_name&gt;, C&lt;email&gt;, and C&lt;can_login&gt; items.
+
+=back
+
+=item B&lt;Errors&gt;
+
+=over
+
+=item 51 (Bad Login Name or Group Name)
+
+You passed an invalid login name in the &quot;names&quot; array or a bad
+group name/id in the C&lt;groups&gt;/C&lt;group_ids&gt; arguments.
+
+=item 304 (Authorization Required)
+
+You are logged in, but you are not authorized to see one of the users you
+wanted to get information about by user id.
+
+=item 505 (User Access By Id or User-Matching Denied)
+
+Logged-out users cannot use the &quot;ids&quot; or &quot;match&quot; arguments to this 
+function.
+
+=back
+
</ins><span class="cx"> =item B&lt;History&gt;
</span><span class="cx"> 
</span><span class="cx"> =over
</span><span class="cx"> 
</span><span class="cx"> =item Added in Bugzilla B&lt;3.4&gt;.
</span><span class="cx"> 
</span><del>-=back
</del><ins>+=item C&lt;group_ids&gt; and C&lt;groups&gt; were added in Bugzilla B&lt;4.0&gt;.
</ins><span class="cx"> 
</span><ins>+=item C&lt;include_disabled&gt; added in Bugzilla B&lt;4.0&gt;. Default behavior 
+for C&lt;match&gt; has changed to only returning enabled accounts.
+
</ins><span class="cx"> =back
</span><span class="cx"> 
</span><span class="cx"> =back
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaWebServiceUtilpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Util.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Util.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/WebService/Util.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,149 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Everything Solved, Inc.
+# Portions created by the Initial Developer are Copyright (C) 2008
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s): 
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+package Bugzilla::WebService::Util;
+use strict;
+use base qw(Exporter);
+
+# We have to &quot;require&quot;, not &quot;use&quot; this, because otherwise it tries to
+# use features of Test::More during import().
+require Test::Taint;
+
+our @EXPORT_OK = qw(
+    filter
+    filter_wants
+    taint_data
+    validate
+);
+
+sub filter ($$) {
+    my ($params, $hash) = @_;
+    my %newhash = %$hash;
+
+    foreach my $key (keys %$hash) {
+        delete $newhash{$key} if !filter_wants($params, $key);
+    }
+
+    return \%newhash;
+}
+
+sub filter_wants ($$) {
+    my ($params, $field) = @_;
+    my %include = map { $_ =&gt; 1 } @{ $params-&gt;{'include_fields'} || [] };
+    my %exclude = map { $_ =&gt; 1 } @{ $params-&gt;{'exclude_fields'} || [] };
+
+    if (defined $params-&gt;{include_fields}) {
+        return 0 if !$include{$field};
+    }
+    if (defined $params-&gt;{exclude_fields}) {
+        return 0 if $exclude{$field};
+    }
+
+    return 1;
+}
+
+sub taint_data {
+    my @params = @_;
+    return if !@params;
+    # Though this is a private function, it hasn't changed since 2004 and
+    # should be safe to use, and prevents us from having to write it ourselves
+    # or require another module to do it.
+    Test::Taint::_deeply_traverse(\&amp;_delete_bad_keys, \@params);
+    Test::Taint::taint_deeply(\@params);
+}
+
+sub _delete_bad_keys {
+    foreach my $item (@_) {
+        next if ref $item ne 'HASH';
+        foreach my $key (keys %$item) {
+            # Making something a hash key always untaints it, in Perl.
+            # However, we need to validate our argument names in some way.
+            # We know that all hash keys passed in to the WebService will 
+            # match \w+, so we delete any key that doesn't match that.
+            if ($key !~ /^\w+$/) {
+                delete $item-&gt;{$key};
+            }
+        }
+    }
+    return @_;
+}
+
+sub validate  {
+    my ($self, $params, @keys) = @_;
+
+    # If $params is defined but not a reference, then we weren't
+    # sent any parameters at all, and we're getting @keys where
+    # $params should be.
+    return ($self, undef) if (defined $params and !ref $params);
+    
+    # If @keys is not empty then we convert any named 
+    # parameters that have scalar values to arrayrefs
+    # that match.
+    foreach my $key (@keys) {
+        if (exists $params-&gt;{$key}) {
+            $params-&gt;{$key} = ref $params-&gt;{$key} 
+                              ? $params-&gt;{$key} 
+                              : [ $params-&gt;{$key} ];
+        }
+    }
+
+    return ($self, $params);
+}
+
+__END__
+
+=head1 NAME
+
+Bugzilla::WebService::Util - Utility functions used inside of the WebService
+code. These are B&lt;not&gt; functions that can be called via the WebService.
+
+=head1 DESCRIPTION
+
+This is somewhat like L&lt;Bugzilla::Util&gt;, but these functions are only used
+internally in the WebService code.
+
+=head1 SYNOPSIS
+
+ filter({ include_fields =&gt; ['id', 'name'], 
+          exclude_fields =&gt; ['name'] }, $hash);
+ my $wants = filter_wants $params, 'field_name';
+ validate(@_, 'ids');
+
+=head1 METHODS
+
+=head2 filter
+
+This helps implement the C&lt;include_fields&gt; and C&lt;exclude_fields&gt; arguments
+of WebService methods. Given a hash (the second argument to this subroutine),
+this will remove any keys that are I&lt;not&gt; in C&lt;include_fields&gt; and then remove
+any keys that I&lt;are&gt; in C&lt;exclude_fields&gt;.
+
+=head2 filter_wants
+
+Returns C&lt;1&gt; if a filter would preserve the specified field when passing
+a hash to L&lt;/filter&gt;, C&lt;0&gt; otherwise.
+
+=head2 validate
+
+This helps in the validation of parameters passed into the WebSerice
+methods. Currently it converts listed parameters into an array reference
+if the client only passed a single scalar value. It modifies the parameters
+hash in place so other parameters should be unaltered.
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaWebServicepm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla/WebService.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/WebService.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/WebService.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -15,130 +15,31 @@
</span><span class="cx"> # Contributor(s): Marc Schumann &lt;wurblzap@gmail.com&gt;
</span><span class="cx"> #                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
</span><span class="cx"> 
</span><ins>+# This is the base class for $self in WebService method calls. For the 
+# actual RPC server, see Bugzilla::WebService::Server and its subclasses.
</ins><span class="cx"> package Bugzilla::WebService;
</span><del>-
</del><span class="cx"> use strict;
</span><del>-use Bugzilla::WebService::Constants;
-use Bugzilla::Util;
-use Date::Parse;
</del><ins>+use Bugzilla::WebService::Server;
</ins><span class="cx"> 
</span><del>-sub fail_unimplemented {
-    my $this = shift;
</del><ins>+# Used by the JSON-RPC server to convert incoming date fields apprpriately.
+use constant DATE_FIELDS =&gt; {};
+# Used by the JSON-RPC server to convert incoming base64 fields appropriately.
+use constant BASE64_FIELDS =&gt; {};
</ins><span class="cx"> 
</span><del>-    die SOAP::Fault
-        -&gt;faultcode(ERROR_UNIMPLEMENTED)
-        -&gt;faultstring('Service Unimplemented');
-}
-
-sub datetime_format {
-    my ($self, $date_string) = @_;
-
-    my $time = str2time($date_string);
-    my ($sec, $min, $hour, $mday, $mon, $year) = localtime $time;
-    # This format string was stolen from SOAP::Utils-&gt;format_datetime,
-    # which doesn't work but which has almost the right format string.
-    my $iso_datetime = sprintf('%d%02d%02dT%02d:%02d:%02d',
-        $year + 1900, $mon + 1, $mday, $hour, $min, $sec);
-    return $iso_datetime;
-}
-
-sub handle_login {
-    my ($classes, $action, $uri, $method) = @_;
-
-    my $class = $classes-&gt;{$uri};
-    eval &quot;require $class&quot;;
-
-    return if $class-&gt;login_exempt($method);
-    Bugzilla-&gt;login();
-
-    # Even though we check for the need to redirect in
-    # Bugzilla-&gt;login() we check here again since Bugzilla-&gt;login()
-    # does not know what the current XMLRPC method is. Therefore
-    # ssl_require_redirect in Bugzilla-&gt;login() will have returned 
-    # false if system was configured to redirect for authenticated 
-    # sessions and the user was not yet logged in.
-    # So here we pass in the method name to ssl_require_redirect so
-    # it can then check for the extra case where the method equals
-    # User.login, which we would then need to redirect if not
-    # over a secure connection. 
-    my $full_method = $uri . &quot;.&quot; . $method;
-    Bugzilla-&gt;cgi-&gt;require_https(Bugzilla-&gt;params-&gt;{'sslbase'})
-        if ssl_require_redirect($full_method);
-
-    return;
-}
-
</del><span class="cx"> # For some methods, we shouldn't call Bugzilla-&gt;login before we call them
</span><span class="cx"> use constant LOGIN_EXEMPT =&gt; { };
</span><span class="cx"> 
</span><ins>+# Used to allow methods to be called in the JSON-RPC WebService via GET.
+# Methods that can modify data MUST not be listed here.
+use constant READ_ONLY =&gt; ();
+
</ins><span class="cx"> sub login_exempt {
</span><span class="cx">     my ($class, $method) = @_;
</span><del>-
</del><span class="cx">     return $class-&gt;LOGIN_EXEMPT-&gt;{$method};
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> 1;
</span><span class="cx"> 
</span><del>-package Bugzilla::WebService::XMLRPC::Transport::HTTP::CGI;
-use strict;
-eval { require XMLRPC::Transport::HTTP; };
-our @ISA = qw(XMLRPC::Transport::HTTP::CGI);
-
-sub initialize {
-    my $self = shift;
-    my %retval = $self-&gt;SUPER::initialize(@_);
-    $retval{'serializer'} = Bugzilla::WebService::XMLRPC::Serializer-&gt;new;
-    return %retval;
-}
-
-sub make_response {
-    my $self = shift;
-
-    $self-&gt;SUPER::make_response(@_);
-
-    # XMLRPC::Transport::HTTP::CGI doesn't know about Bugzilla carrying around
-    # its cookies in Bugzilla::CGI, so we need to copy them over.
-    foreach (@{Bugzilla-&gt;cgi-&gt;{'Bugzilla_cookie_list'}}) {
-        $self-&gt;response-&gt;headers-&gt;push_header('Set-Cookie', $_);
-    }
-}
-
-1;
-
-# This package exists to fix a UTF-8 bug in SOAP::Lite.
-# See http://rt.cpan.org/Public/Bug/Display.html?id=32952.
-package Bugzilla::WebService::XMLRPC::Serializer;
-use strict;
-# We can't use &quot;use base&quot; because XMLRPC::Serializer doesn't return
-# a true value.
-eval { require XMLRPC::Lite; };
-our @ISA = qw(XMLRPC::Serializer);
-
-sub new {
-    my $class = shift;
-    my $self = $class-&gt;SUPER::new(@_);
-    # This fixes UTF-8.
-    $self-&gt;{'_typelookup'}-&gt;{'base64'} =
-        [10, sub { !utf8::is_utf8($_[0]) &amp;&amp; $_[0] =~ /[^\x09\x0a\x0d\x20-\x7f]/},
-        'as_base64'];
-    # This makes arrays work right even though we're a subclass.
-    # (See http://rt.cpan.org//Ticket/Display.html?id=34514)
-    $self-&gt;{'_encodingStyle'} = '';
-    return $self;
-}
-
-sub as_string {
-    my $self = shift;
-    my ($value) = @_;
-    # Something weird happens with XML::Parser when we have upper-ASCII 
-    # characters encoded as UTF-8, and this fixes it.
-    utf8::encode($value) if utf8::is_utf8($value) 
-                            &amp;&amp; $value =~ /^[\x00-\xff]+$/;
-    return $self-&gt;SUPER::as_string($value);
-}
-
-1;
-
</del><span class="cx"> __END__
</span><span class="cx"> 
</span><span class="cx"> =head1 NAME
</span><span class="lines">@@ -150,87 +51,131 @@
</span><span class="cx"> This is the standard API for external programs that want to interact
</span><span class="cx"> with Bugzilla. It provides various methods in various modules.
</span><span class="cx"> 
</span><del>-Currently the only method of accessing the API is via XML-RPC. The XML-RPC
-standard is described here: L&lt;http://www.xmlrpc.com/spec&gt;
</del><ins>+You can interact with this API via
+L&lt;XML-RPC|Bugzilla::WebService::Server::XMLRPC&gt; or
+L&lt;JSON-RPC|Bugzilla::WebService::Server::JSONRPC&gt;.
</ins><span class="cx"> 
</span><del>-The endpoint for Bugzilla WebServices is the C&lt;xmlrpc.cgi&gt; script in
-your Bugzilla installation. For example, if your Bugzilla is at
-C&lt;bugzilla.yourdomain.com&gt;, then your XML-RPC client would access the
-API via: C&lt;http://bugzilla.yourdomain.com/xmlrpc.cgi&gt;
-
</del><span class="cx"> =head1 CALLING METHODS
</span><span class="cx"> 
</span><del>-Methods are called in the normal XML-RPC fashion. Bugzilla does not currently
-implement any extensions to the standard method of XML-RPC method calling.
-
</del><span class="cx"> Methods are grouped into &quot;packages&quot;, like C&lt;Bug&gt; for 
</span><span class="cx"> L&lt;Bugzilla::WebService::Bug&gt;. So, for example,
</span><del>-L&lt;Bugzilla::WebService::Bug/get&gt;, is called as C&lt;Bug.get&gt; in XML-RPC.
</del><ins>+L&lt;Bugzilla::WebService::Bug/get&gt;, is called as C&lt;Bug.get&gt;.
</ins><span class="cx"> 
</span><span class="cx"> =head1 PARAMETERS
</span><span class="cx"> 
</span><del>-In addition to the standard parameter types like C&lt;int&gt;, C&lt;string&gt;, etc.,
-XML-RPC has two data structures, a C&lt;&lt; &lt;struct&gt; &gt;&gt; and an C&lt;&lt; &lt;array&gt; &gt;&gt;.
</del><ins>+The Bugzilla API takes the following various types of parameters:
</ins><span class="cx"> 
</span><del>-=head2 Structs
</del><ins>+=over
</ins><span class="cx"> 
</span><del>-In Perl, we call a C&lt;&lt; &lt;struct&gt; &gt;&gt; a &quot;hash&quot; or a &quot;hashref&quot;. You may see
-us refer to it that way in the API documentation.
</del><ins>+=item C&lt;int&gt;
</ins><span class="cx"> 
</span><del>-In example code, you will see the characters C&lt;{&gt; and C&lt;}&gt; used to represent
-the beginning and end of structs.
</del><ins>+Integer. May be null.
</ins><span class="cx"> 
</span><del>-For example, here's a struct in XML-RPC:
</del><ins>+=item C&lt;double&gt;
</ins><span class="cx"> 
</span><del>- &lt;struct&gt;
-   &lt;member&gt;
-     &lt;name&gt;fruit&lt;/name&gt;
-     &lt;value&gt;&lt;string&gt;oranges&lt;/string&gt;&lt;/value&gt;
-   &lt;/member&gt;
-   &lt;member&gt;
-     &lt;name&gt;vegetable&lt;/name&gt;
-     &lt;value&gt;&lt;string&gt;lettuce&lt;/string&gt;&lt;/value&gt;
-   &lt;/member&gt;
- &lt;/struct&gt;
</del><ins>+A floating-point number. May be null.
</ins><span class="cx"> 
</span><del>-In our example code in these API docs, that would look like:
</del><ins>+=item C&lt;string&gt;
</ins><span class="cx"> 
</span><del>- { fruit =&gt; 'oranges', vegetable =&gt; 'lettuce' }
</del><ins>+A string. May be null.
</ins><span class="cx"> 
</span><del>-=head2 Arrays
</del><ins>+=item C&lt;dateTime&gt;
</ins><span class="cx"> 
</span><ins>+A date/time. Represented differently in different interfaces to this API.
+May be null.
+
+=item C&lt;boolean&gt;
+
+True or false.
+
+=item C&lt;base64&gt;
+
+A base64-encoded string. This is the only way to transfer
+binary data via the WebService.
+
+=item C&lt;array&gt;
+
+An array. There may be mixed types in an array.
+
</ins><span class="cx"> In example code, you will see the characters C&lt;[&gt; and C&lt;]&gt; used to
</span><span class="cx"> represent the beginning and end of arrays.
</span><span class="cx"> 
</span><del>-For example, here's an array in XML-RPC:
</del><ins>+In our example code in these API docs, an array that contains the numbers
+1, 2, and 3 would look like:
</ins><span class="cx"> 
</span><del>- &lt;array&gt;
-   &lt;data&gt;
-     &lt;value&gt;&lt;i4&gt;1&lt;/i4&gt;&lt;/value&gt;
-     &lt;value&gt;&lt;i4&gt;2&lt;/i4&gt;&lt;/value&gt;
-     &lt;value&gt;&lt;i4&gt;3&lt;/i4&gt;&lt;/value&gt;
-   &lt;/data&gt;
- &lt;/array&gt;
</del><ins>+ [1, 2, 3]
</ins><span class="cx"> 
</span><del>-In our example code in these API docs, that would look like:
</del><ins>+=item C&lt;struct&gt;
</ins><span class="cx"> 
</span><del>- [1, 2, 3]
</del><ins>+A mapping of keys to values. Called a &quot;hash&quot;, &quot;dict&quot;, or &quot;map&quot; in some
+other programming languages. We sometimes call this a &quot;hash&quot; in the API
+documentation.
</ins><span class="cx"> 
</span><ins>+The keys are strings, and the values can be any type.
+
+In example code, you will see the characters C&lt;{&gt; and C&lt;}&gt; used to represent
+the beginning and end of structs.
+
+For example, a struct with an &quot;fruit&quot; key whose value is &quot;oranges&quot;,
+and a &quot;vegetable&quot; key whose value is &quot;lettuce&quot; would look like:
+
+ { fruit =&gt; 'oranges', vegetable =&gt; 'lettuce' }
+
+=back
+
</ins><span class="cx"> =head2 How Bugzilla WebService Methods Take Parameters
</span><span class="cx"> 
</span><del>-B&lt;All&gt; Bugzilla WebServices functions take their parameters in
-a C&lt;&lt; &lt;struct&gt; &gt;&gt;. Another way of saying this would be: All functions
-take a single argument, a C&lt;&lt; &lt;struct&gt; &gt;&gt; that contains all parameters.
-The names of the parameters listed in the API docs for each function are
-the C&lt;name&gt; element for the struct C&lt;member&gt;s.
</del><ins>+B&lt;All&gt; Bugzilla WebService functions use I&lt;named&gt; parameters.
+The individual C&lt;Bugzilla::WebService::Server&gt; modules explain
+how this is implemented for those frontends.
</ins><span class="cx"> 
</span><span class="cx"> =head1 LOGGING IN
</span><span class="cx"> 
</span><ins>+There are various ways to log in:
+
+=over
+
+=item C&lt;User.login&gt;
+
</ins><span class="cx"> You can use L&lt;Bugzilla::WebService::User/login&gt; to log in as a Bugzilla 
</span><span class="cx"> user. This issues standard HTTP cookies that you must then use in future
</span><del>-calls, so your XML-RPC client must be capable of receiving and transmitting
</del><ins>+calls, so your client must be capable of receiving and transmitting
</ins><span class="cx"> cookies.
</span><span class="cx"> 
</span><ins>+=item C&lt;Bugzilla_login&gt; and C&lt;Bugzilla_password&gt;
+
+B&lt;Added in Bugzilla 3.6&gt;
+
+You can specify C&lt;Bugzilla_login&gt; and C&lt;Bugzilla_password&gt; as arguments
+to any WebService method, and you will be logged in as that user if your
+credentials are correct. Here are the arguments you can specify to any
+WebService method to perform a login:
+
+=over
+
+=item C&lt;Bugzilla_login&gt; (string) - A user's login name.
+
+=item C&lt;Bugzilla_password&gt; (string) - That user's password.
+
+=item C&lt;Bugzilla_restrictlogin&gt; (boolean) - Optional. If true,
+then your login will only be valid for your IP address.
+
+=item C&lt;Bugzilla_rememberlogin&gt; (boolean) - Optional. If true,
+then the cookie sent back to you with the method response will
+not expire.
+
+=back
+
+The C&lt;Bugzilla_restrictlogin&gt; and C&lt;Bugzilla_rememberlogin&gt; options
+are only used when you have also specified C&lt;Bugzilla_login&gt; and 
+C&lt;Bugzilla_password&gt;.
+
+Note that Bugzilla will return HTTP cookies along with the method
+response when you use these arguments (just like the C&lt;User.login&gt; method
+above).
+
+=back
+
</ins><span class="cx"> =head1 STABLE, EXPERIMENTAL, and UNSTABLE
</span><span class="cx"> 
</span><span class="cx"> Methods are marked B&lt;STABLE&gt; if you can expect their parameters and
</span><span class="lines">@@ -251,18 +196,17 @@
</span><span class="cx"> 
</span><span class="cx"> =head1 ERRORS
</span><span class="cx"> 
</span><del>-If a particular webservice call fails, it will throw a standard XML-RPC
-error. There will be a numeric error code, and then the description
-field will contain descriptive text of the error. Each error that Bugzilla
-can throw has a specific code that will not change between versions of
-Bugzilla.
</del><ins>+If a particular webservice call fails, it will throw an error in the
+appropriate format for the frontend that you are using. For all frontends,
+there is at least a numeric error code and descriptive text for the error.
</ins><span class="cx"> 
</span><span class="cx"> The various errors that functions can throw are specified by the
</span><span class="cx"> documentation of those functions.
</span><span class="cx"> 
</span><del>-If your code needs to know what error Bugzilla threw, use the numeric
-code. Don't try to parse the description, because that may change
-from version to version of Bugzilla.
</del><ins>+Each error that Bugzilla can throw has a specific numeric code that will
+not change between versions of Bugzilla. If your code needs to know what
+error Bugzilla threw, use the numeric code. Don't try to parse the
+description, because that may change from version to version of Bugzilla.
</ins><span class="cx"> 
</span><span class="cx"> Note that if you display the error to the user in an HTML program, make
</span><span class="cx"> sure that you properly escape the error, as it will not be HTML-escaped.
</span><span class="lines">@@ -285,3 +229,93 @@
</span><span class="cx"> Sometimes a function will throw an error that doesn't have a specific
</span><span class="cx"> error code. In this case, the code will be C&lt;-32000&gt; if it's a &quot;fatal&quot;
</span><span class="cx"> error, and C&lt;32000&gt; if it's a &quot;transient&quot; error.
</span><ins>+
+=head1 COMMON PARAMETERS
+
+Many Webservice methods take similar arguments. Instead of re-writing
+the documentation for each method, we document the parameters here, once,
+and then refer back to this documentation from the individual methods
+where these parameters are used.
+
+=head2 Limiting What Fields Are Returned
+
+Many WebService methods return an array of structs with various
+fields in the structs. (For example, L&lt;Bugzilla::WebService::Bug/get&gt;
+returns a list of C&lt;bugs&gt; that have fields like C&lt;id&gt;, C&lt;summary&gt;, 
+C&lt;creation_time&gt;, etc.)
+
+These parameters allow you to limit what fields are present in
+the structs, to possibly improve performance or save some bandwidth.
+
+=over
+
+=item C&lt;include_fields&gt; 
+
+C&lt;array&gt; An array of strings, representing the (case-sensitive) names of
+fields in the return value. Only the fields specified in this hash will
+be returned, the rest will not be included.
+
+If you specify an empty array, then this function will return empty
+hashes.
+
+Invalid field names are ignored.
+
+Example:
+
+  User.get( ids =&gt; [1], include_fields =&gt; ['id', 'name'] )
+
+would return something like:
+
+  { users =&gt; [{ id =&gt; 1, name =&gt; 'user@domain.com' }] }
+
+=item C&lt;exclude_fields&gt;
+
+C&lt;array&gt; An array of strings, representing the (case-sensitive) names of
+fields in the return value. The fields specified will not be included in
+the returned hashes.
+
+If you specify all the fields, then this function will return empty
+hashes.
+
+Invalid field names are ignored.
+
+Specifying fields here overrides C&lt;include_fields&gt;, so if you specify a
+field in both, it will be excluded, not included.
+
+Example:
+
+  User.get( ids =&gt; [1], exclude_fields =&gt; ['name'] )
+
+would return something like:
+
+  { users =&gt; [{ id =&gt; 1, real_name =&gt; 'John Smith' }] }
+
+=back
+
+=head1 SEE ALSO
+
+=head2 Server Types
+
+=over
+
+=item L&lt;Bugzilla::WebService::Server::XMLRPC&gt;
+
+=item L&lt;Bugzilla::WebService::Server::JSONRPC&gt;
+
+=back
+
+=head2 WebService Methods
+
+=over
+
+=item L&lt;Bugzilla::WebService::Bug&gt;
+
+=item L&lt;Bugzilla::WebService::Bugzilla&gt;
+
+=item L&lt;Bugzilla::WebService::Group&gt;
+
+=item L&lt;Bugzilla::WebService::Product&gt;
+
+=item L&lt;Bugzilla::WebService::User&gt;
+
+=back
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaWhineQuerypm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/Whine/Query.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Whine/Query.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Whine/Query.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,136 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Eric Black.
+# Portions created by the Initial Developer are Copyright (C) 2009 
+# Eric Black. All Rights Reserved.
+#
+# Contributor(s): Eric Black &lt;black.eric@gmail.com&gt;
+
+package Bugzilla::Whine::Query;
+
+use strict;
+
+use base qw(Bugzilla::Object);
+
+use Bugzilla::Constants;
+use Bugzilla::Search::Saved;
+
+#############
+# Constants #
+#############
+
+use constant DB_TABLE =&gt; 'whine_queries';
+
+use constant DB_COLUMNS =&gt; qw(
+    id
+    eventid
+    query_name
+    sortkey
+    onemailperbug
+    title
+);
+
+use constant NAME_FIELD =&gt; 'id';
+use constant LIST_ORDER =&gt; 'sortkey';
+
+####################
+# Simple Accessors #
+####################
+sub eventid           { return $_[0]-&gt;{'eventid'};       }
+sub sortkey           { return $_[0]-&gt;{'sortkey'};       }
+sub one_email_per_bug { return $_[0]-&gt;{'onemailperbug'}; }
+sub title             { return $_[0]-&gt;{'title'};         }
+sub name              { return $_[0]-&gt;{'query_name'};    }
+
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::Whine::Query - A query object used by L&lt;Bugzilla::Whine&gt;.
+
+=head1 SYNOPSIS
+
+ use Bugzilla::Whine::Query;
+
+ my $query = new Bugzilla::Whine::Query($id);
+
+ my $event_id          = $query-&gt;eventid;
+ my $id                = $query-&gt;id;
+ my $query_name        = $query-&gt;name;
+ my $sortkey           = $query-&gt;sortkey;
+ my $one_email_per_bug = $query-&gt;one_email_per_bug;
+ my $title             = $query-&gt;title;
+
+=head1 DESCRIPTION
+
+This module exists to represent a query for a L&lt;Bugzilla::Whine::Event&gt;.
+Each event, which are groups of schedules and queries based on how the 
+user configured the event, may have zero or more queries associated
+with it. Additionally, the queries are selected from the user's saved
+searches, or L&lt;Bugzilla::Search::Saved&gt; object with a matching C&lt;name&gt;
+attribute for the user. 
+
+This is an implementation of L&lt;Bugzilla::Object&gt;, and so has all the
+same methods available as L&lt;Bugzilla::Object&gt;, in addition to what is
+documented below.
+
+=head1 METHODS
+
+=head2 Constructors
+
+=over
+
+=item C&lt;new&gt;
+
+Does not accept a bare C&lt;name&gt; argument. Instead, accepts only an id.
+
+See also: L&lt;Bugzilla::Object/new&gt;.
+
+=back
+
+
+=head2 Accessors
+
+These return data about the object, without modifying the object.
+
+=over
+
+=item C&lt;event_id&gt;
+
+The L&lt;Bugzilla::Whine::Event&gt; object id for this object.
+
+=item C&lt;name&gt;
+
+The L&lt;Bugzilla::Search::Saved&gt; query object name for this object.
+
+=item C&lt;sortkey&gt;
+
+The relational sorting key as compared with other L&lt;Bugzilla::Whine::Query&gt;
+objects.
+
+=item C&lt;one_email_per_bug&gt;
+
+Returns a numeric 1(C&lt;true&gt;) or 0(C&lt;false&gt;) to represent whether this
+L&lt;Bugzilla::Whine::Query&gt; object is supposed to be mailed as a list of
+bugs or one email per bug.
+
+=item C&lt;title&gt;
+
+The title of this object as it appears in the user forms and emails.
+
+=back
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaWhineSchedulepm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/Whine/Schedule.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Whine/Schedule.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Whine/Schedule.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,170 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Eric Black.
+# Portions created by the Initial Developer are Copyright (C) 2009 
+# Eric Black. All Rights Reserved.
+#
+# Contributor(s): Eric Black &lt;black.eric@gmail.com&gt;
+
+use strict;
+
+package Bugzilla::Whine::Schedule;
+
+use base qw(Bugzilla::Object);
+
+use Bugzilla::Constants;
+
+#############
+# Constants #
+#############
+
+use constant DB_TABLE =&gt; 'whine_schedules';
+
+use constant DB_COLUMNS =&gt; qw(
+    id
+    eventid
+    run_day
+    run_time
+    run_next
+    mailto
+    mailto_type
+);
+
+use constant UPDATE_COLUMNS =&gt; qw(
+    eventid 
+    run_day 
+    run_time 
+    run_next 
+    mailto 
+    mailto_type
+);
+use constant NAME_FIELD =&gt; 'id';
+use constant LIST_ORDER =&gt; 'id';
+
+####################
+# Simple Accessors #
+####################
+sub eventid         { return $_[0]-&gt;{'eventid'};     }
+sub run_day         { return $_[0]-&gt;{'run_day'};     }
+sub run_time        { return $_[0]-&gt;{'run_time'};    }
+sub mailto_is_group { return $_[0]-&gt;{'mailto_type'}; }
+
+sub mailto {
+    my $self = shift;
+
+    return $self-&gt;{mailto_object} if exists $self-&gt;{mailto_object};
+    my $id = $self-&gt;{'mailto'};
+
+    if ($self-&gt;mailto_is_group) {
+        $self-&gt;{mailto_object} = Bugzilla::Group-&gt;new($id);
+    } else {
+        $self-&gt;{mailto_object} = Bugzilla::User-&gt;new($id);
+    }
+    return $self-&gt;{mailto_object};
+}
+
+sub mailto_users { 
+    my $self = shift;
+    return $self-&gt;{mailto_users} if exists $self-&gt;{mailto_users};
+    my $object = $self-&gt;mailto;
+
+    if ($self-&gt;mailto_is_group) {
+        $self-&gt;{mailto_users} = $object-&gt;members_non_inherited if $object-&gt;is_active;
+    } else {
+        $self-&gt;{mailto_users} = $object;
+    }
+    return $self-&gt;{mailto_users};
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::Whine::Schedule - A schedule object used by L&lt;Bugzilla::Whine&gt;.
+
+=head1 SYNOPSIS
+
+ use Bugzilla::Whine::Schedule;
+
+ my $schedule = new Bugzilla::Whine::Schedule($schedule_id);
+
+ my $event_id    = $schedule-&gt;eventid;
+ my $run_day     = $schedule-&gt;run_day;
+ my $run_time    = $schedule-&gt;run_time;
+ my $is_group    = $schedule-&gt;mailto_is_group;
+ my $object      = $schedule-&gt;mailto;
+ my $array_ref   = $schedule-&gt;mailto_users;
+
+=head1 DESCRIPTION
+
+This module exists to represent a L&lt;Bugzilla::Whine&gt; event schedule.
+
+This is an implementation of L&lt;Bugzilla::Object&gt;, and so has all the
+same methods available as L&lt;Bugzilla::Object&gt;, in addition to what is
+documented below.
+
+=head1 METHODS
+
+=head2 Constructors
+
+=over
+
+=item C&lt;new&gt;
+
+Does not accept a bare C&lt;name&gt; argument. Instead, accepts only an id.
+
+See also: L&lt;Bugzilla::Object/new&gt;.
+
+=back
+
+
+=head2 Accessors
+
+These return data about the object, without modifying the object.
+
+=over
+
+=item C&lt;event_id&gt;
+
+The L&lt;Bugzilla::Whine&gt; event object id for this object.
+
+=item C&lt;run_day&gt;
+
+The day or day pattern that a L&lt;Bugzilla::Whine&gt; event is scheduled to run.
+
+=item C&lt;run_time&gt;
+
+The time or time pattern that a L&lt;Bugzilla::Whine&gt; event is scheduled to run.
+
+=item C&lt;mailto_is_group&gt;
+
+Returns a numeric 1 (C&lt;group&gt;) or 0 (C&lt;user&gt;) to represent whether
+L&lt;/mailto&gt; is a group or user.
+
+=item C&lt;mailto&gt;
+
+This is either a L&lt;Bugzilla::User&gt; or L&lt;Bugzilla::Group&gt; object to represent 
+the user or group this scheduled event is set to be mailed to. 
+
+=item C&lt;mailto_users&gt;
+
+Returns an array reference of L&lt;Bugzilla::User&gt;s. This is derived from the
+L&lt;Bugzilla::Group&gt; stored in L&lt;/mailto&gt; if L&lt;/mailto_is_group&gt; is true and
+the group is still active, otherwise it will contain a single array element
+for the L&lt;Bugzilla::User&gt; in L&lt;/mailto&gt;.
+
+=back
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillaWhinepm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/Bugzilla/Whine.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla/Whine.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/Bugzilla/Whine.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,132 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Eric Black.
+# Portions created by the Initial Developer are Copyright (C) 2010 
+# Eric Black. All Rights Reserved.
+#
+# Contributor(s): Eric Black &lt;black.eric@gmail.com&gt;
+
+use strict;
+
+package Bugzilla::Whine;
+
+use base qw(Bugzilla::Object);
+
+use Bugzilla::Constants;
+use Bugzilla::Error;
+use Bugzilla::User;
+use Bugzilla::Util;
+use Bugzilla::Whine::Schedule;
+use Bugzilla::Whine::Query;
+
+#############
+# Constants #
+#############
+
+use constant DB_TABLE =&gt; 'whine_events';
+
+use constant DB_COLUMNS =&gt; qw(
+    id
+    owner_userid
+    subject
+    body
+    mailifnobugs
+);
+
+use constant LIST_ORDER =&gt; 'id';
+
+####################
+# Simple Accessors #
+####################
+sub subject         { return $_[0]-&gt;{'subject'};      }
+sub body            { return $_[0]-&gt;{'body'};         }
+sub mail_if_no_bugs { return $_[0]-&gt;{'mailifnobugs'}; }
+
+sub user {
+    my ($self) = @_;
+    return $self-&gt;{user} if defined $self-&gt;{user};
+    $self-&gt;{user} = new Bugzilla::User($self-&gt;{'owner_userid'});
+    return $self-&gt;{user};
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+Bugzilla::Whine - A Whine event
+
+=head1 SYNOPSIS
+
+ use Bugzilla::Whine;
+
+ my $event = new Bugzilla::Whine($event_id);
+
+ my $subject      = $event-&gt;subject;
+ my $body         = $event-&gt;body;
+ my $mailifnobugs = $event-&gt;mail_if_no_bugs;
+ my $user         = $event-&gt;user;
+
+=head1 DESCRIPTION
+
+This module exists to represent a whine event that has been
+saved to the database.
+
+This is an implementation of L&lt;Bugzilla::Object&gt;, and so has all the
+same methods available as L&lt;Bugzilla::Object&gt;, in addition to what is
+documented below.
+
+=head1 METHODS
+
+=head2 Constructors
+
+=over
+
+=item C&lt;new&gt;
+
+Does not accept a bare C&lt;name&gt; argument. Instead, accepts only an id.
+
+See also: L&lt;Bugzilla::Object/new&gt;.
+
+=back
+
+
+=head2 Accessors
+
+These return data about the object, without modifying the object.
+
+=over
+
+=item C&lt;subject&gt;
+
+Returns the subject of the whine event.
+
+=item C&lt;body&gt;
+
+Returns the body of the whine event.
+
+=item C&lt;mail_if_no_bugs&gt;
+
+Returns a numeric 1(C&lt;true&gt;) or 0(C&lt;false&gt;) to represent whether this
+whine event object is supposed to be mailed even if there are no bugs
+returned by the query.
+
+=item C&lt;user&gt;
+
+Returns the L&lt;Bugzilla::User&gt; object for the owner of the L&lt;Bugzilla::Whine&gt;
+event.
+
+=back
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgBugzillapm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/Bugzilla.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/Bugzilla.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/Bugzilla.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -40,38 +40,46 @@
</span><span class="cx"> use Bugzilla::Auth;
</span><span class="cx"> use Bugzilla::Auth::Persist::Cookie;
</span><span class="cx"> use Bugzilla::CGI;
</span><ins>+use Bugzilla::Extension;
</ins><span class="cx"> use Bugzilla::DB;
</span><span class="cx"> use Bugzilla::Install::Localconfig qw(read_localconfig);
</span><ins>+use Bugzilla::Install::Requirements qw(OPTIONAL_MODULES);
+use Bugzilla::Install::Util qw(init_console);
</ins><span class="cx"> use Bugzilla::Template;
</span><span class="cx"> use Bugzilla::User;
</span><span class="cx"> use Bugzilla::Error;
</span><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> use Bugzilla::Field;
</span><span class="cx"> use Bugzilla::Flag;
</span><ins>+use Bugzilla::Token;
</ins><span class="cx"> 
</span><span class="cx"> use File::Basename;
</span><span class="cx"> use File::Spec::Functions;
</span><ins>+use DateTime::TimeZone;
+use Date::Parse;
</ins><span class="cx"> use Safe;
</span><span class="cx"> 
</span><del>-# This creates the request cache for non-mod_perl installations.
-our $_request_cache = {};
-
</del><span class="cx"> #####################################################################
</span><span class="cx"> # Constants
</span><span class="cx"> #####################################################################
</span><span class="cx"> 
</span><span class="cx"> # Scripts that are not stopped by shutdownhtml being in effect.
</span><del>-use constant SHUTDOWNHTML_EXEMPT =&gt; [
-    'editparams.cgi',
-    'checksetup.pl',
-    'recode.pl',
-];
</del><ins>+use constant SHUTDOWNHTML_EXEMPT =&gt; qw(
+    editparams.cgi
+    checksetup.pl
+    migrate.pl
+    recode.pl
+);
</ins><span class="cx"> 
</span><span class="cx"> # Non-cgi scripts that should silently exit.
</span><del>-use constant SHUTDOWNHTML_EXIT_SILENTLY =&gt; [
-    'whine.pl'
-];
</del><ins>+use constant SHUTDOWNHTML_EXIT_SILENTLY =&gt; qw(
+    whine.pl
+);
</ins><span class="cx"> 
</span><ins>+# shutdownhtml pages are sent as an HTTP 503. After how many seconds
+# should search engines attempt to index the page again?
+use constant SHUTDOWNHTML_RETRY_AFTER =&gt; 3600;
+
</ins><span class="cx"> #####################################################################
</span><span class="cx"> # Global Code
</span><span class="cx"> #####################################################################
</span><span class="lines">@@ -80,14 +88,27 @@
</span><span class="cx"> 
</span><span class="cx"> # Note that this is a raw subroutine, not a method, so $class isn't available.
</span><span class="cx"> sub init_page {
</span><del>-    (binmode STDOUT, ':utf8') if Bugzilla-&gt;params-&gt;{'utf8'};
</del><ins>+    if (Bugzilla-&gt;usage_mode == USAGE_MODE_CMDLINE) {
+        init_console();
+    }
+    elsif (Bugzilla-&gt;params-&gt;{'utf8'}) {
+        binmode STDOUT, ':utf8';
+    }
</ins><span class="cx"> 
</span><del>-    # Some environment variables are not taint safe
-    delete @::ENV{'PATH', 'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
-    # Some modules throw undefined errors (notably File::Spec::Win32) if
-    # PATH is undefined.
-    $ENV{'PATH'} = '';
</del><ins>+    if (${^TAINT}) {
+        # Some environment variables are not taint safe
+        delete @::ENV{'PATH', 'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
+        # Some modules throw undefined errors (notably File::Spec::Win32) if
+        # PATH is undefined.
+        $ENV{'PATH'} = '';
+    }
</ins><span class="cx"> 
</span><ins>+    # Because this function is run live from perl &quot;use&quot; commands of
+    # other scripts, we're skipping the rest of this function if we get here
+    # during a perl syntax check (perl -c, like we do during the
+    # 001compile.t test).
+    return if $^C;
+
</ins><span class="cx">     # IIS prints out warnings to the webpage, so ignore them, or log them
</span><span class="cx">     # to a file if the file exists.
</span><span class="cx">     if ($ENV{SERVER_SOFTWARE} &amp;&amp; $ENV{SERVER_SOFTWARE} =~ /microsoft-iis/i) {
</span><span class="lines">@@ -102,25 +123,27 @@
</span><span class="cx">         };
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    my $script = basename($0);
+
+    # Because of attachment_base, attachment.cgi handles this itself.
+    if ($script ne 'attachment.cgi') {
+        do_ssl_redirect_if_required();
+    }
+
</ins><span class="cx">     # If Bugzilla is shut down, do not allow anything to run, just display a
</span><span class="cx">     # message to the user about the downtime and log out.  Scripts listed in 
</span><span class="cx">     # SHUTDOWNHTML_EXEMPT are exempt from this message.
</span><span class="cx">     #
</span><del>-    # Because this is code which is run live from perl &quot;use&quot; commands of other
-    # scripts, we're skipping this part if we get here during a perl syntax 
-    # check -- runtests.pl compiles scripts without running them, so we 
-    # need to make sure that this check doesn't apply to 'perl -c' calls.
-    #
</del><span class="cx">     # This code must go here. It cannot go anywhere in Bugzilla::CGI, because
</span><span class="cx">     # it uses Template, and that causes various dependency loops.
</span><del>-    if (!$^C &amp;&amp; Bugzilla-&gt;params-&gt;{&quot;shutdownhtml&quot;} 
-        &amp;&amp; lsearch(SHUTDOWNHTML_EXEMPT, basename($0)) == -1)
</del><ins>+    if (Bugzilla-&gt;params-&gt;{&quot;shutdownhtml&quot;}
+        &amp;&amp; !grep { $_ eq $script } SHUTDOWNHTML_EXEMPT)
</ins><span class="cx">     {
</span><span class="cx">         # Allow non-cgi scripts to exit silently (without displaying any
</span><span class="cx">         # message), if desired. At this point, no DBI call has been made
</span><span class="cx">         # yet, and no error will be returned if the DB is inaccessible.
</span><del>-        if (lsearch(SHUTDOWNHTML_EXIT_SILENTLY, basename($0)) &gt; -1
-            &amp;&amp; !i_am_cgi())
</del><ins>+        if (!i_am_cgi()
+            &amp;&amp; grep { $_ eq $script } SHUTDOWNHTML_EXIT_SILENTLY)
</ins><span class="cx">         {
</span><span class="cx">             exit;
</span><span class="cx">         }
</span><span class="lines">@@ -151,7 +174,12 @@
</span><span class="cx">         else {
</span><span class="cx">             $extension = 'txt';
</span><span class="cx">         }
</span><del>-        print Bugzilla-&gt;cgi-&gt;header() if i_am_cgi();
</del><ins>+        if (i_am_cgi()) {
+            # Set the HTTP status to 503 when Bugzilla is down to avoid pages
+            # being indexed by search engines.
+            print Bugzilla-&gt;cgi-&gt;header(-status =&gt; 503, 
+                -retry_after =&gt; SHUTDOWNHTML_RETRY_AFTER);
+        }
</ins><span class="cx">         my $t_output;
</span><span class="cx">         $template-&gt;process(&quot;global/message.$extension.tmpl&quot;, $vars, \$t_output)
</span><span class="cx">             || ThrowTemplateError($template-&gt;error);
</span><span class="lines">@@ -160,34 +188,103 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-init_page() if !$ENV{MOD_PERL};
-
</del><span class="cx"> #####################################################################
</span><span class="cx"> # Subroutines and Methods
</span><span class="cx"> #####################################################################
</span><span class="cx"> 
</span><span class="cx"> sub template {
</span><span class="cx">     my $class = shift;
</span><del>-    $class-&gt;request_cache-&gt;{language} = &quot;&quot;;
</del><span class="cx">     $class-&gt;request_cache-&gt;{template} ||= Bugzilla::Template-&gt;create();
</span><span class="cx">     return $class-&gt;request_cache-&gt;{template};
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub template_inner {
</span><span class="cx">     my ($class, $lang) = @_;
</span><del>-    $lang = defined($lang) ? $lang : ($class-&gt;request_cache-&gt;{language} || &quot;&quot;);
-    $class-&gt;request_cache-&gt;{language} = $lang;
</del><ins>+    my $cache = $class-&gt;request_cache;
+    my $current_lang = $cache-&gt;{template_current_lang}-&gt;[0];
+    $lang ||= $current_lang || '';
</ins><span class="cx">     $class-&gt;request_cache-&gt;{&quot;template_inner_$lang&quot;}
</span><del>-        ||= Bugzilla::Template-&gt;create();
</del><ins>+        ||= Bugzilla::Template-&gt;create(language =&gt; $lang);
</ins><span class="cx">     return $class-&gt;request_cache-&gt;{&quot;template_inner_$lang&quot;};
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+our $extension_packages;
+sub extensions {
+    my ($class) = @_;
+    my $cache = $class-&gt;request_cache;
+    if (!$cache-&gt;{extensions}) {
+        # Under mod_perl, mod_perl.pl populates $extension_packages for us.
+        if (!$extension_packages) {
+            $extension_packages = Bugzilla::Extension-&gt;load_all();
+        }
+        my @extensions;
+        foreach my $package (@$extension_packages) {
+            my $extension = $package-&gt;new();
+            if ($extension-&gt;enabled) {
+                push(@extensions, $extension);
+            }        
+        }
+        $cache-&gt;{extensions} = \@extensions;
+    }
+    return $cache-&gt;{extensions};
+}
+
+sub feature {
+    my ($class, $feature) = @_;
+    my $cache = $class-&gt;request_cache;
+    return $cache-&gt;{feature}-&gt;{$feature}
+        if exists $cache-&gt;{feature}-&gt;{$feature};
+
+    my $feature_map = $cache-&gt;{feature_map};
+    if (!$feature_map) {
+        foreach my $package (@{ OPTIONAL_MODULES() }) {
+            foreach my $f (@{ $package-&gt;{feature} }) {
+                $feature_map-&gt;{$f} ||= [];
+                push(@{ $feature_map-&gt;{$f} }, $package-&gt;{module});
+            }
+        }
+        $cache-&gt;{feature_map} = $feature_map;
+    }
+
+    if (!$feature_map-&gt;{$feature}) {
+        ThrowCodeError('invalid_feature', { feature =&gt; $feature });
+    }
+
+    my $success = 1;
+    foreach my $module (@{ $feature_map-&gt;{$feature} }) {
+        # We can't use a string eval and &quot;use&quot; here (it kills Template-Toolkit,
+        # see https://rt.cpan.org/Public/Bug/Display.html?id=47929), so we have
+        # to do a block eval.
+        $module =~ s{::}{/}g;
+        $module .= &quot;.pm&quot;;
+        eval { require $module; 1; } or $success = 0;
+    }
+    $cache-&gt;{feature}-&gt;{$feature} = $success;
+    return $success;
+}
+
</ins><span class="cx"> sub cgi {
</span><span class="cx">     my $class = shift;
</span><span class="cx">     $class-&gt;request_cache-&gt;{cgi} ||= new Bugzilla::CGI();
</span><span class="cx">     return $class-&gt;request_cache-&gt;{cgi};
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub input_params {
+    my ($class, $params) = @_;
+    my $cache = $class-&gt;request_cache;
+    # This is how the WebService and other places set input_params.
+    if (defined $params) {
+        $cache-&gt;{input_params} = $params;
+    }
+    return $cache-&gt;{input_params} if defined $cache-&gt;{input_params};
+
+    # Making this scalar makes it a tied hash to the internals of $cgi,
+    # so if a variable is changed, then it actually changes the $cgi object
+    # as well.
+    $cache-&gt;{input_params} = $class-&gt;cgi-&gt;Vars;
+    return $cache-&gt;{input_params};
+}
+
</ins><span class="cx"> sub localconfig {
</span><span class="cx">     my $class = shift;
</span><span class="cx">     $class-&gt;request_cache-&gt;{localconfig} ||= read_localconfig();
</span><span class="lines">@@ -223,6 +320,10 @@
</span><span class="cx">     # NOTE: If you want to log the start of an sudo session, do it here.
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub page_requires_login {
+    return $_[0]-&gt;request_cache-&gt;{page_requires_login};
+}
+
</ins><span class="cx"> sub login {
</span><span class="cx">     my ($class, $type) = @_;
</span><span class="cx"> 
</span><span class="lines">@@ -230,9 +331,17 @@
</span><span class="cx"> 
</span><span class="cx">     my $authorizer = new Bugzilla::Auth();
</span><span class="cx">     $type = LOGIN_REQUIRED if $class-&gt;cgi-&gt;param('GoAheadAndLogIn');
</span><ins>+
</ins><span class="cx">     if (!defined $type || $type == LOGIN_NORMAL) {
</span><span class="cx">         $type = $class-&gt;params-&gt;{'requirelogin'} ? LOGIN_REQUIRED : LOGIN_NORMAL;
</span><span class="cx">     }
</span><ins>+
+    # Allow templates to know that we're in a page that always requires
+    # login.
+    if ($type == LOGIN_REQUIRED) {
+        $class-&gt;request_cache-&gt;{page_requires_login} = 1;
+    }
+
</ins><span class="cx">     my $authenticated_user = $authorizer-&gt;login($type);
</span><span class="cx">     
</span><span class="cx">     # At this point, we now know if a real person is logged in.
</span><span class="lines">@@ -243,37 +352,42 @@
</span><span class="cx">     # 3: There must be a valid value in the 'sudo' cookie
</span><span class="cx">     # 4: A Bugzilla::User object must exist for the given cookie value
</span><span class="cx">     # 5: That user must NOT be in the 'bz_sudo_protect' group
</span><del>-    my $sudo_cookie = $class-&gt;cgi-&gt;cookie('sudo');
-    detaint_natural($sudo_cookie) if defined($sudo_cookie);
-    my $sudo_target;
-    $sudo_target = new Bugzilla::User($sudo_cookie) if defined($sudo_cookie);
-    if (defined($authenticated_user)                 &amp;&amp;
-        $authenticated_user-&gt;in_group('bz_sudoers')  &amp;&amp;
-        defined($sudo_cookie)                        &amp;&amp;
-        defined($sudo_target)                        &amp;&amp;
-        !($sudo_target-&gt;in_group('bz_sudo_protect'))
-       )
-    {
-        $class-&gt;set_user($sudo_target);
-        $class-&gt;request_cache-&gt;{sudoer} = $authenticated_user;
-        # And make sure that both users have the same Auth object,
-        # since we never call Auth::login for the sudo target.
-        $sudo_target-&gt;set_authorizer($authenticated_user-&gt;authorizer);
</del><ins>+    my $token = $class-&gt;cgi-&gt;cookie('sudo');
+    if (defined $authenticated_user &amp;&amp; $token) {
+        my ($user_id, $date, $sudo_target_id) = Bugzilla::Token::GetTokenData($token);
+        if (!$user_id
+            || $user_id != $authenticated_user-&gt;id
+            || !detaint_natural($sudo_target_id)
+            || (time() - str2time($date) &gt; MAX_SUDO_TOKEN_AGE))
+        {
+            $class-&gt;cgi-&gt;remove_cookie('sudo');
+            ThrowUserError('sudo_invalid_cookie');
+        }
</ins><span class="cx"> 
</span><del>-        # NOTE: If you want to do any special logging, do it here.
</del><ins>+        my $sudo_target = new Bugzilla::User($sudo_target_id);
+        if ($authenticated_user-&gt;in_group('bz_sudoers')
+            &amp;&amp; defined $sudo_target
+            &amp;&amp; !$sudo_target-&gt;in_group('bz_sudo_protect'))
+        {
+            $class-&gt;set_user($sudo_target);
+            $class-&gt;request_cache-&gt;{sudoer} = $authenticated_user;
+            # And make sure that both users have the same Auth object,
+            # since we never call Auth::login for the sudo target.
+            $sudo_target-&gt;set_authorizer($authenticated_user-&gt;authorizer);
+
+            # NOTE: If you want to do any special logging, do it here.
+        }
+        else {
+            delete_token($token);
+            $class-&gt;cgi-&gt;remove_cookie('sudo');
+            ThrowUserError('sudo_illegal_action', { sudoer =&gt; $authenticated_user,
+                                                    target_user =&gt; $sudo_target });
+        }
</ins><span class="cx">     }
</span><span class="cx">     else {
</span><span class="cx">         $class-&gt;set_user($authenticated_user);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    # We run after the login has completed since
-    # some of the checks in ssl_require_redirect
-    # look for Bugzilla-&gt;user-&gt;id to determine 
-    # if redirection is required.
-    if (i_am_cgi() &amp;&amp; ssl_require_redirect()) {
-        $class-&gt;cgi-&gt;require_https($class-&gt;params-&gt;{'sslbase'});
-    }
-    
</del><span class="cx">     return $class-&gt;user;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -311,33 +425,30 @@
</span><span class="cx">     # there. Don't rely on it: use Bugzilla-&gt;user-&gt;login instead!
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub job_queue {
+    my $class = shift;
+    require Bugzilla::JobQueue;
+    $class-&gt;request_cache-&gt;{job_queue} ||= Bugzilla::JobQueue-&gt;new();
+    return $class-&gt;request_cache-&gt;{job_queue};
+}
+
</ins><span class="cx"> sub dbh {
</span><span class="cx">     my $class = shift;
</span><span class="cx">     # If we're not connected, then we must want the main db
</span><del>-    $class-&gt;request_cache-&gt;{dbh} ||= $class-&gt;request_cache-&gt;{dbh_main} 
-        = Bugzilla::DB::connect_main();
</del><ins>+    $class-&gt;request_cache-&gt;{dbh} ||= $class-&gt;dbh_main;
</ins><span class="cx"> 
</span><span class="cx">     return $class-&gt;request_cache-&gt;{dbh};
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub dbh_main {
+    my $class = shift;
+    $class-&gt;request_cache-&gt;{dbh_main} ||= Bugzilla::DB::connect_main();
+    return $class-&gt;request_cache-&gt;{dbh_main};
+}
+
</ins><span class="cx"> sub languages {
</span><span class="cx">     my $class = shift;
</span><del>-    return $class-&gt;request_cache-&gt;{languages}
-        if $class-&gt;request_cache-&gt;{languages};
-
-    my @files = glob(catdir(bz_locations-&gt;{'templatedir'}, '*'));
-    my @languages;
-    foreach my $dir_entry (@files) {
-        # It's a language directory only if it contains &quot;default&quot; or
-        # &quot;custom&quot;. This auto-excludes CVS directories as well.
-        next unless (-d catdir($dir_entry, 'default')
-                  || -d catdir($dir_entry, 'custom'));
-        $dir_entry = basename($dir_entry);
-        # Check for language tag format conforming to RFC 1766.
-        next unless $dir_entry =~ /^[a-zA-Z]{1,8}(-[a-zA-Z]{1,8})?$/;
-        push(@languages, $dir_entry);
-    }
-    return $class-&gt;request_cache-&gt;{languages} = \@languages;
</del><ins>+    return Bugzilla::Install::Util::supported_languages();
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub error_mode {
</span><span class="lines">@@ -346,9 +457,18 @@
</span><span class="cx">         $class-&gt;request_cache-&gt;{error_mode} = $newval;
</span><span class="cx">     }
</span><span class="cx">     return $class-&gt;request_cache-&gt;{error_mode}
</span><del>-        || Bugzilla::Constants::ERROR_MODE_WEBPAGE;
</del><ins>+        || (i_am_cgi() ? ERROR_MODE_WEBPAGE : ERROR_MODE_DIE);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# This is used only by Bugzilla::Error to throw errors.
+sub _json_server {
+    my ($class, $newval) = @_;
+    if (defined $newval) {
+        $class-&gt;request_cache-&gt;{_json_server} = $newval;
+    }
+    return $class-&gt;request_cache-&gt;{_json_server};
+}
+
</ins><span class="cx"> sub usage_mode {
</span><span class="cx">     my ($class, $newval) = @_;
</span><span class="cx">     if (defined $newval) {
</span><span class="lines">@@ -358,12 +478,18 @@
</span><span class="cx">         elsif ($newval == USAGE_MODE_CMDLINE) {
</span><span class="cx">             $class-&gt;error_mode(ERROR_MODE_DIE);
</span><span class="cx">         }
</span><del>-        elsif ($newval == USAGE_MODE_WEBSERVICE) {
</del><ins>+        elsif ($newval == USAGE_MODE_XMLRPC) {
</ins><span class="cx">             $class-&gt;error_mode(ERROR_MODE_DIE_SOAP_FAULT);
</span><span class="cx">         }
</span><ins>+        elsif ($newval == USAGE_MODE_JSON) {
+            $class-&gt;error_mode(ERROR_MODE_JSON_RPC);
+        }
</ins><span class="cx">         elsif ($newval == USAGE_MODE_EMAIL) {
</span><span class="cx">             $class-&gt;error_mode(ERROR_MODE_DIE);
</span><span class="cx">         }
</span><ins>+        elsif ($newval == USAGE_MODE_TEST) {
+            $class-&gt;error_mode(ERROR_MODE_TEST);
+        }
</ins><span class="cx">         else {
</span><span class="cx">             ThrowCodeError('usage_mode_invalid',
</span><span class="cx">                            {'invalid_usage_mode', $newval});
</span><span class="lines">@@ -371,7 +497,7 @@
</span><span class="cx">         $class-&gt;request_cache-&gt;{usage_mode} = $newval;
</span><span class="cx">     }
</span><span class="cx">     return $class-&gt;request_cache-&gt;{usage_mode}
</span><del>-        || Bugzilla::Constants::USAGE_MODE_BROWSER;
</del><ins>+        || (i_am_cgi()? USAGE_MODE_BROWSER : USAGE_MODE_CMDLINE);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub installation_mode {
</span><span class="lines">@@ -403,7 +529,7 @@
</span><span class="cx">         if ($class-&gt;params-&gt;{'shadowdb'}) {
</span><span class="cx">             $class-&gt;request_cache-&gt;{dbh_shadow} = Bugzilla::DB::connect_shadow();
</span><span class="cx">         } else {
</span><del>-            $class-&gt;request_cache-&gt;{dbh_shadow} = request_cache()-&gt;{dbh_main};
</del><ins>+            $class-&gt;request_cache-&gt;{dbh_shadow} = $class-&gt;dbh_main;
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -417,21 +543,56 @@
</span><span class="cx"> sub switch_to_main_db {
</span><span class="cx">     my $class = shift;
</span><span class="cx"> 
</span><del>-    $class-&gt;request_cache-&gt;{dbh} = $class-&gt;request_cache-&gt;{dbh_main};
-    # We have to return $class-&gt;dbh instead of {dbh} as
-    # {dbh_main} may be undefined if no connection to the main DB
-    # has been established yet.
-    return $class-&gt;dbh;
</del><ins>+    $class-&gt;request_cache-&gt;{dbh} = $class-&gt;dbh_main;
+    return $class-&gt;dbh_main;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub get_fields {
-    my $class = shift;
-    my $criteria = shift;
-    # This function may be called during installation, and Field::match
-    # may fail at that time. so we want to return an empty list in that
-    # case.
-    my $fields = eval { Bugzilla::Field-&gt;match($criteria) } || [];
-    return @$fields;
</del><ins>+sub fields {
+    my ($class, $criteria) = @_;
+    $criteria ||= {};
+    my $cache = $class-&gt;request_cache;
+
+    # We create an advanced cache for fields by type, so that we
+    # can avoid going back to the database for every fields() call.
+    # (And most of our fields() calls are for getting fields by type.)
+    #
+    # We also cache fields by name, because calling $field-&gt;name a few
+    # million times can be slow in calling code, but if we just do it
+    # once here, that makes things a lot faster for callers.
+    if (!defined $cache-&gt;{fields}) {
+        my @all_fields = Bugzilla::Field-&gt;get_all;
+        my (%by_name, %by_type);
+        foreach my $field (@all_fields) {
+            my $name = $field-&gt;name;
+            $by_type{$field-&gt;type}-&gt;{$name} = $field;
+            $by_name{$name} = $field;
+        }
+        $cache-&gt;{fields} = { by_type =&gt; \%by_type, by_name =&gt; \%by_name };
+    }
+
+    my $fields = $cache-&gt;{fields};
+    my %requested;
+    if (my $types = delete $criteria-&gt;{type}) {
+        $types = ref($types) ? $types : [$types];
+        %requested = map { %{ $fields-&gt;{by_type}-&gt;{$_} || {} } } @$types;
+    }
+    else {
+        %requested = %{ $fields-&gt;{by_name} };
+    }
+
+    my $do_by_name = delete $criteria-&gt;{by_name};
+
+    # Filtering before returning the fields based on
+    # the criterias.
+    foreach my $filter (keys %$criteria) {
+        foreach my $field (keys %requested) {
+            if ($requested{$field}-&gt;$filter != $criteria-&gt;{$filter}) {
+                delete $requested{$field};
+            }
+        }
+    }
+
+    return $do_by_name ? \%requested : [values %requested];
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub active_custom_fields {
</span><span class="lines">@@ -447,21 +608,35 @@
</span><span class="cx">     my $class = shift;
</span><span class="cx"> 
</span><span class="cx">     if (!defined $class-&gt;request_cache-&gt;{has_flags}) {
</span><del>-        $class-&gt;request_cache-&gt;{has_flags} = Bugzilla::Flag::has_flags();
</del><ins>+        $class-&gt;request_cache-&gt;{has_flags} = Bugzilla::Flag-&gt;any_exist;
</ins><span class="cx">     }
</span><span class="cx">     return $class-&gt;request_cache-&gt;{has_flags};
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub hook_args {
-    my ($class, $args) = @_;
-    $class-&gt;request_cache-&gt;{hook_args} = $args if $args;
-    return $class-&gt;request_cache-&gt;{hook_args};
</del><ins>+sub local_timezone {
+    my $class = shift;
+
+    if (!defined $class-&gt;request_cache-&gt;{local_timezone}) {
+        $class-&gt;request_cache-&gt;{local_timezone} =
+          DateTime::TimeZone-&gt;new(name =&gt; 'local');
+    }
+    return $class-&gt;request_cache-&gt;{local_timezone};
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# This creates the request cache for non-mod_perl installations.
+# This is identical to Install::Util::_cache so that things loaded
+# into Install::Util::_cache during installation can be read out
+# of request_cache later in installation.
+our $_request_cache = $Bugzilla::Install::Util::_cache;
+
</ins><span class="cx"> sub request_cache {
</span><span class="cx">     if ($ENV{MOD_PERL}) {
</span><span class="cx">         require Apache2::RequestUtil;
</span><del>-        return Apache2::RequestUtil-&gt;request-&gt;pnotes();
</del><ins>+        # Sometimes (for example, during mod_perl.pl), the request
+        # object isn't available, and we should use $_request_cache instead.
+        my $request = eval { Apache2::RequestUtil-&gt;request };
+        return $_request_cache if !$request;
+        return $request-&gt;pnotes();
</ins><span class="cx">     }
</span><span class="cx">     return $_request_cache;
</span><span class="cx"> }
</span><span class="lines">@@ -479,6 +654,12 @@
</span><span class="cx">         $dbh-&gt;disconnect;
</span><span class="cx">     }
</span><span class="cx">     undef $_request_cache;
</span><ins>+
+    # These are both set by CGI.pm but need to be undone so that
+    # Apache can actually shut down its children if it needs to.
+    foreach my $signal (qw(TERM PIPE)) {
+        $SIG{$signal} = 'DEFAULT' if $SIG{$signal} &amp;&amp; $SIG{$signal} eq 'IGNORE';
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub END {
</span><span class="lines">@@ -486,6 +667,8 @@
</span><span class="cx">     _cleanup() unless $ENV{MOD_PERL};
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+init_page() if !$ENV{MOD_PERL};
+
</ins><span class="cx"> 1;
</span><span class="cx"> 
</span><span class="cx"> __END__
</span><span class="lines">@@ -569,6 +752,26 @@
</span><span class="cx"> general. Not all Bugzilla actions are cgi requests. Its useful as a convenience
</span><span class="cx"> method for those scripts/templates which are only use via CGI, though.
</span><span class="cx"> 
</span><ins>+=item C&lt;input_params&gt;
+
+When running under the WebService, this is a hashref containing the arguments
+passed to the WebService method that was called. When running in a normal
+script, this is a hashref containing the contents of the CGI parameters.
+
+Modifying this hashref will modify the CGI parameters or the WebService
+arguments (depending on what C&lt;input_params&gt; currently represents).
+
+This should be used instead of L&lt;/cgi&gt; in situations where your code
+could be being called by either a normal CGI script or a WebService method,
+such as during a code hook.
+
+B&lt;Note:&gt; When C&lt;input_params&gt; represents the CGI parameters, any
+parameter specified more than once (like C&lt;foo=bar&amp;foo=baz&gt;) will appear
+as an arrayref in the hash, but any value specified only once will appear
+as a scalar. This means that even if a value I&lt;can&gt; appear multiple times,
+if it only I&lt;does&gt; appear once, then it will be a scalar in C&lt;input_params&gt;,
+not an arrayref.
+
</ins><span class="cx"> =item C&lt;user&gt;
</span><span class="cx"> 
</span><span class="cx"> C&lt;undef&gt; if there is no currently logged in user or if the login code has not
</span><span class="lines">@@ -602,6 +805,13 @@
</span><span class="cx"> no logged in user. See L&lt;Bugzilla::Auth|Bugzilla::Auth&gt;, and
</span><span class="cx"> L&lt;Bugzilla::User|Bugzilla::User&gt;.
</span><span class="cx"> 
</span><ins>+=item C&lt;page_requires_login&gt;
+
+If the current page always requires the user to log in (for example,
+C&lt;enter_bug.cgi&gt; or any page called with C&lt;?GoAheadAndLogIn=1&gt;) then
+this will return something true. Otherwise it will return false. (This is
+set when you call L&lt;/login&gt;.)
+
</ins><span class="cx"> =item C&lt;logout($option)&gt;
</span><span class="cx"> 
</span><span class="cx"> Logs out the current user, which involves invalidating user sessions and
</span><span class="lines">@@ -626,6 +836,30 @@
</span><span class="cx"> effect of logging out a user for the current request only; cookies and
</span><span class="cx"> database sessions are left intact.
</span><span class="cx"> 
</span><ins>+=item C&lt;fields&gt;
+
+This is the standard way to get arrays or hashes of L&lt;Bugzilla::Field&gt;
+objects when you need them. It takes the following named arguments
+in a hashref:
+
+=over
+
+=item C&lt;by_name&gt;
+
+If false (or not specified), this method will return an arrayref of
+the requested fields. The order of the returned fields is random.
+
+If true, this method will return a hashref of fields, where the keys
+are field names and the valules are L&lt;Bugzilla::Field&gt; objects.
+
+=item C&lt;type&gt;
+
+Either a single C&lt;FIELD_TYPE_*&gt; constant or an arrayref of them. If specified,
+the returned fields will be limited to the types in the list. If you don't
+specify this argument, all fields will be returned.
+
+=back
+
</ins><span class="cx"> =item C&lt;error_mode&gt;
</span><span class="cx"> 
</span><span class="cx"> Call either C&lt;Bugzilla-&gt;error_mode(Bugzilla::Constants::ERROR_MODE_DIE)&gt;
</span><span class="lines">@@ -646,10 +880,11 @@
</span><span class="cx"> =item C&lt;usage_mode&gt;
</span><span class="cx"> 
</span><span class="cx"> Call either C&lt;Bugzilla-&gt;usage_mode(Bugzilla::Constants::USAGE_MODE_CMDLINE)&gt;
</span><del>-or C&lt;Bugzilla-&gt;usage_mode(Bugzilla::Constants::USAGE_MODE_WEBSERVICE)&gt; near the
</del><ins>+or C&lt;Bugzilla-&gt;usage_mode(Bugzilla::Constants::USAGE_MODE_XMLRPC)&gt; near the
</ins><span class="cx"> beginning of your script to change this flag's default of
</span><span class="cx"> C&lt;Bugzilla::Constants::USAGE_MODE_BROWSER&gt; and to indicate that Bugzilla is
</span><span class="cx"> being called in a non-interactive manner.
</span><ins>+
</ins><span class="cx"> This influences error handling because on usage mode changes, C&lt;usage_mode&gt;
</span><span class="cx"> calls C&lt;Bugzilla-&gt;error_mode&gt; to set an error mode which makes sense for the
</span><span class="cx"> usage mode.
</span><span class="lines">@@ -670,6 +905,10 @@
</span><span class="cx"> 
</span><span class="cx"> The current database handle. See L&lt;DBI&gt;.
</span><span class="cx"> 
</span><ins>+=item C&lt;dbh_main&gt;
+
+The main database handle. See L&lt;DBI&gt;.
+
</ins><span class="cx"> =item C&lt;languages&gt;
</span><span class="cx"> 
</span><span class="cx"> Currently installed languages.
</span><span class="lines">@@ -689,9 +928,21 @@
</span><span class="cx"> does not exist, then we return an empty hashref. If C&lt;data/params&gt;
</span><span class="cx"> is unreadable or is not valid perl, we C&lt;die&gt;.
</span><span class="cx"> 
</span><del>-=item C&lt;hook_args&gt;
</del><ins>+=item C&lt;local_timezone&gt;
</ins><span class="cx"> 
</span><del>-If you are running inside a code hook (see L&lt;Bugzilla::Hook&gt;) this
-is how you get the arguments passed to the hook.
</del><ins>+Returns the local timezone of the Bugzilla installation,
+as a DateTime::TimeZone object. This detection is very time
+consuming, so we cache this information for future references.
</ins><span class="cx"> 
</span><ins>+=item C&lt;job_queue&gt;
+
+Returns a L&lt;Bugzilla::JobQueue&gt; that you can use for queueing jobs.
+Will throw an error if job queueing is not correctly configured on
+this Bugzilla installation.
+
+=item C&lt;feature&gt;
+
+Tells you whether or not a specific feature is enabled. For names
+of features, see C&lt;OPTIONAL_MODULES&gt; in C&lt;Bugzilla::Install::Requirements&gt;.
+
</ins><span class="cx"> =back
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgQUICKSTART"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/QUICKSTART (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/QUICKSTART        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/QUICKSTART        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,84 +0,0 @@
</span><del>-Bugzilla Quick Start Guide 
-==========================
-(or, how to get Bugzilla up and running in 10 steps)
-Christian Reis &lt;kiko@async.com.br&gt;
-
-This express installation guide is for &quot;normal&quot; Bugzilla installations,
-which means a Linux or Unix system on which Apache, Perl, MySQL or PostgreSQL
-and a Sendmail compatible MTA are available. For other configurations, please
-see Section 4 of the Bugzilla Guide in the docs/ directory. 
-
-1. Decide from which URL and directory under your webserver root you
-   will be serving the Bugzilla webpages.
-
-2. Unpack the distribution into the chosen directory (there is no copying or
-   installation involved). 
-
-3. Run ./checksetup.pl, look for unsolved requirements, and install them.
-   You can run checksetup as many times as necessary to check if
-   everything required has been installed.
-
-   These will usually include assorted Perl modules, MySQL or PostgreSQL,
-   and a MTA.
-
-   After a successful dependency check, checksetup should complain that
-   localconfig needs to be edited.
-
-4. Edit the localconfig file, in particular the $webservergroup and 
-   $db_* variables. In particular, $db_name and $db_user will define
-   your database setup in step 5.
-
-5. Using the name you provided as $db_name above, create a MySQL database
-   for Bugzilla. You should also create a user permission for the name
-   supplied as $db_user with read/write access to that database.
-
-   If you are not familiar with MySQL permissions, it's a good idea to
-   use the mysql_setpermission script that is installed with the MySQL
-   distribution, and be sure to read Bugzilla Security - MySQL section
-   in the Bugzilla Guide or PostgreSQL documentation.
-
-6. Run checksetup.pl once more; if all goes well, it should set up the
-   Bugzilla database for you. If not, return to step 5.
-
-   checksetup.pl should ask you, this time, for the administrator's
-   email address and password. These will be used for the initial
-   Bugzilla administrator account.
-
-7. Configure Apache (or install and configure, if you don't have it up
-   yet) to point to the Bugzilla directory. You should enable and
-   activate mod_cgi, and add the configuration entries
-
-        Options +ExecCGI
-        AllowOverride Limit 
-        DirectoryIndex index.cgi
-
-   to your Bugzilla &lt;Directory&gt; block. You may also need
-
-        AddHandler cgi-script .cgi
-
-   if you don't have that in your Apache configuration file yet.
-
-8. Visit the URL you chose for Bugzilla. Your browser should display the
-   default Bugzilla home page. You should then log in as the
-   administrator by following the &quot;Log in&quot; link and supplying the
-   account information you provided in step 6.
-
-9. Scroll to the bottom of the page after logging in, and select
-   &quot;Parameters&quot;. Set up the relevant parameters for your local setup. 
-
-   See section 4.2 of the Bugzilla Guide for a in-depth description of
-   some of the configuration parameters available.
-
-10. That's it. If anything unexpected comes up:
-
-    - read the error message carefully,
-    - backtrack through the steps above, 
-    - check the official installation guide, which is section 4 in the
-      Bugzilla Guide, included in the docs/ directory in various
-      formats.
-
-Support and installation questions should be directed to the
-mozilla-webtools@mozilla.org mailing list -- don't write to the
-developer mailing list: your post *will* be ignored if you do.
-
-Further support information is at http://www.bugzilla.org/support/
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgREADME"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/README (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/README        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/README        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,19 +1,92 @@
</span><del>-* This README is no longer used to house installation instructions.  Instead,
-it contains pointers to where you may find the information you need.
</del><ins>+What is Bugzilla?
+=================
+Bugzilla is a free bug-tracking system that is developed by an active
+community of volunteers in the Mozilla community. You can install and
+use it without having to pay any license fee.
</ins><span class="cx"> 
</span><del>-* A quick installation guide is provided in the QUICKSTART file.
</del><ins>+Minimum requirements
+====================
+It can be installed on Windows, Mac OS X, Linux and other Unix flavors.
+Bugzilla is written in Perl, meaning that Perl must be installed on your system.
+You will also need a web server as well as a DB server (see below).
</ins><span class="cx"> 
</span><del>-* Complete installation instructions are found in docs/, with a
-variety of document types available.  Please refer to these documents
-when installing, configuring, and maintaining your Bugzilla
-installation.  A helpful starting point is docs/txt/Bugzilla-Guide.txt,
-or with a web browser at docs/html/index.html.
</del><ins>+Installation &amp; Upgrading
+========================
+The documentation to install, upgrade, configure and use Bugzilla can be found
+in different formats:
+* docs/en/html/Bugzilla-Guide.html (HTML version)
+* docs/en/txt/Bugzilla-Guide.txt (text version)
+* docs/en/pdf/Bugzilla-Guide.pdf (PDF version)
</ins><span class="cx"> 
</span><del>-* Release notes for people upgrading to a new version of Bugzilla are
-available at docs/rel_notes.txt.
</del><ins>+If the documentation is missing, you can get it online by visiting
+http://www.bugzilla.org/docs/ from where you can select the documentation
+corresponding to the Bugzilla version you are installing.
</ins><span class="cx"> 
</span><del>-* If you wish to contribute to the documentation, please read docs/README.docs.
</del><ins>+Bugzilla Quick Start Guide
+==========================
+(or, how to get Bugzilla up and running in 10 steps)
+Christian Reis &lt;kiko@async.com.br&gt;
</ins><span class="cx"> 
</span><del>-* The Bugzilla web site is at &quot;http://www.bugzilla.org/&quot;.  This site will
-contain the latest Bugzilla information, including how to report bugs and how
-to get help with Bugzilla.
</del><ins>+This express installation guide is for &quot;normal&quot; Bugzilla installations,
+which means a Linux or Unix system on which Apache, Perl, MySQL or PostgreSQL
+and a Sendmail compatible MTA are available. For other configurations, please
+see the &quot;Installing Bugzilla&quot; section of the Bugzilla Guide in the docs/ directory.
+
+1. Decide from which URL and directory under your webserver root you
+   will be serving the Bugzilla webpages.
+
+2. Unpack the distribution into the chosen directory (there is no copying or
+   installation involved).
+
+3. Run ./checksetup.pl, look for unsolved requirements, and install them.
+   You can run checksetup as many times as necessary to check if
+   everything required has been installed.
+
+   These will usually include assorted Perl modules, MySQL or PostgreSQL,
+   and a MTA.
+
+   After a successful dependency check, checksetup should complain that
+   localconfig needs to be edited.
+
+4. Edit the localconfig file, in particular the $webservergroup and
+   $db_* variables. In particular, $db_name and $db_user will define
+   your database setup in step 5.
+
+5. Create a user permission for the name supplied as $db_user with
+   read/write access to the database whose name is given by $db_name.
+
+   If you are not familiar with MySQL permissions, it's a good idea to
+   use the mysql_setpermission script that is installed with the MySQL
+   distribution, and be sure to read Bugzilla Security - MySQL section
+   in the Bugzilla Guide or PostgreSQL documentation.
+
+6. Run checksetup.pl once more; if all goes well, it should set up the
+   Bugzilla database for you. If not, return to step 5.
+
+   checksetup.pl should ask you, this time, for the administrator's
+   email address and password. These will be used for the initial
+   Bugzilla administrator account.
+
+7. Configure Apache (or install and configure, if you don't have it up
+   yet) to point to the Bugzilla directory. You can choose between
+   mod_cgi and mod_perl. The Bugzilla documentation has detailed information
+   for both modes.
+
+8. Visit the URL you chose for Bugzilla. Your browser should display the
+   default Bugzilla home page. You should then log in as the
+   administrator by following the &quot;Log in&quot; link and supplying the
+   account information you provided in step 6.
+
+9. Visit the &quot;Parameters&quot; page, as suggested by the page displayed to you.
+   Set up the relevant parameters for your local setup.
+
+10. That's it. If anything unexpected comes up:
+
+    - read the error message carefully,
+    - backtrack through the steps above,
+    - check the official installation guide.
+
+Support and installation questions should be directed to the
+support-bugzilla@lists.mozilla.org mailing list.
+
+Further support information is at http://www.bugzilla.org/support/
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgUPGRADING"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/UPGRADING (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/UPGRADING        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/UPGRADING        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,3 +0,0 @@
</span><del>-Please consult The Bugzilla Guide for instructions on how to upgrade
-Bugzilla from an older version.  The Guide can be found with this
-distribution, in docs/html, docs/txt, and docs/sgml.
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgUPGRADINGpre28"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/UPGRADING-pre-2.8 (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/UPGRADING-pre-2.8        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/UPGRADING-pre-2.8        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,412 +0,0 @@
</span><del>-This file contains only important changes made to Bugzilla before release
-2.8.  If you are upgrading from version older than 2.8, please read this file.
-If you are upgrading from 2.8 or newer, please read the Installation and
-Upgrade instructions in The Bugzilla Guide, found with this distribution in
-docs/html, docs/txt, and docs/sgml.
-
-Please note that the period in our version numbers is a place separator, not
-a decimal point.  The 14 in version 2.14 is newer than the 8 in 2.8, for
-example.  You should only be using this file if you have a single digit
-after the period in the version 2.x Bugzilla you are upgrading from.
-
-For a complete list of what changes, use Bonsai
-(http://cvs-mirror.mozilla.org/webtools/bonsai/cvsqueryform.cgi) to
-query the CVS tree.  For example,
-
-    http://cvs-mirror.mozilla.org/webtools/bonsai/cvsquery.cgi?module=all&amp;branch=HEAD&amp;branchtype=match&amp;dir=mozilla%2Fwebtools%2Fbugzilla&amp;file=&amp;filetype=match&amp;who=&amp;whotype=match&amp;sortby=Date&amp;hours=2&amp;date=week&amp;mindate=&amp;maxdate=&amp;cvsroot=%2Fcvsroot 
-
-will tell you what has been changed in the last week.
-
-
-10/12/99 The CHANGES file is now obsolete!  There is a new file called
-checksetup.pl.  You should get in the habit of running that file every time
-you update your installation of Bugzilla.  That file will be constantly 
-updated to automatically update your installation to match any code changes.
-If you're curious as to what is going on, changes are commented in that file, 
-at the end.
-
-Many thanks to Holger Schurig &lt;holgerschurig@nikocity.de&gt; for writing this
-script!
-
-
-
-10/11/99 Restructured voting database to add a cached value in each
-bug recording how many total votes that bug has.  While I'm at it, I
-removed the unused &quot;area&quot; field from the bugs database.  It is
-distressing to realize that the bugs table has reached the maximum
-number of indices allowed by MySQL (16), which may make future
-enhancements awkward.
-
-You must feed the following to MySQL:
-
-        alter table bugs drop column area;
-        alter table bugs add column votes mediumint not null, add index (votes);
-
-You then *must* delete the data/versioncache file when you make this
-change, as it contains references to the &quot;area&quot; field.  Deleting it is safe,
-bugzilla will correctly regenerate it.
-
-If you have been using the voting feature at all, then you will then
-need to update the voting cache.  You can do this by visiting the
-sanitycheck.cgi page, and taking it up on its offer to rebuild the
-votes stuff.
-
-
-10/7/99 Added voting ability.  You must run the new script
-&quot;makevotestable.sh&quot;.  You must also feed the following to mysql:
-
-        alter table products add column votesperuser smallint not null;
-
-
-
-9/15/99 Apparently, newer alphas of MySQL won't allow you to have
-&quot;when&quot; as a column name.  So, I have had to rename a column in the
-bugs_activity table.  You must feed the below to mysql or you won't
-work at all.
-
-        alter table bugs_activity change column when bug_when datetime not null;
-
-
-8/16/99 Added &quot;OpenVMS&quot; to the list of OS's. Feed this to mysql:
-
-        alter table bugs change column op_sys op_sys enum(&quot;All&quot;, &quot;Windows 3.1&quot;, &quot;Windows 95&quot;, &quot;Windows 98&quot;, &quot;Windows NT&quot;, &quot;Mac System 7&quot;, &quot;Mac System 7.5&quot;, &quot;Mac System 7.6.1&quot;, &quot;Mac System 8.0&quot;, &quot;Mac System 8.5&quot;, &quot;Mac System 8.6&quot;, &quot;AIX&quot;, &quot;BSDI&quot;, &quot;HP-UX&quot;, &quot;IRIX&quot;, &quot;Linux&quot;, &quot;FreeBSD&quot;, &quot;OSF/1&quot;, &quot;Solaris&quot;, &quot;SunOS&quot;, &quot;Neutrino&quot;, &quot;OS/2&quot;, &quot;BeOS&quot;, &quot;OpenVMS&quot;, &quot;other&quot;) not null;
-
-6/22/99 Added an entry to the attachments table to record who the submitter
-was.  Nothing uses this yet, but it still should be recorded.
-
-        alter table attachments add column submitter_id mediumint not null;
-
-You should also run this script to populate the new field:
-
-#!/usr/bin/perl -w
-use diagnostics;
-use strict;
-require &quot;globals.pl&quot;;
-$|=1;
-ConnectToDatabase();
-SendSQL(&quot;select bug_id, attach_id from attachments order by bug_id&quot;);
-my @list;
-while (MoreSQLData()) {
-    my @row = FetchSQLData();
-    push(@list, \@row);
-}
-foreach my $ref (@list) {
-    my ($bug, $attach) = (@$ref);
-    SendSQL(&quot;select long_desc from bugs where bug_id = $bug&quot;);
-    my $comment = FetchOneColumn() . &quot;Created an attachment (id=$attach)&quot;;
-
-    if ($comment =~ m@-* Additional Comments From ([^ ]*)[- 0-9/:]*\nCreated an attachment \(id=$attach\)@) {
-        print &quot;Found $1\n&quot;;
-        SendSQL(&quot;select userid from profiles where login_name=&quot; .
-                SqlQuote($1));
-        my $userid = FetchOneColumn();
-        if (defined $userid &amp;&amp; $userid &gt; 0) {
-            SendSQL(&quot;update attachments set submitter_id=$userid where attach_id = $attach&quot;);
-        }
-    } else {
-        print &quot;Bug $bug can't find comment for attachment $attach\n&quot;;
-    }
-}
-
-
-
-
-
-
-6/14/99 Added &quot;BeOS&quot; to the list of OS's. Feed this to mysql:
-
-        alter table bugs change column op_sys op_sys enum(&quot;All&quot;, &quot;Windows 3.1&quot;, &quot;Windows 95&quot;, &quot;Windows 98&quot;, &quot;Windows NT&quot;, &quot;Mac System 7&quot;, &quot;Mac System 7.5&quot;, &quot;Mac System 7.6.1&quot;, &quot;Mac System 8.0&quot;, &quot;Mac System 8.5&quot;, &quot;Mac System 8.6&quot;, &quot;AIX&quot;, &quot;BSDI&quot;, &quot;HP-UX&quot;, &quot;IRIX&quot;, &quot;Linux&quot;, &quot;FreeBSD&quot;, &quot;OSF/1&quot;, &quot;Solaris&quot;, &quot;SunOS&quot;, &quot;Neutrino&quot;, &quot;OS/2&quot;, &quot;BeOS&quot;, &quot;other&quot;) not null;
-
-
-5/27/99 Added support for dependency information.  You must run the new
-&quot;makedependenciestable.sh&quot; script.  You can turn off dependencies with the new
-&quot;usedependencies&quot; param, but it defaults to being on.  Also, read very
-carefully the description for the new &quot;webdotbase&quot; param; you will almost
-certainly need to tweak it.
-
-
-5/24/99 Added &quot;Mac System 8.6&quot; and &quot;Neutrino&quot; to the list of OS's.
-Feed this to mysql:
-
-        alter table bugs change column op_sys op_sys enum(&quot;All&quot;, &quot;Windows 3.1&quot;, &quot;Windows 95&quot;, &quot;Windows 98&quot;, &quot;Windows NT&quot;, &quot;Mac System 7&quot;, &quot;Mac System 7.5&quot;, &quot;Mac System 7.6.1&quot;, &quot;Mac System 8.0&quot;, &quot;Mac System 8.5&quot;, &quot;Mac System 8.6&quot;, &quot;AIX&quot;, &quot;BSDI&quot;, &quot;HP-UX&quot;, &quot;IRIX&quot;, &quot;Linux&quot;, &quot;FreeBSD&quot;, &quot;OSF/1&quot;, &quot;Solaris&quot;, &quot;SunOS&quot;, &quot;Neutrino&quot;, &quot;OS/2&quot;, &quot;other&quot;) not null;
-
-
-5/12/99 Added a pref to control how much email you get.  This needs a new
-column in the profiles table, so feed the following to mysql:
-
-        alter table profiles add column emailnotification enum(&quot;ExcludeSelfChanges&quot;, &quot;CConly&quot;, &quot;All&quot;) not null default &quot;ExcludeSelfChanges&quot;;
-
-5/5/99 Added the ability to search by creation date.  To make this perform
-well, you ought to do the following:
-
-        alter table bugs change column creation_ts creation_ts datetime not null, add index (creation_ts);
-
-
-4/30/99 Added a new severity, &quot;blocker&quot;.  To get this into your running
-Bugzilla, do the following:
-
-        alter table bugs change column bug_severity bug_severity enum(&quot;blocker&quot;, &quot;critical&quot;, &quot;major&quot;, &quot;normal&quot;, &quot;minor&quot;, &quot;trivial&quot;, &quot;enhancement&quot;) not null;
-
-
-4/22/99 There was a bug where the long descriptions of bugs had a variety of
-newline characters at the end, depending on the operating system of the browser
-that submitted the text.  This bug has been fixed, so that no further changes
-like that will happen.  But to fix problems that have already crept into your
-database, you can run the following perl script (which is slow and ugly, but
-does work:)
-#!/usr/bin/perl -w
-use diagnostics;
-use strict;
-require &quot;globals.pl&quot;;
-$|=1;
-ConnectToDatabase();
-SendSQL(&quot;select bug_id from bugs order by bug_id&quot;);
-my @list;
-while (MoreSQLData()) {
-    push(@list, FetchOneColumn());
-}
-foreach my $id (@list) {
-    if ($id % 50 == 0) {
-        print &quot;\n$id &quot;;
-    }
-    SendSQL(&quot;select long_desc from bugs where bug_id = $id&quot;);
-    my $comment = FetchOneColumn();
-    my $orig = $comment;
-    $comment =~ s/\r\n/\n/g;     # Get rid of windows-style line endings.
-    $comment =~ s/\r/\n/g;       # Get rid of mac-style line endings.
-    if ($comment ne $orig) {
-        SendSQL(&quot;update bugs set long_desc = &quot; . SqlQuote($comment) .
-                &quot; where bug_id = $id&quot;);
-        print &quot;.&quot;;
-    } else {
-        print &quot;-&quot;;
-    }
-}
-
-
-
-4/8/99 Added ability to store patches with bugs.  This requires a new table
-to store the data, so you will need to run the &quot;makeattachmenttable.sh&quot; script.
-
-3/25/99 Unfortunately, the HTML::FromText CPAN module had too many bugs, and
-so I had to roll my own.  We no longer use the HTML::FromText CPAN module.
-
-3/24/99 (This entry has been removed.  It used to say that we required the
-HTML::FromText CPAN module, but that's no longer true.)
-
-3/22/99 Added the ability to query by fields which have changed within a date
-range.  To make this perform a bit better, we need a new index:
-
-        alter table bugs_activity add index (field);
-
-3/10/99 Added 'groups' stuff, where we have different group bits that we can
-put on a person or on a bug.  Some of the group bits control access to bugzilla
-features.  And a person can't access a bug unless he has every group bit set
-that is also set on the bug.  See the comments in makegroupstable.sh for a bit
-more info.
-
-The 'maintainer' param is now used only as an email address for people to send
-complaints to.  The groups table is what is now used to determine permissions.
-
-You will need to run the new script &quot;makegroupstable.sh&quot;.  And then you need to
-feed the following lines to MySQL (replace XXX with the login name of the
-maintainer, the person you wish to be all-powerful).
-
-        alter table bugs add column groupset bigint not null;
-        alter table profiles add column groupset bigint not null;
-        update profiles set groupset=0x7fffffffffffffff where login_name = XXX;
-
-
-
-3/8/99 Added params to control how priorities are set in a new bug.  You can
-now choose whether to let submitters of new bugs choose a priority, or whether
-they should just accept the default priority (which is now no longer hardcoded
-to &quot;P2&quot;, but is instead a param.)  The default value of the params will cause
-the same behavior as before.
-
-3/3/99 Added a &quot;disallownew&quot; field to the products table.  If non-zero, then
-don't let people file new bugs against this product.  (This is for when a 
-product is retired, but you want to keep the bug reports around for posterity.)
-Feed this to MySQL:
-
-        alter table products add column disallownew tinyint not null;
-
-
-2/8/99 Added FreeBSD to the list of OS's.  Feed this to MySQL:
-
-        alter table bugs change column op_sys op_sys enum(&quot;All&quot;, &quot;Windows 3.1&quot;, &quot;Windows 95&quot;, &quot;Windows 98&quot;, &quot;Windows NT&quot;, &quot;Mac System 7&quot;, &quot;Mac System 7.5&quot;, &quot;Mac System 7.6.1&quot;, &quot;Mac System 8.0&quot;, &quot;Mac System 8.5&quot;, &quot;AIX&quot;, &quot;BSDI&quot;, &quot;HP-UX&quot;, &quot;IRIX&quot;, &quot;Linux&quot;, &quot;FreeBSD&quot;, &quot;OSF/1&quot;, &quot;Solaris&quot;, &quot;SunOS&quot;, &quot;OS/2&quot;, &quot;other&quot;) not null;
-
-
-2/4/99 Added a new column &quot;description&quot; to the components table, and added 
-links to a new page which will use this to describe the components of a 
-given product.  Feed this to MySQL:
-
-        alter table components add column description mediumtext not null;
-
-
-2/3/99 Added a new column &quot;initialqacontact&quot; to the components table that gives
-an initial QA contact field.  It may be empty if you wish the initial qa
-contact to be empty.  If you're not using the QA contact field, you don't need
-to add this column, but you might as well be safe and add it anyway:
-
-        alter table components add column initialqacontact tinytext not null;
-
-
-2/2/99 Added a new column &quot;milestoneurl&quot; to the products table that gives a URL
-which is to describe the currently defined milestones for a product.  If you
-don't use target milestone, you might be able to get away without adding this
-column, but you might as well be safe and add it anyway:
-
-        alter table products add column milestoneurl tinytext not null;
-
-
-1/29/99 Whoops; had a misspelled op_sys.  It was &quot;Mac System 7.1.6&quot;; it should
-be &quot;Mac System 7.6.1&quot;.  It turns out I had no bugs with this value set, so I
-could just do the below simple command.  If you have bugs with this value, you
-may need to do something more complicated.
-
-        alter table bugs change column op_sys op_sys enum(&quot;All&quot;, &quot;Windows 3.1&quot;, &quot;Windows 95&quot;, &quot;Windows 98&quot;, &quot;Windows NT&quot;, &quot;Mac System 7&quot;, &quot;Mac System 7.5&quot;, &quot;Mac System 7.6.1&quot;, &quot;Mac System 8.0&quot;, &quot;Mac System 8.5&quot;, &quot;AIX&quot;, &quot;BSDI&quot;, &quot;HP-UX&quot;, &quot;IRIX&quot;, &quot;Linux&quot;, &quot;OSF/1&quot;, &quot;Solaris&quot;, &quot;SunOS&quot;, &quot;OS/2&quot;, &quot;other&quot;) not null;
-
-
-
-1/20/99 Added new fields: Target Milestone, QA Contact, and Status Whiteboard.
-These fields are all optional in the UI; there are parameters to turn them on.
-However, whether or not you use them, the fields need to be in the DB.  There
-is some code that needs them, even if you don't.
-
-To update your DB to have these fields, send the following to MySQL:
-
-        alter table bugs add column target_milestone varchar(20) not null,
-                add column qa_contact mediumint not null,
-                add column status_whiteboard mediumtext not null,
-                add index (target_milestone), add index (qa_contact);
-
-
-
-1/18/99 You can now query by CC.  To make this perform reasonably, the CC table
-needs some indices.  The following MySQL does the necessary stuff:
-
-        alter table cc add index (bug_id), add index (who);
-
-
-1/15/99 The op_sys field can now be queried by (and more easily tweaked).
-To make this perform reasonably, it needs an index.  The following MySQL 
-command will create the necessary index:
-
-        alter table bugs add index (op_sys);
-
-
-12/2/98 The op_sys and rep_platform fields have been tweaked.  op_sys
-is now an enum, rather than having the legal values all hard-coded in
-perl.  rep_platform now no longer allows a value of &quot;X-Windows&quot;.
-
-Here's how I ported to the new world.  This ought to work for you too.
-Actually, it's probably overkill.  I had a lot of illegal values for op_sys
-in my tables, from importing bugs from strange places.  If you haven't done 
-anything funky, then much of the below will be a no-op.
-
-First, send the following commands to MySQL to make sure all your values for
-rep_platform and op_sys are legal in the new world..
-
-        update bugs set rep_platform=&quot;Sun&quot; where rep_platform=&quot;X-Windows&quot; and op_sys like &quot;Solaris%&quot;;
-        update bugs set rep_platform=&quot;SGI&quot; where rep_platform=&quot;X-Windows&quot; and op_sys = &quot;IRIX&quot;;
-        update bugs set rep_platform=&quot;SGI&quot; where rep_platform=&quot;X-Windows&quot; and op_sys = &quot;HP-UX&quot;;
-        update bugs set rep_platform=&quot;DEC&quot; where rep_platform=&quot;X-Windows&quot; and op_sys = &quot;OSF/1&quot;;
-        update bugs set rep_platform=&quot;PC&quot; where rep_platform=&quot;X-Windows&quot; and op_sys = &quot;Linux&quot;;
-        update bugs set rep_platform=&quot;other&quot; where rep_platform=&quot;X-Windows&quot;;
-        update bugs set rep_platform=&quot;other&quot; where rep_platform=&quot;&quot;;
-        update bugs set op_sys=&quot;Mac System 7&quot; where op_sys=&quot;System 7&quot;;
-        update bugs set op_sys=&quot;Mac System 7.5&quot; where op_sys=&quot;System 7.5&quot;;
-        update bugs set op_sys=&quot;Mac System 8.0&quot; where op_sys=&quot;8.0&quot;;
-        update bugs set op_sys=&quot;OSF/1&quot; where op_sys=&quot;Digital Unix 4.0&quot;;
-        update bugs set op_sys=&quot;IRIX&quot; where op_sys like &quot;IRIX %&quot;;
-        update bugs set op_sys=&quot;HP-UX&quot; where op_sys like &quot;HP-UX %&quot;;
-        update bugs set op_sys=&quot;Windows NT&quot; where op_sys like &quot;NT %&quot;;
-        update bugs set op_sys=&quot;OSF/1&quot; where op_sys like &quot;OSF/1 %&quot;;
-        update bugs set op_sys=&quot;Solaris&quot; where op_sys like &quot;Solaris %&quot;;
-        update bugs set op_sys=&quot;SunOS&quot; where op_sys like &quot;SunOS%&quot;;
-        update bugs set op_sys=&quot;other&quot; where op_sys = &quot;Motif&quot;;
-        update bugs set op_sys=&quot;other&quot; where op_sys = &quot;Other&quot;;
-
-Next, send the following commands to make sure you now have only legal
-entries in your table.  If either of the queries do not come up empty, then
-you have to do more stuff like the above.
-
-        select bug_id,op_sys,rep_platform from bugs where rep_platform not regexp &quot;^(All|DEC|HP|Macintosh|PC|SGI|Sun|X-Windows|Other)$&quot;;
-        select bug_id,op_sys,rep_platform from bugs where op_sys not regexp &quot;^(All|Windows 3.1|Windows 95|Windows 98|Windows NT|Mac System 7|Mac System 7.5|Mac System 7.1.6|Mac System 8.0|AIX|BSDI|HP-UX|IRIX|Linux|OSF/1|Solaris|SunOS|other)$&quot;;
-
-Finally, once that's all clear, alter the table to make enforce the new legal
-entries:
-
-        alter table bugs change column op_sys op_sys enum(&quot;All&quot;, &quot;Windows 3.1&quot;, &quot;Windows 95&quot;, &quot;Windows 98&quot;, &quot;Windows NT&quot;, &quot;Mac System 7&quot;, &quot;Mac System 7.5&quot;, &quot;Mac System 7.1.6&quot;, &quot;Mac System 8.0&quot;, &quot;AIX&quot;, &quot;BSDI&quot;, &quot;HP-UX&quot;, &quot;IRIX&quot;, &quot;Linux&quot;, &quot;OSF/1&quot;, &quot;Solaris&quot;, &quot;SunOS&quot;, &quot;other&quot;) not null, change column rep_platform rep_platform enum(&quot;All&quot;, &quot;DEC&quot;, &quot;HP&quot;, &quot;Macintosh&quot;, &quot;PC&quot;, &quot;SGI&quot;, &quot;Sun&quot;, &quot;Other&quot;);
-
-
-
-
-
-11/20/98 Added searching of CC field.  To better support this, added
-some indexes to the CC table.  You probably want to execute the following
-mysql commands:
-
-        alter table cc add index (bug_id);
-        alter table cc add index (who);
-
-
-10/27/98 security check for legal products in place. bug charts are not
-available as an option if collectstats.pl has never been run. all products 
-get daily stats collected now. README updated: Chart::Base is listed as
-a requirement, instructions for using collectstats.pl included as 
-an optional step. also got silly and added optional quips to bug
-reports. 
-
-10/17/98 modified README installation instructions slightly. 
-
-10/7/98 Added a new table called &quot;products&quot;.  Right now, this is used
-only to have a description for each product, and that description is
-only used when initially adding a new bug.  Anyway, you *must* create
-the new table (which you can do by running the new makeproducttable.sh
-script).  If you just leave it empty, things will work much as they
-did before, or you can add descriptions for some or all of your
-products.
-
-
-9/15/98 Everything has been ported to Perl.  NO MORE TCL.  This
-transition should be relatively painless, except for the &quot;params&quot;
-file.  This is the file that contains parameters you've set up on the
-editparams.cgi page.  Before changing to Perl, this was a tcl-syntax
-file, stored in the same directory as the code; after the change to
-Perl, it becomes a perl-syntax file, stored in a subdirectory named
-&quot;data&quot;.  See the README file for more details on what version of Perl
-you need.
-
-So, if updating from an older version of Bugzilla, you will need to
-edit data/param, change the email address listed for
-$::param{'maintainer'}, and then go revisit the editparams.cgi page
-and reset all the parameters to your taste.  Fortunately, your old
-params file will still be around, and so you ought to be able to
-cut&amp;paste important bits from there.
-
-Also, note that the &quot;whineatnews&quot; script has changed name (it now has
-an extension of .pl instead of .tcl), so you'll need to change your
-cron job.
-
-And the &quot;comments&quot; file has been moved to the data directory.  Just do
-&quot;cat comments &gt;&gt; data/comments&quot; to restore any old comments that may
-have been lost.
-
-
-
-9/2/98 Changed the way password validation works.  We now keep a
-crypt'd version of the password in the database, and check against
-that.  (This is silly, because we're also keeping the plaintext
-version there, but I have plans...)  Stop passing the plaintext
-password around as a cookie; instead, we have a cookie that references
-a record in a new database table, logincookies.
-
-IMPORTANT: if updating from an older version of Bugzilla, you must run
-the following commands to keep things working:
-
- ./makelogincookiestable.sh
- echo &quot;alter table profiles add column cryptpassword varchar(64);&quot; | mysql bugs
- echo &quot;update profiles set cryptpassword = encrypt(password,substring(rand(),3, 4));&quot; | mysql bugs
-
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgattachmentcgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/attachment.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/attachment.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/attachment.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -39,6 +39,7 @@
</span><span class="cx"> use lib qw(. lib);
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla;
</span><ins>+use Bugzilla::BugMail;
</ins><span class="cx"> use Bugzilla::Constants;
</span><span class="cx"> use Bugzilla::Error;
</span><span class="cx"> use Bugzilla::Flag; 
</span><span class="lines">@@ -52,6 +53,7 @@
</span><span class="cx"> use Bugzilla::Token;
</span><span class="cx"> use Bugzilla::Keyword;
</span><span class="cx"> 
</span><ins>+use Encode qw(encode find_encoding);
</ins><span class="cx"> #if WEBKIT_CHANGES
</span><span class="cx"> use Apache2::SubProcess ();
</span><span class="cx"> use Apache2::RequestUtil ();
</span><span class="lines">@@ -76,25 +78,20 @@
</span><span class="cx"> 
</span><span class="cx"> # Determine whether to use the action specified by the user or the default.
</span><span class="cx"> my $action = $cgi-&gt;param('action') || 'view';
</span><ins>+my $format = $cgi-&gt;param('format') || '';
</ins><span class="cx"> 
</span><span class="cx"> # You must use the appropriate urlbase/sslbase param when doing anything
</span><del>-# but viewing an attachment.
-if ($action ne 'view') {
-    my $urlbase = Bugzilla-&gt;params-&gt;{'urlbase'};
-    my $sslbase = Bugzilla-&gt;params-&gt;{'sslbase'};
-    my $path_regexp = $sslbase ? qr/^(\Q$urlbase\E|\Q$sslbase\E)/ : qr/^\Q$urlbase\E/;
-    if (use_attachbase() &amp;&amp; $cgi-&gt;self_url !~ /$path_regexp/) {
</del><ins>+# but viewing an attachment, or a raw diff.
+if ($action ne 'view'
+    &amp;&amp; (($action !~ /^(?:interdiff|diff)$/) || $format ne 'raw'))
+{
+    do_ssl_redirect_if_required();
+    if ($cgi-&gt;url_is_attachment_base) {
</ins><span class="cx">         $cgi-&gt;redirect_to_urlbase;
</span><span class="cx">     }
</span><span class="cx">     Bugzilla-&gt;login();
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-# Determine if PatchReader is installed
-eval {
-    require PatchReader;
-    $vars-&gt;{'patchviewerinstalled'} = 1;
-};
-
</del><span class="cx"> # When viewing an attachment, do not request credentials if we are on
</span><span class="cx"> # the alternate host. Let view() decide when to call Bugzilla-&gt;login.
</span><span class="cx"> if ($action eq &quot;view&quot;)
</span><span class="lines">@@ -157,7 +154,7 @@
</span><span class="cx"> }
</span><span class="cx"> else 
</span><span class="cx"> { 
</span><del>-  ThrowCodeError(&quot;unknown_action&quot;, { action =&gt; $action });
</del><ins>+  ThrowUserError('unknown_action', {action =&gt; $action});
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> exit;
</span><span class="lines">@@ -197,11 +194,12 @@
</span><span class="cx">     # non-natural, so use the original value from $cgi in our exception
</span><span class="cx">     # message here.
</span><span class="cx">     detaint_natural($attach_id)
</span><del>-     || ThrowUserError(&quot;invalid_attach_id&quot;, { attach_id =&gt; $cgi-&gt;param($param) });
</del><ins>+        || ThrowUserError(&quot;invalid_attach_id&quot;,
+                          { attach_id =&gt; scalar $cgi-&gt;param($param) });
</ins><span class="cx">   
</span><span class="cx">     # Make sure the attachment exists in the database.
</span><del>-    my $attachment = Bugzilla::Attachment-&gt;get($attach_id)
-      || ThrowUserError(&quot;invalid_attach_id&quot;, { attach_id =&gt; $attach_id });
</del><ins>+    my $attachment = new Bugzilla::Attachment($attach_id)
+        || ThrowUserError(&quot;invalid_attach_id&quot;, { attach_id =&gt; $attach_id });
</ins><span class="cx"> 
</span><span class="cx">     return $attachment if ($dont_validate_access || check_can_access($attachment));
</span><span class="cx"> }
</span><span class="lines">@@ -212,10 +210,13 @@
</span><span class="cx">     my $user = Bugzilla-&gt;user;
</span><span class="cx"> 
</span><span class="cx">     # Make sure the user is authorized to access this attachment's bug.
</span><del>-    ValidateBugID($attachment-&gt;bug_id);
-    if ($attachment-&gt;isprivate &amp;&amp; $user-&gt;id != $attachment-&gt;attacher-&gt;id &amp;&amp; !$user-&gt;is_insider) {
</del><ins>+    Bugzilla::Bug-&gt;check($attachment-&gt;bug_id);
+    if ($attachment-&gt;isprivate &amp;&amp; $user-&gt;id != $attachment-&gt;attacher-&gt;id 
+        &amp;&amp; !$user-&gt;is_insider) 
+    {
</ins><span class="cx">         ThrowUserError('auth_failure', {action =&gt; 'access',
</span><del>-                                        object =&gt; 'attachment'});
</del><ins>+                                        object =&gt; 'attachment',
+                                        attach_id =&gt; $attachment-&gt;id});
</ins><span class="cx">     }
</span><span class="cx">     return 1;
</span><span class="cx"> }
</span><span class="lines">@@ -235,12 +236,10 @@
</span><span class="cx"> # Validates format of a diff/interdiff. Takes a list as an parameter, which
</span><span class="cx"> # defines the valid format values. Will throw an error if the format is not
</span><span class="cx"> # in the list. Returns either the user selected or default format.
</span><del>-sub validateFormat
-{
</del><ins>+sub validateFormat {
</ins><span class="cx">   # receives a list of legal formats; first item is a default
</span><span class="cx">   my $format = $cgi-&gt;param('format') || $_[0];
</span><del>-  if ( lsearch(\@_, $format) == -1)
-  {
</del><ins>+  if (not grep($_ eq $format, @_)) {
</ins><span class="cx">      ThrowUserError(&quot;invalid_format&quot;, { format  =&gt; $format, formats =&gt; \@_ });
</span><span class="cx">   }
</span><span class="cx"> 
</span><span class="lines">@@ -260,63 +259,51 @@
</span><span class="cx">   return $context;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub validateCanChangeBug
-{
-    my ($bugid) = @_;
-    my $dbh = Bugzilla-&gt;dbh;
-    my ($productid) = $dbh-&gt;selectrow_array(
-            &quot;SELECT product_id
-             FROM bugs 
-             WHERE bug_id = ?&quot;, undef, $bugid);
</del><ins>+# Gets the attachment object(s) generated by validateID, while ensuring
+# attachbase and token authentication is used when required.
+sub get_attachment {
+    my @field_names = @_ ? @_ : qw(id);
</ins><span class="cx"> 
</span><del>-    Bugzilla-&gt;user-&gt;can_edit_product($productid)
-      || ThrowUserError(&quot;illegal_attachment_edit_bug&quot;,
-                        { bug_id =&gt; $bugid });
-}
</del><ins>+    my %attachments;
</ins><span class="cx"> 
</span><del>-################################################################################
-# Functions
-################################################################################
-
-# Display an attachment.
-sub view {
-    my $attachment;
-
</del><span class="cx">     if (use_attachbase()) {
</span><del>-        $attachment = validateID(undef, 1);
-        # Replace %bugid% by the ID of the bug the attachment belongs to, if present.
-        my $attachbase = Bugzilla-&gt;params-&gt;{'attachment_base'};
-        my $bug_id = $attachment-&gt;bug_id;
-        $attachbase =~ s/%bugid%/$bug_id/;
-        my $path = 'attachment.cgi?id=' . $attachment-&gt;id;
</del><ins>+        # Load each attachment, and ensure they are all from the same bug
+        my $bug_id = 0;
+        foreach my $field_name (@field_names) {
+            my $attachment = validateID($field_name, 1);
+            if (!$bug_id) {
+                $bug_id = $attachment-&gt;bug_id;
+            } elsif ($attachment-&gt;bug_id != $bug_id) {
+                ThrowUserError('attachment_bug_id_mismatch');
+            }
+            $attachments{$field_name} = $attachment;
+        }
+        my @args = map { $_ . '=' . $attachments{$_}-&gt;id } @field_names;
+        my $cgi_params = $cgi-&gt;canonicalise_query(@field_names, 't',
+            'Bugzilla_login', 'Bugzilla_password');
+        push(@args, $cgi_params) if $cgi_params;
+        my $path = 'attachment.cgi?' . join('&amp;', @args);
</ins><span class="cx"> 
</span><span class="cx">         # Make sure the attachment is served from the correct server.
</span><del>-        if ($cgi-&gt;self_url !~ /^\Q$attachbase\E/) {
-            # We couldn't call Bugzilla-&gt;login earlier as we first had to make sure
-            # we were not going to request credentials on the alternate host.
-            Bugzilla-&gt;login();
-            if (attachmentIsPublic($attachment)) {
-                # No need for a token; redirect to attachment base.
-                print $cgi-&gt;redirect(-location =&gt; $attachbase . $path);
-                exit;
-            } else {
-                # Make sure the user can view the attachment.
-                check_can_access($attachment);
-                # Create a token and redirect.
-                my $token = url_quote(issue_session_token($attachment-&gt;id));
-                print $cgi-&gt;redirect(-location =&gt; $attachbase . &quot;$path&amp;t=$token&quot;);
-                exit;
-            }
-        } else {
</del><ins>+        if ($cgi-&gt;url_is_attachment_base($bug_id)) {
</ins><span class="cx">             # No need to validate the token for public attachments. We cannot request
</span><span class="cx">             # credentials as we are on the alternate host.
</span><del>-            if (!attachmentIsPublic($attachment)) {
</del><ins>+            if (!all_attachments_are_public(\%attachments)) {
</ins><span class="cx">                 my $token = $cgi-&gt;param('t');
</span><del>-                my ($userid, undef, $token_attach_id) = Bugzilla::Token::GetTokenData($token);
-                unless ($userid
-                        &amp;&amp; detaint_natural($token_attach_id)
-                        &amp;&amp; ($token_attach_id == $attachment-&gt;id))
-                {
</del><ins>+                my ($userid, undef, $token_data) = Bugzilla::Token::GetTokenData($token);
+                my %token_data = unpack_token_data($token_data);
+                my $valid_token = 1;
+                foreach my $field_name (@field_names) {
+                    my $token_id = $token_data{$field_name};
+                    if (!$token_id
+                        || !detaint_natural($token_id)
+                        || $attachments{$field_name}-&gt;id != $token_id)
+                    {
+                        $valid_token = 0;
+                        last;
+                    }
+                }
+                unless ($userid &amp;&amp; $valid_token) {
</ins><span class="cx">                     # Not a valid token.
</span><span class="cx">                     print $cgi-&gt;redirect('-location' =&gt; correct_urlbase() . $path);
</span><span class="cx">                     exit;
</span><span class="lines">@@ -327,24 +314,91 @@
</span><span class="cx">                 delete_token($token);
</span><span class="cx">             }
</span><span class="cx">         }
</span><ins>+        elsif ($cgi-&gt;url_is_attachment_base) {
+            # If we come here, this means that each bug has its own host
+            # for attachments, and that we are trying to view one attachment
+            # using another bug's host. That's not desired.
+            $cgi-&gt;redirect_to_urlbase;
+        }
+        else {
+            # We couldn't call Bugzilla-&gt;login earlier as we first had to
+            # make sure we were not going to request credentials on the
+            # alternate host.
+            Bugzilla-&gt;login();
+            my $attachbase = Bugzilla-&gt;params-&gt;{'attachment_base'};
+            # Replace %bugid% by the ID of the bug the attachment 
+            # belongs to, if present.
+            $attachbase =~ s/\%bugid\%/$bug_id/;
+            if (all_attachments_are_public(\%attachments)) {
+                # No need for a token; redirect to attachment base.
+                print $cgi-&gt;redirect(-location =&gt; $attachbase . $path);
+                exit;
+            } else {
+                # Make sure the user can view the attachment.
+                foreach my $field_name (@field_names) {
+                    check_can_access($attachments{$field_name});
+                }
+                # Create a token and redirect.
+                my $token = url_quote(issue_session_token(pack_token_data(\%attachments)));
+                print $cgi-&gt;redirect(-location =&gt; $attachbase . &quot;$path&amp;t=$token&quot;);
+                exit;
+            }
+        }
</ins><span class="cx">     } else {
</span><ins>+        do_ssl_redirect_if_required();
</ins><span class="cx">         # No alternate host is used. Request credentials if required.
</span><span class="cx">         Bugzilla-&gt;login();
</span><del>-        $attachment = validateID();
</del><ins>+        foreach my $field_name (@field_names) {
+            $attachments{$field_name} = validateID($field_name);
+        }
</ins><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    return wantarray
+        ? map { $attachments{$_} } @field_names
+        : $attachments{$field_names[0]};
+}
+
+sub all_attachments_are_public {
+    my $attachments = shift;
+    foreach my $field_name (keys %$attachments) {
+        if (!attachmentIsPublic($attachments-&gt;{$field_name})) {
+            return 0;
+        }
+    }
+    return 1;
+}
+
+sub pack_token_data {
+    my $attachments = shift;
+    return join(' ', map { $_ . '=' . $attachments-&gt;{$_}-&gt;id } keys %$attachments);
+}
+
+sub unpack_token_data {
+    my @token_data = split(/ /, shift || '');
+    my %data;
+    foreach my $token (@token_data) {
+        my ($field_name, $attach_id) = split('=', $token);
+        $data{$field_name} = $attach_id;
+    }
+    return %data;
+}
+
+################################################################################
+# Functions
+################################################################################
+
+# Display an attachment.
+sub view {
+    my $attachment = get_attachment();
+
</ins><span class="cx">     # At this point, Bugzilla-&gt;login has been called if it had to.
</span><span class="cx">     my $contenttype = $attachment-&gt;contenttype;
</span><span class="cx">     my $filename = $attachment-&gt;filename;
</span><span class="cx"> 
</span><span class="cx">     # Bug 111522: allow overriding content-type manually in the posted form
</span><span class="cx">     # params.
</span><del>-    if (defined $cgi-&gt;param('content_type'))
-    {
-        $cgi-&gt;param('contenttypemethod', 'manual');
-        $cgi-&gt;param('contenttypeentry', $cgi-&gt;param('content_type'));
-        Bugzilla::Attachment-&gt;validate_content_type(THROW_ERROR);
-        $contenttype = $cgi-&gt;param('content_type');
</del><ins>+    if (defined $cgi-&gt;param('content_type')) {
+        $contenttype = $attachment-&gt;_check_content_type($cgi-&gt;param('content_type'));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # Return the appropriate HTTP response headers.
</span><span class="lines">@@ -355,20 +409,45 @@
</span><span class="cx">     $filename =~ s/\\/\\\\/g; # escape backslashes
</span><span class="cx">     $filename =~ s/&quot;/\\&quot;/g; # escape quotes
</span><span class="cx"> 
</span><ins>+    # Avoid line wrapping done by Encode, which we don't need for HTTP
+    # headers. See discussion in bug 328628 for details.
+    local $Encode::Encoding{'MIME-Q'}-&gt;{'bpl'} = 10000;
+    $filename = encode('MIME-Q', $filename);
+
</ins><span class="cx">     my $disposition = Bugzilla-&gt;params-&gt;{'allow_attachment_display'} ? 'inline' : 'attachment';
</span><span class="cx"> 
</span><ins>+    # Don't send a charset header with attachments--they might not be UTF-8.
+    # However, we do allow people to explicitly specify a charset if they
+    # want.
+    if ($contenttype !~ /\bcharset=/i) {
+        # In order to prevent Apache from adding a charset, we have to send a
+        # charset that's a single space.
+        $cgi-&gt;charset(' ');
+        if (Bugzilla-&gt;feature('detect_charset') &amp;&amp; $contenttype =~ /^text\//) {
+            my $encoding = detect_encoding($attachment-&gt;data);
+            if ($encoding) {
+                $cgi-&gt;charset(find_encoding($encoding)-&gt;mime_name);
+            }
+        }
+    }
</ins><span class="cx">     print $cgi-&gt;header(-type=&gt;&quot;$contenttype; name=\&quot;$filename\&quot;&quot;,
</span><span class="cx">                        -content_disposition=&gt; &quot;$disposition; filename=\&quot;$filename\&quot;&quot;,
</span><del>-                       -content_length =&gt; $attachment-&gt;datasize);
</del><ins>+                       -content_length =&gt; $attachment-&gt;datasize,
+                       -x_content_type_options =&gt; &quot;nosniff&quot;);
</ins><span class="cx">     disable_utf8();
</span><span class="cx">     print $attachment-&gt;data;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub interdiff {
</span><span class="cx">     # Retrieve and validate parameters
</span><del>-    my $old_attachment = validateID('oldid');
-    my $new_attachment = validateID('newid');
</del><span class="cx">     my $format = validateFormat('html', 'raw');
</span><ins>+    my($old_attachment, $new_attachment);
+    if ($format eq 'raw') {
+        ($old_attachment, $new_attachment) = get_attachment('oldid', 'newid');
+    } else {
+        $old_attachment = validateID('oldid');
+        $new_attachment = validateID('newid');
+    }
</ins><span class="cx">     my $context = validateContext();
</span><span class="cx"> 
</span><span class="cx">     Bugzilla::Attachment::PatchReader::process_interdiff(
</span><span class="lines">@@ -411,8 +490,8 @@
</span><span class="cx"> 
</span><span class="cx"> sub diff {
</span><span class="cx">     # Retrieve and validate parameters
</span><del>-    my $attachment = validateID();
</del><span class="cx">     my $format = validateFormat('html', 'raw');
</span><ins>+    my $attachment = $format eq 'raw' ? get_attachment() : validateID();
</ins><span class="cx">     my $context = validateContext();
</span><span class="cx"> 
</span><span class="cx">     # If it is not a patch, view normally.
</span><span class="lines">@@ -428,12 +507,18 @@
</span><span class="cx"> # HTML page.
</span><span class="cx"> sub viewall {
</span><span class="cx">     # Retrieve and validate parameters
</span><del>-    my $bugid = $cgi-&gt;param('bugid');
-    ValidateBugID($bugid);
-    my $bug = new Bugzilla::Bug($bugid);
</del><ins>+    my $bug = Bugzilla::Bug-&gt;check(scalar $cgi-&gt;param('bugid'));
+    my $bugid = $bug-&gt;id;
</ins><span class="cx"> 
</span><span class="cx">     my $attachments = Bugzilla::Attachment-&gt;get_attachments_by_bug($bugid);
</span><ins>+    # Ignore deleted attachments.
+    @$attachments = grep { $_-&gt;datasize } @$attachments;
</ins><span class="cx"> 
</span><ins>+    if ($cgi-&gt;param('hide_obsolete')) {
+        @$attachments = grep { !$_-&gt;isobsolete } @$attachments;
+        $vars-&gt;{'hide_obsolete'} = 1;
+    }
+
</ins><span class="cx">     # Define the variables and functions that will be passed to the UI template.
</span><span class="cx">     $vars-&gt;{'bug'} = $bug;
</span><span class="cx">     $vars-&gt;{'attachments'} = $attachments;
</span><span class="lines">@@ -448,13 +533,12 @@
</span><span class="cx"> # Display a form for entering a new attachment.
</span><span class="cx"> sub enter {
</span><span class="cx">   # Retrieve and validate parameters
</span><del>-  my $bugid = $cgi-&gt;param('bugid');
-  ValidateBugID($bugid);
-  validateCanChangeBug($bugid);
</del><ins>+  my $bug = Bugzilla::Bug-&gt;check(scalar $cgi-&gt;param('bugid'));
+  my $bugid = $bug-&gt;id;
+  Bugzilla::Attachment-&gt;_check_bug($bug);
</ins><span class="cx">   my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx">   my $user = Bugzilla-&gt;user;
</span><span class="cx"> 
</span><del>-  my $bug = new Bugzilla::Bug($bugid, $user-&gt;id);
</del><span class="cx">   # Retrieve the attachments the user can edit from the database and write
</span><span class="cx">   # them into an array of hashes where each hash represents one attachment.
</span><span class="cx">   my $canEdit = &quot;&quot;;
</span><span class="lines">@@ -467,14 +551,15 @@
</span><span class="cx"> 
</span><span class="cx">   # Define the variables and functions that will be passed to the UI template.
</span><span class="cx">   $vars-&gt;{'bug'} = $bug;
</span><del>-  $vars-&gt;{'attachments'} = Bugzilla::Attachment-&gt;get_list($attach_ids);
</del><ins>+  $vars-&gt;{'attachments'} = Bugzilla::Attachment-&gt;new_from_list($attach_ids);
</ins><span class="cx"> 
</span><span class="cx">   my $flag_types = Bugzilla::FlagType::match({'target_type'  =&gt; 'attachment',
</span><span class="cx">                                               'product_id'   =&gt; $bug-&gt;product_id,
</span><span class="cx">                                               'component_id' =&gt; $bug-&gt;component_id});
</span><span class="cx">   $vars-&gt;{'flag_types'} = $flag_types;
</span><del>-  $vars-&gt;{'any_flags_requesteeble'} = grep($_-&gt;is_requesteeble, @$flag_types);
-  $vars-&gt;{'token'} = issue_session_token('createattachment:');
</del><ins>+  $vars-&gt;{'any_flags_requesteeble'} =
+    grep { $_-&gt;is_requestable &amp;&amp; $_-&gt;is_requesteeble } @$flag_types;
+  $vars-&gt;{'token'} = issue_session_token('create_attachment');
</ins><span class="cx"> 
</span><span class="cx">   print $cgi-&gt;header();
</span><span class="cx"> 
</span><span class="lines">@@ -491,47 +576,58 @@
</span><span class="cx">     $dbh-&gt;bz_start_transaction;
</span><span class="cx"> 
</span><span class="cx">     # Retrieve and validate parameters
</span><del>-    my $bugid = $cgi-&gt;param('bugid');
-    ValidateBugID($bugid);
-    validateCanChangeBug($bugid);
-    my ($timestamp) = Bugzilla-&gt;dbh-&gt;selectrow_array(&quot;SELECT NOW()&quot;);
</del><ins>+    my $bug = Bugzilla::Bug-&gt;check(scalar $cgi-&gt;param('bugid'));
+    my $bugid = $bug-&gt;id;
+    my ($timestamp) = $dbh-&gt;selectrow_array(&quot;SELECT NOW()&quot;);
</ins><span class="cx"> 
</span><span class="cx">     # Detect if the user already used the same form to submit an attachment
</span><span class="cx">     my $token = trim($cgi-&gt;param('token'));
</span><del>-    if ($token) {
-        my ($creator_id, $date, $old_attach_id) = Bugzilla::Token::GetTokenData($token);
-        unless ($creator_id 
-            &amp;&amp; ($creator_id == $user-&gt;id) 
-                &amp;&amp; ($old_attach_id =~ &quot;^createattachment:&quot;)) 
-        {
-            # The token is invalid.
-            ThrowUserError('token_does_not_exist');
-        }
-    
-        $old_attach_id =~ s/^createattachment://;
-   
-        if ($old_attach_id) {
-            $vars-&gt;{'bugid'} = $bugid;
-            $vars-&gt;{'attachid'} = $old_attach_id;
-            print $cgi-&gt;header();
-            $template-&gt;process(&quot;attachment/cancel-create-dupe.html.tmpl&quot;,  $vars)
-                || ThrowTemplateError($template-&gt;error());
-            exit;
-        }
</del><ins>+    check_token_data($token, 'create_attachment', 'index.cgi');
+
+    # Check attachments the user tries to mark as obsolete.
+    my @obsolete_attachments;
+    if ($cgi-&gt;param('obsolete')) {
+        my @obsolete = $cgi-&gt;param('obsolete');
+        @obsolete_attachments = Bugzilla::Attachment-&gt;validate_obsolete($bug, \@obsolete);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    my $bug = new Bugzilla::Bug($bugid);
-    my $attachment =
-        Bugzilla::Attachment-&gt;insert_attachment_for_bug(THROW_ERROR, $bug, $user,
-                                                        $timestamp, $vars);
</del><ins>+    # Must be called before create() as it may alter $cgi-&gt;param('ispatch').
+    my $content_type = Bugzilla::Attachment::get_content_type();
</ins><span class="cx"> 
</span><ins>+    # Get the filehandle of the attachment.
+    my $data_fh = $cgi-&gt;upload('data');
+
+    my $attachment = Bugzilla::Attachment-&gt;create(
+        {bug           =&gt; $bug,
+         creation_ts   =&gt; $timestamp,
+         data          =&gt; scalar $cgi-&gt;param('attach_text') || $data_fh,
+         description   =&gt; scalar $cgi-&gt;param('description'),
+         filename      =&gt; $cgi-&gt;param('attach_text') ? &quot;file_$bugid.txt&quot; : scalar $cgi-&gt;upload('data'),
+         ispatch       =&gt; scalar $cgi-&gt;param('ispatch'),
+         isprivate     =&gt; scalar $cgi-&gt;param('isprivate'),
+         mimetype      =&gt; $content_type,
+         });
+
+    # Delete the token used to create this attachment.
+    delete_token($token);
+
+    foreach my $obsolete_attachment (@obsolete_attachments) {
+        $obsolete_attachment-&gt;set_is_obsolete(1);
+        $obsolete_attachment-&gt;update($timestamp);
+    }
+
+    my ($flags, $new_flags) = Bugzilla::Flag-&gt;extract_flags_from_cgi(
+                                  $bug, $attachment, $vars, SKIP_REQUESTEE_ON_ERROR);
+    $attachment-&gt;set_flags($flags, $new_flags);
+    $attachment-&gt;update($timestamp);
+
</ins><span class="cx">     # Insert a comment about the new attachment into the database.
</span><del>-    my $comment = &quot;Created an attachment (id=&quot; . $attachment-&gt;id . &quot;)\n&quot; .
-                  $attachment-&gt;description . &quot;\n&quot;;
-    $comment .= (&quot;\n&quot; . $cgi-&gt;param('comment')) if defined $cgi-&gt;param('comment');
</del><ins>+    my $comment = $cgi-&gt;param('comment');
+    $comment = '' unless defined $comment;
+    $bug-&gt;add_comment($comment, { isprivate =&gt; $attachment-&gt;isprivate,
+                                  type =&gt; CMT_ATTACHMENT_CREATED,
+                                  extra_data =&gt; $attachment-&gt;id });
</ins><span class="cx"> 
</span><del>-    $bug-&gt;add_comment($comment, { isprivate =&gt; $attachment-&gt;isprivate });
-
</del><span class="cx">   # Assign the bug to the user, if they are allowed to take it
</span><span class="cx">   my $owner = &quot;&quot;;
</span><span class="cx">   if ($cgi-&gt;param('takebug') &amp;&amp; $user-&gt;in_group('editbugs', $bug-&gt;product_id)) {
</span><span class="lines">@@ -540,9 +636,10 @@
</span><span class="cx">       ($bug_status) = grep {$_-&gt;name eq $bug_status} @{$bug-&gt;status-&gt;can_change_to};
</span><span class="cx"> 
</span><span class="cx">       if ($bug_status &amp;&amp; $bug_status-&gt;is_open
</span><del>-          &amp;&amp; ($bug_status-&gt;name ne 'UNCONFIRMED' || $bug-&gt;product_obj-&gt;votes_to_confirm))
</del><ins>+          &amp;&amp; ($bug_status-&gt;name ne 'UNCONFIRMED' 
+              || $bug-&gt;product_obj-&gt;allows_unconfirmed))
</ins><span class="cx">       {
</span><del>-          $bug-&gt;set_status($bug_status-&gt;name);
</del><ins>+          $bug-&gt;set_bug_status($bug_status-&gt;name);
</ins><span class="cx">           $bug-&gt;clear_resolution();
</span><span class="cx">       }
</span><span class="cx">       # Make sure the person we are taking the bug from gets mail.
</span><span class="lines">@@ -551,25 +648,19 @@
</span><span class="cx">   }
</span><span class="cx">   $bug-&gt;update($timestamp);
</span><span class="cx"> 
</span><del>-  if ($token) {
-      trick_taint($token);
-      $dbh-&gt;do('UPDATE tokens SET eventdata = ? WHERE token = ?', undef,
-               (&quot;createattachment:&quot; . $attachment-&gt;id, $token));
-  }
-
</del><span class="cx">   $dbh-&gt;bz_commit_transaction;
</span><span class="cx"> 
</span><span class="cx">   # Define the variables and functions that will be passed to the UI template.
</span><del>-  $vars-&gt;{'mailrecipients'} =  { 'changer' =&gt; $user-&gt;login,
-                                 'owner'   =&gt; $owner };
</del><span class="cx">   $vars-&gt;{'attachment'} = $attachment;
</span><span class="cx">   # We cannot reuse the $bug object as delta_ts has eventually been updated
</span><span class="cx">   # since the object was created.
</span><span class="cx">   $vars-&gt;{'bugs'} = [new Bugzilla::Bug($bugid)];
</span><span class="cx">   $vars-&gt;{'header_done'} = 1;
</span><span class="cx">   $vars-&gt;{'contenttypemethod'} = $cgi-&gt;param('contenttypemethod');
</span><del>-  $vars-&gt;{'use_keywords'} = 1 if Bugzilla::Keyword::keyword_count();
</del><span class="cx"> 
</span><ins>+  my $recipients =  { 'changer' =&gt; $user, 'owner' =&gt; $owner };
+  $vars-&gt;{'sent_bugmail'} = Bugzilla::BugMail::Send($bugid, $recipients);
+
</ins><span class="cx">   print $cgi-&gt;header();
</span><span class="cx">   # Generate and return the UI (HTML page) from the appropriate template.
</span><span class="cx">   $template-&gt;process(&quot;attachment/created.html.tmpl&quot;, $vars)
</span><span class="lines">@@ -587,32 +678,19 @@
</span><span class="cx"> #endif // WEBKIT_CHANGES
</span><span class="cx"> 
</span><span class="cx">   my $attachment = validateID();
</span><del>-  my $dbh = Bugzilla-&gt;dbh;
</del><span class="cx"> 
</span><del>-  # Retrieve a list of attachments for this bug as well as a summary of the bug
-  # to use in a navigation bar across the top of the screen.
</del><span class="cx">   my $bugattachments =
</span><span class="cx">       Bugzilla::Attachment-&gt;get_attachments_by_bug($attachment-&gt;bug_id);
</span><span class="cx">   # We only want attachment IDs.
</span><span class="cx">   @$bugattachments = map { $_-&gt;id } @$bugattachments;
</span><span class="cx"> 
</span><del>-  my ($bugsummary, $product_id, $component_id) =
-      $dbh-&gt;selectrow_array('SELECT short_desc, product_id, component_id
-                               FROM bugs
-                              WHERE bug_id = ?', undef, $attachment-&gt;bug_id);
-
-  # Get a list of flag types that can be set for this attachment.
-  my $flag_types = Bugzilla::FlagType::match({ 'target_type'  =&gt; 'attachment' ,
-                                               'product_id'   =&gt; $product_id ,
-                                               'component_id' =&gt; $component_id });
-  foreach my $flag_type (@$flag_types) {
-    $flag_type-&gt;{'flags'} = Bugzilla::Flag-&gt;match({ 'type_id'   =&gt; $flag_type-&gt;id,
-                                                    'attach_id' =&gt; $attachment-&gt;id });
-  }
-  $vars-&gt;{'flag_types'} = $flag_types;
-  $vars-&gt;{'any_flags_requesteeble'} = grep($_-&gt;is_requesteeble, @$flag_types);
</del><ins>+  my $any_flags_requesteeble =
+    grep { $_-&gt;is_requestable &amp;&amp; $_-&gt;is_requesteeble } @{$attachment-&gt;flag_types};
+  # Useful in case a flagtype is no longer requestable but a requestee
+  # has been set before we turned off that bit.
+  $any_flags_requesteeble ||= grep { $_-&gt;requestee_id } @{$attachment-&gt;flags};
+  $vars-&gt;{'any_flags_requesteeble'} = $any_flags_requesteeble;
</ins><span class="cx">   $vars-&gt;{'attachment'} = $attachment;
</span><del>-  $vars-&gt;{'bugsummary'} = $bugsummary; 
</del><span class="cx">   $vars-&gt;{'attachments'} = $bugattachments;
</span><span class="cx"> 
</span><span class="cx"> #if WEBKIT_CHANGES
</span><span class="lines">@@ -630,48 +708,53 @@
</span><span class="cx">     || ThrowTemplateError($template-&gt;error());
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-# Updates an attachment record. Users with &quot;editbugs&quot; privileges, (or the
-# original attachment's submitter) can edit the attachment's description,
-# content type, ispatch and isobsolete flags, and statuses, and they can
-# also submit a comment that appears in the bug.
</del><ins>+# Updates an attachment record. Only users with &quot;editbugs&quot; privileges,
+# (or the original attachment's submitter) can edit the attachment.
</ins><span class="cx"> # Users cannot edit the content of the attachment itself.
</span><span class="cx"> sub update {
</span><span class="cx">     my $user = Bugzilla-&gt;user;
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx"> 
</span><ins>+    # Start a transaction in preparation for updating the attachment.
+    $dbh-&gt;bz_start_transaction();
+
</ins><span class="cx">     # Retrieve and validate parameters
</span><span class="cx">     my $attachment = validateID();
</span><del>-    my $bug = new Bugzilla::Bug($attachment-&gt;bug_id);
-    $attachment-&gt;validate_can_edit($bug-&gt;product_id);
-    validateCanChangeBug($bug-&gt;id);
-    Bugzilla::Attachment-&gt;validate_description(THROW_ERROR);
-    Bugzilla::Attachment-&gt;validate_is_patch(THROW_ERROR);
-    Bugzilla::Attachment-&gt;validate_content_type(THROW_ERROR) unless $cgi-&gt;param('ispatch');
-    $cgi-&gt;param('isobsolete', $cgi-&gt;param('isobsolete') ? 1 : 0);
-    $cgi-&gt;param('isprivate', $cgi-&gt;param('isprivate') ? 1 : 0);
</del><ins>+    my $bug = $attachment-&gt;bug;
+    $attachment-&gt;_check_bug;
+    my $can_edit = $attachment-&gt;validate_can_edit($bug-&gt;product_id);
</ins><span class="cx"> 
</span><del>-    # Now make sure the attachment has not been edited since we loaded the page.
-    if (defined $cgi-&gt;param('delta_ts')
-        &amp;&amp; $cgi-&gt;param('delta_ts') ne $attachment-&gt;modification_time)
-    {
-        ($vars-&gt;{'operations'}) =
-            Bugzilla::Bug::GetBugActivity($bug-&gt;id, $attachment-&gt;id, $cgi-&gt;param('delta_ts'));
</del><ins>+    if ($can_edit) {
+        $attachment-&gt;set_description(scalar $cgi-&gt;param('description'));
+        $attachment-&gt;set_is_patch(scalar $cgi-&gt;param('ispatch'));
+        $attachment-&gt;set_content_type(scalar $cgi-&gt;param('contenttypeentry'));
+        $attachment-&gt;set_is_obsolete(scalar $cgi-&gt;param('isobsolete'));
+        $attachment-&gt;set_is_private(scalar $cgi-&gt;param('isprivate'));
+        $attachment-&gt;set_filename(scalar $cgi-&gt;param('filename'));
</ins><span class="cx"> 
</span><del>-        # The token contains the old modification_time. We need a new one.
-        $cgi-&gt;param('token', issue_hash_token([$attachment-&gt;id, $attachment-&gt;modification_time]));
</del><ins>+        # Now make sure the attachment has not been edited since we loaded the page.
+        if (defined $cgi-&gt;param('delta_ts')
+            &amp;&amp; $cgi-&gt;param('delta_ts') ne $attachment-&gt;modification_time)
+        {
+            ($vars-&gt;{'operations'}) =
+                Bugzilla::Bug::GetBugActivity($bug-&gt;id, $attachment-&gt;id, $cgi-&gt;param('delta_ts'));
</ins><span class="cx"> 
</span><del>-        # If the modification date changed but there is no entry in
-        # the activity table, this means someone commented only.
-        # In this case, there is no reason to midair.
-        if (scalar(@{$vars-&gt;{'operations'}})) {
-            $cgi-&gt;param('delta_ts', $attachment-&gt;modification_time);
-            $vars-&gt;{'attachment'} = $attachment;
</del><ins>+            # The token contains the old modification_time. We need a new one.
+            $cgi-&gt;param('token', issue_hash_token([$attachment-&gt;id, $attachment-&gt;modification_time]));
</ins><span class="cx"> 
</span><del>-            print $cgi-&gt;header();
-            # Warn the user about the mid-air collision and ask them what to do.
-            $template-&gt;process(&quot;attachment/midair.html.tmpl&quot;, $vars)
-              || ThrowTemplateError($template-&gt;error());
-            exit;
</del><ins>+            # If the modification date changed but there is no entry in
+            # the activity table, this means someone commented only.
+            # In this case, there is no reason to midair.
+            if (scalar(@{$vars-&gt;{'operations'}})) {
+                $cgi-&gt;param('delta_ts', $attachment-&gt;modification_time);
+                $vars-&gt;{'attachment'} = $attachment;
+
+                print $cgi-&gt;header();
+                # Warn the user about the mid-air collision and ask them what to do.
+                $template-&gt;process(&quot;attachment/midair.html.tmpl&quot;, $vars)
+                  || ThrowTemplateError($template-&gt;error());
+                exit;
+            }
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -680,128 +763,49 @@
</span><span class="cx">     my $token = $cgi-&gt;param('token');
</span><span class="cx">     check_hash_token($token, [$attachment-&gt;id, $attachment-&gt;modification_time]);
</span><span class="cx"> 
</span><del>-    # If the submitter of the attachment is not in the insidergroup,
-    # be sure that he cannot overwrite the private bit.
-    # This check must be done before calling Bugzilla::Flag*::validate(),
-    # because they will look at the private bit when checking permissions.
-    # XXX - This is a ugly hack. Ideally, we shouldn't have to look at the
-    # old private bit twice (first here, and then below again), but this is
-    # the less risky change.
-    unless ($user-&gt;is_insider) {
-        $cgi-&gt;param('isprivate', $attachment-&gt;isprivate);
-    }
-
</del><span class="cx">     # If the user submitted a comment while editing the attachment,
</span><span class="cx">     # add the comment to the bug. Do this after having validated isprivate!
</span><del>-    if ($cgi-&gt;param('comment')) {
-        # Prepend a string to the comment to let users know that the comment came
-        # from the &quot;edit attachment&quot; screen.
-        my $comment = &quot;(From update of attachment &quot; . $attachment-&gt;id . &quot;)\n&quot; .
-                      $cgi-&gt;param('comment');
</del><ins>+    my $comment = $cgi-&gt;param('comment');
+    if (defined $comment &amp;&amp; trim($comment) ne '') {
+        $bug-&gt;add_comment($comment, { isprivate =&gt; $attachment-&gt;isprivate,
+                                      type =&gt; CMT_ATTACHMENT_UPDATED,
+                                      extra_data =&gt; $attachment-&gt;id });
+    }
</ins><span class="cx"> 
</span><del>-        $bug-&gt;add_comment($comment, { isprivate =&gt; $cgi-&gt;param('isprivate') });
</del><ins>+    if ($can_edit) {
+        my ($flags, $new_flags) =
+          Bugzilla::Flag-&gt;extract_flags_from_cgi($bug, $attachment, $vars);
+        $attachment-&gt;set_flags($flags, $new_flags);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    # The order of these function calls is important, as Flag::validate
-    # assumes User::match_field has ensured that the values in the
-    # requestee fields are legitimate user email addresses.
-    Bugzilla::User::match_field($cgi, {
-        '^requestee(_type)?-(\d+)$' =&gt; { 'type' =&gt; 'multi' }
-    });
-    Bugzilla::Flag::validate($bug-&gt;id, $attachment-&gt;id);
</del><ins>+    # Figure out when the changes were made.
+    my $timestamp = $dbh-&gt;selectrow_array('SELECT LOCALTIMESTAMP(0)');
</ins><span class="cx"> 
</span><del>-    # Start a transaction in preparation for updating the attachment.
-    $dbh-&gt;bz_start_transaction();
</del><ins>+    if ($can_edit) {
+        my $changes = $attachment-&gt;update($timestamp);
+        # If there are changes, we updated delta_ts in the DB. We have to
+        # reflect this change in the bug object.
+        $bug-&gt;{delta_ts} = $timestamp if scalar(keys %$changes);
+    }
</ins><span class="cx"> 
</span><del>-  # Quote the description and content type for use in the SQL UPDATE statement.
-  my $description = $cgi-&gt;param('description');
-  my $contenttype = $cgi-&gt;param('contenttype');
-  my $filename = $cgi-&gt;param('filename');
-  # we can detaint this way thanks to placeholders
-  trick_taint($description);
-  trick_taint($contenttype);
-  trick_taint($filename);
</del><ins>+    # Commit the comment, if any.
+    $bug-&gt;update($timestamp);
</ins><span class="cx"> 
</span><del>-  # Figure out when the changes were made.
-  my ($timestamp) = $dbh-&gt;selectrow_array(&quot;SELECT NOW()&quot;);
-    
-  # Update flags.  We have to do this before committing changes
-  # to attachments so that we can delete pending requests if the user
-  # is obsoleting this attachment without deleting any requests
-  # the user submits at the same time.
-  Bugzilla::Flag-&gt;process($bug, $attachment, $timestamp, $vars);
</del><ins>+    # Commit the transaction now that we are finished updating the database.
+    $dbh-&gt;bz_commit_transaction();
</ins><span class="cx"> 
</span><del>-  # Update the attachment record in the database.
-  $dbh-&gt;do(&quot;UPDATE  attachments 
-            SET     description = ?,
-                    mimetype    = ?,
-                    filename    = ?,
-                    ispatch     = ?,
-                    isobsolete  = ?,
-                    isprivate   = ?,
-                    modification_time = ?
-            WHERE   attach_id   = ?&quot;,
-            undef, ($description, $contenttype, $filename,
-            $cgi-&gt;param('ispatch'), $cgi-&gt;param('isobsolete'), 
-            $cgi-&gt;param('isprivate'), $timestamp, $attachment-&gt;id));
</del><ins>+    # Define the variables and functions that will be passed to the UI template.
+    $vars-&gt;{'attachment'} = $attachment;
+    $vars-&gt;{'bugs'} = [$bug];
+    $vars-&gt;{'header_done'} = 1;
+    $vars-&gt;{'sent_bugmail'} = 
+        Bugzilla::BugMail::Send($bug-&gt;id, { 'changer' =&gt; $user });
</ins><span class="cx"> 
</span><del>-  my $updated_attachment = Bugzilla::Attachment-&gt;get($attachment-&gt;id);
-  # Record changes in the activity table.
-  my $sth = $dbh-&gt;prepare('INSERT INTO bugs_activity (bug_id, attach_id, who, bug_when,
-                                                      fieldid, removed, added)
-                           VALUES (?, ?, ?, ?, ?, ?, ?)');
</del><ins>+    print $cgi-&gt;header();
</ins><span class="cx"> 
</span><del>-  if ($attachment-&gt;description ne $updated_attachment-&gt;description) {
-    my $fieldid = get_field_id('attachments.description');
-    $sth-&gt;execute($bug-&gt;id, $attachment-&gt;id, $user-&gt;id, $timestamp, $fieldid,
-                  $attachment-&gt;description, $updated_attachment-&gt;description);
-  }
-  if ($attachment-&gt;contenttype ne $updated_attachment-&gt;contenttype) {
-    my $fieldid = get_field_id('attachments.mimetype');
-    $sth-&gt;execute($bug-&gt;id, $attachment-&gt;id, $user-&gt;id, $timestamp, $fieldid,
-                  $attachment-&gt;contenttype, $updated_attachment-&gt;contenttype);
-  }
-  if ($attachment-&gt;filename ne $updated_attachment-&gt;filename) {
-    my $fieldid = get_field_id('attachments.filename');
-    $sth-&gt;execute($bug-&gt;id, $attachment-&gt;id, $user-&gt;id, $timestamp, $fieldid,
-                  $attachment-&gt;filename, $updated_attachment-&gt;filename);
-  }
-  if ($attachment-&gt;ispatch != $updated_attachment-&gt;ispatch) {
-    my $fieldid = get_field_id('attachments.ispatch');
-    $sth-&gt;execute($bug-&gt;id, $attachment-&gt;id, $user-&gt;id, $timestamp, $fieldid,
-                  $attachment-&gt;ispatch, $updated_attachment-&gt;ispatch);
-  }
-  if ($attachment-&gt;isobsolete != $updated_attachment-&gt;isobsolete) {
-    my $fieldid = get_field_id('attachments.isobsolete');
-    $sth-&gt;execute($bug-&gt;id, $attachment-&gt;id, $user-&gt;id, $timestamp, $fieldid,
-                  $attachment-&gt;isobsolete, $updated_attachment-&gt;isobsolete);
-  }
-  if ($attachment-&gt;isprivate != $updated_attachment-&gt;isprivate) {
-    my $fieldid = get_field_id('attachments.isprivate');
-    $sth-&gt;execute($bug-&gt;id, $attachment-&gt;id, $user-&gt;id, $timestamp, $fieldid,
-                  $attachment-&gt;isprivate, $updated_attachment-&gt;isprivate);
-  }
-  
-  # Commit the transaction now that we are finished updating the database.
-  $dbh-&gt;bz_commit_transaction();
-
-  # Commit the comment, if any.
-  $bug-&gt;update();
-
-  # Define the variables and functions that will be passed to the UI template.
-  $vars-&gt;{'mailrecipients'} = { 'changer' =&gt; Bugzilla-&gt;user-&gt;login };
-  $vars-&gt;{'attachment'} = $attachment;
-  # We cannot reuse the $bug object as delta_ts has eventually been updated
-  # since the object was created.
-  $vars-&gt;{'bugs'} = [new Bugzilla::Bug($bug-&gt;id)];
-  $vars-&gt;{'header_done'} = 1;
-  $vars-&gt;{'use_keywords'} = 1 if Bugzilla::Keyword::keyword_count();
-
-  print $cgi-&gt;header();
-
-  # Generate and return the UI (HTML page) from the appropriate template.
-  $template-&gt;process(&quot;attachment/updated.html.tmpl&quot;, $vars)
-    || ThrowTemplateError($template-&gt;error());
</del><ins>+    # Generate and return the UI (HTML page) from the appropriate template.
+    $template-&gt;process(&quot;attachment/updated.html.tmpl&quot;, $vars)
+      || ThrowTemplateError($template-&gt;error());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> # Only administrators can delete attachments.
</span><span class="lines">@@ -821,7 +825,7 @@
</span><span class="cx"> 
</span><span class="cx">     # Make sure the administrator is allowed to edit this attachment.
</span><span class="cx">     my $attachment = validateID();
</span><del>-    validateCanChangeBug($attachment-&gt;bug_id);
</del><ins>+    Bugzilla::Attachment-&gt;_check_bug($attachment-&gt;bug);
</ins><span class="cx"> 
</span><span class="cx">     $attachment-&gt;datasize || ThrowUserError('attachment_removed');
</span><span class="cx"> 
</span><span class="lines">@@ -831,7 +835,7 @@
</span><span class="cx">         my ($creator_id, $date, $event) = Bugzilla::Token::GetTokenData($token);
</span><span class="cx">         unless ($creator_id
</span><span class="cx">                   &amp;&amp; ($creator_id == $user-&gt;id)
</span><del>-                  &amp;&amp; ($event eq 'attachment' . $attachment-&gt;id))
</del><ins>+                  &amp;&amp; ($event eq 'delete_attachment' . $attachment-&gt;id))
</ins><span class="cx">         {
</span><span class="cx">             # The token is invalid.
</span><span class="cx">             ThrowUserError('token_does_not_exist');
</span><span class="lines">@@ -844,7 +848,6 @@
</span><span class="cx">         $vars-&gt;{'attachment'} = $attachment;
</span><span class="cx">         $vars-&gt;{'date'} = $date;
</span><span class="cx">         $vars-&gt;{'reason'} = clean_text($cgi-&gt;param('reason') || '');
</span><del>-        $vars-&gt;{'mailrecipients'} = { 'changer' =&gt; $user-&gt;login };
</del><span class="cx"> 
</span><span class="cx">         $template-&gt;process(&quot;attachment/delete_reason.txt.tmpl&quot;, $vars, \$msg)
</span><span class="cx">           || ThrowTemplateError($template-&gt;error());
</span><span class="lines">@@ -867,14 +870,16 @@
</span><span class="cx">         # Required to display the bug the deleted attachment belongs to.
</span><span class="cx">         $vars-&gt;{'bugs'} = [$bug];
</span><span class="cx">         $vars-&gt;{'header_done'} = 1;
</span><del>-        $vars-&gt;{'use_keywords'} = 1 if Bugzilla::Keyword::keyword_count();
</del><span class="cx"> 
</span><ins>+        $vars-&gt;{'sent_bugmail'} =
+            Bugzilla::BugMail::Send($bug-&gt;id, { 'changer' =&gt; $user });
+
</ins><span class="cx">         $template-&gt;process(&quot;attachment/updated.html.tmpl&quot;, $vars)
</span><span class="cx">           || ThrowTemplateError($template-&gt;error());
</span><span class="cx">     }
</span><span class="cx">     else {
</span><span class="cx">         # Create a token.
</span><del>-        $token = issue_session_token('attachment' . $attachment-&gt;id);
</del><ins>+        $token = issue_session_token('delete_attachment' . $attachment-&gt;id);
</ins><span class="cx"> 
</span><span class="cx">         $vars-&gt;{'a'} = $attachment;
</span><span class="cx">         $vars-&gt;{'token'} = $token;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgbuglistcgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/buglist.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/buglist.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/buglist.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -40,6 +40,7 @@
</span><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> use Bugzilla::Search;
</span><span class="cx"> use Bugzilla::Search::Quicksearch;
</span><ins>+use Bugzilla::Search::Recent;
</ins><span class="cx"> use Bugzilla::Search::Saved;
</span><span class="cx"> use Bugzilla::User;
</span><span class="cx"> use Bugzilla::Bug;
</span><span class="lines">@@ -60,13 +61,15 @@
</span><span class="cx"> # We have to check the login here to get the correct footer if an error is
</span><span class="cx"> # thrown and to prevent a logged out user to use QuickSearch if 'requirelogin'
</span><span class="cx"> # is turned 'on'.
</span><del>-Bugzilla-&gt;login();
</del><ins>+my $user = Bugzilla-&gt;login();
</ins><span class="cx"> 
</span><span class="cx"> if (length($buffer) == 0) {
</span><span class="cx">     print $cgi-&gt;header(-refresh=&gt; '10; URL=query.cgi');
</span><span class="cx">     ThrowUserError(&quot;buglist_parameters_required&quot;);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+$cgi-&gt;redirect_search_url();
+
</ins><span class="cx"> # Determine whether this is a quicksearch query.
</span><span class="cx"> my $searchstring = $cgi-&gt;param('quicksearch');
</span><span class="cx"> if (defined($searchstring)) {
</span><span class="lines">@@ -79,7 +82,7 @@
</span><span class="cx"> # If configured to not allow empty words, reject empty searches from the
</span><span class="cx"> # Find a Specific Bug search form, including words being a single or 
</span><span class="cx"> # several consecutive whitespaces only.
</span><del>-if (!Bugzilla-&gt;params-&gt;{'specific_search_allow_empty_words'}
</del><ins>+if (!Bugzilla-&gt;params-&gt;{'search_allow_no_criteria'}
</ins><span class="cx">     &amp;&amp; defined($cgi-&gt;param('content')) &amp;&amp; $cgi-&gt;param('content') =~ /^\s*$/)
</span><span class="cx"> {
</span><span class="cx">     ThrowUserError(&quot;buglist_parameters_required&quot;);
</span><span class="lines">@@ -109,16 +112,6 @@
</span><span class="cx">     $cgi-&gt;param('ctype', &quot;atom&quot;);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-# The js ctype presents a security risk; a malicious site could use it  
-# to gather information about secure bugs. So, we only allow public bugs to be
-# retrieved with this format.
-#
-# Note that if and when this call clears cookies or has other persistent 
-# effects, we'll need to do this another way instead.
-if ((defined $cgi-&gt;param('ctype')) &amp;&amp; ($cgi-&gt;param('ctype') eq &quot;js&quot;)) {
-    Bugzilla-&gt;logout_request();
-}
-
</del><span class="cx"> # An agent is a program that automatically downloads and extracts data
</span><span class="cx"> # on its user's behalf.  If this request comes from an agent, we turn off
</span><span class="cx"> # various aspects of bug list functionality so agent requests succeed
</span><span class="lines">@@ -154,37 +147,34 @@
</span><span class="cx">                 || $cgi-&gt;param('serverpush');
</span><span class="cx"> 
</span><span class="cx"> my $order = $cgi-&gt;param('order') || &quot;&quot;;
</span><del>-my $order_from_cookie = 0;  # True if $order set using the LASTORDER cookie
</del><span class="cx"> 
</span><span class="cx"> # The params object to use for the actual query itself
</span><span class="cx"> my $params;
</span><span class="cx"> 
</span><span class="cx"> # If the user is retrieving the last bug list they looked at, hack the buffer
</span><span class="cx"> # storing the query string so that it looks like a query retrieving those bugs.
</span><del>-if (defined $cgi-&gt;param('regetlastlist')) {
-    $cgi-&gt;cookie('BUGLIST') || ThrowUserError(&quot;missing_cookie&quot;);
</del><ins>+if (my $last_list = $cgi-&gt;param('regetlastlist')) {
+    my $bug_ids;
</ins><span class="cx"> 
</span><del>-    $order = &quot;reuse last sort&quot; unless $order;
-    my $bug_id = $cgi-&gt;cookie('BUGLIST');
-    $bug_id =~ s/:/,/g;
</del><ins>+    # Logged-out users use the old cookie method for storing the last search.
+    if (!$user-&gt;id or $last_list eq 'cookie') {
+        $bug_ids = $cgi-&gt;cookie('BUGLIST') or ThrowUserError(&quot;missing_cookie&quot;);
+        $bug_ids =~ s/[:-]/,/g;
+        $order ||= &quot;reuse last sort&quot;;
+    }
+    # But logged in users store the last X searches in the DB so they can
+    # have multiple bug lists available.
+    else {
+        my $last_search = Bugzilla::Search::Recent-&gt;check(
+            { id =&gt; $last_list });
+        $bug_ids = join(',', @{ $last_search-&gt;bug_list });
+        $order ||= $last_search-&gt;list_order;
+    }
</ins><span class="cx">     # set up the params for this new query
</span><del>-    $params = new Bugzilla::CGI({
-                                 bug_id =&gt; $bug_id,
-                                 order =&gt; $order,
-                                });
</del><ins>+    $params = new Bugzilla::CGI({ bug_id =&gt; $bug_ids, order =&gt; $order });
+    $params-&gt;param('list_id', $last_list);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-if ($buffer =~ /&amp;cmd-/) {
-    my $url = &quot;query.cgi?$buffer#chart&quot;;
-    print $cgi-&gt;redirect(-location =&gt; $url);
-    # Generate and return the UI (HTML page) from the appropriate template.
-    $vars-&gt;{'message'} = &quot;buglist_adding_field&quot;;
-    $vars-&gt;{'url'} = $url;
-    $template-&gt;process(&quot;global/message.html.tmpl&quot;, $vars)
-      || ThrowTemplateError($template-&gt;error());
-    exit;
-}
-
</del><span class="cx"> # Figure out whether or not the user is doing a fulltext search.  If not,
</span><span class="cx"> # we'll remove the relevance column from the lists of columns to display
</span><span class="cx"> # and order by, since relevance only exists when doing a fulltext search.
</span><span class="lines">@@ -202,82 +192,35 @@
</span><span class="cx"> # Utilities
</span><span class="cx"> ################################################################################
</span><span class="cx"> 
</span><del>-local our @weekday= qw( Sun Mon Tue Wed Thu Fri Sat );
</del><span class="cx"> sub DiffDate {
</span><span class="cx">     my ($datestr) = @_;
</span><span class="cx">     my $date = str2time($datestr);
</span><span class="cx">     my $age = time() - $date;
</span><del>-    my ($s,$m,$h,$d,$mo,$y,$wd)= localtime $date;
</del><ins>+
</ins><span class="cx">     if( $age &lt; 18*60*60 ) {
</span><del>-        $date = sprintf &quot;%02d:%02d:%02d&quot;, $h,$m,$s;
</del><ins>+        $date = format_time($datestr, '%H:%M:%S');
</ins><span class="cx">     } elsif( $age &lt; 6*24*60*60 ) {
</span><del>-        $date = sprintf &quot;%s %02d:%02d&quot;, $weekday[$wd],$h,$m;
</del><ins>+        $date = format_time($datestr, '%a %H:%M');
</ins><span class="cx">     } else {
</span><del>-        $date = sprintf &quot;%04d-%02d-%02d&quot;, 1900+$y,$mo+1,$d;
</del><ins>+        $date = format_time($datestr, '%Y-%m-%d');
</ins><span class="cx">     }
</span><span class="cx">     return $date;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub LookupNamedQuery {
</span><del>-    my ($name, $sharer_id, $query_type, $throw_error) = @_;
-    my $user = Bugzilla-&gt;login(LOGIN_REQUIRED);
-    my $dbh = Bugzilla-&gt;dbh;
-    my $owner_id;
-    $throw_error = 1 unless defined $throw_error;
</del><ins>+    my ($name, $sharer_id) = @_;
</ins><span class="cx"> 
</span><del>-    # $name and $sharer_id are safe -- we only use them below in SELECT
-    # placeholders and then in error messages (which are always HTML-filtered).
-    $name || ThrowUserError(&quot;query_name_missing&quot;);
-    trick_taint($name);
-    if ($sharer_id) {
-        $owner_id = $sharer_id;
-        detaint_natural($owner_id);
-        $owner_id || ThrowUserError('illegal_user_id', {'userid' =&gt; $sharer_id});
-    }
-    else {
-        $owner_id = $user-&gt;id;
-    }
</del><ins>+    Bugzilla-&gt;login(LOGIN_REQUIRED);
</ins><span class="cx"> 
</span><del>-    my @args = ($owner_id, $name);
-    my $extra = '';
-    # If $query_type is defined, then we restrict our search.
-    if (defined $query_type) {
-        $extra = ' AND query_type = ? ';
-        detaint_natural($query_type);
-        push(@args, $query_type);
-    }
-    my ($id, $result) = $dbh-&gt;selectrow_array(&quot;SELECT id, query
-                                                 FROM namedqueries
-                                                WHERE userid = ? AND name = ?
-                                                      $extra&quot;,
-                                               undef, @args);
</del><ins>+    my $query = Bugzilla::Search::Saved-&gt;check(
+        { user =&gt; $sharer_id, name =&gt; $name });
</ins><span class="cx"> 
</span><del>-    # Some DBs (read: Oracle) incorrectly mark this string as UTF-8
-    # even though it has no UTF-8 characters in it, which prevents
-    # Bugzilla::CGI from later reading it correctly.
-    utf8::downgrade($result) if utf8::is_utf8($result);
</del><ins>+    $query-&gt;url
+       || ThrowUserError(&quot;buglist_parameters_required&quot;);
</ins><span class="cx"> 
</span><del>-    if (!defined($result)) {
-        return 0 unless $throw_error;
-        ThrowUserError(&quot;missing_query&quot;, {'queryname' =&gt; $name,
-                                         'sharer_id' =&gt; $sharer_id});
-    }
-
-    if ($sharer_id) {
-        my $group = $dbh-&gt;selectrow_array('SELECT group_id
-                                             FROM namedquery_group_map
-                                            WHERE namedquery_id = ?',
-                                          undef, $id);
-        if (!grep {$_ == $group} values(%{$user-&gt;groups()})) {
-            ThrowUserError(&quot;missing_query&quot;, {'queryname' =&gt; $name,
-                                             'sharer_id' =&gt; $sharer_id});
-        }
-    }
-    
-    $result
-       || ThrowUserError(&quot;buglist_parameters_required&quot;, {'queryname' =&gt; $name});
-
-    return wantarray ? ($result, $id) : $result;
</del><ins>+    # Detaint $sharer_id.
+    $sharer_id = $query-&gt;user-&gt;id if $sharer_id;
+    return wantarray ? ($query-&gt;url, $query-&gt;id, $sharer_id) : $query-&gt;url;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> # Inserts a Named Query (a &quot;Saved Search&quot;) into the database, or
</span><span class="lines">@@ -293,15 +236,13 @@
</span><span class="cx"> #         empty, or we will throw a UserError.
</span><span class="cx"> # link_in_footer (optional) - 1 if the Named Query should be 
</span><span class="cx"> # displayed in the user's footer, 0 otherwise.
</span><del>-# query_type (optional) - 1 if the Named Query contains a list of
-# bug IDs only, 0 otherwise (default).
</del><span class="cx"> #
</span><span class="cx"> # All parameters are validated before passing them into the database.
</span><span class="cx"> #
</span><span class="cx"> # Returns: A boolean true value if the query existed in the database 
</span><span class="cx"> # before, and we updated it. A boolean false value otherwise.
</span><span class="cx"> sub InsertNamedQuery {
</span><del>-    my ($query_name, $query, $link_in_footer, $query_type) = @_;
</del><ins>+    my ($query_name, $query, $link_in_footer) = @_;
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx"> 
</span><span class="cx">     $query_name = trim($query_name);
</span><span class="lines">@@ -310,13 +251,11 @@
</span><span class="cx">     if ($query_obj) {
</span><span class="cx">         $query_obj-&gt;set_name($query_name);
</span><span class="cx">         $query_obj-&gt;set_url($query);
</span><del>-        $query_obj-&gt;set_query_type($query_type);
</del><span class="cx">         $query_obj-&gt;update();
</span><span class="cx">     } else {
</span><span class="cx">         Bugzilla::Search::Saved-&gt;create({
</span><span class="cx">             name           =&gt; $query_name,
</span><span class="cx">             query          =&gt; $query,
</span><del>-            query_type     =&gt; $query_type,
</del><span class="cx">             link_in_footer =&gt; $link_in_footer
</span><span class="cx">         });
</span><span class="cx">     }
</span><span class="lines">@@ -398,14 +337,15 @@
</span><span class="cx"> # Command Execution
</span><span class="cx"> ################################################################################
</span><span class="cx"> 
</span><del>-$cgi-&gt;param('cmdtype', &quot;&quot;) if !defined $cgi-&gt;param('cmdtype');
-$cgi-&gt;param('remaction', &quot;&quot;) if !defined $cgi-&gt;param('remaction');
</del><ins>+my $cmdtype   = $cgi-&gt;param('cmdtype')   || '';
+my $remaction = $cgi-&gt;param('remaction') || '';
+my $sharer_id;
</ins><span class="cx"> 
</span><span class="cx"> # Backwards-compatibility - the old interface had cmdtype=&quot;runnamed&quot; to run
</span><span class="cx"> # a named command, and we can't break this because it's in bookmarks.
</span><del>-if ($cgi-&gt;param('cmdtype') eq &quot;runnamed&quot;) {  
-    $cgi-&gt;param('cmdtype', &quot;dorem&quot;);
-    $cgi-&gt;param('remaction', &quot;run&quot;);
</del><ins>+if ($cmdtype eq &quot;runnamed&quot;) {  
+    $cmdtype = &quot;dorem&quot;;
+    $remaction = &quot;run&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> # Now we're going to be running, so ensure that the params object is set up,
</span><span class="lines">@@ -423,7 +363,7 @@
</span><span class="cx"> my @time = localtime(time());
</span><span class="cx"> my $date = sprintf &quot;%04d-%02d-%02d&quot;, 1900+$time[5],$time[4]+1,$time[3];
</span><span class="cx"> my $filename = &quot;bugs-$date.$format-&gt;{extension}&quot;;
</span><del>-if ($cgi-&gt;param('cmdtype') eq &quot;dorem&quot; &amp;&amp; $cgi-&gt;param('remaction') =~ /^run/) {
</del><ins>+if ($cmdtype eq &quot;dorem&quot; &amp;&amp; $remaction =~ /^run/) {
</ins><span class="cx">     $filename = $cgi-&gt;param('namedcmd') . &quot;-$date.$format-&gt;{extension}&quot;;
</span><span class="cx">     # Remove white-space from the filename so the user cannot tamper
</span><span class="cx">     # with the HTTP headers.
</span><span class="lines">@@ -433,11 +373,12 @@
</span><span class="cx"> $filename =~ s/&quot;/\\&quot;/g; # escape quotes
</span><span class="cx"> 
</span><span class="cx"> # Take appropriate action based on user's request.
</span><del>-if ($cgi-&gt;param('cmdtype') eq &quot;dorem&quot;) {  
-    if ($cgi-&gt;param('remaction') eq &quot;run&quot;) {
</del><ins>+if ($cmdtype eq &quot;dorem&quot;) {  
+    if ($remaction eq &quot;run&quot;) {
</ins><span class="cx">         my $query_id;
</span><del>-        ($buffer, $query_id) = LookupNamedQuery(scalar $cgi-&gt;param(&quot;namedcmd&quot;),
-                                                scalar $cgi-&gt;param('sharer_id'));
</del><ins>+        ($buffer, $query_id, $sharer_id) =
+          LookupNamedQuery(scalar $cgi-&gt;param(&quot;namedcmd&quot;),
+                           scalar $cgi-&gt;param('sharer_id'));
</ins><span class="cx">         # If this is the user's own query, remember information about it
</span><span class="cx">         # so that it can be modified easily.
</span><span class="cx">         $vars-&gt;{'searchname'} = $cgi-&gt;param('namedcmd');
</span><span class="lines">@@ -450,15 +391,15 @@
</span><span class="cx">         $order = $params-&gt;param('order') || $order;
</span><span class="cx"> 
</span><span class="cx">     }
</span><del>-    elsif ($cgi-&gt;param('remaction') eq &quot;runseries&quot;) {
</del><ins>+    elsif ($remaction eq &quot;runseries&quot;) {
</ins><span class="cx">         $buffer = LookupSeries(scalar $cgi-&gt;param(&quot;series_id&quot;));
</span><span class="cx">         $vars-&gt;{'searchname'} = $cgi-&gt;param('namedcmd');
</span><span class="cx">         $vars-&gt;{'searchtype'} = &quot;series&quot;;
</span><span class="cx">         $params = new Bugzilla::CGI($buffer);
</span><span class="cx">         $order = $params-&gt;param('order') || $order;
</span><span class="cx">     }
</span><del>-    elsif ($cgi-&gt;param('remaction') eq &quot;forget&quot;) {
-        my $user = Bugzilla-&gt;login(LOGIN_REQUIRED);
</del><ins>+    elsif ($remaction eq &quot;forget&quot;) {
+        $user = Bugzilla-&gt;login(LOGIN_REQUIRED);
</ins><span class="cx">         # Copy the name into a variable, so that we can trick_taint it for
</span><span class="cx">         # the DB. We know it's safe, because we're using placeholders in 
</span><span class="cx">         # the SQL, and the SQL is only a DELETE.
</span><span class="lines">@@ -485,14 +426,10 @@
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         # If we are here, then we can safely remove the saved search
</span><del>-        my ($query_id) = $dbh-&gt;selectrow_array('SELECT id FROM namedqueries
-                                                    WHERE userid = ?
-                                                      AND name   = ?',
-                                                  undef, ($user-&gt;id, $qname));
-        if (!$query_id) {
-            # The user has no query of this name. Play along.
-        }
-        else {
</del><ins>+        my $query_id;
+        ($buffer, $query_id) = LookupNamedQuery(scalar $cgi-&gt;param(&quot;namedcmd&quot;),
+                                                $user-&gt;id);
+        if ($query_id) {
</ins><span class="cx">             # Make sure the user really wants to delete his saved search.
</span><span class="cx">             my $token = $cgi-&gt;param('token');
</span><span class="cx">             check_hash_token($token, [$query_id, $qname]);
</span><span class="lines">@@ -515,103 +452,70 @@
</span><span class="cx">         # Generate and return the UI (HTML page) from the appropriate template.
</span><span class="cx">         $vars-&gt;{'message'} = &quot;buglist_query_gone&quot;;
</span><span class="cx">         $vars-&gt;{'namedcmd'} = $qname;
</span><del>-        $vars-&gt;{'url'} = &quot;query.cgi&quot;;
</del><ins>+        $vars-&gt;{'url'} = &quot;buglist.cgi?newquery=&quot; . url_quote($buffer) . &quot;&amp;cmdtype=doit&amp;remtype=asnamed&amp;newqueryname=&quot; . url_quote($qname);
</ins><span class="cx">         $template-&gt;process(&quot;global/message.html.tmpl&quot;, $vars)
</span><span class="cx">           || ThrowTemplateError($template-&gt;error());
</span><span class="cx">         exit;
</span><span class="cx">     }
</span><span class="cx"> }
</span><del>-elsif (($cgi-&gt;param('cmdtype') eq &quot;doit&quot;) &amp;&amp; defined $cgi-&gt;param('remtype')) {
</del><ins>+elsif (($cmdtype eq &quot;doit&quot;) &amp;&amp; defined $cgi-&gt;param('remtype')) {
</ins><span class="cx">     if ($cgi-&gt;param('remtype') eq &quot;asdefault&quot;) {
</span><del>-        my $user = Bugzilla-&gt;login(LOGIN_REQUIRED);
</del><ins>+        $user = Bugzilla-&gt;login(LOGIN_REQUIRED);
</ins><span class="cx">         InsertNamedQuery(DEFAULT_QUERY_NAME, $buffer);
</span><span class="cx">         $vars-&gt;{'message'} = &quot;buglist_new_default_query&quot;;
</span><span class="cx">     }
</span><span class="cx">     elsif ($cgi-&gt;param('remtype') eq &quot;asnamed&quot;) {
</span><del>-        my $user = Bugzilla-&gt;login(LOGIN_REQUIRED);
</del><ins>+        $user = Bugzilla-&gt;login(LOGIN_REQUIRED);
</ins><span class="cx">         my $query_name = $cgi-&gt;param('newqueryname');
</span><span class="cx">         my $new_query = $cgi-&gt;param('newquery');
</span><del>-        my $query_type = QUERY_LIST;
-        # If list_of_bugs is true, we are adding/removing individual bugs
-        # to a saved search. We get the existing list of bug IDs (if any)
-        # and add/remove the passed ones.
</del><ins>+        my $token = $cgi-&gt;param('token');
+        check_hash_token($token, ['savedsearch']);
+        # If list_of_bugs is true, we are adding/removing tags to/from
+        # individual bugs.
</ins><span class="cx">         if ($cgi-&gt;param('list_of_bugs')) {
</span><del>-            # We add or remove bugs based on the action choosen.
</del><ins>+            # We add/remove tags based on the action choosen.
</ins><span class="cx">             my $action = trim($cgi-&gt;param('action') || '');
</span><span class="cx">             $action =~ /^(add|remove)$/
</span><del>-              || ThrowCodeError('unknown_action', {'action' =&gt; $action});
</del><ins>+              || ThrowUserError('unknown_action', {action =&gt; $action});
</ins><span class="cx"> 
</span><del>-            # If we are removing bugs, then we must have an existing
-            # saved search selected.
-            if ($action eq 'remove') {
-                $query_name &amp;&amp; ThrowUserError('no_bugs_to_remove');
-            }
</del><ins>+            my $method = &quot;${action}_tag&quot;;
</ins><span class="cx"> 
</span><del>-            my %bug_ids;
-            my $is_new_name = 0;
-            if ($query_name) {
-                my ($query, $query_id) =
-                  LookupNamedQuery($query_name, undef, QUERY_LIST, !THROW_ERROR);
-                # Make sure this name is not already in use by a normal saved search.
-                if ($query) {
-                    ThrowUserError('query_name_exists', {name     =&gt; $query_name,
-                                                         query_id =&gt; $query_id});
-                }
-                $is_new_name = 1;
-            }
</del><span class="cx">             # If no new tag name has been given, use the selected one.
</span><del>-            $query_name ||= $cgi-&gt;param('oldqueryname');
</del><ins>+            $query_name ||= $cgi-&gt;param('oldqueryname')
+              or ThrowUserError('no_tag_to_edit', {action =&gt; $action});
</ins><span class="cx"> 
</span><del>-            # Don't throw an error if it's a new tag name: if the tag already
-            # exists, add/remove bugs to it, else create it. But if we are
-            # considering an existing tag, then it has to exist and we throw
-            # an error if it doesn't (hence the usage of !$is_new_name).
-            if (my $old_query = LookupNamedQuery($query_name, undef, LIST_OF_BUGS, !$is_new_name)) {
-                # We get the encoded query. We need to decode it.
-                my $old_cgi = new Bugzilla::CGI($old_query);
-                foreach my $bug_id (split /[\s,]+/, scalar $old_cgi-&gt;param('bug_id')) {
-                    $bug_ids{$bug_id} = 1 if detaint_natural($bug_id);
-                }
-            }
-
-            my $keep_bug = ($action eq 'add') ? 1 : 0;
-            my $changes = 0;
</del><ins>+            my @buglist;
+            # Validate all bug IDs before editing tags in any of them.
</ins><span class="cx">             foreach my $bug_id (split(/[\s,]+/, $cgi-&gt;param('bug_ids'))) {
</span><span class="cx">                 next unless $bug_id;
</span><del>-                ValidateBugID($bug_id);
-                $bug_ids{$bug_id} = $keep_bug;
-                $changes = 1;
</del><ins>+                push(@buglist, Bugzilla::Bug-&gt;check($bug_id));
</ins><span class="cx">             }
</span><del>-            ThrowUserError('no_bug_ids',
-                           {'action' =&gt; $action,
-                            'tag' =&gt; $query_name})
-              unless $changes;
</del><span class="cx"> 
</span><del>-            # Only keep bug IDs we want to add/keep. Disregard deleted ones.
-            my @bug_ids = grep { $bug_ids{$_} == 1 } keys %bug_ids;
-            # If the list is now empty, we could as well delete it completely.
-            ThrowUserError('no_bugs_in_list', {'tag' =&gt; $query_name})
-              unless scalar(@bug_ids);
</del><ins>+            foreach my $bug (@buglist) {
+                $bug-&gt;$method($query_name);
+            }
</ins><span class="cx"> 
</span><del>-            $new_query = &quot;bug_id=&quot; . join(',', sort {$a &lt;=&gt; $b} @bug_ids);
-            $query_type = LIST_OF_BUGS;
</del><ins>+            $vars-&gt;{'message'} = 'tag_updated';
+            $vars-&gt;{'action'} = $action;
+            $vars-&gt;{'tag'} = $query_name;
+            $vars-&gt;{'buglist'} = [map { $_-&gt;id } @buglist];
</ins><span class="cx">         }
</span><del>-        my $tofooter = 1;
-        my $existed_before = InsertNamedQuery($query_name, $new_query,
-                                              $tofooter, $query_type);
-        if ($existed_before) {
-            $vars-&gt;{'message'} = &quot;buglist_updated_named_query&quot;;
-        }
</del><span class="cx">         else {
</span><del>-            $vars-&gt;{'message'} = &quot;buglist_new_named_query&quot;;
-        }
</del><ins>+            my $existed_before = InsertNamedQuery($query_name, $new_query, 1);
+            if ($existed_before) {
+                $vars-&gt;{'message'} = &quot;buglist_updated_named_query&quot;;
+            }
+            else {
+                $vars-&gt;{'message'} = &quot;buglist_new_named_query&quot;;
+            }
</ins><span class="cx"> 
</span><del>-        # Make sure to invalidate any cached query data, so that the footer is
-        # correctly displayed
-        $user-&gt;flush_queries_cache();
</del><ins>+            # Make sure to invalidate any cached query data, so that the footer is
+            # correctly displayed
+            $user-&gt;flush_queries_cache();
</ins><span class="cx"> 
</span><del>-        $vars-&gt;{'queryname'} = $query_name;
-        
</del><ins>+            $vars-&gt;{'queryname'} = $query_name;
+        }
+
</ins><span class="cx">         print $cgi-&gt;header();
</span><span class="cx">         $template-&gt;process(&quot;global/message.html.tmpl&quot;, $vars)
</span><span class="cx">           || ThrowTemplateError($template-&gt;error());
</span><span class="lines">@@ -631,84 +535,8 @@
</span><span class="cx"> # Column Definition
</span><span class="cx"> ################################################################################
</span><span class="cx"> 
</span><del>-# Define the columns that can be selected in a query and/or displayed in a bug
-# list.  Column records include the following fields:
-#
-# 1. ID: a unique identifier by which the column is referred in code;
-#
-# 2. Name: The name of the column in the database (may also be an expression
-#          that returns the value of the column);
-#
-# 3. Title: The title of the column as displayed to users.
-# 
-# Note: There are a few hacks in the code that deviate from these definitions.
-#       In particular, when the list is sorted by the &quot;votes&quot; field the word 
-#       &quot;DESC&quot; is added to the end of the field to sort in descending order, 
-#       and the redundant short_desc column is removed when the client
-#       requests &quot;all&quot; columns.
-# Note: For column names using aliasing (SQL &quot;&lt;field&gt; AS &lt;alias&gt;&quot;), the column
-#       ID needs to be identical to the field ID for list ordering to work.
</del><ins>+my $columns = Bugzilla::Search::COLUMNS;
</ins><span class="cx"> 
</span><del>-local our $columns = {};
-sub DefineColumn {
-    my ($id, $name, $title) = @_;
-    $columns-&gt;{$id} = { 'name' =&gt; $name , 'title' =&gt; $title };
-}
-
-# Column:     ID                    Name                           Title
-DefineColumn(&quot;bug_id&quot;            , &quot;bugs.bug_id&quot;                , &quot;ID&quot;               );
-DefineColumn(&quot;alias&quot;             , &quot;bugs.alias&quot;                 , &quot;Alias&quot;            );
-DefineColumn(&quot;opendate&quot;          , &quot;bugs.creation_ts&quot;           , &quot;Opened&quot;           );
-DefineColumn(&quot;changeddate&quot;       , &quot;bugs.delta_ts&quot;              , &quot;Changed&quot;          );
-DefineColumn(&quot;bug_severity&quot;      , &quot;bugs.bug_severity&quot;          , &quot;Severity&quot;         );
-DefineColumn(&quot;priority&quot;          , &quot;bugs.priority&quot;              , &quot;Priority&quot;         );
-DefineColumn(&quot;rep_platform&quot;      , &quot;bugs.rep_platform&quot;          , &quot;Hardware&quot;         );
-DefineColumn(&quot;assigned_to&quot;       , &quot;map_assigned_to.login_name&quot; , &quot;Assignee&quot;         );
-DefineColumn(&quot;reporter&quot;          , &quot;map_reporter.login_name&quot;    , &quot;Reporter&quot;         );
-DefineColumn(&quot;qa_contact&quot;        , &quot;map_qa_contact.login_name&quot;  , &quot;QA Contact&quot;       );
-if ($format-&gt;{'extension'} eq 'html') {
-    DefineColumn(&quot;assigned_to_realname&quot;, &quot;CASE WHEN map_assigned_to.realname = '' THEN map_assigned_to.login_name ELSE map_assigned_to.realname END AS assigned_to_realname&quot;, &quot;Assignee&quot;  );
-    DefineColumn(&quot;reporter_realname&quot;   , &quot;CASE WHEN map_reporter.realname    = '' THEN map_reporter.login_name    ELSE map_reporter.realname    END AS reporter_realname&quot;   , &quot;Reporter&quot;  );
-    DefineColumn(&quot;qa_contact_realname&quot; , &quot;CASE WHEN map_qa_contact.realname  = '' THEN map_qa_contact.login_name  ELSE map_qa_contact.realname  END AS qa_contact_realname&quot; , &quot;QA Contact&quot;);
-} else {
-    DefineColumn(&quot;assigned_to_realname&quot;, &quot;map_assigned_to.realname AS assigned_to_realname&quot;, &quot;Assignee&quot;  );
-    DefineColumn(&quot;reporter_realname&quot;   , &quot;map_reporter.realname AS reporter_realname&quot;      , &quot;Reporter&quot;  );
-    DefineColumn(&quot;qa_contact_realname&quot; , &quot;map_qa_contact.realname AS qa_contact_realname&quot;  , &quot;QA Contact&quot;);
-}
-DefineColumn(&quot;bug_status&quot;        , &quot;bugs.bug_status&quot;            , &quot;Status&quot;           );
-DefineColumn(&quot;resolution&quot;        , &quot;bugs.resolution&quot;            , &quot;Resolution&quot;       );
-DefineColumn(&quot;short_short_desc&quot;  , &quot;bugs.short_desc&quot;            , &quot;Summary&quot;          );
-DefineColumn(&quot;short_desc&quot;        , &quot;bugs.short_desc&quot;            , &quot;Summary&quot;          );
-DefineColumn(&quot;status_whiteboard&quot; , &quot;bugs.status_whiteboard&quot;     , &quot;Whiteboard&quot;       );
-DefineColumn(&quot;component&quot;         , &quot;map_components.name&quot;        , &quot;Component&quot;        );
-DefineColumn(&quot;product&quot;           , &quot;map_products.name&quot;          , &quot;Product&quot;          );
-DefineColumn(&quot;classification&quot;    , &quot;map_classifications.name&quot;   , &quot;Classification&quot;   );
-DefineColumn(&quot;version&quot;           , &quot;bugs.version&quot;               , &quot;Version&quot;          );
-DefineColumn(&quot;op_sys&quot;            , &quot;bugs.op_sys&quot;                , &quot;OS&quot;               );
-DefineColumn(&quot;target_milestone&quot;  , &quot;bugs.target_milestone&quot;      , &quot;Target Milestone&quot; );
-DefineColumn(&quot;votes&quot;             , &quot;bugs.votes&quot;                 , &quot;Votes&quot;            );
-DefineColumn(&quot;keywords&quot;          , &quot;bugs.keywords&quot;              , &quot;Keywords&quot;         );
-DefineColumn(&quot;estimated_time&quot;    , &quot;bugs.estimated_time&quot;        , &quot;Estimated Hours&quot;  );
-DefineColumn(&quot;remaining_time&quot;    , &quot;bugs.remaining_time&quot;        , &quot;Remaining Hours&quot;  );
-DefineColumn(&quot;actual_time&quot;       , &quot;(SUM(ldtime.work_time)*COUNT(DISTINCT ldtime.bug_when)/COUNT(bugs.bug_id)) AS actual_time&quot;, &quot;Actual Hours&quot;);
-DefineColumn(&quot;percentage_complete&quot;,
-    &quot;(CASE WHEN (SUM(ldtime.work_time)*COUNT(DISTINCT ldtime.bug_when)/COUNT(bugs.bug_id)) &quot; .
-    &quot;            + bugs.remaining_time = 0.0 &quot; .
-    &quot;THEN 0.0 &quot; .
-    &quot;ELSE 100*((SUM(ldtime.work_time)*COUNT(DISTINCT ldtime.bug_when)/COUNT(bugs.bug_id)) &quot; .
-    &quot;     /((SUM(ldtime.work_time)*COUNT(DISTINCT ldtime.bug_when)/COUNT(bugs.bug_id)) + bugs.remaining_time)) &quot; .
-    &quot;END) AS percentage_complete&quot;                               , &quot;% Complete&quot;); 
-DefineColumn(&quot;relevance&quot;         , &quot;relevance&quot;                  , &quot;Relevance&quot;        );
-DefineColumn(&quot;deadline&quot;          , $dbh-&gt;sql_date_format('bugs.deadline', '%Y-%m-%d') . &quot; AS deadline&quot;, &quot;Deadline&quot;);
-
-foreach my $field (Bugzilla-&gt;active_custom_fields) {
-    # Multi-select fields are not (yet) supported in buglists.
-    next if $field-&gt;type == FIELD_TYPE_MULTI_SELECT;
-    DefineColumn($field-&gt;name, 'bugs.' . $field-&gt;name, $field-&gt;description);
-}
-
-Bugzilla::Hook::process(&quot;buglist-columns&quot;, {'columns' =&gt; $columns} );
-
</del><span class="cx"> ################################################################################
</span><span class="cx"> # Display Column Determination
</span><span class="cx"> ################################################################################
</span><span class="lines">@@ -754,21 +582,9 @@
</span><span class="cx"> # and are hard-coded into the display templates.
</span><span class="cx"> @displaycolumns = grep($_ ne 'bug_id', @displaycolumns);
</span><span class="cx"> 
</span><del>-# Add the votes column to the list of columns to be displayed
-# in the bug list if the user is searching for bugs with a certain
-# number of votes and the votes column is not already on the list.
-
-# Some versions of perl will taint 'votes' if this is done as a single
-# statement, because the votes param is tainted at this point
-my $votes = $params-&gt;param('votes');
-$votes ||= &quot;&quot;;
-if (trim($votes) &amp;&amp; !grep($_ eq 'votes', @displaycolumns)) {
-    push(@displaycolumns, 'votes');
-}
-
</del><span class="cx"> # Remove the timetracking columns if they are not a part of the group
</span><span class="cx"> # (happens if a user had access to time tracking and it was revoked/disabled)
</span><del>-if (!Bugzilla-&gt;user-&gt;in_group(Bugzilla-&gt;params-&gt;{&quot;timetrackinggroup&quot;})) {
</del><ins>+if (!Bugzilla-&gt;user-&gt;is_timetracker) {
</ins><span class="cx">    @displaycolumns = grep($_ ne 'estimated_time', @displaycolumns);
</span><span class="cx">    @displaycolumns = grep($_ ne 'remaining_time', @displaycolumns);
</span><span class="cx">    @displaycolumns = grep($_ ne 'actual_time', @displaycolumns);
</span><span class="lines">@@ -792,27 +608,35 @@
</span><span class="cx"> # Severity, priority, resolution and status are required for buglist
</span><span class="cx"> # CSS classes.
</span><span class="cx"> my @selectcolumns = (&quot;bug_id&quot;, &quot;bug_severity&quot;, &quot;priority&quot;, &quot;bug_status&quot;,
</span><del>-                     &quot;resolution&quot;);
</del><ins>+                     &quot;resolution&quot;, &quot;product&quot;);
</ins><span class="cx"> 
</span><del>-# if using classification, we also need to look in product.classification_id
-if (Bugzilla-&gt;params-&gt;{&quot;useclassification&quot;}) {
-    push (@selectcolumns,&quot;product&quot;);
-}
-
</del><span class="cx"> # remaining and actual_time are required for percentage_complete calculation:
</span><del>-if (lsearch(\@displaycolumns, &quot;percentage_complete&quot;) &gt;= 0) {
</del><ins>+if (grep { $_ eq &quot;percentage_complete&quot; } @displaycolumns) {
</ins><span class="cx">     push (@selectcolumns, &quot;remaining_time&quot;);
</span><span class="cx">     push (@selectcolumns, &quot;actual_time&quot;);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# Make sure that the login_name version of a field is always also
+# requested if the realname version is requested, so that we can
+# display the login name when the realname is empty.
+my @realname_fields = grep(/_realname$/, @displaycolumns);
+foreach my $item (@realname_fields) {
+    my $login_field = $item;
+    $login_field =~ s/_realname$//;
+    if (!grep($_ eq $login_field, @selectcolumns)) {
+        push(@selectcolumns, $login_field);
+    }
+}
+
</ins><span class="cx"> # Display columns are selected because otherwise we could not display them.
</span><del>-push (@selectcolumns, @displaycolumns);
</del><ins>+foreach my $col (@displaycolumns) {
+    push (@selectcolumns, $col) if !grep($_ eq $col, @selectcolumns);
+}
</ins><span class="cx"> 
</span><del>-# If the user is editing multiple bugs, we also make sure to select the product
-# and status because the values of those fields determine what options the user
</del><ins>+# If the user is editing multiple bugs, we also make sure to select the 
+# status, because the values of that field determines what options the user
</ins><span class="cx"> # has for modifying the bugs.
</span><span class="cx"> if ($dotweak) {
</span><del>-    push(@selectcolumns, &quot;product&quot;) if !grep($_ eq 'product', @selectcolumns);
</del><span class="cx">     push(@selectcolumns, &quot;bug_status&quot;) if !grep($_ eq 'bug_status', @selectcolumns);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -829,9 +653,11 @@
</span><span class="cx">       'short_desc',
</span><span class="cx">       'opendate',
</span><span class="cx">       'changeddate',
</span><ins>+      'reporter',
</ins><span class="cx">       'reporter_realname',
</span><span class="cx">       'priority',
</span><span class="cx">       'bug_severity',
</span><ins>+      'assigned_to',
</ins><span class="cx">       'assigned_to_realname',
</span><span class="cx">       'bug_status',
</span><span class="cx">       'product',
</span><span class="lines">@@ -846,17 +672,6 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ################################################################################
</span><del>-# Query Generation
-################################################################################
-
-# Convert the list of columns being selected into a list of column names.
-my @selectnames = map($columns-&gt;{$_}-&gt;{'name'}, @selectcolumns);
-
-# Remove columns with no names, such as percentage_complete
-#  (or a removed *_time column due to permissions)
-@selectnames = grep($_ ne '', @selectnames);
-
-################################################################################
</del><span class="cx"> # Sort Order Determination
</span><span class="cx"> ################################################################################
</span><span class="cx"> 
</span><span class="lines">@@ -871,59 +686,58 @@
</span><span class="cx">         # Cookies from early versions of Specific Search included this text,
</span><span class="cx">         # which is now invalid.
</span><span class="cx">         $order =~ s/ LIMIT 200//;
</span><del>-        
-        $order_from_cookie = 1;
</del><span class="cx">     }
</span><span class="cx">     else {
</span><span class="cx">         $order = '';  # Remove possible &quot;reuse&quot; identifier as unnecessary
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-my $db_order = &quot;&quot;;  # Modified version of $order for use with SQL query
</del><span class="cx"> if ($order) {
</span><span class="cx">     # Convert the value of the &quot;order&quot; form field into a list of columns
</span><span class="cx">     # by which to sort the results.
</span><span class="cx">     ORDER: for ($order) {
</span><span class="cx">         /^Bug Number$/ &amp;&amp; do {
</span><del>-            $order = &quot;bugs.bug_id&quot;;
</del><ins>+            $order = &quot;bug_id&quot;;
</ins><span class="cx">             last ORDER;
</span><span class="cx">         };
</span><span class="cx">         /^Importance$/ &amp;&amp; do {
</span><del>-            $order = &quot;bugs.priority, bugs.bug_severity&quot;;
</del><ins>+            $order = &quot;priority,bug_severity&quot;;
</ins><span class="cx">             last ORDER;
</span><span class="cx">         };
</span><span class="cx">         /^Assignee$/ &amp;&amp; do {
</span><del>-            $order = &quot;map_assigned_to.login_name, bugs.bug_status, bugs.priority, bugs.bug_id&quot;;
</del><ins>+            $order = &quot;assigned_to,bug_status,priority,bug_id&quot;;
</ins><span class="cx">             last ORDER;
</span><span class="cx">         };
</span><span class="cx">         /^Last Changed$/ &amp;&amp; do {
</span><del>-            $order = &quot;bugs.delta_ts, bugs.bug_status, bugs.priority, map_assigned_to.login_name, bugs.bug_id&quot;;
</del><ins>+            $order = &quot;changeddate,bug_status,priority,assigned_to,bug_id&quot;;
</ins><span class="cx">             last ORDER;
</span><span class="cx">         };
</span><span class="cx">         do {
</span><del>-            my @order;
-            my @columnnames = map($columns-&gt;{lc($_)}-&gt;{'name'}, keys(%$columns));
</del><ins>+            my (@order, @invalid_fragments);
+
</ins><span class="cx">             # A custom list of columns.  Make sure each column is valid.
</span><span class="cx">             foreach my $fragment (split(/,/, $order)) {
</span><span class="cx">                 $fragment = trim($fragment);
</span><span class="cx">                 next unless $fragment;
</span><del>-                # Accept an order fragment matching a column name, with
-                # asc|desc optionally following (to specify the direction)
-                if (grep($fragment =~ /^\Q$_\E(\s+(asc|desc))?$/, @columnnames, keys(%$columns))) {
-                    next if $fragment =~ /\brelevance\b/ &amp;&amp; !$fulltext;
-                    push(@order, $fragment);
</del><ins>+                my ($column_name, $direction) = split_order_term($fragment);
+                $column_name = translate_old_column($column_name);
+
+                # Special handlings for certain columns
+                next if $column_name eq 'relevance' &amp;&amp; !$fulltext;
+                                
+                if (exists $columns-&gt;{$column_name}) {
+                    $direction = &quot; $direction&quot; if $direction;
+                    push(@order, &quot;$column_name$direction&quot;);
</ins><span class="cx">                 }
</span><span class="cx">                 else {
</span><del>-                    my $vars = { fragment =&gt; $fragment };
-                    if ($order_from_cookie) {
-                        $cgi-&gt;remove_cookie('LASTORDER');
-                        ThrowCodeError(&quot;invalid_column_name_cookie&quot;, $vars);
-                    }
-                    else {
-                        ThrowCodeError(&quot;invalid_column_name_form&quot;, $vars);
-                    }
</del><ins>+                    push(@invalid_fragments, $fragment);
</ins><span class="cx">                 }
</span><span class="cx">             }
</span><ins>+            if (scalar @invalid_fragments) {
+                $vars-&gt;{'message'} = 'invalid_column_name';
+                $vars-&gt;{'invalid_fragments'} = \@invalid_fragments;
+            }
+
</ins><span class="cx">             $order = join(&quot;,&quot;, @order);
</span><span class="cx">             # Now that we have checked that all columns in the order are valid,
</span><span class="cx">             # detaint the order string.
</span><span class="lines">@@ -934,74 +748,35 @@
</span><span class="cx"> 
</span><span class="cx"> if (!$order) {
</span><span class="cx">     # DEFAULT
</span><del>-    $order = &quot;bugs.bug_status, bugs.priority, map_assigned_to.login_name, bugs.bug_id&quot;;
</del><ins>+    $order = &quot;bug_status,priority,assigned_to,bug_id&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-# Make sure ORDER BY columns are included in the field list.
-foreach my $fragment (split(/,/, $order)) {
-    $fragment = trim($fragment);
-    if (!grep($fragment =~ /^\Q$_\E(\s+(asc|desc))?$/, @selectnames)) {
-        # Add order columns to selectnames
-        # The fragment has already been validated
-        $fragment =~ s/\s+(asc|desc)$//;
</del><ins>+my @orderstrings = split(/,\s*/, $order);
</ins><span class="cx"> 
</span><del>-        # While newer fragments contain IDs for aliased columns, older
-        # LASTORDER cookies (or bookmarks) may contain full names.
-        # Convert them to an ID here.
-        if ($fragment =~ / AS (\w+)/) {
-            $fragment = $1;
-        }
</del><ins>+if ($fulltext and grep { /^relevance/ } @orderstrings) {
+    $vars-&gt;{'message'} = 'buglist_sorted_by_relevance'
+}
</ins><span class="cx"> 
</span><del>-        $fragment =~ tr/a-zA-Z\.0-9\-_//cd;
-
-        # If the order fragment is an ID, we need its corresponding name
-        # to be in the field list.
-        if (exists($columns-&gt;{$fragment})) {
-            $fragment = $columns-&gt;{$fragment}-&gt;{'name'};
-        }
-
-        push @selectnames, $fragment;
-    }
</del><ins>+# In the HTML interface, by default, we limit the returned results,
+# which speeds up quite a few searches where people are really only looking
+# for the top results.
+if ($format-&gt;{'extension'} eq 'html' &amp;&amp; !defined $params-&gt;param('limit')) {
+    $params-&gt;param('limit', Bugzilla-&gt;params-&gt;{'default_search_limit'});
+    $vars-&gt;{'default_limited'} = 1;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-$db_order = $order;  # Copy $order into $db_order for use with SQL query
-
-# If we are sorting by votes, sort in descending order if no explicit
-# sort order was given
-$db_order =~ s/bugs.votes\s*(,|$)/bugs.votes desc$1/i;
-                             
-# the 'actual_time' field is defined as an aggregate function, but 
-# for order we just need the column name 'actual_time'
-my $aggregate_search = quotemeta($columns-&gt;{'actual_time'}-&gt;{'name'});
-$db_order =~ s/$aggregate_search/actual_time/g;
-
-# the 'percentage_complete' field is defined as an aggregate too
-$aggregate_search = quotemeta($columns-&gt;{'percentage_complete'}-&gt;{'name'});
-$db_order =~ s/$aggregate_search/percentage_complete/g;
-
-# Now put $db_order into a format that Bugzilla::Search can use.
-# (We create $db_order as a string first because that's the way
-# we did it before Bugzilla::Search took an &quot;order&quot; argument.)
-my @orderstrings = split(/,\s*/, $db_order);
-
</del><span class="cx"> # Generate the basic SQL query that will be used to generate the bug list.
</span><del>-my $search = new Bugzilla::Search('fields' =&gt; \@selectnames, 
-                                  'params' =&gt; $params,
-                                  'order' =&gt; \@orderstrings);
-my $query = $search-&gt;getSQL();
</del><ins>+my $search = new Bugzilla::Search('fields' =&gt; \@selectcolumns, 
+                                  'params' =&gt; scalar $params-&gt;Vars,
+                                  'order'  =&gt; \@orderstrings,
+                                  'sharer' =&gt; $sharer_id);
+my $query = $search-&gt;sql;
+$vars-&gt;{'search_description'} = $search-&gt;search_description;
</ins><span class="cx"> 
</span><del>-if (defined $cgi-&gt;param('limit')) {
-    my $limit = $cgi-&gt;param('limit');
-    if (detaint_natural($limit)) {
-        $query .= &quot; &quot; . $dbh-&gt;sql_limit($limit);
-    }
-}
-elsif ($fulltext) {
-    $query .= &quot; &quot; . $dbh-&gt;sql_limit(FULLTEXT_BUGLIST_LIMIT);
-    $vars-&gt;{'message'} = 'buglist_sorted_by_relevance' if ($cgi-&gt;param('order') =~ /^relevance/);
-}
</del><ins>+# We don't want saved searches and other buglist things to save
+# our default limit.
+$params-&gt;delete('limit') if $vars-&gt;{'default_limited'};
</ins><span class="cx"> 
</span><del>-
</del><span class="cx"> ################################################################################
</span><span class="cx"> # Query Execution
</span><span class="cx"> ################################################################################
</span><span class="lines">@@ -1012,7 +787,13 @@
</span><span class="cx"> ) {
</span><span class="cx">     $vars-&gt;{'debug'} = 1;
</span><span class="cx">     $vars-&gt;{'query'} = $query;
</span><del>-    $vars-&gt;{'debugdata'} = $search-&gt;getDebugData();
</del><ins>+    # Explains are limited to admins because you could use them to figure
+    # out how many hidden bugs are in a particular product (by doing
+    # searches and looking at the number of rows the explain says it's
+    # examining).
+    if (Bugzilla-&gt;user-&gt;in_group('admin')) {
+        $vars-&gt;{'query_explain'} = $dbh-&gt;bz_explain($query);
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> # Time to use server push to display an interim message to the user until
</span><span class="lines">@@ -1058,6 +839,22 @@
</span><span class="cx"> # Retrieve the query results one row at a time and write the data into a list
</span><span class="cx"> # of Perl records.
</span><span class="cx"> 
</span><ins>+# If we're doing time tracking, then keep totals for all bugs.
+my $percentage_complete = grep($_ eq 'percentage_complete', @displaycolumns);
+my $estimated_time      = grep($_ eq 'estimated_time', @displaycolumns);
+my $remaining_time      = grep($_ eq 'remaining_time', @displaycolumns)
+                            || $percentage_complete;
+my $actual_time         = grep($_ eq 'actual_time', @displaycolumns)
+                            || $percentage_complete;
+
+my $time_info = { 'estimated_time' =&gt; 0,
+                  'remaining_time' =&gt; 0,
+                  'actual_time' =&gt; 0,
+                  'percentage_complete' =&gt; 0,
+                  'time_present' =&gt; ($estimated_time || $remaining_time ||
+                                     $actual_time || $percentage_complete),
+                };
+    
</ins><span class="cx"> my $bugowners = {};
</span><span class="cx"> my $bugproducts = {};
</span><span class="cx"> my $bugstatuses = {};
</span><span class="lines">@@ -1080,16 +877,12 @@
</span><span class="cx">         $bug-&gt;{'changeddate'} =~ 
</span><span class="cx">             s/^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})$/$1-$2-$3 $4:$5:$6/;
</span><span class="cx"> 
</span><del>-        # Put in the change date as a time, so that the template date plugin
-        # can format the date in any way needed by the template. ICS and Atom
-        # have specific, and different, date and time formatting.
-        $bug-&gt;{'changedtime'} = str2time($bug-&gt;{'changeddate'}, Bugzilla-&gt;params-&gt;{'timezone'});
-        $bug-&gt;{'changeddate'} = DiffDate($bug-&gt;{'changeddate'});        
</del><ins>+        $bug-&gt;{'changedtime'} = $bug-&gt;{'changeddate'}; # for iCalendar and Atom
+        $bug-&gt;{'changeddate'} = DiffDate($bug-&gt;{'changeddate'});
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if ($bug-&gt;{'opendate'}) {
</span><del>-        # Put in the open date as a time for the template date plugin.
-        $bug-&gt;{'opentime'} = str2time($bug-&gt;{'opendate'}, Bugzilla-&gt;params-&gt;{'timezone'});
</del><ins>+        $bug-&gt;{'opentime'} = $bug-&gt;{'opendate'}; # for iCalendar
</ins><span class="cx">         $bug-&gt;{'opendate'} = DiffDate($bug-&gt;{'opendate'});
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -1105,6 +898,11 @@
</span><span class="cx"> 
</span><span class="cx">     # Add id to list for checking for bug privacy later
</span><span class="cx">     push(@bugidlist, $bug-&gt;{'bug_id'});
</span><ins>+
+    # Compute time tracking info.
+    $time_info-&gt;{'estimated_time'} += $bug-&gt;{'estimated_time'} if ($estimated_time);
+    $time_info-&gt;{'remaining_time'} += $bug-&gt;{'remaining_time'} if ($remaining_time);
+    $time_info-&gt;{'actual_time'}    += $bug-&gt;{'actual_time'}    if ($actual_time);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> # Check for bug privacy and set $bug-&gt;{'secure_mode'} to 'implied' or 'manual'
</span><span class="lines">@@ -1137,6 +935,15 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# Compute percentage complete without rounding.
+my $sum = $time_info-&gt;{'actual_time'}+$time_info-&gt;{'remaining_time'};
+if ($sum &gt; 0) {
+    $time_info-&gt;{'percentage_complete'} = 100*$time_info-&gt;{'actual_time'}/$sum;
+}
+else { # remaining_time &lt;= 0 
+    $time_info-&gt;{'percentage_complete'} = 0
+}                             
+
</ins><span class="cx"> ################################################################################
</span><span class="cx"> # Template Variable Definition
</span><span class="cx"> ################################################################################
</span><span class="lines">@@ -1152,16 +959,20 @@
</span><span class="cx"> $vars-&gt;{'openstates'} = [BUG_STATE_OPEN];
</span><span class="cx"> $vars-&gt;{'closedstates'} = [map {$_-&gt;name} closed_bug_statuses()];
</span><span class="cx"> 
</span><del>-# The list of query fields in URL query string format, used when creating
-# URLs to the same query results page with different parameters (such as
-# a different sort order or when taking some action on the set of query
-# results).  To get this string, we call the Bugzilla::CGI::canoncalise_query
-# function with a list of elements to be removed from the URL.
-$vars-&gt;{'urlquerypart'} = $params-&gt;canonicalise_query('order',
-                                                      'cmdtype',
-                                                      'query_based_on');
</del><ins>+# The iCal file needs priorities ordered from 1 to 9 (highest to lowest)
+# If there are more than 9 values, just make all the lower ones 9
+if ($format-&gt;{'extension'} eq 'ics') {
+    my $n = 1;
+    $vars-&gt;{'ics_priorities'} = {};
+    my $priorities = get_legal_field_values('priority');
+    foreach my $p (@$priorities) {
+        $vars-&gt;{'ics_priorities'}-&gt;{$p} = ($n &gt; 9) ? 9 : $n++;
+    }
+}
+
</ins><span class="cx"> $vars-&gt;{'order'} = $order;
</span><span class="cx"> $vars-&gt;{'caneditbugs'} = 1;
</span><ins>+$vars-&gt;{'time_info'} = $time_info;
</ins><span class="cx"> 
</span><span class="cx"> if (!Bugzilla-&gt;user-&gt;in_group('editbugs')) {
</span><span class="cx">     foreach my $product (keys %$bugproducts) {
</span><span class="lines">@@ -1186,8 +997,27 @@
</span><span class="cx"> $vars-&gt;{'splitheader'} = $cgi-&gt;cookie('SPLITHEADER') ? 1 : 0;
</span><span class="cx"> 
</span><span class="cx"> $vars-&gt;{'quip'} = GetQuip();
</span><del>-$vars-&gt;{'currenttime'} = time();
</del><ins>+$vars-&gt;{'currenttime'} = localtime(time());
</ins><span class="cx"> 
</span><ins>+# See if there's only one product in all the results (or only one product
+# that we searched for), which allows us to provide more helpful links.
+my @products = keys %$bugproducts;
+my $one_product;
+if (scalar(@products) == 1) {
+    $one_product = new Bugzilla::Product({ name =&gt; $products[0] });
+}
+# This is used in the &quot;Zarroo Boogs&quot; case.
+elsif (my @product_input = $cgi-&gt;param('product')) {
+    if (scalar(@product_input) == 1 and $product_input[0] ne '') {
+        $one_product = new Bugzilla::Product({ name =&gt; $cgi-&gt;param('product') });
+    }
+}
+# We only want the template to use it if the user can actually 
+# enter bugs against it.
+if ($one_product &amp;&amp; Bugzilla-&gt;user-&gt;can_enter_product($one_product)) {
+    $vars-&gt;{'one_product'} = $one_product;
+}
+
</ins><span class="cx"> # The following variables are used when the user is making changes to multiple bugs.
</span><span class="cx"> if ($dotweak &amp;&amp; scalar @bugs) {
</span><span class="cx">     if (!$vars-&gt;{'caneditbugs'}) {
</span><span class="lines">@@ -1197,7 +1027,6 @@
</span><span class="cx">                                         object =&gt; 'multiple_bugs'});
</span><span class="cx">     }
</span><span class="cx">     $vars-&gt;{'dotweak'} = 1;
</span><del>-    $vars-&gt;{'use_keywords'} = 1 if Bugzilla::Keyword::keyword_count();
</del><span class="cx">   
</span><span class="cx">     # issue_session_token needs to write to the master DB.
</span><span class="cx">     Bugzilla-&gt;switch_to_main_db();
</span><span class="lines">@@ -1211,8 +1040,6 @@
</span><span class="cx">     $vars-&gt;{'severities'} = get_legal_field_values('bug_severity');
</span><span class="cx">     $vars-&gt;{'resolutions'} = get_legal_field_values('resolution');
</span><span class="cx"> 
</span><del>-    $vars-&gt;{'unconfirmedstate'} = 'UNCONFIRMED';
-
</del><span class="cx">     # Convert bug statuses to their ID.
</span><span class="cx">     my @bug_statuses = map {$dbh-&gt;quote($_)} keys %$bugstatuses;
</span><span class="cx">     my $bug_status_ids =
</span><span class="lines">@@ -1242,19 +1069,19 @@
</span><span class="cx">     $vars-&gt;{'new_bug_statuses'} = Bugzilla::Status-&gt;new_from_list($bug_status_ids);
</span><span class="cx"> 
</span><span class="cx">     # The groups the user belongs to and which are editable for the given buglist.
</span><del>-    my @products = keys %$bugproducts;
</del><span class="cx">     $vars-&gt;{'groups'} = GetGroups(\@products);
</span><span class="cx"> 
</span><span class="cx">     # If all bugs being changed are in the same product, the user can change
</span><span class="cx">     # their version and component, so generate a list of products, a list of
</span><span class="cx">     # versions for the product (if there is only one product on the list of
</span><span class="cx">     # products), and a list of components for the product.
</span><del>-    if (scalar(@products) == 1) {
-        my $product = new Bugzilla::Product({name =&gt; $products[0]});
-        $vars-&gt;{'versions'} = [map($_-&gt;name ,@{$product-&gt;versions})];
-        $vars-&gt;{'components'} = [map($_-&gt;name, @{$product-&gt;components})];
-        $vars-&gt;{'targetmilestones'} = [map($_-&gt;name, @{$product-&gt;milestones})]
-            if Bugzilla-&gt;params-&gt;{'usetargetmilestone'};
</del><ins>+    if ($one_product) {
+        $vars-&gt;{'versions'} = [map($_-&gt;name, grep($_-&gt;is_active, @{ $one_product-&gt;versions }))];
+        $vars-&gt;{'components'} = [map($_-&gt;name, grep($_-&gt;is_active, @{ $one_product-&gt;components }))];
+        if (Bugzilla-&gt;params-&gt;{'usetargetmilestone'}) {
+            $vars-&gt;{'targetmilestones'} = [map($_-&gt;name, grep($_-&gt;is_active,  
+                                               @{ $one_product-&gt;milestones }))];
+        }
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -1262,6 +1089,9 @@
</span><span class="cx"> # the &quot;Remember search as&quot; field.
</span><span class="cx"> $vars-&gt;{'defaultsavename'} = $cgi-&gt;param('query_based_on');
</span><span class="cx"> 
</span><ins>+# If we did a quick search then redisplay the previously entered search 
+# string in the text field.
+$vars-&gt;{'quicksearch'} = $searchstring;
</ins><span class="cx"> 
</span><span class="cx"> ################################################################################
</span><span class="cx"> # HTTP Header Generation
</span><span class="lines">@@ -1273,36 +1103,28 @@
</span><span class="cx"> my $disposition = &quot;inline&quot;;
</span><span class="cx"> 
</span><span class="cx"> if ($format-&gt;{'extension'} eq &quot;html&quot; &amp;&amp; !$agent) {
</span><del>-    if ($order) {
-        $cgi-&gt;send_cookie(-name =&gt; 'LASTORDER',
-                          -value =&gt; $order,
-                          -expires =&gt; 'Fri, 01-Jan-2038 00:00:00 GMT');
-    }
-    my $bugids = join(&quot;:&quot;, @bugidlist);
-    # See also Bug 111999
-    if (length($bugids) == 0) {
-        $cgi-&gt;remove_cookie('BUGLIST');
-    }
-    elsif (length($bugids) &lt; 4000) {
-        $cgi-&gt;send_cookie(-name =&gt; 'BUGLIST',
-                          -value =&gt; $bugids,
-                          -expires =&gt; 'Fri, 01-Jan-2038 00:00:00 GMT');
-    }
-    else {
-        $cgi-&gt;remove_cookie('BUGLIST');
-        $vars-&gt;{'toolong'} = 1;
-    }
-
</del><ins>+    my $list_id = $cgi-&gt;param('list_id') || $cgi-&gt;param('regetlastlist');
+    my $search = $user-&gt;save_last_search(
+        { bugs =&gt; \@bugidlist, order =&gt; $order, vars =&gt; $vars, list_id =&gt; $list_id });
+    $cgi-&gt;param('list_id', $search-&gt;id) if $search;
</ins><span class="cx">     $contenttype = &quot;text/html&quot;;
</span><span class="cx"> }
</span><span class="cx"> else {
</span><span class="cx">     $contenttype = $format-&gt;{'ctype'};
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# Set 'urlquerypart' once the buglist ID is known.
+$vars-&gt;{'urlquerypart'} = $params-&gt;canonicalise_query('order', 'cmdtype',
+                                                      'query_based_on');
+
</ins><span class="cx"> if ($format-&gt;{'extension'} eq &quot;csv&quot;) {
</span><span class="cx">     # We set CSV files to be downloaded, as they are designed for importing
</span><span class="cx">     # into other programs.
</span><span class="cx">     $disposition = &quot;attachment&quot;;
</span><ins>+
+    # If the user clicked the CSV link in the search results,
+    # They should get the Field Description, not the column name in the db
+    $vars-&gt;{'human'} = $cgi-&gt;param('human');
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> # Suggest a name for the bug list if the user wants to save it as a file.
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgbugzilladtd"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/bugzilla.dtd (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/bugzilla.dtd        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/bugzilla.dtd        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,13 +1,19 @@
</span><span class="cx"> &lt;!ELEMENT bugzilla (bug+)&gt;
</span><span class="cx"> &lt;!ATTLIST bugzilla
</span><del>-        version CDATA #REQUIRED
-        urlbase CDATA #REQUIRED
-        maintainer CDATA #REQUIRED
-        exporter CDATA #IMPLIED
</del><ins>+          version CDATA #REQUIRED
+          urlbase CDATA #REQUIRED
+          maintainer CDATA #REQUIRED
+          exporter CDATA #IMPLIED
</ins><span class="cx"> &gt;
</span><del>-&lt;!ELEMENT bug (bug_id, (alias?, creation_ts, short_desc, delta_ts, reporter_accessible, cclist_accessible, classification_id, classification, product, component, version, rep_platform, op_sys, bug_status, resolution?, dup_id?, bug_file_loc?, status_whiteboard?, keywords*, priority, bug_severity, target_milestone?, dependson*, blocked*, votes?, everconfirmed, reporter, assigned_to, qa_contact?, cc*, (estimated_time, remaining_time, actual_time, deadline)?, group*, flag*, long_desc*, attachment*)?)&gt;
</del><ins>+&lt;!ELEMENT bug (bug_id, (alias?, creation_ts, short_desc, delta_ts, reporter_accessible, 
+    cclist_accessible, classification_id, classification, product, component, 
+    version, rep_platform, op_sys, bug_status, resolution?, dup_id?, see_also*, 
+    bug_file_loc?, status_whiteboard?, keywords*, priority, bug_severity, 
+    target_milestone?, dependson*, blocked*, everconfirmed, reporter, assigned_to, 
+    cc*, (estimated_time, remaining_time, actual_time, deadline?)?, qa_contact?, 
+    votes?, token?, group*, flag*, long_desc*, attachment*)?)&gt;
</ins><span class="cx"> &lt;!ATTLIST bug
</span><del>-        error (NotFound | NotPermitted | InvalidBugId) #IMPLIED
</del><ins>+          error (NotFound | NotPermitted | InvalidBugId) #IMPLIED
</ins><span class="cx"> &gt;
</span><span class="cx"> &lt;!ELEMENT bug_id (#PCDATA)&gt;
</span><span class="cx"> &lt;!ELEMENT alias (#PCDATA)&gt;
</span><span class="lines">@@ -23,13 +29,22 @@
</span><span class="cx"> &lt;!ELEMENT version (#PCDATA)&gt;
</span><span class="cx"> &lt;!ELEMENT rep_platform (#PCDATA)&gt;
</span><span class="cx"> &lt;!ELEMENT assigned_to (#PCDATA)&gt;
</span><ins>+&lt;!ATTLIST assigned_to 
+          name CDATA #REQUIRED
+&gt;
</ins><span class="cx"> &lt;!ELEMENT delta_ts (#PCDATA)&gt;
</span><span class="cx"> &lt;!ELEMENT component (#PCDATA)&gt;
</span><span class="cx"> &lt;!ELEMENT reporter (#PCDATA)&gt;
</span><ins>+&lt;!ATTLIST reporter
+          name CDATA #REQUIRED
+&gt;
</ins><span class="cx"> &lt;!ELEMENT target_milestone (#PCDATA)&gt;
</span><span class="cx"> &lt;!ELEMENT bug_severity (#PCDATA)&gt;
</span><span class="cx"> &lt;!ELEMENT creation_ts (#PCDATA)&gt;
</span><span class="cx"> &lt;!ELEMENT qa_contact (#PCDATA)&gt;
</span><ins>+&lt;!ATTLIST qa_contact
+          name CDATA #REQUIRED
+&gt;
</ins><span class="cx"> &lt;!ELEMENT status_whiteboard (#PCDATA)&gt;
</span><span class="cx"> &lt;!ELEMENT op_sys (#PCDATA)&gt;
</span><span class="cx"> &lt;!ELEMENT resolution (#PCDATA)&gt;
</span><span class="lines">@@ -39,29 +54,38 @@
</span><span class="cx"> &lt;!ELEMENT keywords (#PCDATA)&gt;
</span><span class="cx"> &lt;!ELEMENT dependson (#PCDATA)&gt;
</span><span class="cx"> &lt;!ELEMENT blocked (#PCDATA)&gt;
</span><del>-&lt;!ELEMENT votes (#PCDATA)&gt;
</del><span class="cx"> &lt;!ELEMENT everconfirmed (#PCDATA)&gt;
</span><span class="cx"> &lt;!ELEMENT cc (#PCDATA)&gt;
</span><ins>+&lt;!ELEMENT see_also (#PCDATA)&gt;
+&lt;!ELEMENT votes (#PCDATA)&gt;
+&lt;!ELEMENT token (#PCDATA)&gt;
</ins><span class="cx"> &lt;!ELEMENT group (#PCDATA)&gt;
</span><ins>+&lt;!ATTLIST group
+          id CDATA #REQUIRED
+&gt;
</ins><span class="cx"> &lt;!ELEMENT estimated_time (#PCDATA)&gt;
</span><span class="cx"> &lt;!ELEMENT remaining_time (#PCDATA)&gt;
</span><span class="cx"> &lt;!ELEMENT actual_time (#PCDATA)&gt;
</span><span class="cx"> &lt;!ELEMENT deadline (#PCDATA)&gt;
</span><del>-&lt;!ELEMENT long_desc (who, bug_when, work_time?, thetext)&gt;
</del><ins>+&lt;!ELEMENT long_desc (commentid, attachid?, who, bug_when, work_time?, thetext)&gt;
</ins><span class="cx"> &lt;!ATTLIST long_desc
</span><del>-          encoding (base64) #IMPLIED
-          isprivate (0|1) #IMPLIED
- &gt;
</del><ins>+          isprivate (0|1) #REQUIRED
+&gt;
+&lt;!ELEMENT commentid (#PCDATA)&gt;
</ins><span class="cx"> &lt;!ELEMENT who (#PCDATA)&gt;
</span><ins>+&lt;!ATTLIST who
+          name CDATA #REQUIRED
+&gt;
</ins><span class="cx"> &lt;!ELEMENT bug_when (#PCDATA)&gt;
</span><span class="cx"> &lt;!ELEMENT work_time (#PCDATA)&gt;
</span><span class="cx"> &lt;!ELEMENT thetext (#PCDATA)&gt;
</span><del>-&lt;!ELEMENT attachment (attachid, date, desc, filename?, type?, size?, data?, flag*)&gt;
</del><ins>+&lt;!ELEMENT attachment (attachid, date, delta_ts, desc, filename, type, size, attacher, token?, data?, flag*)&gt;
</ins><span class="cx"> &lt;!ATTLIST attachment
</span><del>-          isobsolete (0|1) #IMPLIED
-          ispatch (0|1) #IMPLIED
-          isprivate (0|1) #IMPLIED
</del><ins>+          isobsolete (0|1) #REQUIRED
+          ispatch (0|1) #REQUIRED
+          isprivate (0|1) #REQUIRED
</ins><span class="cx"> &gt;
</span><ins>+&lt;!ELEMENT attacher (#PCDATA)&gt;
</ins><span class="cx"> &lt;!ELEMENT attachid (#PCDATA)&gt;
</span><span class="cx"> &lt;!ELEMENT date (#PCDATA)&gt;
</span><span class="cx"> &lt;!ELEMENT desc (#PCDATA)&gt;
</span><span class="lines">@@ -75,7 +99,9 @@
</span><span class="cx"> &lt;!ELEMENT flag EMPTY&gt;
</span><span class="cx"> &lt;!ATTLIST flag
</span><span class="cx">           name CDATA #REQUIRED
</span><ins>+          id CDATA #REQUIRED
+          type_id CDATA #REQUIRED 
</ins><span class="cx">           status CDATA #REQUIRED
</span><del>-          setter CDATA #IMPLIED
</del><ins>+          setter CDATA #REQUIRED
</ins><span class="cx">           requestee CDATA #IMPLIED
</span><span class="cx"> &gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgchartcgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/chart.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/chart.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/chart.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -20,6 +20,7 @@
</span><span class="cx"> #
</span><span class="cx"> # Contributor(s): Gervase Markham &lt;gerv@gerv.net&gt;
</span><span class="cx"> #                 Lance Larsh &lt;lance.larsh@oracle.com&gt;
</span><ins>+#                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
</ins><span class="cx"> 
</span><span class="cx"> # Glossary:
</span><span class="cx"> # series:   An individual, defined set of data plotted over time.
</span><span class="lines">@@ -47,11 +48,13 @@
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla;
</span><span class="cx"> use Bugzilla::Constants;
</span><ins>+use Bugzilla::CGI;
</ins><span class="cx"> use Bugzilla::Error;
</span><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> use Bugzilla::Chart;
</span><span class="cx"> use Bugzilla::Series;
</span><span class="cx"> use Bugzilla::User;
</span><ins>+use Bugzilla::Token;
</ins><span class="cx"> 
</span><span class="cx"> # For most scripts we don't make $cgi and $template global variables. But
</span><span class="cx"> # when preparing Bugzilla for mod_perl, this script used these
</span><span class="lines">@@ -60,12 +63,19 @@
</span><span class="cx"> local our $cgi = Bugzilla-&gt;cgi;
</span><span class="cx"> local our $template = Bugzilla-&gt;template;
</span><span class="cx"> local our $vars = {};
</span><ins>+my $dbh = Bugzilla-&gt;dbh;
</ins><span class="cx"> 
</span><ins>+my $user = Bugzilla-&gt;login(LOGIN_REQUIRED);
+
+if (!Bugzilla-&gt;feature('new_charts')) {
+    ThrowCodeError('feature_disabled', { feature =&gt; 'new_charts' });
+}
+
</ins><span class="cx"> # Go back to query.cgi if we are adding a boolean chart parameter.
</span><span class="cx"> if (grep(/^cmd-/, $cgi-&gt;param())) {
</span><span class="cx">     my $params = $cgi-&gt;canonicalise_query(&quot;format&quot;, &quot;ctype&quot;, &quot;action&quot;);
</span><del>-    print &quot;Location: query.cgi?format=&quot; . $cgi-&gt;param('query_format') .
-                                          ($params ? &quot;&amp;$params&quot; : &quot;&quot;) . &quot;\n\n&quot;;
</del><ins>+    print $cgi-&gt;redirect(&quot;query.cgi?format=&quot; . $cgi-&gt;param('query_format') .
+                                               ($params ? &quot;&amp;$params&quot; : &quot;&quot;));
</ins><span class="cx">     exit;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -88,19 +98,17 @@
</span><span class="cx"> # Go to buglist.cgi if we are doing a search.
</span><span class="cx"> if ($action eq &quot;search&quot;) {
</span><span class="cx">     my $params = $cgi-&gt;canonicalise_query(&quot;format&quot;, &quot;ctype&quot;, &quot;action&quot;);
</span><del>-    print &quot;Location: buglist.cgi&quot; . ($params ? &quot;?$params&quot; : &quot;&quot;) . &quot;\n\n&quot;;
</del><ins>+    print $cgi-&gt;redirect(&quot;buglist.cgi&quot; . ($params ? &quot;?$params&quot; : &quot;&quot;));
</ins><span class="cx">     exit;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-my $user = Bugzilla-&gt;login(LOGIN_REQUIRED);
-
-Bugzilla-&gt;user-&gt;in_group(Bugzilla-&gt;params-&gt;{&quot;chartgroup&quot;})
</del><ins>+$user-&gt;in_group(Bugzilla-&gt;params-&gt;{&quot;chartgroup&quot;})
</ins><span class="cx">   || ThrowUserError(&quot;auth_failure&quot;, {group  =&gt; Bugzilla-&gt;params-&gt;{&quot;chartgroup&quot;},
</span><span class="cx">                                      action =&gt; &quot;use&quot;,
</span><span class="cx">                                      object =&gt; &quot;charts&quot;});
</span><span class="cx"> 
</span><span class="cx"> # Only admins may create public queries
</span><del>-Bugzilla-&gt;user-&gt;in_group('admin') || $cgi-&gt;delete('public');
</del><ins>+$user-&gt;in_group('admin') || $cgi-&gt;delete('public');
</ins><span class="cx"> 
</span><span class="cx"> # All these actions relate to chart construction.
</span><span class="cx"> if ($action =~ /^(assemble|add|remove|sum|subscribe|unsubscribe)$/) {
</span><span class="lines">@@ -138,38 +146,32 @@
</span><span class="cx"> }
</span><span class="cx"> elsif ($action eq &quot;create&quot;) {
</span><span class="cx">     assertCanCreate($cgi);
</span><ins>+    my $token = $cgi-&gt;param('token');
+    check_hash_token($token, ['create-series']);
</ins><span class="cx">     
</span><span class="cx">     my $series = new Bugzilla::Series($cgi);
</span><span class="cx"> 
</span><del>-    if (!$series-&gt;existsInDatabase()) {
-        $series-&gt;writeToDatabase();
-        $vars-&gt;{'message'} = &quot;series_created&quot;;
-    }
-    else {
-        ThrowUserError(&quot;series_already_exists&quot;, {'series' =&gt; $series});
-    }
</del><ins>+    ThrowUserError(&quot;series_already_exists&quot;, {'series' =&gt; $series})
+      if $series-&gt;existsInDatabase;
</ins><span class="cx"> 
</span><ins>+    $series-&gt;writeToDatabase();
+    $vars-&gt;{'message'} = &quot;series_created&quot;;
</ins><span class="cx">     $vars-&gt;{'series'} = $series;
</span><span class="cx"> 
</span><del>-    print $cgi-&gt;header();
-    $template-&gt;process(&quot;global/message.html.tmpl&quot;, $vars)
-      || ThrowTemplateError($template-&gt;error());
</del><ins>+    my $chart = new Bugzilla::Chart($cgi);
+    view($chart);
</ins><span class="cx"> }
</span><span class="cx"> elsif ($action eq &quot;edit&quot;) {
</span><del>-    detaint_natural($series_id) || ThrowCodeError(&quot;invalid_series_id&quot;);
-    assertCanEdit($series_id);
-
-    my $series = new Bugzilla::Series($series_id);
-    
</del><ins>+    my $series = assertCanEdit($series_id);
</ins><span class="cx">     edit($series);
</span><span class="cx"> }
</span><span class="cx"> elsif ($action eq &quot;alter&quot;) {
</span><del>-    # This is the &quot;commit&quot; action for editing a series
-    detaint_natural($series_id) || ThrowCodeError(&quot;invalid_series_id&quot;);
-    assertCanEdit($series_id);
</del><ins>+    my $series = assertCanEdit($series_id);
+    my $token = $cgi-&gt;param('token');
+    check_hash_token($token, [$series-&gt;id, $series-&gt;name]);
+    # XXX - This should be replaced by $series-&gt;set_foo() methods.
+    $series = new Bugzilla::Series($cgi);
</ins><span class="cx"> 
</span><del>-    my $series = new Bugzilla::Series($cgi);
-
</del><span class="cx">     # We need to check if there is _another_ series in the database with
</span><span class="cx">     # our (potentially new) name. So we call existsInDatabase() to see if
</span><span class="cx">     # the return value is us or some other series we need to avoid stomping
</span><span class="lines">@@ -186,8 +188,50 @@
</span><span class="cx">     
</span><span class="cx">     edit($series);
</span><span class="cx"> }
</span><ins>+elsif ($action eq &quot;confirm-delete&quot;) {
+    $vars-&gt;{'series'} = assertCanEdit($series_id);
+
+    print $cgi-&gt;header();
+    $template-&gt;process(&quot;reports/delete-series.html.tmpl&quot;, $vars)
+      || ThrowTemplateError($template-&gt;error());
+}
+elsif ($action eq &quot;delete&quot;) {
+    my $series = assertCanEdit($series_id);
+    my $token = $cgi-&gt;param('token');
+    check_hash_token($token, [$series-&gt;id, $series-&gt;name]);
+
+    $dbh-&gt;bz_start_transaction();
+
+    $series-&gt;remove_from_db();
+    # Remove (sub)categories which no longer have any series.
+    foreach my $cat (qw(category subcategory)) {
+        my $is_used = $dbh-&gt;selectrow_array(&quot;SELECT COUNT(*) FROM series WHERE $cat = ?&quot;,
+                                             undef, $series-&gt;{&quot;${cat}_id&quot;});
+        if (!$is_used) {
+            $dbh-&gt;do('DELETE FROM series_categories WHERE id = ?',
+                      undef, $series-&gt;{&quot;${cat}_id&quot;});
+        }
+    }
+    $dbh-&gt;bz_commit_transaction();
+
+    $vars-&gt;{'message'} = &quot;series_deleted&quot;;
+    $vars-&gt;{'series'} = $series;
+    view();
+}
+elsif ($action eq &quot;convert_search&quot;) {
+    my $saved_search = $cgi-&gt;param('series_from_search') || '';
+    my ($query) = grep { $_-&gt;name eq $saved_search } @{ $user-&gt;queries };
+    my $url = '';
+    if ($query) {
+        my $params = new Bugzilla::CGI($query-&gt;edit_link);
+        # These two parameters conflict with the one below.
+        $url = $params-&gt;canonicalise_query('format', 'query_format');
+        $url = '&amp;amp;' . html_quote($url);
+    }
+    print $cgi-&gt;redirect(-location =&gt; correct_urlbase() . &quot;query.cgi?format=create-series$url&quot;);
+}
</ins><span class="cx"> else {
</span><del>-    ThrowCodeError(&quot;unknown_action&quot;);
</del><ins>+    ThrowUserError('unknown_action', {action =&gt; $action});
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> exit;
</span><span class="lines">@@ -208,30 +252,31 @@
</span><span class="cx"> 
</span><span class="cx"> # Check if the user is the owner of series_id or is an admin. 
</span><span class="cx"> sub assertCanEdit {
</span><del>-    my ($series_id) = @_;
</del><ins>+    my $series_id = shift;
</ins><span class="cx">     my $user = Bugzilla-&gt;user;
</span><span class="cx"> 
</span><del>-    return if $user-&gt;in_group('admin');
</del><ins>+    my $series = new Bugzilla::Series($series_id)
+      || ThrowCodeError('invalid_series_id');
</ins><span class="cx"> 
</span><del>-    my $dbh = Bugzilla-&gt;dbh;
-    my $iscreator = $dbh-&gt;selectrow_array(&quot;SELECT CASE WHEN creator = ? &quot; .
-                                          &quot;THEN 1 ELSE 0 END FROM series &quot; .
-                                          &quot;WHERE series_id = ?&quot;, undef,
-                                          $user-&gt;id, $series_id);
-    $iscreator || ThrowUserError(&quot;illegal_series_edit&quot;);
</del><ins>+    if (!$user-&gt;in_group('admin') &amp;&amp; $series-&gt;{creator_id} != $user-&gt;id) {
+        ThrowUserError('illegal_series_edit');
+    }
+
+    return $series;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> # Check if the user is permitted to create this series with these parameters.
</span><span class="cx"> sub assertCanCreate {
</span><span class="cx">     my ($cgi) = shift;
</span><del>-    
-    Bugzilla-&gt;user-&gt;in_group(&quot;editbugs&quot;) || ThrowUserError(&quot;illegal_series_creation&quot;);
</del><ins>+    my $user = Bugzilla-&gt;user;
</ins><span class="cx"> 
</span><ins>+    $user-&gt;in_group(&quot;editbugs&quot;) || ThrowUserError(&quot;illegal_series_creation&quot;);
+
</ins><span class="cx">     # Check permission for frequency
</span><span class="cx">     my $min_freq = 7;
</span><del>-    if ($cgi-&gt;param('frequency') &lt; $min_freq &amp;&amp; !Bugzilla-&gt;user-&gt;in_group(&quot;admin&quot;)) {
</del><ins>+    if ($cgi-&gt;param('frequency') &lt; $min_freq &amp;&amp; !$user-&gt;in_group(&quot;admin&quot;)) {
</ins><span class="cx">         ThrowUserError(&quot;illegal_frequency&quot;, { 'minimum' =&gt; $min_freq });
</span><del>-    }    
</del><ins>+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub validateWidthAndHeight {
</span><span class="lines">@@ -261,7 +306,6 @@
</span><span class="cx">     my $series = shift;
</span><span class="cx"> 
</span><span class="cx">     $vars-&gt;{'category'} = Bugzilla::Chart::getVisibleSeries();
</span><del>-    $vars-&gt;{'creator'} = new Bugzilla::User($series-&gt;{'creator'});
</del><span class="cx">     $vars-&gt;{'default'} = $series;
</span><span class="cx"> 
</span><span class="cx">     print $cgi-&gt;header();
</span><span class="lines">@@ -294,7 +338,7 @@
</span><span class="cx">     # We create a Chart object so we can validate the parameters
</span><span class="cx">     my $chart = new Bugzilla::Chart($cgi);
</span><span class="cx">     
</span><del>-    $vars-&gt;{'time'} = time();
</del><ins>+    $vars-&gt;{'time'} = localtime(time());
</ins><span class="cx"> 
</span><span class="cx">     $vars-&gt;{'imagebase'} = $cgi-&gt;canonicalise_query(
</span><span class="cx">                 &quot;action&quot;, &quot;action-wrap&quot;, &quot;ctype&quot;, &quot;format&quot;, &quot;width&quot;, &quot;height&quot;);
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgchecksetuppl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/checksetup.pl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/checksetup.pl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/checksetup.pl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -53,15 +53,19 @@
</span><span class="cx"> use lib qw(. lib);
</span><span class="cx"> use Bugzilla::Constants;
</span><span class="cx"> use Bugzilla::Install::Requirements;
</span><del>-use Bugzilla::Install::Util qw(install_string get_version_and_os get_console_locale);
</del><ins>+use Bugzilla::Install::Util qw(install_string get_version_and_os 
+                               init_console success);
</ins><span class="cx"> 
</span><span class="cx"> ######################################################################
</span><span class="cx"> # Live Code
</span><span class="cx"> ######################################################################
</span><span class="cx"> 
</span><ins>+# Do not run checksetup.pl from the web browser.
+Bugzilla::Install::Util::no_checksetup_from_cgi() if $ENV{'SERVER_SOFTWARE'};
+
</ins><span class="cx"> # When we're running at the command line, we need to pick the right
</span><span class="cx"> # language before ever displaying any string.
</span><del>-$ENV{'HTTP_ACCEPT_LANGUAGE'} ||= get_console_locale();
</del><ins>+init_console();
</ins><span class="cx"> 
</span><span class="cx"> my %switch;
</span><span class="cx"> GetOptions(\%switch, 'help|h|?', 'check-modules', 'no-templates|t',
</span><span class="lines">@@ -95,11 +99,12 @@
</span><span class="cx"> # then instead of our nice normal checksetup message, the user would
</span><span class="cx"> # get a cryptic perl error about the missing module.
</span><span class="cx"> 
</span><del>-# We need $::ENV{'PATH'} to remain defined.
-my $env = $::ENV{'PATH'};
</del><span class="cx"> require Bugzilla;
</span><del>-$::ENV{'PATH'} = $env;
</del><ins>+require Bugzilla::User;
</ins><span class="cx"> 
</span><ins>+require Bugzilla::Util;
+import Bugzilla::Util qw(get_text);
+
</ins><span class="cx"> require Bugzilla::Config;
</span><span class="cx"> import Bugzilla::Config qw(:admin);
</span><span class="cx"> 
</span><span class="lines">@@ -115,7 +120,6 @@
</span><span class="cx"> require Bugzilla::Field;
</span><span class="cx"> require Bugzilla::Install;
</span><span class="cx"> 
</span><del>-Bugzilla-&gt;usage_mode(USAGE_MODE_CMDLINE);
</del><span class="cx"> Bugzilla-&gt;installation_mode(INSTALLATION_MODE_NON_INTERACTIVE) if $answers_file;
</span><span class="cx"> Bugzilla-&gt;installation_answers($answers_file);
</span><span class="cx"> 
</span><span class="lines">@@ -193,6 +197,7 @@
</span><span class="cx"> ###########################################################################
</span><span class="cx"> 
</span><span class="cx"> Bugzilla::Install::DB::update_table_definitions(\%old_params);
</span><ins>+Bugzilla::Install::init_workflow();
</ins><span class="cx"> 
</span><span class="cx"> ###########################################################################
</span><span class="cx"> # Bugzilla uses --GROUPS-- to assign various rights to its users.
</span><span class="lines">@@ -200,6 +205,9 @@
</span><span class="cx"> 
</span><span class="cx"> Bugzilla::Install::update_system_groups();
</span><span class="cx"> 
</span><ins>+# &quot;Log In&quot; as the fake superuser who can do everything.
+Bugzilla-&gt;set_user(Bugzilla::User-&gt;super_user);
+
</ins><span class="cx"> ###########################################################################
</span><span class="cx"> # Create --SETTINGS-- users can adjust
</span><span class="cx"> ###########################################################################
</span><span class="lines">@@ -217,12 +225,12 @@
</span><span class="cx">     if $switch{'reset-password'};
</span><span class="cx"> 
</span><span class="cx"> ###########################################################################
</span><del>-# Create default Product and Classification
</del><ins>+# Create default Product
</ins><span class="cx"> ###########################################################################
</span><span class="cx"> 
</span><span class="cx"> Bugzilla::Install::create_default_product();
</span><span class="cx"> 
</span><del>-Bugzilla::Hook::process('install-before_final_checks', {'silent' =&gt; $silent });
</del><ins>+Bugzilla::Hook::process('install_before_final_checks', { silent =&gt; $silent });
</ins><span class="cx"> 
</span><span class="cx"> ###########################################################################
</span><span class="cx"> # Final checks
</span><span class="lines">@@ -231,9 +239,12 @@
</span><span class="cx"> # Check if the default parameter for urlbase is still set, and if so, give
</span><span class="cx"> # notification that they should go and visit editparams.cgi 
</span><span class="cx"> if (Bugzilla-&gt;params-&gt;{'urlbase'} eq '') {
</span><del>-    print &quot;\n&quot; . Bugzilla::Install::get_text('install_urlbase_default') . &quot;\n&quot;
</del><ins>+    print &quot;\n&quot; . get_text('install_urlbase_default') . &quot;\n&quot;
</ins><span class="cx">         unless $silent;
</span><span class="cx"> }
</span><ins>+if (!$silent) {
+    success(get_text('install_success'));
+}
</ins><span class="cx"> 
</span><span class="cx"> __END__
</span><span class="cx"> 
</span><span class="lines">@@ -406,6 +417,10 @@
</span><span class="cx"> 
</span><span class="cx"> The code for this is in L&lt;Bugzilla::Install::DB/update_table_definitions&gt;.
</span><span class="cx"> 
</span><ins>+This includes creating the default Classification (using 
+L&lt;Bugzilla::Install/create_default_classification&gt;) and setting up all
+the foreign keys for all tables, using L&lt;Bugzilla::DB/bz_setup_foreign_keys&gt;.
+
</ins><span class="cx"> =item 14
</span><span class="cx"> 
</span><span class="cx"> Creates the system groups--the ones like C&lt;editbugs&gt;, C&lt;admin&gt;, and so on.
</span><span class="lines">@@ -426,7 +441,7 @@
</span><span class="cx"> 
</span><span class="cx"> =item 17
</span><span class="cx"> 
</span><del>-Creates the default Classification, Product, and Component, using
</del><ins>+Creates the default Product and Component, using
</ins><span class="cx"> L&lt;Bugzilla::Install/create_default_product&gt;.
</span><span class="cx"> 
</span><span class="cx"> =back
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgcolchangecgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/colchange.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/colchange.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/colchange.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -21,9 +21,9 @@
</span><span class="cx"> # Contributor(s): Terry Weissman &lt;terry@mozilla.org&gt;
</span><span class="cx"> #                 Gervase Markham &lt;gerv@gerv.net&gt;
</span><span class="cx"> #                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
</span><ins>+#                 Pascal Held &lt;paheld@gmail.com&gt;
</ins><span class="cx"> 
</span><span class="cx"> use strict;
</span><del>-
</del><span class="cx"> use lib qw(. lib);
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla;
</span><span class="lines">@@ -33,79 +33,86 @@
</span><span class="cx"> use Bugzilla::Search::Saved;
</span><span class="cx"> use Bugzilla::Error;
</span><span class="cx"> use Bugzilla::User;
</span><del>-use Bugzilla::Keyword;
</del><ins>+use Bugzilla::Token;
</ins><span class="cx"> 
</span><ins>+use Storable qw(dclone);
+
+# Maps parameters that control columns to the names of columns.
+use constant COLUMN_PARAMS =&gt; {
+    'useclassification'   =&gt; ['classification'],
+    'usebugaliases'       =&gt; ['alias'],
+    'usetargetmilestone'  =&gt; ['target_milestone'],
+    'useqacontact'        =&gt; ['qa_contact', 'qa_contact_realname'],
+    'usestatuswhiteboard' =&gt; ['status_whiteboard'],
+};
+
+# We only show these columns if an object of this type exists in the
+# database.
+use constant COLUMN_CLASSES =&gt; {
+    'Bugzilla::Flag'    =&gt; 'flagtypes.name',
+    'Bugzilla::Keyword' =&gt; 'keywords',
+};
+
</ins><span class="cx"> Bugzilla-&gt;login();
</span><span class="cx"> 
</span><span class="cx"> my $cgi = Bugzilla-&gt;cgi;
</span><span class="cx"> my $template = Bugzilla-&gt;template;
</span><span class="cx"> my $vars = {};
</span><span class="cx"> 
</span><del>-# The master list not only says what fields are possible, but what order
-# they get displayed in.
-my @masterlist = (&quot;opendate&quot;, &quot;changeddate&quot;, &quot;bug_severity&quot;, &quot;priority&quot;,
-                  &quot;rep_platform&quot;, &quot;assigned_to&quot;, &quot;assigned_to_realname&quot;,
-                  &quot;reporter&quot;, &quot;reporter_realname&quot;, &quot;bug_status&quot;,
-                  &quot;resolution&quot;);
</del><ins>+my $columns = dclone(Bugzilla::Search::COLUMNS);
</ins><span class="cx"> 
</span><del>-if (Bugzilla-&gt;params-&gt;{&quot;useclassification&quot;}) {
-    push(@masterlist, &quot;classification&quot;);
</del><ins>+# You can't manually select &quot;relevance&quot; as a column you want to see.
+delete $columns-&gt;{'relevance'};
+
+foreach my $param (keys %{ COLUMN_PARAMS() }) {
+    next if Bugzilla-&gt;params-&gt;{$param};
+    foreach my $column (@{ COLUMN_PARAMS-&gt;{$param} }) {
+        delete $columns-&gt;{$column};
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-push(@masterlist, (&quot;product&quot;, &quot;component&quot;, &quot;version&quot;, &quot;op_sys&quot;));
-
-if (Bugzilla-&gt;params-&gt;{&quot;usevotes&quot;}) {
-    push (@masterlist, &quot;votes&quot;);
</del><ins>+foreach my $class (keys %{ COLUMN_CLASSES() }) {
+    eval(&quot;use $class; 1;&quot;) || die $@;
+    my $column = COLUMN_CLASSES-&gt;{$class};
+    delete $columns-&gt;{$column} if !$class-&gt;any_exist;
</ins><span class="cx"> }
</span><del>-if (Bugzilla-&gt;params-&gt;{&quot;usebugaliases&quot;}) {
-    unshift(@masterlist, &quot;alias&quot;);
-}
-if (Bugzilla-&gt;params-&gt;{&quot;usetargetmilestone&quot;}) {
-    push(@masterlist, &quot;target_milestone&quot;);
-}
-if (Bugzilla-&gt;params-&gt;{&quot;useqacontact&quot;}) {
-    push(@masterlist, &quot;qa_contact&quot;);
-    push(@masterlist, &quot;qa_contact_realname&quot;);
-}
-if (Bugzilla-&gt;params-&gt;{&quot;usestatuswhiteboard&quot;}) {
-    push(@masterlist, &quot;status_whiteboard&quot;);
-}
-if (Bugzilla::Keyword::keyword_count()) {
-    push(@masterlist, &quot;keywords&quot;);
-}
</del><span class="cx"> 
</span><del>-if (Bugzilla-&gt;user-&gt;in_group(Bugzilla-&gt;params-&gt;{&quot;timetrackinggroup&quot;})) {
-    push(@masterlist, (&quot;estimated_time&quot;, &quot;remaining_time&quot;, &quot;actual_time&quot;,
-                       &quot;percentage_complete&quot;, &quot;deadline&quot;)); 
</del><ins>+if (!Bugzilla-&gt;user-&gt;is_timetracker) {
+    foreach my $column (TIMETRACKING_FIELDS) {
+        delete $columns-&gt;{$column};
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-push(@masterlist, (&quot;short_desc&quot;, &quot;short_short_desc&quot;));
</del><ins>+$vars-&gt;{'columns'} = $columns;
</ins><span class="cx"> 
</span><del>-my @custom_fields = grep { $_-&gt;type != FIELD_TYPE_MULTI_SELECT }
-                         Bugzilla-&gt;active_custom_fields;
-push(@masterlist, map { $_-&gt;name } @custom_fields);
-
-Bugzilla::Hook::process(&quot;colchange-columns&quot;, {'columns' =&gt; \@masterlist} );
-
-$vars-&gt;{'masterlist'} = \@masterlist;
-
</del><span class="cx"> my @collist;
</span><span class="cx"> if (defined $cgi-&gt;param('rememberedquery')) {
</span><ins>+    my $search;
+    if (defined $cgi-&gt;param('saved_search')) {
+        $search = new Bugzilla::Search::Saved($cgi-&gt;param('saved_search'));
+    }
+
+    my $token = $cgi-&gt;param('token');
+    if ($search) {
+        check_hash_token($token, [$search-&gt;id, $search-&gt;name]);
+    }
+    else {
+        check_hash_token($token, ['default-list']);
+    }
+
</ins><span class="cx">     my $splitheader = 0;
</span><span class="cx">     if (defined $cgi-&gt;param('resetit')) {
</span><span class="cx">         @collist = DEFAULT_COLUMN_LIST;
</span><span class="cx">     } else {
</span><del>-        foreach my $i (@masterlist) {
-            if (defined $cgi-&gt;param(&quot;column_$i&quot;)) {
-                push @collist, $i;
-            }
</del><ins>+        if (defined $cgi-&gt;param(&quot;selected_columns&quot;)) {
+            @collist = grep { exists $columns-&gt;{$_} } 
+                            $cgi-&gt;param(&quot;selected_columns&quot;);
</ins><span class="cx">         }
</span><span class="cx">         if (defined $cgi-&gt;param('splitheader')) {
</span><span class="cx">             $splitheader = $cgi-&gt;param('splitheader')? 1: 0;
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     my $list = join(&quot; &quot;, @collist);
</span><del>-    my $urlbase = Bugzilla-&gt;params-&gt;{&quot;urlbase&quot;};
</del><span class="cx"> 
</span><span class="cx">     if ($list) {
</span><span class="cx">         # Only set the cookie if this is not a saved search.
</span><span class="lines">@@ -130,11 +137,6 @@
</span><span class="cx"> 
</span><span class="cx">     $vars-&gt;{'message'} = &quot;change_columns&quot;;
</span><span class="cx"> 
</span><del>-    my $search;
-    if (defined $cgi-&gt;param('saved_search')) {
-        $search = new Bugzilla::Search::Saved($cgi-&gt;param('saved_search'));
-    }
-
</del><span class="cx">     if ($cgi-&gt;param('save_columns_for_search')
</span><span class="cx">         &amp;&amp; defined $search &amp;&amp; $search-&gt;user-&gt;id == Bugzilla-&gt;user-&gt;id) 
</span><span class="cx">     {
</span><span class="lines">@@ -142,19 +144,20 @@
</span><span class="cx">         $params-&gt;param('columnlist', join(&quot;,&quot;, @collist));
</span><span class="cx">         $search-&gt;set_url($params-&gt;query_string());
</span><span class="cx">         $search-&gt;update();
</span><del>-        $vars-&gt;{'redirect_url'} = &quot;buglist.cgi?&quot;.$cgi-&gt;param('rememberedquery');
</del><span class="cx">     }
</span><del>-    else {
-        my $params = new Bugzilla::CGI($cgi-&gt;param('rememberedquery'));
-        $params-&gt;param('columnlist', join(&quot;,&quot;, @collist));
-        $vars-&gt;{'redirect_url'} = &quot;buglist.cgi?&quot;.$params-&gt;query_string();
-    }
</del><span class="cx"> 
</span><ins>+    my $params = new Bugzilla::CGI($cgi-&gt;param('rememberedquery'));
+    $params-&gt;param('columnlist', join(&quot;,&quot;, @collist));
+    $vars-&gt;{'redirect_url'} = &quot;buglist.cgi?&quot;.$params-&gt;query_string();
</ins><span class="cx"> 
</span><del>-    # If we're running on Microsoft IIS, using cgi-&gt;redirect discards
-    # the Set-Cookie lines -- workaround is to use the old-fashioned 
-    # redirection mechanism. See bug 214466 for details.
-    if ($ENV{'SERVER_SOFTWARE'} =~ /Microsoft-IIS/
</del><ins>+
+    # If we're running on Microsoft IIS, $cgi-&gt;redirect discards
+    # the Set-Cookie lines. In mod_perl, $cgi-&gt;redirect with cookies
+    # causes the page to be rendered as text/plain.
+    # Workaround is to use the old-fashioned  redirection mechanism. 
+    # See bug 214466 and bug 376044 for details.
+    if ($ENV{'MOD_PERL'} 
+        || $ENV{'SERVER_SOFTWARE'} =~ /Microsoft-IIS/
</ins><span class="cx">         || $ENV{'SERVER_SOFTWARE'} =~ /Sun ONE Web/)
</span><span class="cx">     {
</span><span class="cx">       print $cgi-&gt;header(-type =&gt; &quot;text/html&quot;,
</span><span class="lines">@@ -162,6 +165,7 @@
</span><span class="cx">     }
</span><span class="cx">     else {
</span><span class="cx">       print $cgi-&gt;redirect($vars-&gt;{'redirect_url'});
</span><ins>+      exit;
</ins><span class="cx">     }
</span><span class="cx">     
</span><span class="cx">     $template-&gt;process(&quot;global/message.html.tmpl&quot;, $vars)
</span><span class="lines">@@ -169,7 +173,9 @@
</span><span class="cx">     exit;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-if (defined $cgi-&gt;cookie('COLUMNLIST')) {
</del><ins>+if (defined $cgi-&gt;param('columnlist')) {
+    @collist = split(/[ ,]+/, $cgi-&gt;param('columnlist'));
+} elsif (defined $cgi-&gt;cookie('COLUMNLIST')) {
</ins><span class="cx">     @collist = split(/ /, $cgi-&gt;cookie('COLUMNLIST'));
</span><span class="cx"> } else {
</span><span class="cx">     @collist = DEFAULT_COLUMN_LIST;
</span><span class="lines">@@ -185,16 +191,8 @@
</span><span class="cx">     my $searches = Bugzilla-&gt;user-&gt;queries;
</span><span class="cx">     my ($search) = grep($_-&gt;name eq $cgi-&gt;param('query_based_on'), @$searches);
</span><span class="cx"> 
</span><del>-    # Only allow users to edit their own queries.
-    if ($search &amp;&amp; $search-&gt;user-&gt;id == Bugzilla-&gt;user-&gt;id) {
</del><ins>+    if ($search) {
</ins><span class="cx">         $vars-&gt;{'saved_search'} = $search;
</span><del>-        $vars-&gt;{'buffer'} = &quot;cmdtype=runnamed&amp;namedcmd=&quot;. url_quote($search-&gt;name);
-
-        my $params = new Bugzilla::CGI($search-&gt;url);
-        if ($params-&gt;param('columnlist')) {
-            my @collist = split(',', $params-&gt;param('columnlist'));
-            $vars-&gt;{'collist'} = \@collist if scalar (@collist);
-        }
</del><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgcollectstatspl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/collectstats.pl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/collectstats.pl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/collectstats.pl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -25,18 +25,14 @@
</span><span class="cx"> #                 Jean-Sebastien Guay &lt;jean_seb@hybride.com&gt;
</span><span class="cx"> #                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
</span><span class="cx"> 
</span><del>-# Run me out of cron at midnight to collect Bugzilla statistics.
-#
-# To run new charts for a specific date, pass it in on the command line in
-# ISO (2004-08-14) format.
-
-use AnyDBM_File;
</del><span class="cx"> use strict;
</span><del>-use IO::Handle;
-use Cwd;
-
</del><span class="cx"> use lib qw(. lib);
</span><span class="cx"> 
</span><ins>+use Getopt::Long qw(:config bundling);
+use Pod::Usage;
+use List::Util qw(first);
+use Cwd;
+
</ins><span class="cx"> use Bugzilla;
</span><span class="cx"> use Bugzilla::Constants;
</span><span class="cx"> use Bugzilla::Error;
</span><span class="lines">@@ -45,38 +41,32 @@
</span><span class="cx"> use Bugzilla::User;
</span><span class="cx"> use Bugzilla::Product;
</span><span class="cx"> use Bugzilla::Field;
</span><ins>+use Bugzilla::Install::Filesystem qw(fix_dir_permissions);
</ins><span class="cx"> 
</span><ins>+my %switch;
+GetOptions(\%switch, 'help|h', 'regenerate');
+
+# Print the help message if that switch was selected.
+pod2usage({-verbose =&gt; 1, -exitval =&gt; 1}) if $switch{'help'};
+
</ins><span class="cx"> # Turn off output buffering (probably needed when displaying output feedback
</span><span class="cx"> # in the regenerate mode).
</span><span class="cx"> $| = 1;
</span><span class="cx"> 
</span><ins>+my $datadir = bz_locations()-&gt;{'datadir'};
+my $graphsdir = bz_locations()-&gt;{'graphsdir'};
+
</ins><span class="cx"> # Tidy up after graphing module
</span><span class="cx"> my $cwd = Cwd::getcwd();
</span><del>-if (chdir(&quot;graphs&quot;)) {
</del><ins>+if (chdir($graphsdir)) {
</ins><span class="cx">     unlink &lt;./*.gif&gt;;
</span><span class="cx">     unlink &lt;./*.png&gt;;
</span><span class="cx">     # chdir(&quot;..&quot;) doesn't work if graphs is a symlink, see bug 429378
</span><span class="cx">     chdir($cwd);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-# This is a pure command line script.
-Bugzilla-&gt;usage_mode(USAGE_MODE_CMDLINE);
-
</del><span class="cx"> my $dbh = Bugzilla-&gt;switch_to_shadow_db();
</span><span class="cx"> 
</span><del>-
-# To recreate the daily statistics,  run &quot;collectstats.pl --regenerate&quot; .
-my $regenerate = 0;
-if ($#ARGV &gt;= 0 &amp;&amp; $ARGV[0] eq &quot;--regenerate&quot;) {
-    shift(@ARGV);
-    $regenerate = 1;
-}
-
-my $datadir = bz_locations()-&gt;{'datadir'};
-
-my @myproducts = map {$_-&gt;name} Bugzilla::Product-&gt;get_all;
-unshift(@myproducts, &quot;-All-&quot;);
-
</del><span class="cx"> # As we can now customize statuses and resolutions, looking at the current list
</span><span class="cx"> # of legal values only is not enough as some now removed statuses and resolutions
</span><span class="cx"> # may have existed in the past, or have been renamed. We want them all.
</span><span class="lines">@@ -114,71 +104,74 @@
</span><span class="cx"> # Exclude &quot;&quot; from the resolution list.
</span><span class="cx"> @resolutions = grep {$_} @resolutions;
</span><span class="cx"> 
</span><ins>+# --regenerate was taking an enormous amount of time to query everything
+# per bug, per day. Instead, we now just get all the data out of the DB
+# at once and stuff it into some data structures.
+my (%bug_status, %bug_resolution, %removed);
+if ($switch{'regenerate'}) {
+    %bug_resolution = @{ $dbh-&gt;selectcol_arrayref(
+        'SELECT bug_id, resolution FROM bugs', {Columns=&gt;[1,2]}) };
+    %bug_status = @{ $dbh-&gt;selectcol_arrayref(
+        'SELECT bug_id, bug_status FROM bugs', {Columns=&gt;[1,2]}) };
+
+    my $removed_sth = $dbh-&gt;prepare(
+        q{SELECT bugs_activity.bug_id, bugs_activity.removed,}
+        . $dbh-&gt;sql_to_days('bugs_activity.bug_when')
+       . q{ FROM bugs_activity
+           WHERE bugs_activity.fieldid = ?
+        ORDER BY bugs_activity.bug_when});
+
+    %removed = (bug_status =&gt; {}, resolution =&gt; {});
+    foreach my $field (qw(bug_status resolution)) {
+        my $field_id = Bugzilla::Field-&gt;check($field)-&gt;id;
+        my $rows = $dbh-&gt;selectall_arrayref($removed_sth, undef, $field_id);
+        my $hash = $removed{$field};
+        foreach my $row (@$rows) {
+            my ($bug_id, $removed, $when) = @$row;
+            $hash-&gt;{$bug_id} ||= [];
+            push(@{ $hash-&gt;{$bug_id} }, { when    =&gt; int($when),
+                                          removed =&gt; $removed });
+        }
+    }
+}
+
</ins><span class="cx"> my $tstart = time;
</span><del>-foreach (@myproducts) {
-    my $dir = &quot;$datadir/mining&quot;;
</del><span class="cx"> 
</span><del>-    &amp;check_data_dir ($dir);
</del><ins>+my @myproducts = Bugzilla::Product-&gt;get_all;
+unshift(@myproducts, &quot;-All-&quot;);
</ins><span class="cx"> 
</span><del>-    if ($regenerate) {
-        &amp;regenerate_stats($dir, $_);
</del><ins>+my $dir = &quot;$datadir/mining&quot;;
+if (!-d $dir) {
+    mkdir $dir or die &quot;mkdir $dir failed: $!&quot;;
+    fix_dir_permissions($dir);
+}
+
+foreach (@myproducts) {
+    if ($switch{'regenerate'}) {
+        regenerate_stats($dir, $_, \%bug_resolution, \%bug_status, \%removed);
</ins><span class="cx">     } else {
</span><span class="cx">         &amp;collect_stats($dir, $_);
</span><span class="cx">     }
</span><span class="cx"> }
</span><ins>+# Fix permissions for all files in mining/.
+fix_dir_permissions($dir);
+
</ins><span class="cx"> my $tend = time;
</span><span class="cx"> # Uncomment the following line for performance testing.
</span><span class="cx"> #print &quot;Total time taken &quot; . delta_time($tstart, $tend) . &quot;\n&quot;;
</span><span class="cx"> 
</span><del>-&amp;calculate_dupes();
-
</del><span class="cx"> CollectSeriesData();
</span><span class="cx"> 
</span><del>-{
-    local $ENV{'GATEWAY_INTERFACE'} = 'cmdline';
-    local $ENV{'REQUEST_METHOD'} = 'GET';
-    local $ENV{'QUERY_STRING'} = 'ctype=rdf';
-
-    my $perl = $^X;
-    trick_taint($perl);
-
-    # Generate a static RDF file containing the default view of the duplicates data.
-    open(CGI, &quot;$perl -T duplicates.cgi |&quot;)
-        || die &quot;can't fork duplicates.cgi: $!&quot;;
-    open(RDF, &quot;&gt;$datadir/duplicates.tmp&quot;)
-        || die &quot;can't write to $datadir/duplicates.tmp: $!&quot;;
-    my $headers_done = 0;
-    while (&lt;CGI&gt;) {
-        print RDF if $headers_done;
-        $headers_done = 1 if $_ eq &quot;\r\n&quot;;
-    }
-    close CGI;
-    close RDF;
-}
-if (-s &quot;$datadir/duplicates.tmp&quot;) {
-    rename(&quot;$datadir/duplicates.rdf&quot;, &quot;$datadir/duplicates-old.rdf&quot;);
-    rename(&quot;$datadir/duplicates.tmp&quot;, &quot;$datadir/duplicates.rdf&quot;);
-}
-
-sub check_data_dir {
-    my $dir = shift;
-
-    if (! -d $dir) {
-        mkdir $dir, 0755;
-        chmod 0755, $dir;
-    }
-}
-
</del><span class="cx"> sub collect_stats {
</span><span class="cx">     my $dir = shift;
</span><span class="cx">     my $product = shift;
</span><span class="cx">     my $when = localtime (time);
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><del>-
</del><span class="cx">     my $product_id;
</span><del>-    if ($product ne '-All-') {
-        my $prod = Bugzilla::Product::check_product($product);
-        $product_id = $prod-&gt;id;
</del><ins>+
+    if (ref $product) {
+        $product_id = $product-&gt;id;
+        $product = $product-&gt;name;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # NB: Need to mangle the product for the filename, but use the real
</span><span class="lines">@@ -202,6 +195,10 @@
</span><span class="cx">           || ThrowCodeError('chart_file_open_fail', {'filename' =&gt; $file});
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    if (Bugzilla-&gt;params-&gt;{'utf8'}) {
+        binmode DATA, ':utf8';
+    }
+
</ins><span class="cx">     # Now collect current data.
</span><span class="cx">     my @row = (today());
</span><span class="cx">     my $status_sql = q{SELECT COUNT(*) FROM bugs WHERE bug_status = ?};
</span><span class="lines">@@ -250,7 +247,6 @@
</span><span class="cx">     }
</span><span class="cx">     print DATA (join '|', @row) . &quot;\n&quot;;
</span><span class="cx">     close DATA;
</span><del>-    chmod 0644, $file;
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub get_old_data {
</span><span class="lines">@@ -259,6 +255,10 @@
</span><span class="cx">     open(DATA, '&lt;', $file)
</span><span class="cx">       || ThrowCodeError('chart_file_open_fail', {'filename' =&gt; $file});
</span><span class="cx"> 
</span><ins>+    if (Bugzilla-&gt;params-&gt;{'utf8'}) {
+        binmode DATA, ':utf8';
+    }
+
</ins><span class="cx">     my @data;
</span><span class="cx">     my @columns;
</span><span class="cx">     my $recreate = 0;
</span><span class="lines">@@ -295,85 +295,9 @@
</span><span class="cx">     return @data;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub calculate_dupes {
-    my $dbh = Bugzilla-&gt;dbh;
-    my $rows = $dbh-&gt;selectall_arrayref(&quot;SELECT dupe_of, dupe FROM duplicates&quot;);
-
-    my %dupes;
-    my %count;
-    my $key;
-    my $changed = 1;
-
-    my $today = &amp;today_dash;
-
-    # Save % count here in a date-named file
-    # so we can read it back in to do changed counters
-    # First, delete it if it exists, so we don't add to the contents of an old file
-    my $datadir = bz_locations()-&gt;{'datadir'};
-
-    if (my @files = &lt;$datadir/duplicates/dupes$today*&gt;) {
-        map { trick_taint($_) } @files;
-        unlink @files;
-    }
-   
-    dbmopen(%count, &quot;$datadir/duplicates/dupes$today&quot;, 0644) || die &quot;Can't open DBM dupes file: $!&quot;;
-
-    # Create a hash with key &quot;a bug number&quot;, value &quot;bug which that bug is a
-    # direct dupe of&quot; - straight from the duplicates table.
-    foreach my $row (@$rows) {
-        my ($dupe_of, $dupe) = @$row;
-        $dupes{$dupe} = $dupe_of;
-    }
-
-    # Total up the number of bugs which are dupes of a given bug
-    # count will then have key = &quot;bug number&quot;, 
-    # value = &quot;number of immediate dupes of that bug&quot;.
-    foreach $key (keys(%dupes)) 
-    {
-        my $dupe_of = $dupes{$key};
-
-        if (!defined($count{$dupe_of})) {
-            $count{$dupe_of} = 0;
-        }
-
-        $count{$dupe_of}++;
-    }
-
-    # Now we collapse the dupe tree by iterating over %count until
-    # there is no further change.
-    while ($changed == 1)
-    {
-        $changed = 0;
-        foreach $key (keys(%count)) {
-            # if this bug is actually itself a dupe, and has a count...
-            if (defined($dupes{$key}) &amp;&amp; $count{$key} &gt; 0) {
-                # add that count onto the bug it is a dupe of,
-                # and zero the count; the check is to avoid
-                # loops
-                if ($count{$dupes{$key}} != 0) {
-                    $count{$dupes{$key}} += $count{$key};
-                    $count{$key} = 0;
-                    $changed = 1;
-                }
-            }
-        }
-    }
-
-    # Remove the values for which the count is zero
-    foreach $key (keys(%count))
-    {
-        if ($count{$key} == 0) {
-            delete $count{$key};
-        }
-    }
-   
-    dbmclose(%count);
-}
-
</del><span class="cx"> # This regenerates all statistics from the database.
</span><span class="cx"> sub regenerate_stats {
</span><del>-    my $dir = shift;
-    my $product = shift;
</del><ins>+    my ($dir, $product, $bug_resolution, $bug_status, $removed) = @_;
</ins><span class="cx"> 
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx">     my $when = localtime(time());
</span><span class="lines">@@ -381,12 +305,13 @@
</span><span class="cx"> 
</span><span class="cx">     # NB: Need to mangle the product for the filename, but use the real
</span><span class="cx">     # product name in the query
</span><ins>+    if (ref $product) {
+        $product = $product-&gt;name;
+    }
</ins><span class="cx">     my $file_product = $product;
</span><span class="cx">     $file_product =~ s/\//-/gs;
</span><span class="cx">     my $file = join '/', $dir, $file_product;
</span><span class="cx"> 
</span><del>-    my @bugs;
-
</del><span class="cx">     my $and_product = &quot;&quot;;
</span><span class="cx">     my $from_product = &quot;&quot;;
</span><span class="cx"> 
</span><span class="lines">@@ -402,7 +327,7 @@
</span><span class="cx">     # database was created, and the end date from the current day.
</span><span class="cx">     # If there were no bugs in the search, return early.
</span><span class="cx">     my $query = q{SELECT } .
</span><del>-                $dbh-&gt;sql_to_days('creation_ts') . q{ AS start_day, } . 
</del><ins>+                $dbh-&gt;sql_to_days('creation_ts') . q{ AS start_day, } .
</ins><span class="cx">                 $dbh-&gt;sql_to_days('current_date') . q{ AS end_day, } . 
</span><span class="cx">                 $dbh-&gt;sql_to_days(&quot;'1970-01-01'&quot;) . 
</span><span class="cx">                  qq{ FROM bugs $from_product 
</span><span class="lines">@@ -416,7 +341,6 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if (open DATA, &quot;&gt;$file&quot;) {
</span><del>-        DATA-&gt;autoflush(1);
</del><span class="cx">         my $fields = join('|', ('DATE', @statuses, @resolutions));
</span><span class="cx">         print DATA &lt;&lt;FIN;
</span><span class="cx"> # Bugzilla Daily Bug Stats
</span><span class="lines">@@ -429,6 +353,7 @@
</span><span class="cx"> FIN
</span><span class="cx">         # For each day, generate a line of statistics.
</span><span class="cx">         my $total_days = $end - $start;
</span><ins>+        my @bugs;
</ins><span class="cx">         for (my $day = $start + 1; $day &lt;= $end; $day++) {
</span><span class="cx">             # Some output feedback
</span><span class="cx">             my $percent_done = ($day - $start - 1) * 100 / $total_days;
</span><span class="lines">@@ -445,56 +370,25 @@
</span><span class="cx">                         $and_product . q{ ORDER BY bug_id};
</span><span class="cx"> 
</span><span class="cx">             my $bug_ids = $dbh-&gt;selectcol_arrayref($query, undef, @values);
</span><del>-
</del><span class="cx">             push(@bugs, @$bug_ids);
</span><span class="cx"> 
</span><del>-            # For each bug that existed on that day, determine its status
-            # at the beginning of the day.  If there were no status
-            # changes on or after that day, the status was the same as it
-            # is today, which can be found in the bugs table.  Otherwise,
-            # the status was equal to the first &quot;previous value&quot; entry in
-            # the bugs_activity table for that bug made on or after that
-            # day.
</del><span class="cx">             my %bugcount;
</span><span class="cx">             foreach (@statuses) { $bugcount{$_} = 0; }
</span><span class="cx">             foreach (@resolutions) { $bugcount{$_} = 0; }
</span><span class="cx">             # Get information on bug states and resolutions.
</span><del>-            $query = qq{SELECT bugs_activity.removed 
-                          FROM bugs_activity 
-                    INNER JOIN fielddefs 
-                            ON bugs_activity.fieldid = fielddefs.id 
-                         WHERE fielddefs.name = ? 
-                           AND bugs_activity.bug_id = ? 
-                           AND bugs_activity.bug_when &gt;= } . 
-                           $dbh-&gt;sql_from_days($day) . 
-                    &quot; ORDER BY bugs_activity.bug_when &quot; . 
-                          $dbh-&gt;sql_limit(1);
-
-            my $sth_bug = $dbh-&gt;prepare($query);
-            my $sth_status = $dbh-&gt;prepare(q{SELECT bug_status 
-                                               FROM bugs 
-                                              WHERE bug_id = ?});
-            
-            my $sth_reso = $dbh-&gt;prepare(q{SELECT resolution 
-                                             FROM bugs 
-                                            WHERE bug_id = ?});
-
</del><span class="cx">             for my $bug (@bugs) {
</span><del>-                my $status = $dbh-&gt;selectrow_array($sth_bug, undef, 
-                                                       'bug_status', $bug);
-                unless ($status) {
-                    $status = $dbh-&gt;selectrow_array($sth_status, undef, $bug);
-                }
</del><ins>+                my $status = _get_value(
+                    $removed-&gt;{'bug_status'}-&gt;{$bug},
+                    $bug_status,  $day, $bug);
</ins><span class="cx"> 
</span><span class="cx">                 if (defined $bugcount{$status}) {
</span><span class="cx">                     $bugcount{$status}++;
</span><span class="cx">                 }
</span><del>-                my $resolution = $dbh-&gt;selectrow_array($sth_bug, undef, 
-                                                         'resolution', $bug);
-                unless ($resolution) {
-                    $resolution = $dbh-&gt;selectrow_array($sth_reso, undef, $bug);
-                }
-                
</del><ins>+
+                my $resolution = _get_value(
+                    $removed-&gt;{'resolution'}-&gt;{$bug},
+                    $bug_resolution, $day, $bug);
+
</ins><span class="cx">                 if (defined $bugcount{$resolution}) {
</span><span class="cx">                     $bugcount{$resolution}++;
</span><span class="cx">                 }
</span><span class="lines">@@ -508,17 +402,34 @@
</span><span class="cx">             foreach (@resolutions) { print DATA &quot;|$bugcount{$_}&quot;; }
</span><span class="cx">             print DATA &quot;\n&quot;;
</span><span class="cx">         }
</span><del>-        
</del><ins>+
</ins><span class="cx">         # Finish up output feedback for this product.
</span><span class="cx">         my $tend = time;
</span><span class="cx">         print &quot;\rRegenerating $product \[100.0\%] - &quot; .
</span><span class="cx">             delta_time($tstart, $tend) . &quot;\n&quot;;
</span><del>-            
</del><ins>+
</ins><span class="cx">         close DATA;
</span><del>-        chmod 0640, $file;
</del><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# A helper for --regenerate.
+# For each bug that exists on a day, we determine its status/resolution
+# at the beginning of the day.  If there were no status/resolution
+# changes on or after that day, the status was the same as it
+# is today (the &quot;current&quot; value).  Otherwise, the status was equal to the
+# first &quot;previous value&quot; entry in the bugs_activity table for that 
+# bug made on or after that day.
+sub _get_value {
+    my ($removed, $current, $day, $bug) = @_;
+
+    # Get the first change that's on or after this day.
+    my $item = first { $_-&gt;{when} &gt;= $day } @{ $removed || [] };
+
+    # If there's no change on or after this day, then we just return the
+    # current value.
+    return $item ? $item-&gt;{removed} : $current-&gt;{$bug};
+}
+
</ins><span class="cx"> sub today {
</span><span class="cx">     my ($dom, $mon, $year) = (localtime(time))[3, 4, 5];
</span><span class="cx">     return sprintf &quot;%04d%02d%02d&quot;, 1900 + $year, ++$mon, $dom;
</span><span class="lines">@@ -555,7 +466,7 @@
</span><span class="cx">     # (days_since_epoch + series_id) % frequency = 0. So they'll run every
</span><span class="cx">     # &lt;frequency&gt; days, but the start date depends on the series_id.
</span><span class="cx">     my $days_since_epoch = int(time() / (60 * 60 * 24));
</span><del>-    my $today = $ARGV[0] || today_dash();
</del><ins>+    my $today = today_dash();
</ins><span class="cx"> 
</span><span class="cx">     # We save a copy of the main $dbh and then switch to the shadow and get
</span><span class="cx">     # that one too. Remember, these may be the same.
</span><span class="lines">@@ -589,10 +500,11 @@
</span><span class="cx">         # Do not die if Search-&gt;new() detects invalid data, such as an obsolete
</span><span class="cx">         # login name or a renamed product or component, etc.
</span><span class="cx">         eval {
</span><del>-            my $search = new Bugzilla::Search('params' =&gt; $cgi,
-                                              'fields' =&gt; [&quot;bugs.bug_id&quot;],
</del><ins>+            my $search = new Bugzilla::Search('params' =&gt; scalar $cgi-&gt;Vars,
+                                              'fields' =&gt; [&quot;bug_id&quot;],
+                                              'allow_unlimited' =&gt; 1,
</ins><span class="cx">                                               'user'   =&gt; $user);
</span><del>-            my $sql = $search-&gt;getSQL();
</del><ins>+            my $sql = $search-&gt;sql;
</ins><span class="cx">             $data = $shadow_dbh-&gt;selectall_arrayref($sql);
</span><span class="cx">         };
</span><span class="cx"> 
</span><span class="lines">@@ -607,3 +519,39 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+__END__
+
+=head1 NAME
+
+collectstats.pl - Collect data about Bugzilla bugs.
+
+=head1 SYNOPSIS
+
+ ./collectstats.pl [--regenerate] [--help]
+
+Collects data about bugs to be used in Old and New Charts.
+
+=head1 OPTIONS
+
+=over
+
+=item B&lt;--help&gt;
+
+Print this help page.
+
+=item B&lt;--regenerate&gt;
+
+Recreate all the data about bugs, from day 1. This option is only relevant
+for Old Charts, and has no effect for New Charts.
+This option will overwrite all existing collected data and can take a huge
+amount of time. You normally don't need to use this option (do not use it
+in a cron job).
+
+=back
+
+=head1 DESCRIPTION
+
+This script collects data about all bugs for Old Charts, triaged by product
+and by bug status and resolution. It also collects data for New Charts, based
+on existing series. For New Charts, data is only collected once a series is
+defined; this script cannot recreate data prior to this date.
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgconfigcgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/config.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/config.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/config.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -20,6 +20,7 @@
</span><span class="cx"> #
</span><span class="cx"> # Contributor(s): Terry Weissman &lt;terry@mozilla.org&gt;
</span><span class="cx"> #                 Myk Melez &lt;myk@mozilla.org&gt;
</span><ins>+#                 Frank Becker &lt;Frank@Frank-Becker.de&gt;
</ins><span class="cx"> 
</span><span class="cx"> ################################################################################
</span><span class="cx"> # Script Initialization
</span><span class="lines">@@ -34,9 +35,12 @@
</span><span class="cx"> use Bugzilla::Constants;
</span><span class="cx"> use Bugzilla::Error;
</span><span class="cx"> use Bugzilla::Keyword;
</span><ins>+use Bugzilla::Product;
</ins><span class="cx"> use Bugzilla::Status;
</span><span class="cx"> use Bugzilla::Field;
</span><span class="cx"> 
</span><ins>+use Digest::MD5 qw(md5_base64);
+
</ins><span class="cx"> my $user = Bugzilla-&gt;login(LOGIN_OPTIONAL);
</span><span class="cx"> my $cgi  = Bugzilla-&gt;cgi;
</span><span class="cx"> 
</span><span class="lines">@@ -46,6 +50,9 @@
</span><span class="cx">     display_data();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# Get data from the shadow DB as they don't change very often.
+Bugzilla-&gt;switch_to_shadow_db;
+
</ins><span class="cx"> # Pass a bunch of Bugzilla configuration to the templates.
</span><span class="cx"> my $vars = {};
</span><span class="cx"> $vars-&gt;{'priority'}  = get_legal_field_values('priority');
</span><span class="lines">@@ -56,14 +63,13 @@
</span><span class="cx"> $vars-&gt;{'resolution'} = get_legal_field_values('resolution');
</span><span class="cx"> $vars-&gt;{'status'}    = get_legal_field_values('bug_status');
</span><span class="cx"> $vars-&gt;{'custom_fields'} =
</span><del>-  [ grep {$_-&gt;type == FIELD_TYPE_SINGLE_SELECT || $_-&gt;type == FIELD_TYPE_MULTI_SELECT}
-         Bugzilla-&gt;active_custom_fields ];
</del><ins>+    [ grep {$_-&gt;is_select} Bugzilla-&gt;active_custom_fields ];
</ins><span class="cx"> 
</span><span class="cx"> # Include a list of product objects.
</span><span class="cx"> if ($cgi-&gt;param('product')) {
</span><span class="cx">     my @products = $cgi-&gt;param('product');
</span><span class="cx">     foreach my $product_name (@products) {
</span><del>-        # We don't use check_product because config.cgi outputs mostly
</del><ins>+        # We don't use check() because config.cgi outputs mostly
</ins><span class="cx">         # in XML and JS and we don't want to display an HTML error
</span><span class="cx">         # instead of that.
</span><span class="cx">         my $product = new Bugzilla::Product({ name =&gt; $product_name });
</span><span class="lines">@@ -75,6 +81,18 @@
</span><span class="cx">     $vars-&gt;{'products'} = $user-&gt;get_selectable_products;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# We set the 2nd argument to 1 to also preload flag types.
+Bugzilla::Product::preload($vars-&gt;{'products'}, 1);
+
+# Allow consumers to specify whether or not they want flag data.
+if (defined $cgi-&gt;param('flags')) {
+    $vars-&gt;{'show_flags'} = $cgi-&gt;param('flags');
+}
+else {
+    # We default to sending flag data.
+    $vars-&gt;{'show_flags'} = 1;
+}
+
</ins><span class="cx"> # Create separate lists of open versus resolved statuses.  This should really
</span><span class="cx"> # be made part of the configuration.
</span><span class="cx"> my @open_status;
</span><span class="lines">@@ -89,7 +107,7 @@
</span><span class="cx"> # Generate a list of fields that can be queried.
</span><span class="cx"> my @fields = @{Bugzilla::Field-&gt;match({obsolete =&gt; 0})};
</span><span class="cx"> # Exclude fields the user cannot query.
</span><del>-if (!Bugzilla-&gt;user-&gt;in_group(Bugzilla-&gt;params-&gt;{'timetrackinggroup'})) {
</del><ins>+if (!Bugzilla-&gt;user-&gt;is_timetracker) {
</ins><span class="cx">     @fields = grep { $_-&gt;name !~ /^(estimated_time|remaining_time|work_time|percentage_complete|deadline)$/ } @fields;
</span><span class="cx"> }
</span><span class="cx"> $vars-&gt;{'field'} = \@fields;
</span><span class="lines">@@ -108,11 +126,41 @@
</span><span class="cx">     my $format = $template-&gt;get_format(&quot;config&quot;, scalar($cgi-&gt;param('format')),
</span><span class="cx">                                        scalar($cgi-&gt;param('ctype')) || &quot;js&quot;);
</span><span class="cx"> 
</span><del>-    # Return HTTP headers.
-    print &quot;Content-Type: $format-&gt;{'ctype'}\n\n&quot;;
</del><ins>+    # Generate the configuration data.
+    my $output;
+    $template-&gt;process($format-&gt;{'template'}, $vars, \$output)
+      || ThrowTemplateError($template-&gt;error());
</ins><span class="cx"> 
</span><del>-    # Generate the configuration file and return it to the user.
-    $template-&gt;process($format-&gt;{'template'}, $vars)
-      || ThrowTemplateError($template-&gt;error());
</del><ins>+    # Wide characters cause md5_base64() to die.
+    my $digest_data = $output;
+    utf8::encode($digest_data) if utf8::is_utf8($digest_data);
+    my $digest = md5_base64($digest_data);
+
+    # ETag support.
+    my $if_none_match = $cgi-&gt;http('If-None-Match') || &quot;&quot;;
+    my $found304;
+    my @if_none = split(/[\s,]+/, $if_none_match);
+    foreach my $if_none (@if_none) {
+        # remove quotes from begin and end of the string
+        $if_none =~ s/^\&quot;//g;
+        $if_none =~ s/\&quot;$//g;
+        if ($if_none eq $digest or $if_none eq '*') {
+            # leave the loop after the first match
+            $found304 = $if_none;
+            last;
+        }
+    }

+   if ($found304) {
+        print $cgi-&gt;header(-type =&gt; 'text/html',
+                           -ETag =&gt; $found304,
+                           -status =&gt; '304 Not Modified');
+    }
+    else {
+        # Return HTTP headers.
+        print $cgi-&gt;header (-ETag =&gt; $digest,
+                            -type =&gt; $format-&gt;{'ctype'});
+        print $output;
+    }
</ins><span class="cx">     exit;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgcontribREADME"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/contrib/README (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/contrib/README        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/contrib/README        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -8,19 +8,13 @@
</span><span class="cx"> 
</span><span class="cx"> This directory includes:
</span><span class="cx"> 
</span><del>-bugzilla_ldapsync.rb --  Script that can be run via Cron that queries an LDAP
-                         server for e-mail addresses to add Bugzilla users
-                         for. Will optionally disable Bugzilla users with
-                         no matching LDAP record. Contributed by Thomas
-                         Stromberg &lt;thomas+bugzilla@stromberg.org&gt;.
-
</del><span class="cx">     bugzilla-submit/ --  A standalone bug submission program.
</span><span class="cx"> 
</span><span class="cx">          bzdbcopy.pl --  A script to copy data from an installation running 
</span><span class="cx">                          on one DB platform to an installation running on 
</span><span class="cx">                          another DB platform.
</span><span class="cx"> 
</span><del>-bz_webservice_demo.p --  An example script that demonstrates how to talk to
</del><ins>+bz_webservice_demo.pl --  An example script that demonstrates how to talk to
</ins><span class="cx">                          Bugzilla via XMLRPC.
</span><span class="cx"> 
</span><span class="cx">              cmdline/ -- Various commands for querying your Bugzilla 
</span><span class="lines">@@ -30,13 +24,6 @@
</span><span class="cx">                          from a given directory. The log is useful when
</span><span class="cx">                          changes need to be backed out.
</span><span class="cx"> 
</span><del>-         gnatsparse/ --  A Python script used to import a GNATS database
-                         into Bugzilla.
-
-         gnats2bz.pl --  A Perl script to help import bugs from a GNATS 
-                         database into a Bugzilla database.  Contributed by
-                         Tom Schutter &lt;tom@platte.com&gt;.
-
</del><span class="cx">             jb2bz.py --  Script to import bugs from JitterBug to Bugzilla.
</span><span class="cx"> 
</span><span class="cx">       merge-users.pl --  Script to merge two user accounts. The activities
</span><span class="lines">@@ -68,6 +55,3 @@
</span><span class="cx">                          missing users to Bugzilla. Can disable/update 
</span><span class="cx">                          non-existing/changed information. Contributed by
</span><span class="cx">                          Andreas Höfler &lt;andreas.hoefler@bearingpoint.com&gt;.
</span><del>-
-        yp_nomail.sh --  Script that can be run via Cron that regularly updates
-                         the nomail file for terminated employees. 
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgcontribbugzillaqueuerhel"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/contrib/bugzilla-queue.rhel (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/contrib/bugzilla-queue.rhel                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/contrib/bugzilla-queue.rhel        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,109 @@
</span><ins>+#!/bin/bash
+# 
+# bugzilla-queue This starts, stops, and restarts the Bugzilla jobqueue.pl
+#                 daemon, which manages sending queued mail and possibly
+#                 other queued tasks in the future.
+#
+# chkconfig: 345 85 15
+# description: Bugzilla queue runner
+#
+### BEGIN INIT INFO
+# Provides: bugzilla-queue
+# Required-Start: $local_fs $syslog MTA mysqld
+# Required-Stop: $local_fs $syslog MTA mysqld
+# Default-Start: 3 5
+# Default-Stop: 0 1 2 6
+# Short-Description: Start and stop the Bugzilla queue runner.
+# Description: The Bugzilla queue runner (jobqueue.pl) sends any mail
+#        that Bugzilla has queued to be sent in the background. If you
+#        have enabled the use_mailer_queue parameter in Bugzilla, you
+#        must run this daemon.
+### END INIT INFO
+
+NAME=`basename $0`
+
+#################
+# Configuration #
+#################
+
+# This should be the path to your Bugzilla
+BUGZILLA=/var/www/html/bugzilla
+# Who owns the Bugzilla directory and files?
+USER=root
+
+# If you want to pass any options to the daemon (like -d for debugging)
+# specify it here.
+OPTIONS=&quot;&quot;
+
+# You can also override the configuration by creating a 
+# /etc/sysconfig/bugzilla-queue file so that you don't
+# have to edit this script. 
+if [ -r /etc/sysconfig/$NAME ]; then
+  . /etc/sysconfig/$NAME
+fi
+
+##########
+# Script #
+##########
+
+RETVAL=0
+BIN=$BUGZILLA/jobqueue.pl
+PIDFILE=/var/run/$NAME.pid
+
+# Source function library.
+. /etc/rc.d/init.d/functions
+
+usage ()
+{
+    echo &quot;Usage: service $NAME {start|stop|status|restart|condrestart}&quot;
+    RETVAL=1
+}
+
+
+start ()
+{
+    if [ -f &quot;$PIDFILE&quot; ]; then
+        checkpid `cat $PIDFILE` &amp;&amp; return 0
+    fi
+    echo -n &quot;Starting $NAME: &quot;
+    touch $PIDFILE
+    chown $USER $PIDFILE
+    daemon --user=$USER \
+        &quot;$BIN ${OPTIONS} -p '$PIDFILE' -n $NAME start &gt; /dev/null&quot;
+    ret=$?
+    [ $ret -eq &quot;0&quot; ] &amp;&amp; touch /var/lock/subsys/$NAME
+    echo
+    return $ret
+}
+
+stop ()
+{
+    [ -f /var/lock/subsys/$NAME ] || return 0
+    echo -n &quot;Killing $NAME: &quot;
+    killproc $NAME
+    echo
+    rm -f /var/lock/subsys/$NAME
+}
+
+restart ()
+{
+    stop
+    start
+}
+
+condrestart ()
+{
+    [ -e /var/lock/subsys/$NAME ] &amp;&amp; restart || return 0
+}
+
+
+case &quot;$1&quot; in
+    start) start; RETVAL=$? ;;
+    stop) stop; RETVAL=$? ;;
+    status) $BIN -p $PIDFILE -n $NAME check; RETVAL=$?;;
+    restart) restart; RETVAL=$? ;;
+    condrestart) condrestart; RETVAL=$? ;;
+    *) usage ; RETVAL=2 ;;
+esac
+
+exit $RETVAL
</ins><span class="cx">Property changes on: trunk/Websites/bugs.webkit.org/contrib/bugzilla-queue.rhel
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkWebsitesbugswebkitorgcontribbugzillaqueuesuse"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/contrib/bugzilla-queue.suse (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/contrib/bugzilla-queue.suse                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/contrib/bugzilla-queue.suse        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,174 @@
</span><ins>+#!/bin/bash
+# 
+# bugzilla-queue This starts, stops, and restarts the Bugzilla jobqueue.pl
+#                 daemon, which manages sending queued mail and possibly
+#                 other queued tasks in the future.
+#
+# chkconfig: 345 85 15
+# description: Bugzilla queue runner
+#
+### BEGIN INIT INFO
+# Provides: bugzilla-queue
+# Required-Start: $local_fs $syslog
+# Required-Stop: $local_fs $syslog
+# Default-Start: 3 5
+# Default-Stop: 0 1 2 6
+# Short-Description: Start and stop the Bugzilla queue runner.
+# Description: The Bugzilla queue runner (jobqueue.pl) sends any mail
+#        that Bugzilla has queued to be sent in the background. If you
+#        have enabled the use_mailer_queue parameter in Bugzilla, you
+#        must run this daemon.
+### END INIT INFO
+
+NAME=`basename $0`
+
+#################
+# Configuration #
+#################
+
+# This should be the path to your Bugzilla
+BUGZILLA=/var/www/html/bugzilla
+# Who owns the Bugzilla directory and files?
+USER=root
+
+# If you want to pass any options to the daemon (like -d for debugging)
+# specify it here.
+OPTIONS=&quot;&quot;
+
+# You can also override the configuration by creating a 
+# /etc/sysconfig/bugzilla-queue file so that you don't
+# have to edit this script. 
+if [ -r /etc/sysconfig/$NAME ]; then
+  . /etc/sysconfig/$NAME
+fi
+
+##########
+# Script #
+##########
+
+BIN=$BUGZILLA/jobqueue.pl
+if [ ! -x $BIN ]; then
+    echo &quot;$BIN not installed&quot;
+    if [ &quot;$1&quot; = &quot;stop&quot; ]; then
+        exit 0
+    else
+        exit 5
+    fi
+fi
+
+# Source LSB function library.
+. /lib/lsb/init-functions
+
+# Reset status of this service.
+rc_reset
+
+# Return values for all commands but status:
+# 0       - success
+# 1       - generic or unspecified error
+# 2       - invalid or excess argument(s)
+# 3       - unimplemented feature (e.g. &quot;reload&quot;)
+# 4       - user had insufficient privileges
+# 5       - program is not installed
+# 6       - program is not configured
+# 7       - program is not running
+# 8--199  - reserved (8--99 LSB, 100--149 distrib, 150--199 appl)
+#
+# Note that starting an already running service, stopping
+# or restarting a not-running service as well as the restart
+# with force-reload (in case signaling is not supported) are
+# considered a success.
+
+case &quot;$1&quot; in
+    start)
+        echo -n &quot;Starting $NAME &quot;
+        # Start daemon with startproc(8).  If this fails the return value
+        # is set appropriately by startproc.
+        start_daemon -u $USER $BIN ${OPTIONS} start
+
+        # Remember status and be verbose
+        rc_status -v
+        ;;
+
+    stop)
+        echo -n &quot;Shutting down $NAME &quot;
+        # Stop daemon with killproc(8) and if this fails killproc sets the
+        # return value according to LSB.
+        killproc -TERM $BIN
+
+        # Remember status and be verbose
+        rc_status -v
+        ;;
+
+    status)
+        echo -n &quot;Checking for service $NAME &quot;
+        # Check status with checkproc(8), if process is running checkproc
+        # will return with exit status 0.
+
+        # Return value is slightly different for the status command:
+        # 0 - service up and running
+        # 1 - service dead, but /var/run/  pid  file exists
+        # 2 - service dead, but /var/lock/ lock file exists
+        # 3 - service not running (unused)
+        # 4 - service status unknown :-(
+        # 5--199 reserved (5--99 LSB, 100--149 distro, 150--199 appl.)
+
+        # NOTE: checkproc returns LSB compliant status values.
+        checkproc $BIN
+
+        # NOTE: rc_status knows that we called this init script with
+        # &quot;status&quot; option and adapts its messages accordingly.
+        rc_status -v
+
+        # Run jobqueue's own check function too.
+        $BIN check
+        ;;
+
+    restart)
+        # Stop the service and regardless of whether it was running or not,
+        # start it again.
+        $0 stop
+        $0 start
+
+        # Remember status and be quiet.
+        rc_status
+        ;;
+
+    try-restart|condrestart)
+        # Do a restart only if the service was active before.
+        # NOTE: try-restart is now part of LSB (as of 1.9). RH has a
+        # similar command named condrestart.
+        if [ &quot;$1&quot; = &quot;condrestart&quot; ]; then
+            echo &quot;${attn} Use try-restart ${done}(LSB)${attn} rather than condrestart ${warn}(RH)${norm}&quot;
+        fi
+        $0 status
+        if [ $? -eq 0 ]; then
+            $0 restart
+        else
+            rc_reset        # Not running is not a failure.
+        fi
+
+        # Remember status and be quiet
+        rc_status
+        ;;
+
+    force-reload)
+        # The jobqueue.pl daemon does not support SIGHUP for reload.  Just
+        # restart the service if it is running.
+        echo -n &quot;Reload service $NAME &quot;
+
+        $0 try-restart
+        rc_status
+        ;;
+
+    reload)
+        # The jobqueue.pl daemon does not support SIGHUP for reload.
+        rc_failed 3
+        rc_status -v
+        ;;
+
+    *)
+        echo &quot;Usage: $0 {start|stop|status|try-restart|restart|force-reload|reload}&quot;
+        exit 1
+esac
+
+rc_exit
</ins><span class="cx">Property changes on: trunk/Websites/bugs.webkit.org/contrib/bugzilla-queue.suse
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkWebsitesbugswebkitorgcontribbugzillasubmitbugdatatxt"></a>
<div class="propset"><h4>Property changes: trunk/Websites/bugs.webkit.org/contrib/bugzilla-submit/bugdata.txt</h4>
<pre class="diff"><span>
</span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkWebsitesbugswebkitorgcontribbugzillasubmitbugzillasubmit"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/contrib/bugzilla-submit/bugzilla-submit (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/contrib/bugzilla-submit/bugzilla-submit        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/contrib/bugzilla-submit/bugzilla-submit        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -152,13 +152,13 @@
</span><span class="cx">     if 'rep_platform' not in data:
</span><span class="cx">         data['rep_platform'] = 'PC'
</span><span class="cx">     if 'bug_status' not in data:
</span><del>-        data['bug_status'] = 'NEW'
</del><ins>+        data['bug_status'] = 'CONFIRMED'
</ins><span class="cx">     if 'bug_severity' not in data:
</span><span class="cx">         data['bug_severity'] = 'normal'
</span><span class="cx">     if 'bug_file_loc' not in data:
</span><span class="cx">         data['bug_file_loc'] = 'http://'        # Yes, Bugzilla needs this
</span><span class="cx">     if 'priority' not in data:
</span><del>-        data['priority'] = 'P2'
</del><ins>+        data['priority'] = 'Normal'
</ins><span class="cx"> 
</span><span class="cx"> def validate_fields(data):
</span><span class="cx">     # Fields for validation
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgcontribbugzillasubmitbugzillasubmitxml"></a>
<div class="propset"><h4>Property changes: trunk/Websites/bugs.webkit.org/contrib/bugzilla-submit/bugzilla-submit.xml</h4>
<pre class="diff"><span>
</span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkWebsitesbugswebkitorgcontribbugzilla_ldapsyncrb"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/contrib/bugzilla_ldapsync.rb (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/contrib/bugzilla_ldapsync.rb        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/contrib/bugzilla_ldapsync.rb        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,185 +0,0 @@
</span><del>-#!/usr/local/bin/ruby
-
-# Queries an LDAP server for all email addresses (tested against Exchange 5.5),
-# and makes nice bugzilla user entries out of them. Also disables Bugzilla users
-# that are not found in LDAP.
-
-# $Id$
-
-require 'ldap'
-require 'dbi'
-require 'getoptlong'
-
-opts = GetoptLong.new(
-    ['--dbname',        '-d', GetoptLong::OPTIONAL_ARGUMENT],
-    ['--dbpassword',    '-p', GetoptLong::OPTIONAL_ARGUMENT],
-    ['--dbuser',        '-u',     GetoptLong::OPTIONAL_ARGUMENT],
-    ['--dbpassfile',    '-P', GetoptLong::OPTIONAL_ARGUMENT],
-    ['--ldaphost',      '-h', GetoptLong::REQUIRED_ARGUMENT],
-    ['--ldapbase',      '-b', GetoptLong::OPTIONAL_ARGUMENT],
-    ['--ldapquery',     '-q', GetoptLong::OPTIONAL_ARGUMENT],
-    ['--maildomain',    '-m', GetoptLong::OPTIONAL_ARGUMENT],
-    ['--noremove',      '-n', GetoptLong::OPTIONAL_ARGUMENT],
-    ['--defaultpass',   '-D', GetoptLong::OPTIONAL_ARGUMENT],
-    ['--checkmode',     '-c', GetoptLong::OPTIONAL_ARGUMENT]
-)
-
-
-# in hash to make it easy
-optHash = Hash.new
-opts.each do |opt, arg|
-        optHash[opt]=arg
-end    
-
-# grab password from file if it's an option
-if optHash['--dbpassfile']
-    dbPassword=File.open(optHash['--dbpassfile'], 'r').readlines[0].chomp!
-else
-    dbPassword=optHash['--dbpassword'] || nil
-end
-
-# make bad assumptions.
-dbName = optHash['--dbname'] || 'bugzilla'
-dbUser = optHash['--dbuser'] || 'bugzilla'
-ldapHost = optHash['--ldaphost'] || 'ldap'
-ldapBase = optHash['--ldapbase'] || ''
-mailDomain = optHash['--maildomain'] || `domainname`.chomp!
-ldapQuery = optHash['--ldapquery'] || &quot;(&amp;(objectclass=person)(rfc822Mailbox=*@#{mailDomain}))&quot;
-checkMode = optHash['--checkmode'] || nil
-noRemove = optHash['--noremove'] || nil
-defaultPass = optHash['--defaultpass'] || 'bugzilla'
-
-if (! dbPassword)
-    puts &quot;bugzilla_ldapsync v1.3 (c) 2003 Thomas Stromberg &lt;thomas+bugzilla@stromberg.org&gt;&quot;
-    puts &quot;&quot;
-    puts &quot; -d | --dbname        name of MySQL database            [#{dbName}]&quot;
-    puts &quot; -u | --dbuser        username for MySQL database       [#{dbUser}]&quot;
-    puts &quot; -p | --dbpassword    password for MySQL user           [#{dbPassword}]&quot;
-    puts &quot; -P | --dbpassfile    filename containing password for MySQL user&quot;
-    puts &quot; -h | --ldaphost      hostname for LDAP server          [#{ldapHost}]&quot;
-    puts &quot; -b | --ldapbase      Base of LDAP query, for instance, o=Bugzilla.com&quot;
-    puts &quot; -q | --ldapquery     LDAP query, uses maildomain       [#{ldapQuery}]&quot;
-    puts &quot; -m | --maildomain    e-mail domain to use records from&quot;
-    puts &quot; -n | --noremove      do not remove Bugzilla users that are not in LDAP&quot;
-    puts &quot; -c | --checkmode     checkmode, does not perform any SQL changes&quot;
-    puts &quot; -D | --defaultpass   default password for new users    [#{defaultPass}]&quot;
-    puts
-    puts &quot;example:&quot;
-    puts
-    puts &quot; bugzilla_ldapsync.rb -c -u taskzilla -P /tmp/test -d taskzilla -h bhncmail -m \&quot;bowebellhowell.com\&quot;&quot;
-    exit
-end
-
-
-if (checkMode)
-    puts '(checkmode enabled, no SQL writes will actually happen)'
-    puts &quot;ldapquery is #{ldapQuery}&quot;
-    puts
-end
-    
-
-bugzillaUsers = Hash.new
-ldapUsers = Hash.new
-encPassword = defaultPass.crypt('xx')
-sqlNewUser = &quot;INSERT INTO profiles VALUES ('', ?, '#{encPassword}', ?, '', 1, NULL, '0000-00-00 00:00:00');&quot;
-
-# presumes that the MySQL database is local.
-dbh = DBI.connect(&quot;DBI:Mysql:#{dbName}&quot;, dbUser, dbPassword)
-
-# select all e-mail addresses where there is no disabledtext defined. Only valid users, please!
-dbh.select_all('select login_name, realname, disabledtext from profiles') { |row|
-    login = row[0].downcase
-    bugzillaUsers[login] = Hash.new
-    bugzillaUsers[login]['desc'] = row[1]
-    bugzillaUsers[login]['disabled'] = row[2]
-    #puts &quot;bugzilla has #{login} - \&quot;#{bugzillaUsers[login]['desc']}\&quot; (#{bugzillaUsers[login]['disabled']})&quot;
-}
-
-
-LDAP::Conn.new(ldapHost, 389).bind{|conn|
-  sub = nil
-  # perform the query, but only get the e-mail address, location, and name returned to us.
-  conn.search(ldapBase, LDAP::LDAP_SCOPE_SUBTREE, ldapQuery,  
-          ['rfc822Mailbox', 'physicalDeliveryOfficeName', 'cn'])  { |entry|
-        
-                # Get the users first (primary) e-mail address, but I only want what's before the @ sign.
-                entry.vals(&quot;rfc822Mailbox&quot;)[0] =~ /([\w\.-]+)\@/
-                email = $1
-        
-                # We put the officename in the users description, and nothing otherwise.
-                if entry.vals(&quot;physicalDeliveryOfficeName&quot;)
-                        location = entry.vals(&quot;physicalDeliveryOfficeName&quot;)[0]
-                else
-                        location = ''
-                end
-        
-                # for whatever reason, we get blank entries. Do some double checking here.
-                if (email &amp;&amp; (email.length &gt; 4) &amp;&amp; (location !~ /Generic/) &amp;&amp; (entry.vals(&quot;cn&quot;)))                
-                        if (location.length &gt; 2) 
-                                desc = entry.vals(&quot;cn&quot;)[0] + &quot; (&quot; + location + &quot;)&quot;
-                        else
-                                desc = entry.vals(&quot;cn&quot;)[0]
-                        end
-            
-            # take care of the whitespace.
-            desc.sub!(&quot;\s+$&quot;, &quot;&quot;)
-            desc.sub!(&quot;^\s+&quot;, &quot;&quot;)
-            
-            # dumb hack. should be properly escaped, and apostrophes should never ever ever be in email.
-                        email.sub!(&quot;\'&quot;, &quot;%&quot;)
-                        email.sub!('%', &quot;\'&quot;)
-            email=email.downcase
-            ldapUsers[email.downcase] = Hash.new
-            ldapUsers[email.downcase]['desc'] = desc
-            ldapUsers[email.downcase]['disabled'] = nil
-            #puts &quot;ldap has #{email} - #{ldapUsers[email.downcase]['desc']}&quot;
-        end
-        }
-}
-
-# This is the loop that takes the users that we found in Bugzilla originally, and 
-# checks to see if they are still in the LDAP server. If they are not, away they go!
-
-ldapUsers.each_key { |user|
-    # user does not exist at all.
-    #puts &quot;checking ldap user #{user}&quot;
-    if (! bugzillaUsers[user])
-        puts &quot;+ Adding #{user} - #{ldapUsers[user]['desc']}&quot;
-
-        if (! checkMode) 
-            dbh.do(sqlNewUser, user, ldapUsers[user]['desc'])
-        end
-        
-        # short-circuit now.
-        next
-     end
-
-     if (bugzillaUsers[user]['desc'] != ldapUsers[user]['desc'])
-     puts &quot;* Changing #{user} from \&quot;#{bugzillaUsers[user]['desc']}\&quot; to \&quot;#{ldapUsers[user]['desc']}\&quot;&quot;
-         if (! checkMode)
-            # not efficient.
-            dbh.do(&quot;UPDATE profiles SET realname = ? WHERE login_name = ?&quot;, ldapUsers[user]['desc'], user)
-         end
-     end
-
-     if (bugzillaUsers[user]['disabled'].length &gt; 0)
-         puts &quot;+ Enabling #{user} (was \&quot;#{bugzillaUsers[user]['disabled']}\&quot;)&quot; 
-         if (! checkMode)
-             dbh.do(&quot;UPDATE profiles SET disabledtext = NULL WHERE login_name=\&quot;#{user}\&quot;&quot;)
-         end
-     end
-}
-
-if (! noRemove)
-    bugzillaUsers.each_key { |user|
-        if ((bugzillaUsers[user]['disabled'].length &lt; 1) &amp;&amp; (! ldapUsers[user]))
-            puts &quot;- Disabling #{user} (#{bugzillaUsers[user]['disabled']})&quot;
-
-            if (! checkMode)
-                 dbh.do(&quot;UPDATE profiles SET disabledtext = \'auto-disabled by ldap sync\' WHERE login_name=\&quot;#{user}\&quot;&quot;)
-            end
-        end
-    }
-end
-dbh.disconnect
-
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgcontribbz_webservice_demopl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/contrib/bz_webservice_demo.pl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/contrib/bz_webservice_demo.pl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/contrib/bz_webservice_demo.pl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -210,7 +210,7 @@
</span><span class="cx">     _die_on_fault($soapresult);
</span><span class="cx">     my $extensions = $soapresult-&gt;result()-&gt;{extensions};
</span><span class="cx">     foreach my $extensionname (keys(%$extensions)) {
</span><del>-        print &quot;Extensionn '$extensionname' information\n&quot;;
</del><ins>+        print &quot;Extension '$extensionname' information\n&quot;;
</ins><span class="cx">         my $extension = $extensions-&gt;{$extensionname};
</span><span class="cx">         foreach my $data (keys(%$extension)) {
</span><span class="cx">             print '  ' . $data . ' =&gt; ' . $extension-&gt;{$data} . &quot;\n&quot;;
</span><span class="lines">@@ -390,7 +390,7 @@
</span><span class="cx">         version     =&gt; &quot;unspecified&quot;,
</span><span class="cx">         description =&gt; &quot;This is a description of the bug... hohoho&quot;,
</span><span class="cx">         op_sys      =&gt; &quot;All&quot;,
</span><del>-        platform    =&gt; &quot;All&quot;,        
</del><ins>+        platform    =&gt; &quot;All&quot;,
</ins><span class="cx">         priority    =&gt; &quot;P4&quot;,
</span><span class="cx">         severity    =&gt; &quot;normal&quot;
</span><span class="cx">     };
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgcontribbzdbcopypl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/contrib/bzdbcopy.pl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/contrib/bzdbcopy.pl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/contrib/bzdbcopy.pl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -48,15 +48,18 @@
</span><span class="cx"> # MAIN SCRIPT
</span><span class="cx"> #####################################################################
</span><span class="cx"> 
</span><del>-Bugzilla-&gt;usage_mode(USAGE_MODE_CMDLINE);
-
</del><span class="cx"> print &quot;Connecting to the '&quot; . SOURCE_DB_NAME . &quot;' source database on &quot; 
</span><span class="cx">       . SOURCE_DB_TYPE . &quot;...\n&quot;;
</span><del>-my $source_db = Bugzilla::DB::_connect(SOURCE_DB_TYPE, SOURCE_DB_HOST, 
-    SOURCE_DB_NAME, undef, undef, SOURCE_DB_USER, SOURCE_DB_PASSWORD);
</del><ins>+my $source_db = Bugzilla::DB::_connect({
+    db_driver =&gt; SOURCE_DB_TYPE, 
+    db_host   =&gt; SOURCE_DB_HOST, 
+    db_name   =&gt; SOURCE_DB_NAME, 
+    db_user   =&gt; SOURCE_DB_USER, 
+    db_pass   =&gt; SOURCE_DB_PASSWORD,
+});
</ins><span class="cx"> # Don't read entire tables into memory.
</span><span class="cx"> if (SOURCE_DB_TYPE eq 'Mysql') {
</span><del>-    $source_db-&gt;{'mysql_use_result'}=1;
</del><ins>+    $source_db-&gt;{'mysql_use_result'} = 1;
</ins><span class="cx"> 
</span><span class="cx">     # MySQL cannot have two queries running at the same time. Ensure the schema
</span><span class="cx">     # is loaded from the database so bz_column_info will not execute a query
</span><span class="lines">@@ -65,20 +68,23 @@
</span><span class="cx"> 
</span><span class="cx"> print &quot;Connecting to the '&quot; . TARGET_DB_NAME . &quot;' target database on &quot;
</span><span class="cx">       . TARGET_DB_TYPE . &quot;...\n&quot;;
</span><del>-my $target_db = Bugzilla::DB::_connect(TARGET_DB_TYPE, TARGET_DB_HOST, 
-    TARGET_DB_NAME, undef, undef, TARGET_DB_USER, TARGET_DB_PASSWORD);
</del><ins>+my $target_db = Bugzilla::DB::_connect({
+    db_driver =&gt; TARGET_DB_TYPE,
+    db_host   =&gt; TARGET_DB_HOST, 
+    db_name   =&gt; TARGET_DB_NAME, 
+    db_user   =&gt; TARGET_DB_USER,
+    db_pass   =&gt; TARGET_DB_PASSWORD,
+});
</ins><span class="cx"> my $ident_char = $target_db-&gt;get_info( 29 ); # SQL_IDENTIFIER_QUOTE_CHAR
</span><span class="cx"> 
</span><span class="cx"> # We use the table list from the target DB, because if somebody
</span><span class="cx"> # has customized their source DB, we still want the script to work,
</span><span class="cx"> # and it may otherwise fail in that situation (that is, the tables
</span><span class="cx"> # may not exist in the target DB).
</span><del>-my @table_list = $target_db-&gt;bz_table_list_real();
</del><ins>+#
+# We don't want to copy over the bz_schema table's contents, though.
+my @table_list = grep { $_ ne 'bz_schema' } $target_db-&gt;bz_table_list_real();
</ins><span class="cx"> 
</span><del>-# We don't want to copy over the bz_schema table's contents.
-my $bz_schema_location = lsearch(\@table_list, 'bz_schema');
-splice(@table_list, $bz_schema_location, 1) if $bz_schema_location &gt; 0;
-
</del><span class="cx"> # Instead of figuring out some fancy algorithm to insert data in the right
</span><span class="cx"> # order and not break FK integrity, we just drop them all.
</span><span class="cx"> $target_db-&gt;bz_drop_foreign_keys();
</span><span class="lines">@@ -195,8 +201,7 @@
</span><span class="cx">                 # PostgreSQL doesn't like it when you insert values into
</span><span class="cx">                 # a serial field; it doesn't increment the counter 
</span><span class="cx">                 # automatically.
</span><del>-                $target_db-&gt;do(&quot;SELECT pg_catalog.setval 
-                                ('${table}_${column}_seq', $max_val, false)&quot;);
</del><ins>+                $target_db-&gt;bz_set_next_serial_value($table, $column);
</ins><span class="cx">             }
</span><span class="cx">             elsif ($target_db-&gt;isa('Bugzilla::DB::Oracle')) {
</span><span class="cx">                 # Oracle increments the counter on every insert, and *always*
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgcontribcmdlinequeryconf"></a>
<div class="propset"><h4>Property changes: trunk/Websites/bugs.webkit.org/contrib/cmdline/query.conf</h4>
<pre class="diff"><span>
</span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkWebsitesbugswebkitorgcontribconsolepl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/contrib/console.pl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/contrib/console.pl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/contrib/console.pl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,186 @@
</span><ins>+#!/usr/bin/env perl -w
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the &quot;License&quot;); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS IS&quot; basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is the National Aeronautics
+# and Space Administration of the United States Government.
+# Portions created by the Initial Developer are Copyright (C) 2010
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s): Jesse Clark &lt;jjclark1982@gmail.com&gt;
+
+use File::Basename;
+BEGIN { chdir dirname($0) . &quot;/..&quot;; }
+use lib qw(. lib);
+
+use Bugzilla;
+use Bugzilla::Constants;
+use Bugzilla::Util;
+use Bugzilla::Bug;
+
+use Term::ReadLine;
+use Data::Dumper;
+$Data::Dumper::Sortkeys = 1;
+$Data::Dumper::Terse = 1;
+$Data::Dumper::Indent = 1;
+$Data::Dumper::Useqq = 1;
+$Data::Dumper::Maxdepth = 1;
+$Data::Dumper::Deparse = 0;
+
+my $sysname = get_text('term', {term =&gt; 'Bugzilla'});
+my $term = new Term::ReadLine &quot;$sysname Console&quot;;
+read_history($term);
+END { write_history($term) }
+
+while ( defined (my $input = $term-&gt;readline(&quot;$sysname&gt; &quot;)) ) {
+    my @res = eval($input);
+    if ($@) {
+        warn $@;
+    }
+    else {
+        print Dumper(@res);
+    }
+}
+print STDERR &quot;\n&quot;;
+exit 0;
+
+# d: full dump (normal behavior is limited to depth of 1)
+sub d {
+    local $Data::Dumper::Maxdepth = 0;
+    local $Data::Dumper::Deparse = 1;
+    print Dumper(@_);
+    return ();
+}
+
+# p: print as a single string (normal behavior puts list items on separate lines)
+sub p {
+    local $^W=0; # suppress possible undefined var message 
+    print(@_, &quot;\n&quot;);
+    return ();
+}
+
+sub filter {
+    my $name = shift;
+    my $filter = Bugzilla-&gt;template-&gt;{SERVICE}-&gt;{CONTEXT}-&gt;{CONFIG}-&gt;{FILTERS}-&gt;{$name};
+    if (scalar @_) {
+        return $filter-&gt;(@_);
+    }
+    else {
+        return $filter;
+    }
+}
+
+sub b { get_object('Bugzilla::Bug', @_) }
+sub u { get_object('Bugzilla::User', @_) }
+sub f { get_object('Bugzilla::Field', @_) }
+
+sub get_object {
+    my $class = shift;
+    $_ = shift;
+    my @results = ();
+    
+    if (ref $_ eq 'HASH' &amp;&amp; keys %$_) {
+        @results = @{$class-&gt;match($_)};
+    }
+    elsif (m/^\d+$/) {
+        @results = ($class-&gt;new($_));
+    }
+    elsif (m/\w/i &amp;&amp; grep {$_ eq 'name'} ($class-&gt;_get_db_columns)) {
+        @results = @{$class-&gt;match({name =&gt; $_})};
+    }
+    else {
+        @results = ();
+    }
+    
+    if (wantarray) {
+        return @results;
+    }
+    else {
+        return shift @results;
+    }
+}
+
+sub read_history {
+    my ($term) = @_;
+    
+    if (open HIST, &quot;&lt;$ENV{HOME}/.bugzilla_console_history&quot;) {
+        foreach (&lt;HIST&gt;) {
+            chomp;
+            $term-&gt;addhistory($_);
+        }
+        close HIST;
+    }
+}
+
+sub write_history {
+    my ($term) = @_;
+
+    if ($term-&gt;can('GetHistory') &amp;&amp; open HIST, &quot;&gt;$ENV{HOME}/.bugzilla_console_history&quot;) {
+        my %seen_hist = ();
+        my @hist = ();
+        foreach my $line (reverse $term-&gt;GetHistory()) {
+            next unless $line =~ m/\S/;
+            next if $seen_hist{$line};
+            $seen_hist{$line} = 1;
+            push @hist, $line;
+            last if (scalar @hist &gt; 500);
+        }
+        foreach (reverse @hist) {
+            print HIST $_, &quot;\n&quot;;
+        }
+        close HIST;
+    }
+}
+
+__END__
+
+=head1 NAME
+
+B&lt;console.pl&gt; - command-line interface to Bugzilla API
+
+=head1 SYNOPSIS
+
+$ B&lt;contrib/console.pl&gt;
+
+Bugzilla&gt; B&lt;b(5)-E&lt;gt&gt;short_desc&gt;
+
+=over 8
+
+&quot;Misplaced Widget&quot;
+
+=back
+
+Bugzilla&gt; B&lt;$f = f &quot;cf_subsystem&quot;; scalar @{$f-E&lt;gt&gt;legal_values}&gt;
+
+=over 8
+
+177
+
+=back
+
+Bugzilla&gt; B&lt;p filter html_light, &quot;1 E&lt;lt&gt; 2 E&lt;lt&gt;bE&lt;gt&gt;3E&lt;lt&gt;/bE&lt;gt&gt;&quot;&gt;
+
+=over 8
+
+1 &amp;lt; 2 E&lt;lt&gt;bE&lt;gt&gt;3E&lt;lt&gt;/bE&lt;gt&gt;
+
+=back
+
+Bugzilla&gt; B&lt;$u = u 5; $u-E&lt;gt&gt;groups; d $u&gt;
+
+=head1 DESCRIPTION
+
+Loads Bugzilla packages and prints expressions with Data::Dumper.
+Useful for checking results of Bugzilla API calls without opening
+a debug file from a cgi.
</ins><span class="cx">Property changes on: trunk/Websites/bugs.webkit.org/contrib/console.pl
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkWebsitesbugswebkitorgcontribconvertworkflowpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/contrib/convert-workflow.pl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/contrib/convert-workflow.pl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/contrib/convert-workflow.pl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,135 @@
</span><ins>+#!/usr/bin/env perl -w
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Everything Solved, Inc.
+# Portions created by the Initial Developer are Copyright (C) 2009 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+use strict;
+use warnings;
+use lib qw(. lib);
+
+use Bugzilla;
+use Bugzilla::Config qw(:admin);
+use Bugzilla::Search::Saved;
+use Bugzilla::Status;
+use Getopt::Long;
+
+my $confirmed   = new Bugzilla::Status({ name =&gt; 'CONFIRMED' });
+my $in_progress = new Bugzilla::Status({ name =&gt; 'IN_PROGRESS' });
+
+if ($confirmed and $in_progress) {
+    print &quot;You are already using the new workflow.\n&quot;;
+    exit 1;
+}
+my $enable_unconfirmed  = 0;
+my $result = GetOptions(&quot;enable-unconfirmed&quot; =&gt; \$enable_unconfirmed);
+
+print &lt;&lt;END;
+WARNING: This will convert the status of all bugs using the following
+system:
+
+  &quot;NEW&quot; will become &quot;CONFIRMED&quot;
+  &quot;ASSIGNED&quot; will become &quot;IN_PROGRESS&quot;
+  &quot;REOPENED&quot; will become &quot;CONFIRMED&quot; (and the &quot;REOPENED&quot; status will be removed)
+  &quot;CLOSED&quot; will become &quot;VERIFIED&quot; (and the &quot;CLOSED&quot; status will be removed)
+
+This change will be immediate. The history of each bug will also be changed
+so that it appears that these statuses were always in existence.
+
+Emails will not be sent for the change.
+
+END
+if ($enable_unconfirmed) {
+    print &quot;UNCONFIRMED will be enabled in all products.\n&quot;;
+} else {
+    print &lt;&lt;END;
+If you also want to enable the UNCONFIRMED status in every product,
+restart this script with the --enable-unconfirmed option.
+END
+}
+print &quot;\nTo continue, press any key, or press Ctrl-C to stop this program...&quot;;
+getc;
+
+my $dbh = Bugzilla-&gt;dbh;
+# This is an array instead of a hash so that we can be sure that
+# the translation happens in the right order. In particular, we
+# want NEW to be renamed to CONFIRMED, instead of having REOPENED
+# be the one that gets renamed.
+my @translation = (
+    [NEW      =&gt; 'CONFIRMED'],
+    [ASSIGNED =&gt; 'IN_PROGRESS'],
+    [REOPENED =&gt; 'CONFIRMED'],
+    [CLOSED   =&gt; 'VERIFIED'],
+);
+
+my $status_field = Bugzilla::Field-&gt;check('bug_status');
+$dbh-&gt;bz_start_transaction();
+foreach my $pair (@translation) {
+    my ($from, $to) = @$pair;
+    print &quot;Converting $from to $to...\n&quot;;
+    $dbh-&gt;do('UPDATE bugs SET bug_status = ? WHERE bug_status = ?',
+             undef, $to, $from);
+
+    if (Bugzilla-&gt;params-&gt;{'duplicate_or_move_bug_status'} eq $from) {
+        SetParam('duplicate_or_move_bug_status', $to);
+        write_params();
+    }
+
+    foreach my $what (qw(added removed)) {
+        $dbh-&gt;do(&quot;UPDATE bugs_activity SET $what = ?
+                   WHERE fieldid = ? AND $what = ?&quot;,
+                 undef, $to, $status_field-&gt;id, $from);
+    }
+
+    # Delete any transitions where it now appears that
+    # a bug moved from a status to itself.
+    $dbh-&gt;do('DELETE FROM bugs_activity WHERE fieldid = ? AND added = removed',
+             undef, $status_field-&gt;id);
+
+    # If the new status already exists, just delete the old one, but retain
+    # the workflow items from it.
+    if (my $existing = new Bugzilla::Status({ name =&gt; $to })) {
+        $dbh-&gt;do('DELETE FROM bug_status WHERE value = ?', undef, $from);
+    }
+    # Otherwise, rename the old status to the new one.
+    else {
+        $dbh-&gt;do('UPDATE bug_status SET value = ? WHERE value = ?',
+                 undef, $to, $from);
+    }
+
+    Bugzilla::Search::Saved-&gt;rename_field_value('bug_status', $from, $to);
+    Bugzilla::Series-&gt;Bugzilla::Search::Saved::rename_field_value('bug_status',
+        $from, $to);
+}
+if ($enable_unconfirmed) {
+    print &quot;Enabling UNCONFIRMED in all products...\n&quot;;
+    $dbh-&gt;do('UPDATE products SET allows_unconfirmed = 1');
+}
+$dbh-&gt;bz_commit_transaction();
+
+print &lt;&lt;END;
+Done. There are some things you may want to fix, now:
+
+  * You may want to run ./collectstats.pl --regenerate to regenerate
+    data for the Old Charts system. 
+  * You may have to fix the Status Workflow using the Status Workflow
+    panel in &quot;Administration&quot;.
+  * You will probably want to update the &quot;mybugstemplate&quot; and &quot;defaultquery&quot;
+    parameters using the Parameters panel in &quot;Administration&quot;. (Just
+    resetting them to the default will work.)
+END
</ins><span class="cx">Property changes on: trunk/Websites/bugs.webkit.org/contrib/convert-workflow.pl
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkWebsitesbugswebkitorgcontribcvsupdatepl"></a>
<div class="propset"><h4>Property changes: trunk/Websites/bugs.webkit.org/contrib/cvs-update.pl</h4>
<pre class="diff"><span>
</span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkWebsitesbugswebkitorgcontribextensionconvertpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/contrib/extension-convert.pl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/contrib/extension-convert.pl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/contrib/extension-convert.pl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,303 @@
</span><ins>+#!/usr/bin/env perl -w
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Everything Solved, Inc.
+# Portions created by the Initial Developer are Copyright (C) 2009 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+use strict;
+use warnings;
+use lib qw(. lib);
+
+use Bugzilla;
+use Bugzilla::Constants;
+use Bugzilla::Util qw(trim);
+
+use File::Basename;
+use File::Copy qw(move);
+use File::Find;
+use File::Path qw(mkpath rmtree);
+
+my $from = $ARGV[0]
+  or die &lt;&lt;END;
+You must specify the name of the extension you are converting from,
+as the first argument.
+END
+my $extension_name = ucfirst($from);
+
+my $extdir = bz_locations()-&gt;{'extensionsdir'};
+
+my $from_dir = &quot;$extdir/$from&quot;;
+if (!-d $from_dir) {
+    die &quot;$from_dir does not exist.\n&quot;;
+}
+
+my $to_dir = &quot;$extdir/$extension_name&quot;;
+if (-d $to_dir) {
+    die &quot;$to_dir already exists, not converting.\n&quot;;
+}
+
+if (ON_WINDOWS) {
+    # There's no easy way to recursively copy a directory on Windows.
+    print &quot;WARNING: This will modify the contents of $from_dir.\n&quot;,
+          &quot;Press Ctrl-C to stop or any other key to continue...\n&quot;;
+    getc;
+    move($from_dir, $to_dir) 
+        || die &quot;rename of $from_dir to $to_dir failed: $!&quot;;
+}
+else {
+    print &quot;Copying $from_dir to $to_dir...\n&quot;;
+    system(&quot;cp&quot;, &quot;-r&quot;, $from_dir, $to_dir);
+}
+
+# Make sure we don't accidentally modify the $from_dir anywhere else 
+# in this script.
+undef $from_dir;
+
+if (!-d $to_dir) {
+    die &quot;$to_dir was not created.\n&quot;;
+}
+
+my $version = get_version($to_dir);
+move_template_hooks($to_dir);
+rename_module_packages($to_dir, $extension_name);
+my $install_requirements = get_install_requirements($to_dir);
+my ($modules, $subs) = code_files_to_subroutines($to_dir);
+
+my $config_pm = &lt;&lt;END;
+package Bugzilla::Extension::$extension_name;
+use strict;
+use constant NAME =&gt; '$extension_name';
+$install_requirements
+__PACKAGE__-&gt;NAME;
+END
+
+my $extension_pm = &lt;&lt;END;
+package Bugzilla::Extension::$extension_name;
+use strict;
+use base qw(Bugzilla::Extension);
+
+$modules
+
+our \$VERSION = '$version';
+
+$subs
+
+__PACKAGE__-&gt;NAME;
+END
+
+open(my $config_fh, '&gt;', &quot;$to_dir/Config.pm&quot;) || die &quot;$to_dir/Config.pm: $!&quot;;
+print $config_fh $config_pm;
+close($config_fh);
+open(my $extension_fh, '&gt;', &quot;$to_dir/Extension.pm&quot;) 
+  || die &quot;$to_dir/Extension.pm: $!&quot;;
+print $extension_fh $extension_pm;
+close($extension_fh);
+
+rmtree(&quot;$to_dir/code&quot;);
+unlink(&quot;$to_dir/info.pl&quot;);
+
+###############
+# Subroutines #
+###############
+
+sub rename_module_packages {
+    my ($dir, $name) = @_;
+    my $lib_dir = &quot;$dir/lib&quot;;
+
+    # We don't want things like Bugzilla::Extension::Testopia::Testopia.
+    if (-d &quot;$lib_dir/$name&quot;) {
+        print &quot;Moving contents of $lib_dir/$name into $lib_dir...\n&quot;;
+        foreach my $file (glob(&quot;$lib_dir/$name/*&quot;)) {
+            my $dirname = dirname($file);
+            my $basename = basename($file);
+            rename($file, &quot;$dirname/../$basename&quot;) || warn &quot;$file: $!\n&quot;;
+        }
+    }
+
+    my @modules;
+    find({ wanted   =&gt; sub { $_ =~ /\.pm$/i and push(@modules, $_) }, 
+           no_chdir =&gt; 1 }, $lib_dir);
+    my %module_rename;
+    foreach my $file (@modules) {
+        open(my $fh, '&lt;', $file) || die &quot;$file: $!&quot;;
+        my $content = do { local $/ = undef; &lt;$fh&gt; };
+        close($fh);
+        if ($content =~ /^package (\S+);/m) {
+            my $package = $1;
+            my $new_name = $file;
+            $new_name =~ s/^$lib_dir\///;
+            $new_name =~ s/\.pm$//;
+            $new_name = join('::', File::Spec-&gt;splitdir($new_name));
+            $new_name = &quot;Bugzilla::Extension::${name}::$new_name&quot;;
+            print &quot;Renaming $package to $new_name...\n&quot;;
+            $content =~ s/^package \Q$package\E;/package \Q$new_name\E;/;
+            open(my $write_fh, '&gt;', $file) || die &quot;$file: $!&quot;;
+            print $write_fh $content;
+            close($write_fh);
+            $module_rename{$package} = $new_name;
+        }
+    }
+
+    print &quot;Renaming module names inside of library and code files...\n&quot;;
+    my @code_files = glob(&quot;$dir/code/*.pl&quot;);
+    rename_modules_internally(\%module_rename, [@modules, @code_files]);
+}
+
+sub rename_modules_internally {
+    my ($rename, $files) = @_;
+
+    # We can't use \b because :: matches \b.
+    my $break = qr/^|[^\w:]|$/;
+    foreach my $file (@$files) {
+        open(my $fh, '&lt;', $file) || die &quot;$file: $!&quot;;
+        my $content = do { local $/ = undef; &lt;$fh&gt; };
+        close($fh);
+        foreach my $old_name (keys %$rename) {
+            my $new_name = $rename-&gt;{$old_name};
+            $content =~ s/($break)\Q$old_name\E($break)/$1$new_name$2/gms;
+        }
+        open(my $write_fh, '&gt;', $file) || die &quot;$file: $!&quot;;
+        print $write_fh $content;
+        close($write_fh);
+    }
+}
+
+sub get_version {
+    my ($dir) = @_;
+    print &quot;Getting version info from info.pl...\n&quot;;
+    my $info;
+    {
+        local @INC = (&quot;$dir/lib&quot;, @INC);
+        $info = do &quot;$dir/info.pl&quot;; die $@ if $@;
+    }
+    return $info-&gt;{version};
+}
+
+sub get_install_requirements {
+    my ($dir) = @_;
+    my $file = &quot;$dir/code/install-requirements.pl&quot;;
+    return '' if !-f $file;
+
+    print &quot;Moving install-requirements.pl code into Config.pm...\n&quot;;
+    my ($modules, $code) = process_code_file($file);
+    $modules = join('', @$modules);
+    $code = join('', @$code);
+    if ($modules) {
+        return &quot;$modules\n\n$code&quot;;
+    }
+    return $code;
+}
+
+sub process_code_file {
+    my ($file) = @_;
+    open(my $fh, '&lt;', $file) || die &quot;$file: $!&quot;;
+    my $stuff_started;
+    my (@modules, @code);
+    foreach my $line (&lt;$fh&gt;) {
+        $stuff_started = 1 if $line !~ /^#/;
+        next if !$stuff_started;
+        next if $line =~ /^use (warnings|strict|lib|Bugzilla)[^\w:]/;
+        if ($line =~ /^(?:use|require)\b/) {
+            push(@modules, $line);
+        }
+        else {
+            push(@code, $line);
+        }
+    }
+    close $fh;
+    return (\@modules, \@code);
+}
+
+sub code_files_to_subroutines {
+    my ($dir) = @_;
+
+    my @dir_files = glob(&quot;$dir/code/*.pl&quot;);
+    my (@all_modules, @subroutines);
+    foreach my $file (@dir_files) {
+        next if $file =~ /install-requirements/;
+        print &quot;Moving $file code into Extension.pm...\n&quot;;
+        my ($modules, $code) = process_code_file($file);
+        my @code_lines = map { &quot;    $_&quot; } @$code;
+        my $code_string = join('', @code_lines);
+        $code_string =~ s/Bugzilla-&gt;hook_args/\$args/g;
+        $code_string =~ s/my\s+\$args\s+=\s+\$args;//gs;
+        chomp($code_string);
+        push(@all_modules, @$modules);
+        my $name = basename($file);
+        $name =~ s/-/_/;
+        $name =~ s/\.pl$//;
+
+        my $subroutine = &lt;&lt;END;
+sub $name {
+    my (\$self, \$args) = \@_;
+$code_string
+}
+END
+        push(@subroutines, $subroutine);
+    }
+
+    my %seen_modules = map { trim($_) =&gt; 1 } @all_modules;
+    my $module_string = join(&quot;\n&quot;, sort keys %seen_modules);
+    my $subroutine_string = join(&quot;\n&quot;, @subroutines);
+    return ($module_string, $subroutine_string);
+}
+
+sub move_template_hooks {
+    my ($dir) = @_;
+    foreach my $lang (glob(&quot;$dir/template/*&quot;)) {
+        next if !_file_matters($lang);
+        my $hook_container = &quot;$lang/default/hook&quot;;
+        mkpath($hook_container) || warn &quot;$hook_container: $!&quot;;
+        # Hooks can be in all sorts of weird places, including
+        # template/default/hook.
+        foreach my $file (glob(&quot;$lang/*&quot;)) {
+            next if !_file_matters($file, 1);
+            my $dirname = basename($file);
+            print &quot;Moving $file to $hook_container/$dirname...\n&quot;;
+            rename($file, &quot;$hook_container/$dirname&quot;) || die &quot;move failed: $!&quot;;
+        }
+    }
+}
+
+sub _file_matters {
+     my ($path, $tmpl) = @_;
+     my @ignore = qw(default custom CVS);
+     my $file = basename($path);
+     return 0 if grep(lc($_) eq lc($file), @ignore);
+      # Hidden files
+     return 0 if $file =~ /^\./;
+     if ($tmpl) {
+         return 1 if $file =~ /\.tmpl$/;
+     }
+     return 0 if !-d $path;
+     return 1;
+}
+
+__END__
+
+=head1 NAME
+
+extension-convert.pl - Convert extensions from the pre-3.6 format to the 
+3.6 format.
+
+=head1 SYNOPSIS
+
+ contrib/extension-convert.pl name
+
+ Converts an extension in the F&lt;extensions/&gt; directory into the new
+ extension layout for Bugzilla 3.6.
</ins><span class="cx">Property changes on: trunk/Websites/bugs.webkit.org/contrib/extension-convert.pl
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkWebsitesbugswebkitorgcontribfixpermsplfromrev173253trunkWebsitesbugswebkitorgextensionsexamplecodewebservicepl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/contrib/fixperms.pl (from rev 173253, trunk/Websites/bugs.webkit.org/extensions/example/code/webservice.pl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/contrib/fixperms.pl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/contrib/fixperms.pl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,28 @@
</span><ins>+#!/usr/bin/env perl -w
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Everything Solved, Inc.
+# Portions created by the Initial Developer are Copyright (C) 2010 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+use strict;
+use warnings;
+use lib qw(. lib);
+
+use Bugzilla;
+use Bugzilla::Install::Filesystem qw(fix_all_file_permissions);
+fix_all_file_permissions(1);
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgcontribfixpermspl"></a>
<div class="propset"><h4>Property changes: trunk/Websites/bugs.webkit.org/contrib/fixperms.pl</h4>
<pre class="diff"><span>
</span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkWebsitesbugswebkitorgcontribgnats2bzpl"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/contrib/gnats2bz.pl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/contrib/gnats2bz.pl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/contrib/gnats2bz.pl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,1067 +0,0 @@
</span><del>-#!/usr/bin/env perl -w
-# -*- Mode: perl; indent-tabs-mode: nil -*-
-#
-# The contents of this file are subject to the Mozilla Public
-# License Version 1.1 (the &quot;License&quot;); you may not use this file
-# except in compliance with the License. You may obtain a copy of
-# the License at http://www.mozilla.org/MPL/
-#
-# Software distributed under the License is distributed on an &quot;AS
-# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
-# implied. See the License for the specific language governing
-# rights and limitations under the License.
-#
-# The Original Code is the Gnats To Bugzilla Conversion Utility.
-#
-# The Initial Developer of the Original Code is Tom
-# Schutter. Portions created by Tom Schutter are
-# Copyright (C) 1999 Tom Schutter. All
-# Rights Reserved.
-#
-# Contributor(s): Tom Schutter &lt;tom@platte.com&gt;
-#
-# Perl script to convert a GNATS database to a Bugzilla database.
-# This script generates a file that contains SQL commands for MySQL.
-# This script DOES NOT MODIFY the GNATS database.
-# This script DOES NOT MODIFY the Bugzilla database.
-#
-# Usage procedure:
-#   1) Regenerate the GNATS index file.  It sometimes has inconsistencies,
-#      and this script relies on it being correct.  Use the GNATS command:
-#        gen-index --numeric --outfile=$GNATS_DIR/gnats-db/gnats-adm/index
-#   2) Modify variables at the beginning of this script to match
-#      what your site requires.
-#   3) Modify translate_pr() and write_bugs() below to fixup mapping from
-#      your GNATS policies to Bugzilla.  For example, how do the
-#      Severity/Priority fields map to bug_severity/priority?
-#   4) Run this script.
-#   5) Fix the problems in the GNATS database identified in the output
-#      script file gnats2bz_cleanup.sh.  Fixing problems may be a job
-#      for a custom perl script.  If you make changes to GNATS, goto step 2.
-#   6) Examine the statistics in the output file gnats2bz_stats.txt.
-#      These may indicate some more cleanup that is needed.  For example,
-#      you may find that there are invalid &quot;State&quot;s, or not a consistent
-#      scheme for &quot;Release&quot;s.  If you make changes to GNATS, goto step 2.
-#   7) Examine the output data file gnats2bz_data.sql.  If problems
-#      exist, goto step 2.
-#   8) Create a new, empty Bugzilla database.
-#   9) Import the data using the command:
-#      mysql -uroot -p'ROOT_PASSWORD' bugs &lt; gnats2bz_data.sql
-#   10) Update the shadow directory with the command:
-#       cd $BUGZILLA_DIR; ./processmail regenerate
-#   11) Run a sanity check by visiting the sanitycheck.cgi page.
-#   12) Manually verify that the database is ok.  If it is not, goto step 2.
-#
-# Important notes:
-#   Confidential is not mapped or exported.
-#   Submitter-Id is not mapped or exported.
-#
-# Design decisions:
-#   This script generates a SQL script file rather than dumping the data
-#     directly into the database.  This is to allow the user to check
-#     and/or modify the results before they are put into the database.
-#   The PR number is very important and must be maintained as the Bugzilla
-#     bug number, because there are many references to the PR number, such
-#     as in code comments, CVS comments, customer communications, etc.
-#   Reading ENUMERATED and TEXT fields:
-#     1) All leading and trailing whitespace is stripped.
-#   Reading MULTITEXT fields:
-#     1) All leading blank lines are stripped.
-#     2) All trailing whitespace is stripped.
-#     3) Indentation is preserved.
-#   Audit-Trail is not mapped to bugs_activity table, because there
-#     is no place to put the &quot;Why&quot; text, which can have a fair amount
-#     of information content.
-#
-# 15 January 2002 - changes from Andrea Dell'Amico &lt;adellam@link.it&gt;
-#
-#     * Adapted to the new database structure: now long_descs is a 
-#       separate table.
-#     * Set a default for the target milestone, otherwise bugzilla
-#       doesn't work with the imported database if milestones are used.
-#     * In gnats version 3.113 records are separated by &quot;|&quot; and not &quot;:&quot;.
-#     * userid &quot;1&quot; is for the bugzilla administrator, so it's better to
-#       start from 2.
-#
-
-use strict;
-
-# Suffix to be appended to username to make it an email address.
-my($username_suffix) = &quot;\@platte.com&quot;;
-
-# Default organization that should be ignored and not passed on to Bugzilla.
-# Only bugs that are reported outside of the default organization will have
-# their Originator,Organization fields passed on.
-# The assumption here is that if the Organization is identical to the
-# $default_organization, then the Originator will most likely be only an
-# alias for the From field in the mail header.
-my($default_organization) = &quot;Platte River Associates|platte&quot;;
-
-# Username for reporter field if unable to determine from mail header
-my($gnats_username) = &quot;gnats\@platte.com&quot;;
-
-# Flag indicating if cleanup file should use edit-pr or ${EDITOR}.
-# Using edit-pr is safer, but may be too slow if there are too many
-# PRs that need cleanup.  If you use ${EDITOR}, then you must make
-# sure that you have exclusive access to the database, and that you
-# do not screw up any fields.
-my($cleanup_with_edit_pr) = 0;
-
-# Component name and description for bugs imported from GNATS.
-my($default_component) = &quot;GNATS Import&quot;;
-my($default_component_description) = &quot;Bugs imported from GNATS.&quot;;
-
-# First generated userid. Start from 2: 1 is used for the bugzilla
-# administrator.
-my($userid_base) = 2;
-
-# Output filenames.
-my($cleanup_pathname) = &quot;gnats2bz_cleanup.sh&quot;;
-my($stats_pathname) = &quot;gnats2bz_stats.txt&quot;;
-my($data_pathname) = &quot;gnats2bz_data.sql&quot;;
-
-# List of ENUMERATED and TEXT fields.
-my(@text_fields) = qw(Number Category Synopsis Confidential Severity
-                      Priority Responsible State Class Submitter-Id
-                      Arrival-Date Originator Release);
-
-# List of MULTITEXT fields.
-my(@multitext_fields) = qw(Mail-Header Organization Environment Description
-                           How-To-Repeat Fix Audit-Trail Unformatted);
-
-# List of fields to report statistics for.
-my(@statistics_fields) = qw(Category Confidential Severity Priority
-                            Responsible State Class Submitter-Id Originator
-                            Organization Release Environment);
-
-# Array to hold list of GNATS PRs.
-my(@pr_list);
-
-# Array to hold list of GNATS categories.
-my(@categories_list);
-
-# Array to hold list of GNATS responsible users.
-my(@responsible_list);
-
-# Array to hold list of usernames.
-my(@username_list);
-# Put the gnats_username in first.
-get_userid($gnats_username);
-
-# Hash to hold list of versions.
-my(%versions_table);
-
-# Hash to hold contents of PR.
-my(%pr_data);
-
-# String to hold duplicate fields found during read of PR.
-my($pr_data_dup_fields) = &quot;&quot;;
-
-# String to hold badly labeled fields found during read of PR.
-# This usually happens when the user does not separate the field name
-# from the field data with whitespace.
-my($pr_data_bad_fields) = &quot; &quot;;
-
-# Hash to hold statistics (note that this a hash of hashes).
-my(%pr_stats);
-
-# Process commmand line.
-my($gnats_db_dir) = @ARGV;
-defined($gnats_db_dir) || die &quot;gnats-db dir not specified&quot;;
-(-d $gnats_db_dir) || die &quot;$gnats_db_dir is not a directory&quot;;
-
-# Load @pr_list from GNATS index file.
-my($index_pathname) = $gnats_db_dir . &quot;/gnats-adm/index&quot;;
-(-f $index_pathname) || die &quot;$index_pathname not found&quot;;
-print &quot;Reading $index_pathname...\n&quot;;
-if (!load_index($index_pathname)) {
-    return(0);
-}
-
-# Load @category_list from GNATS categories file.
-my($categories_pathname) = $gnats_db_dir . &quot;/gnats-adm/categories&quot;;
-(-f $categories_pathname) || die &quot;$categories_pathname not found&quot;;
-print &quot;Reading $categories_pathname...\n&quot;;
-if (!load_categories($categories_pathname)) {
-    return(0);
-}
-
-# Load @responsible_list from GNATS responsible file.
-my($responsible_pathname) = $gnats_db_dir . &quot;/gnats-adm/responsible&quot;;
-(-f $responsible_pathname) || die &quot;$responsible_pathname not found&quot;;
-print &quot;Reading $responsible_pathname...\n&quot;;
-if (!load_responsible($responsible_pathname)) {
-    return(0);
-}
-
-# Open cleanup file.
-open(CLEANUP, &quot;&gt;$cleanup_pathname&quot;) ||
-    die &quot;Unable to open $cleanup_pathname: $!&quot;;
-chmod(0744, $cleanup_pathname) || warn &quot;Unable to chmod $cleanup_pathname: $!&quot;;
-print CLEANUP &quot;#!/bin/sh\n&quot;;
-print CLEANUP &quot;# List of PRs that have problems found by gnats2bz.pl.\n&quot;;
-
-# Open data file.
-open(DATA, &quot;&gt;$data_pathname&quot;) || die &quot;Unable to open $data_pathname: $!&quot;;
-print DATA &quot;-- Exported data from $gnats_db_dir by gnats2bz.pl.\n&quot;;
-print DATA &quot;-- Load it into a Bugzilla database using the command:\n&quot;;
-print DATA &quot;--   mysql -uroot -p'ROOT_PASSWORD' bugs &lt; gnats2bz_data.sql\n&quot;;
-print DATA &quot;--\n&quot;;
-
-# Loop over @pr_list.
-my($pr);
-foreach $pr (@pr_list) {
-    print &quot;Processing $pr...\n&quot;;
-    if (!read_pr(&quot;$gnats_db_dir/$pr&quot;)) {
-        next;
-    }
-
-    translate_pr();
-
-    check_pr($pr);
-
-    collect_stats();
-
-    update_versions();
-
-    write_bugs();
-
-    write_longdescs();
-
-}
-
-write_non_bugs_tables();
-
-close(CLEANUP) || die &quot;Unable to close $cleanup_pathname: $!&quot;;
-close(DATA) || die &quot;Unable to close $data_pathname: $!&quot;;
-
-print &quot;Generating $stats_pathname...\n&quot;;
-report_stats();
-
-sub load_index {
-    my($pathname) = @_;
-    my($record);
-    my(@fields);
-
-    open(INDEX, $pathname) || die &quot;Unable to open $pathname: $!&quot;;
-
-    while ($record = &lt;INDEX&gt;) {
-        @fields = split(/\|/, $record);
-        push(@pr_list, $fields[0]);
-    }
-
-    close(INDEX) || die &quot;Unable to close $pathname: $!&quot;;
-
-    return(1);
-}
-
-sub load_categories {
-    my($pathname) = @_;
-    my($record);
-
-    open(CATEGORIES, $pathname) || die &quot;Unable to open $pathname: $!&quot;;
-
-    while ($record = &lt;CATEGORIES&gt;) {
-        if ($record =~ /^#/) {
-            next;
-        }
-        push(@categories_list, [split(/:/, $record)]);
-    }
-
-    close(CATEGORIES) || die &quot;Unable to close $pathname: $!&quot;;
-
-    return(1);
-}
-
-sub load_responsible {
-    my($pathname) = @_;
-    my($record);
-
-    open(RESPONSIBLE, $pathname) || die &quot;Unable to open $pathname: $!&quot;;
-
-    while ($record = &lt;RESPONSIBLE&gt;) {
-        if ($record =~ /^#/) {
-            next;
-        }
-        push(@responsible_list, [split(/\|/, $record)]);
-    }
-
-    close(RESPONSIBLE) || die &quot;Unable to close $pathname: $!&quot;;
-
-    return(1);
-}
-
-sub read_pr {
-    my($pr_filename) = @_;
-    my($multitext) = &quot;Mail-Header&quot;;
-    my($field, $mail_header);
-
-    # Empty the hash.
-    %pr_data = ();
-
-    # Empty the list of duplicate fields.
-    $pr_data_dup_fields = &quot;&quot;;
-
-    # Empty the list of badly labeled fields.
-    $pr_data_bad_fields = &quot;&quot;;
-
-    unless (open(PR, $pr_filename)) {
-        warn &quot;error opening $pr_filename: $!&quot;;
-        return(0);
-    }
-
-    LINELOOP: while (&lt;PR&gt;) {
-        chomp;
-
-        if ($multitext eq &quot;Unformatted&quot;) {
-            # once we reach &quot;Unformatted&quot;, rest of file goes there
-            $pr_data{$multitext} = append_multitext($pr_data{$multitext}, $_);
-            next LINELOOP;
-        }
-
-        # Handle ENUMERATED and TEXT fields.
-        foreach $field (@text_fields) {
-            if (/^&gt;$field:($|\s+)/) {
-                $pr_data{$field} = $'; # part of string after match
-                $pr_data{$field} =~ s/\s+$//; # strip trailing whitespace
-                $multitext = &quot;&quot;;
-                next LINELOOP;
-            }
-        }
-
-        # Handle MULTITEXT fields.
-        foreach $field (@multitext_fields) {
-            if (/^&gt;$field:\s*$/) {
-                $_ = $'; # set to part of string after match part
-                if (defined($pr_data{$field})) {
-                    if ($pr_data_dup_fields eq &quot;&quot;) {
-                        $pr_data_dup_fields = $field;
-                    } else {
-                        $pr_data_dup_fields = &quot;$pr_data_dup_fields $field&quot;;
-                    }
-                }
-                $pr_data{$field} = $_;
-                $multitext = $field;
-                next LINELOOP;
-            }
-        }
-
-        # Check for badly labeled fields.
-        foreach $field ((@text_fields, @multitext_fields)) {
-            if (/^&gt;$field:/) {
-                if ($pr_data_bad_fields eq &quot;&quot;) {
-                    $pr_data_bad_fields = $field;
-                } else {
-                    $pr_data_bad_fields = &quot;$pr_data_bad_fields $field&quot;;
-                }
-            }
-        }
-
-        # Handle continued MULTITEXT field.
-        $pr_data{$multitext} = append_multitext($pr_data{$multitext}, $_);
-    }
-
-    close(PR) || warn &quot;error closing $pr_filename: $!&quot;;
-
-    # Strip trailing newlines from MULTITEXT fields.
-    foreach $field (@multitext_fields) {
-        if (defined($pr_data{$field})) {
-            $pr_data{$field} =~ s/\s+$//;
-        }
-    }
-
-    return(1);
-}
-
-sub append_multitext {
-    my($original, $addition) = @_;
-
-    if (defined($original) &amp;&amp; $original ne &quot;&quot;) {
-        return &quot;$original\n$addition&quot;;
-    } else {
-        return $addition;
-    }
-}
-
-sub check_pr {
-    my($pr) = @_;
-    my($error_list) = &quot;&quot;;
-
-    if ($pr_data_dup_fields ne &quot;&quot;) {
-        $error_list = append_error($error_list, &quot;Multiple '$pr_data_dup_fields'&quot;);
-    }
-
-    if ($pr_data_bad_fields ne &quot;&quot;) {
-        $error_list = append_error($error_list, &quot;Bad field labels '$pr_data_bad_fields'&quot;);
-    }
-
-    if (!defined($pr_data{&quot;Description&quot;}) || $pr_data{&quot;Description&quot;} eq &quot;&quot;) {
-        $error_list = append_error($error_list, &quot;Description empty&quot;);
-    }
-
-    if (defined($pr_data{&quot;Unformatted&quot;}) &amp;&amp; $pr_data{&quot;Unformatted&quot;} ne &quot;&quot;) {
-        $error_list = append_error($error_list, &quot;Unformatted text&quot;);
-    }
-
-    if (defined($pr_data{&quot;Release&quot;}) &amp;&amp; length($pr_data{&quot;Release&quot;}) &gt; 16) {
-        $error_list = append_error($error_list, &quot;Release &gt; 16 chars&quot;);
-    }
-
-    if (defined($pr_data{&quot;Fix&quot;}) &amp;&amp; $pr_data{&quot;Fix&quot;} =~ /State-Changed-/) {
-        $error_list = append_error($error_list, &quot;Audit in Fix field&quot;);
-    }
-
-    if (defined($pr_data{&quot;Arrival-Date&quot;})) {
-        if ($pr_data{&quot;Arrival-Date&quot;} eq &quot;&quot;) {
-            $error_list = append_error($error_list, &quot;Arrival-Date empty&quot;);
-
-        } elsif (unixdate2datetime($pr, $pr_data{&quot;Arrival-Date&quot;}) eq &quot;&quot;) {
-            $error_list = append_error($error_list, &quot;Arrival-Date format&quot;);
-        }
-    }
-
-    # More checks should go here.
-
-    if ($error_list ne &quot;&quot;) {
-        if ($cleanup_with_edit_pr) {
-            my(@parts) = split(&quot;/&quot;, $pr);
-            my($pr_num) = $parts[1];
-            print CLEANUP &quot;echo \&quot;$error_list\&quot;; edit-pr $pr_num\n&quot;;
-        } else {
-            print CLEANUP &quot;echo \&quot;$error_list\&quot;; \${EDITOR} $pr\n&quot;;
-        }
-    }
-}
-
-sub append_error {
-    my($original, $addition) = @_;
-
-    if ($original ne &quot;&quot;) {
-        return &quot;$original, $addition&quot;;
-    } else {
-        return $addition;
-    }
-}
-
-sub translate_pr {
-    # This function performs GNATS -&gt; Bugzilla translations that should
-    # happen before collect_stats().
-
-    if (!defined($pr_data{&quot;Organization&quot;})) {
-        $pr_data{&quot;Originator&quot;} = &quot;&quot;;
-    }
-    if ($pr_data{&quot;Organization&quot;} =~ /$default_organization/) {
-        $pr_data{&quot;Originator&quot;} = &quot;&quot;;
-        $pr_data{&quot;Organization&quot;} = &quot;&quot;;
-    }
-    $pr_data{&quot;Organization&quot;} =~ s/^\s+//g; # strip leading whitespace
-
-    if (!defined($pr_data{&quot;Release&quot;}) ||
-        $pr_data{&quot;Release&quot;} eq &quot;&quot; ||
-        $pr_data{&quot;Release&quot;} =~ /^unknown-1.0$/
-        ) {
-        $pr_data{&quot;Release&quot;} = &quot;unknown&quot;;
-    }
-
-    if (defined($pr_data{&quot;Responsible&quot;})) {
-        $pr_data{&quot;Responsible&quot;} =~ /\w+/;
-        $pr_data{&quot;Responsible&quot;} = &quot;$&amp;$username_suffix&quot;;
-    }
-
-    my($rep_platform, $op_sys) = (&quot;All&quot;, &quot;All&quot;);
-    if (defined($pr_data{&quot;Environment&quot;})) {
-        if ($pr_data{&quot;Environment&quot;} =~ /[wW]in.*NT/) {
-            $rep_platform = &quot;PC&quot;;
-            $op_sys = &quot;Windows NT&quot;;
-        } elsif ($pr_data{&quot;Environment&quot;} =~ /[wW]in.*95/) {
-            $rep_platform = &quot;PC&quot;;
-            $op_sys = &quot;Windows 95&quot;;
-        } elsif ($pr_data{&quot;Environment&quot;} =~ /[wW]in.*98/) {
-            $rep_platform = &quot;PC&quot;;
-            $op_sys = &quot;Windows 98&quot;;
-        } elsif ($pr_data{&quot;Environment&quot;} =~ /OSF/) {
-            $rep_platform = &quot;DEC&quot;;
-            $op_sys = &quot;OSF/1&quot;;
-        } elsif ($pr_data{&quot;Environment&quot;} =~ /AIX/) {
-            $rep_platform = &quot;RS/6000&quot;;
-            $op_sys = &quot;AIX&quot;;
-        } elsif ($pr_data{&quot;Environment&quot;} =~ /IRIX/) {
-            $rep_platform = &quot;SGI&quot;;
-            $op_sys = &quot;IRIX&quot;;
-        } elsif ($pr_data{&quot;Environment&quot;} =~ /SunOS.*5\.\d/) {
-            $rep_platform = &quot;Sun&quot;;
-            $op_sys = &quot;Solaris&quot;;
-        } elsif ($pr_data{&quot;Environment&quot;} =~ /SunOS.*4\.\d/) {
-            $rep_platform = &quot;Sun&quot;;
-            $op_sys = &quot;SunOS&quot;;
-        }
-    }
-
-    $pr_data{&quot;Environment&quot;} = &quot;$rep_platform:$op_sys&quot;;
-}
-
-sub collect_stats {
-    my($field, $value);
-
-    foreach $field (@statistics_fields) {
-        $value = $pr_data{$field};
-        if (!defined($value)) {
-            $value = &quot;&quot;;
-        }
-        if (defined($pr_stats{$field}{$value})) {
-            $pr_stats{$field}{$value}++;
-        } else {
-            $pr_stats{$field}{$value} = 1;
-        }
-    }
-}
-
-sub report_stats {
-    my($field, $value, $count);
-
-    open(STATS, &quot;&gt;$stats_pathname&quot;) ||
-        die &quot;Unable to open $stats_pathname: $!&quot;;
-    print STATS &quot;Statistics of $gnats_db_dir collated by gnats2bz.pl.\n&quot;;
-
-    my($field_stats);
-    while (($field, $field_stats) = each(%pr_stats)) {
-        print STATS &quot;\n$field:\n&quot;;
-        while (($value, $count) = each(%$field_stats)) {
-            print STATS &quot;  $value: $count\n&quot;;
-        }
-    }
-
-    close(STATS) || die &quot;Unable to close $stats_pathname: $!&quot;;
-}
-
-sub get_userid {
-    my($responsible) = @_;
-    my($username, $userid);
-
-    if (!defined($responsible)) {
-        return(-1);
-    }
-
-    # Search for current username in the list.
-    $userid = $userid_base;
-    foreach $username (@username_list) {
-        if ($username eq $responsible) {
-            return($userid);
-        }
-        $userid++;
-    }
-
-    push(@username_list, $responsible);
-    return($userid);
-}
-
-sub update_versions {
-
-    if (!defined($pr_data{&quot;Release&quot;}) || !defined($pr_data{&quot;Category&quot;})) {
-        return;
-    }
-
-    my($curr_product) = $pr_data{&quot;Category&quot;};
-    my($curr_version) = $pr_data{&quot;Release&quot;};
-
-    if ($curr_version eq &quot;&quot;) {
-        return;
-    }
-
-    if (!defined($versions_table{$curr_product})) {
-        $versions_table{$curr_product} = [ ];
-    }
-
-    my($version_list) = $versions_table{$curr_product};
-    my($version);
-    foreach $version (@$version_list) {
-        if ($version eq $curr_version) {
-            return;
-        }
-    }
-
-    push(@$version_list, $curr_version);
-}
-
-sub write_bugs {
-    my($bug_id) = $pr_data{&quot;Number&quot;};
-
-    my($userid) = get_userid($pr_data{&quot;Responsible&quot;});
-
-    # Mapping from Class,Severity to bug_severity
-    # At our site, the Severity,Priority fields have degenerated
-    # into a 9-level priority field.
-    my($bug_severity) = &quot;normal&quot;;
-    if ($pr_data{&quot;Class&quot;} eq &quot;change-request&quot;) {
-        $bug_severity = &quot;enhancement&quot;;
-    } elsif (defined($pr_data{&quot;Synopsis&quot;})) {
-        if ($pr_data{&quot;Synopsis&quot;} =~ /crash|assert/i) {
-            $bug_severity = &quot;critical&quot;;
-        } elsif ($pr_data{&quot;Synopsis&quot;} =~ /wrong|error/i) {
-            $bug_severity = &quot;major&quot;;
-        }
-    }
-    $bug_severity = SqlQuote($bug_severity);
-
-    # Mapping from Severity,Priority to priority
-    # At our site, the Severity,Priority fields have degenerated
-    # into a 9-level priority field.
-    my($priority) = &quot;P1&quot;;
-    if (defined($pr_data{&quot;Severity&quot;}) &amp;&amp; defined($pr_data{&quot;Severity&quot;})) {
-        if ($pr_data{&quot;Severity&quot;} eq &quot;critical&quot;) {
-            if ($pr_data{&quot;Priority&quot;} eq &quot;high&quot;) {
-                $priority = &quot;P1&quot;;
-            } else {
-                $priority = &quot;P2&quot;;
-            }
-        } elsif ($pr_data{&quot;Severity&quot;} eq &quot;serious&quot;) {
-            if ($pr_data{&quot;Priority&quot;} eq &quot;low&quot;) {
-                $priority = &quot;P4&quot;;
-            } else {
-                $priority = &quot;P3&quot;;
-            }
-        } else {
-            if ($pr_data{&quot;Priority&quot;} eq &quot;high&quot;) {
-                $priority = &quot;P4&quot;;
-            } else {
-                $priority = &quot;P5&quot;;
-            }
-        }
-    }
-    $priority = SqlQuote($priority);
-
-    # Map State,Class to bug_status,resolution
-    my($bug_status, $resolution);
-    if ($pr_data{&quot;State&quot;} eq &quot;open&quot; || $pr_data{&quot;State&quot;} eq &quot;analyzed&quot;) {
-        $bug_status = &quot;ASSIGNED&quot;;
-        $resolution = &quot;&quot;;
-    } elsif ($pr_data{&quot;State&quot;} eq &quot;feedback&quot;) {
-        $bug_status = &quot;RESOLVED&quot;;
-        $resolution = &quot;FIXED&quot;;
-    } elsif ($pr_data{&quot;State&quot;} eq &quot;closed&quot;) {
-        $bug_status = &quot;CLOSED&quot;;
-        if (defined($pr_data{&quot;Class&quot;}) &amp;&amp; $pr_data{&quot;Class&quot;} =~ /^duplicate/) {
-            $resolution = &quot;DUPLICATE&quot;;
-        } elsif (defined($pr_data{&quot;Class&quot;}) &amp;&amp; $pr_data{&quot;Class&quot;} =~ /^mistaken/) {
-            $resolution = &quot;INVALID&quot;;
-        } else {
-            $resolution = &quot;FIXED&quot;;
-        }
-    } elsif ($pr_data{&quot;State&quot;} eq &quot;suspended&quot;) {
-        $bug_status = &quot;RESOLVED&quot;;
-        $resolution = &quot;WONTFIX&quot;;
-    } else {
-        $bug_status = &quot;NEW&quot;;
-        $resolution = &quot;&quot;;
-    }
-    $bug_status = SqlQuote($bug_status);
-    $resolution = SqlQuote($resolution);
-
-    my($creation_ts) = &quot;&quot;;
-    if (defined($pr_data{&quot;Arrival-Date&quot;}) &amp;&amp; $pr_data{&quot;Arrival-Date&quot;} ne &quot;&quot;) {
-        $creation_ts = unixdate2datetime($bug_id, $pr_data{&quot;Arrival-Date&quot;});
-    }
-    $creation_ts = SqlQuote($creation_ts);
-
-    my($delta_ts) = &quot;&quot;;
-    if (defined($pr_data{&quot;Audit-Trail&quot;})) {
-        # note that (?:.|\n)+ is greedy, so this should match the
-        # last Changed-When
-        if ($pr_data{&quot;Audit-Trail&quot;} =~ /(?:.|\n)+-Changed-When: (.+)/) {
-            $delta_ts = unixdate2timestamp($bug_id, $1);
-        }
-    }
-    if ($delta_ts eq &quot;&quot;) {
-        if (defined($pr_data{&quot;Arrival-Date&quot;}) &amp;&amp; $pr_data{&quot;Arrival-Date&quot;} ne &quot;&quot;) {
-            $delta_ts = unixdate2timestamp($bug_id, $pr_data{&quot;Arrival-Date&quot;});
-        }
-    }
-    $delta_ts = SqlQuote($delta_ts);
-
-    my($short_desc) = SqlQuote($pr_data{&quot;Synopsis&quot;});
-
-    my($rep_platform, $op_sys) = split(/\|/, $pr_data{&quot;Environment&quot;});
-    $rep_platform = SqlQuote($rep_platform);
-    $op_sys = SqlQuote($op_sys);
-
-    my($reporter) = get_userid($gnats_username);
-    if (
-        defined($pr_data{&quot;Mail-Header&quot;}) &amp;&amp;
-        $pr_data{&quot;Mail-Header&quot;} =~ /From ([\w.]+\@[\w.]+)/
-        ) {
-        $reporter = get_userid($1);
-    }
-
-    my($version) = &quot;&quot;;
-    if (defined($pr_data{&quot;Release&quot;})) {
-        $version = substr($pr_data{&quot;Release&quot;}, 0, 16);
-    }
-    $version = SqlQuote($version);
-
-    my($product) = &quot;&quot;;
-    if (defined($pr_data{&quot;Category&quot;})) {
-        $product = $pr_data{&quot;Category&quot;};
-    }
-    $product = SqlQuote($product);
-
-    my($component) = SqlQuote($default_component);
-
-    my($target_milestone) = &quot;0&quot;;
-    # $target_milestone = SqlQuote($target_milestone);
-
-    my($qa_contact) = &quot;0&quot;;
-
-    # my($bug_file_loc) = &quot;&quot;;
-    # $bug_file_loc = SqlQuote($bug_file_loc);
-
-    # my($status_whiteboard) = &quot;&quot;;
-    # $status_whiteboard = SqlQuote($status_whiteboard);
-
-    print DATA &quot;\ninsert into bugs (\n&quot;;
-    print DATA &quot;  bug_id, assigned_to, bug_severity, priority, bug_status, creation_ts, delta_ts,\n&quot;;
-    print DATA &quot;  short_desc,\n&quot;;
-    print DATA &quot;  rep_platform, op_sys, reporter, version,\n&quot;;
-    print DATA &quot;  product, component, resolution, target_milestone, qa_contact\n&quot;;
-    print DATA &quot;) values (\n&quot;;
-    print DATA &quot;  $bug_id, $userid, $bug_severity, $priority, $bug_status, $creation_ts, $delta_ts,\n&quot;;
-    print DATA &quot;  $short_desc,\n&quot;;
-    print DATA &quot;  $rep_platform, $op_sys, $reporter, $version,\n&quot;;
-    print DATA &quot;  $product, $component, $resolution, $target_milestone, $qa_contact\n&quot;;
-    print DATA &quot;);\n&quot;;
-}
-
-sub write_longdescs {
-
-    my($bug_id) = $pr_data{&quot;Number&quot;};
-    my($who) = get_userid($pr_data{&quot;Responsible&quot;});;
-    my($bug_when) = &quot;&quot;;
-    if (defined($pr_data{&quot;Arrival-Date&quot;}) &amp;&amp; $pr_data{&quot;Arrival-Date&quot;} ne &quot;&quot;) {
-        $bug_when = unixdate2datetime($bug_id, $pr_data{&quot;Arrival-Date&quot;});
-    }
-    $bug_when = SqlQuote($bug_when);
-    my($thetext) = $pr_data{&quot;Description&quot;};
-    if (defined($pr_data{&quot;How-To-Repeat&quot;}) &amp;&amp; $pr_data{&quot;How-To-Repeat&quot;} ne &quot;&quot;) {
-        $thetext =
-            $thetext . &quot;\n\nHow-To-Repeat:\n&quot; . $pr_data{&quot;How-To-Repeat&quot;};
-    }
-    if (defined($pr_data{&quot;Fix&quot;}) &amp;&amp; $pr_data{&quot;Fix&quot;} ne &quot;&quot;) {
-        $thetext = $thetext . &quot;\n\nFix:\n&quot; . $pr_data{&quot;Fix&quot;};
-    }
-    if (defined($pr_data{&quot;Originator&quot;}) &amp;&amp; $pr_data{&quot;Originator&quot;} ne &quot;&quot;) {
-        $thetext = $thetext . &quot;\n\nOriginator:\n&quot; . $pr_data{&quot;Originator&quot;};
-    }
-    if (defined($pr_data{&quot;Organization&quot;}) &amp;&amp; $pr_data{&quot;Organization&quot;} ne &quot;&quot;) {
-        $thetext = $thetext . &quot;\n\nOrganization:\n&quot; . $pr_data{&quot;Organization&quot;};
-    }
-    if (defined($pr_data{&quot;Audit-Trail&quot;}) &amp;&amp; $pr_data{&quot;Audit-Trail&quot;} ne &quot;&quot;) {
-        $thetext = $thetext . &quot;\n\nAudit-Trail:\n&quot; . $pr_data{&quot;Audit-Trail&quot;};
-    }
-    if (defined($pr_data{&quot;Unformatted&quot;}) &amp;&amp; $pr_data{&quot;Unformatted&quot;} ne &quot;&quot;) {
-        $thetext = $thetext . &quot;\n\nUnformatted:\n&quot; . $pr_data{&quot;Unformatted&quot;};
-    }
-    $thetext = SqlQuote($thetext);
-
-    print DATA &quot;\ninsert into longdescs (\n&quot;;
-    print DATA &quot;  bug_id, who, bug_when, thetext\n&quot;;
-    print DATA &quot;) values (\n&quot;;
-    print DATA &quot;  $bug_id, $who, $bug_when, $thetext\n&quot;;
-    print DATA &quot;);\n&quot;;
-
-}
-
-sub write_non_bugs_tables {
-
-    my($categories_record);
-    foreach $categories_record (@categories_list) {
-        my($component) = SqlQuote($default_component);
-        my($product) = SqlQuote(@$categories_record[0]);
-        my($description) = SqlQuote(@$categories_record[1]);
-        my($initialowner) = SqlQuote(@$categories_record[2] . $username_suffix);
-
-        print DATA &quot;\ninsert into products (\n&quot;;
-        print DATA
-            &quot;  product, description, milestoneurl, disallownew\n&quot;;
-        print DATA &quot;) values (\n&quot;;
-        print DATA
-            &quot;  $product, $description, '', 0\n&quot;;
-        print DATA &quot;);\n&quot;;
-
-        print DATA &quot;\ninsert into components (\n&quot;;
-        print DATA
-            &quot;  value, program, initialowner, initialqacontact, description\n&quot;;
-        print DATA &quot;) values (\n&quot;;
-        print DATA
-            &quot;  $component, $product, $initialowner, '', $description\n&quot;;
-        print DATA &quot;);\n&quot;;
-
-        print DATA &quot;\ninsert into milestones (\n&quot;;
-        print DATA
-            &quot;  value, product, sortkey\n&quot;;
-        print DATA &quot;) values (\n&quot;;
-        print DATA
-            &quot;  0, $product, 0\n&quot;;
-        print DATA &quot;);\n&quot;;
-    }
-
-    my($username);
-    my($userid) = $userid_base;
-    my($password) = &quot;password&quot;;
-    my($realname);
-    my($groupset) = 0;
-    foreach $username (@username_list) {
-        $realname = map_username_to_realname($username);
-        $username = SqlQuote($username);
-        $realname = SqlQuote($realname);
-        print DATA &quot;\ninsert into profiles (\n&quot;;
-        print DATA
-            &quot;  userid, login_name, cryptpassword, realname, groupset\n&quot;;
-        print DATA &quot;) values (\n&quot;;
-        print DATA
-            &quot;  $userid, $username, encrypt('$password'), $realname, $groupset\n&quot;;
-        print DATA &quot;);\n&quot;;
-        $userid++;
-    }
-
-    my($product);
-    my($version_list);
-    while (($product, $version_list) = each(%versions_table)) {
-        $product = SqlQuote($product);
-
-        my($version);
-        foreach $version (@$version_list) {
-            $version = SqlQuote($version);
-
-            print DATA &quot;\ninsert into versions (value, program) &quot;;
-            print DATA &quot;values ($version, $product);\n&quot;;
-        }
-    }
-
-}
-
-sub map_username_to_realname() {
-    my($username) = @_;
-    my($name, $realname);
-
-    # get the portion before the @
-    $name = $username;
-    $name =~ s/\@.*//;
-
-    my($responsible_record);
-    foreach $responsible_record (@responsible_list) {
-        if (@$responsible_record[0] eq $name) {
-            return(@$responsible_record[1]);
-        }
-        if (defined(@$responsible_record[2])) {
-            if (@$responsible_record[2] eq $username) {
-                return(@$responsible_record[1]);
-            }
-        }
-    }
-
-    return(&quot;&quot;);
-}
-
-sub detaint_string {
-    my ($str) = @_;
-    $str =~ m/^(.*)$/s;
-    $str = $1;
-}
-
-sub SqlQuote {
-    my ($str) = (@_);
-    $str =~ s/([\\\'])/\\$1/g;
-    $str =~ s/\0/\\0/g;
-    # If it's been SqlQuote()ed, then it's safe, so we tell -T that.
-    $str = detaint_string($str);
-    return &quot;'$str'&quot;;
-}
-
-sub unixdate2datetime {
-    my($bugid, $unixdate) = @_;
-    my($year, $month, $day, $hour, $min, $sec);
-
-    if (!split_unixdate($bugid, $unixdate, \$year, \$month, \$day, \$hour, \$min, \$sec)) {
-        return(&quot;&quot;);
-    }
-
-    return(&quot;$year-$month-$day $hour:$min:$sec&quot;);
-}
-
-sub unixdate2timestamp {
-    my($bugid, $unixdate) = @_;
-    my($year, $month, $day, $hour, $min, $sec);
-
-    if (!split_unixdate($bugid, $unixdate, \$year, \$month, \$day, \$hour, \$min, \$sec)) {
-        return(&quot;&quot;);
-    }
-
-    return(&quot;$year$month$day$hour$min$sec&quot;);
-}
-
-sub split_unixdate {
-    # &quot;Tue Jun  6 14:50:00 1995&quot;
-    # &quot;Mon Nov 20 17:03:11 [MST] 1995&quot;
-    # &quot;12/13/94&quot;
-    # &quot;jan 1, 1995&quot;
-    my($bugid, $unixdate, $year, $month, $day, $hour, $min, $sec) = @_;
-    my(@parts);
-
-    $$hour = &quot;00&quot;;
-    $$min = &quot;00&quot;;
-    $$sec = &quot;00&quot;;
-
-    @parts = split(/ +/, $unixdate);
-    if (@parts &gt;= 5) {
-        # year
-        $$year = $parts[4];
-        if ($$year =~ /[A-Z]{3}/) {
-            # Must be timezone, try next field.
-            $$year = $parts[5];
-        }
-        if ($$year =~ /\D/) {
-            warn &quot;$bugid: Error processing year part '$$year' of date '$unixdate'\n&quot;;
-            return(0);
-        }
-        if ($$year &lt; 30) {
-            $$year = &quot;20&quot; . $$year;
-        } elsif ($$year &lt; 100) {
-            $$year = &quot;19&quot; . $$year;
-        } elsif ($$year &lt; 1970 || $$year &gt; 2029) {
-            warn &quot;$bugid: Error processing year part '$$year' of date '$unixdate'\n&quot;;
-            return(0);
-        }
-
-        # month
-        $$month = $parts[1];
-        if ($$month =~ /\D/) {
-            if (!month2number($month)) {
-                warn &quot;$bugid: Error processing month part '$$month' of date '$unixdate'\n&quot;;
-                return(0);
-            }
-
-        } elsif ($$month &lt; 1 || $$month &gt; 12) {
-            warn &quot;$bugid: Error processing month part '$$month' of date '$unixdate'\n&quot;;
-            return(0);
-
-        } elsif (length($$month) == 1) {
-            $$month = &quot;0&quot; . $$month;
-        }
-
-        # day
-        $$day = $parts[2];
-        if ($$day &lt; 1 || $$day &gt; 31) {
-            warn &quot;$bugid: Error processing day part '$day' of date '$unixdate'\n&quot;;
-            return(0);
-
-        } elsif (length($$day) == 1) {
-            $$day = &quot;0&quot; . $$day;
-        }
-
-        @parts = split(/:/, $parts[3]);
-        $$hour = $parts[0];
-        $$min = $parts[1];
-        $$sec = $parts[2];
-
-        return(1);
-
-    } elsif (@parts == 3) {
-        # year
-        $$year = $parts[2];
-        if ($$year =~ /\D/) {
-            warn &quot;$bugid: Error processing year part '$$year' of date '$unixdate'\n&quot;;
-            return(0);
-        }
-        if ($$year &lt; 30) {
-            $$year = &quot;20&quot; . $$year;
-        } elsif ($$year &lt; 100) {
-            $$year = &quot;19&quot; . $$year;
-        } elsif ($$year &lt; 1970 || $$year &gt; 2029) {
-            warn &quot;$bugid: Error processing year part '$$year' of date '$unixdate'\n&quot;;
-            return(0);
-        }
-
-        # month
-        $$month = $parts[0];
-        if ($$month =~ /\D/) {
-            if (!month2number($month)) {
-                warn &quot;$bugid: Error processing month part '$$month' of date '$unixdate'\n&quot;;
-                return(0);
-            }
-
-        } elsif ($$month &lt; 1 || $$month &gt; 12) {
-            warn &quot;$bugid: Error processing month part '$$month' of date '$unixdate'\n&quot;;
-            return(0);
-
-        } elsif (length($$month) == 1) {
-            $$month = &quot;0&quot; . $$month;
-        }
-
-        # day
-        $$day = $parts[1];
-        $$day =~ s/,//;
-        if ($$day &lt; 1 || $$day &gt; 31) {
-            warn &quot;$bugid: Error processing day part '$day' of date '$unixdate'\n&quot;;
-            return(0);
-
-        } elsif (length($$day) == 1) {
-            $$day = &quot;0&quot; . $$day;
-        }
-
-        return(1);
-    }
-
-    @parts = split(/:/, $unixdate);
-    if (@parts == 3 &amp;&amp; length($unixdate) &lt;= 8) {
-        $$year = &quot;19&quot; . $parts[2];
-
-        $$month = $parts[0];
-        if (length($$month) == 1) {
-            $$month = &quot;0&quot; . $$month;
-        }
-
-        $$day = $parts[1];
-        if (length($$day) == 1) {
-            $$day = &quot;0&quot; . $$day;
-        }
-
-        return(1);
-    }
-
-    warn &quot;$bugid: Error processing date '$unixdate'\n&quot;;
-    return(0);
-}
-
-sub month2number {
-    my($month) = @_;
-
-    if ($$month =~ /jan/i) {
-        $$month = &quot;01&quot;;
-    } elsif ($$month =~ /feb/i) {
-        $$month = &quot;02&quot;;
-    } elsif ($$month =~ /mar/i) {
-        $$month = &quot;03&quot;;
-    } elsif ($$month =~ /apr/i) {
-        $$month = &quot;04&quot;;
-    } elsif ($$month =~ /may/i) {
-        $$month = &quot;05&quot;;
-    } elsif ($$month =~ /jun/i) {
-        $$month = &quot;06&quot;;
-    } elsif ($$month =~ /jul/i) {
-        $$month = &quot;07&quot;;
-    } elsif ($$month =~ /aug/i) {
-        $$month = &quot;08&quot;;
-    } elsif ($$month =~ /sep/i) {
-        $$month = &quot;09&quot;;
-    } elsif ($$month =~ /oct/i) {
-        $$month = &quot;10&quot;;
-    } elsif ($$month =~ /nov/i) {
-        $$month = &quot;11&quot;;
-    } elsif ($$month =~ /dec/i) {
-        $$month = &quot;12&quot;;
-    } else {
-        return(0);
-    }
-
-    return(1);
-}
-
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgcontribjb2bzpy"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/contrib/jb2bz.py (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/contrib/jb2bz.py        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/contrib/jb2bz.py        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -28,7 +28,7 @@
</span><span class="cx"> if not mimetypes.encodings_map.has_key('.bz2'):
</span><span class="cx">     mimetypes.encodings_map['.bz2'] = &quot;bzip2&quot;
</span><span class="cx"> 
</span><del>-bug_status='NEW'
</del><ins>+bug_status='CONFIRMED'
</ins><span class="cx"> component=&quot;default&quot;
</span><span class="cx"> version=&quot;&quot;
</span><span class="cx"> product=&quot;&quot; # this is required, the rest of these are defaulted as above
</span><span class="lines">@@ -265,8 +265,8 @@
</span><span class="cx"> Where OPTIONS are one or more of the following:
</span><span class="cx"> 
</span><span class="cx">   -h                This help information.
</span><del>-  -s STATUS         One of UNCONFIRMED, NEW, ASSIGNED, REOPENED, RESOLVED, VERIFIED, CLOSED
-                    (default is NEW)
</del><ins>+  -s STATUS         One of UNCONFIRMED, CONFIRMED, IN_PROGRESS, RESOLVED, VERIFIED
+                    (default is CONFIRMED)
</ins><span class="cx">   -c COMPONENT      The component to attach to each bug as it is important. This should be
</span><span class="cx">                     valid component for the Product.
</span><span class="cx">   -v VERSION        Version to assign to these defects.
</span><span class="lines">@@ -285,7 +285,7 @@
</span><span class="cx"> 
</span><span class="cx">     for o,a in opts:
</span><span class="cx">         if o == &quot;-s&quot;:
</span><del>-            if a in ('UNCONFIRMED','NEW','ASSIGNED','REOPENED','RESOLVED','VERIFIED','CLOSED'):
</del><ins>+            if a in ('UNCONFIRMED','CONFIRMED','IN_PROGRESS','RESOLVED','VERIFIED'):
</ins><span class="cx">                 bug_status = a
</span><span class="cx">         elif o == '-c':
</span><span class="cx">             component = a
</span><span class="cx">Property changes on: trunk/Websites/bugs.webkit.org/contrib/jb2bz.py
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkWebsitesbugswebkitorgcontribmergeuserspl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/contrib/merge-users.pl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/contrib/merge-users.pl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/contrib/merge-users.pl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -121,21 +121,13 @@
</span><span class="cx"> #     where fooN is the column to update, and barN1, barN2, ... are
</span><span class="cx"> #     the columns to take into account to avoid duplicated entries.
</span><span class="cx"> #     Note that the barNM columns are optional.
</span><del>-my $changes = {
-    # Tables affecting bugs.
-    bugs            =&gt; ['assigned_to', 'reporter', 'qa_contact'],
-    bugs_activity   =&gt; ['who'],
-    attachments     =&gt; ['submitter_id'],
-    flags           =&gt; ['setter_id', 'requestee_id'],
</del><ins>+#
+# We set the tables that require custom stuff (multiple columns to check)
+# here, but the simple stuff is all handled below by bz_get_related_fks.
+my %changes = (
</ins><span class="cx">     cc              =&gt; ['who bug_id'],
</span><del>-    longdescs       =&gt; ['who'],
-    votes           =&gt; ['who'],
</del><span class="cx">     # Tables affecting global behavior / other users.
</span><del>-    components      =&gt; ['initialowner', 'initialqacontact'],
</del><span class="cx">     component_cc    =&gt; ['user_id component_id'],
</span><del>-    quips           =&gt; ['userid'],
-    series          =&gt; ['creator'],
-    whine_events    =&gt; ['owner_userid'],
</del><span class="cx">     watch           =&gt; ['watcher watched', 'watched watcher'],
</span><span class="cx">     # Tables affecting the user directly.
</span><span class="cx">     namedqueries    =&gt; ['userid name'],
</span><span class="lines">@@ -143,18 +135,24 @@
</span><span class="cx">     user_group_map  =&gt; ['user_id group_id isbless grant_type'],
</span><span class="cx">     email_setting   =&gt; ['user_id relationship event'],
</span><span class="cx">     profile_setting =&gt; ['user_id setting_name'],
</span><del>-    profiles_activity =&gt; ['userid', 'who'], # Should activity be migrated?
</del><span class="cx"> 
</span><span class="cx">     # Only do it if mailto_type = 0, i.e is pointing to a user account!
</span><span class="cx">     # This requires to be done separately due to this condition.
</span><span class="cx">     whine_schedules =&gt; [], # ['mailto'],
</span><ins>+);
</ins><span class="cx"> 
</span><del>-    # Delete all old records for these tables; no migration.
-    logincookies    =&gt; [], # ['userid'],
-    tokens          =&gt; [], # ['userid'],
-    profiles        =&gt; [], # ['userid'],
-};
</del><ins>+my $userid_fks = $dbh-&gt;bz_get_related_fks('profiles', 'userid');
+foreach my $item (@$userid_fks) {
+    my ($table, $column) = @$item;
+    $changes{$table} ||= [];
+    push(@{ $changes{$table} }, $column);
+}
</ins><span class="cx"> 
</span><ins>+# Delete all old records for these tables; no migration.
+foreach my $table (qw(logincookies tokens profiles)) {
+    $changes{$table} = [];
+}
+
</ins><span class="cx"> # Start the transaction
</span><span class="cx"> $dbh-&gt;bz_start_transaction();
</span><span class="cx"> 
</span><span class="lines">@@ -163,8 +161,8 @@
</span><span class="cx"> $dbh-&gt;do('DELETE FROM tokens WHERE userid = ?', undef, $old_id);
</span><span class="cx"> 
</span><span class="cx"> # Migrate records from old user to new user.
</span><del>-foreach my $table (keys(%$changes)) {
-    foreach my $column_list (@{$changes-&gt;{$table}}) {
</del><ins>+foreach my $table (keys %changes) {
+    foreach my $column_list (@{ $changes{$table} }) {
</ins><span class="cx">         # Get all columns to consider. There is always at least
</span><span class="cx">         # one column given: the one to update.
</span><span class="cx">         my @columns = split(/[\s]+/, $column_list);
</span><span class="cx">Property changes on: trunk/Websites/bugs.webkit.org/contrib/merge-users.pl
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkWebsitesbugswebkitorgcontribnewyuish"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/contrib/new-yui.sh (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/contrib/new-yui.sh                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/contrib/new-yui.sh        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,17 @@
</span><ins>+#!/bin/sh
+#
+# Updates the version of YUI used by Bugzilla. Just pass the path to 
+# an unzipped yui release directory, like:
+#
+#  contrib/new-yui.sh /path/to/yui-2.8.1/
+#
+rsync -av --delete $1/build/ js/yui/
+cd js/yui
+rm -rf editor/ yuiloader-dom-event/
+find -name '*.js' -not -name '*-min.js' -not -name '*-dom-event.js' \
+     -exec rm -f {} \;
+find -name '*-skin.css' -exec rm -f {} \;
+find -depth -path '*/assets' -not -path './assets' -exec rm -rf {} \;
+rm assets/skins/sam/sprite.psd
+rm assets/skins/sam/skin.css
+rmdir utilities
</ins><span class="cx">Property changes on: trunk/Websites/bugs.webkit.org/contrib/new-yui.sh
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkWebsitesbugswebkitorgcontribrecodepl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/contrib/recode.pl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/contrib/recode.pl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/contrib/recode.pl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -24,10 +24,10 @@
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla;
</span><span class="cx"> use Bugzilla::Constants;
</span><ins>+use Bugzilla::Util qw(detect_encoding);
</ins><span class="cx"> 
</span><span class="cx"> use Digest::MD5 qw(md5_base64);
</span><span class="cx"> use Encode qw(encode decode resolve_alias is_utf8);
</span><del>-use Encode::Guess;
</del><span class="cx"> use Getopt::Long;
</span><span class="cx"> use Pod::Usage;
</span><span class="cx"> 
</span><span class="lines">@@ -72,61 +72,6 @@
</span><span class="cx">     return $truncated;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub do_guess {
-    my ($data) = @_;
-
-    my $encoding = detect($data);
-    $encoding = resolve_alias($encoding) if $encoding;
-
-    # Encode::Detect is bad at detecting certain charsets, but Encode::Guess
-    # is better at them. Here's the details:
-
-    # shiftjis, big5-eten, euc-kr, and euc-jp: (Encode::Detect
-    # tends to accidentally mis-detect UTF-8 strings as being
-    # these encodings.)
-    my @utf8_accidental = qw(shiftjis big5-eten euc-kr euc-jp);
-    if ($encoding &amp;&amp; grep($_ eq $encoding, @utf8_accidental)) {
-        $encoding = undef;
-        my $decoder = guess_encoding($data, @utf8_accidental);
-        $encoding = $decoder-&gt;name if ref $decoder;
-    }
-
-    # Encode::Detect sometimes mis-detects various ISO encodings as iso-8859-8,
-    # but Encode::Guess can usually tell which one it is.
-    if ($encoding &amp;&amp; $encoding eq 'iso-8859-8') {
-        my $decoded_as = guess_iso($data, 'iso-8859-8', 
-            # These are ordered this way because it gives the most 
-            # accurate results.
-            qw(iso-8859-7 iso-8859-2));
-        $encoding = $decoded_as if $decoded_as;
-    }
-
-    # Workaround for WebKit Bug 9630 which caused WebKit nightly builds
-    # to send non-breaking space characters (0xA0) when submitting
-    # textarea content to Bugzilla.
-    if (!$encoding) {
-        my $decoder = guess_encoding($data, qw(cp1252));
-        $encoding = $decoder-&gt;name if ref $decoder;
-    }
-
-    return $encoding;
-}
-
-# A helper for do_guess.
-sub guess_iso {
-    my ($data, $versus, @isos) = @_;
-
-    my $encoding;
-    foreach my $iso (@isos) {
-        my $decoder = guess_encoding($data, ($iso, $versus));
-        if (ref $decoder) {
-            $encoding = $decoder-&gt;name if ref $decoder;
-            last;
-        }
-    }
-    return $encoding;
-}
-
</del><span class="cx"> sub is_valid_utf8 {
</span><span class="cx">     my ($str) = @_;
</span><span class="cx">     Encode::_utf8_on($str);
</span><span class="lines">@@ -152,8 +97,6 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> if ($switch{'guess'}) {
</span><del>-    # Encode::Detect::Detector doesn't seem to return a true value.
-    # So we have to check if we can run detect.
</del><span class="cx">     if (!eval { require Encode::Detect::Detector }) {
</span><span class="cx">         my $root = ROOT_USER;
</span><span class="cx">         print STDERR &lt;&lt;EOT;
</span><span class="lines">@@ -165,8 +108,6 @@
</span><span class="cx"> EOT
</span><span class="cx">         exit;
</span><span class="cx">     }
</span><del>-
-    import Encode::Detect::Detector qw(detect);
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> my %overrides;
</span><span class="lines">@@ -266,7 +207,7 @@
</span><span class="cx"> 
</span><span class="cx">                 my $encoding;
</span><span class="cx">                 if ($switch{'guess'}) {
</span><del>-                    $encoding = do_guess($data);
</del><ins>+                    $encoding = detect_encoding($data);
</ins><span class="cx"> 
</span><span class="cx">                     # We only show failures if they don't appear to be
</span><span class="cx">                     # ASCII.
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgcontribsendbugmailpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/contrib/sendbugmail.pl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/contrib/sendbugmail.pl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/contrib/sendbugmail.pl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -4,8 +4,6 @@
</span><span class="cx"> #
</span><span class="cx"> # Nick Barnes, Ravenbrook Limited, 2004-04-01.
</span><span class="cx"> #
</span><del>-# $Id$
-# 
</del><span class="cx"> # Bugzilla email script for Bugzilla 2.17.4 and later.  Invoke this to send
</span><span class="cx"> # bugmail for a bug which has been changed directly in the database.
</span><span class="cx"> # This uses Bugzilla's own BugMail facility, and will email the
</span><span class="lines">@@ -58,13 +56,14 @@
</span><span class="cx">     print STDERR &quot;Changer \&quot;$changer\&quot; doesn't match email regular expression.\n&quot;;
</span><span class="cx">     usage();
</span><span class="cx"> }
</span><del>-if(!login_to_id($changer)) {
-    print STDERR &quot;\&quot;$changer\&quot; is not a login ID.\n&quot;;
</del><ins>+my $changer_user = new Bugzilla::User({ name =&gt; $changer });
+unless ($changer_user) {
+    print STDERR &quot;\&quot;$changer\&quot; is not a valid user.\n&quot;;
</ins><span class="cx">     usage();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> # Send the email.
</span><del>-my $outputref = Bugzilla::BugMail::Send($bugnum, {'changer' =&gt; $changer });
</del><ins>+my $outputref = Bugzilla::BugMail::Send($bugnum, {'changer' =&gt; $changer_user });
</ins><span class="cx"> 
</span><span class="cx"> # Report the results.
</span><span class="cx"> my $sent = scalar(@{$outputref-&gt;{sent}});
</span><span class="cx">Property changes on: trunk/Websites/bugs.webkit.org/contrib/sendbugmail.pl
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkWebsitesbugswebkitorgcontribsendunsentbugmailpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/contrib/sendunsentbugmail.pl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/contrib/sendunsentbugmail.pl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/contrib/sendunsentbugmail.pl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -35,7 +35,8 @@
</span><span class="cx">         'SELECT bug_id FROM bugs 
</span><span class="cx">           WHERE lastdiffed IS NULL
</span><span class="cx">              OR lastdiffed &lt; delta_ts 
</span><del>-            AND delta_ts &lt; NOW() - ' . $dbh-&gt;sql_interval(30, 'MINUTE') .
</del><ins>+            AND delta_ts &lt; ' 
+                . $dbh-&gt;sql_date_math('NOW()', '-', 30, 'MINUTE') .
</ins><span class="cx">      ' ORDER BY bug_id');
</span><span class="cx"> 
</span><span class="cx"> if (scalar(@$list) &gt; 0) {
</span><span class="cx">Property changes on: trunk/Websites/bugs.webkit.org/contrib/sendunsentbugmail.pl
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkWebsitesbugswebkitorgcontribyp_nomailsh"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/contrib/yp_nomail.sh (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/contrib/yp_nomail.sh        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/contrib/yp_nomail.sh        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,78 +0,0 @@
</span><del>-#!/bin/sh
-# -*- Mode: ksh -*-
-##############################################################################
-# $Id$
-# yp_nomail
-#
-# Our mail admins got annoyed when bugzilla kept sending email
-# to people who'd had bugzilla entries and left the company.  They
-# were no longer in the list of valid email users so it'd bounce.
-# Maintaining the 'data/nomail' file was a pain.  Luckily, our UNIX
-# admins list all the users that ever were, but the people who've left
-# have a distinct marker in their password file. For example:
-#
-# fired:*LK*:2053:1010:You're Fired Dude:/home/loser:/bin/false
-#
-# This script takes advantage of the &quot;*LK*&quot; convention seen via 
-# ypcat passwd and dumps those people into the nomail file. Any
-# manual additions are kept in a &quot;nomail.(domainname)&quot; file and 
-# appended to the list of yp lockouts every night via Cron
-#
-# 58 23 * * * /export/bugzilla/contrib/yp_nomail.sh &gt; /dev/null 2&gt;&amp;1
-#
-# Tak ( Mark Takacs ) 08/2000
-#
-# XXX: Maybe should crosscheck w/bugzilla users?
-##############################################################################
-
-####
-# Configure this section to suite yer installation
-####
-
-DOMAIN=`domainname`
-MOZILLA_HOME=&quot;/export/mozilla&quot;
-BUGZILLA_HOME=&quot;${MOZILLA_HOME}/bugzilla&quot;
-NOMAIL_DIR=&quot;${BUGZILLA_HOME}/data&quot;
-NOMAIL=&quot;${NOMAIL_DIR}/nomail&quot;
-NOMAIL_ETIME=&quot;${NOMAIL}.${DOMAIN}&quot;
-NOMAIL_YP=&quot;${NOMAIL}.yp&quot;
-FIRED_FLAG=&quot;\*LK\*&quot;
-
-YPCAT=&quot;/usr/bin/ypcat&quot;
-GREP=&quot;/usr/bin/grep&quot;
-SORT=&quot;/usr/bin/sort&quot;
-
-########################## no more config needed  #################
-
-# This dir comes w/Bugzilla. WAY too paranoid
-if [ ! -d ${NOMAIL_DIR} ] ; then
-    echo &quot;Creating $date_dir&quot;
-    mkdir -p ${NOMAIL_DIR}
-fi
-
-#
-# Do some (more) paranoid checking
-#
-touch ${NOMAIL}
-if [ ! -w ${NOMAIL} ] ; then
-    echo &quot;Can't write nomail file: ${NOMAIL} -- exiting&quot;
-    exit
-fi
-if [ ! -r ${NOMAIL_ETIME} ] ; then
-    echo &quot;Can't access custom nomail file: ${NOMAIL_ETIME} -- skipping&quot;
-    NOMAIL_ETIME=&quot;&quot;
-fi
-
-#
-# add all the people with '*LK*' password to the nomail list
-# XXX: maybe I should customize the *LK* string. Doh.
-#
-
-LOCKOUT=`$YPCAT passwd | $GREP &quot;${FIRED_FLAG}&quot; | cut -d: -f1 | sort &gt; ${NOMAIL_YP}`
-`cat ${NOMAIL_YP} ${NOMAIL_ETIME} &gt; ${NOMAIL}`
-
-exit
-
-
-# end
-
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgcreateaccountcgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/createaccount.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/createaccount.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/createaccount.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -31,47 +31,30 @@
</span><span class="cx"> use Bugzilla;
</span><span class="cx"> use Bugzilla::Constants;
</span><span class="cx"> use Bugzilla::Error;
</span><del>-use Bugzilla::User;
-use Bugzilla::BugMail;
-use Bugzilla::Util;
</del><ins>+use Bugzilla::Token;
</ins><span class="cx"> 
</span><span class="cx"> # Just in case someone already has an account, let them get the correct footer
</span><span class="cx"> # on an error message. The user is logged out just after the account is
</span><span class="cx"> # actually created.
</span><del>-Bugzilla-&gt;login(LOGIN_OPTIONAL);
-
-my $dbh = Bugzilla-&gt;dbh;
</del><ins>+my $user = Bugzilla-&gt;login(LOGIN_OPTIONAL);
</ins><span class="cx"> my $cgi = Bugzilla-&gt;cgi;
</span><span class="cx"> my $template = Bugzilla-&gt;template;
</span><del>-my $vars = {};
</del><ins>+my $vars = { doc_section =&gt; 'myaccount.html' };
</ins><span class="cx"> 
</span><del>-$vars-&gt;{'doc_section'} = 'myaccount.html';
-
</del><span class="cx"> print $cgi-&gt;header();
</span><span class="cx"> 
</span><del>-# If we're using LDAP for login, then we can't create a new account here.
-unless (Bugzilla-&gt;user-&gt;authorizer-&gt;user_can_create_account) {
-    ThrowUserError(&quot;auth_cant_create_account&quot;);
-}
-
-my $createexp = Bugzilla-&gt;params-&gt;{'createemailregexp'};
-unless ($createexp) {
-    ThrowUserError(&quot;account_creation_disabled&quot;);
-}
-
</del><ins>+$user-&gt;check_account_creation_enabled;
</ins><span class="cx"> my $login = $cgi-&gt;param('login');
</span><span class="cx"> 
</span><span class="cx"> if (defined($login)) {
</span><del>-    $login = Bugzilla::User-&gt;check_login_name_for_creation($login);
</del><ins>+    # Check the hash token to make sure this user actually submitted
+    # the create account form.
+    my $token = $cgi-&gt;param('token');
+    check_hash_token($token, ['create_account']);
+
+    $user-&gt;check_and_send_account_creation_confirmation($login);
</ins><span class="cx">     $vars-&gt;{'login'} = $login;
</span><span class="cx"> 
</span><del>-    if ($login !~ /$createexp/) {
-        ThrowUserError(&quot;account_creation_restricted&quot;);
-    }
-
-    # Create and send a token for this new account.
-    Bugzilla::Token::issue_new_user_account_token($login);
-
</del><span class="cx">     $template-&gt;process(&quot;account/created.html.tmpl&quot;, $vars)
</span><span class="cx">       || ThrowTemplateError($template-&gt;error());
</span><span class="cx">     exit;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgdescribecomponentscgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/describecomponents.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/describecomponents.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/describecomponents.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -32,20 +32,21 @@
</span><span class="cx"> use Bugzilla::Product;
</span><span class="cx"> 
</span><span class="cx"> my $user = Bugzilla-&gt;login();
</span><del>-
</del><span class="cx"> my $cgi = Bugzilla-&gt;cgi;
</span><del>-my $dbh = Bugzilla-&gt;dbh;
</del><span class="cx"> my $template = Bugzilla-&gt;template;
</span><span class="cx"> my $vars = {};
</span><span class="cx"> 
</span><span class="cx"> print $cgi-&gt;header();
</span><span class="cx"> 
</span><ins>+# This script does nothing but displaying mostly static data.
+Bugzilla-&gt;switch_to_shadow_db;
+
</ins><span class="cx"> my $product_name = trim($cgi-&gt;param('product') || '');
</span><span class="cx"> my $product = new Bugzilla::Product({'name' =&gt; $product_name});
</span><span class="cx"> 
</span><del>-unless ($product &amp;&amp; $user-&gt;can_enter_product($product-&gt;name)) {
</del><ins>+unless ($product &amp;&amp; $user-&gt;can_access_product($product-&gt;name)) {
</ins><span class="cx">     # Products which the user is allowed to see.
</span><del>-    my @products = @{$user-&gt;get_enterable_products};
</del><ins>+    my @products = @{$user-&gt;get_accessible_products};
</ins><span class="cx"> 
</span><span class="cx">     if (scalar(@products) == 0) {
</span><span class="cx">         ThrowUserError(&quot;no_products&quot;);
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgdescribekeywordscgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/describekeywords.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/describekeywords.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/describekeywords.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -35,6 +35,9 @@
</span><span class="cx"> my $template = Bugzilla-&gt;template;
</span><span class="cx"> my $vars = {};
</span><span class="cx"> 
</span><ins>+# Run queries against the shadow DB.
+Bugzilla-&gt;switch_to_shadow_db;
+
</ins><span class="cx"> $vars-&gt;{'keywords'} = Bugzilla::Keyword-&gt;get_all_with_bug_count();
</span><span class="cx"> $vars-&gt;{'caneditkeywords'} = Bugzilla-&gt;user-&gt;in_group(&quot;editkeywords&quot;);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgdocsencvsignore"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/docs/en/.cvsignore (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/docs/en/.cvsignore        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/docs/en/.cvsignore        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,3 +0,0 @@
</span><del>-txt
-pdf
-html
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgdocsenREADMEdocs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/docs/en/README.docs (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/docs/en/README.docs        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/docs/en/README.docs        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -42,7 +42,7 @@
</span><span class="cx"> 
</span><span class="cx"> Trying to set up an XML Docbook editing environment the 
</span><span class="cx"> first time can be a daunting task.
</span><del>-I use Linux-Mandrake, in part, because it has a fully-functional
</del><ins>+I use Mandriva Linux, in part, because it has a fully-functional
</ins><span class="cx"> XML Docbook editing environment included as part of the
</span><span class="cx"> distribution CD's.  If you have easier instructions for how to
</span><span class="cx"> do this for a particular Linux distribution or platform, please
</span><span class="lines">@@ -70,9 +70,9 @@
</span><span class="cx"> sgml-common
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-If you're getting these from RedHat, make sure you get the ones in the
</del><ins>+If you're getting these from Red Hat, make sure you get the ones in the
</ins><span class="cx"> rawhide area.  The ones in the 7.2 distribution are too old and don't
</span><del>-include the XML stuff.  The packages distrubuted with RedHat 8.0 and 9
</del><ins>+include the XML stuff.  The packages distrubuted with Red Hat Linux 8.0 and 9
</ins><span class="cx"> and known to work.
</span><span class="cx"> 
</span><span class="cx"> Download &quot;ldp.dsl&quot; from the Resources page on tldp.org.  This is the 
</span><span class="lines">@@ -91,7 +91,7 @@
</span><span class="cx"> Note the difference is the top one points to the HTML docbook stylesheet, 
</span><span class="cx"> and the next one points to the PRINT docbook stylesheet.
</span><span class="cx"> 
</span><del>-Also note that modifying ldp.dsl doesn't seem to be needed on RedHat 9.
</del><ins>+Also note that modifying ldp.dsl doesn't seem to be needed on Red Hat Linux 9.
</ins><span class="cx"> 
</span><span class="cx">   You know, this sure looks awful involved.  Anyway, once you have this in
</span><span class="cx"> place, add to your .bashrc:
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgdocsenimagesbzLifecyclepng"></a>
<div class="binary"><h4>Modified: trunk/Websites/bugs.webkit.org/docs/en/images/bzLifecycle.png</h4>
<pre class="diff"><span>
<span class="cx">(Binary files differ)
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgdocsenimagesbzLifecyclexml"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/docs/en/images/bzLifecycle.xml (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/docs/en/images/bzLifecycle.xml        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/docs/en/images/bzLifecycle.xml        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -62,17 +62,17 @@
</span><span class="cx">       &lt;/dia:composite&gt;
</span><span class="cx">     &lt;/dia:attribute&gt;
</span><span class="cx">   &lt;/dia:diagramdata&gt;
</span><del>-  &lt;dia:layer name=&quot;Background&quot; visible=&quot;true&quot;&gt;
</del><ins>+  &lt;dia:layer name=&quot;Background&quot; visible=&quot;true&quot; active=&quot;true&quot;&gt;
</ins><span class="cx">     &lt;dia:object type=&quot;Standard - Line&quot; version=&quot;0&quot; id=&quot;O0&quot;&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;21,0&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;25.05,2.6&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;20.5,-0.05;21.5,2.05&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;24.6882,2.55;25.4118,5.0618&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;conn_endpoints&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;21,0&quot;/&gt;
-        &lt;dia:point val=&quot;21,2&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;25.05,2.6&quot;/&gt;
+        &lt;dia:point val=&quot;25.05,4.95&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;numcp&quot;&gt;
</span><span class="cx">         &lt;dia:int val=&quot;2&quot;/&gt;
</span><span class="lines">@@ -87,76 +87,15 @@
</span><span class="cx">         &lt;dia:real val=&quot;0.5&quot;/&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:connections&gt;
</span><del>-        &lt;dia:connection handle=&quot;1&quot; to=&quot;O10&quot; connection=&quot;2&quot;/&gt;
</del><ins>+        &lt;dia:connection handle=&quot;1&quot; to=&quot;O4&quot; connection=&quot;2&quot;/&gt;
</ins><span class="cx">       &lt;/dia:connections&gt;
</span><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Standard - BezierLine&quot; version=&quot;0&quot; id=&quot;O1&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Standard - Line&quot; version=&quot;0&quot; id=&quot;O1&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;21,4&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
-        &lt;dia:rectangle val=&quot;15.5,3.95;21.05,7.05&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;bez_points&quot;&gt;
-        &lt;dia:point val=&quot;21,4&quot;/&gt;
-        &lt;dia:point val=&quot;21,6.95&quot;/&gt;
-        &lt;dia:point val=&quot;16,4&quot;/&gt;
-        &lt;dia:point val=&quot;16,7&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;corner_types&quot;&gt;
-        &lt;dia:enum val=&quot;0&quot;/&gt;
-        &lt;dia:enum val=&quot;0&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow&quot;&gt;
-        &lt;dia:enum val=&quot;22&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow_length&quot;&gt;
-        &lt;dia:real val=&quot;0.5&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow_width&quot;&gt;
-        &lt;dia:real val=&quot;0.5&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:connections&gt;
-        &lt;dia:connection handle=&quot;0&quot; to=&quot;O10&quot; connection=&quot;13&quot;/&gt;
-        &lt;dia:connection handle=&quot;3&quot; to=&quot;O11&quot; connection=&quot;2&quot;/&gt;
-      &lt;/dia:connections&gt;
-    &lt;/dia:object&gt;
-    &lt;dia:object type=&quot;Standard - BezierLine&quot; version=&quot;0&quot; id=&quot;O2&quot;&gt;
-      &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
-        &lt;dia:point val=&quot;10,4&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
-        &lt;dia:rectangle val=&quot;9.95,3.95;16.5,7.05&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;bez_points&quot;&gt;
-        &lt;dia:point val=&quot;10,4&quot;/&gt;
-        &lt;dia:point val=&quot;10,7&quot;/&gt;
-        &lt;dia:point val=&quot;16,4&quot;/&gt;
-        &lt;dia:point val=&quot;16,7&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;corner_types&quot;&gt;
-        &lt;dia:enum val=&quot;0&quot;/&gt;
-        &lt;dia:enum val=&quot;0&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow&quot;&gt;
-        &lt;dia:enum val=&quot;22&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow_length&quot;&gt;
-        &lt;dia:real val=&quot;0.5&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow_width&quot;&gt;
-        &lt;dia:real val=&quot;0.5&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:connections&gt;
-        &lt;dia:connection handle=&quot;3&quot; to=&quot;O11&quot; connection=&quot;2&quot;/&gt;
-      &lt;/dia:connections&gt;
-    &lt;/dia:object&gt;
-    &lt;dia:object type=&quot;Standard - Line&quot; version=&quot;0&quot; id=&quot;O3&quot;&gt;
-      &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</del><span class="cx">         &lt;dia:point val=&quot;16,8.9&quot;/&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;15.5,8.85;16.5,12.05&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;15.6382,8.85;16.3618,12.1118&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;conn_endpoints&quot;&gt;
</span><span class="cx">         &lt;dia:point val=&quot;16,8.9&quot;/&gt;
</span><span class="lines">@@ -175,44 +114,16 @@
</span><span class="cx">         &lt;dia:real val=&quot;0.5&quot;/&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:connections&gt;
</span><del>-        &lt;dia:connection handle=&quot;0&quot; to=&quot;O11&quot; connection=&quot;13&quot;/&gt;
-        &lt;dia:connection handle=&quot;1&quot; to=&quot;O12&quot; connection=&quot;2&quot;/&gt;
</del><ins>+        &lt;dia:connection handle=&quot;0&quot; to=&quot;O5&quot; connection=&quot;13&quot;/&gt;
+        &lt;dia:connection handle=&quot;1&quot; to=&quot;O6&quot; connection=&quot;2&quot;/&gt;
</ins><span class="cx">       &lt;/dia:connections&gt;
</span><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Standard - Arc&quot; version=&quot;0&quot; id=&quot;O4&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Standard - Line&quot; version=&quot;0&quot; id=&quot;O2&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;13,13&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
-        &lt;dia:rectangle val=&quot;10.95,7.9;13.5,13.05&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;conn_endpoints&quot;&gt;
-        &lt;dia:point val=&quot;13,13&quot;/&gt;
-        &lt;dia:point val=&quot;13,7.95&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;curve_distance&quot;&gt;
-        &lt;dia:real val=&quot;-1.9999999999999998&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow&quot;&gt;
-        &lt;dia:enum val=&quot;22&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow_length&quot;&gt;
-        &lt;dia:real val=&quot;0.5&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow_width&quot;&gt;
-        &lt;dia:real val=&quot;0.5&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:connections&gt;
-        &lt;dia:connection handle=&quot;0&quot; to=&quot;O12&quot; connection=&quot;7&quot;/&gt;
-        &lt;dia:connection handle=&quot;1&quot; to=&quot;O11&quot; connection=&quot;7&quot;/&gt;
-      &lt;/dia:connections&gt;
-    &lt;/dia:object&gt;
-    &lt;dia:object type=&quot;Standard - Line&quot; version=&quot;0&quot; id=&quot;O5&quot;&gt;
-      &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</del><span class="cx">         &lt;dia:point val=&quot;16,14&quot;/&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;15.5,13.95;16.5,17.05&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;15.6382,13.95;16.3618,17.1118&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;conn_endpoints&quot;&gt;
</span><span class="cx">         &lt;dia:point val=&quot;16,14&quot;/&gt;
</span><span class="lines">@@ -231,37 +142,22 @@
</span><span class="cx">         &lt;dia:real val=&quot;0.5&quot;/&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:connections&gt;
</span><del>-        &lt;dia:connection handle=&quot;0&quot; to=&quot;O12&quot; connection=&quot;13&quot;/&gt;
-        &lt;dia:connection handle=&quot;1&quot; to=&quot;O13&quot; connection=&quot;2&quot;/&gt;
</del><ins>+        &lt;dia:connection handle=&quot;0&quot; to=&quot;O6&quot; connection=&quot;13&quot;/&gt;
+        &lt;dia:connection handle=&quot;1&quot; to=&quot;O7&quot; connection=&quot;2&quot;/&gt;
</ins><span class="cx">       &lt;/dia:connections&gt;
</span><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Standard - Line&quot; version=&quot;0&quot; id=&quot;O6&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Standard - BezierLine&quot; version=&quot;0&quot; id=&quot;O3&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;10,3&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
-        &lt;dia:rectangle val=&quot;9.95,2.95;10.05,4.05&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;conn_endpoints&quot;&gt;
-        &lt;dia:point val=&quot;10,3&quot;/&gt;
-        &lt;dia:point val=&quot;10,4&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;numcp&quot;&gt;
-        &lt;dia:int val=&quot;2&quot;/&gt;
-      &lt;/dia:attribute&gt;
-    &lt;/dia:object&gt;
-    &lt;dia:object type=&quot;Standard - BezierLine&quot; version=&quot;0&quot; id=&quot;O7&quot;&gt;
-      &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</del><span class="cx">         &lt;dia:point val=&quot;16,18.9&quot;/&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;15.95,18.85;21.5,22.05&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;15.6382,18.85;16.3618,22.2&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;bez_points&quot;&gt;
</span><span class="cx">         &lt;dia:point val=&quot;16,18.9&quot;/&gt;
</span><span class="cx">         &lt;dia:point val=&quot;16,22&quot;/&gt;
</span><del>-        &lt;dia:point val=&quot;21,19&quot;/&gt;
-        &lt;dia:point val=&quot;21,22&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;16,19.2&quot;/&gt;
+        &lt;dia:point val=&quot;16,22.2&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;corner_types&quot;&gt;
</span><span class="cx">         &lt;dia:enum val=&quot;0&quot;/&gt;
</span><span class="lines">@@ -277,87 +173,28 @@
</span><span class="cx">         &lt;dia:real val=&quot;0.5&quot;/&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:connections&gt;
</span><del>-        &lt;dia:connection handle=&quot;0&quot; to=&quot;O13&quot; connection=&quot;13&quot;/&gt;
-        &lt;dia:connection handle=&quot;3&quot; to=&quot;O14&quot; connection=&quot;2&quot;/&gt;
</del><ins>+        &lt;dia:connection handle=&quot;0&quot; to=&quot;O7&quot; connection=&quot;13&quot;/&gt;
+        &lt;dia:connection handle=&quot;3&quot; to=&quot;O8&quot; connection=&quot;2&quot;/&gt;
</ins><span class="cx">       &lt;/dia:connections&gt;
</span><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Standard - BezierLine&quot; version=&quot;0&quot; id=&quot;O8&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Flowchart - Box&quot; version=&quot;0&quot; id=&quot;O4&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;16,18.9&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;21.81,4.95&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;9.5,18.85;16.05,22.05&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;21.76,4.9;28.34,7&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><del>-      &lt;dia:attribute name=&quot;bez_points&quot;&gt;
-        &lt;dia:point val=&quot;16,18.9&quot;/&gt;
-        &lt;dia:point val=&quot;16,22&quot;/&gt;
-        &lt;dia:point val=&quot;10,19&quot;/&gt;
-        &lt;dia:point val=&quot;10,22&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;corner_types&quot;&gt;
-        &lt;dia:enum val=&quot;0&quot;/&gt;
-        &lt;dia:enum val=&quot;0&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow&quot;&gt;
-        &lt;dia:enum val=&quot;22&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow_length&quot;&gt;
-        &lt;dia:real val=&quot;0.5&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow_width&quot;&gt;
-        &lt;dia:real val=&quot;0.5&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:connections&gt;
-        &lt;dia:connection handle=&quot;0&quot; to=&quot;O13&quot; connection=&quot;13&quot;/&gt;
-        &lt;dia:connection handle=&quot;3&quot; to=&quot;O15&quot; connection=&quot;2&quot;/&gt;
-      &lt;/dia:connections&gt;
-    &lt;/dia:object&gt;
-    &lt;dia:object type=&quot;Standard - Arc&quot; version=&quot;0&quot; id=&quot;O9&quot;&gt;
-      &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
-        &lt;dia:point val=&quot;8.5,22&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
-        &lt;dia:rectangle val=&quot;8.4318,13.5624;13.6055,22.0682&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;conn_endpoints&quot;&gt;
-        &lt;dia:point val=&quot;8.5,22&quot;/&gt;
-        &lt;dia:point val=&quot;13.1464,13.8536&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;curve_distance&quot;&gt;
-        &lt;dia:real val=&quot;-0.71725063066182693&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow&quot;&gt;
-        &lt;dia:enum val=&quot;22&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow_length&quot;&gt;
-        &lt;dia:real val=&quot;0.5&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow_width&quot;&gt;
-        &lt;dia:real val=&quot;0.5&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:connections&gt;
-        &lt;dia:connection handle=&quot;0&quot; to=&quot;O15&quot; connection=&quot;1&quot;/&gt;
-        &lt;dia:connection handle=&quot;1&quot; to=&quot;O12&quot; connection=&quot;11&quot;/&gt;
-      &lt;/dia:connections&gt;
-    &lt;/dia:object&gt;
-    &lt;dia:object type=&quot;Flowchart - Box&quot; version=&quot;0&quot; id=&quot;O10&quot;&gt;
-      &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
-        &lt;dia:point val=&quot;17.9,2&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
-        &lt;dia:rectangle val=&quot;17.85,1.95;24.15,4.05&quot;/&gt;
-      &lt;/dia:attribute&gt;
</del><span class="cx">       &lt;dia:attribute name=&quot;elem_corner&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;17.9,2&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;21.81,4.95&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;elem_width&quot;&gt;
</span><del>-        &lt;dia:real val=&quot;6.1999999999999993&quot;/&gt;
</del><ins>+        &lt;dia:real val=&quot;6.480000001490116&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;elem_height&quot;&gt;
</span><span class="cx">         &lt;dia:real val=&quot;2&quot;/&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><del>-      &lt;dia:attribute name=&quot;inner_color&quot;&gt;
-        &lt;dia:color val=&quot;#e5e5e5&quot;/&gt;
</del><ins>+      &lt;dia:attribute name=&quot;border_width&quot;&gt;
+        &lt;dia:real val=&quot;0.10000000149011612&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;show_background&quot;&gt;
</span><span class="cx">         &lt;dia:boolean val=&quot;true&quot;/&gt;
</span><span class="lines">@@ -374,13 +211,13 @@
</span><span class="cx">             &lt;dia:string&gt;#UNCONFIRMED#&lt;/dia:string&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;font&quot;&gt;
</span><del>-            &lt;dia:font family=&quot;sans&quot; style=&quot;80&quot; name=&quot;Helvetica&quot;/&gt;
</del><ins>+            &lt;dia:font family=&quot;sans&quot; style=&quot;80&quot; name=&quot;Helvetica-Bold&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;height&quot;&gt;
</span><span class="cx">             &lt;dia:real val=&quot;0.80000000000000004&quot;/&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;pos&quot;&gt;
</span><del>-            &lt;dia:point val=&quot;21,3.3&quot;/&gt;
</del><ins>+            &lt;dia:point val=&quot;25.05,6.145&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;color&quot;&gt;
</span><span class="cx">             &lt;dia:color val=&quot;#000000&quot;/&gt;
</span><span class="lines">@@ -391,7 +228,7 @@
</span><span class="cx">         &lt;/dia:composite&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Flowchart - Box&quot; version=&quot;0&quot; id=&quot;O11&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Flowchart - Box&quot; version=&quot;0&quot; id=&quot;O5&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><span class="cx">         &lt;dia:point val=&quot;13,7&quot;/&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="lines">@@ -419,16 +256,16 @@
</span><span class="cx">       &lt;dia:attribute name=&quot;text&quot;&gt;
</span><span class="cx">         &lt;dia:composite type=&quot;text&quot;&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;string&quot;&gt;
</span><del>-            &lt;dia:string&gt;#NEW#&lt;/dia:string&gt;
</del><ins>+            &lt;dia:string&gt;#CONFIRMED#&lt;/dia:string&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;font&quot;&gt;
</span><del>-            &lt;dia:font family=&quot;sans&quot; style=&quot;80&quot; name=&quot;Helvetica&quot;/&gt;
</del><ins>+            &lt;dia:font family=&quot;sans&quot; style=&quot;80&quot; name=&quot;Helvetica-Bold&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;height&quot;&gt;
</span><span class="cx">             &lt;dia:real val=&quot;0.80000000000000004&quot;/&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;pos&quot;&gt;
</span><del>-            &lt;dia:point val=&quot;16,8.25&quot;/&gt;
</del><ins>+            &lt;dia:point val=&quot;16,8.145&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;color&quot;&gt;
</span><span class="cx">             &lt;dia:color val=&quot;#000000&quot;/&gt;
</span><span class="lines">@@ -439,18 +276,18 @@
</span><span class="cx">         &lt;/dia:composite&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Flowchart - Box&quot; version=&quot;0&quot; id=&quot;O12&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Flowchart - Box&quot; version=&quot;0&quot; id=&quot;O6&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;13,12&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;12.9625,12&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;12.95,11.95;19.05,14.05&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;12.9125,11.95;19.0875,14.05&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;elem_corner&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;13,12&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;12.9625,12&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;elem_width&quot;&gt;
</span><del>-        &lt;dia:real val=&quot;6&quot;/&gt;
</del><ins>+        &lt;dia:real val=&quot;6.0749999999999993&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;elem_height&quot;&gt;
</span><span class="cx">         &lt;dia:real val=&quot;2&quot;/&gt;
</span><span class="lines">@@ -467,16 +304,16 @@
</span><span class="cx">       &lt;dia:attribute name=&quot;text&quot;&gt;
</span><span class="cx">         &lt;dia:composite type=&quot;text&quot;&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;string&quot;&gt;
</span><del>-            &lt;dia:string&gt;#ASSIGNED#&lt;/dia:string&gt;
</del><ins>+            &lt;dia:string&gt;#IN_PROGRESS#&lt;/dia:string&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;font&quot;&gt;
</span><del>-            &lt;dia:font family=&quot;sans&quot; style=&quot;80&quot; name=&quot;Helvetica&quot;/&gt;
</del><ins>+            &lt;dia:font family=&quot;sans&quot; style=&quot;80&quot; name=&quot;Helvetica-Bold&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;height&quot;&gt;
</span><span class="cx">             &lt;dia:real val=&quot;0.80000000000000004&quot;/&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;pos&quot;&gt;
</span><del>-            &lt;dia:point val=&quot;16,13.3&quot;/&gt;
</del><ins>+            &lt;dia:point val=&quot;16,13.195&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;color&quot;&gt;
</span><span class="cx">             &lt;dia:color val=&quot;#000000&quot;/&gt;
</span><span class="lines">@@ -487,7 +324,7 @@
</span><span class="cx">         &lt;/dia:composite&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Flowchart - Box&quot; version=&quot;0&quot; id=&quot;O13&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Flowchart - Box&quot; version=&quot;0&quot; id=&quot;O7&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><span class="cx">         &lt;dia:point val=&quot;13,17&quot;/&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="lines">@@ -521,13 +358,13 @@
</span><span class="cx">             &lt;dia:string&gt;#RESOLVED#&lt;/dia:string&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;font&quot;&gt;
</span><del>-            &lt;dia:font family=&quot;sans&quot; style=&quot;80&quot; name=&quot;Helvetica&quot;/&gt;
</del><ins>+            &lt;dia:font family=&quot;sans&quot; style=&quot;80&quot; name=&quot;Helvetica-Bold&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;height&quot;&gt;
</span><span class="cx">             &lt;dia:real val=&quot;0.80000000000000004&quot;/&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;pos&quot;&gt;
</span><del>-            &lt;dia:point val=&quot;16,18.25&quot;/&gt;
</del><ins>+            &lt;dia:point val=&quot;16,18.145&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;color&quot;&gt;
</span><span class="cx">             &lt;dia:color val=&quot;#000000&quot;/&gt;
</span><span class="lines">@@ -538,15 +375,15 @@
</span><span class="cx">         &lt;/dia:composite&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Flowchart - Box&quot; version=&quot;0&quot; id=&quot;O14&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Flowchart - Box&quot; version=&quot;0&quot; id=&quot;O8&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;18,22&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;13,22.2&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;17.95,21.95;24.05,23.95&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;12.95,22.15;19.05,24.15&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;elem_corner&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;18,22&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;13,22.2&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;elem_width&quot;&gt;
</span><span class="cx">         &lt;dia:real val=&quot;6&quot;/&gt;
</span><span class="lines">@@ -572,13 +409,13 @@
</span><span class="cx">             &lt;dia:string&gt;#VERIFIED#&lt;/dia:string&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;font&quot;&gt;
</span><del>-            &lt;dia:font family=&quot;sans&quot; style=&quot;80&quot; name=&quot;Helvetica&quot;/&gt;
</del><ins>+            &lt;dia:font family=&quot;sans&quot; style=&quot;80&quot; name=&quot;Helvetica-Bold&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;height&quot;&gt;
</span><span class="cx">             &lt;dia:real val=&quot;0.80000000000000004&quot;/&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;pos&quot;&gt;
</span><del>-            &lt;dia:point val=&quot;21,23.25&quot;/&gt;
</del><ins>+            &lt;dia:point val=&quot;16,23.345&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;color&quot;&gt;
</span><span class="cx">             &lt;dia:color val=&quot;#000000&quot;/&gt;
</span><span class="lines">@@ -589,69 +426,89 @@
</span><span class="cx">         &lt;/dia:composite&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Flowchart - Box&quot; version=&quot;0&quot; id=&quot;O15&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;1&quot; id=&quot;O9&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;7,22&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;17.75,5.0625&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;6.95,21.95;13.05,23.95&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;17.75,4.6175;21.6275,5.775&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><del>-      &lt;dia:attribute name=&quot;elem_corner&quot;&gt;
-        &lt;dia:point val=&quot;7,22&quot;/&gt;
</del><ins>+      &lt;dia:attribute name=&quot;text&quot;&gt;
+        &lt;dia:composite type=&quot;text&quot;&gt;
+          &lt;dia:attribute name=&quot;string&quot;&gt;
+            &lt;dia:string&gt;#Bug determined
+to be present#&lt;/dia:string&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;font&quot;&gt;
+            &lt;dia:font family=&quot;sans&quot; style=&quot;0&quot; name=&quot;Helvetica&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;height&quot;&gt;
+            &lt;dia:real val=&quot;0.59999999999999998&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;pos&quot;&gt;
+            &lt;dia:point val=&quot;17.75,5.0625&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;color&quot;&gt;
+            &lt;dia:color val=&quot;#000000&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;alignment&quot;&gt;
+            &lt;dia:enum val=&quot;0&quot;/&gt;
+          &lt;/dia:attribute&gt;
+        &lt;/dia:composite&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><del>-      &lt;dia:attribute name=&quot;elem_width&quot;&gt;
-        &lt;dia:real val=&quot;6&quot;/&gt;
</del><ins>+      &lt;dia:attribute name=&quot;valign&quot;&gt;
+        &lt;dia:enum val=&quot;3&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><del>-      &lt;dia:attribute name=&quot;elem_height&quot;&gt;
-        &lt;dia:real val=&quot;1.9000000000000001&quot;/&gt;
</del><ins>+    &lt;/dia:object&gt;
+    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;1&quot; id=&quot;O10&quot;&gt;
+      &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
+        &lt;dia:point val=&quot;16.3365,10.4&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><del>-      &lt;dia:attribute name=&quot;show_background&quot;&gt;
-        &lt;dia:boolean val=&quot;true&quot;/&gt;
</del><ins>+      &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
+        &lt;dia:rectangle val=&quot;16.3365,9.955;21.394,11.1125&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><del>-      &lt;dia:attribute name=&quot;corner_radius&quot;&gt;
-        &lt;dia:real val=&quot;0.5&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;padding&quot;&gt;
-        &lt;dia:real val=&quot;0.5&quot;/&gt;
-      &lt;/dia:attribute&gt;
</del><span class="cx">       &lt;dia:attribute name=&quot;text&quot;&gt;
</span><span class="cx">         &lt;dia:composite type=&quot;text&quot;&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;string&quot;&gt;
</span><del>-            &lt;dia:string&gt;#REOPEN#&lt;/dia:string&gt;
</del><ins>+            &lt;dia:string&gt;#Developer is working
+on the bug#&lt;/dia:string&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;font&quot;&gt;
</span><del>-            &lt;dia:font family=&quot;sans&quot; style=&quot;80&quot; name=&quot;Helvetica&quot;/&gt;
</del><ins>+            &lt;dia:font family=&quot;sans&quot; style=&quot;0&quot; name=&quot;Helvetica&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;height&quot;&gt;
</span><del>-            &lt;dia:real val=&quot;0.80000000000000004&quot;/&gt;
</del><ins>+            &lt;dia:real val=&quot;0.59999999999999998&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;pos&quot;&gt;
</span><del>-            &lt;dia:point val=&quot;10,23.25&quot;/&gt;
</del><ins>+            &lt;dia:point val=&quot;16.3365,10.4&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;color&quot;&gt;
</span><span class="cx">             &lt;dia:color val=&quot;#000000&quot;/&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;alignment&quot;&gt;
</span><del>-            &lt;dia:enum val=&quot;1&quot;/&gt;
</del><ins>+            &lt;dia:enum val=&quot;0&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">         &lt;/dia:composite&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><ins>+      &lt;dia:attribute name=&quot;valign&quot;&gt;
+        &lt;dia:enum val=&quot;3&quot;/&gt;
+      &lt;/dia:attribute&gt;
</ins><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Flowchart - Box&quot; version=&quot;0&quot; id=&quot;O16&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Flowchart - Box&quot; version=&quot;0&quot; id=&quot;O11&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;13,27&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;-1.03711,14.8573&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;12.95,26.95;19.05,28.95&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;-1.08711,14.8073;4.71289,20.1073&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;elem_corner&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;13,27&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;-1.03711,14.8573&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;elem_width&quot;&gt;
</span><del>-        &lt;dia:real val=&quot;6&quot;/&gt;
</del><ins>+        &lt;dia:real val=&quot;5.6999999999999993&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;elem_height&quot;&gt;
</span><del>-        &lt;dia:real val=&quot;1.9000000000000001&quot;/&gt;
</del><ins>+        &lt;dia:real val=&quot;5.1999999999999993&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;inner_color&quot;&gt;
</span><span class="cx">         &lt;dia:color val=&quot;#bfbfbf&quot;/&gt;
</span><span class="lines">@@ -660,316 +517,109 @@
</span><span class="cx">         &lt;dia:boolean val=&quot;true&quot;/&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;corner_radius&quot;&gt;
</span><del>-        &lt;dia:real val=&quot;0.5&quot;/&gt;
</del><ins>+        &lt;dia:real val=&quot;0.10000000000000001&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;padding&quot;&gt;
</span><del>-        &lt;dia:real val=&quot;0.5&quot;/&gt;
</del><ins>+        &lt;dia:real val=&quot;0.14999999999999999&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;text&quot;&gt;
</span><span class="cx">         &lt;dia:composite type=&quot;text&quot;&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;string&quot;&gt;
</span><del>-            &lt;dia:string&gt;#CLOSED#&lt;/dia:string&gt;
</del><ins>+            &lt;dia:string&gt;#Possible resolutions:
+  FIXED
+  DUPLICATE
+  WONTFIX
+  WORKSFORME
+  INVALID#&lt;/dia:string&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;font&quot;&gt;
</span><del>-            &lt;dia:font family=&quot;sans&quot; style=&quot;80&quot; name=&quot;Helvetica&quot;/&gt;
</del><ins>+            &lt;dia:font family=&quot;sans&quot; style=&quot;0&quot; name=&quot;Helvetica&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;height&quot;&gt;
</span><del>-            &lt;dia:real val=&quot;0.80000000000000004&quot;/&gt;
</del><ins>+            &lt;dia:real val=&quot;0.59999999999999998&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;pos&quot;&gt;
</span><del>-            &lt;dia:point val=&quot;16,28.25&quot;/&gt;
</del><ins>+            &lt;dia:point val=&quot;-0.93711,16.1023&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;color&quot;&gt;
</span><span class="cx">             &lt;dia:color val=&quot;#000000&quot;/&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;alignment&quot;&gt;
</span><del>-            &lt;dia:enum val=&quot;1&quot;/&gt;
</del><ins>+            &lt;dia:enum val=&quot;0&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">         &lt;/dia:composite&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Standard - BezierLine&quot; version=&quot;0&quot; id=&quot;O17&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Standard - Line&quot; version=&quot;0&quot; id=&quot;O12&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;21,23.9&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;4.66289,18.7573&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;15.5,23.85;21.05,27.05&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;4.63788,18.7286;13.1714,18.7823&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><del>-      &lt;dia:attribute name=&quot;bez_points&quot;&gt;
-        &lt;dia:point val=&quot;21,23.9&quot;/&gt;
-        &lt;dia:point val=&quot;21,27&quot;/&gt;
-        &lt;dia:point val=&quot;16,24&quot;/&gt;
-        &lt;dia:point val=&quot;16,27&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;corner_types&quot;&gt;
-        &lt;dia:enum val=&quot;0&quot;/&gt;
-        &lt;dia:enum val=&quot;0&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow&quot;&gt;
-        &lt;dia:enum val=&quot;22&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow_length&quot;&gt;
-        &lt;dia:real val=&quot;0.5&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow_width&quot;&gt;
-        &lt;dia:real val=&quot;0.5&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:connections&gt;
-        &lt;dia:connection handle=&quot;0&quot; to=&quot;O14&quot; connection=&quot;13&quot;/&gt;
-        &lt;dia:connection handle=&quot;3&quot; to=&quot;O16&quot; connection=&quot;2&quot;/&gt;
-      &lt;/dia:connections&gt;
-    &lt;/dia:object&gt;
-    &lt;dia:object type=&quot;Standard - BezierLine&quot; version=&quot;0&quot; id=&quot;O18&quot;&gt;
-      &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
-        &lt;dia:point val=&quot;19,17.95&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
-        &lt;dia:rectangle val=&quot;18.945,17.8995;25.05,28.4505&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;bez_points&quot;&gt;
-        &lt;dia:point val=&quot;19,17.95&quot;/&gt;
-        &lt;dia:point val=&quot;24,18&quot;/&gt;
-        &lt;dia:point val=&quot;25,21&quot;/&gt;
-        &lt;dia:point val=&quot;25,23&quot;/&gt;
-        &lt;dia:point val=&quot;25,25&quot;/&gt;
-        &lt;dia:point val=&quot;24,28&quot;/&gt;
-        &lt;dia:point val=&quot;19,27.95&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;corner_types&quot;&gt;
-        &lt;dia:enum val=&quot;0&quot;/&gt;
-        &lt;dia:enum val=&quot;0&quot;/&gt;
-        &lt;dia:enum val=&quot;0&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow&quot;&gt;
-        &lt;dia:enum val=&quot;22&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow_length&quot;&gt;
-        &lt;dia:real val=&quot;0.5&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow_width&quot;&gt;
-        &lt;dia:real val=&quot;0.5&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:connections&gt;
-        &lt;dia:connection handle=&quot;0&quot; to=&quot;O13&quot; connection=&quot;8&quot;/&gt;
-        &lt;dia:connection handle=&quot;6&quot; to=&quot;O16&quot; connection=&quot;8&quot;/&gt;
-      &lt;/dia:connections&gt;
-    &lt;/dia:object&gt;
-    &lt;dia:object type=&quot;Standard - Line&quot; version=&quot;0&quot; id=&quot;O19&quot;&gt;
-      &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
-        &lt;dia:point val=&quot;18,22.95&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
-        &lt;dia:rectangle val=&quot;12.95,22.45;18.05,23.45&quot;/&gt;
-      &lt;/dia:attribute&gt;
</del><span class="cx">       &lt;dia:attribute name=&quot;conn_endpoints&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;18,22.95&quot;/&gt;
-        &lt;dia:point val=&quot;13,22.95&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;4.66289,18.7573&quot;/&gt;
+        &lt;dia:point val=&quot;13.1464,18.7536&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;numcp&quot;&gt;
</span><span class="cx">         &lt;dia:int val=&quot;1&quot;/&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><del>-      &lt;dia:attribute name=&quot;end_arrow&quot;&gt;
-        &lt;dia:enum val=&quot;22&quot;/&gt;
</del><ins>+      &lt;dia:attribute name=&quot;line_width&quot;&gt;
+        &lt;dia:real val=&quot;0.050000000000000003&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><del>-      &lt;dia:attribute name=&quot;end_arrow_length&quot;&gt;
-        &lt;dia:real val=&quot;0.5&quot;/&gt;
</del><ins>+      &lt;dia:attribute name=&quot;line_style&quot;&gt;
+        &lt;dia:enum val=&quot;4&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><del>-      &lt;dia:attribute name=&quot;end_arrow_width&quot;&gt;
-        &lt;dia:real val=&quot;0.5&quot;/&gt;
-      &lt;/dia:attribute&gt;
</del><span class="cx">       &lt;dia:connections&gt;
</span><del>-        &lt;dia:connection handle=&quot;0&quot; to=&quot;O14&quot; connection=&quot;7&quot;/&gt;
-        &lt;dia:connection handle=&quot;1&quot; to=&quot;O15&quot; connection=&quot;8&quot;/&gt;
</del><ins>+        &lt;dia:connection handle=&quot;0&quot; to=&quot;O11&quot; connection=&quot;10&quot;/&gt;
+        &lt;dia:connection handle=&quot;1&quot; to=&quot;O7&quot; connection=&quot;11&quot;/&gt;
</ins><span class="cx">       &lt;/dia:connections&gt;
</span><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Standard - BezierLine&quot; version=&quot;0&quot; id=&quot;O20&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;1&quot; id=&quot;O13&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;14.5,27&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;16.4,15.6&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;9.5,23.85;14.5851,27.0575&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;16.4,15.155;19.8425,15.7125&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><del>-      &lt;dia:attribute name=&quot;bez_points&quot;&gt;
-        &lt;dia:point val=&quot;14.5,27&quot;/&gt;
-        &lt;dia:point val=&quot;15,24&quot;/&gt;
-        &lt;dia:point val=&quot;10,27&quot;/&gt;
-        &lt;dia:point val=&quot;10,23.9&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;corner_types&quot;&gt;
-        &lt;dia:enum val=&quot;0&quot;/&gt;
-        &lt;dia:enum val=&quot;0&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow&quot;&gt;
-        &lt;dia:enum val=&quot;22&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow_length&quot;&gt;
-        &lt;dia:real val=&quot;0.5&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow_width&quot;&gt;
-        &lt;dia:real val=&quot;0.5&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:connections&gt;
-        &lt;dia:connection handle=&quot;0&quot; to=&quot;O16&quot; connection=&quot;1&quot;/&gt;
-        &lt;dia:connection handle=&quot;3&quot; to=&quot;O15&quot; connection=&quot;13&quot;/&gt;
-      &lt;/dia:connections&gt;
-    &lt;/dia:object&gt;
-    &lt;dia:object type=&quot;Standard - Arc&quot; version=&quot;0&quot; id=&quot;O21&quot;&gt;
-      &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
-        &lt;dia:point val=&quot;8.5,22&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
-        &lt;dia:rectangle val=&quot;8.42939,17.5449;13.3716,22.0706&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;conn_endpoints&quot;&gt;
-        &lt;dia:point val=&quot;8.5,22&quot;/&gt;
-        &lt;dia:point val=&quot;13,17.95&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;curve_distance&quot;&gt;
-        &lt;dia:real val=&quot;-0.74169570721594136&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow&quot;&gt;
-        &lt;dia:enum val=&quot;22&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow_length&quot;&gt;
-        &lt;dia:real val=&quot;0.5&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow_width&quot;&gt;
-        &lt;dia:real val=&quot;0.5&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:connections&gt;
-        &lt;dia:connection handle=&quot;0&quot; to=&quot;O15&quot; connection=&quot;1&quot;/&gt;
-        &lt;dia:connection handle=&quot;1&quot; to=&quot;O13&quot; connection=&quot;7&quot;/&gt;
-      &lt;/dia:connections&gt;
-    &lt;/dia:object&gt;
-    &lt;dia:object type=&quot;Standard - Arc&quot; version=&quot;0&quot; id=&quot;O22&quot;&gt;
-      &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
-        &lt;dia:point val=&quot;19,7.95&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
-        &lt;dia:rectangle val=&quot;18.5,7.9;22.05,17.525&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;conn_endpoints&quot;&gt;
-        &lt;dia:point val=&quot;19,7.95&quot;/&gt;
-        &lt;dia:point val=&quot;19,17.475&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;curve_distance&quot;&gt;
-        &lt;dia:real val=&quot;-3&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow&quot;&gt;
-        &lt;dia:enum val=&quot;22&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow_length&quot;&gt;
-        &lt;dia:real val=&quot;0.5&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow_width&quot;&gt;
-        &lt;dia:real val=&quot;0.5&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:connections&gt;
-        &lt;dia:connection handle=&quot;0&quot; to=&quot;O11&quot; connection=&quot;8&quot;/&gt;
-        &lt;dia:connection handle=&quot;1&quot; to=&quot;O13&quot; connection=&quot;6&quot;/&gt;
-      &lt;/dia:connections&gt;
-    &lt;/dia:object&gt;
-    &lt;dia:object type=&quot;Standard - Arc&quot; version=&quot;0&quot; id=&quot;O23&quot;&gt;
-      &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
-        &lt;dia:point val=&quot;21,4&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
-        &lt;dia:rectangle val=&quot;18.4981,3.9432;23.6948,17.5979&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;conn_endpoints&quot;&gt;
-        &lt;dia:point val=&quot;21,4&quot;/&gt;
-        &lt;dia:point val=&quot;19,17.475&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;curve_distance&quot;&gt;
-        &lt;dia:real val=&quot;-3.5943353432190368&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow&quot;&gt;
-        &lt;dia:enum val=&quot;22&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow_length&quot;&gt;
-        &lt;dia:real val=&quot;0.5&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow_width&quot;&gt;
-        &lt;dia:real val=&quot;0.5&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:connections&gt;
-        &lt;dia:connection handle=&quot;0&quot; to=&quot;O10&quot; connection=&quot;13&quot;/&gt;
-        &lt;dia:connection handle=&quot;1&quot; to=&quot;O13&quot; connection=&quot;6&quot;/&gt;
-      &lt;/dia:connections&gt;
-    &lt;/dia:object&gt;
-    &lt;dia:object type=&quot;Standard - Arc&quot; version=&quot;0&quot; id=&quot;O24&quot;&gt;
-      &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
-        &lt;dia:point val=&quot;21,4&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
-        &lt;dia:rectangle val=&quot;18.5011,3.94034;21.8578,13.1573&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;conn_endpoints&quot;&gt;
-        &lt;dia:point val=&quot;21,4&quot;/&gt;
-        &lt;dia:point val=&quot;19,13&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;curve_distance&quot;&gt;
-        &lt;dia:real val=&quot;-1.6769027424613245&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow&quot;&gt;
-        &lt;dia:enum val=&quot;22&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow_length&quot;&gt;
-        &lt;dia:real val=&quot;0.5&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;end_arrow_width&quot;&gt;
-        &lt;dia:real val=&quot;0.5&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:connections&gt;
-        &lt;dia:connection handle=&quot;0&quot; to=&quot;O10&quot; connection=&quot;13&quot;/&gt;
-        &lt;dia:connection handle=&quot;1&quot; to=&quot;O12&quot; connection=&quot;8&quot;/&gt;
-      &lt;/dia:connections&gt;
-    &lt;/dia:object&gt;
-    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;0&quot; id=&quot;O25&quot;&gt;
-      &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
-        &lt;dia:point val=&quot;10.025,0.825&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
-        &lt;dia:rectangle val=&quot;7.2,0.225;12.85,3.225&quot;/&gt;
-      &lt;/dia:attribute&gt;
</del><span class="cx">       &lt;dia:attribute name=&quot;text&quot;&gt;
</span><span class="cx">         &lt;dia:composite type=&quot;text&quot;&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;string&quot;&gt;
</span><del>-            &lt;dia:string&gt;#New bug from a
-user with canconfirm
-or a product without
-UNCONFIRMED state#&lt;/dia:string&gt;
</del><ins>+            &lt;dia:string&gt;#Fix checked in#&lt;/dia:string&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;font&quot;&gt;
</span><span class="cx">             &lt;dia:font family=&quot;sans&quot; style=&quot;0&quot; name=&quot;Helvetica&quot;/&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;height&quot;&gt;
</span><del>-            &lt;dia:real val=&quot;0.69999999999999996&quot;/&gt;
</del><ins>+            &lt;dia:real val=&quot;0.59999999999999998&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;pos&quot;&gt;
</span><del>-            &lt;dia:point val=&quot;10.025,0.825&quot;/&gt;
</del><ins>+            &lt;dia:point val=&quot;16.4,15.6&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;color&quot;&gt;
</span><span class="cx">             &lt;dia:color val=&quot;#000000&quot;/&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;alignment&quot;&gt;
</span><del>-            &lt;dia:enum val=&quot;1&quot;/&gt;
</del><ins>+            &lt;dia:enum val=&quot;0&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">         &lt;/dia:composite&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><ins>+      &lt;dia:attribute name=&quot;valign&quot;&gt;
+        &lt;dia:enum val=&quot;3&quot;/&gt;
+      &lt;/dia:attribute&gt;
</ins><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;0&quot; id=&quot;O26&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;1&quot; id=&quot;O14&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;20.325,4.48321&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;8.2865,16.95&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;14.675,3.93321;20.325,5.28321&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;8.2865,16.505;12.294,17.6625&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;text&quot;&gt;
</span><span class="cx">         &lt;dia:composite type=&quot;text&quot;&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;string&quot;&gt;
</span><del>-            &lt;dia:string&gt;#Bug confirmed or
-receives enough votes#&lt;/dia:string&gt;
</del><ins>+            &lt;dia:string&gt;#QA not satisfied
+with the solution#&lt;/dia:string&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;font&quot;&gt;
</span><span class="cx">             &lt;dia:font family=&quot;sans&quot; style=&quot;0&quot; name=&quot;Helvetica&quot;/&gt;
</span><span class="lines">@@ -978,29 +628,32 @@
</span><span class="cx">             &lt;dia:real val=&quot;0.59999999999999998&quot;/&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;pos&quot;&gt;
</span><del>-            &lt;dia:point val=&quot;20.325,4.48321&quot;/&gt;
</del><ins>+            &lt;dia:point val=&quot;8.2865,16.95&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;color&quot;&gt;
</span><span class="cx">             &lt;dia:color val=&quot;#000000&quot;/&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;alignment&quot;&gt;
</span><del>-            &lt;dia:enum val=&quot;2&quot;/&gt;
</del><ins>+            &lt;dia:enum val=&quot;0&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">         &lt;/dia:composite&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><ins>+      &lt;dia:attribute name=&quot;valign&quot;&gt;
+        &lt;dia:enum val=&quot;3&quot;/&gt;
+      &lt;/dia:attribute&gt;
</ins><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;0&quot; id=&quot;O27&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;1&quot; id=&quot;O15&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;16.2865,10.1&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;16.2865,20.5&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;16.2865,9.55;20.3865,10.9&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;16.2865,20.055;20.6865,21.2125&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;text&quot;&gt;
</span><span class="cx">         &lt;dia:composite type=&quot;text&quot;&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;string&quot;&gt;
</span><del>-            &lt;dia:string&gt;#Developer takes
-possession#&lt;/dia:string&gt;
</del><ins>+            &lt;dia:string&gt;#QA verifies that
+the solution works#&lt;/dia:string&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;font&quot;&gt;
</span><span class="cx">             &lt;dia:font family=&quot;sans&quot; style=&quot;0&quot; name=&quot;Helvetica&quot;/&gt;
</span><span class="lines">@@ -1009,7 +662,7 @@
</span><span class="cx">             &lt;dia:real val=&quot;0.59999999999999998&quot;/&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;pos&quot;&gt;
</span><del>-            &lt;dia:point val=&quot;16.2865,10.1&quot;/&gt;
</del><ins>+            &lt;dia:point val=&quot;16.2865,20.5&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;color&quot;&gt;
</span><span class="cx">             &lt;dia:color val=&quot;#000000&quot;/&gt;
</span><span class="lines">@@ -1019,19 +672,21 @@
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">         &lt;/dia:composite&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><ins>+      &lt;dia:attribute name=&quot;valign&quot;&gt;
+        &lt;dia:enum val=&quot;3&quot;/&gt;
+      &lt;/dia:attribute&gt;
</ins><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;0&quot; id=&quot;O28&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;1&quot; id=&quot;O16&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;10.7629,9.45&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;6.4365,22.7&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;8.0629,8.8825;10.7804,10.285&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;6.4365,22.255;12.494,22.8125&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;text&quot;&gt;
</span><span class="cx">         &lt;dia:composite type=&quot;text&quot;&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;string&quot;&gt;
</span><del>-            &lt;dia:string&gt;#Ownership
-is changed#&lt;/dia:string&gt;
</del><ins>+            &lt;dia:string&gt;#Fix turns out to be wrong#&lt;/dia:string&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;font&quot;&gt;
</span><span class="cx">             &lt;dia:font family=&quot;sans&quot; style=&quot;0&quot; name=&quot;Helvetica&quot;/&gt;
</span><span class="lines">@@ -1040,29 +695,32 @@
</span><span class="cx">             &lt;dia:real val=&quot;0.59999999999999998&quot;/&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;pos&quot;&gt;
</span><del>-            &lt;dia:point val=&quot;10.7629,9.45&quot;/&gt;
</del><ins>+            &lt;dia:point val=&quot;6.4365,22.7&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;color&quot;&gt;
</span><span class="cx">             &lt;dia:color val=&quot;#000000&quot;/&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;alignment&quot;&gt;
</span><del>-            &lt;dia:enum val=&quot;2&quot;/&gt;
</del><ins>+            &lt;dia:enum val=&quot;0&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">         &lt;/dia:composite&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><ins>+      &lt;dia:attribute name=&quot;valign&quot;&gt;
+        &lt;dia:enum val=&quot;3&quot;/&gt;
+      &lt;/dia:attribute&gt;
</ins><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;0&quot; id=&quot;O29&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;1&quot; id=&quot;O17&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;21.4576,6.43623&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;22.8,22.15&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;17.3576,5.88623;21.4576,7.23623&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;22.8,21.705;27.85,22.8625&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;text&quot;&gt;
</span><span class="cx">         &lt;dia:composite type=&quot;text&quot;&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;string&quot;&gt;
</span><del>-            &lt;dia:string&gt;#Developer takes
-possession#&lt;/dia:string&gt;
</del><ins>+            &lt;dia:string&gt;#Bug is reopened,
+was never confirmed#&lt;/dia:string&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;font&quot;&gt;
</span><span class="cx">             &lt;dia:font family=&quot;sans&quot; style=&quot;0&quot; name=&quot;Helvetica&quot;/&gt;
</span><span class="lines">@@ -1071,63 +729,40 @@
</span><span class="cx">             &lt;dia:real val=&quot;0.59999999999999998&quot;/&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;pos&quot;&gt;
</span><del>-            &lt;dia:point val=&quot;21.4576,6.43623&quot;/&gt;
</del><ins>+            &lt;dia:point val=&quot;22.8,22.15&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;color&quot;&gt;
</span><span class="cx">             &lt;dia:color val=&quot;#000000&quot;/&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;alignment&quot;&gt;
</span><del>-            &lt;dia:enum val=&quot;2&quot;/&gt;
</del><ins>+            &lt;dia:enum val=&quot;0&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">         &lt;/dia:composite&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><ins>+      &lt;dia:attribute name=&quot;valign&quot;&gt;
+        &lt;dia:enum val=&quot;3&quot;/&gt;
+      &lt;/dia:attribute&gt;
</ins><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Flowchart - Box&quot; version=&quot;0&quot; id=&quot;O30&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;1&quot; id=&quot;O18&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;4.81289,11.0073&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;16,7.95&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;4.76289,10.9573;10.5629,16.2573&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;16,7.355;16,8.1&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><del>-      &lt;dia:attribute name=&quot;elem_corner&quot;&gt;
-        &lt;dia:point val=&quot;4.81289,11.0073&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;elem_width&quot;&gt;
-        &lt;dia:real val=&quot;5.6999999999999993&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;elem_height&quot;&gt;
-        &lt;dia:real val=&quot;5.1999999999999993&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;inner_color&quot;&gt;
-        &lt;dia:color val=&quot;#bfbfbf&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;show_background&quot;&gt;
-        &lt;dia:boolean val=&quot;true&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;corner_radius&quot;&gt;
-        &lt;dia:real val=&quot;0.10000000000000001&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;padding&quot;&gt;
-        &lt;dia:real val=&quot;0.14999999999999999&quot;/&gt;
-      &lt;/dia:attribute&gt;
</del><span class="cx">       &lt;dia:attribute name=&quot;text&quot;&gt;
</span><span class="cx">         &lt;dia:composite type=&quot;text&quot;&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;string&quot;&gt;
</span><del>-            &lt;dia:string&gt;#Possible resolutions:
-  FIXED
-  DUPLICATE
-  WONTFIX
-  WORKSFORME
-  INVALID#&lt;/dia:string&gt;
</del><ins>+            &lt;dia:string&gt;##&lt;/dia:string&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;font&quot;&gt;
</span><span class="cx">             &lt;dia:font family=&quot;sans&quot; style=&quot;0&quot; name=&quot;Helvetica&quot;/&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;height&quot;&gt;
</span><del>-            &lt;dia:real val=&quot;0.59999999999999998&quot;/&gt;
</del><ins>+            &lt;dia:real val=&quot;0.80000000000000004&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;pos&quot;&gt;
</span><del>-            &lt;dia:point val=&quot;4.91289,11.7573&quot;/&gt;
</del><ins>+            &lt;dia:point val=&quot;16,7.95&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;color&quot;&gt;
</span><span class="cx">             &lt;dia:color val=&quot;#000000&quot;/&gt;
</span><span class="lines">@@ -1137,53 +772,33 @@
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">         &lt;/dia:composite&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><del>-    &lt;/dia:object&gt;
-    &lt;dia:object type=&quot;Standard - Line&quot; version=&quot;0&quot; id=&quot;O31&quot;&gt;
-      &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
-        &lt;dia:point val=&quot;10.3629,14.9073&quot;/&gt;
</del><ins>+      &lt;dia:attribute name=&quot;valign&quot;&gt;
+        &lt;dia:enum val=&quot;3&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><del>-      &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
-        &lt;dia:rectangle val=&quot;10.3278,14.8722;13.1815,17.1815&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;conn_endpoints&quot;&gt;
-        &lt;dia:point val=&quot;10.3629,14.9073&quot;/&gt;
-        &lt;dia:point val=&quot;13.1464,17.1464&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;numcp&quot;&gt;
-        &lt;dia:int val=&quot;1&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;line_width&quot;&gt;
-        &lt;dia:real val=&quot;0.050000000000000003&quot;/&gt;
-      &lt;/dia:attribute&gt;
-      &lt;dia:attribute name=&quot;line_style&quot;&gt;
-        &lt;dia:enum val=&quot;4&quot;/&gt;
-      &lt;/dia:attribute&gt;
</del><span class="cx">       &lt;dia:connections&gt;
</span><del>-        &lt;dia:connection handle=&quot;0&quot; to=&quot;O30&quot; connection=&quot;10&quot;/&gt;
-        &lt;dia:connection handle=&quot;1&quot; to=&quot;O13&quot; connection=&quot;0&quot;/&gt;
</del><ins>+        &lt;dia:connection handle=&quot;0&quot; to=&quot;O5&quot; connection=&quot;16&quot;/&gt;
</ins><span class="cx">       &lt;/dia:connections&gt;
</span><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;0&quot; id=&quot;O32&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;1&quot; id=&quot;O19&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;16.299,15.3073&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;16.9,10.5125&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;16.299,14.7573;20.449,16.1073&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;16.9,9.9175;16.9,10.6625&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;text&quot;&gt;
</span><span class="cx">         &lt;dia:composite type=&quot;text&quot;&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;string&quot;&gt;
</span><del>-            &lt;dia:string&gt;#Development is
-finished with bug#&lt;/dia:string&gt;
</del><ins>+            &lt;dia:string&gt;##&lt;/dia:string&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;font&quot;&gt;
</span><span class="cx">             &lt;dia:font family=&quot;sans&quot; style=&quot;0&quot; name=&quot;Helvetica&quot;/&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;height&quot;&gt;
</span><del>-            &lt;dia:real val=&quot;0.59999999999999998&quot;/&gt;
</del><ins>+            &lt;dia:real val=&quot;0.80000000000000004&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;pos&quot;&gt;
</span><del>-            &lt;dia:point val=&quot;16.299,15.3073&quot;/&gt;
</del><ins>+            &lt;dia:point val=&quot;16.9,10.5125&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;color&quot;&gt;
</span><span class="cx">             &lt;dia:color val=&quot;#000000&quot;/&gt;
</span><span class="lines">@@ -1193,28 +808,30 @@
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">         &lt;/dia:composite&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><ins>+      &lt;dia:attribute name=&quot;valign&quot;&gt;
+        &lt;dia:enum val=&quot;3&quot;/&gt;
+      &lt;/dia:attribute&gt;
</ins><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;0&quot; id=&quot;O33&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;1&quot; id=&quot;O20&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;11.4365,21&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;19.55,15.6125&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;11.4365,20.45;15.5365,21.8&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;19.55,15.0175;19.55,15.7625&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;text&quot;&gt;
</span><span class="cx">         &lt;dia:composite type=&quot;text&quot;&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;string&quot;&gt;
</span><del>-            &lt;dia:string&gt;#QA not satisfied
-with solution#&lt;/dia:string&gt;
</del><ins>+            &lt;dia:string&gt;##&lt;/dia:string&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;font&quot;&gt;
</span><span class="cx">             &lt;dia:font family=&quot;sans&quot; style=&quot;0&quot; name=&quot;Helvetica&quot;/&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;height&quot;&gt;
</span><del>-            &lt;dia:real val=&quot;0.59999999999999998&quot;/&gt;
</del><ins>+            &lt;dia:real val=&quot;0.80000000000000004&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;pos&quot;&gt;
</span><del>-            &lt;dia:point val=&quot;11.4365,21&quot;/&gt;
</del><ins>+            &lt;dia:point val=&quot;19.55,15.6125&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;color&quot;&gt;
</span><span class="cx">             &lt;dia:color val=&quot;#000000&quot;/&gt;
</span><span class="lines">@@ -1224,28 +841,30 @@
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">         &lt;/dia:composite&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><ins>+      &lt;dia:attribute name=&quot;valign&quot;&gt;
+        &lt;dia:enum val=&quot;3&quot;/&gt;
+      &lt;/dia:attribute&gt;
</ins><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;0&quot; id=&quot;O34&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;1&quot; id=&quot;O21&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;16.8365,21.05&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;20.3,20.8625&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;16.8365,20.5;20.7365,21.85&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;20.3,20.2675;20.3,21.0125&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;text&quot;&gt;
</span><span class="cx">         &lt;dia:composite type=&quot;text&quot;&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;string&quot;&gt;
</span><del>-            &lt;dia:string&gt;#QA verifies
-solution worked#&lt;/dia:string&gt;
</del><ins>+            &lt;dia:string&gt;##&lt;/dia:string&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;font&quot;&gt;
</span><span class="cx">             &lt;dia:font family=&quot;sans&quot; style=&quot;0&quot; name=&quot;Helvetica&quot;/&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;height&quot;&gt;
</span><del>-            &lt;dia:real val=&quot;0.59999999999999998&quot;/&gt;
</del><ins>+            &lt;dia:real val=&quot;0.80000000000000004&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;pos&quot;&gt;
</span><del>-            &lt;dia:point val=&quot;16.8365,21.05&quot;/&gt;
</del><ins>+            &lt;dia:point val=&quot;20.3,20.8625&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;color&quot;&gt;
</span><span class="cx">             &lt;dia:color val=&quot;#000000&quot;/&gt;
</span><span class="lines">@@ -1255,27 +874,30 @@
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">         &lt;/dia:composite&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><ins>+      &lt;dia:attribute name=&quot;valign&quot;&gt;
+        &lt;dia:enum val=&quot;3&quot;/&gt;
+      &lt;/dia:attribute&gt;
</ins><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;0&quot; id=&quot;O35&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;1&quot; id=&quot;O22&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;17.224,25.875&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;20.2,20.8625&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;17.224,25.325;20.574,26.075&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;20.2,20.2675;20.2,21.0125&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;text&quot;&gt;
</span><span class="cx">         &lt;dia:composite type=&quot;text&quot;&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;string&quot;&gt;
</span><del>-            &lt;dia:string&gt;#Bug is closed#&lt;/dia:string&gt;
</del><ins>+            &lt;dia:string&gt;##&lt;/dia:string&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;font&quot;&gt;
</span><span class="cx">             &lt;dia:font family=&quot;sans&quot; style=&quot;0&quot; name=&quot;Helvetica&quot;/&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;height&quot;&gt;
</span><del>-            &lt;dia:real val=&quot;0.59999999999999998&quot;/&gt;
</del><ins>+            &lt;dia:real val=&quot;0.80000000000000004&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;pos&quot;&gt;
</span><del>-            &lt;dia:point val=&quot;17.224,25.875&quot;/&gt;
</del><ins>+            &lt;dia:point val=&quot;20.2,20.8625&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;color&quot;&gt;
</span><span class="cx">             &lt;dia:color val=&quot;#000000&quot;/&gt;
</span><span class="lines">@@ -1285,27 +907,30 @@
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">         &lt;/dia:composite&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><ins>+      &lt;dia:attribute name=&quot;valign&quot;&gt;
+        &lt;dia:enum val=&quot;3&quot;/&gt;
+      &lt;/dia:attribute&gt;
</ins><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;0&quot; id=&quot;O36&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;1&quot; id=&quot;O23&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;22.5365,18.5&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;19.75,21.0625&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;22.5365,17.95;25.8865,18.7&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;19.75,20.4675;19.75,21.2125&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;text&quot;&gt;
</span><span class="cx">         &lt;dia:composite type=&quot;text&quot;&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;string&quot;&gt;
</span><del>-            &lt;dia:string&gt;#Bug is closed#&lt;/dia:string&gt;
</del><ins>+            &lt;dia:string&gt;##&lt;/dia:string&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;font&quot;&gt;
</span><span class="cx">             &lt;dia:font family=&quot;sans&quot; style=&quot;0&quot; name=&quot;Helvetica&quot;/&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;height&quot;&gt;
</span><del>-            &lt;dia:real val=&quot;0.59999999999999998&quot;/&gt;
</del><ins>+            &lt;dia:real val=&quot;0.80000000000000004&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;pos&quot;&gt;
</span><del>-            &lt;dia:point val=&quot;22.5365,18.5&quot;/&gt;
</del><ins>+            &lt;dia:point val=&quot;19.75,21.0625&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;color&quot;&gt;
</span><span class="cx">             &lt;dia:color val=&quot;#000000&quot;/&gt;
</span><span class="lines">@@ -1315,59 +940,63 @@
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">         &lt;/dia:composite&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><ins>+      &lt;dia:attribute name=&quot;valign&quot;&gt;
+        &lt;dia:enum val=&quot;3&quot;/&gt;
+      &lt;/dia:attribute&gt;
</ins><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;0&quot; id=&quot;O37&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;1&quot; id=&quot;O24&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;9.62401,17.8111&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;12.8,1.5125&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;5.52401,17.2611;9.62401,18.6111&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;12.8,0.9175;12.8,1.6625&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;text&quot;&gt;
</span><span class="cx">         &lt;dia:composite type=&quot;text&quot;&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;string&quot;&gt;
</span><del>-            &lt;dia:string&gt;#Developer takes
-possession#&lt;/dia:string&gt;
</del><ins>+            &lt;dia:string&gt;##&lt;/dia:string&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;font&quot;&gt;
</span><span class="cx">             &lt;dia:font family=&quot;sans&quot; style=&quot;0&quot; name=&quot;Helvetica&quot;/&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;height&quot;&gt;
</span><del>-            &lt;dia:real val=&quot;0.59999999999999998&quot;/&gt;
</del><ins>+            &lt;dia:real val=&quot;0.80000000000000004&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;pos&quot;&gt;
</span><del>-            &lt;dia:point val=&quot;9.62401,17.8111&quot;/&gt;
</del><ins>+            &lt;dia:point val=&quot;12.8,1.5125&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;color&quot;&gt;
</span><span class="cx">             &lt;dia:color val=&quot;#000000&quot;/&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;alignment&quot;&gt;
</span><del>-            &lt;dia:enum val=&quot;2&quot;/&gt;
</del><ins>+            &lt;dia:enum val=&quot;0&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">         &lt;/dia:composite&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><ins>+      &lt;dia:attribute name=&quot;valign&quot;&gt;
+        &lt;dia:enum val=&quot;3&quot;/&gt;
+      &lt;/dia:attribute&gt;
</ins><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;0&quot; id=&quot;O38&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;1&quot; id=&quot;O25&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;11.1865,19.15&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;13.7,15.7625&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;11.1865,18.6;13.3365,19.95&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;13.7,15.1675;13.7,15.9125&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;text&quot;&gt;
</span><span class="cx">         &lt;dia:composite type=&quot;text&quot;&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;string&quot;&gt;
</span><del>-            &lt;dia:string&gt;#Issue is
-resolved#&lt;/dia:string&gt;
</del><ins>+            &lt;dia:string&gt;##&lt;/dia:string&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;font&quot;&gt;
</span><span class="cx">             &lt;dia:font family=&quot;sans&quot; style=&quot;0&quot; name=&quot;Helvetica&quot;/&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;height&quot;&gt;
</span><del>-            &lt;dia:real val=&quot;0.59999999999999998&quot;/&gt;
</del><ins>+            &lt;dia:real val=&quot;0.80000000000000004&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;pos&quot;&gt;
</span><del>-            &lt;dia:point val=&quot;11.1865,19.15&quot;/&gt;
</del><ins>+            &lt;dia:point val=&quot;13.7,15.7625&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;color&quot;&gt;
</span><span class="cx">             &lt;dia:color val=&quot;#000000&quot;/&gt;
</span><span class="lines">@@ -1377,27 +1006,31 @@
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">         &lt;/dia:composite&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><ins>+      &lt;dia:attribute name=&quot;valign&quot;&gt;
+        &lt;dia:enum val=&quot;3&quot;/&gt;
+      &lt;/dia:attribute&gt;
</ins><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;0&quot; id=&quot;O39&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;1&quot; id=&quot;O26&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;11.049,25.325&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;9.65,11.7125&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;11.049,24.775;15.049,25.525&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;9.65,11.2675;13.555,12.4247&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;text&quot;&gt;
</span><span class="cx">         &lt;dia:composite type=&quot;text&quot;&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;string&quot;&gt;
</span><del>-            &lt;dia:string&gt;#Bug is reopened#&lt;/dia:string&gt;
</del><ins>+            &lt;dia:string&gt;#Developer stops
+work on bug#&lt;/dia:string&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;font&quot;&gt;
</span><span class="cx">             &lt;dia:font family=&quot;sans&quot; style=&quot;0&quot; name=&quot;Helvetica&quot;/&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;height&quot;&gt;
</span><del>-            &lt;dia:real val=&quot;0.59999999999999998&quot;/&gt;
</del><ins>+            &lt;dia:real val=&quot;0.59972222571740919&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;pos&quot;&gt;
</span><del>-            &lt;dia:point val=&quot;11.049,25.325&quot;/&gt;
</del><ins>+            &lt;dia:point val=&quot;9.65,11.7125&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;color&quot;&gt;
</span><span class="cx">             &lt;dia:color val=&quot;#000000&quot;/&gt;
</span><span class="lines">@@ -1407,27 +1040,31 @@
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">         &lt;/dia:composite&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><ins>+      &lt;dia:attribute name=&quot;valign&quot;&gt;
+        &lt;dia:enum val=&quot;3&quot;/&gt;
+      &lt;/dia:attribute&gt;
</ins><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;0&quot; id=&quot;O40&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;1&quot; id=&quot;O27&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;13.9365,22.75&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;20.55,19.0625&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;13.9365,22.2;17.9365,22.95&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;20.55,18.6175;26.5875,19.7747&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;text&quot;&gt;
</span><span class="cx">         &lt;dia:composite type=&quot;text&quot;&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;string&quot;&gt;
</span><del>-            &lt;dia:string&gt;#Bug is reopened#&lt;/dia:string&gt;
</del><ins>+            &lt;dia:string&gt;#Bug is not fixable
+(e.g because it is invalid)#&lt;/dia:string&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;font&quot;&gt;
</span><span class="cx">             &lt;dia:font family=&quot;sans&quot; style=&quot;0&quot; name=&quot;Helvetica&quot;/&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;height&quot;&gt;
</span><del>-            &lt;dia:real val=&quot;0.59999999999999998&quot;/&gt;
</del><ins>+            &lt;dia:real val=&quot;0.59972222571740919&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;pos&quot;&gt;
</span><del>-            &lt;dia:point val=&quot;13.9365,22.75&quot;/&gt;
</del><ins>+            &lt;dia:point val=&quot;20.55,19.0625&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;color&quot;&gt;
</span><span class="cx">             &lt;dia:color val=&quot;#000000&quot;/&gt;
</span><span class="lines">@@ -1437,28 +1074,66 @@
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">         &lt;/dia:composite&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><ins>+      &lt;dia:attribute name=&quot;valign&quot;&gt;
+        &lt;dia:enum val=&quot;3&quot;/&gt;
+      &lt;/dia:attribute&gt;
</ins><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Standard - BezierLine&quot; version=&quot;0&quot; id=&quot;O41&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Standard - ZigZagLine&quot; version=&quot;1&quot; id=&quot;O28&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;19,17.95&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;12.9625,13&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;18.9494,3.46851;29.05,18.0006&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;9.3,8.0632;13.1118,13.05&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><del>-      &lt;dia:attribute name=&quot;bez_points&quot;&gt;
-        &lt;dia:point val=&quot;19,17.95&quot;/&gt;
-        &lt;dia:point val=&quot;23,18&quot;/&gt;
-        &lt;dia:point val=&quot;29,14&quot;/&gt;
-        &lt;dia:point val=&quot;29,11&quot;/&gt;
-        &lt;dia:point val=&quot;29,8&quot;/&gt;
-        &lt;dia:point val=&quot;27,7&quot;/&gt;
-        &lt;dia:point val=&quot;23.9286,3.85355&quot;/&gt;
</del><ins>+      &lt;dia:attribute name=&quot;orth_points&quot;&gt;
+        &lt;dia:point val=&quot;12.9625,13&quot;/&gt;
+        &lt;dia:point val=&quot;9.35,13&quot;/&gt;
+        &lt;dia:point val=&quot;9.35,8.425&quot;/&gt;
+        &lt;dia:point val=&quot;13,8.425&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><del>-      &lt;dia:attribute name=&quot;corner_types&quot;&gt;
</del><ins>+      &lt;dia:attribute name=&quot;orth_orient&quot;&gt;
</ins><span class="cx">         &lt;dia:enum val=&quot;0&quot;/&gt;
</span><ins>+        &lt;dia:enum val=&quot;1&quot;/&gt;
</ins><span class="cx">         &lt;dia:enum val=&quot;0&quot;/&gt;
</span><ins>+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;autorouting&quot;&gt;
+        &lt;dia:boolean val=&quot;false&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;end_arrow&quot;&gt;
+        &lt;dia:enum val=&quot;22&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;end_arrow_length&quot;&gt;
+        &lt;dia:real val=&quot;0.5&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;end_arrow_width&quot;&gt;
+        &lt;dia:real val=&quot;0.5&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:connections&gt;
+        &lt;dia:connection handle=&quot;0&quot; to=&quot;O6&quot; connection=&quot;7&quot;/&gt;
+        &lt;dia:connection handle=&quot;1&quot; to=&quot;O5&quot; connection=&quot;9&quot;/&gt;
+      &lt;/dia:connections&gt;
+    &lt;/dia:object&gt;
+    &lt;dia:object type=&quot;Standard - ZigZagLine&quot; version=&quot;1&quot; id=&quot;O29&quot;&gt;
+      &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
+        &lt;dia:point val=&quot;13,17.95&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
+        &lt;dia:rectangle val=&quot;7.65,7.5882;13.1118,18&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;orth_points&quot;&gt;
+        &lt;dia:point val=&quot;13,17.95&quot;/&gt;
+        &lt;dia:point val=&quot;7.7,17.95&quot;/&gt;
+        &lt;dia:point val=&quot;7.7,7.95&quot;/&gt;
+        &lt;dia:point val=&quot;13,7.95&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;orth_orient&quot;&gt;
</ins><span class="cx">         &lt;dia:enum val=&quot;0&quot;/&gt;
</span><ins>+        &lt;dia:enum val=&quot;1&quot;/&gt;
+        &lt;dia:enum val=&quot;0&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><ins>+      &lt;dia:attribute name=&quot;autorouting&quot;&gt;
+        &lt;dia:boolean val=&quot;false&quot;/&gt;
+      &lt;/dia:attribute&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;end_arrow&quot;&gt;
</span><span class="cx">         &lt;dia:enum val=&quot;22&quot;/&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="lines">@@ -1469,62 +1144,102 @@
</span><span class="cx">         &lt;dia:real val=&quot;0.5&quot;/&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:connections&gt;
</span><del>-        &lt;dia:connection handle=&quot;0&quot; to=&quot;O13&quot; connection=&quot;8&quot;/&gt;
-        &lt;dia:connection handle=&quot;6&quot; to=&quot;O10&quot; connection=&quot;15&quot;/&gt;
</del><ins>+        &lt;dia:connection handle=&quot;0&quot; to=&quot;O7&quot; connection=&quot;7&quot;/&gt;
+        &lt;dia:connection handle=&quot;1&quot; to=&quot;O5&quot; connection=&quot;7&quot;/&gt;
</ins><span class="cx">       &lt;/dia:connections&gt;
</span><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;0&quot; id=&quot;O42&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Standard - ZigZagLine&quot; version=&quot;1&quot; id=&quot;O30&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;24,10&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;13,23.15&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;24,9.45;28.15,10.8&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;5.9,7.1132;13.1118,23.2&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><del>-      &lt;dia:attribute name=&quot;text&quot;&gt;
-        &lt;dia:composite type=&quot;text&quot;&gt;
-          &lt;dia:attribute name=&quot;string&quot;&gt;
-            &lt;dia:string&gt;#Development is
-finished with bug#&lt;/dia:string&gt;
-          &lt;/dia:attribute&gt;
-          &lt;dia:attribute name=&quot;font&quot;&gt;
-            &lt;dia:font family=&quot;sans&quot; style=&quot;0&quot; name=&quot;Helvetica&quot;/&gt;
-          &lt;/dia:attribute&gt;
-          &lt;dia:attribute name=&quot;height&quot;&gt;
-            &lt;dia:real val=&quot;0.59999999999999998&quot;/&gt;
-          &lt;/dia:attribute&gt;
-          &lt;dia:attribute name=&quot;pos&quot;&gt;
-            &lt;dia:point val=&quot;24,10&quot;/&gt;
-          &lt;/dia:attribute&gt;
-          &lt;dia:attribute name=&quot;color&quot;&gt;
-            &lt;dia:color val=&quot;#000000&quot;/&gt;
-          &lt;/dia:attribute&gt;
-          &lt;dia:attribute name=&quot;alignment&quot;&gt;
-            &lt;dia:enum val=&quot;0&quot;/&gt;
-          &lt;/dia:attribute&gt;
-        &lt;/dia:composite&gt;
</del><ins>+      &lt;dia:attribute name=&quot;orth_points&quot;&gt;
+        &lt;dia:point val=&quot;13,23.15&quot;/&gt;
+        &lt;dia:point val=&quot;5.95,23.15&quot;/&gt;
+        &lt;dia:point val=&quot;5.95,7.475&quot;/&gt;
+        &lt;dia:point val=&quot;13,7.475&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><ins>+      &lt;dia:attribute name=&quot;orth_orient&quot;&gt;
+        &lt;dia:enum val=&quot;0&quot;/&gt;
+        &lt;dia:enum val=&quot;1&quot;/&gt;
+        &lt;dia:enum val=&quot;0&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;autorouting&quot;&gt;
+        &lt;dia:boolean val=&quot;false&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;line_style&quot;&gt;
+        &lt;dia:enum val=&quot;4&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;end_arrow&quot;&gt;
+        &lt;dia:enum val=&quot;22&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;end_arrow_length&quot;&gt;
+        &lt;dia:real val=&quot;0.5&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;end_arrow_width&quot;&gt;
+        &lt;dia:real val=&quot;0.5&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:connections&gt;
+        &lt;dia:connection handle=&quot;0&quot; to=&quot;O8&quot; connection=&quot;7&quot;/&gt;
+        &lt;dia:connection handle=&quot;1&quot; to=&quot;O5&quot; connection=&quot;5&quot;/&gt;
+      &lt;/dia:connections&gt;
</ins><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Standard - BezierLine&quot; version=&quot;0&quot; id=&quot;O43&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Standard - ZigZagLine&quot; version=&quot;1&quot; id=&quot;O31&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;23.8536,22.1464&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;19.0498,7.95&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;23.5359,3.46851;29.0712,22.2033&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;18.8882,7.9;22.7,17.8368&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><del>-      &lt;dia:attribute name=&quot;bez_points&quot;&gt;
-        &lt;dia:point val=&quot;23.8536,22.1464&quot;/&gt;
-        &lt;dia:point val=&quot;29.6426,21.2696&quot;/&gt;
-        &lt;dia:point val=&quot;29,14&quot;/&gt;
-        &lt;dia:point val=&quot;29,11&quot;/&gt;
-        &lt;dia:point val=&quot;29,8&quot;/&gt;
-        &lt;dia:point val=&quot;27,7&quot;/&gt;
-        &lt;dia:point val=&quot;23.9286,3.85355&quot;/&gt;
</del><ins>+      &lt;dia:attribute name=&quot;orth_points&quot;&gt;
+        &lt;dia:point val=&quot;19.0498,7.95&quot;/&gt;
+        &lt;dia:point val=&quot;22.65,7.95&quot;/&gt;
+        &lt;dia:point val=&quot;22.65,17.475&quot;/&gt;
+        &lt;dia:point val=&quot;19,17.475&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><del>-      &lt;dia:attribute name=&quot;corner_types&quot;&gt;
</del><ins>+      &lt;dia:attribute name=&quot;orth_orient&quot;&gt;
</ins><span class="cx">         &lt;dia:enum val=&quot;0&quot;/&gt;
</span><ins>+        &lt;dia:enum val=&quot;1&quot;/&gt;
</ins><span class="cx">         &lt;dia:enum val=&quot;0&quot;/&gt;
</span><ins>+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;autorouting&quot;&gt;
+        &lt;dia:boolean val=&quot;false&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;end_arrow&quot;&gt;
+        &lt;dia:enum val=&quot;22&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;end_arrow_length&quot;&gt;
+        &lt;dia:real val=&quot;0.5&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;end_arrow_width&quot;&gt;
+        &lt;dia:real val=&quot;0.5&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:connections&gt;
+        &lt;dia:connection handle=&quot;0&quot; to=&quot;O5&quot; connection=&quot;16&quot;/&gt;
+        &lt;dia:connection handle=&quot;1&quot; to=&quot;O7&quot; connection=&quot;6&quot;/&gt;
+      &lt;/dia:connections&gt;
+    &lt;/dia:object&gt;
+    &lt;dia:object type=&quot;Standard - ZigZagLine&quot; version=&quot;1&quot; id=&quot;O32&quot;&gt;
+      &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
+        &lt;dia:point val=&quot;26.67,6.95&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
+        &lt;dia:rectangle val=&quot;18.8882,6.9;26.72,18.7868&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;orth_points&quot;&gt;
+        &lt;dia:point val=&quot;26.67,6.95&quot;/&gt;
+        &lt;dia:point val=&quot;26.67,18.425&quot;/&gt;
+        &lt;dia:point val=&quot;19,18.425&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;orth_orient&quot;&gt;
+        &lt;dia:enum val=&quot;1&quot;/&gt;
</ins><span class="cx">         &lt;dia:enum val=&quot;0&quot;/&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><ins>+      &lt;dia:attribute name=&quot;autorouting&quot;&gt;
+        &lt;dia:boolean val=&quot;true&quot;/&gt;
+      &lt;/dia:attribute&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;end_arrow&quot;&gt;
</span><span class="cx">         &lt;dia:enum val=&quot;22&quot;/&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="lines">@@ -1535,35 +1250,163 @@
</span><span class="cx">         &lt;dia:real val=&quot;0.5&quot;/&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:connections&gt;
</span><del>-        &lt;dia:connection handle=&quot;0&quot; to=&quot;O14&quot; connection=&quot;4&quot;/&gt;
-        &lt;dia:connection handle=&quot;6&quot; to=&quot;O10&quot; connection=&quot;15&quot;/&gt;
</del><ins>+        &lt;dia:connection handle=&quot;0&quot; to=&quot;O4&quot; connection=&quot;14&quot;/&gt;
+        &lt;dia:connection handle=&quot;1&quot; to=&quot;O7&quot; connection=&quot;10&quot;/&gt;
</ins><span class="cx">       &lt;/dia:connections&gt;
</span><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Standard - BezierLine&quot; version=&quot;0&quot; id=&quot;O44&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Standard - ZigZagLine&quot; version=&quot;1&quot; id=&quot;O33&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;18.8536,28.7536&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;23.43,6.95&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;18.8032,3.46851;29.05,28.8043&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;18.9257,6.9;23.48,13.3618&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><del>-      &lt;dia:attribute name=&quot;bez_points&quot;&gt;
-        &lt;dia:point val=&quot;18.8536,28.7536&quot;/&gt;
-        &lt;dia:point val=&quot;28.0326,28.8213&quot;/&gt;
-        &lt;dia:point val=&quot;29,24&quot;/&gt;
-        &lt;dia:point val=&quot;29,21&quot;/&gt;
-        &lt;dia:point val=&quot;29,18&quot;/&gt;
-        &lt;dia:point val=&quot;29,14&quot;/&gt;
-        &lt;dia:point val=&quot;29,11&quot;/&gt;
-        &lt;dia:point val=&quot;29,8&quot;/&gt;
-        &lt;dia:point val=&quot;27,7&quot;/&gt;
-        &lt;dia:point val=&quot;23.9286,3.85355&quot;/&gt;
</del><ins>+      &lt;dia:attribute name=&quot;orth_points&quot;&gt;
+        &lt;dia:point val=&quot;23.43,6.95&quot;/&gt;
+        &lt;dia:point val=&quot;23.43,13&quot;/&gt;
+        &lt;dia:point val=&quot;19.0375,13&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><del>-      &lt;dia:attribute name=&quot;corner_types&quot;&gt;
</del><ins>+      &lt;dia:attribute name=&quot;orth_orient&quot;&gt;
+        &lt;dia:enum val=&quot;1&quot;/&gt;
</ins><span class="cx">         &lt;dia:enum val=&quot;0&quot;/&gt;
</span><ins>+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;autorouting&quot;&gt;
+        &lt;dia:boolean val=&quot;true&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;line_style&quot;&gt;
+        &lt;dia:enum val=&quot;4&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;end_arrow&quot;&gt;
+        &lt;dia:enum val=&quot;22&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;end_arrow_length&quot;&gt;
+        &lt;dia:real val=&quot;0.5&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;end_arrow_width&quot;&gt;
+        &lt;dia:real val=&quot;0.5&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:connections&gt;
+        &lt;dia:connection handle=&quot;0&quot; to=&quot;O4&quot; connection=&quot;12&quot;/&gt;
+        &lt;dia:connection handle=&quot;1&quot; to=&quot;O6&quot; connection=&quot;8&quot;/&gt;
+      &lt;/dia:connections&gt;
+    &lt;/dia:object&gt;
+    &lt;dia:object type=&quot;Standard - ZigZagLine&quot; version=&quot;1&quot; id=&quot;O34&quot;&gt;
+      &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
+        &lt;dia:point val=&quot;19,17.95&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
+        &lt;dia:rectangle val=&quot;18.95,6.8382;25.4118,18&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;orth_points&quot;&gt;
+        &lt;dia:point val=&quot;19,17.95&quot;/&gt;
+        &lt;dia:point val=&quot;25.05,17.95&quot;/&gt;
+        &lt;dia:point val=&quot;25.05,6.95&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;orth_orient&quot;&gt;
</ins><span class="cx">         &lt;dia:enum val=&quot;0&quot;/&gt;
</span><ins>+        &lt;dia:enum val=&quot;1&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;autorouting&quot;&gt;
+        &lt;dia:boolean val=&quot;true&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;end_arrow&quot;&gt;
+        &lt;dia:enum val=&quot;22&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;end_arrow_length&quot;&gt;
+        &lt;dia:real val=&quot;0.5&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;end_arrow_width&quot;&gt;
+        &lt;dia:real val=&quot;0.5&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:connections&gt;
+        &lt;dia:connection handle=&quot;0&quot; to=&quot;O7&quot; connection=&quot;8&quot;/&gt;
+        &lt;dia:connection handle=&quot;1&quot; to=&quot;O4&quot; connection=&quot;13&quot;/&gt;
+      &lt;/dia:connections&gt;
+    &lt;/dia:object&gt;
+    &lt;dia:object type=&quot;Standard - ZigZagLine&quot; version=&quot;1&quot; id=&quot;O35&quot;&gt;
+      &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
+        &lt;dia:point val=&quot;19,23.15&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
+        &lt;dia:rectangle val=&quot;19,6.69175;28.5054,23.2&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;orth_points&quot;&gt;
+        &lt;dia:point val=&quot;19,23.15&quot;/&gt;
+        &lt;dia:point val=&quot;19,23.15&quot;/&gt;
+        &lt;dia:point val=&quot;28.1436,23.15&quot;/&gt;
+        &lt;dia:point val=&quot;28.1436,6.80355&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;orth_orient&quot;&gt;
+        &lt;dia:enum val=&quot;1&quot;/&gt;
</ins><span class="cx">         &lt;dia:enum val=&quot;0&quot;/&gt;
</span><ins>+        &lt;dia:enum val=&quot;1&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;autorouting&quot;&gt;
+        &lt;dia:boolean val=&quot;false&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;line_style&quot;&gt;
+        &lt;dia:enum val=&quot;4&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;end_arrow&quot;&gt;
+        &lt;dia:enum val=&quot;22&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;end_arrow_length&quot;&gt;
+        &lt;dia:real val=&quot;0.5&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;end_arrow_width&quot;&gt;
+        &lt;dia:real val=&quot;0.5&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:connections&gt;
+        &lt;dia:connection handle=&quot;0&quot; to=&quot;O8&quot; connection=&quot;8&quot;/&gt;
+        &lt;dia:connection handle=&quot;1&quot; to=&quot;O4&quot; connection=&quot;15&quot;/&gt;
+      &lt;/dia:connections&gt;
+    &lt;/dia:object&gt;
+    &lt;dia:object type=&quot;Standard - Line&quot; version=&quot;0&quot; id=&quot;O36&quot;&gt;
+      &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
+        &lt;dia:point val=&quot;16,0.65&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
+        &lt;dia:rectangle val=&quot;15.6382,0.6;16.3618,7.1118&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;conn_endpoints&quot;&gt;
+        &lt;dia:point val=&quot;16,0.65&quot;/&gt;
+        &lt;dia:point val=&quot;16,7&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;numcp&quot;&gt;
+        &lt;dia:int val=&quot;1&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;end_arrow&quot;&gt;
+        &lt;dia:enum val=&quot;22&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;end_arrow_length&quot;&gt;
+        &lt;dia:real val=&quot;0.5&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;end_arrow_width&quot;&gt;
+        &lt;dia:real val=&quot;0.5&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:connections&gt;
+        &lt;dia:connection handle=&quot;1&quot; to=&quot;O5&quot; connection=&quot;2&quot;/&gt;
+      &lt;/dia:connections&gt;
+    &lt;/dia:object&gt;
+    &lt;dia:object type=&quot;Standard - ZigZagLine&quot; version=&quot;1&quot; id=&quot;O37&quot;&gt;
+      &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
+        &lt;dia:point val=&quot;21.81,5.95&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
+        &lt;dia:rectangle val=&quot;17.1382,5.9;21.86,7.1118&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;orth_points&quot;&gt;
+        &lt;dia:point val=&quot;21.81,5.95&quot;/&gt;
+        &lt;dia:point val=&quot;17.5,5.95&quot;/&gt;
+        &lt;dia:point val=&quot;17.5,7&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;orth_orient&quot;&gt;
</ins><span class="cx">         &lt;dia:enum val=&quot;0&quot;/&gt;
</span><ins>+        &lt;dia:enum val=&quot;1&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><ins>+      &lt;dia:attribute name=&quot;autorouting&quot;&gt;
+        &lt;dia:boolean val=&quot;true&quot;/&gt;
+      &lt;/dia:attribute&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;end_arrow&quot;&gt;
</span><span class="cx">         &lt;dia:enum val=&quot;22&quot;/&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="lines">@@ -1574,31 +1417,32 @@
</span><span class="cx">         &lt;dia:real val=&quot;0.5&quot;/&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:connections&gt;
</span><del>-        &lt;dia:connection handle=&quot;0&quot; to=&quot;O16&quot; connection=&quot;15&quot;/&gt;
-        &lt;dia:connection handle=&quot;9&quot; to=&quot;O10&quot; connection=&quot;15&quot;/&gt;
</del><ins>+        &lt;dia:connection handle=&quot;0&quot; to=&quot;O4&quot; connection=&quot;7&quot;/&gt;
+        &lt;dia:connection handle=&quot;1&quot; to=&quot;O5&quot; connection=&quot;3&quot;/&gt;
</ins><span class="cx">       &lt;/dia:connections&gt;
</span><span class="cx">     &lt;/dia:object&gt;
</span><del>-    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;0&quot; id=&quot;O45&quot;&gt;
</del><ins>+    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;1&quot; id=&quot;O38&quot;&gt;
</ins><span class="cx">       &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
</span><del>-        &lt;dia:point val=&quot;25,4&quot;/&gt;
</del><ins>+        &lt;dia:point val=&quot;20.65,1.05&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
</span><del>-        &lt;dia:rectangle val=&quot;25,3.45;30.1,4.8&quot;/&gt;
</del><ins>+        &lt;dia:rectangle val=&quot;20.65,0.605;28.575,2.36194&quot;/&gt;
</ins><span class="cx">       &lt;/dia:attribute&gt;
</span><span class="cx">       &lt;dia:attribute name=&quot;text&quot;&gt;
</span><span class="cx">         &lt;dia:composite type=&quot;text&quot;&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;string&quot;&gt;
</span><del>-            &lt;dia:string&gt;#Bug is reopened,
-was never confirmed#&lt;/dia:string&gt;
</del><ins>+            &lt;dia:string&gt;#Bug is filed by a non-empowered
+user in a product where the
+UNCONFIRMED state is enabled#&lt;/dia:string&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;font&quot;&gt;
</span><span class="cx">             &lt;dia:font family=&quot;sans&quot; style=&quot;0&quot; name=&quot;Helvetica&quot;/&gt;
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;height&quot;&gt;
</span><del>-            &lt;dia:real val=&quot;0.59999999999999998&quot;/&gt;
</del><ins>+            &lt;dia:real val=&quot;0.59972222571740919&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;pos&quot;&gt;
</span><del>-            &lt;dia:point val=&quot;25,4&quot;/&gt;
</del><ins>+            &lt;dia:point val=&quot;20.65,1.05&quot;/&gt;
</ins><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">           &lt;dia:attribute name=&quot;color&quot;&gt;
</span><span class="cx">             &lt;dia:color val=&quot;#000000&quot;/&gt;
</span><span class="lines">@@ -1608,6 +1452,273 @@
</span><span class="cx">           &lt;/dia:attribute&gt;
</span><span class="cx">         &lt;/dia:composite&gt;
</span><span class="cx">       &lt;/dia:attribute&gt;
</span><ins>+      &lt;dia:attribute name=&quot;valign&quot;&gt;
+        &lt;dia:enum val=&quot;3&quot;/&gt;
+      &lt;/dia:attribute&gt;
</ins><span class="cx">     &lt;/dia:object&gt;
</span><ins>+    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;1&quot; id=&quot;O39&quot;&gt;
+      &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
+        &lt;dia:point val=&quot;26.65,1.5&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
+        &lt;dia:rectangle val=&quot;26.65,0.905;26.65,1.65&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;text&quot;&gt;
+        &lt;dia:composite type=&quot;text&quot;&gt;
+          &lt;dia:attribute name=&quot;string&quot;&gt;
+            &lt;dia:string&gt;##&lt;/dia:string&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;font&quot;&gt;
+            &lt;dia:font family=&quot;sans&quot; style=&quot;0&quot; name=&quot;Helvetica&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;height&quot;&gt;
+            &lt;dia:real val=&quot;0.80000000000000004&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;pos&quot;&gt;
+            &lt;dia:point val=&quot;26.65,1.5&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;color&quot;&gt;
+            &lt;dia:color val=&quot;#000000&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;alignment&quot;&gt;
+            &lt;dia:enum val=&quot;0&quot;/&gt;
+          &lt;/dia:attribute&gt;
+        &lt;/dia:composite&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;valign&quot;&gt;
+        &lt;dia:enum val=&quot;3&quot;/&gt;
+      &lt;/dia:attribute&gt;
+    &lt;/dia:object&gt;
+    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;1&quot; id=&quot;O40&quot;&gt;
+      &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
+        &lt;dia:point val=&quot;21.2,5.2&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
+        &lt;dia:rectangle val=&quot;21.2,4.605;21.2,5.35&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;text&quot;&gt;
+        &lt;dia:composite type=&quot;text&quot;&gt;
+          &lt;dia:attribute name=&quot;string&quot;&gt;
+            &lt;dia:string&gt;##&lt;/dia:string&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;font&quot;&gt;
+            &lt;dia:font family=&quot;sans&quot; style=&quot;0&quot; name=&quot;Helvetica&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;height&quot;&gt;
+            &lt;dia:real val=&quot;0.80000000000000004&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;pos&quot;&gt;
+            &lt;dia:point val=&quot;21.2,5.2&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;color&quot;&gt;
+            &lt;dia:color val=&quot;#000000&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;alignment&quot;&gt;
+            &lt;dia:enum val=&quot;0&quot;/&gt;
+          &lt;/dia:attribute&gt;
+        &lt;/dia:composite&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;valign&quot;&gt;
+        &lt;dia:enum val=&quot;3&quot;/&gt;
+      &lt;/dia:attribute&gt;
+    &lt;/dia:object&gt;
+    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;1&quot; id=&quot;O41&quot;&gt;
+      &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
+        &lt;dia:point val=&quot;12.95,10.85&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
+        &lt;dia:rectangle val=&quot;12.95,10.255;12.95,11&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;text&quot;&gt;
+        &lt;dia:composite type=&quot;text&quot;&gt;
+          &lt;dia:attribute name=&quot;string&quot;&gt;
+            &lt;dia:string&gt;##&lt;/dia:string&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;font&quot;&gt;
+            &lt;dia:font family=&quot;sans&quot; style=&quot;0&quot; name=&quot;Helvetica&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;height&quot;&gt;
+            &lt;dia:real val=&quot;0.80000000000000004&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;pos&quot;&gt;
+            &lt;dia:point val=&quot;12.95,10.85&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;color&quot;&gt;
+            &lt;dia:color val=&quot;#000000&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;alignment&quot;&gt;
+            &lt;dia:enum val=&quot;0&quot;/&gt;
+          &lt;/dia:attribute&gt;
+        &lt;/dia:composite&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;valign&quot;&gt;
+        &lt;dia:enum val=&quot;3&quot;/&gt;
+      &lt;/dia:attribute&gt;
+    &lt;/dia:object&gt;
+    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;1&quot; id=&quot;O42&quot;&gt;
+      &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
+        &lt;dia:point val=&quot;18.95,15.45&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
+        &lt;dia:rectangle val=&quot;18.95,14.855;18.95,15.6&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;text&quot;&gt;
+        &lt;dia:composite type=&quot;text&quot;&gt;
+          &lt;dia:attribute name=&quot;string&quot;&gt;
+            &lt;dia:string&gt;##&lt;/dia:string&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;font&quot;&gt;
+            &lt;dia:font family=&quot;sans&quot; style=&quot;0&quot; name=&quot;Helvetica&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;height&quot;&gt;
+            &lt;dia:real val=&quot;0.80000000000000004&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;pos&quot;&gt;
+            &lt;dia:point val=&quot;18.95,15.45&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;color&quot;&gt;
+            &lt;dia:color val=&quot;#000000&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;alignment&quot;&gt;
+            &lt;dia:enum val=&quot;0&quot;/&gt;
+          &lt;/dia:attribute&gt;
+        &lt;/dia:composite&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;valign&quot;&gt;
+        &lt;dia:enum val=&quot;3&quot;/&gt;
+      &lt;/dia:attribute&gt;
+    &lt;/dia:object&gt;
+    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;1&quot; id=&quot;O43&quot;&gt;
+      &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
+        &lt;dia:point val=&quot;21,15.55&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
+        &lt;dia:rectangle val=&quot;21,14.955;21,15.7&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;text&quot;&gt;
+        &lt;dia:composite type=&quot;text&quot;&gt;
+          &lt;dia:attribute name=&quot;string&quot;&gt;
+            &lt;dia:string&gt;##&lt;/dia:string&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;font&quot;&gt;
+            &lt;dia:font family=&quot;sans&quot; style=&quot;0&quot; name=&quot;Helvetica&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;height&quot;&gt;
+            &lt;dia:real val=&quot;0.80000000000000004&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;pos&quot;&gt;
+            &lt;dia:point val=&quot;21,15.55&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;color&quot;&gt;
+            &lt;dia:color val=&quot;#000000&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;alignment&quot;&gt;
+            &lt;dia:enum val=&quot;0&quot;/&gt;
+          &lt;/dia:attribute&gt;
+        &lt;/dia:composite&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;valign&quot;&gt;
+        &lt;dia:enum val=&quot;3&quot;/&gt;
+      &lt;/dia:attribute&gt;
+    &lt;/dia:object&gt;
+    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;1&quot; id=&quot;O44&quot;&gt;
+      &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
+        &lt;dia:point val=&quot;13.6,20.7&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
+        &lt;dia:rectangle val=&quot;13.6,20.105;13.6,20.85&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;text&quot;&gt;
+        &lt;dia:composite type=&quot;text&quot;&gt;
+          &lt;dia:attribute name=&quot;string&quot;&gt;
+            &lt;dia:string&gt;##&lt;/dia:string&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;font&quot;&gt;
+            &lt;dia:font family=&quot;sans&quot; style=&quot;0&quot; name=&quot;Helvetica&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;height&quot;&gt;
+            &lt;dia:real val=&quot;0.80000000000000004&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;pos&quot;&gt;
+            &lt;dia:point val=&quot;13.6,20.7&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;color&quot;&gt;
+            &lt;dia:color val=&quot;#000000&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;alignment&quot;&gt;
+            &lt;dia:enum val=&quot;0&quot;/&gt;
+          &lt;/dia:attribute&gt;
+        &lt;/dia:composite&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;valign&quot;&gt;
+        &lt;dia:enum val=&quot;3&quot;/&gt;
+      &lt;/dia:attribute&gt;
+    &lt;/dia:object&gt;
+    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;1&quot; id=&quot;O45&quot;&gt;
+      &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
+        &lt;dia:point val=&quot;24.35,9.7&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
+        &lt;dia:rectangle val=&quot;24.35,9.105;24.35,9.85&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;text&quot;&gt;
+        &lt;dia:composite type=&quot;text&quot;&gt;
+          &lt;dia:attribute name=&quot;string&quot;&gt;
+            &lt;dia:string&gt;##&lt;/dia:string&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;font&quot;&gt;
+            &lt;dia:font family=&quot;sans&quot; style=&quot;0&quot; name=&quot;Helvetica&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;height&quot;&gt;
+            &lt;dia:real val=&quot;0.80000000000000004&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;pos&quot;&gt;
+            &lt;dia:point val=&quot;24.35,9.7&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;color&quot;&gt;
+            &lt;dia:color val=&quot;#000000&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;alignment&quot;&gt;
+            &lt;dia:enum val=&quot;0&quot;/&gt;
+          &lt;/dia:attribute&gt;
+        &lt;/dia:composite&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;valign&quot;&gt;
+        &lt;dia:enum val=&quot;3&quot;/&gt;
+      &lt;/dia:attribute&gt;
+    &lt;/dia:object&gt;
+    &lt;dia:object type=&quot;Standard - Text&quot; version=&quot;1&quot; id=&quot;O46&quot;&gt;
+      &lt;dia:attribute name=&quot;obj_pos&quot;&gt;
+        &lt;dia:point val=&quot;23.85,9.95&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;obj_bb&quot;&gt;
+        &lt;dia:rectangle val=&quot;23.85,9.355;23.85,10.1&quot;/&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;text&quot;&gt;
+        &lt;dia:composite type=&quot;text&quot;&gt;
+          &lt;dia:attribute name=&quot;string&quot;&gt;
+            &lt;dia:string&gt;##&lt;/dia:string&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;font&quot;&gt;
+            &lt;dia:font family=&quot;sans&quot; style=&quot;0&quot; name=&quot;Helvetica&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;height&quot;&gt;
+            &lt;dia:real val=&quot;0.80000000000000004&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;pos&quot;&gt;
+            &lt;dia:point val=&quot;23.85,9.95&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;color&quot;&gt;
+            &lt;dia:color val=&quot;#000000&quot;/&gt;
+          &lt;/dia:attribute&gt;
+          &lt;dia:attribute name=&quot;alignment&quot;&gt;
+            &lt;dia:enum val=&quot;0&quot;/&gt;
+          &lt;/dia:attribute&gt;
+        &lt;/dia:composite&gt;
+      &lt;/dia:attribute&gt;
+      &lt;dia:attribute name=&quot;valign&quot;&gt;
+        &lt;dia:enum val=&quot;3&quot;/&gt;
+      &lt;/dia:attribute&gt;
+    &lt;/dia:object&gt;
</ins><span class="cx">   &lt;/dia:layer&gt;
</span><span class="cx"> &lt;/dia:diagram&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgdocsenimagescautiongif"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/docs/en/images/caution.gif (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/docs/en/images/caution.gif        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/docs/en/images/caution.gif        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,6 +1 @@
</span><del>-GIF89a@\xA1\xFF\xFF\xFFp\x80\x90!\xF9,@Õ„\x8F\xA9\xCB\xED\xA3\x9C\x85[\xDD\xDD!/\x98g\x80\x9BHf
-\x9E)\xB2\x82[\xAD\xB20d\xAB8\xE3:\xEB-f×›\xECZH\x9A\x9C-\x89JXk\xEA\x8CX\x85\xD4'\xF0\xC2\xEDj\xB7\xCD,
-\x96\x8A\xC7h\xB5\xF9\xDC.\xBFL\xEC&lt;&gt;\xAD\xD1\xC3z\xA8\xFB\xFD@fw\xC7R\xB7\xC6v\xF2\xD7wr\x95D\xD5\xF4\xF3\xE5&amp;        \xD6xW8Yy4\xA8)Z\xC5H        z\xC9\xD9y#\xF7r\x84\x9A\xD2\xE3*;`;\x9Br0\x8B\xE9Ä‹\x92\xB2\xB4ʺ\xF4b2D\xB8\x87\xB4Ü–\xD7+\xF8\xAB\xB0\xA4jZ\x98F\x9By\xAA8\xC7c\xE8X3{^\x81c\x8B5-\xB1[.Ûž /\xFFP;
</del><span class="cx">\ No newline at end of file
</span><ins>+GIF89a\xC2\xFF\xFF\xFFp\x80\x90\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF!\xF9,K\xBAΰ\xB9 &quot;\x9B\xB4Z0\x85ߘ7hPè‘—s\xA2i6\x82\xAA\xF0F\xE6Gw\xF6\xED\xB2 \x9E\x971^o\xB7\xE1a+\xA4L\xB88ÍŠ\x83Ó˜)bEjFx=Y\xBA\xCF\xD6j*\xFAE\x92\x91;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgdocsenimagestipgif"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/docs/en/images/tip.gif (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/docs/en/images/tip.gif        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/docs/en/images/tip.gif        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,23 +1,7 @@
</span><del>-GIF89aE-\xE7R))\xDE\xD6\xC6Z9s\x94scƽ\xB5k11\xDE\xC6\xC6B\x84{\xBD\xB5ks\x94RB\x84BZZR\xEF\xE7ç­½\x9C\xA5kc\xA5ZB!RR{\xF7Þ½{Ɯ޵\x94)9Bc1Öµ\x8C{!\xADZ9\x8C{\x8C\xBD\xADÆŒJ)sRc罌\xD6\xC6\xEF\xEF\x9Csν\xC6!1ç­Œs!B\x84Rc{k{\xD6\xDE\xDEZ9)\xBD\xB5\xB5)!1\x9Ck!!R1!\xBD\x8C\x94sBR\xE7\xDE\xDE\xE7\xAD{\xE7\xD6\xDEέ\xB5\xAD\x94\x84\xAD{c1\x84\xA5\x9CsR9Z\xAD{J!{1\x94cJ\xAD\xB5ÖŒkB\xA5{JBJc\x8CcB\xEFέ\x94k\x8C\xA5kJ\xA5\x84\xAD9)1)B!\x84Þ”Z\xD6\xE7\xF7JkscsRJ\xD6\xCE\xD6Ö½\xB5s{\xAD\xEF\xDE\xDE\xD6\xC6\xD6Z\xCE\xCEÎ¥J!k9!ε\xAD\x84ZJ\xB5\x8C\x84\x84ck\xB5\xB5組\x84\xC6\xC6Ƶsc\xA5c{Zk\x94sB9\xFF\xEFÖ­\xDE\xEF\xCEƽ\xBDsZε\x9C)9\x9CÎœ{\xAD\x8Ck\x84J9\x94\x94\xA5Æ”s\xAD\x9C\xAD΄{ƽ֥\xAD\xC6c\xAD\xBD\xDEkB\x84sÞœk9RJZR99\x9C{{\xDE\xEF\x{1D4514}JJR\xAD\xC6\xDE\xDE\xD6\xD6\xDE\xCE\xD6Þ½\xB5sZB\xBD\xAD\xA5\xBD\x9C\x84J!1\x94\xA5\xF7\x94\x94\xD6B\xEF\xDEÖ¥\x94\x94\x84{cÖµ\xAD\xE7\xB5kZ\xB5ÎŒRJ\xE7\xD6\xCEÎœ\x84s\xCE{c1B{)JÖ”9\xBD\xAD\x94sJ1Ö
 µ\x9C\xBD\x8Css)\xE7\xE7\xDE)1\xE7νR1B\xCE{R\xB5s\x8C\xAD{\x84\xE7\xB5\xDEZ99\xFFÞœ9))\xFF\xFF\xFFkk{kZZJ9)1\xAD\x84R\xC6\xE7\xFF\xB5c9\xF7\xF7\xF7\xD6\xE7猌\x84cJRB1!Þµ\xAD\xD6\xCE\xC6{1!\x9C91\xEF\xEF便\xADÆ­\xBD\xA5c)\xEF\xD6\xCEÖ­\xA5{\xBD\xD6\xE7\xE7\xE7çµ¥B)\xBD\x94k\x94cZ\x8CZ1\xEF\xE7\xDE\xE7\xADR\x84\x9C\xADε\x8C\xBDkJﵜ\xA5kZ\xB5\x84c\xE7Ƶ\xB5\x94\xA5ÆŒcZkss\x8C\x9CÆœ\xA5)sc{ÆŒ\xA5\xDE\xF7組R\x94Z!\xF9d,E-@\xFE\xC9H\xB0\xA0\xC1\x83*\XP\x97\xAEe}-&quot;qÙŸ?\xBA8E\x89bKWNO89
-P\x86\x80.\x86(S
-\V\xE1R_}\xB5t\x89AKP6\x92\xD9\xC0\x91%\xC81LD2]\x80\xA4\xE0\xD1\xC5e\xB2\x96銢\xCB\xD8#_\x9C\x96\xC9\xFCe'j\xD4^ 
-\xC4 \xB5'\x81T\x88\x98%\xC2 \x9E-Mh]\xB0\xA4cM\x96\x8D\xE9pÑ©)        \xAFØ°\xB1\xE1\x97%F
-\I\x91Â’!C ]\xB9BKA3dc\xF2\xF4\xD8p$\xD10\x95\x983&lt;1\xE9\xC0&amp;\xA9Dqà°¡\xC5 ,Iu\xA15%\x9Acc~rb\xD9 \xDD\xF9\xB3\xC1\x8634;4\xE0k\x97\x97}f\xCC
-p\xE8\xB2\xEC\xE7)?*\xE5\xF4G\x88\xAC\x8B\xBB=z\xF3%eʬ\xFE}\xF9\xF2\xAA,]\x8E.\x9D\xF9\xC3ii\x94C*`\x86\xADÕ  T\x83\xC7U\xFD\xA1J3m(\xF3\xC5\xC9\xE0 Y\xAC\x88\x80XrG'\xA8p\xC5\xC0\xC0D\x83,\x98\xA2K)\xA5\xE4\xC1)\xAF\x94\xA2FDQ\x82-b\x84$\x9BX1\xC5\x90\xEC\x90K\xC44\x83\x8B~IaG,\xFCB\xE1.$r
-,np2\xC62\x9D\xAC\xF0\xCB&lt;R        e\xB8\xF1-&lt;f9&quot;K(6&quot;b'] \x96L%3h\xA9\xE6\x9Al\xB6\xA9\x92.\xB47\x81TPA\x91C38\xE4G\xC32\x86sn2\xE4D\x90\xB0K\x88V\xF0HƼ$Ä£BpÒž.\x87\xFC\x81\xC5м-4\xB2P\xE1\x87#\xD5T\xA3IlF%\xC4D1w\xC9.\x97cCx\xFEu\xE0@\xC4xj(cC3\xF8&quot;\xC8.O\xFC\x81T{Q-\xC50\xBAP\x80\xB8\xD0@+\xA1\xE0\xC7 ~\xA0\x84&amp;\xB6\x91\xCCͨ\x81\xC96 \xC0u\x84\xFB\x85-D\x81%\xB1\xA4K\xCA\xCD Õ«\x9D\x9C\x82
-@\xC0\xC3%\xE8\xD2@)&lt;B        \xA3P\xD2&amp;JM\xC0\*7YD(LY(\xC4\xC3M\xF0\xC4_.H\xE8\x82!éº\xEE.\xB8p-@\x90F:t\x902BL` &quot;@\x92I\x9D\xE8\xB1PtÐ@Ý¢G1\xBC\xC8!4p@\xC8B\x88\x90B\x8A\xC7\xC7\xF2 *\xA22\xC8Kb\xC8/WÔ\x81\xA2\xC30\x801\x81\xAA\x840\xBC( \x98\xC2&quot;\xAC\xC1\x9A/\x81\xA0&quot;\xC6\xBE S\xC1x\xB8v\xFEl\xD1X\xD2L3\x9C\xAC\xB2\xC9\xCA@c\xC2\xD6\@){dž\xC7 ~\x80\x82\x88@\x81 \x8D\xABÙ„%\x9F,\x84&quot;\x9D\x97\x8E'$\xE5\x88&amp;\xAE\xF4b:t\x87Hz\x91,\xB2\xB7\x8BD\xF4\xC3!\x87DAF\xAF+{T0U\xF4GR\x93F1\xC6\xF9b\x8C\xC1\xF5?\xD0!\xA7&quot;u        L\xD8\xFDDe4A\xEF\xC3\xF4I@%\x8A\xF8!\xC2\xF9&quot;\xCC@\x85\xA4\xBA\xE9ÈœQ\x9D\xB1\xCB\xFC`\x90FÛ¦\x81\x81Ý\xF2Ëœ\xB8\xCE\xF1|a\x80\x8Dl$\xF3A\x8E&amp;\xFA\xA4%8\xD9        *B\xF8\xF6\xF1P\x80&quot;\xC9HF0\x92\xF1`O\xD0ΰ,#_c\xC8\xC8FQ\x862 \xA3\xFB\x82\x9Dd\xC7        \xF8\xE2\x8D2F3 D\xF0\xFEP\x86\xAB\x82A\x8BH\xE3L9Þ¤8\xB1\x8BS\xB5\xE7\x97\x803h\xB0 \xA
 C0Cl(-Z\xB8\x903\xA2-m\x86\xFE\xB6f \x90 -\xC0\xC0&amp;\xFE&amp;A \xA0 \xC2.\xB0\x84X\xC5\xEC\xE1\x84&quot;aT@\xCA 0\x80\xD1N\xD8&quot;
-\xADp\xC4.\xA2\xA0\x91        \xCC/
-\x83\x83
-\xC4R\x90|\x81\xFDi +&quot;\xF0`\xE3Ú‰0\xC4  a(\x80YpZ,R\xB0\x86d\\x82v^x\x82z&gt;T\x8Ai\x90\xC2w\xE8H\x86Q\x8AfT\xA1
-\xD7`\x81hT\x859D\xC2\xCBF\xAE\xCA&quot;&lt;\xF8 8\x92\xA1\x8A((s\x99 \xB3M\x90\xA5K\xB9\x81\x81\xE2\xE8D)\x85Lp\xAB\xB0&quot;        `@rP.\xAC\x82 \xBC\xFE`\xC4-\x800\x82M0\xA00\x80\xC3²\xF09@B \xF3\x81\xB7r\xA1\Aj\xB1\x90\x864Z0\xF8%\xB0\xC42\xD0qB \x90X\x83HP\x811\xD8\xE2+\xE8\xC4l&amp;D\x9C\xA5\x88*\xD2u\x85\xC0\xA6\x80\xCF
-\x86%\xA4\x80\xA8\x98\xA9%R\xE0\xB4\xE0\x86\xB0\xC4/RpA\xCBS\xC4+NP\xE9-\xE4\x9D\x90\x86\xC7~\xE1\xB4_(-\xA48E \x8BTB\xC7x\xF9\xA1\x85x\xC1\xAAd\xB8\xC5Z\x80
-lA\xBB\xE8B#p\xC2\xE8`        \xAF8\x84q         \x82H\xC0 \xE0*\x90g\xC0\xA2p H\x90\x8Cx`\x83@j\x88\xD4ZD\xC18c2\x8Dc,܃!t\x90 -\xC0&quot;j\x80cF(7Úƒt\xC2\x99\xE8@U\xEF`\x89Kpb          \x84UÛƒ0c        (B\x8A+\xBC@\xB8\xC4C PP\\x83\xC0\xC2Q\xF8\x83
-2iT\x86h\x86,V݃\xBC\xE0\xB9\x80 @1 `\xA9\xBC(\xE1\xC33@&amp;\xE03;
</del><span class="cx">\ No newline at end of file
</span><ins>+GIF89a&quot;\xE7R))\xDE\xD6\xC6Z9s\x94scƽ\xB5k11\xDE\xC6\xC6B\x84{\xBD\xB5ks\x94RB\x84BZZR\xEF\xE7筽\x9C\xA5kc\xA5ZB!RR{\xF7޽{Ɯ޵\x94)9Bc1ֵ\x8C{!\xADZ9\x8C{\x8C\xBD\xADƌJ)sRc罌\xD6\xC6\xEF\xEF\x9Csν\xC6!1筌s!B\x84Rc{k{\xD6\xDE\xDEZ9)\xBD\xB5\xB5)!1\x9Ck!!R1!\xBD\x8C\x94sBR\xE7\xDE\xDE\xE7\xAD{\xE7\xD6\xDEέ\xB5\xAD\x94\x84\xAD{c1\x84\xA5\x9CsR9Z\xAD{J!{1\x94cJ\xAD\xB5֌kB\xA5{JBJc\x8CcB\xEFέ\x94k\x8C\xA5kJ\xA5\x84\xAD9)1)B!\x84ޔZ\xD6\xE7\xF7JkscsRJ\xD6\xCE\xD6ֽ\xB5s{\xAD\xEF\xDE\xDE\xD6\xC6\xD6Z\xCE\xCEΥJ!k9!ε\xAD\x84ZJ\xB5\x8C\x84\x84ck\xB5\xB5組\x84\xC6\xC6Ƶsc\xA5c{Zk\x94sB9\xFF\xEF֭\xDE\xEF\xCEƽ\xBDsZε\x9C)9\x9CΜ{\xAD\x8Ck\x84J9\x94\x94\xA5Ɣs\xAD\x9C\xAD΄{ƽ֥\xAD\xC6c\xAD\xBD\xDEkB\x84sޜk9RJZR99\x9C{{\xDE\xEF\x{1D4514}JJR\xAD\xC6\xDE\xDE\xD6\xD6\xDE\xCE\xD6޽\xB5sZB\xBD\xAD\xA5\xBD\x9C\x84J!1\x94\xA5\xF7\x94\x94\xD6B\xEF\xDE֥\x94\x94\x84{cֵ\xAD\xE7\xB5kZ\xB5ΌRJ\xE7\xD6\xCEΜ\x84s\xCE{c1B{)J֔9\xBD\xAD\x9
 4sJ1Öµ\x9C\xBD\x8Css)\xE7\xE7\xDE)1\xE7νR1B\xCE{R\xB5s\x8C\xAD{\x84\xE7\xB5\xDEZ99\xFFÞœ9))\xFF\xFF\xFFkk{kZZJ9)1\xAD\x84R\xC6\xE7\xFF\xB5c9\xF7\xF7\xF7\xD6\xE7猌\x84cJRB1!Þµ\xAD\xD6\xCE\xC6{1!\x9C91\xEF\xEF便\xADÆ­\xBD\xA5c)\xEF\xD6\xCEÖ­\xA5{\xBD\xD6\xE7\xE7\xE7çµ¥B)\xBD\x94k\x94cZ\x8CZ1\xEF\xE7\xDE\xE7\xADR\x84\x9C\xADε\x8C\xBDkJﵜ\xA5kZ\xB5\x84c\xE7Ƶ\xB5\x94\xA5ÆŒcZkss\x8C\x9CÆœ\xA5)sc{ÆŒ\xA5\xDE\xF7組R\x94Z\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF!\xF9\xFF,&quot;\xFEu\xD8`F\x80a\xFF*\È°aC]\x9C&amp;\xF8\x
 E2\xB4l\x99.]~\x86\x8Dq\xC8Ñ¡\xAE\x8A\xCB|-\xFB\xC3)
+DNt\\xF9\xEF\xE3\x9F]*\xA4\xA9 D']\x87\xB0@\x83&amp;\xCBO5M,X\xC6I\xC8\xCBG_\x88(\xFB\xF2\xE6\xE6\xA5?\xBA\xA2\xC0V5\x96E\x85\x84\xBCtɆ5_\xD4ؘ \xE8        Q\x8Að\xC0\xD5 
+\x8A+\x97]Y\xE1\x86.6ld9Fä‚‚?\xA3\xA3\x855D̨!&quot;!eD¾\xC0\xA3NR\xB1b\xADYfv\xD9!.\xE9*\xF5\x88%L\xBA\xE0\xF0O+U\xAF\xDB|I$  @wP]\xE6K\x96\xA0RyH\x95
+ÅŠ!IV\xA6\xECH\xD2\xEC@²\xD4\xE6a\xC9\xC5C\x99︠!Md\xABA*\xA0\x87a:=\x9C7\xB9\xA0#K#\x9DH\xBDb\xC1\x92\x91+) ]\xB8B\xABÙ˜G Ô‘\xBC\xC8Ak \x91\xE2\x82 \xB1\xA0b\xC8\x80\xFCRG\xC3 \xD4Jv\\xD0\xC9\x89\xC0B\xD1
+\x82\x854\\xC80\x84\xB0@\xA4\xE2 *_ \xF3\x84&amp;v4\xC9&amp;\xA9p\xB0\xC1,q55\xB2M3\x9Cl\xA2\x8C        \xD6\xE4J\x882\x806tqA%Kv\x84\x87\x88\xFCc\x88 \xC1PQ%Gf\xA9d\xC4 \xF8eGM|DG;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgdocsenimageswarninggif"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/docs/en/images/warning.gif (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/docs/en/images/warning.gif        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/docs/en/images/warning.gif        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1 +1 @@
</span><del>-GIF89a\xA1\xFF\xFF\xFF\xFF\xBF\xBF\xBF!\xF9,h\x9C\x8F\xA9\xCB\x9AL0\xCEYß•\xD9n\xD5i\x8EN(\x9Ah\xFAe\x82\x90\xA9\xD5\xB7\xF3 W6$@Ù¸z? \x8B1\xF4\xD1t\x9CWC:\x95Ë \x94\x87\xA3V\x8F\x87\xE1Kk\x{11CC38}2\x949~\x98\xC1a9[,G^\xB3=\xBAÊ—\xE8\xFA\xBE\xC6\xC8'\x882P;
</del><span class="cx">\ No newline at end of file
</span><ins>+GIF89a\xA1\xFF\xFF\xFF\xFF\xFF\xFF\xFF!\xF9,]\x9C\x8F\x91\xED\xB9Ö›0\xD2\xED}Y\xEE\xD6i\xDFz\xE3\x90        Bv\xA2\x91ÊŽ\xA9\xBA\x8A\xD8 \xB5I\xCD9l\xE3\xBC\xBF\xA37$\xEA\x80&lt;P\xB2h\x9C\xCCTÐ4\xA9\xA4E\x9D \xAD\x97CL\xA9KppL\xFE\x86]ݯ;\\x8A\xCB\xF2:ËŽ\xCF\xEB;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgdocsenrel_notestxt"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/docs/en/rel_notes.txt (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/docs/en/rel_notes.txt        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/docs/en/rel_notes.txt        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -3019,10 +3019,10 @@
</span><span class="cx"> *** USERS UPGRADING FROM 2.8 OR EARLIER ***
</span><span class="cx"> *******************************************
</span><span class="cx"> 
</span><del>-Release notes were not compiled for versions of Bugzilla before
-2.12.
</del><ins>+This version of Bugzilla cannot upgrade from version 2.8 (released
+November 19, 1999). You will first have to upgrade to Bugzilla 3.6 and
+then upgrade to the latest release.
</ins><span class="cx"> 
</span><del>-The file 'UPGRADING-pre-2.8' contains instructions you may
-need to perform in addition to running 'checksetup.pl' if you
-are running a pre 2.8 version.
-
</del><ins>+If you are upgrading from a version earlier than 2.8, See the 
+PGRADING-pre-2.8 file in Bugzilla 3.0 for information
+on upgrading from a version that is earlier than 2.8.
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgdocsenxmlcvsignore"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/docs/en/xml/.cvsignore (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/docs/en/xml/.cvsignore        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/docs/en/xml/.cvsignore        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1 +0,0 @@
</span><del>-bugzilla.ent
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgdocsenxmlBugzillaGuidexml"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/docs/en/xml/Bugzilla-Guide.xml (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/docs/en/xml/Bugzilla-Guide.xml        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/docs/en/xml/Bugzilla-Guide.xml        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -13,12 +13,10 @@
</span><span class="cx"> &lt;!ENTITY administration SYSTEM &quot;administration.xml&quot;&gt;
</span><span class="cx"> &lt;!ENTITY security SYSTEM &quot;security.xml&quot;&gt;
</span><span class="cx"> &lt;!ENTITY using SYSTEM &quot;using.xml&quot;&gt;
</span><del>-&lt;!ENTITY integration SYSTEM &quot;integration.xml&quot;&gt;
</del><span class="cx"> &lt;!ENTITY index SYSTEM &quot;index.xml&quot;&gt;
</span><span class="cx"> &lt;!ENTITY customization SYSTEM &quot;customization.xml&quot;&gt;
</span><span class="cx"> &lt;!ENTITY troubleshooting SYSTEM &quot;troubleshooting.xml&quot;&gt;
</span><span class="cx"> &lt;!ENTITY patches SYSTEM &quot;patches.xml&quot;&gt;
</span><del>-&lt;!ENTITY introduction SYSTEM &quot;introduction.xml&quot;&gt;
</del><span class="cx"> &lt;!ENTITY modules SYSTEM &quot;modules.xml&quot;&gt;
</span><span class="cx"> 
</span><span class="cx"> &lt;!-- Things to change for a stable release:
</span><span class="lines">@@ -34,12 +32,12 @@
</span><span class="cx">      For a devel release, simple bump bz-ver and bz-date
</span><span class="cx"> --&gt;
</span><span class="cx"> 
</span><del>-&lt;!ENTITY bz-ver &quot;3.2.3&quot;&gt;
-&lt;!ENTITY bz-nextver &quot;3.4&quot;&gt;
-&lt;!ENTITY bz-date &quot;2009-03-30&quot;&gt;
-&lt;!ENTITY current-year &quot;2009&quot;&gt;
</del><ins>+&lt;!ENTITY bz-ver &quot;4.2.1&quot;&gt;
+&lt;!ENTITY bz-nextver &quot;4.4&quot;&gt;
+&lt;!ENTITY bz-date &quot;2012-04-18&quot;&gt;
+&lt;!ENTITY current-year &quot;2012&quot;&gt;
</ins><span class="cx"> 
</span><del>-&lt;!ENTITY landfillbase &quot;http://landfill.bugzilla.org/bugzilla-3.2-branch/&quot;&gt;
</del><ins>+&lt;!ENTITY landfillbase &quot;http://landfill.bugzilla.org/bugzilla-4.2-branch/&quot;&gt;
</ins><span class="cx"> &lt;!ENTITY bz &quot;http://www.bugzilla.org/&quot;&gt;
</span><span class="cx"> &lt;!ENTITY bzg-bugs &quot;&lt;ulink url='https://bugzilla.mozilla.org/enter_bug.cgi?product=Bugzilla&amp;amp;component=Documentation'&gt;Bugzilla Documentation&lt;/ulink&gt;&quot;&gt;
</span><span class="cx"> &lt;!ENTITY mysql &quot;http://www.mysql.com/&quot;&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgdocsenxmlaboutxml"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/docs/en/xml/about.xml (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/docs/en/xml/about.xml        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/docs/en/xml/about.xml        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,6 +1,5 @@
</span><span class="cx"> &lt;!-- &lt;!DOCTYPE chapter PUBLIC &quot;-//OASIS//DTD DocBook V4.1//EN&quot; [
</span><span class="cx"> &lt;!ENTITY conventions SYSTEM &quot;conventions.xml&quot;&gt; ] &gt; --&gt;
</span><del>-&lt;!-- $Id$ --&gt;
</del><span class="cx"> 
</span><span class="cx"> &lt;chapter id=&quot;about&quot;&gt;
</span><span class="cx"> &lt;title&gt;About This Guide&lt;/title&gt;
</span><span class="lines">@@ -65,48 +64,23 @@
</span><span class="cx">     &lt;para&gt;
</span><span class="cx">       This is the &amp;bz-ver; version of The Bugzilla Guide. It is so named 
</span><span class="cx">       to match the current version of Bugzilla. 
</span><ins>+      &lt;!-- BZ-DEVEL --&gt; This version of the guide, like its associated Bugzilla version, is a
+      development version.&lt;!-- /BZ-DEVEL --&gt; 
</ins><span class="cx">     &lt;/para&gt;
</span><span class="cx">     &lt;para&gt;
</span><span class="cx">       The latest version of this guide can always be found at &lt;ulink
</span><del>-      url=&quot;http://www.bugzilla.org&quot;/&gt;, or checked out via CVS by
-      following the &lt;ulink url=&quot;http://www.mozilla.org/cvs.html&quot;&gt;Mozilla 
-      CVS&lt;/ulink&gt; instructions and check out the 
-      &lt;filename&gt;mozilla/webtools/bugzilla/docs/&lt;/filename&gt;
-      subtree. However, you should read the version
-      which came with the Bugzilla release you are using.
</del><ins>+      url=&quot;http://www.bugzilla.org/docs/&quot;/&gt;. However, you should read
+      the version which came with the Bugzilla release you are using.
</ins><span class="cx">     &lt;/para&gt;
</span><del>-    &lt;para&gt;
-      The Bugzilla Guide, or a section of it, is also available in
-      the following languages:
-      &lt;ulink url=&quot;http://www.traduc.org/docs/guides/lecture/bugzilla/&quot;&gt;French&lt;/ulink&gt;,
-      &lt;ulink url=&quot;http://bugzilla-de.sourceforge.net/docs/html/&quot;&gt;German&lt;/ulink&gt;,
-      &lt;ulink url=&quot;http://www.bugzilla.jp/docs/2.18/&quot;&gt;Japanese&lt;/ulink&gt;.
-      Note that these may be outdated or not up to date.
-    &lt;/para&gt;
</del><span class="cx">     
</span><span class="cx">     &lt;para&gt;  
</span><span class="cx">       In addition, there are Bugzilla template localization projects in
</span><del>-      the following languages. They may have translated documentation 
-      available: 
-      &lt;ulink url=&quot;http://sourceforge.net/projects/bugzilla-ar/&quot;&gt;Arabic&lt;/ulink&gt;,
-      &lt;ulink url=&quot;http://sourceforge.net/projects/bugzilla-be/&quot;&gt;Belarusian&lt;/ulink&gt;,
-      &lt;ulink url=&quot;http://openfmi.net/projects/mozilla-bg/&quot;&gt;Bulgarian&lt;/ulink&gt;,
-      &lt;ulink url=&quot;http://sourceforge.net/projects/bugzilla-br/&quot;&gt;Brazilian Portuguese&lt;/ulink&gt;,
-      &lt;ulink url=&quot;http://sourceforge.net/projects/bugzilla-cn/&quot;&gt;Chinese&lt;/ulink&gt;,
-      &lt;ulink url=&quot;http://sourceforge.net/projects/bugzilla-fr/&quot;&gt;French&lt;/ulink&gt;,
-      &lt;ulink url=&quot;http://germzilla.ganderbay.net/&quot;&gt;German&lt;/ulink&gt;,
-      &lt;ulink url=&quot;http://sourceforge.net/projects/bugzilla-it/&quot;&gt;Italian&lt;/ulink&gt;,
-      &lt;ulink url=&quot;http://www.bugzilla.jp/about/jp.html&quot;&gt;Japanese&lt;/ulink&gt;,
-      &lt;ulink url=&quot;http://sourceforge.net/projects/bugzilla-kr/&quot;&gt;Korean&lt;/ulink&gt;,
-      &lt;ulink url=&quot;http://sourceforge.net/projects/bugzilla-ru/&quot;&gt;Russian&lt;/ulink&gt; and
-      &lt;ulink url=&quot;http://sourceforge.net/projects/bugzilla-es/&quot;&gt;Spanish&lt;/ulink&gt;.
</del><ins>+      &lt;ulink url=&quot;http://www.bugzilla.org/download/#localizations&quot;&gt;several languages&lt;/ulink&gt;.
+      They may have translated documentation available. If you would like to
+      volunteer to translate the Guide into additional languages, please visit the
+      &lt;ulink url=&quot;https://wiki.mozilla.org/Bugzilla:L10n&quot;&gt;Bugzilla L10n team&lt;/ulink&gt;
+      page.
</ins><span class="cx">     &lt;/para&gt;
</span><del>-    
-    &lt;para&gt;  
-      If you would like to volunteer to translate the Guide into additional
-      languages, please contact
-      &lt;ulink url=&quot;mailto:justdave@bugzilla.org&quot;&gt;Dave Miller&lt;/ulink&gt;.
-    &lt;/para&gt;
</del><span class="cx">   &lt;/section&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;section id=&quot;credits&quot;&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgdocsenxmladministrationxml"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/docs/en/xml/administration.xml (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/docs/en/xml/administration.xml        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/docs/en/xml/administration.xml        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -100,13 +100,13 @@
</span><span class="cx"> 
</span><span class="cx">           &lt;varlistentry&gt;
</span><span class="cx">             &lt;term&gt;
</span><del>-              ssl
</del><ins>+              ssl_redirect
</ins><span class="cx">             &lt;/term&gt;
</span><span class="cx">             &lt;listitem&gt;
</span><span class="cx">               &lt;para&gt;
</span><del>-                Determines when Bugzilla will force HTTPS (SSL) connections, using
-                the URL defined in &lt;command&gt;sslbase&lt;/command&gt;. 
-                Options include &quot;always&quot;, &quot;never&quot;, and &quot;authenticated sessions&quot;. 
</del><ins>+                If enabled, Bugzilla will force HTTPS (SSL) connections, by
+                automatically redirecting any users who try to use a non-SSL
+                connection.
</ins><span class="cx">               &lt;/para&gt;
</span><span class="cx">             &lt;/listitem&gt;
</span><span class="cx">           &lt;/varlistentry&gt;
</span><span class="lines">@@ -147,18 +147,6 @@
</span><span class="cx"> 
</span><span class="cx">           &lt;varlistentry&gt;
</span><span class="cx">             &lt;term&gt;
</span><del>-              timezone
-            &lt;/term&gt;
-            &lt;listitem&gt;
-              &lt;para&gt;
-                Timezone of server. The timezone is displayed with timestamps. If 
-                this parameter is left blank, the timezone is not displayed.
-              &lt;/para&gt;
-            &lt;/listitem&gt;
-          &lt;/varlistentry&gt;
-
-          &lt;varlistentry&gt;
-            &lt;term&gt;
</del><span class="cx">               utf8
</span><span class="cx">             &lt;/term&gt;
</span><span class="cx">             &lt;listitem&gt;
</span><span class="lines">@@ -262,34 +250,11 @@
</span><span class="cx"> 
</span><span class="cx">         &lt;section id=&quot;param-admin-policies&quot;&gt;
</span><span class="cx">           &lt;title&gt;Administrative Policies&lt;/title&gt;
</span><del>-        &lt;para&gt;
-        This page contains parameters for basic administrative functions.
-        Options include whether to allow the deletion of bugs and users, whether
-        to allow users to change their email address, and whether to allow
-        user watching (one user receiving all notifications of a selected
-        other user). 
-        &lt;/para&gt;
-
-        &lt;variablelist&gt;
-
-          &lt;varlistentry&gt;
-            &lt;term&gt;
-              supportwatchers
-            &lt;/term&gt;
-            &lt;listitem&gt;
-              &lt;para&gt;
-                Turning on this option allows users to ask to receive copies 
-                of bug mail sent to another user.  Watching a user with
-                different group permissions is not a way to 'get around' the
-                system; copied emails are still subject to the normal groupset
-                permissions of a bug, and &lt;quote&gt;watchers&lt;/quote&gt; will only be 
-                copied on emails from bugs they would normally be allowed to view. 
-              &lt;/para&gt; 
-            &lt;/listitem&gt;
-          &lt;/varlistentry&gt;
-
-        &lt;/variablelist&gt;
-
</del><ins>+          &lt;para&gt;
+            This page contains parameters for basic administrative functions.
+            Options include whether to allow the deletion of bugs and users,
+            and whether to allow users to change their email address.
+          &lt;/para&gt;
</ins><span class="cx">         &lt;/section&gt;
</span><span class="cx"> 
</span><span class="cx">         &lt;section id=&quot;param-user-authentication&quot;&gt;
</span><span class="lines">@@ -516,25 +481,6 @@
</span><span class="cx"> 
</span><span class="cx">           &lt;varlistentry&gt;
</span><span class="cx">             &lt;term&gt;
</span><del>-              useentrygroupdefault
-            &lt;/term&gt;
-            &lt;listitem&gt;
-              &lt;para&gt;
-                Bugzilla products can have a group associated with them, so that
-                certain users can only see bugs in certain products. When this 
-                parameter is set to &lt;quote&gt;on&lt;/quote&gt;, this 
-                causes the initial group controls on newly created products 
-                to place all newly-created bugs in the group 
-                having the same name as the product immediately.
-                After a product is initially created, the group controls
-                can be further adjusted without interference by 
-                this mechanism.
-              &lt;/para&gt;
-            &lt;/listitem&gt;
-          &lt;/varlistentry&gt;
-
-          &lt;varlistentry&gt;
-            &lt;term&gt;
</del><span class="cx">               usevisibilitygroups
</span><span class="cx">             &lt;/term&gt;
</span><span class="cx">             &lt;listitem&gt;
</span><span class="lines">@@ -820,28 +766,74 @@
</span><span class="cx"> 
</span><span class="cx">           &lt;varlistentry&gt;
</span><span class="cx">             &lt;term&gt;
</span><del>-              sendmailnow
</del><ins>+              smtpserver
</ins><span class="cx">             &lt;/term&gt;
</span><span class="cx">             &lt;listitem&gt;
</span><span class="cx">               &lt;para&gt;
</span><del>-                When Bugzilla is using Sendmail older than 8.12, turning this option
-                off will improve performance by not waiting for Sendmail to actually
-                send mail.  If Sendmail 8.12 or later is being used, there is 
-                nothing to gain by turning this off.  If another MTA is being used, 
-                such as Postfix, then this option *must* be turned on (even if you 
-                are using the fake sendmail executable that Postfix provides).
</del><ins>+                This is the SMTP server address, if the &lt;quote&gt;mail_delivery_method&lt;/quote&gt;
+                parameter is set to SMTP.  Use &quot;localhost&quot; if you have a local MTA
+                running, otherwise use a remote SMTP server.  Append &quot;:&quot; and the port
+                number, if a non-default port is needed.
</ins><span class="cx">               &lt;/para&gt;
</span><span class="cx">             &lt;/listitem&gt;
</span><span class="cx">           &lt;/varlistentry&gt;
</span><span class="cx"> 
</span><span class="cx">           &lt;varlistentry&gt;
</span><span class="cx">             &lt;term&gt;
</span><ins>+              smtp_username
+            &lt;/term&gt;
+            &lt;listitem&gt;
+              &lt;para&gt;
+                Username to use for SASL authentication to the SMTP server.  Leave
+                this parameter empty if your server does not require authentication.
+              &lt;/para&gt;
+            &lt;/listitem&gt;
+          &lt;/varlistentry&gt;
+
+          &lt;varlistentry&gt;
+            &lt;term&gt;
+              smtp_password
+            &lt;/term&gt;
+            &lt;listitem&gt;
+              &lt;para&gt;
+                Password to use for SASL authentication to the SMTP server. This
+                parameter will be ignored if the &lt;quote&gt;smtp_username&lt;/quote&gt;
+                parameter is left empty.
+              &lt;/para&gt;
+            &lt;/listitem&gt;
+          &lt;/varlistentry&gt;
+
+          &lt;varlistentry&gt;
+            &lt;term&gt;
+              smtp_ssl
+            &lt;/term&gt;
+            &lt;listitem&gt;
+              &lt;para&gt;
+                Enable SSL support for connection to the SMTP server.
+              &lt;/para&gt;
+            &lt;/listitem&gt;
+          &lt;/varlistentry&gt;
+
+          &lt;varlistentry&gt;
+            &lt;term&gt;
+              smtp_debug
+            &lt;/term&gt;
+            &lt;listitem&gt;
+              &lt;para&gt;
+                This parameter allows you to enable detailed debugging output.
+                Log messages are printed the web server's error log.
+              &lt;/para&gt;
+            &lt;/listitem&gt;
+          &lt;/varlistentry&gt;
+
+          &lt;varlistentry&gt;
+            &lt;term&gt;
</ins><span class="cx">               whinedays
</span><span class="cx">             &lt;/term&gt;
</span><span class="cx">             &lt;listitem&gt;
</span><span class="cx">               &lt;para&gt;
</span><span class="cx">                 Set this to the number of days you want to let bugs go
</span><del>-                in the NEW or REOPENED state before notifying people they have
</del><ins>+                in the CONFIRMED state before notifying people they have
</ins><span class="cx">                 untouched new bugs. If you do not plan to use this feature, simply 
</span><span class="cx">                 do not set up the whining cron job described in the installation
</span><span class="cx">                 instructions, or set this value to &quot;0&quot; (never whine).
</span><span class="lines">@@ -932,7 +924,12 @@
</span><span class="cx">             contains parameters for how user names can be queried and matched
</span><span class="cx">             when entered.
</span><span class="cx">           &lt;/para&gt;
</span><del>-
</del><ins>+          &lt;para&gt;
+            Another setting called 'ajax_user_autocompletion' enables certain
+            user fields to display a list of matched user names as a drop down after typing 
+            a few characters. Note that it is recommended to use mod_perl when
+            enabling 'ajax_user_autocompletion'.
+          &lt;/para&gt;
</ins><span class="cx">         &lt;/section&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;/section&gt;
</span><span class="lines">@@ -1127,7 +1124,10 @@
</span><span class="cx">             &lt;emphasis&gt;&amp;lt;groupname&amp;gt;&lt;/emphasis&gt;: 
</span><span class="cx">             If you have created some groups, e.g. &quot;securitysensitive&quot;, then
</span><span class="cx">             checkboxes will appear here to allow you to add users to, or
</span><del>-            remove them from, these groups.
</del><ins>+            remove them from, these groups. The first checkbox gives the
+            user the ability to add and remove other users as members of
+            this group. The second checkbox adds the user himself as a member
+            of the group.
</ins><span class="cx">             &lt;/para&gt;
</span><span class="cx">           &lt;/listitem&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -1309,7 +1309,7 @@
</span><span class="cx">     basis. The number of &lt;quote&gt;votes&lt;/quote&gt; available to 
</span><span class="cx">     users is set per-product, as is the number of votes
</span><span class="cx">     required to move a bug automatically from the UNCONFIRMED 
</span><del>-    status to the NEW status.
</del><ins>+    status to the CONFIRMED status.
</ins><span class="cx">     &lt;/para&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;para&gt;
</span><span class="lines">@@ -1343,17 +1343,6 @@
</span><span class="cx"> 
</span><span class="cx">       &lt;varlistentry&gt;
</span><span class="cx">         &lt;term&gt;
</span><del>-          URL describing milestones for this product
-        &lt;/term&gt;
-        &lt;listitem&gt;
-          &lt;para&gt; 
-            If there is reference URL, provide it here
-          &lt;/para&gt;
-        &lt;/listitem&gt;
-      &lt;/varlistentry&gt;
-
-      &lt;varlistentry&gt;
-        &lt;term&gt;
</del><span class="cx">           Default milestone
</span><span class="cx">         &lt;/term&gt;
</span><span class="cx">         &lt;listitem&gt;
</span><span class="lines">@@ -1882,12 +1871,12 @@
</span><span class="cx"> 
</span><span class="cx">     &lt;note&gt;
</span><span class="cx">       &lt;para&gt;Milestone options will only appear for a Product if you turned
</span><del>-      on the &quot;usetargetmilestone&quot; Param in the &quot;Edit Parameters&quot; screen.
</del><ins>+      on the &quot;usetargetmilestone&quot; parameter in the &quot;Bug Fields&quot; tab of the
+      &quot;Parameters&quot; page.
</ins><span class="cx">       &lt;/para&gt;
</span><span class="cx">     &lt;/note&gt;
</span><span class="cx"> 
</span><del>-    &lt;para&gt;To create new Milestones, set Default Milestones, and set
-    Milestone URL:&lt;/para&gt;
</del><ins>+    &lt;para&gt;To create new Milestones, and set Default Milestones:&lt;/para&gt;
</ins><span class="cx"> 
</span><span class="cx">     &lt;orderedlist&gt;
</span><span class="cx">       &lt;listitem&gt;
</span><span class="lines">@@ -1895,8 +1884,7 @@
</span><span class="cx">       &lt;/listitem&gt;
</span><span class="cx"> 
</span><span class="cx">       &lt;listitem&gt;
</span><del>-        &lt;para&gt;Select &quot;Add&quot; in the bottom right corner.
-        text&lt;/para&gt;
</del><ins>+        &lt;para&gt;Select &quot;Add&quot; in the bottom right corner.&lt;/para&gt;
</ins><span class="cx">       &lt;/listitem&gt;
</span><span class="cx"> 
</span><span class="cx">       &lt;listitem&gt;
</span><span class="lines">@@ -1907,12 +1895,6 @@
</span><span class="cx">         occur in alphanumeric order For example, &quot;Future&quot; might be
</span><span class="cx">         after &quot;Release 1.2&quot;. Select &quot;Add&quot;.&lt;/para&gt;
</span><span class="cx">       &lt;/listitem&gt;
</span><del>-
-      &lt;listitem&gt;
-        &lt;para&gt;From the Edit product screen, you can enter the URL of a 
-        page which gives information about your milestones and what
-        they mean. &lt;/para&gt;
-      &lt;/listitem&gt;
</del><span class="cx">     &lt;/orderedlist&gt;
</span><span class="cx">   &lt;/section&gt;
</span><span class="cx">   
</span><span class="lines">@@ -2136,8 +2118,8 @@
</span><span class="cx">      &lt;section id=&quot;flags-edit&quot;&gt;
</span><span class="cx">        &lt;title&gt;Editing a Flag&lt;/title&gt;
</span><span class="cx">        &lt;para&gt;
</span><del>-         To edit a flag's properties, just click on the &lt;quote&gt;Edit&lt;/quote&gt;
-         link next to the flag's description. That will take you to the same
</del><ins>+         To edit a flag's properties, just click the flag's name.
+         That will take you to the same
</ins><span class="cx">          form as described below (&lt;xref linkend=&quot;flags-create&quot;/&gt;).
</span><span class="cx">        &lt;/para&gt;
</span><span class="cx">      &lt;/section&gt;
</span><span class="lines">@@ -2445,6 +2427,11 @@
</span><span class="cx">               several types available:
</span><span class="cx">                &lt;simplelist&gt;
</span><span class="cx">                  &lt;member&gt;
</span><ins>+                   Bug ID: A field where you can enter the ID of another bug from
+                   the same Bugzilla installation. To point to a bug in a remote
+                   installation, use the See Also field instead.
+                 &lt;/member&gt;
+                 &lt;member&gt;
</ins><span class="cx">                    Large Text Box: A multiple line box for entering free text.
</span><span class="cx">                  &lt;/member&gt;
</span><span class="cx">                  &lt;member&gt;
</span><span class="lines">@@ -2483,6 +2470,16 @@
</span><span class="cx"> 
</span><span class="cx">           &lt;listitem&gt;
</span><span class="cx">             &lt;para&gt;
</span><ins>+              &lt;emphasis&gt;Reverse Relationship Description:&lt;/emphasis&gt;
+              When the custom field is of type &lt;quote&gt;Bug ID&lt;/quote&gt;, you can
+              enter text here which will be used as label in the referenced
+              bug to list bugs which point to it. This gives you the ability
+              to have a mutual relationship between two bugs.
+            &lt;/para&gt;
+          &lt;/listitem&gt;
+
+          &lt;listitem&gt;
+            &lt;para&gt;
</ins><span class="cx">               &lt;emphasis&gt;Can be set on bug creation:&lt;/emphasis&gt;
</span><span class="cx">               Boolean that determines whether this field can be set on
</span><span class="cx">               bug creation. If not selected, then a bug must be created 
</span><span class="lines">@@ -2507,6 +2504,45 @@
</span><span class="cx">               be displayed at all. Obsolete Custom Fields are hidden.
</span><span class="cx">             &lt;/para&gt;
</span><span class="cx">           &lt;/listitem&gt;
</span><ins>+
+          &lt;listitem&gt;
+            &lt;para&gt;
+              &lt;emphasis&gt;Is mandatory:&lt;/emphasis&gt;
+              Boolean that determines whether this field must be set.
+              For single and multi-select fields, this means that a (non-default)
+              value must be selected, and for text and date fields, some text
+              must be entered.
+            &lt;/para&gt;
+          &lt;/listitem&gt;
+
+          &lt;listitem&gt;
+            &lt;para&gt;
+              &lt;emphasis&gt;Field only appears when:&lt;/emphasis&gt;
+              A custom field can be made visible when some criteria is met.
+              For instance, when the bug belongs to one or more products,
+              or when the bug is of some given severity. If left empty, then
+              the custom field will always be visible, in all bugs.
+            &lt;/para&gt;
+          &lt;/listitem&gt;
+
+          &lt;listitem&gt;
+            &lt;para&gt;
+              &lt;emphasis&gt;Field that controls the values that appear in this field:&lt;/emphasis&gt;
+              When the custom field is of type &lt;quote&gt;Drop Down&lt;/quote&gt; or
+              &lt;quote&gt;Multiple-Selection Box&lt;/quote&gt;, you can restrict the
+              availability of the values of the custom field based on the
+              value of another field. This criteria is independent of the
+              criteria used in the &lt;quote&gt;Field only appears when&lt;/quote&gt;
+              setting. For instance, you may decide that some given value
+              &lt;quote&gt;valueY&lt;/quote&gt; is only available when the bug status
+              is RESOLVED while the value &lt;quote&gt;valueX&lt;/quote&gt; should
+              always be listed.
+              Once you have selected the field which should control the
+              availability of the values of this custom field, you can
+              edit values of this custom field to set the criteria, see
+              &lt;xref linkend=&quot;edit-values-list&quot; /&gt;.
+            &lt;/para&gt;
+          &lt;/listitem&gt;
</ins><span class="cx">         &lt;/itemizedlist&gt;
</span><span class="cx">       &lt;/para&gt;
</span><span class="cx">     &lt;/section&gt;
</span><span class="lines">@@ -2526,10 +2562,13 @@
</span><span class="cx">       &lt;title&gt;Deleting Custom Fields&lt;/title&gt;
</span><span class="cx"> 
</span><span class="cx">       &lt;para&gt;
</span><del>-        It is only possible to delete obsolete Custom Fields 
-        if the field has never been used in the database.
-        To remove a field which already has content,
-        mark it as obsolete.
</del><ins>+        Only custom fields which are marked as obsolete, and which never
+        have been used, can be deleted completely (else the integrity
+        of the bug history would be compromised). For custom fields marked
+        as obsolete, a &quot;Delete&quot; link will appear in the &lt;quote&gt;Action&lt;/quote&gt;
+        column. If the custom field has been used in the past, the deletion
+        will be rejected. But marking the field as obsolete is sufficient
+        to hide it from the user interface entirely.
</ins><span class="cx">       &lt;/para&gt;
</span><span class="cx">     &lt;/section&gt;
</span><span class="cx">   &lt;/section&gt;
</span><span class="lines">@@ -2538,20 +2577,19 @@
</span><span class="cx">     &lt;title&gt;Legal Values&lt;/title&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;para&gt;
</span><del>-      Since Bugzilla 2.20 RC1, legal values for Operating Systems, platforms,
-      bug priorities and severities can be edited from the User Interface
-      directly. This means that it is no longer required to manually edit
-      &lt;filename&gt;localconfig&lt;/filename&gt;. Starting with Bugzilla 2.23.3, 
-      the list of valid resolutions can be customized from the same interface.
-      Since Bugzilla 3.1.1 the list of valid bug statuses can be customized
-      as well.
</del><ins>+      Legal values for the operating system, platform, bug priority and
+      severity, custom fields of type &lt;quote&gt;Drop Down&lt;/quote&gt; and
+      &lt;quote&gt;Multiple-Selection Box&lt;/quote&gt; (see &lt;xref linkend=&quot;custom-fields&quot; /&gt;),
+      as well as the list of valid bug statuses and resolutions can be
+      customized from the same interface. You can add, edit, disable and
+      remove values which can be used with these fields.
</ins><span class="cx">     &lt;/para&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;section id=&quot;edit-values-list&quot;&gt;
</span><span class="cx">       &lt;title&gt;Viewing/Editing legal values&lt;/title&gt;
</span><span class="cx">       &lt;para&gt;
</span><span class="cx">         Editing legal values requires &lt;quote&gt;admin&lt;/quote&gt; privileges.
</span><del>-        Select &quot;Legal Values&quot; from the Administration page. A list of all
</del><ins>+        Select &quot;Field Values&quot; from the Administration page. A list of all
</ins><span class="cx">         fields, both system fields and Custom Fields, for which legal values
</span><span class="cx">         can be edited appears. Click a field name to edit its legal values.
</span><span class="cx">       &lt;/para&gt;
</span><span class="lines">@@ -2560,6 +2598,11 @@
</span><span class="cx">         must be unique to that field. The sortkey is important to display these
</span><span class="cx">         values in the desired order.
</span><span class="cx">       &lt;/para&gt;
</span><ins>+      &lt;para&gt;
+        When the availability of the values of a custom field is controlled
+        by another field, you can select from here which value of the other field
+        must be set for the value of the custom field to appear.
+      &lt;/para&gt;
</ins><span class="cx">     &lt;/section&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;section id=&quot;edit-values-delete&quot;&gt;
</span><span class="lines">@@ -2611,12 +2654,17 @@
</span><span class="cx">   &lt;section id=&quot;voting&quot;&gt;
</span><span class="cx">     &lt;title&gt;Voting&lt;/title&gt;
</span><span class="cx"> 
</span><ins>+    &lt;para&gt;All of the code for voting in Bugzilla has been moved into an
+    extension, called &quot;Voting&quot;, in the &lt;filename&gt;extensions/Voting/&lt;/filename&gt;
+    directory. To enable it, you must remove the &lt;filename&gt;disabled&lt;/filename&gt;
+    file from that directory, and run &lt;filename&gt;checksetup.pl&lt;/filename&gt;.&lt;/para&gt;
+
</ins><span class="cx">     &lt;para&gt;Voting allows users to be given a pot of votes which they can allocate
</span><span class="cx">     to bugs, to indicate that they'd like them fixed. 
</span><span class="cx">     This allows developers to gauge
</span><span class="cx">     user need for a particular enhancement or bugfix. By allowing bugs with
</span><span class="cx">     a certain number of votes to automatically move from &quot;UNCONFIRMED&quot; to
</span><del>-    &quot;NEW&quot;, users of the bug system can help high-priority bugs garner
</del><ins>+    &quot;CONFIRMED&quot;, users of the bug system can help high-priority bugs garner
</ins><span class="cx">     attention so they don't sit for a long time awaiting triage.&lt;/para&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;para&gt;To modify Voting settings:&lt;/para&gt;
</span><span class="lines">@@ -2645,7 +2693,7 @@
</span><span class="cx">         &lt;para&gt;&lt;emphasis&gt;Number of votes a bug in this product needs to
</span><span class="cx">         automatically get out of the UNCONFIRMED state&lt;/emphasis&gt;: 
</span><span class="cx">         Setting this field to &quot;0&quot; disables the automatic move of
</span><del>-        bugs from UNCONFIRMED to NEW. 
</del><ins>+        bugs from UNCONFIRMED to CONFIRMED. 
</ins><span class="cx">         &lt;/para&gt;
</span><span class="cx">       &lt;/listitem&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -2667,12 +2715,12 @@
</span><span class="cx">     &lt;/para&gt;
</span><span class="cx">   
</span><span class="cx">     &lt;para&gt;
</span><del>-      Quips are controlled by the &lt;emphasis&gt;enablequips&lt;/emphasis&gt; parameter.
-      It has several possible values: on, approved, frozen or off.
-      In order to enable quips approval you need to set this parameter
-      to &quot;approved&quot;. In this way, users are free to submit quips for
-      addition but an administrator must explicitly approve them before
-      they are actually used.
</del><ins>+      Quip submission is controlled by the &lt;emphasis&gt;quip_list_entry_control&lt;/emphasis&gt;
+      parameter.  It has several possible values: open, moderated, or closed.
+      In order to enable quips approval you need to set this parameter to
+      &quot;moderated&quot;. In this way, users are free to submit quips for addition
+      but an administrator must explicitly approve them before they are
+      actually used.
</ins><span class="cx">     &lt;/para&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;para&gt;
</span><span class="lines">@@ -2687,7 +2735,7 @@
</span><span class="cx">     &lt;/para&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;para&gt;
</span><del>-      Next to each tip there is a checkbox, under the
</del><ins>+      Next to each quip there is a checkbox, under the
</ins><span class="cx">       &quot;Approved&quot; column. Quips who have this checkbox checked are
</span><span class="cx">       already approved and will appear next to the search results.
</span><span class="cx">       The ones that have it unchecked are still preserved in the
</span><span class="lines">@@ -2699,6 +2747,11 @@
</span><span class="cx">       Also, there is a delete link next to each quip,
</span><span class="cx">       which can be used in order to permanently delete a quip.
</span><span class="cx">     &lt;/para&gt;
</span><ins>+
+    &lt;para&gt;
+      Display of quips is controlled by the &lt;emphasis&gt;display_quips&lt;/emphasis&gt;
+      user preference.  Possible values are &quot;on&quot; and &quot;off&quot;.
+    &lt;/para&gt;
</ins><span class="cx">   &lt;/section&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;section id=&quot;groups&quot;&gt;
</span><span class="lines">@@ -2706,7 +2759,7 @@
</span><span class="cx"> 
</span><span class="cx">     &lt;para&gt;
</span><span class="cx">     Groups allow for separating bugs into logical divisions.
</span><del>-    Groups are typically used to
</del><ins>+    Groups are typically used
</ins><span class="cx">     to isolate bugs that should only be seen by certain people. For
</span><span class="cx">     example, a company might create a different group for each one of its customers
</span><span class="cx">     or partners. Group permissions could be set so that each partner or customer would
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgdocsenxmlcustomizationxml"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/docs/en/xml/customization.xml (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/docs/en/xml/customization.xml        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/docs/en/xml/customization.xml        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -2,6 +2,23 @@
</span><span class="cx"> &lt;chapter id=&quot;customization&quot;&gt;
</span><span class="cx">   &lt;title&gt;Customizing Bugzilla&lt;/title&gt;
</span><span class="cx"> 
</span><ins>+  &lt;section id=&quot;extensions&quot;&gt;
+    &lt;title&gt;Bugzilla Extensions&lt;/title&gt;
+
+    &lt;para&gt;
+      One of the best ways to customize Bugzilla is by writing a Bugzilla
+      Extension. Bugzilla Extensions let you modify both the code and
+      UI of Bugzilla in a way that can be distributed to other Bugzilla
+      users and ported forward to future versions of Bugzilla with minimal
+      effort.
+    &lt;/para&gt;
+
+    &lt;para&gt;
+      See the &lt;ulink url=&quot;api/Bugzilla/Extension.html&quot;&gt;Bugzilla Extension
+      documentation&lt;/ulink&gt; for information on how to write an Extension.
+    &lt;/para&gt;
+  &lt;/section&gt;
+
</ins><span class="cx">   &lt;section id=&quot;cust-skins&quot;&gt;
</span><span class="cx">     &lt;title&gt;Custom Skins&lt;/title&gt;
</span><span class="cx">     
</span><span class="lines">@@ -146,9 +163,9 @@
</span><span class="cx">       &lt;note&gt;
</span><span class="cx">         &lt;para&gt;
</span><span class="cx">           Regardless of which method you choose, it is recommended that
</span><del>-          you run &lt;command&gt;./checksetup.pl&lt;/command&gt; after creating or
</del><ins>+          you run &lt;command&gt;./checksetup.pl&lt;/command&gt; after 
</ins><span class="cx">           editing any templates in the &lt;filename&gt;template/en/default&lt;/filename&gt;
</span><del>-          directory, and after editing any templates in the 
</del><ins>+          directory, and after creating or editing any templates in the 
</ins><span class="cx">           &lt;filename&gt;custom&lt;/filename&gt; directory.
</span><span class="cx">         &lt;/para&gt;
</span><span class="cx">       &lt;/note&gt;
</span><span class="lines">@@ -190,21 +207,12 @@
</span><span class="cx">         This means that if the data can possibly contain special HTML characters
</span><span class="cx">         such as &amp;lt;, and the data was not intended to be HTML, they need to be
</span><span class="cx">         converted to entity form, i.e. &amp;amp;lt;.  You use the 'html' filter in the
</span><del>-        Template Toolkit to do this.  If you forget, you may open up
-        your installation to cross-site scripting attacks.
</del><ins>+        Template Toolkit to do this (or the 'uri' filter to encode special
+        characters in URLs).  If you forget, you may open up your installation
+        to cross-site scripting attacks.
</ins><span class="cx">       &lt;/para&gt;
</span><span class="cx"> 
</span><span class="cx">       &lt;para&gt;
</span><del>-        Also note that Bugzilla adds a few filters of its own, that are not
-        in standard Template Toolkit.  In particular, the 'url_quote' filter
-        can convert characters that are illegal or have special meaning in URLs,
-        such as &amp;amp;, to the encoded form, i.e. %26.  This actually encodes most
-        characters (but not the common ones such as letters and numbers and so
-        on), including the HTML-special characters, so there's never a need to
-        HTML filter afterwards.
-      &lt;/para&gt;

-      &lt;para&gt;
</del><span class="cx">         Editing templates is a good way of doing a &lt;quote&gt;poor man's custom
</span><span class="cx">         fields&lt;/quote&gt;.
</span><span class="cx">         For example, if you don't use the Status Whiteboard, but want to have
</span><span class="lines">@@ -438,241 +446,6 @@
</span><span class="cx">       
</span><span class="cx">   &lt;/section&gt;
</span><span class="cx"> 
</span><del>-  &lt;section id=&quot;cust-hooks&quot;&gt;
-    &lt;title&gt;The Bugzilla Extension Mechanism&lt;/title&gt;
-    
-    &lt;warning&gt;
-      &lt;para&gt;
-        Note that the below paths are inconsistent and confusing. They will
-        likely be changed in Bugzilla 4.0.
-      &lt;/para&gt;
-    &lt;/warning&gt;
-       
-    &lt;para&gt;
-      Extensions are a way for extensions to Bugzilla to insert code
-      into the standard Bugzilla templates and source files
-      without modifying these files themselves.  The extension mechanism 
-      defines a consistent API for extending the standard templates and source files 
-      in a way that cleanly separates standard code from extension code.  
-      Hooks reduce merge conflicts and make it easier to write extensions that work 
-      across multiple versions of Bugzilla, making upgrading a Bugzilla installation 
-      with installed extensions easier. Furthermore, they make it easy to install 
-      and remove extensions as each extension is nothing more than a 
-      simple directory structure. 
-    &lt;/para&gt;
-    
-    &lt;para&gt;
-      There are two main types of hooks: code hooks and template hooks. Code 
-      hooks allow extensions to invoke code at specific points in various 
-      source files, while template hooks allow extensions to add elements to 
-      the Bugzilla user interface. 
-    &lt;/para&gt;
-
-    &lt;para&gt;
-      A hook is just a named place in a standard source or template file
-      where extension source code or template files for that hook get processed. 
-      Each extension has a corresponding directory in the Bugzilla directory 
-      tree (&lt;filename&gt;BUGZILLA_ROOT/extensions/extension_name&lt;/filename&gt;).  Hooking 
-      an extension source file or template to a hook is as simple as putting 
-      the extension file into extension's template or code directory. 
-      When Bugzilla processes the source file or template and reaches the hook, 
-      it will process all extension files in the hook's directory. 
-      The hooks themselves can be added into any source file or standard template 
-      upon request by extension authors.
-    &lt;/para&gt;
-    
-    &lt;para&gt;
-      To use hooks to extend Bugzilla, first make sure there is
-      a hook at the appropriate place within the source file or template you 
-      want to extend. The exact appearance of a hook depends on if the hook 
-      is a code hook or a template hook. 
-    &lt;/para&gt;
-    
-    &lt;para&gt;
-      Code hooks appear in Bugzilla source files as a single method call 
-      in the format &lt;literal role=&quot;code&quot;&gt;Bugzilla::Hook-&gt;process(&quot;&lt;varname&gt;name&lt;/varname&gt;&quot;);&lt;/literal&gt;.
-      For instance, &lt;filename&gt;enter_bug.cgi&lt;/filename&gt; may invoke the hook 
-      &quot;&lt;varname&gt;enter_bug-entrydefaultvars&lt;/varname&gt;&quot;. Thus, a source file at 
-      &lt;filename&gt;BUGZILLA_ROOT/extensions/EXTENSION_NAME/code/enter_bug-entrydefaultvars.pl&lt;/filename&gt;
-      will be automatically invoked when the code hook is reached. 
-    &lt;/para&gt;
-   
-    &lt;para&gt;  
-      Template hooks appear in the standard Bugzilla templates as a 
-      single directive in the format
-      &lt;literal role=&quot;code&quot;&gt;[% Hook.process(&quot;&lt;varname&gt;name&lt;/varname&gt;&quot;) %]&lt;/literal&gt;,
-      where &lt;varname&gt;name&lt;/varname&gt; is the unique name of the hook.
-    &lt;/para&gt;
-
-    &lt;para&gt;
-      If you aren't sure what you want to extend or just want to browse the 
-      available hooks, either use your favorite multi-file search
-      tool (e.g. &lt;command&gt;grep&lt;/command&gt;) to search the standard templates
-      for occurrences of &lt;methodname&gt;Hook.process&lt;/methodname&gt; or the source 
-      files for occurrences of &lt;methodname&gt;Bugzilla::Hook::process&lt;/methodname&gt;.
-    &lt;/para&gt;
-
-    &lt;para&gt;
-      If there is no hook at the appropriate place within the Bugzilla 
-      source file or template you want to extend,
-      &lt;ulink url=&quot;http://bugzilla.mozilla.org/enter_bug.cgi?product=Bugzilla&amp;amp;component=User%20Interface&quot;&gt;file
-      a bug requesting one&lt;/ulink&gt;, specifying:
-    &lt;/para&gt;
-
-    &lt;simplelist&gt;
-      &lt;member&gt;the source or template file for which you are 
-          requesting a hook;&lt;/member&gt;
-      &lt;member&gt;
-        where in the file you would like the hook to be placed
-        (line number/position for latest version of the file in CVS
-        or description of location);
-      &lt;/member&gt;
-      &lt;member&gt;the purpose of the hook;&lt;/member&gt;
-      &lt;member&gt;a link to information about your extension, if any.&lt;/member&gt;
-    &lt;/simplelist&gt;
-
-    &lt;para&gt;
-      The Bugzilla reviewers will promptly review each hook request,
-      name the hook, add it to the template or source file, and check 
-      the new version of the template into CVS.
-    &lt;/para&gt;
-
-    &lt;para&gt;
-      You may optionally attach a patch to the bug which implements the hook
-      and check it in yourself after receiving approval from a Bugzilla
-      reviewer.  The developers may suggest changes to the location of the
-      hook based on their analysis of your needs or so the hook can satisfy
-      the needs of multiple extensions, but the process of getting hooks
-      approved and checked in is not as stringent as the process for general
-      changes to Bugzilla, and any extension, whether released or still in
-      development, can have hooks added to meet their needs.
-    &lt;/para&gt;
-
-    &lt;para&gt;
-      After making sure the hook you need exists (or getting it added if not),
-      add your extension to the directory within the Bugzilla
-      extensions tree corresponding to the hook. 
-    &lt;/para&gt;
-    
-    &lt;para&gt;
-      That's it!  Now, when the source file or template containing the hook
-      is processed, your extension file will be processed at the point 
-      where the hook appears.
-    &lt;/para&gt;
-
-    &lt;para&gt;
-      For example, let's say you have an extension named Projman that adds
-      project management capabilities to Bugzilla.  Projman has an
-      administration interface &lt;filename&gt;edit-projects.cgi&lt;/filename&gt;, 
-      and you want to add a link to it into the navigation bar at the bottom
-      of every Bugzilla page for those users who are authorized
-      to administer projects.
-    &lt;/para&gt;
-
-    &lt;para&gt;
-      The navigation bar is generated by the template file
-      &lt;filename&gt;useful-links.html.tmpl&lt;/filename&gt;, which is located in
-      the &lt;filename&gt;global/&lt;/filename&gt; subdirectory on the standard Bugzilla 
-      template path
-      &lt;filename&gt;BUGZILLA_ROOT/template/en/default/&lt;/filename&gt;.
-      Looking in &lt;filename&gt;useful-links.html.tmpl&lt;/filename&gt;, you find
-      the following hook at the end of the list of standard Bugzilla
-      administration links:
-    &lt;/para&gt;
-
-    &lt;programlisting&gt;&lt;![CDATA[...
-    [% ', &lt;a href=&quot;editkeywords.cgi&quot;&gt;keywords&lt;/a&gt;' 
-                                              IF user.groups.editkeywords %]
-    [% Hook.process(&quot;edit&quot;) %]
-...]]&gt;&lt;/programlisting&gt;
-
-    &lt;para&gt;
-      The corresponding extension file for this hook is
-      &lt;filename&gt;BUGZILLA_ROOT/extensions/projman/template/en/global/useful-links-edit.html.tmpl&lt;/filename&gt;.
-      You then create that template file and add the following constant:
-    &lt;/para&gt;
-
-    &lt;programlisting&gt;&lt;![CDATA[...[% ', &lt;a href=&quot;edit-projects.cgi&quot;&gt;projects&lt;/a&gt;' IF user.groups.projman_admins %]]]&gt;&lt;/programlisting&gt;
-
-    &lt;para&gt;
-      Voila!  The link now appears after the other administration links in the
-      navigation bar for users in the &lt;literal&gt;projman_admins&lt;/literal&gt; group.
-    &lt;/para&gt;
-    
-    &lt;para&gt;
-      Now, let us say your extension adds a custom &quot;project_manager&quot; field 
-      to enter_bug.cgi. You want to modify the CGI script to set the default 
-      project manager to be productname@company.com. Looking at 
-      &lt;filename&gt;enter_bug.cgi&lt;/filename&gt;, you see the enter_bug-entrydefaultvars 
-      hook near the bottom of the file before the default form values are set. 
-      The corresponding extension source file for this hook is located at 
-      &lt;filename&gt;BUGZILLA_ROOT/extensions/projman/code/enter_bug-entrydefaultvars.pl&lt;/filename&gt;.
-      You then create that file and add the following:
-    &lt;/para&gt;
-    
-    &lt;programlisting&gt;$default{'project_manager'} = $product.'@company.com';&lt;/programlisting&gt;
-    
-    &lt;para&gt;
-      This code will be invoked whenever enter_bug.cgi is executed. 
-      Assuming that the rest of the customization was completed (e.g. the 
-      custom field was added to the enter_bug template and the required hooks 
-      were used in process_bug.cgi), the new field will now have this 
-      default value. 
-    &lt;/para&gt;
-      
-    &lt;para&gt;
-      Notes:
-    &lt;/para&gt;
-
-    &lt;itemizedlist&gt;
-      &lt;listitem&gt;
-        &lt;para&gt;
-          If your extension includes entirely new templates in addition to
-          extensions of standard templates, it should store those new
-          templates in its
-          &lt;filename&gt;BUGZILLA_ROOT/extensions/template/en/&lt;/filename&gt; 
-          directory. Extension template directories, like the 
-          &lt;filename&gt;default/&lt;/filename&gt; and &lt;filename&gt;custom/&lt;/filename&gt;
-          directories, are part of the template search path, so putting templates
-          there enables them to be found by the template processor.
-        &lt;/para&gt;
-
-        &lt;para&gt;
-          The template processor looks for templates first in the
-          &lt;filename&gt;custom/&lt;/filename&gt; directory (i.e. templates added by the 
-          specific installation), then in the &lt;filename&gt;extensions/&lt;/filename&gt;
-          directory (i.e. templates added by extensions), and finally in the 
-          &lt;filename&gt;default/&lt;/filename&gt; directory (i.e. the standard Bugzilla 
-          templates). Thus, installation-specific templates override both 
-          default and extension templates.
-        &lt;/para&gt;
-      &lt;/listitem&gt;
-
-      &lt;listitem&gt;
-        &lt;para&gt;
-          If you are looking to customize Bugzilla, you can also take advantage 
-          of template hooks. To do so, create a directory in
-          &lt;filename&gt;BUGZILLA_ROOT/template/en/custom/hook/&lt;/filename&gt;
-          that corresponds to the hook you wish to use, then place your 
-          customization templates into those directories. For example, 
-          if you wanted to use the hook &quot;end&quot; in 
-          &lt;filename&gt;global/useful-links.html.tmpl&lt;/filename&gt;, you would 
-          create the directory &lt;filename&gt;BUGZILLA_ROOT/template/en/custom/hook/
-          global/useful-links.html.tmpl/end/&lt;/filename&gt; and add your customization 
-          template to this directory. 
-        &lt;/para&gt;
-
-        &lt;para&gt;
-          Obviously this method of customizing Bugzilla only lets you add code
-          to the standard source files and templates; you cannot change the 
-          existing code. Nevertheless, for those customizations that only add 
-          code, this method can reduce conflicts when merging changes, 
-          making upgrading your customized Bugzilla installation easier.
-        &lt;/para&gt;
-      &lt;/listitem&gt;
-    &lt;/itemizedlist&gt;    
-  &lt;/section&gt;
-
</del><span class="cx">   &lt;section id=&quot;cust-change-permissions&quot;&gt;
</span><span class="cx">     &lt;title&gt;Customizing Who Can Change What&lt;/title&gt;
</span><span class="cx">     
</span><span class="lines">@@ -746,7 +519,7 @@
</span><span class="cx">       positive check, which returns 1 (allow) if certain conditions are true,
</span><span class="cx">       or a negative check, which returns 0 (deny.) E.g.:
</span><span class="cx">       &lt;programlisting&gt;    if ($field eq &quot;qacontact&quot;) {
</span><del>-        if (Bugzilla-&gt;user-&gt;groups(&quot;quality_assurance&quot;)) {
</del><ins>+        if (Bugzilla-&gt;user-&gt;in_group(&quot;quality_assurance&quot;)) {
</ins><span class="cx">             return 1;
</span><span class="cx">         } 
</span><span class="cx">         else {
</span><span class="lines">@@ -790,9 +563,18 @@
</span><span class="cx">     &lt;/para&gt;    
</span><span class="cx">   &lt;/section&gt;   
</span><span class="cx"> 
</span><del>-  &lt;!-- Integrating Bugzilla with Third-Party Tools --&gt;
-  &amp;integration;
</del><ins>+  &lt;section id=&quot;integration&quot;&gt;
+    &lt;title&gt;Integrating Bugzilla with Third-Party Tools&lt;/title&gt;
</ins><span class="cx"> 
</span><ins>+    &lt;para&gt;
+      Many utilities and applications can integrate with Bugzilla,
+      either on the client- or server-side. None of them are maintained
+      by the Bugzilla community, nor are they tested during our
+      QA tests, so use them at your own risk. They are listed at
+      &lt;ulink url=&quot;https://wiki.mozilla.org/Bugzilla:Addons&quot; /&gt;.
+    &lt;/para&gt;
+  &lt;/section&gt;
+
</ins><span class="cx"> &lt;/chapter&gt;
</span><span class="cx"> 
</span><span class="cx"> &lt;!-- Keep this comment at the end of the file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgdocsenxmlgfdlxml"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/docs/en/xml/gfdl.xml (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/docs/en/xml/gfdl.xml        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/docs/en/xml/gfdl.xml        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -9,8 +9,8 @@
</span><span class="cx">   &lt;para&gt;Version 1.1, March 2000&lt;/para&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;blockquote&gt;
</span><del>-    &lt;para&gt;Copyright (C) 2000 Free Software Foundation, Inc. 59 Temple Place,
-    Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and
</del><ins>+    &lt;para&gt;Copyright (C) 2000 Free Software Foundation, Inc. 51 Franklin Street,
+    Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and
</ins><span class="cx">     distribute verbatim copies of this license document, but changing it is
</span><span class="cx">     not allowed.&lt;/para&gt;
</span><span class="cx">   &lt;/blockquote&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgdocsenxmlglossaryxml"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/docs/en/xml/glossary.xml (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/docs/en/xml/glossary.xml        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/docs/en/xml/glossary.xml        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -271,8 +271,6 @@
</span><span class="cx">         Perl module, which Bugzilla uses to send email, can be configured to
</span><span class="cx">         use many different underlying implementations for actually sending the
</span><span class="cx">         mail using the &lt;option&gt;mail_delivery_method&lt;/option&gt; parameter.
</span><del>-        Implementations other than &lt;literal&gt;sendmail&lt;/literal&gt; require that the
-        &lt;option&gt;sendmailnow&lt;/option&gt; param be set to &lt;literal&gt;on&lt;/literal&gt;.
</del><span class="cx">         &lt;/para&gt;
</span><span class="cx">       &lt;/glossdef&gt;
</span><span class="cx">     &lt;/glossentry&gt;
</span><span class="lines">@@ -281,7 +279,7 @@
</span><span class="cx">       &lt;glossterm&gt;MySQL&lt;/glossterm&gt;
</span><span class="cx"> 
</span><span class="cx">       &lt;glossdef&gt;
</span><del>-        &lt;para&gt;MySQL is currently the required
</del><ins>+        &lt;para&gt;MySQL is one of the supported
</ins><span class="cx">         &lt;glossterm linkend=&quot;gloss-rdbms&quot;&gt;RDBMS&lt;/glossterm&gt; for Bugzilla. MySQL
</span><span class="cx">         can be downloaded from &lt;ulink url=&quot;http://www.mysql.com&quot;/&gt;. While you
</span><span class="cx">         should familiarize yourself with all of the documentation, some high
</span><span class="lines">@@ -306,8 +304,7 @@
</span><span class="cx">           &lt;varlistentry&gt;
</span><span class="cx">             &lt;term&gt;&lt;ulink url=&quot;http://www.mysql.com/doc/en/Privilege_system.html&quot;&gt;Privilege System&lt;/ulink&gt;&lt;/term&gt;
</span><span class="cx">             &lt;listitem&gt;
</span><del>-              &lt;para&gt;Much more detailed information about the suggestions in
-              &lt;xref linkend=&quot;security-mysql&quot;/&gt;.
</del><ins>+              &lt;para&gt;Information about how to protect your MySQL server.
</ins><span class="cx">               &lt;/para&gt;
</span><span class="cx">             &lt;/listitem&gt;
</span><span class="cx">           &lt;/varlistentry&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgdocsenxmlinstallationxml"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/docs/en/xml/installation.xml (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/docs/en/xml/installation.xml        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/docs/en/xml/installation.xml        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,5 +1,4 @@
</span><span class="cx"> &lt;!-- &lt;!DOCTYPE chapter PUBLIC &quot;-//OASIS//DTD DocBook XML V4.1.2//EN&quot;&gt; --&gt;
</span><del>-&lt;!-- $Id$ --&gt;
</del><span class="cx"> &lt;chapter id=&quot;installing-bugzilla&quot;&gt;
</span><span class="cx">   &lt;title&gt;Installing Bugzilla&lt;/title&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -84,7 +83,7 @@
</span><span class="cx">       
</span><span class="cx">       &lt;para&gt;Any machine that doesn't have Perl on it is a sad machine indeed.
</span><span class="cx">       If you don't have it and your OS doesn't provide official packages, 
</span><del>-      visit &lt;ulink url=&quot;http://www.perl.com&quot;/&gt;.
</del><ins>+      visit &lt;ulink url=&quot;http://www.perl.org&quot;/&gt;.
</ins><span class="cx">       Although Bugzilla runs with Perl &amp;min-perl-ver;,
</span><span class="cx">       it's a good idea to be using the latest stable version.
</span><span class="cx">       &lt;/para&gt;
</span><span class="lines">@@ -119,8 +118,8 @@
</span><span class="cx">           &lt;/note&gt; 
</span><span class="cx">            
</span><span class="cx">           &lt;para&gt;If you install from something other than a packaging/installation
</span><del>-          system, such as .rpm (Redhat Package), .deb (Debian Package), .exe
-          (Windows Executable), or .msi (Microsoft Installer), make sure the MySQL
</del><ins>+          system, such as .rpm (RPM Package Manager), .deb (Debian Package), .exe
+          (Windows Executable), or .msi (Windows Installer), make sure the MySQL
</ins><span class="cx">           server is started when the machine boots.
</span><span class="cx">           &lt;/para&gt;
</span><span class="cx">       &lt;/section&gt;
</span><span class="lines">@@ -136,8 +135,8 @@
</span><span class="cx">           &lt;/para&gt;
</span><span class="cx">            
</span><span class="cx">           &lt;para&gt;If you install from something other than a packaging/installation
</span><del>-          system, such as .rpm (Redhat Package), .deb (Debian Package), .exe
-          (Windows Executable), or .msi (Microsoft Installer), make sure the
</del><ins>+          system, such as .rpm (RPM Package Manager), .deb (Debian Package), .exe
+          (Windows Executable), or .msi (Windows Installer), make sure the
</ins><span class="cx">           PostgreSQL server is started when the machine boots.
</span><span class="cx">           &lt;/para&gt;
</span><span class="cx">       &lt;/section&gt;
</span><span class="lines">@@ -157,8 +156,8 @@
</span><span class="cx"> 
</span><span class="cx">         &lt;para&gt;
</span><span class="cx">           If you install from something other than a packaging/installation
</span><del>-          system, such as .rpm (Redhat Package), .deb (Debian Package), .exe
-          (Windows Executable), or .msi (Microsoft Installer), make sure the
</del><ins>+          system, such as .rpm (RPM Package Manager), .deb (Debian Package), .exe
+          (Windows Executable), or .msi (Windows Installer), make sure the
</ins><span class="cx">           Oracle server is started when the machine boots.
</span><span class="cx">         &lt;/para&gt;
</span><span class="cx">       &lt;/section&gt;
</span><span class="lines">@@ -243,29 +242,20 @@
</span><span class="cx">       &lt;/para&gt;
</span><span class="cx">       
</span><span class="cx">       &lt;para&gt;
</span><del>-        There is a meta-module called Bundle::Bugzilla, 
-        which installs all the other 
-        modules with a single command. You should use this if you are running
-        Perl 5.6.1 or above.
-      &lt;/para&gt;
-      
-      &lt;para&gt;
-        The preferred way of installing Perl modules is via CPAN on Unix, 
-        or PPM on Windows (see &lt;xref linkend=&quot;win32-perl-modules&quot;/&gt;). These
-        instructions assume you are using CPAN; if for some reason you need 
-        to install the Perl modules manually, see 
-        &lt;xref linkend=&quot;install-perlmodules-manual&quot;/&gt;.
</del><ins>+        The preferred way to install missing Perl modules is to use the package
+        manager provided by your operating system (e.g &lt;quote&gt;rpm&lt;/quote&gt; or
+        &lt;quote&gt;yum&lt;/quote&gt; on Linux distros, or &lt;quote&gt;ppm&lt;/quote&gt; on Windows
+        if using ActivePerl, see &lt;xref linkend=&quot;win32-perl-modules&quot;/&gt;).
+        If some Perl modules are still missing or are too old, then we recommend
+        using the &lt;filename&gt;install-module.pl&lt;/filename&gt; script (doesn't work
+        with ActivePerl on Windows). If for some reason you really need to
+        install the Perl modules manually, see
+        &lt;xref linkend=&quot;install-perlmodules-manual&quot;/&gt;. For instance, on Unix,
+        you invoke &lt;filename&gt;install-module.pl&lt;/filename&gt; as follows:
</ins><span class="cx">       &lt;/para&gt;  
</span><span class="cx">         
</span><del>-      &lt;screen&gt;&lt;prompt&gt;bash#&lt;/prompt&gt; perl -MCPAN -e 'install &quot;&amp;lt;modulename&amp;gt;&quot;'&lt;/screen&gt;
</del><ins>+      &lt;screen&gt;&lt;prompt&gt;bash#&lt;/prompt&gt; perl install-module.pl &amp;lt;modulename&amp;gt;&lt;/screen&gt;
</ins><span class="cx"> 
</span><del>-      &lt;para&gt;
-        If you using Bundle::Bugzilla, invoke the magic CPAN command on it.
-        Otherwise, you need to work down the 
-        list of modules that &lt;filename&gt;checksetup.pl&lt;/filename&gt; says are
-        required, in the order given, invoking the command on each.
-      &lt;/para&gt;
-      
</del><span class="cx">       &lt;tip&gt;
</span><span class="cx">         &lt;para&gt;Many people complain that Perl modules will not install for
</span><span class="cx">         them. Most times, the error messages complain that they are missing a
</span><span class="lines">@@ -299,7 +289,7 @@
</span><span class="cx"> 
</span><span class="cx">         &lt;listitem&gt;
</span><span class="cx">           &lt;para&gt;
</span><del>-            CGI &amp;min-cgi-ver;
</del><ins>+            CGI (&amp;min-cgi-ver;)
</ins><span class="cx">           &lt;/para&gt;
</span><span class="cx">         &lt;/listitem&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -311,14 +301,25 @@
</span><span class="cx">     
</span><span class="cx">         &lt;listitem&gt;
</span><span class="cx">           &lt;para&gt;
</span><ins>+            DateTime (&amp;min-datetime-ver;)
+          &lt;/para&gt;
+        &lt;/listitem&gt;
+
+        &lt;listitem&gt;
+          &lt;para&gt;
+            DateTime::TimeZone (&amp;min-datetime-timezone-ver;)
+          &lt;/para&gt;
+        &lt;/listitem&gt;
+
+        &lt;listitem&gt;
+          &lt;para&gt;
</ins><span class="cx">             DBI (&amp;min-dbi-ver;)
</span><span class="cx">           &lt;/para&gt;
</span><span class="cx">         &lt;/listitem&gt;
</span><span class="cx"> 
</span><span class="cx">         &lt;listitem&gt;
</span><span class="cx">           &lt;para&gt;
</span><del>-            &lt;link linkend=&quot;install-modules-dbd-mysql&quot;&gt;DBD::mysql&lt;/link&gt;
-            (&amp;min-dbd-mysql-ver;) if using MySQL
</del><ins>+            DBD::mysql (&amp;min-dbd-mysql-ver;) if using MySQL
</ins><span class="cx">           &lt;/para&gt;
</span><span class="cx">         &lt;/listitem&gt;
</span><span class="cx">         
</span><span class="lines">@@ -336,71 +337,71 @@
</span><span class="cx"> 
</span><span class="cx">         &lt;listitem&gt;
</span><span class="cx">           &lt;para&gt;
</span><del>-            File::Spec (&amp;min-file-spec-ver;)
</del><ins>+            Digest::SHA (&amp;min-digest-sha-ver;)
</ins><span class="cx">           &lt;/para&gt;
</span><span class="cx">         &lt;/listitem&gt;
</span><span class="cx"> 
</span><span class="cx">         &lt;listitem&gt;
</span><span class="cx">           &lt;para&gt;
</span><del>-            &lt;link linkend=&quot;install-modules-template&quot;&gt;Template&lt;/link&gt;
-            (&amp;min-template-ver;)
</del><ins>+            Email::Send (&amp;min-email-send-ver;)
</ins><span class="cx">           &lt;/para&gt;
</span><span class="cx">         &lt;/listitem&gt;
</span><span class="cx"> 
</span><span class="cx">         &lt;listitem&gt;
</span><span class="cx">           &lt;para&gt;
</span><del>-            Email::Send (&amp;min-email-send-ver;)
</del><ins>+            Email::MIME (&amp;min-email-mime-ver;)
</ins><span class="cx">           &lt;/para&gt;
</span><span class="cx">         &lt;/listitem&gt;
</span><span class="cx"> 
</span><span class="cx">         &lt;listitem&gt;
</span><span class="cx">           &lt;para&gt;
</span><del>-            Email::MIME::Modifier (&amp;min-email-mime-modifier-ver;)
</del><ins>+            Template (&amp;min-template-ver;)
</ins><span class="cx">           &lt;/para&gt;
</span><span class="cx">         &lt;/listitem&gt;
</span><ins>+
+        &lt;listitem&gt;
+          &lt;para&gt;
+            URI (&amp;min-uri-ver;)
+          &lt;/para&gt;
+        &lt;/listitem&gt;
</ins><span class="cx">       &lt;/orderedlist&gt;
</span><span class="cx"> 
</span><span class="cx">       Optional Perl modules:
</span><span class="cx">       &lt;orderedlist&gt;
</span><span class="cx">         &lt;listitem&gt;
</span><span class="cx">           &lt;para&gt;
</span><del>-            &lt;link linkend=&quot;install-modules-gd&quot;&gt;GD&lt;/link&gt;
-            (&amp;min-gd-ver;) for bug charting
</del><ins>+            GD (&amp;min-gd-ver;) for bug charting
</ins><span class="cx">           &lt;/para&gt;
</span><span class="cx">         &lt;/listitem&gt;
</span><span class="cx"> 
</span><span class="cx">         &lt;listitem&gt;
</span><span class="cx">           &lt;para&gt;
</span><span class="cx">             Template::Plugin::GD::Image
</span><del>-            (&amp;min-gd-ver;) for Graphical Reports
</del><ins>+            (&amp;min-template-plugin-gd-image-ver;) for Graphical Reports
</ins><span class="cx">           &lt;/para&gt;
</span><span class="cx">         &lt;/listitem&gt;
</span><span class="cx"> 
</span><span class="cx">         &lt;listitem&gt;
</span><span class="cx">           &lt;para&gt;
</span><del>-            &lt;link linkend=&quot;install-modules-chart-base&quot;&gt;Chart::Base&lt;/link&gt;
-            (&amp;min-chart-base-ver;) for bug charting
</del><ins>+            Chart::Lines (&amp;min-chart-lines-ver;) for bug charting
</ins><span class="cx">           &lt;/para&gt;
</span><span class="cx">         &lt;/listitem&gt;
</span><span class="cx"> 
</span><span class="cx">         &lt;listitem&gt;
</span><span class="cx">           &lt;para&gt;
</span><del>-            &lt;link linkend=&quot;install-modules-gd-graph&quot;&gt;GD::Graph&lt;/link&gt;
-            (&amp;min-gd-graph-ver;) for bug charting
</del><ins>+            GD::Graph (&amp;min-gd-graph-ver;) for bug charting
</ins><span class="cx">           &lt;/para&gt;
</span><span class="cx">         &lt;/listitem&gt;
</span><span class="cx"> 
</span><span class="cx">         &lt;listitem&gt;
</span><span class="cx">           &lt;para&gt;
</span><del>-            &lt;link linkend=&quot;install-modules-gd-text&quot;&gt;GD::Text&lt;/link&gt;
-            (&amp;min-gd-text-ver;) for bug charting
</del><ins>+            GD::Text (&amp;min-gd-text-ver;) for bug charting
</ins><span class="cx">           &lt;/para&gt;
</span><span class="cx">         &lt;/listitem&gt;
</span><span class="cx"> 
</span><span class="cx">         &lt;listitem&gt;
</span><span class="cx">           &lt;para&gt;
</span><del>-            &lt;link linkend=&quot;install-modules-xml-twig&quot;&gt;XML::Twig&lt;/link&gt;
-            (&amp;min-xml-twig-ver;) for bug import/export
</del><ins>+            XML::Twig (&amp;min-xml-twig-ver;) for bug import/export
</ins><span class="cx">           &lt;/para&gt;
</span><span class="cx">         &lt;/listitem&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -419,21 +420,21 @@
</span><span class="cx"> 
</span><span class="cx">         &lt;listitem&gt;
</span><span class="cx">           &lt;para&gt;
</span><del>-            &lt;link linkend=&quot;install-modules-patchreader&quot;&gt;PatchReader&lt;/link&gt;
-            (&amp;min-patchreader-ver;) for pretty HTML view of patches
</del><ins>+            PatchReader (&amp;min-patchreader-ver;) for pretty HTML view of patches
</ins><span class="cx">           &lt;/para&gt;
</span><span class="cx">         &lt;/listitem&gt;
</span><span class="cx"> 
</span><span class="cx">         &lt;listitem&gt;
</span><span class="cx">           &lt;para&gt;
</span><del>-            Image::Magick (&amp;min-image-magick-ver;) for converting BMP image attachments to PNG
</del><ins>+            Net::LDAP
+            (&amp;min-net-ldap-ver;) for LDAP Authentication
</ins><span class="cx">           &lt;/para&gt;
</span><span class="cx">         &lt;/listitem&gt;
</span><span class="cx"> 
</span><span class="cx">         &lt;listitem&gt;
</span><span class="cx">           &lt;para&gt;
</span><del>-            Net::LDAP
-            (&amp;min-net-ldap-ver;) for LDAP Authentication
</del><ins>+            Authen::SASL
+            (&amp;min-authen-sasl-ver;) for SASL Authentication
</ins><span class="cx">           &lt;/para&gt;
</span><span class="cx">         &lt;/listitem&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -446,13 +447,26 @@
</span><span class="cx"> 
</span><span class="cx">         &lt;listitem&gt;
</span><span class="cx">           &lt;para&gt;
</span><del>-            &lt;link linkend=&quot;install-modules-soap-lite&quot;&gt;SOAP::Lite&lt;/link&gt;
-            (&amp;min-soap-lite-ver;) for the web service interface
</del><ins>+            SOAP::Lite (&amp;min-soap-lite-ver;) for the web service interface
</ins><span class="cx">           &lt;/para&gt;
</span><span class="cx">         &lt;/listitem&gt;
</span><span class="cx"> 
</span><span class="cx">         &lt;listitem&gt;
</span><span class="cx">           &lt;para&gt;
</span><ins>+            JSON::RPC
+            (&amp;min-json-rpc-ver;) for the JSON-RPC interface
+          &lt;/para&gt;
+        &lt;/listitem&gt;
+
+        &lt;listitem&gt;
+          &lt;para&gt;
+            Test::Taint
+            (&amp;min-test-taint-ver;) for the web service interface
+          &lt;/para&gt;
+        &lt;/listitem&gt;
+
+        &lt;listitem&gt;
+          &lt;para&gt;
</ins><span class="cx">             HTML::Parser
</span><span class="cx">             (&amp;min-html-parser-ver;) for More HTML in Product/Group Descriptions
</span><span class="cx">           &lt;/para&gt;
</span><span class="lines">@@ -481,127 +495,28 @@
</span><span class="cx"> 
</span><span class="cx">         &lt;listitem&gt;
</span><span class="cx">           &lt;para&gt;
</span><del>-            mod_perl2
-            (&amp;min-mod_perl2-ver;) for mod_perl
</del><ins>+            TheSchwartz
+            (&amp;min-theschwartz-ver;) for Mail Queueing
</ins><span class="cx">           &lt;/para&gt;
</span><span class="cx">         &lt;/listitem&gt;
</span><span class="cx"> 
</span><span class="cx">         &lt;listitem&gt;
</span><span class="cx">           &lt;para&gt;
</span><del>-            CGI
-            (&amp;min-mp-cgi-ver;) for mod_perl
</del><ins>+            Daemon::Generic
+            (&amp;min-daemon-generic-ver;) for Mail Queueing
</ins><span class="cx">           &lt;/para&gt;
</span><span class="cx">         &lt;/listitem&gt;
</span><span class="cx"> 
</span><ins>+        &lt;listitem&gt;
+          &lt;para&gt;
+            mod_perl2
+            (&amp;min-mod_perl2-ver;) for mod_perl
+          &lt;/para&gt;
+        &lt;/listitem&gt;
</ins><span class="cx">       &lt;/orderedlist&gt;
</span><span class="cx">       &lt;/para&gt;
</span><del>-
-      &lt;section id=&quot;install-modules-dbd-mysql&quot;&gt;
-        &lt;title&gt;DBD::mysql&lt;/title&gt;
-
-        &lt;para&gt;The installation process will ask you a few questions about the
-        desired compilation target and your MySQL installation. For most of the
-        questions the provided default will be adequate, but when asked if your
-        desired target is the MySQL or mSQL packages, you should
-        select the MySQL-related ones. Later you will be asked if you wish to
-        provide backwards compatibility with the older MySQL packages; you
-        should answer YES to this question. The default is NO.&lt;/para&gt;
-
-        &lt;para&gt;A host of 'localhost' should be fine. A testing user of 'test',
-        with a null password, should have sufficient access to run
-        tests on the 'test' database which MySQL creates upon installation.
-        &lt;/para&gt;
-      &lt;/section&gt;
-
-      &lt;section id=&quot;install-modules-template&quot;&gt;
-        &lt;title&gt;Template Toolkit (&amp;min-template-ver;)&lt;/title&gt;
-
-        &lt;para&gt;When you install Template Toolkit, you'll get asked various
-        questions about features to enable. The defaults are fine, except
-        that it is recommended you use the high speed XS Stash of the Template
-        Toolkit, in order to achieve best performance.
-        &lt;/para&gt;
-      &lt;/section&gt; 
-
-      &lt;section id=&quot;install-modules-gd&quot;&gt;
-        &lt;title&gt;GD (&amp;min-gd-ver;)&lt;/title&gt;
-
-        &lt;para&gt;The GD module is only required if you want graphical reports.
-        &lt;/para&gt;
-
-        &lt;note&gt;
-          &lt;para&gt;The Perl GD module requires some other libraries that may or
-          may not be installed on your system, including 
-          &lt;classname&gt;libpng&lt;/classname&gt;
-          and 
-          &lt;classname&gt;libgd&lt;/classname&gt;. 
-          The full requirements are listed in the Perl GD module README.
-          If compiling GD fails, it's probably because you're
-          missing a required library.&lt;/para&gt;
-        &lt;/note&gt;
-
-        &lt;tip&gt;
-          &lt;para&gt;The version of the GD module you need is very closely tied
-          to the &lt;classname&gt;libgd&lt;/classname&gt; version installed on your system.
-          If you have a version 1.x of &lt;classname&gt;libgd&lt;/classname&gt; the 2.x
-          versions of the GD module won't work for you.
-         &lt;/para&gt;
-       &lt;/tip&gt;
-      &lt;/section&gt;
-
-      &lt;section id=&quot;install-modules-chart-base&quot;&gt;
-        &lt;title&gt;Chart::Base (&amp;min-chart-base-ver;)&lt;/title&gt;
-
-        &lt;para&gt;The Chart::Base module is only required if you want graphical 
-        reports. 
-        Note that earlier versions that 0.99c used GIFs, which are no longer
-        supported by the latest versions of GD.&lt;/para&gt;
-      &lt;/section&gt;
-
-      &lt;section id=&quot;install-modules-gd-graph&quot;&gt;
-        &lt;title&gt;GD::Graph (&amp;min-gd-graph-ver;)&lt;/title&gt;
-
-        &lt;para&gt;The GD::Graph module is only required if you want graphical 
-        reports.
-        &lt;/para&gt;
-      &lt;/section&gt;
-
-      &lt;section id=&quot;install-modules-gd-text&quot;&gt;
-        &lt;title&gt;GD::Text (&amp;min-gd-text-ver;)&lt;/title&gt;
-
-        &lt;para&gt;The GD::Text module is only required if you want graphical 
-        reports.
-        &lt;/para&gt;
-      &lt;/section&gt;
-
-      &lt;section id=&quot;install-modules-xml-twig&quot;&gt;
-        &lt;title&gt;XML::Twig (&amp;min-xml-twig-ver;)&lt;/title&gt;
-
-        &lt;para&gt;The XML::Twig module is only required if you want to import
-        XML bugs using the &lt;filename&gt;importxml.pl&lt;/filename&gt;
-        script. This is required to use Bugzilla's &quot;move bugs&quot; feature;
-        you may also want to use it for migrating from another bug database.
-        &lt;/para&gt;
-      &lt;/section&gt;
-
-      &lt;section id=&quot;install-modules-soap-lite&quot;&gt;
-        &lt;title&gt;SOAP::Lite (&amp;min-soap-lite-ver;)&lt;/title&gt;
-        &lt;para&gt;Installing SOAP::Lite enables your Bugzilla installation to be
-        accessible at a standardized Web Service interface (SOAP/XML-RPC)
-        by third-party applications via HTTP(S).
-        &lt;/para&gt;
-      &lt;/section&gt;
-
-      &lt;section id=&quot;install-modules-patchreader&quot;&gt;
-        &lt;title&gt;PatchReader (&amp;min-patchreader-ver;)&lt;/title&gt;
-
-        &lt;para&gt;The PatchReader module is only required if you want to use
-        Patch Viewer, a
-        Bugzilla feature to show code patches in your web browser in a more
-        readable form.
-        &lt;/para&gt;
-      &lt;/section&gt;
</del><span class="cx">     &lt;/section&gt;
</span><ins>+
</ins><span class="cx">     &lt;section id=&quot;install-MTA&quot;&gt;
</span><span class="cx">       &lt;title&gt;Mail Transfer Agent (MTA)&lt;/title&gt;
</span><span class="cx">     
</span><span class="lines">@@ -665,10 +580,6 @@
</span><span class="cx">       &lt;para&gt;Bugzilla requires &lt;literal&gt;mod_perl&lt;/literal&gt; to be installed, which can be
</span><span class="cx">       obtained from &lt;ulink url=&quot;http://perl.apache.org&quot;/&gt; - Bugzilla requires
</span><span class="cx">       version &amp;min-mod_perl2-ver; (AKA 2.0.0-RC5) to be installed.&lt;/para&gt;
</span><del>-      
-      &lt;para&gt;Bugzilla also requires a more up-to-date version of the CGI
-      perl module to be installed, version &amp;min-mp-cgi-ver; as opposed to &amp;min-cgi-ver;
-      &lt;/para&gt;
</del><span class="cx">     &lt;/section&gt;
</span><span class="cx">   &lt;/section&gt;
</span><span class="cx">   
</span><span class="lines">@@ -707,7 +618,7 @@
</span><span class="cx">         the user you will create for your database. Pick a strong
</span><span class="cx">         password (for simplicity, it should not contain single quote
</span><span class="cx">         characters) and put it here. $db_driver can be either 'mysql',
</span><del>-        'Pg' or 'oracle'.
</del><ins>+        'Pg', 'Oracle' or 'Sqlite'.
</ins><span class="cx">       &lt;/para&gt;
</span><span class="cx"> 
</span><span class="cx">       &lt;note&gt;
</span><span class="lines">@@ -751,8 +662,8 @@
</span><span class="cx">       &lt;para&gt;
</span><span class="cx">         This section deals with configuring your database server for use
</span><span class="cx">         with Bugzilla. Currently, MySQL (&lt;xref linkend=&quot;mysql&quot;/&gt;),
</span><del>-        PostgreSQL (&lt;xref linkend=&quot;postgresql&quot;/&gt;) and Oracle (&lt;xref linkend=&quot;oracle&quot;/&gt;)
-        are available.
</del><ins>+        PostgreSQL (&lt;xref linkend=&quot;postgresql&quot;/&gt;), Oracle (&lt;xref linkend=&quot;oracle&quot;/&gt;)
+        and SQLite (&lt;xref linkend=&quot;sqlite&quot;/&gt;) are available.
</ins><span class="cx">       &lt;/para&gt;
</span><span class="cx"> 
</span><span class="cx">       &lt;section id=&quot;database-schema&quot;&gt;
</span><span class="lines">@@ -773,9 +684,23 @@
</span><span class="cx"> 
</span><span class="cx">         &lt;caution&gt;
</span><span class="cx">           &lt;para&gt;
</span><del>-            MySQL's default configuration is very insecure.
-            &lt;xref linkend=&quot;security-mysql&quot;/&gt; has some good information for
-            improving your installation's security.
</del><ins>+            MySQL's default configuration is insecure.
+            We highly recommend to run &lt;filename&gt;mysql_secure_installation&lt;/filename&gt;
+            on Linux or the MySQL installer on Windows, and follow the instructions.
+            Important points to note are:
+            &lt;orderedlist&gt;
+              &lt;listitem&gt;
+                &lt;para&gt;Be sure that the root account has a secure password set.&lt;/para&gt;
+              &lt;/listitem&gt;
+              &lt;listitem&gt;
+                &lt;para&gt;Do not create an anonymous account, and if it exists, say &quot;yes&quot;
+                to remove it.&lt;/para&gt;
+              &lt;/listitem&gt;
+              &lt;listitem&gt;
+                &lt;para&gt;If your web server and MySQL server are on the same machine,
+                you should disable the network access.&lt;/para&gt;
+              &lt;/listitem&gt;
+            &lt;/orderedlist&gt;
</ins><span class="cx">           &lt;/para&gt;
</span><span class="cx">         &lt;/caution&gt;
</span><span class="cx">  
</span><span class="lines">@@ -783,11 +708,11 @@
</span><span class="cx">           &lt;title&gt;Allow large attachments and many comments&lt;/title&gt;
</span><span class="cx">           
</span><span class="cx">           &lt;para&gt;By default, MySQL will only allow you to insert things
</span><del>-          into the database that are smaller than 64KB. Attachments
</del><ins>+          into the database that are smaller than 1MB. Attachments
</ins><span class="cx">           may be larger than this. Also, Bugzilla combines all comments
</span><span class="cx">           on a single bug into one field for full-text searching, and the
</span><del>-          combination of all comments on a single bug are very likely to
-          be larger than 64KB.&lt;/para&gt;
</del><ins>+          combination of all comments on a single bug could in some cases
+          be larger than 1MB.&lt;/para&gt;
</ins><span class="cx">           
</span><span class="cx">           &lt;para&gt;To change MySQL's default, you need to edit your MySQL
</span><span class="cx">           configuration file, which is usually &lt;filename&gt;/etc/my.cnf&lt;/filename&gt;
</span><span class="lines">@@ -918,12 +843,12 @@
</span><span class="cx"> 
</span><span class="cx">           &lt;para&gt;As the postgres user, you then need to create a new user: &lt;/para&gt;
</span><span class="cx">             
</span><del>-          &lt;screen&gt; &lt;prompt&gt;bash$&lt;/prompt&gt; createuser -U postgres -dAP bugs&lt;/screen&gt;
</del><ins>+          &lt;screen&gt; &lt;prompt&gt;bash$&lt;/prompt&gt; createuser -U postgres -dRSP bugs&lt;/screen&gt;
</ins><span class="cx">  
</span><span class="cx">           &lt;para&gt;When asked for a password, provide the password which will be set as
</span><span class="cx">           &lt;replaceable&gt;$db_pass&lt;/replaceable&gt; in &lt;filename&gt;localconfig&lt;/filename&gt;.
</span><del>-          The created user will have the ability to create databases and will not be
-          able to create new users.&lt;/para&gt;
</del><ins>+          The created user will not be a superuser (-S) and will not be able to create
+          new users (-R). He will only have the ability to create databases (-d).&lt;/para&gt;
</ins><span class="cx">         &lt;/section&gt;
</span><span class="cx">         
</span><span class="cx">         &lt;section&gt;
</span><span class="lines">@@ -1021,8 +946,27 @@
</span><span class="cx">           &lt;/para&gt;
</span><span class="cx">         &lt;/section&gt;
</span><span class="cx">       &lt;/section&gt;
</span><del>-    &lt;/section&gt;  
</del><span class="cx"> 
</span><ins>+      &lt;section id=&quot;sqlite&quot;&gt;
+        &lt;title&gt;SQLite&lt;/title&gt;
+
+        &lt;caution&gt;
+          &lt;para&gt;
+            Due to SQLite's &lt;ulink url=&quot;http://sqlite.org/faq.html#q5&quot;&gt;concurrency
+            limitations&lt;/ulink&gt; we recommend SQLite only for small and development
+            Bugzilla installations.
+          &lt;/para&gt;
+        &lt;/caution&gt;
+
+        &lt;para&gt;
+          No special configuration is required to run Bugzilla on SQLite.
+          The database will be stored in &lt;filename&gt;data/db/$db_name&lt;/filename&gt;,
+          where &lt;literal&gt;$db_name&lt;/literal&gt; is the database name defined
+          in &lt;filename&gt;localconfig&lt;/filename&gt;.
+        &lt;/para&gt;
+      &lt;/section&gt;
+    &lt;/section&gt;
+
</ins><span class="cx">     &lt;section&gt;
</span><span class="cx">       &lt;title&gt;checksetup.pl&lt;/title&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -1107,7 +1051,7 @@
</span><span class="cx">     AddHandler cgi-script .cgi
</span><span class="cx">     Options +Indexes +ExecCGI
</span><span class="cx">     DirectoryIndex index.cgi
</span><del>-    AllowOverride Limit
</del><ins>+    AllowOverride Limit FileInfo Indexes
</ins><span class="cx">     &amp;lt;/Directory&amp;gt;
</span><span class="cx">                 &lt;/programlisting&gt;
</span><span class="cx">     
</span><span class="lines">@@ -1132,6 +1076,14 @@
</span><span class="cx">                     when granting extra access.
</span><span class="cx">                 &lt;/para&gt;
</span><span class="cx">                 &lt;/note&gt;
</span><ins>+
+                &lt;note&gt;
+                &lt;para&gt;
+                    On Windows, you may have to also add the
+                    &lt;computeroutput&gt;ScriptInterpreterSource Registry-Strict&lt;/computeroutput&gt;
+                    line, see &lt;link linkend=&quot;win32-http&quot;&gt;Windows specific notes&lt;/link&gt;.
+                &lt;/para&gt;
+                &lt;/note&gt;
</ins><span class="cx">             &lt;/step&gt;                    
</span><span class="cx">     
</span><span class="cx">             &lt;step&gt;
</span><span class="lines">@@ -1199,7 +1151,7 @@
</span><span class="cx">                 &lt;/warning&gt; 
</span><span class="cx">                 
</span><span class="cx">                 &lt;programlisting&gt;
</span><del>-    PerlSwitches -I/var/www/html/bugzilla -I/var/www/html/bugzilla/lib -w -T
</del><ins>+    PerlSwitches -w -T
</ins><span class="cx">     PerlConfigRequire /var/www/html/bugzilla/mod_perl.pl
</span><span class="cx">                 &lt;/programlisting&gt;
</span><span class="cx">             &lt;/step&gt;
</span><span class="lines">@@ -1377,9 +1329,7 @@
</span><span class="cx">       &lt;para&gt;
</span><span class="cx">         Log in with the administrator account you defined in the last 
</span><span class="cx">         &lt;filename&gt;checksetup.pl&lt;/filename&gt; run. You should go through 
</span><del>-        the parameters on the Edit Parameters page
-        (see link in the footer) and see if there are any you wish to
-        change. 
</del><ins>+        the Parameters page and see if there are any you wish to change.
</ins><span class="cx">         They key parameters are documented in &lt;xref linkend=&quot;parameters&quot;/&gt;;
</span><span class="cx">         you should certainly alter 
</span><span class="cx">         &lt;command&gt;maintainer&lt;/command&gt; and &lt;command&gt;urlbase&lt;/command&gt;; 
</span><span class="lines">@@ -1388,14 +1338,6 @@
</span><span class="cx">       &lt;/para&gt;
</span><span class="cx"> 
</span><span class="cx">       &lt;para&gt;
</span><del>-        This would also be a good time to revisit the
-        &lt;filename&gt;localconfig&lt;/filename&gt; file and make sure that the 
-        names of the priorities, severities, platforms and operating systems
-        are those you wish to use when you start creating bugs. Remember
-        to rerun &lt;filename&gt;checksetup.pl&lt;/filename&gt; if you change it.
-      &lt;/para&gt;
-
-      &lt;para&gt;
</del><span class="cx">         Bugzilla has several optional features which require extra 
</span><span class="cx">         configuration. You can read about those in
</span><span class="cx">         &lt;xref linkend=&quot;extraconfig&quot;/&gt;.
</span><span class="lines">@@ -1427,7 +1369,7 @@
</span><span class="cx">         daily at 5 after midnight:
</span><span class="cx">       &lt;/para&gt;
</span><span class="cx">       
</span><del>-      &lt;programlisting&gt;5 0 * * * cd &amp;lt;your-bugzilla-directory&amp;gt; ; ./collectstats.pl&lt;/programlisting&gt;
</del><ins>+      &lt;programlisting&gt;5 0 * * * cd &amp;lt;your-bugzilla-directory&amp;gt; &amp;amp;&amp;amp; ./collectstats.pl&lt;/programlisting&gt;
</ins><span class="cx"> 
</span><span class="cx">       &lt;para&gt;
</span><span class="cx">         After two days have passed you'll be able to view bug graphs from
</span><span class="lines">@@ -1450,7 +1392,7 @@
</span><span class="cx">       &lt;para&gt;What good are
</span><span class="cx">       bugs if they're not annoying? To help make them more so you
</span><span class="cx">       can set up Bugzilla's automatic whining system to complain at engineers
</span><del>-      which leave their bugs in the NEW or REOPENED state without triaging them.
</del><ins>+      which leave their bugs in the CONFIRMED state without triaging them.
</ins><span class="cx">       &lt;/para&gt;
</span><span class="cx">       &lt;para&gt;
</span><span class="cx">         This can be done by adding the following command as a daily
</span><span class="lines">@@ -1458,7 +1400,7 @@
</span><span class="cx">         graphs. This example runs it at 12.55am. 
</span><span class="cx">       &lt;/para&gt;
</span><span class="cx"> 
</span><del>-      &lt;programlisting&gt;55 0 * * * cd &amp;lt;your-bugzilla-directory&amp;gt; ; ./whineatnews.pl&lt;/programlisting&gt;
</del><ins>+      &lt;programlisting&gt;55 0 * * * cd &amp;lt;your-bugzilla-directory&amp;gt; &amp;amp;&amp;amp; ./whineatnews.pl&lt;/programlisting&gt;
</ins><span class="cx"> 
</span><span class="cx">       &lt;note&gt;
</span><span class="cx">         &lt;para&gt;
</span><span class="lines">@@ -1488,7 +1430,7 @@
</span><span class="cx">         graphs. This example runs it every 15 minutes. 
</span><span class="cx">       &lt;/para&gt;
</span><span class="cx"> 
</span><del>-      &lt;programlisting&gt;*/15 * * * * cd &amp;lt;your-bugzilla-directory&amp;gt; ; ./whine.pl&lt;/programlisting&gt;
</del><ins>+      &lt;programlisting&gt;*/15 * * * * cd &amp;lt;your-bugzilla-directory&amp;gt; &amp;amp;&amp;amp; ./whine.pl&lt;/programlisting&gt;
</ins><span class="cx"> 
</span><span class="cx">       &lt;note&gt;
</span><span class="cx">         &lt;para&gt;
</span><span class="lines">@@ -1688,16 +1630,6 @@
</span><span class="cx">         &lt;/tip&gt;
</span><span class="cx">       &lt;/section&gt;
</span><span class="cx">   
</span><del>-      &lt;section id=&quot;win32-code-changes&quot;&gt;
-        &lt;title&gt;Code changes required to run on Win32&lt;/title&gt;
-
-        &lt;para&gt;
-          Bugzilla on Win32 is supported out of the box from version 2.20; this
-          means that no code changes are required to get Bugzilla running.
-        &lt;/para&gt;
-        
-      &lt;/section&gt;
-
</del><span class="cx">       &lt;section id=&quot;win32-http&quot;&gt;
</span><span class="cx">         &lt;title&gt;Serving the web pages&lt;/title&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -1713,14 +1645,16 @@
</span><span class="cx"> 
</span><span class="cx">         &lt;note&gt;
</span><span class="cx">           &lt;para&gt;
</span><del>-            If using Apache on windows, you can set the &lt;ulink
-            url=&quot;http://httpd.apache.org/docs-2.0/mod/core.html#scriptinterpretersource&quot;&gt;ScriptInterpreterSource&lt;/ulink&gt;
-            directive in your Apache config to avoid having to modify
-            the first line of every script to contain your path to Perl
-            instead of &lt;filename&gt;/usr/bin/perl&lt;/filename&gt;. When setting
-            &lt;filename&gt;ScriptInterpreterSource&lt;/filename&gt;, do not forget
-            to specify the &lt;command&gt;-T&lt;/command&gt; flag to enable the taint
-            mode. For example: &lt;command&gt;C:\Perl\bin\perl.exe -T&lt;/command&gt;.
</del><ins>+            The web server looks at &lt;filename&gt;/usr/bin/perl&lt;/filename&gt; to
+            call Perl. If you are using Apache on windows, you can set the
+            &lt;ulink url=&quot;http://httpd.apache.org/docs-2.0/mod/core.html#scriptinterpretersource&quot;&gt;ScriptInterpreterSource&lt;/ulink&gt;
+            directive in your Apache config file to make it look at the
+            right place: insert the line
+            &lt;programlisting&gt;ScriptInterpreterSource Registry-Strict&lt;/programlisting&gt;
+            into your &lt;filename&gt;httpd.conf&lt;/filename&gt; file, and create the key
+            &lt;programlisting&gt;HKEY_CLASSES_ROOT\.cgi\Shell\ExecCGI\Command&lt;/programlisting&gt;
+            with &lt;option&gt;C:\Perl\bin\perl.exe -T&lt;/option&gt; as value (adapt to your
+            path if needed) in the registry. When this is done, restart Apache.
</ins><span class="cx">           &lt;/para&gt;
</span><span class="cx">         &lt;/note&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -1750,14 +1684,9 @@
</span><span class="cx">         &lt;ulink url=&quot;http://www.postfix.org/&quot;&gt;Postfix&lt;/ulink&gt; 
</span><span class="cx">         is used as the built-in email server.  Postfix provides an executable
</span><span class="cx">         that mimics sendmail enough to fool Bugzilla, as long as Bugzilla can 
</span><del>-        find it.&lt;/para&gt;
</del><ins>+        find it. Bugzilla is able to find the fake sendmail executable without
+        any assistance.&lt;/para&gt;
</ins><span class="cx"> 
</span><del>-        &lt;para&gt;As of version 2.20, Bugzilla will be able to find the fake 
-        sendmail executable without any assistance.  However, you will have 
-        to turn on the sendmailnow parameter before you do anything that would 
-        result in email being sent.  For more information, see the description 
-        of the sendmailnow parameter in &lt;xref linkend=&quot;parameters&quot;/&gt;.&lt;/para&gt;
-
</del><span class="cx">       &lt;/section&gt;
</span><span class="cx"> 
</span><span class="cx">       &lt;section id=&quot;macosx-libraries&quot;&gt;
</span><span class="lines">@@ -1766,12 +1695,12 @@
</span><span class="cx">         &lt;para&gt;Apple does not include the GD library with Mac OS X. Bugzilla
</span><span class="cx">         needs this for bug graphs.&lt;/para&gt;
</span><span class="cx"> 
</span><del>-        &lt;para&gt;You can use DarwinPorts (&lt;ulink url=&quot;http://darwinports.com/&quot;/&gt;)
</del><ins>+        &lt;para&gt;You can use MacPorts (&lt;ulink url=&quot;http://www.macports.org/&quot;/&gt;)
</ins><span class="cx">         or Fink (&lt;ulink url=&quot;http://sourceforge.net/projects/fink/&quot;/&gt;), both
</span><span class="cx">         of which are similar in nature to the CPAN installer, but install
</span><span class="cx">         common unix programs.&lt;/para&gt;
</span><span class="cx"> 
</span><del>-        &lt;para&gt;Follow the instructions for setting up DarwinPorts or Fink.
</del><ins>+        &lt;para&gt;Follow the instructions for setting up MacPorts or Fink.
</ins><span class="cx">         Once you have one installed, you'll want to use it to install the
</span><span class="cx">         &lt;filename&gt;gd2&lt;/filename&gt; package.
</span><span class="cx">         &lt;/para&gt;
</span><span class="lines">@@ -1797,7 +1726,7 @@
</span><span class="cx">           &lt;/para&gt;
</span><span class="cx">         &lt;/note&gt;
</span><span class="cx"> 
</span><del>-        &lt;para&gt;Also available via DarwinPorts and Fink is
</del><ins>+        &lt;para&gt;Also available via MacPorts and Fink is
</ins><span class="cx">         &lt;filename&gt;expat&lt;/filename&gt;. After installing the expat package, you
</span><span class="cx">         will be able to install XML::Parser using CPAN. If you use fink, there
</span><span class="cx">         is one caveat. Unlike recent versions of
</span><span class="lines">@@ -1976,7 +1905,7 @@
</span><span class="cx"> 
</span><span class="cx">       &lt;screen&gt;
</span><span class="cx">         &lt;prompt&gt;bash$&lt;/prompt&gt;
</span><del>-        &lt;command&gt;wget http://perl.com/CPAN/src/stable.tar.gz&lt;/command&gt;
</del><ins>+        &lt;command&gt;wget http://perl.org/CPAN/src/stable.tar.gz&lt;/command&gt;
</ins><span class="cx">         &lt;prompt&gt;bash$&lt;/prompt&gt;
</span><span class="cx">         &lt;command&gt;tar zvxf stable.tar.gz&lt;/command&gt;
</span><span class="cx">         &lt;prompt&gt;bash$&lt;/prompt&gt;
</span><span class="lines">@@ -2092,21 +2021,22 @@
</span><span class="cx"> 
</span><span class="cx">   &lt;section id=&quot;upgrade&quot;&gt;
</span><span class="cx">     &lt;title&gt;Upgrading to New Releases&lt;/title&gt;
</span><del>-    
</del><ins>+
</ins><span class="cx">     &lt;para&gt;Upgrading to new Bugzilla releases is very simple. There is
</span><del>-      a script included with Bugzilla that will automatically
-      do all of the database migration for you.&lt;/para&gt;
-    
</del><ins>+      a script named &lt;filename&gt;checksetup.pl&lt;/filename&gt; included with
+      Bugzilla that will automatically do all of the database migration
+      for you.&lt;/para&gt;
+
</ins><span class="cx">     &lt;para&gt;The following sections explain how to upgrade from one
</span><span class="cx">       version of Bugzilla to another. Whether you are upgrading
</span><del>-      from one bug-fix version to another (such as 3.0.1 to 3.0.2)
-      or from one major version to another (such as from 3.0 to 3.2),
</del><ins>+      from one bug-fix version to another (such as 4.2 to 4.2.1)
+      or from one major version to another (such as from 4.0 to 4.2),
</ins><span class="cx">       the instructions are always the same.&lt;/para&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;note&gt;
</span><span class="cx">       &lt;para&gt;
</span><span class="cx">         Any examples in the following sections are written as though the
</span><del>-        user were updating to version 2.22.1, but the procedures are the
</del><ins>+        user were updating to version 4.2.1, but the procedures are the
</ins><span class="cx">         same no matter what version you're updating to. Also, in the
</span><span class="cx">         examples, the user's Bugzilla installation is found at
</span><span class="cx">         &lt;filename&gt;/var/www/html/bugzilla&lt;/filename&gt;. If that is not the
</span><span class="lines">@@ -2202,10 +2132,10 @@
</span><span class="cx">       
</span><span class="cx">       &lt;variablelist&gt;
</span><span class="cx">         &lt;varlistentry&gt;
</span><del>-          &lt;term&gt;CVS (&lt;xref linkend=&quot;upgrade-cvs&quot;/&gt;)&lt;/term&gt;
</del><ins>+          &lt;term&gt;Bzr (&lt;xref linkend=&quot;upgrade-bzr&quot;/&gt;)&lt;/term&gt;
</ins><span class="cx">           &lt;listitem&gt;
</span><span class="cx">             &lt;para&gt;
</span><del>-              If have &lt;command&gt;cvs&lt;/command&gt; installed on your machine
</del><ins>+              If you have &lt;command&gt;bzr&lt;/command&gt; installed on your machine
</ins><span class="cx">               and you have Internet access, this is the easiest way to
</span><span class="cx">               upgrade, particularly if you have made modifications
</span><span class="cx">               to the code or templates of Bugzilla.
</span><span class="lines">@@ -2230,12 +2160,12 @@
</span><span class="cx">             &lt;para&gt;
</span><span class="cx">               If you have made modifications to your Bugzilla, and
</span><span class="cx">               you don't have Internet access or you don't want to use
</span><del>-              cvs, then this is the best way to upgrade.
</del><ins>+              bzr, then this is the best way to upgrade.
</ins><span class="cx">             &lt;/para&gt;
</span><del>-            
</del><ins>+
</ins><span class="cx">             &lt;para&gt;
</span><del>-              You can only do minor upgrades (such as 3.0 to 3.0.1 or
-              3.0.1 to 3.0.2) with patches.
</del><ins>+              You can only do minor upgrades (such as 4.2 to 4.2.1 or
+              4.2.1 to 4.2.2) with patches.
</ins><span class="cx">             &lt;/para&gt;
</span><span class="cx">           &lt;/listitem&gt;
</span><span class="cx">         &lt;/varlistentry&gt;
</span><span class="lines">@@ -2255,8 +2185,8 @@
</span><span class="cx">         &lt;para&gt;
</span><span class="cx">           The larger the jump you are trying to make, the more difficult it
</span><span class="cx">           is going to be to upgrade if you have made local customizations.
</span><del>-          Upgrading from 3.0 to 3.0.1 should be fairly painless even if
-          you are heavily customized, but going from 2.18 to 3.0 is going
</del><ins>+          Upgrading from 4.2 to 4.2.1 should be fairly painless even if
+          you are heavily customized, but going from 2.18 to 4.2 is going
</ins><span class="cx">           to mean a fair bit of work re-writing your local changes to use
</span><span class="cx">           the new files, logic, templates, etc. If you have done no local
</span><span class="cx">           changes at all, however, then upgrading should be approximately
</span><span class="lines">@@ -2265,41 +2195,53 @@
</span><span class="cx">         &lt;/para&gt;
</span><span class="cx">       &lt;/section&gt;
</span><span class="cx"> 
</span><del>-      &lt;section id=&quot;upgrade-cvs&quot;&gt;
-        &lt;title&gt;Upgrading using CVS&lt;/title&gt;
</del><ins>+      &lt;section id=&quot;upgrade-bzr&quot;&gt;
+        &lt;title&gt;Upgrading using Bzr&lt;/title&gt;
</ins><span class="cx"> 
</span><span class="cx">         &lt;para&gt;
</span><del>-          This requires that you have cvs installed (most Unix machines do),
-          and requires that you are able to access cvs-mirror.mozilla.org
-          on port 2401, which may not be an option if you are behind a
-          highly restrictive firewall or don't have Internet access.
</del><ins>+          This requires that you have bzr installed (most Unix machines do),
+          and requires that you are able to access
+          &lt;ulink url=&quot;http://bzr.mozilla.org/bugzilla/&quot;&gt;bzr.mozilla.org&lt;/ulink&gt;,
+          which may not be an option if you don't have Internet access.
</ins><span class="cx">         &lt;/para&gt;
</span><span class="cx"> 
</span><span class="cx">         &lt;para&gt;
</span><span class="cx">           The following shows the sequence of commands needed to update a
</span><del>-          Bugzilla installation via CVS, and a typical series of results.
</del><ins>+          Bugzilla installation via Bzr, and a typical series of results.
+          These commands assume that you already have Bugzilla installed
+          using Bzr.
</ins><span class="cx">         &lt;/para&gt;
</span><span class="cx"> 
</span><ins>+        &lt;warning&gt;
+          &lt;para&gt;
+            If your installation is still using CVS, you must first convert
+            it to Bzr. A very detailed step by step documentation can be
+            found on &lt;ulink url=&quot;https://wiki.mozilla.org/Bugzilla:Moving_From_CVS_To_Bazaar&quot;&gt;wiki.mozilla.org&lt;/ulink&gt;.
+          &lt;/para&gt;
+        &lt;/warning&gt;
+
</ins><span class="cx">         &lt;programlisting&gt;
</span><span class="cx"> bash$ &lt;command&gt;cd /var/www/html/bugzilla&lt;/command&gt;
</span><del>-bash$ &lt;command&gt;cvs login&lt;/command&gt;
-Logging in to :pserver:anonymous@cvs-mirror.mozilla.org:2401/cvsroot
-CVS password: &lt;emphasis&gt;('anonymous', or just leave it blank)&lt;/emphasis&gt;
-bash$ &lt;command&gt;cvs -q update -r BUGZILLA-2_22_1 -dP&lt;/command&gt;
-P checksetup.pl
-P collectstats.pl
-P docs/rel_notes.txt
-P template/en/default/list/quips.html.tmpl
-&lt;emphasis&gt;(etc.)&lt;/emphasis&gt;
</del><ins>+bash$ &lt;command&gt;bzr switch 4.2&lt;/command&gt; (only run this command when not yet running 4.2)
+bash$ &lt;command&gt;bzr up -r tag:bugzilla-4.2.1&lt;/command&gt;
++N  extensions/MoreBugUrl/
++N  extensions/MoreBugUrl/Config.pm
++N  extensions/MoreBugUrl/Extension.pm
+...
+ M  Bugzilla/Attachment.pm
+ M  Bugzilla/Attachment/PatchReader.pm
+ M  Bugzilla/Bug.pm
+...
+All changes applied successfully.
</ins><span class="cx">         &lt;/programlisting&gt;
</span><span class="cx"> 
</span><span class="cx">         &lt;caution&gt;
</span><span class="cx">           &lt;para&gt;
</span><del>-            If a line in the output from &lt;command&gt;cvs update&lt;/command&gt; begins
-            with a &lt;computeroutput&gt;C&lt;/computeroutput&gt;, then that represents a
-            file with local changes that CVS was unable to properly merge. You
-            need to resolve these conflicts manually before Bugzilla (or at
-            least the portion using that file) will be usable.
</del><ins>+            If a line in the output from &lt;command&gt;bzr up&lt;/command&gt; mentions
+            a conflict, then that represents a file with local changes that
+            Bzr was unable to properly merge. You need to resolve these
+            conflicts manually before Bugzilla (or at least the portion using
+            that file) will be usable.
</ins><span class="cx">           &lt;/para&gt;
</span><span class="cx">         &lt;/caution&gt;
</span><span class="cx">       &lt;/section&gt;
</span><span class="lines">@@ -2308,7 +2250,7 @@
</span><span class="cx">         &lt;title&gt;Upgrading using the tarball&lt;/title&gt;
</span><span class="cx"> 
</span><span class="cx">         &lt;para&gt;
</span><del>-          If you are unable (or unwilling) to use CVS, another option that's
</del><ins>+          If you are unable (or unwilling) to use Bzr, another option that's
</ins><span class="cx">           always available is to obtain the latest tarball from the &lt;ulink
</span><span class="cx">           url=&quot;http://www.bugzilla.org/download/&quot;&gt;Download Page&lt;/ulink&gt; and 
</span><span class="cx">           create a new Bugzilla installation from that.
</span><span class="lines">@@ -2325,18 +2267,18 @@
</span><span class="cx"> 
</span><span class="cx">         &lt;programlisting&gt;
</span><span class="cx"> bash$ &lt;command&gt;cd /var/www/html&lt;/command&gt;
</span><del>-bash$ &lt;command&gt;wget http://ftp.mozilla.org/pub/mozilla.org/webtools/bugzilla-2.22.1.tar.gz&lt;/command&gt;
</del><ins>+bash$ &lt;command&gt;wget http://ftp.mozilla.org/pub/mozilla.org/webtools/bugzilla-4.2.1.tar.gz&lt;/command&gt;
</ins><span class="cx"> &lt;emphasis&gt;(Output omitted)&lt;/emphasis&gt;
</span><del>-bash$ &lt;command&gt;tar xzvf bugzilla-2.22.1.tar.gz&lt;/command&gt;
-bugzilla-2.22.1/
-bugzilla-2.22.1/.cvsignore
</del><ins>+bash$ &lt;command&gt;tar xzvf bugzilla-4.2.1.tar.gz&lt;/command&gt;
+bugzilla-4.2.1/
+bugzilla-4.2.1/colchange.cgi
</ins><span class="cx"> &lt;emphasis&gt;(Output truncated)&lt;/emphasis&gt;
</span><del>-bash$ &lt;command&gt;cd bugzilla-2.22.1&lt;/command&gt;
</del><ins>+bash$ &lt;command&gt;cd bugzilla-4.2.1&lt;/command&gt;
</ins><span class="cx"> bash$ &lt;command&gt;cp ../bugzilla/localconfig* .&lt;/command&gt;
</span><span class="cx"> bash$ &lt;command&gt;cp -r ../bugzilla/data .&lt;/command&gt;
</span><span class="cx"> bash$ &lt;command&gt;cd ..&lt;/command&gt;
</span><span class="cx"> bash$ &lt;command&gt;mv bugzilla bugzilla.old&lt;/command&gt;
</span><del>-bash$ &lt;command&gt;mv bugzilla-2.22.1 bugzilla&lt;/command&gt;
</del><ins>+bash$ &lt;command&gt;mv bugzilla-4.2.1 bugzilla&lt;/command&gt;
</ins><span class="cx">         &lt;/programlisting&gt;
</span><span class="cx"> 
</span><span class="cx">         &lt;warning&gt;
</span><span class="lines">@@ -2347,6 +2289,15 @@
</span><span class="cx">           &lt;/para&gt;
</span><span class="cx">         &lt;/warning&gt;
</span><span class="cx"> 
</span><ins>+        &lt;caution&gt;
+          &lt;para&gt;
+            If you have some extensions installed, you will have to copy them
+            to the new bugzilla directory too. Extensions are located in
+            &lt;filename&gt;bugzilla/extensions/&lt;/filename&gt;. Only copy those you
+            installed, not those managed by the Bugzilla team.
+          &lt;/para&gt;
+        &lt;/caution&gt;
+
</ins><span class="cx">         &lt;para&gt;
</span><span class="cx">           This upgrade method will give you a clean install of Bugzilla.
</span><span class="cx">           That's fine if you don't have any local customizations that you
</span><span class="lines">@@ -2362,15 +2313,15 @@
</span><span class="cx">           A patch is a collection of all the bug fixes that have been made
</span><span class="cx">           since the last bug-fix release.
</span><span class="cx">         &lt;/para&gt;
</span><del>-        
</del><ins>+
</ins><span class="cx">         &lt;para&gt;
</span><span class="cx">           If you are doing a bug-fix upgrade&amp;mdash;that is, one where only the 
</span><del>-          last number of the revision changes, such as from 2.22 to
-          2.22.1&amp;mdash;then you have the option of obtaining and applying a
</del><ins>+          last number of the revision changes, such as from 4.2 to
+          4.2.1&amp;mdash;then you have the option of obtaining and applying a
</ins><span class="cx">           patch file from the &lt;ulink
</span><span class="cx">           url=&quot;http://www.bugzilla.org/download/&quot;&gt;Download Page&lt;/ulink&gt;.
</span><span class="cx">         &lt;/para&gt;
</span><del>-        
</del><ins>+
</ins><span class="cx">         &lt;para&gt;
</span><span class="cx">           As above, this example starts with obtaining the file via the 
</span><span class="cx">           command line. If you have already downloaded it, you can omit the
</span><span class="lines">@@ -2379,21 +2330,21 @@
</span><span class="cx"> 
</span><span class="cx">         &lt;programlisting&gt;
</span><span class="cx"> bash$ &lt;command&gt;cd /var/www/html/bugzilla&lt;/command&gt;
</span><del>-bash$ &lt;command&gt;wget http://ftp.mozilla.org/pub/mozilla.org/webtools/bugzilla-2.22-to-2.22.1.diff.gz&lt;/command&gt;
</del><ins>+bash$ &lt;command&gt;wget http://ftp.mozilla.org/pub/mozilla.org/webtools/bugzilla-4.2-to-4.2.1.diff.gz&lt;/command&gt;
</ins><span class="cx"> &lt;emphasis&gt;(Output omitted)&lt;/emphasis&gt;
</span><del>-bash$ &lt;command&gt;gunzip bugzilla-2.22-to-2.22.1.diff.gz&lt;/command&gt;
-bash$ &lt;command&gt;patch -p1 &amp;lt; bugzilla-2.22-to-2.22.1.diff&lt;/command&gt;
-patching file checksetup.pl
-patching file collectstats.pl
</del><ins>+bash$ &lt;command&gt;gunzip bugzilla-4.2-to-4.2.1.diff.gz&lt;/command&gt;
+bash$ &lt;command&gt;patch -p1 &amp;lt; bugzilla-4.2-to-4.2.1.diff&lt;/command&gt;
+patching file Bugzilla/Constants.pm
+patching file enter_bug.cgi
</ins><span class="cx"> &lt;emphasis&gt;(etc.)&lt;/emphasis&gt;
</span><span class="cx">         &lt;/programlisting&gt;
</span><span class="cx"> 
</span><span class="cx">         &lt;warning&gt;
</span><span class="cx">           &lt;para&gt;
</span><span class="cx">             Be aware that upgrading from a patch file does not change the
</span><del>-            entries in your &lt;filename class=&quot;directory&quot;&gt;CVS&lt;/filename&gt; directory.
-            This could make it more difficult to upgrade using CVS
-            (&lt;xref linkend=&quot;upgrade-cvs&quot;/&gt;) in the future.
</del><ins>+            entries in your &lt;filename class=&quot;directory&quot;&gt;.bzr&lt;/filename&gt; directory.
+            This could make it more difficult to upgrade using Bzr
+            (&lt;xref linkend=&quot;upgrade-bzr&quot;/&gt;) in the future.
</ins><span class="cx">           &lt;/para&gt;
</span><span class="cx">         &lt;/warning&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -2453,7 +2404,7 @@
</span><span class="cx">           
</span><span class="cx">           &lt;caution&gt;
</span><span class="cx">             &lt;para&gt;
</span><del>-              If this is a major upgrade (say, 2.22 to 3.0 or similar),
</del><ins>+              If this is a major upgrade (say, 3.6 to 4.2 or similar),
</ins><span class="cx">               running &lt;command&gt;checksetup.pl&lt;/command&gt; on a large
</span><span class="cx">               installation (75,000 or more bugs) can take a long time,
</span><span class="cx">               possibly several hours.
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgdocsenxmlintegrationxml"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/docs/en/xml/integration.xml (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/docs/en/xml/integration.xml        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/docs/en/xml/integration.xml        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,120 +0,0 @@
</span><del>-&lt;!-- &lt;!DOCTYPE chapter PUBLIC &quot;-//OASIS//DTD DocBook V4.1//EN&quot; &gt; --&gt;
-&lt;!-- Keep these tools listings in alphabetical order please. -MPB --&gt;
-&lt;section id=&quot;integration&quot;&gt;
-  &lt;title&gt;Integrating Bugzilla with Third-Party Tools&lt;/title&gt;
-
-  &lt;section id=&quot;bonsai&quot;
-  xreflabel=&quot;Bonsai, the Mozilla automated CVS management system&quot;&gt;
-    &lt;title&gt;Bonsai&lt;/title&gt;
-
-    &lt;para&gt;Bonsai is a web-based tool for managing 
-    &lt;xref linkend=&quot;cvs&quot; /&gt;
-
-    . Using Bonsai, administrators can control open/closed status of trees,
-    query a fast relational database back-end for change, branch, and comment
-    information, and view changes made since the last time the tree was
-    closed. Bonsai
-    also integrates with  
-    &lt;xref linkend=&quot;tinderbox&quot; /&gt;.
-    &lt;/para&gt;
-  &lt;/section&gt;
-
-  &lt;section id=&quot;cvs&quot; xreflabel=&quot;CVS, the Concurrent Versioning System&quot;&gt;
-    &lt;title&gt;CVS&lt;/title&gt;
-
-    &lt;para&gt;CVS integration is best accomplished, at this point, using the
-    Bugzilla Email Gateway.&lt;/para&gt;
-
-    &lt;para&gt;Follow the instructions in this Guide for enabling Bugzilla e-mail
-    integration. Ensure that your check-in script sends an email to your
-    Bugzilla e-mail gateway with the subject of 
-    &lt;quote&gt;[Bug XXXX]&lt;/quote&gt;, 
-    and you can have CVS check-in comments append to your Bugzilla bug. If
-    you  want to have the bug be closed automatically, you'll have to modify
-    the &lt;filename&gt;contrib/bugzilla_email_append.pl&lt;/filename&gt; script.
-    &lt;/para&gt;
-
-    &lt;para&gt;There is also a CVSZilla project, based upon somewhat dated 
-    Bugzilla code, to integrate CVS and Bugzilla through CVS' ability to 
-    email. Check it out at: &lt;ulink url=&quot;http://www.cvszilla.org/&quot;/&gt;.
-    &lt;/para&gt;
-
-    &lt;para&gt;Another system capable of CVS integration with Bugzilla is
-    Scmbug. This system provides generic integration of Source code
-    Configuration Management with Bugtracking. Check it out at: &lt;ulink
-    url=&quot;http://freshmeat.net/projects/scmbug/&quot;/&gt;.
-    &lt;/para&gt;
-
-  &lt;/section&gt;
-
-  &lt;section id=&quot;scm&quot;
-  xreflabel=&quot;Perforce SCM (Fast Software Configuration Management System, a powerful commercial alternative to CVS&quot;&gt;
-
-    &lt;title&gt;Perforce SCM&lt;/title&gt;
-
-    &lt;para&gt;You can find the project page for Bugzilla and Teamtrack Perforce
-    integration (p4dti) at: 
-    &lt;ulink url=&quot;http://www.ravenbrook.com/project/p4dti/&quot;/&gt;
-
-    . 
-    &lt;quote&gt;p4dti&lt;/quote&gt;
-
-    is now an officially supported product from Perforce, and you can find
-    the &quot;Perforce Public Depot&quot; p4dti page at 
-    &lt;ulink url=&quot;http://public.perforce.com/public/perforce/p4dti/index.html&quot;/&gt;
-
-    .&lt;/para&gt;
-
-    &lt;para&gt;Integration of Perforce with Bugzilla, once patches are applied, is
-    seamless. Perforce replication information will appear below the comments
-    of each bug. Be certain you have a matching set of patches for the
-    Bugzilla version you are installing. p4dti is designed to support
-    multiple defect trackers, and maintains its own documentation for it.
-    Please consult the pages linked above for further information.&lt;/para&gt;
-  &lt;/section&gt;
-
-  &lt;section id=&quot;svn&quot;
-  xreflabel=&quot;Subversion, a compelling replacement for CVS&quot;&gt;
-     &lt;title&gt;Subversion&lt;/title&gt;
-     &lt;para&gt;Subversion is a free/open-source version control system,
-     designed to overcome various limitations of CVS. Integration of
-     Subversion with Bugzilla is possible using Scmbug, a system
-     providing generic integration of Source Code Configuration
-     Management with Bugtracking. Scmbug is available at &lt;ulink
-     url=&quot;http://freshmeat.net/projects/scmbug/&quot;/&gt;.&lt;/para&gt;
-  &lt;/section&gt;
-
-  &lt;section id=&quot;tinderbox&quot;
-  xreflabel=&quot;Tinderbox, the Mozilla automated build management system&quot;&gt;
-    &lt;title&gt;Tinderbox/Tinderbox2&lt;/title&gt;
-
-    &lt;para&gt;Tinderbox is a continuous-build system which can integrate with
-    Bugzilla - see
-    &lt;ulink url=&quot;http://www.mozilla.org/projects/tinderbox&quot;/&gt; for details
-    of Tinderbox, and 
-    &lt;ulink url=&quot;http://tinderbox.mozilla.org/showbuilds.cgi&quot;/&gt; to see it
-    in action.&lt;/para&gt;
-  &lt;/section&gt;
-&lt;/section&gt;
-
-&lt;!-- Keep this comment at the end of the file
-Local variables:
-mode: sgml
-sgml-always-quote-attributes:t
-sgml-auto-insert-required-elements:t
-sgml-balanced-tag-edit:t
-sgml-exposed-tags:nil
-sgml-general-insert-case:lower
-sgml-indent-data:t
-sgml-indent-step:2
-sgml-local-catalogs:nil
-sgml-local-ecat-files:nil
-sgml-minimize-attributes:nil
-sgml-namecase-general:t
-sgml-omittag:t
-sgml-parent-document:(&quot;Bugzilla-Guide.xml&quot; &quot;book&quot; &quot;chapter&quot;)
-sgml-shorttag:t
-sgml-tag-region-if-active:t
-End:
---&gt;
-
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgdocsenxmlintroductionxml"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/docs/en/xml/introduction.xml (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/docs/en/xml/introduction.xml        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/docs/en/xml/introduction.xml        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,149 +0,0 @@
</span><del>-&lt;chapter id=&quot;introduction&quot;&gt;
-  &lt;title&gt;Introduction&lt;/title&gt;
-
-  &lt;section id=&quot;whatis&quot;&gt;
-    &lt;title&gt;What is Bugzilla?&lt;/title&gt;
-
-    &lt;para&gt;
-    Bugzilla is a bug- or issue-tracking system. Bug-tracking
-    systems allow individual or groups of developers effectively to keep track
-    of outstanding problems with their product. 
-    Bugzilla was originally
-    written by Terry Weissman in a programming language called TCL, to
-    replace a rudimentary bug-tracking database used internally by Netscape
-    Communications. Terry later ported Bugzilla to Perl from TCL, and in Perl
-    it remains to this day. Most commercial defect-tracking software vendors
-    at the time charged enormous licensing fees, and Bugzilla quickly became
-    a favorite of the open-source crowd (with its genesis in the open-source
-    browser project, Mozilla). It is now the de-facto standard
-    defect-tracking system against which all others are measured.
-    &lt;/para&gt;
-
-    &lt;para&gt;Bugzilla boasts many advanced features. These include: 
-    &lt;itemizedlist&gt;
-      &lt;listitem&gt;
-        &lt;para&gt;Powerful searching&lt;/para&gt;
-      &lt;/listitem&gt;
-
-      &lt;listitem&gt;
-        &lt;para&gt;User-configurable email notifications of bug changes&lt;/para&gt;
-      &lt;/listitem&gt;
-
-      &lt;listitem&gt;
-        &lt;para&gt;Full change history&lt;/para&gt;
-      &lt;/listitem&gt;
-
-      &lt;listitem&gt;
-        &lt;para&gt;Inter-bug dependency tracking and graphing&lt;/para&gt;
-      &lt;/listitem&gt;
-
-      &lt;listitem&gt;
-        &lt;para&gt;Excellent attachment management&lt;/para&gt;
-      &lt;/listitem&gt;
-
-      &lt;listitem&gt;
-        &lt;para&gt;Integrated, product-based, granular security schema&lt;/para&gt;
-      &lt;/listitem&gt;
-
-      &lt;listitem&gt;
-        &lt;para&gt;Fully security-audited, and runs under Perl's taint mode&lt;/para&gt;
-      &lt;/listitem&gt;
-
-      &lt;listitem&gt;
-        &lt;para&gt;A robust, stable RDBMS back-end&lt;/para&gt;
-      &lt;/listitem&gt;
-
-      &lt;listitem&gt;
-        &lt;para&gt;Web, XML, email and console interfaces&lt;/para&gt;
-      &lt;/listitem&gt;
-
-      &lt;listitem&gt;
-        &lt;para&gt;Completely customisable and/or localisable web user
-        interface&lt;/para&gt;
-      &lt;/listitem&gt;
-
-      &lt;listitem&gt;
-        &lt;para&gt;Extensive configurability&lt;/para&gt;
-      &lt;/listitem&gt;
-
-      &lt;listitem&gt;
-        &lt;para&gt;Smooth upgrade pathway between versions&lt;/para&gt;
-      &lt;/listitem&gt;
-    &lt;/itemizedlist&gt;
-    &lt;/para&gt;
-  &lt;/section&gt;
-
-  &lt;section id=&quot;why&quot;&gt;
-    &lt;title&gt;Why Should We Use Bugzilla?&lt;/title&gt;
-
-    &lt;para&gt;For many years, defect-tracking software has remained principally
-    the domain of large software development houses. Even then, most shops
-    never bothered with bug-tracking software, and instead simply relied on
-    shared lists and email to monitor the status of defects. This procedure
-    is error-prone and tends to cause those bugs judged least significant by
-    developers to be dropped or ignored.&lt;/para&gt;
-
-    &lt;para&gt;These days, many companies are finding that integrated
-    defect-tracking systems reduce downtime, increase productivity, and raise
-    customer satisfaction with their systems. Along with full disclosure, an
-    open bug-tracker allows manufacturers to keep in touch with their clients
-    and resellers, to communicate about problems effectively throughout the
-    data management chain. Many corporations have also discovered that
-    defect-tracking helps reduce costs by providing IT support
-    accountability, telephone support knowledge bases, and a common,
-    well-understood system for accounting for unusual system or software
-    issues.&lt;/para&gt;
-
-    &lt;para&gt;But why should 
-    &lt;emphasis&gt;you&lt;/emphasis&gt;
-
-    use Bugzilla?&lt;/para&gt;
-
-    &lt;para&gt;Bugzilla is very adaptable to various situations. Known uses
-    currently include IT support queues, Systems Administration deployment
-    management, chip design and development problem tracking (both
-    pre-and-post fabrication), and software and hardware bug tracking for
-    luminaries such as Redhat, NASA, Linux-Mandrake, and VA Systems.
-    Combined with systems such as 
-    &lt;ulink url=&quot;http://www.cvshome.org&quot;&gt;CVS&lt;/ulink&gt;, 
-    &lt;ulink url=&quot;http://www.mozilla.org/bonsai.html&quot;&gt;Bonsai&lt;/ulink&gt;, or 
-    &lt;ulink url=&quot;http://www.perforce.com&quot;&gt;Perforce SCM&lt;/ulink&gt;, Bugzilla
-    provides a powerful, easy-to-use solution to configuration management and
-    replication problems.&lt;/para&gt;
-
-    &lt;para&gt;Bugzilla can dramatically increase the productivity and
-    accountability of individual employees by providing a documented workflow
-    and positive feedback for good performance. How many times do you wake up
-    in the morning, remembering that you were supposed to do 
-    &lt;emphasis&gt;something&lt;/emphasis&gt;
-    today, but you just can't quite remember? Put it in Bugzilla, and you
-    have a record of it from which you can extrapolate milestones, predict
-    product versions for integration, and  follow the discussion trail 
-    that led to critical decisions.&lt;/para&gt;
-
-    &lt;para&gt;Ultimately, Bugzilla puts the power in your hands to improve your
-    value to your employer or business while providing a usable framework for
-    your natural attention to detail and knowledge store to flourish.&lt;/para&gt;
-  &lt;/section&gt;
-&lt;/chapter&gt;
-
-&lt;!-- Keep this comment at the end of the file
-Local variables:
-mode: sgml
-sgml-always-quote-attributes:t
-sgml-auto-insert-required-elements:t
-sgml-balanced-tag-edit:t
-sgml-exposed-tags:nil
-sgml-general-insert-case:lower
-sgml-indent-data:t
-sgml-indent-step:2
-sgml-local-catalogs:nil
-sgml-local-ecat-files:nil
-sgml-minimize-attributes:nil
-sgml-namecase-general:t
-sgml-omittag:t
-sgml-parent-document:(&quot;Bugzilla-Guide.sgml&quot; &quot;book&quot; &quot;chapter&quot;)
-sgml-shorttag:t
-sgml-tag-region-if-active:t
-End:
---&gt;
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgdocsenxmlmodulesxml"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/docs/en/xml/modules.xml (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/docs/en/xml/modules.xml        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/docs/en/xml/modules.xml        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -98,14 +98,6 @@
</span><span class="cx">     &lt;/para&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;para&gt;
</span><del>-      File::Spec:
-      &lt;literallayout&gt;
-        CPAN Download Page: &lt;ulink url=&quot;http://search.cpan.org/dist/File-Spec/&quot;/&gt;
-        Documentation: &lt;ulink url=&quot;http://perldoc.perl.org/File/Spec.html&quot;/&gt;
-      &lt;/literallayout&gt;
-    &lt;/para&gt;
-
-    &lt;para&gt;
</del><span class="cx">       Template-Toolkit:
</span><span class="cx">       &lt;literallayout&gt;
</span><span class="cx">         CPAN Download Page: &lt;ulink url=&quot;http://search.cpan.org/dist/Template-Toolkit/&quot;/&gt;
</span><span class="lines">@@ -143,7 +135,7 @@
</span><span class="cx">     &lt;title&gt;Optional Modules&lt;/title&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;para&gt;
</span><del>-      Chart::Base:
</del><ins>+      Chart::Lines:
</ins><span class="cx">       &lt;literallayout&gt;
</span><span class="cx">         CPAN Download Page: &lt;ulink url=&quot;http://search.cpan.org/dist/Chart/&quot;/&gt;
</span><span class="cx">         Documentation: &lt;ulink url=&quot;http://search.cpan.org/dist/Chart/Chart.pod&quot;/&gt;
</span><span class="lines">@@ -181,13 +173,5 @@
</span><span class="cx">         Documentation: &lt;ulink url=&quot;http://www.johnkeiser.com/mozilla/Patch_Viewer.html&quot;/&gt;
</span><span class="cx">       &lt;/literallayout&gt;
</span><span class="cx">     &lt;/para&gt;
</span><del>-
-   &lt;para&gt;
-      Image::Magick:
-      &lt;literallayout&gt;
-        CPAN Download Page: &lt;ulink url=&quot;http://search.cpan.org/dist/PerlMagick/&quot;/&gt;
-        Documentation: &lt;ulink url=&quot;http://www.imagemagick.org/script/resources.php&quot;/&gt;
-      &lt;/literallayout&gt;
-    &lt;/para&gt;
</del><span class="cx">    &lt;/section&gt;
</span><span class="cx"> &lt;/appendix&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgdocsenxmlpatchesxml"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/docs/en/xml/patches.xml (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/docs/en/xml/patches.xml        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/docs/en/xml/patches.xml        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -21,7 +21,7 @@
</span><span class="cx"> 
</span><span class="cx">     &lt;warning&gt;
</span><span class="cx">       &lt;para&gt;
</span><del>-        These files pre-date the templatisation work done as part of the
</del><ins>+        These files pre-date the templatization work done as part of the
</ins><span class="cx">         2.16 release, and have not been updated.
</span><span class="cx">       &lt;/para&gt;
</span><span class="cx">     &lt;/warning&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgdocsenxmlrequiredsoftwarexml"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/docs/en/xml/requiredsoftware.xml (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/docs/en/xml/requiredsoftware.xml        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/docs/en/xml/requiredsoftware.xml        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,86 +0,0 @@
</span><del>-&lt;!-- &lt;!DOCTYPE appendix PUBLIC &quot;-//OASIS//DTD DocBook V4.1//EN&quot;&gt; --&gt;
-
-&lt;appendix id=&quot;downloadlinks&quot;&gt;
-  &lt;title&gt;Software Download Links&lt;/title&gt;
-  &lt;para&gt;
-    All of these sites are current as of April, 2001.  Hopefully
-    they'll stay current for a while.
-  &lt;/para&gt;
-  &lt;para&gt;
-    Apache Web Server: &lt;ulink url=&quot;http://www.apache.org/&quot;&gt;http://www.apache.org&lt;/ulink&gt;
-    Optional web server for Bugzilla, but recommended because of broad user base and support.
-  &lt;/para&gt;
-  &lt;para&gt;
-    Bugzilla: &lt;ulink url=&quot;http://www.mozilla.org/projects/bugzilla/&quot;&gt;
-      http://www.mozilla.org/projects/bugzilla/&lt;/ulink&gt;
-  &lt;/para&gt;
-  &lt;para&gt;
-    MySQL: &lt;ulink url=&quot;http://www.mysql.com/&quot;&gt;http://www.mysql.com/&lt;/ulink&gt;
-  &lt;/para&gt;
-  &lt;para&gt;
-    Perl: &lt;ulink url=&quot;http://www.perl.org&quot;&gt;http://www.perl.org/&lt;/ulink&gt;
-  &lt;/para&gt;
-  &lt;para&gt;
-    CPAN: &lt;ulink url=&quot;http://www.cpan.org/&quot;&gt;http://www.cpan.org/&lt;/ulink&gt;
-  &lt;/para&gt;
-  &lt;para&gt;
-    DBI Perl module: 
-    &lt;ulink url=&quot;http://www.cpan.org/modules/by-module/DBI/&quot;&gt;
-      http://www.cpan.org/modules/by-module/DBI/&lt;/ulink&gt;
-  &lt;/para&gt;
-  &lt;para&gt;
-    Data::Dumper module: 
-    &lt;ulink url=&quot;http://www.cpan.org/modules/by-module/Data/&quot;&gt;
-      http://www.cpan.org/modules/by-module/Data/&lt;/ulink&gt;
-  &lt;/para&gt;
-  &lt;para&gt;
-    MySQL related Perl modules:
-    &lt;ulink url=&quot;http://www.cpan.org/modules/by-module/Mysql/&quot;&gt;
-      http://www.cpan.org/modules/by-module/Mysql/&lt;/ulink&gt;
-  &lt;/para&gt;
-  &lt;para&gt;
-    TimeDate Perl module collection:
-    &lt;ulink url=&quot;http://www.cpan.org/modules/by-module/Date/&quot;&gt;
-      http://www.cpan.org/modules/by-module/Date/&lt;/ulink&gt;
-  &lt;/para&gt;
-  &lt;para&gt;
-    GD Perl module:
-    &lt;ulink url=&quot;http://www.cpan.org/modules/by-module/GD/&quot;&gt;
-      http://www.cpan.org/modules/by-module/GD/&lt;/ulink&gt;
-    Alternately, you should be able to find the latest version of
-    GD at &lt;ulink url=&quot;http://www.boutell.com/gd/&quot;&gt;http://www.boutell.com/gd/&lt;/ulink&gt;
-  &lt;/para&gt;
-  &lt;para&gt;
-    Chart::Base module:
-    &lt;ulink url=&quot;http://www.cpan.org/modules/by-module/Chart/&quot;&gt;
-    http://www.cpan.org/modules/by-module/Chart/&lt;/ulink&gt;
-  &lt;/para&gt;
-  &lt;para&gt;
-    LinuxDoc Software: 
-    &lt;ulink url=&quot;http://www.linuxdoc.org/&quot;&gt;http://www.linuxdoc.org/&lt;/ulink&gt;
-    (for documentation maintenance)
-  &lt;/para&gt;
-
-&lt;/appendix&gt;
-
-
-&lt;!-- Keep this comment at the end of the file
-Local variables:
-mode: sgml
-sgml-always-quote-attributes:t
-sgml-auto-insert-required-elements:t
-sgml-balanced-tag-edit:t
-sgml-exposed-tags:nil
-sgml-general-insert-case:lower
-sgml-indent-data:t
-sgml-indent-step:2
-sgml-local-catalogs:nil
-sgml-local-ecat-files:nil
-sgml-minimize-attributes:nil
-sgml-namecase-general:t
-sgml-omittag:t
-sgml-parent-document:(&quot;Bugzilla-Guide.sgml&quot; &quot;book&quot; &quot;chapter&quot;)
-sgml-shorttag:t
-sgml-tag-region-if-active:t
-End:
---&gt;
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgdocsenxmlsecurityxml"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/docs/en/xml/security.xml (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/docs/en/xml/security.xml        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/docs/en/xml/security.xml        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,5 +1,4 @@
</span><span class="cx"> &lt;!-- &lt;!DOCTYPE chapter PUBLIC &quot;-//OASIS//DTD DocBook XML V4.1.2//EN&quot;&gt; --&gt;
</span><del>-&lt;!-- $Id$ --&gt;
</del><span class="cx"> 
</span><span class="cx"> &lt;chapter id=&quot;security&quot;&gt;
</span><span class="cx"> &lt;title&gt;Bugzilla Security&lt;/title&gt;
</span><span class="lines">@@ -80,96 +79,7 @@
</span><span class="cx">     &lt;/section&gt;
</span><span class="cx">   
</span><span class="cx">   &lt;/section&gt;
</span><del>-  
-  
-  
-  &lt;section id=&quot;security-mysql&quot;&gt;
-  &lt;title&gt;MySQL&lt;/title&gt;
-  
-    &lt;section id=&quot;security-mysql-account&quot;&gt;
-    &lt;title&gt;The MySQL System Account&lt;/title&gt;
-    
-      &lt;para&gt;As mentioned in &lt;xref linkend=&quot;security-os-accounts&quot;/&gt;, the MySQL
-      daemon should run as a non-privileged, unique user. Be sure to consult
-      the MySQL documentation or the documentation that came with your system
-      for instructions.
-      &lt;/para&gt;
-    &lt;/section&gt;
-    
-    &lt;section id=&quot;security-mysql-root&quot;&gt;
-    &lt;title&gt;The MySQL &lt;quote&gt;root&lt;/quote&gt; and &lt;quote&gt;anonymous&lt;/quote&gt; Users&lt;/title&gt;
-    
-      &lt;para&gt;By default, MySQL comes with a &lt;quote&gt;root&lt;/quote&gt; user with a
-      blank password and an &lt;quote&gt;anonymous&lt;/quote&gt; user, also with a blank
-      password. In order to protect your data, the &lt;quote&gt;root&lt;/quote&gt; user
-      should be given a password and the anonymous user should be disabled.
-      &lt;/para&gt;
-      
-      &lt;example id=&quot;security-mysql-account-root&quot;&gt;
-      &lt;title&gt;Assigning the MySQL &lt;quote&gt;root&lt;/quote&gt; User a Password&lt;/title&gt;
-      
-        &lt;screen&gt;
-&lt;prompt&gt;bash$&lt;/prompt&gt; mysql mysql
-&lt;prompt&gt;mysql&amp;gt;&lt;/prompt&gt; UPDATE user SET password = password('&lt;replaceable&gt;new_password&lt;/replaceable&gt;') WHERE user = 'root';
-&lt;prompt&gt;mysql&amp;gt;&lt;/prompt&gt; FLUSH PRIVILEGES;
-        &lt;/screen&gt;
-      &lt;/example&gt;
-      
-      &lt;example id=&quot;security-mysql-account-anonymous&quot;&gt;
-      &lt;title&gt;Disabling the MySQL &lt;quote&gt;anonymous&lt;/quote&gt; User&lt;/title&gt;
-        &lt;screen&gt;
-&lt;prompt&gt;bash$&lt;/prompt&gt; mysql -u root -p mysql           &lt;co id=&quot;security-mysql-account-anonymous-mysql&quot;/&gt;
-&lt;prompt&gt;Enter Password:&lt;/prompt&gt; &lt;replaceable&gt;new_password&lt;/replaceable&gt;
-&lt;prompt&gt;mysql&amp;gt;&lt;/prompt&gt; DELETE FROM user WHERE user = '';
-&lt;prompt&gt;mysql&amp;gt;&lt;/prompt&gt; FLUSH PRIVILEGES;
-        &lt;/screen&gt;
-        &lt;calloutlist&gt;
-          &lt;callout arearefs=&quot;security-mysql-account-anonymous-mysql&quot;&gt;
-            &lt;para&gt;This command assumes that you have already completed
-            &lt;xref linkend=&quot;security-mysql-account-root&quot;/&gt;.
-            &lt;/para&gt;
-          &lt;/callout&gt;
-        &lt;/calloutlist&gt;
-      &lt;/example&gt;
-          
-    &lt;/section&gt;
-    
-    &lt;section id=&quot;security-mysql-network&quot;&gt;
-    &lt;title&gt;Network Access&lt;/title&gt;
-    
-      &lt;para&gt;If MySQL and your web server both run on the same machine and you
-      have no other reason to access MySQL remotely, then you should disable
-      the network access. This, along with the suggestion in
-      &lt;xref linkend=&quot;security-os-ports&quot;/&gt;, will help protect your system from
-      any remote vulnerabilities in MySQL.
-      &lt;/para&gt;
-      
-      &lt;example id=&quot;security-mysql-network-ex&quot;&gt;
-      &lt;title&gt;Disabling Networking in MySQL&lt;/title&gt;
-      
-        &lt;para&gt;Simply enter the following in &lt;filename&gt;/etc/my.cnf&lt;/filename&gt;:
-        &lt;screen&gt;
-[mysqld]
-# Prevent network access to MySQL.
-skip-networking
-        &lt;/screen&gt;
-        &lt;/para&gt;
-      &lt;/example&gt;
-      
-    &lt;/section&gt;
</del><span class="cx"> 
</span><del>-
-&lt;!-- For possible addition in the future: How to better control the bugs user
-    &lt;section id=&quot;security-mysql-bugs&quot;&gt;
-    &lt;title&gt;The bugs User&lt;/title&gt;
-    
-    &lt;/section&gt;
---&gt;
-  
-  &lt;/section&gt;
-  
-  
-  
</del><span class="cx">   &lt;section id=&quot;security-webserver&quot;&gt;
</span><span class="cx">   &lt;title&gt;Web server&lt;/title&gt;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgdocsenxmltroubleshootingxml"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/docs/en/xml/troubleshooting.xml (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/docs/en/xml/troubleshooting.xml        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/docs/en/xml/troubleshooting.xml        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,5 +1,4 @@
</span><span class="cx"> &lt;!-- &lt;!DOCTYPE chapter PUBLIC &quot;-//OASIS//DTD DocBook XML V4.1.2//EN&quot;&gt; --&gt;
</span><del>-&lt;!-- $Id$ --&gt;
</del><span class="cx"> 
</span><span class="cx"> &lt;appendix id=&quot;troubleshooting&quot;&gt;
</span><span class="cx"> &lt;title&gt;Troubleshooting&lt;/title&gt;
</span><span class="lines">@@ -22,7 +21,7 @@
</span><span class="cx">     &lt;para&gt;If you have made it all the way through
</span><span class="cx">     &lt;xref linkend=&quot;installation&quot;/&gt; (Installation) and
</span><span class="cx">     &lt;xref linkend=&quot;configuration&quot;/&gt; (Configuration) but accessing the Bugzilla
</span><del>-    URL doesn't work, the first thing to do is to check your webserver error
</del><ins>+    URL doesn't work, the first thing to do is to check your web server error
</ins><span class="cx">     log. For Apache, this is often located at
</span><span class="cx">     &lt;filename&gt;/etc/logs/httpd/error_log&lt;/filename&gt;. The error messages
</span><span class="cx">     you see may be self-explanatory enough to enable you to diagnose and
</span><span class="lines">@@ -32,7 +31,7 @@
</span><span class="cx"> 
</span><span class="cx">     &lt;para&gt;
</span><span class="cx">       Bugzilla can also log all user-based errors (and many code-based errors)
</span><del>-      that occur, without polluting the web server error log.  To enable
</del><ins>+      that occur, without polluting the web server's error log.  To enable
</ins><span class="cx">       Bugzilla error logging, create a file that Bugzilla can write to, named
</span><span class="cx">       &lt;filename&gt;errorlog&lt;/filename&gt;, in the Bugzilla &lt;filename&gt;data&lt;/filename&gt;
</span><span class="cx">       directory.  Errors will be logged as they occur, and will include the type
</span><span class="lines">@@ -45,10 +44,10 @@
</span><span class="cx">   &lt;/section&gt;
</span><span class="cx">         
</span><span class="cx">   &lt;section id=&quot;trbl-testserver&quot;&gt;
</span><del>-  &lt;title&gt;The Apache webserver is not serving Bugzilla pages&lt;/title&gt;
</del><ins>+  &lt;title&gt;The Apache web server is not serving Bugzilla pages&lt;/title&gt;
</ins><span class="cx">     &lt;para&gt;After you have run &lt;command&gt;checksetup.pl&lt;/command&gt; twice,
</span><span class="cx">     run &lt;command&gt;testserver.pl http://yoursite.yourdomain/yoururl&lt;/command&gt;
</span><del>-    to confirm that your webserver is configured properly for
</del><ins>+    to confirm that your web server is configured properly for
</ins><span class="cx">     Bugzilla.
</span><span class="cx">     &lt;/para&gt;
</span><span class="cx">     &lt;programlisting&gt;
</span><span class="lines">@@ -75,9 +74,9 @@
</span><span class="cx">         &lt;/para&gt;
</span><span class="cx">       &lt;/listitem&gt;
</span><span class="cx">       &lt;listitem&gt;
</span><del>-        &lt;para&gt;The permissions on your library directories are set incorrectly.
-        They must, at the very least, be readable by the webserver user or
-        group. It is recommended that they be world readable.
</del><ins>+        &lt;para&gt;The permissions on your library directories are set incorrectly.
+        They must, at the very least, be readable by the web server user or
+        group. It is recommended that they be world readable.
</ins><span class="cx">         &lt;/para&gt;
</span><span class="cx">       &lt;/listitem&gt;
</span><span class="cx">     &lt;/orderedlist&gt;
</span><span class="lines">@@ -139,55 +138,12 @@
</span><span class="cx">     &lt;/para&gt;
</span><span class="cx">   &lt;/section&gt;    
</span><span class="cx"> 
</span><del>-  &lt;section id=&quot;trouble-filetemp&quot;&gt;
-  &lt;title&gt;Your vendor has not defined Fcntl macro O_NOINHERIT&lt;/title&gt;
-
-    &lt;para&gt;This is caused by a bug in the version of
-    &lt;productname&gt;File::Temp&lt;/productname&gt; that is distributed with perl
-    5.6.0. Many minor variations of this error have been reported:
-    &lt;/para&gt;
-
-    &lt;programlisting&gt;Your vendor has not defined Fcntl macro O_NOINHERIT, used 
-at /usr/lib/perl5/site_perl/5.6.0/File/Temp.pm line 208.
-
-Your vendor has not defined Fcntl macro O_EXLOCK, used 
-at /usr/lib/perl5/site_perl/5.6.0/File/Temp.pm line 210.
-
-Your vendor has not defined Fcntl macro O_TEMPORARY, used 
-at /usr/lib/perl5/site_perl/5.6.0/File/Temp.pm line 233.&lt;/programlisting&gt;
-
-    &lt;para&gt;Numerous people have reported that upgrading to version 5.6.1
-    or higher solved the problem for them. A less involved fix is to apply
-    the following patch, which is also
-    available as a &lt;ulink url=&quot;../xml/filetemp.patch&quot;&gt;patch file&lt;/ulink&gt;.
-    &lt;/para&gt;
-
-    &lt;programlisting&gt;&lt;![CDATA[--- File/Temp.pm.orig   Thu Feb  6 16:26:00 2003
-+++ File/Temp.pm        Thu Feb  6 16:26:23 2003
-@@ -205,6 +205,7 @@
-     # eg CGI::Carp
-     local $SIG{__DIE__} = sub {};
-     local $SIG{__WARN__} = sub {};
-+    local *CORE::GLOBAL::die = sub {};
-     $bit = &amp;$func();
-     1;
-   };
-@@ -226,6 +227,7 @@
-     # eg CGI::Carp
-     local $SIG{__DIE__} = sub {};
-     local $SIG{__WARN__} = sub {};
-+    local *CORE::GLOBAL::die = sub {};
-     $bit = &amp;$func();
-     1;
-   };]]&gt;&lt;/programlisting&gt;
-  &lt;/section&gt;
-
</del><span class="cx">   &lt;section id=&quot;trbl-relogin-everyone&quot;&gt;
</span><span class="cx">   &lt;title&gt;Everybody is constantly being forced to relogin&lt;/title&gt;
</span><span class="cx">   
</span><span class="cx">   &lt;para&gt;The most-likely cause is that the &lt;quote&gt;cookiepath&lt;/quote&gt; parameter
</span><span class="cx">   is not set correctly in the Bugzilla configuration.  You can change this (if
</span><del>-  you're a Bugzilla administrator) from the editparams.cgi page via the web.
</del><ins>+  you're a Bugzilla administrator) from the editparams.cgi page via the web interface.
</ins><span class="cx">   &lt;/para&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;para&gt;The value of the cookiepath parameter should be the actual directory
</span><span class="lines">@@ -256,35 +212,6 @@
</span><span class="cx">     &lt;/para&gt;
</span><span class="cx">   &lt;/section&gt;
</span><span class="cx"> 
</span><del>-  &lt;section id=&quot;trbl-relogin-some&quot;&gt;
-  &lt;title&gt;Some users are constantly being forced to relogin&lt;/title&gt;
-
-    &lt;para&gt;First, make sure cookies are enabled in the user's browser.
-    &lt;/para&gt;
-
-    &lt;para&gt;If that doesn't fix the problem, it may be that the user's ISP
-     implements a rotating proxy server. This causes the user's effective IP
-     address (the address which the Bugzilla server perceives him coming from)
-     to change periodically. Since Bugzilla cookies are tied to a specific IP
-     address, each time the effective address changes, the user will have to
-     log in again.
-     &lt;/para&gt;
-
-     &lt;para&gt;If you are using 2.18 (or later), there is a
-     parameter called &lt;quote&gt;loginnetmask&lt;/quote&gt;, which you can use to set
-     the number of bits of the user's IP address to require to be matched when
-     authenticating the cookies. If you set this to something less than 32,
-     then the user will be given a checkbox for &lt;quote&gt;Restrict this login to
-     my IP address&lt;/quote&gt; on the login screen, which defaults to checked. If
-     they leave the box checked, Bugzilla will behave the same as it did
-     before, requiring an exact match on their IP address to remain logged in.
-     If they uncheck the box, then only the left side of their IP address (up
-     to the number of bits you specified in the parameter) has to match to
-     remain logged in.
-     &lt;/para&gt;
-
-   &lt;/section&gt;
-
</del><span class="cx">   &lt;section id=&quot;trbl-index&quot;&gt;
</span><span class="cx">   &lt;title&gt;&lt;filename&gt;index.cgi&lt;/filename&gt; doesn't show up unless specified in the URL&lt;/title&gt;
</span><span class="cx">     &lt;para&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgdocsenxmlusingxml"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/docs/en/xml/using.xml (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/docs/en/xml/using.xml        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/docs/en/xml/using.xml        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -332,9 +332,7 @@
</span><span class="cx">         &lt;para&gt;
</span><span class="cx">         &lt;emphasis&gt;Attachments:&lt;/emphasis&gt;
</span><span class="cx">           You can attach files (e.g. testcases or patches) to bugs. If there
</span><del>-          are any attachments, they are listed in this section.  Attachments are
-          normally stored in the Bugzilla database, unless they are marked as
-          Big Files, which are stored directly on disk.
</del><ins>+          are any attachments, they are listed in this section.
</ins><span class="cx">         &lt;/para&gt;
</span><span class="cx">       &lt;/listitem&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -365,10 +363,12 @@
</span><span class="cx">     &lt;title&gt;Life Cycle of a Bug&lt;/title&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;para&gt;
</span><del>-      The life cycle, also known as work flow, of a bug is currently hardcoded
-      into Bugzilla. &lt;xref linkend=&quot;lifecycle-image&quot;/&gt; contains a graphical
-      representation of this life cycle. If you wish to customize this image for
-      your site, the &lt;ulink url=&quot;../images/bzLifecycle.xml&quot;&gt;diagram file&lt;/ulink&gt;
</del><ins>+      The life cycle of a bug, also known as workflow, is customizable to match
+      the needs of your organization, see &lt;xref linkend=&quot;bug_status_workflow&quot;/&gt;.
+      &lt;xref linkend=&quot;lifecycle-image&quot;/&gt; contains a graphical representation of
+      the default workflow using the default bug statuses. If you wish to
+      customize this image for your site, the
+      &lt;ulink url=&quot;../images/bzLifecycle.xml&quot;&gt;diagram file&lt;/ulink&gt;
</ins><span class="cx">       is available in &lt;ulink url=&quot;http://www.gnome.org/projects/dia&quot;&gt;Dia's&lt;/ulink&gt;
</span><span class="cx">       native XML format.
</span><span class="cx">     &lt;/para&gt;
</span><span class="lines">@@ -659,16 +659,6 @@
</span><span class="cx">         &lt;/member&gt;
</span><span class="cx">       &lt;/simplelist&gt;
</span><span class="cx">       &lt;/para&gt;
</span><del>-
-      &lt;para&gt;
-        If you would like to access the bug list from another program
-        it is often useful to have the list returned in something other
-        than HTML. By adding the ctype=type parameter into the bug list URL
-        you can specify several alternate formats. Besides the types described
-        above, the following formats are also supported: ECMAScript, also known
-        as JavaScript (ctype=js), and Resource Description Framework RDF/XML
-        (ctype=rdf).
-      &lt;/para&gt;
</del><span class="cx">     &lt;/section&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;section id=&quot;individual-buglists&quot;&gt;
</span><span class="lines">@@ -862,28 +852,20 @@
</span><span class="cx">     &lt;/para&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;para&gt;
</span><del>-      If you have a really large attachment, something that does not need to
-      be recorded forever (as most attachments are), or something that is too
-      big for your database, you can mark your attachment as a
-      &lt;quote&gt;Big File&lt;/quote&gt;, assuming the administrator of the installation
-      has enabled this feature.  Big Files are stored directly on disk instead
-      of in the database.  The maximum size of a &lt;quote&gt;Big File&lt;/quote&gt; is
-      normally larger than the maximum size of a regular attachment. Independently
-      of the storage system used, an administrator can delete these attachments
-      at any time. Nevertheless, if these files are stored in the database, the
-      &lt;quote&gt;allow_attachment_deletion&lt;/quote&gt; parameter (which is turned off
-      by default) must be enabled in order to delete them.
-    &lt;/para&gt;
-
-    &lt;para&gt;
-      Also, if the administrator turned on the &lt;quote&gt;allow_attach_url&lt;/quote&gt;
-      parameter, you can enter the URL pointing to the attachment instead of
</del><ins>+      Also, you can enter the URL pointing to the attachment instead of
</ins><span class="cx">       uploading the attachment itself. For example, this is useful if you want to
</span><span class="cx">       point to an external application, a website or a very large file. Note that
</span><span class="cx">       there is no guarantee that the source file will always be available, nor
</span><span class="cx">       that its content will remain unchanged.
</span><span class="cx">     &lt;/para&gt;
</span><span class="cx"> 
</span><ins>+    &lt;para&gt;
+      Another way to attach data is to paste text directly in the text field,
+      and Bugzilla will convert it into an attachment. This is pretty useful
+      when you do copy and paste, and you don't want to put the text in a temporary
+      file first.
+    &lt;/para&gt;
+
</ins><span class="cx">     &lt;section id=&quot;patchviewer&quot;&gt;
</span><span class="cx">       &lt;title&gt;Patch Viewer&lt;/title&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -1383,7 +1365,18 @@
</span><span class="cx">              Indicates user can configure whine reports for self.
</span><span class="cx">             &lt;/para&gt;
</span><span class="cx">           &lt;/listitem&gt;
</span><del>-        &lt;/varlistentry&gt;                 
</del><ins>+        &lt;/varlistentry&gt;
+
+        &lt;varlistentry&gt;
+          &lt;term&gt;
+             bz_quip_moderators
+          &lt;/term&gt;
+          &lt;listitem&gt;
+            &lt;para&gt;
+             Indicates user can moderate quips.
+            &lt;/para&gt;
+          &lt;/listitem&gt;
+        &lt;/varlistentry&gt;
</ins><span class="cx">  
</span><span class="cx">         &lt;varlistentry&gt;
</span><span class="cx">           &lt;term&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgdocslibPodSimpleHTMLBatchBugzillapm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/docs/lib/Pod/Simple/HTMLBatch/Bugzilla.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/docs/lib/Pod/Simple/HTMLBatch/Bugzilla.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/docs/lib/Pod/Simple/HTMLBatch/Bugzilla.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -31,8 +31,9 @@
</span><span class="cx"> # Note that if you leave out a category here, it will not be indexed
</span><span class="cx"> # in the contents file, even though its HTML POD will still exist.
</span><span class="cx"> use constant FILE_TRANSLATION =&gt; {
</span><del>-    Files      =&gt; ['importxml', 'contrib', 'checksetup', 'email_in', 'install-module',
-                   'sanitycheck'],
</del><ins>+    Files      =&gt; ['importxml', 'contrib', 'checksetup', 'email_in', 
+                   'install-module', 'sanitycheck', 'jobqueue', 'migrate',
+                   'collectstats'],
</ins><span class="cx">     Modules    =&gt; ['bugzilla'],
</span><span class="cx">     Extensions =&gt; ['extensions'],
</span><span class="cx"> };
</span><span class="lines">@@ -106,4 +107,14 @@
</span><span class="cx">     return $retval;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# Exclude modules being in lib/.
+sub find_all_pods {
+    my($self, $dirs) = @_;
+    my $mod2path = $self-&gt;SUPER::find_all_pods($dirs);
+    foreach my $mod (keys %$mod2path) {
+        delete $mod2path-&gt;{$mod} if $mod =~ /^lib::/;
+    }
+    return $mod2path;
+}
+
</ins><span class="cx"> 1;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgdocsmakedocspl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/docs/makedocs.pl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/docs/makedocs.pl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/docs/makedocs.pl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -73,13 +73,6 @@
</span><span class="cx">     print ENTITIES '&lt;!ENTITY min-' . $name . '-ver &quot;'.$version.'&quot;&gt;' . &quot;\n&quot;;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-# CGI is a special case, because for Perl versions below 5.10, it has an
-# optional version *and* a required version.
-# We check @opt_modules first, then @modules, and pick the first we get.
-# We'll get the optional one then, if it is given, otherwise the required one.
-my ($cgi_opt) = grep($_-&gt;{module} eq 'CGI', @$opt_modules, @$modules);
-print ENTITIES '&lt;!ENTITY min-mp-cgi-ver &quot;' . $cgi_opt-&gt;{version} . '&quot;&gt;' . &quot;\n&quot;;
-
</del><span class="cx"> print ENTITIES &quot;\n &lt;!-- Database Versions --&gt; \n&quot;;
</span><span class="cx"> 
</span><span class="cx"> my $db_modules = DB_MODULE;
</span><span class="lines">@@ -211,12 +204,12 @@
</span><span class="cx">     chdir 'html';
</span><span class="cx"> 
</span><span class="cx">     MakeDocs('separate HTML', &quot;jade -t sgml -i html -d $LDP_HOME/ldp.dsl\#html &quot; .
</span><del>-         &quot;$JADE_PUB/xml.dcl ../xml/Bugzilla-Guide.xml&quot;);
</del><ins>+         &quot;$JADE_PUB/xml.dcl ../xml/Bugzilla-Guide.xml&quot;);
</ins><span class="cx">     MakeDocs('big HTML', &quot;jade -V nochunks -t sgml -i html -d &quot; .
</span><span class="cx">          &quot;$LDP_HOME/ldp.dsl\#html $JADE_PUB/xml.dcl &quot; .
</span><del>-         &quot;../xml/Bugzilla-Guide.xml &gt; Bugzilla-Guide.html&quot;);
</del><ins>+         &quot;../xml/Bugzilla-Guide.xml &gt; Bugzilla-Guide.html&quot;);
</ins><span class="cx">     MakeDocs('big text', &quot;lynx -dump -justify=off -nolist Bugzilla-Guide.html &quot; .
</span><del>-         &quot;&gt; ../txt/Bugzilla-Guide.txt&quot;);
</del><ins>+         &quot;&gt; ../txt/Bugzilla-Guide.txt&quot;);
</ins><span class="cx"> 
</span><span class="cx">     if (! grep($_ eq &quot;--with-pdf&quot;, @ARGV)) {
</span><span class="cx">         next;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgduplicatescgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/duplicates.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/duplicates.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/duplicates.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -18,15 +18,11 @@
</span><span class="cx"> # Copyright (C) 1998 Netscape Communications Corporation. All
</span><span class="cx"> # Rights Reserved.
</span><span class="cx"> #
</span><del>-# Contributor(s): Gervase Markham &lt;gerv@gerv.net&gt;
-#
-# Generates mostfreq list from data collected by collectstats.pl.
</del><ins>+# Contributor(s): 
+#   Gervase Markham &lt;gerv@gerv.net&gt;
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
</ins><span class="cx"> 
</span><del>-
</del><span class="cx"> use strict;
</span><del>-
-use AnyDBM_File;
-
</del><span class="cx"> use lib qw(. lib);
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla;
</span><span class="lines">@@ -34,99 +30,131 @@
</span><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> use Bugzilla::Error;
</span><span class="cx"> use Bugzilla::Search;
</span><ins>+use Bugzilla::Field;
</ins><span class="cx"> use Bugzilla::Product;
</span><span class="cx"> 
</span><del>-my $cgi = Bugzilla-&gt;cgi;
-my $template = Bugzilla-&gt;template;
-my $vars = {};
</del><ins>+use constant DEFAULTS =&gt; {
+    # We want to show bugs which:
+    # a) Aren't CLOSED; and
+    # b)  i) Aren't VERIFIED; OR
+    #    ii) Were resolved INVALID/WONTFIX
+    #
+    # The rationale behind this is that people will eventually stop
+    # reporting fixed bugs when they get newer versions of the software,
+    # but if the bug is determined to be erroneous, people will still
+    # keep reporting it, so we do need to show it here.
+    fully_exclude_status  =&gt; ['CLOSED'],
+    partly_exclude_status =&gt; ['VERIFIED'],
+    except_resolution =&gt; ['INVALID', 'WONTFIX'],
+    changedsince =&gt; 7,
+    maxrows      =&gt; 20,
+    sortby       =&gt; 'count',
+};
</ins><span class="cx"> 
</span><del>-# collectstats.pl uses duplicates.cgi to generate the RDF duplicates stats.
-# However, this conflicts with requirelogin if it's enabled; so we make
-# logging-in optional if we are running from the command line.
-if ($::ENV{'GATEWAY_INTERFACE'} eq &quot;cmdline&quot;) {
-    Bugzilla-&gt;login(LOGIN_OPTIONAL);
-}
-else {
-    Bugzilla-&gt;login();
-}
</del><ins>+###############
+# Subroutines #
+###############
</ins><span class="cx"> 
</span><del>-my $dbh = Bugzilla-&gt;switch_to_shadow_db();
</del><ins>+# $counts is a count of exactly how many direct duplicates there are for
+# each bug we're considering. $dups is a map of duplicates, from one
+# bug_id to another. We go through the duplicates map ($dups) and if one bug
+# in $count is a duplicate of another bug in $count, we add their counts
+# together under the target bug.
+sub add_indirect_dups {
+    my ($counts, $dups) = @_;
</ins><span class="cx"> 
</span><del>-my %dbmcount;
-my %count;
-my %before;
</del><ins>+    foreach my $add_from (keys %$dups) {
+        my $add_to     = walk_dup_chain($dups, $add_from);
+        my $add_amount = delete $counts-&gt;{$add_from} || 0;
+        $counts-&gt;{$add_to} += $add_amount;
+    }
+}
</ins><span class="cx"> 
</span><ins>+sub walk_dup_chain {
+    my ($dups, $from_id) = @_;
+    my $to_id = $dups-&gt;{$from_id};
+    my %seen;
+    while (my $bug_id = $dups-&gt;{$to_id}) {
+        if ($seen{$bug_id}) {
+            warn &quot;Duplicate loop: $to_id -&gt; $bug_id\n&quot;;
+            last;
+        }
+        $seen{$bug_id} = 1;
+        $to_id = $bug_id;
+    }
+    # Optimize for future calls to add_indirect_dups.
+    $dups-&gt;{$from_id} = $to_id;
+    return $to_id;
+}
+
</ins><span class="cx"> # Get params from URL
</span><span class="cx"> sub formvalue {
</span><del>-    my ($name, $default) = (@_);
-    return Bugzilla-&gt;cgi-&gt;param($name) || $default || &quot;&quot;;
</del><ins>+    my ($name) = (@_);
+    my $cgi = Bugzilla-&gt;cgi;
+    if (defined $cgi-&gt;param($name)) {
+        return $cgi-&gt;param($name);
+    }
+    elsif (exists DEFAULTS-&gt;{$name}) {
+        return ref DEFAULTS-&gt;{$name} ? @{ DEFAULTS-&gt;{$name} } 
+                                     : DEFAULTS-&gt;{$name};
+    }
+    return undef;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-my $sortby = formvalue(&quot;sortby&quot;);
-my $changedsince = formvalue(&quot;changedsince&quot;, 7);
-my $maxrows = formvalue(&quot;maxrows&quot;, 100);
-my $openonly = formvalue(&quot;openonly&quot;);
-my $reverse = formvalue(&quot;reverse&quot;) ? 1 : 0;
-my @query_products = $cgi-&gt;param('product');
-my $sortvisible = formvalue(&quot;sortvisible&quot;);
-my @buglist = (split(/[:,]/, formvalue(&quot;bug_id&quot;)));
-
-# Make sure all products are valid.
-foreach my $p (@query_products) {
-    Bugzilla::Product::check_product($p);
</del><ins>+sub sort_duplicates {
+    my ($a, $b, $sort_by) = @_;
+    if ($sort_by eq 'count' or $sort_by eq 'delta') {
+        return $a-&gt;{$sort_by} &lt;=&gt; $b-&gt;{$sort_by};
+    }
+    if ($sort_by =~ /^(bug_)?id$/) {
+        return $a-&gt;{'bug'}-&gt;$sort_by &lt;=&gt; $b-&gt;{'bug'}-&gt;$sort_by;
+    }
+    return $a-&gt;{'bug'}-&gt;$sort_by cmp $b-&gt;{'bug'}-&gt;$sort_by;
+    
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-# Small backwards-compatibility hack, dated 2002-04-10.
-$sortby = &quot;count&quot; if $sortby eq &quot;dup_count&quot;;
</del><ins>+###############
+# Main Script #
+###############
</ins><span class="cx"> 
</span><del>-# Open today's record of dupes
-my $today = days_ago(0);
-my $yesterday = days_ago(1);
</del><ins>+my $cgi = Bugzilla-&gt;cgi;
+my $template = Bugzilla-&gt;template;
+my $user = Bugzilla-&gt;login();
</ins><span class="cx"> 
</span><del>-# We don't know the exact file name, because the extension depends on the
-# underlying dbm library, which could be anything. We can't glob, because
-# perl &lt; 5.6 considers if (&lt;*&gt;) { ... } to be tainted
-# Instead, just check the return value for today's data and yesterday's,
-# and ignore file not found errors
</del><ins>+my $dbh = Bugzilla-&gt;switch_to_shadow_db();
</ins><span class="cx"> 
</span><del>-use Errno;
-use Fcntl;
-
-my $datadir = bz_locations()-&gt;{'datadir'};
-
-if (!tie(%dbmcount, 'AnyDBM_File', &quot;$datadir/duplicates/dupes$today&quot;,
-         O_RDONLY, 0644)) {
-    if ($!{ENOENT}) {
-        if (!tie(%dbmcount, 'AnyDBM_File', &quot;$datadir/duplicates/dupes$yesterday&quot;,
-                 O_RDONLY, 0644)) {
-            my $vars = { today =&gt; $today };
-            if ($!{ENOENT}) {
-                ThrowUserError(&quot;no_dupe_stats&quot;, $vars);
-            } else {
-                $vars-&gt;{'error_msg'} = $!;
-                ThrowUserError(&quot;no_dupe_stats_error_yesterday&quot;, $vars);
-            }
-        }
-    } else {
-        ThrowUserError(&quot;no_dupe_stats_error_today&quot;,
-                       { error_msg =&gt; $! });
</del><ins>+my $changedsince = formvalue(&quot;changedsince&quot;);
+my $maxrows = formvalue(&quot;maxrows&quot;);
+my $openonly = formvalue(&quot;openonly&quot;);
+my $sortby = formvalue(&quot;sortby&quot;);
+if (!grep(lc($_) eq lc($sortby), qw(count delta id))) {
+    Bugzilla::Field-&gt;check($sortby);
+}
+my $reverse = formvalue(&quot;reverse&quot;);
+# Reverse count and delta by default.
+if (!defined $reverse) {
+    if ($sortby eq 'count' or $sortby eq 'delta') {
+        $reverse = 1;
</ins><span class="cx">     }
</span><ins>+    else {
+        $reverse = 0;
+    }
</ins><span class="cx"> }
</span><ins>+my @query_products = $cgi-&gt;param('product');
+my $sortvisible = formvalue(&quot;sortvisible&quot;);
+my @bugs;
+if ($sortvisible) {
+    my @limit_to_ids = (split(/[:,]/, formvalue(&quot;bug_id&quot;) || ''));
+    @bugs = @{ Bugzilla::Bug-&gt;new_from_list(\@limit_to_ids) };
+    @bugs = @{ $user-&gt;visible_bugs(\@bugs) };
+}
</ins><span class="cx"> 
</span><del>-# Copy hash (so we don't mess up the on-disk file when we remove entries)
-%count = %dbmcount;
</del><ins>+# Make sure all products are valid.
+@query_products = map { Bugzilla::Product-&gt;check($_) } @query_products;
</ins><span class="cx"> 
</span><del>-# Remove all those dupes under the threshold parameter. 
-# We do this, before the sorting, for performance reasons.
-my $threshold = Bugzilla-&gt;params-&gt;{&quot;mostfreqthreshold&quot;};
</del><ins>+# Small backwards-compatibility hack, dated 2002-04-10.
+$sortby = &quot;count&quot; if $sortby eq &quot;dup_count&quot;;
</ins><span class="cx"> 
</span><del>-while (my ($key, $value) = each %count) {
-    delete $count{$key} if ($value &lt; $threshold);
-    
-    # If there's a buglist, restrict the bugs to that list.
-    delete $count{$key} if $sortvisible &amp;&amp; (lsearch(\@buglist, $key) == -1);
-}
-
</del><span class="cx"> my $origmaxrows = $maxrows;
</span><span class="cx"> detaint_natural($maxrows)
</span><span class="cx">   || ThrowUserError(&quot;invalid_maxrows&quot;, { maxrows =&gt; $origmaxrows});
</span><span class="lines">@@ -136,137 +164,100 @@
</span><span class="cx">   || ThrowUserError(&quot;invalid_changedsince&quot;, 
</span><span class="cx">                     { changedsince =&gt; $origchangedsince });
</span><span class="cx"> 
</span><del>-# Try and open the database from &quot;changedsince&quot; days ago
-my $dobefore = 0;
-my %delta;
-my $whenever = days_ago($changedsince);    
</del><ins>+my %total_dups = @{$dbh-&gt;selectcol_arrayref(
+    &quot;SELECT dupe_of, COUNT(dupe)
+       FROM duplicates
+   GROUP BY dupe_of&quot;, {Columns =&gt; [1,2]})};
</ins><span class="cx"> 
</span><del>-if (!tie(%before, 'AnyDBM_File', &quot;$datadir/duplicates/dupes$whenever&quot;,
-         O_RDONLY, 0644)) {
-    # Ignore file not found errors
-    if (!$!{ENOENT}) {
-        ThrowUserError(&quot;no_dupe_stats_error_whenever&quot;,
-                       { error_msg =&gt; $!,
-                         changedsince =&gt; $changedsince,
-                         whenever =&gt; $whenever,
-                       });
-    }
-} else {
-    # Calculate the deltas
-    ($delta{$_} = $count{$_} - ($before{$_} || 0)) foreach (keys(%count));
</del><ins>+my %dupe_relation = @{$dbh-&gt;selectcol_arrayref(
+    &quot;SELECT dupe, dupe_of FROM duplicates
+      WHERE dupe IN (SELECT dupe_of FROM duplicates)&quot;,
+    {Columns =&gt; [1,2]})};
+add_indirect_dups(\%total_dups, \%dupe_relation);
</ins><span class="cx"> 
</span><del>-    $dobefore = 1;
-}
</del><ins>+my $reso_field_id = get_field_id('resolution');
+my %since_dups = @{$dbh-&gt;selectcol_arrayref(
+    &quot;SELECT dupe_of, COUNT(dupe)
+       FROM duplicates INNER JOIN bugs_activity 
+                       ON bugs_activity.bug_id = duplicates.dupe 
+      WHERE added = 'DUPLICATE' AND fieldid = ? 
+            AND bug_when &gt;= &quot;
+                . $dbh-&gt;sql_date_math('LOCALTIMESTAMP(0)', '-', '?', 'DAY') .
+ &quot; GROUP BY dupe_of&quot;, {Columns=&gt;[1,2]},
+    $reso_field_id, $changedsince)};
+add_indirect_dups(\%since_dups, \%dupe_relation);
</ins><span class="cx"> 
</span><del>-my @bugs;
-my @bug_ids; 
-
-if (scalar(%count)) {
-    # use Bugzilla::Search so that we get the security checking
-    my $params = new Bugzilla::CGI({ 'bug_id' =&gt; [keys %count] });
-
-    if ($openonly) {
-        $params-&gt;param('resolution', '---');
-    } else {
-        # We want to show bugs which:
-        # a) Aren't CLOSED; and
-        # b)  i) Aren't VERIFIED; OR
-        #    ii) Were resolved INVALID/WONTFIX
-
-        # The rationale behind this is that people will eventually stop
-        # reporting fixed bugs when they get newer versions of the software,
-        # but if the bug is determined to be erroneous, people will still
-        # keep reporting it, so we do need to show it here.
-
-        # a)
-        $params-&gt;param('field0-0-0', 'bug_status');
-        $params-&gt;param('type0-0-0', 'notequals');
-        $params-&gt;param('value0-0-0', 'CLOSED');
-
-        # b) i)
-        $params-&gt;param('field0-1-0', 'bug_status');
-        $params-&gt;param('type0-1-0', 'notequals');
-        $params-&gt;param('value0-1-0', 'VERIFIED');
-
-        # b) ii)
-        $params-&gt;param('field0-1-1', 'resolution');
-        $params-&gt;param('type0-1-1', 'anyexact');
-        $params-&gt;param('value0-1-1', 'INVALID,WONTFIX');
</del><ins>+# Enforce the mostfreqthreshold parameter and the &quot;bug_id&quot; cgi param.
+my $mostfreq = Bugzilla-&gt;params-&gt;{'mostfreqthreshold'};
+foreach my $id (keys %total_dups) {
+    if ($total_dups{$id} &lt; $mostfreq) {
+        delete $total_dups{$id};
+        next;
</ins><span class="cx">     }
</span><del>-
-    # Restrict to product if requested
-    if ($cgi-&gt;param('product')) {
-        $params-&gt;param('product', join(',', @query_products));
</del><ins>+    if ($sortvisible and !grep($_-&gt;id == $id, @bugs)) {
+        delete $total_dups{$id};
</ins><span class="cx">     }
</span><ins>+}
</ins><span class="cx"> 
</span><del>-    my $query = new Bugzilla::Search('fields' =&gt; [qw(bugs.bug_id
-                                                     map_components.name
-                                                     bugs.bug_severity
-                                                     bugs.op_sys
-                                                     bugs.target_milestone
-                                                     bugs.short_desc
-                                                     bugs.bug_status
-                                                     bugs.resolution
-                                                    )
-                                                 ],
-                                     'params' =&gt; $params,
-                                    );
</del><ins>+if (!@bugs) {
+    @bugs = @{ Bugzilla::Bug-&gt;new_from_list([keys %total_dups]) };
+    @bugs = @{ $user-&gt;visible_bugs(\@bugs) };
+}
</ins><span class="cx"> 
</span><del>-    my $results = $dbh-&gt;selectall_arrayref($query-&gt;getSQL());
</del><ins>+my @fully_exclude_status = formvalue('fully_exclude_status');
+my @partly_exclude_status = formvalue('partly_exclude_status');
+my @except_resolution = formvalue('except_resolution');
</ins><span class="cx"> 
</span><del>-    foreach my $result (@$results) {
-        # Note: maximum row count is dealt with in the template.
</del><ins>+# Filter bugs by criteria
+my @result_bugs;
+foreach my $bug (@bugs) {
+    # It's possible, if somebody specified a bug ID that wasn't a dup
+    # in the &quot;buglist&quot; parameter and specified $sortvisible that there
+    # would be bugs in the list with 0 dups, so we want to avoid that.
+    next if !$total_dups{$bug-&gt;id};
</ins><span class="cx"> 
</span><del>-        my ($id, $component, $bug_severity, $op_sys, $target_milestone, 
-            $short_desc, $bug_status, $resolution) = @$result;
</del><ins>+    next if ($openonly and !$bug-&gt;isopened);
+    # If the bug has a status in @fully_exclude_status, we skip it,
+    # no question.
+    next if grep($_ eq $bug-&gt;bug_status, @fully_exclude_status);
+    # If the bug has a status in @partly_exclude_status, we skip it...
+    if (grep($_ eq $bug-&gt;bug_status, @partly_exclude_status)) {
+        # ...unless it has a resolution in @except_resolution.
+        next if !grep($_ eq $bug-&gt;resolution, @except_resolution);
+    }
</ins><span class="cx"> 
</span><del>-        push (@bugs, { id =&gt; $id,
-                       count =&gt; $count{$id},
-                       delta =&gt; $delta{$id}, 
-                       component =&gt; $component,
-                       bug_severity =&gt; $bug_severity,
-                       op_sys =&gt; $op_sys,
-                       target_milestone =&gt; $target_milestone,
-                       short_desc =&gt; $short_desc,
-                       bug_status =&gt; $bug_status, 
-                       resolution =&gt; $resolution });
-        push (@bug_ids, $id); 
</del><ins>+    if (scalar @query_products) {
+        next if !grep($_-&gt;id == $bug-&gt;product_id, @query_products);
</ins><span class="cx">     }
</span><ins>+
+    # Note: maximum row count is dealt with later.
+    push (@result_bugs, { bug =&gt; $bug,
+                          count =&gt; $total_dups{$bug-&gt;id},
+                          delta =&gt; $since_dups{$bug-&gt;id} || 0 });
</ins><span class="cx"> }
</span><ins>+@bugs = @result_bugs;
+@bugs = sort { sort_duplicates($a, $b, $sortby) } @bugs;
+if ($reverse) {
+    @bugs = reverse @bugs;
+}
+@bugs = @bugs[0..$maxrows-1] if scalar(@bugs) &gt; $maxrows;
</ins><span class="cx"> 
</span><del>-$vars-&gt;{'bugs'} = \@bugs;
-$vars-&gt;{'bug_ids'} = \@bug_ids;
-
-$vars-&gt;{'dobefore'} = $dobefore;
-$vars-&gt;{'sortby'} = $sortby;
-$vars-&gt;{'sortvisible'} = $sortvisible;
-$vars-&gt;{'changedsince'} = $changedsince;
-$vars-&gt;{'maxrows'} = $maxrows;
-$vars-&gt;{'openonly'} = $openonly;
-$vars-&gt;{'reverse'} = $reverse;
-$vars-&gt;{'format'} = $cgi-&gt;param('format');
-$vars-&gt;{'query_products'} = \@query_products;
-$vars-&gt;{'products'} = Bugzilla-&gt;user-&gt;get_selectable_products;
-
-
-my $format = $template-&gt;get_format(&quot;reports/duplicates&quot;,
-                                   scalar($cgi-&gt;param('format')),
-                                   scalar($cgi-&gt;param('ctype')));
-
-# We set the charset in Bugzilla::CGI, but CGI.pm ignores it unless the
-# Content-Type is a text type. In some cases, such as when we are
-# generating RDF, it isn't, so we specify the charset again here.
-print $cgi-&gt;header(
-    -type =&gt; $format-&gt;{'ctype'},
-    (Bugzilla-&gt;params-&gt;{'utf8'} ? ('charset', 'utf8') : () )
</del><ins>+my %vars = (
+    bugs     =&gt; \@bugs,
+    bug_ids  =&gt; [map { $_-&gt;{'bug'}-&gt;id } @bugs],
+    sortby   =&gt; $sortby,
+    openonly =&gt; $openonly,
+    maxrows  =&gt; $maxrows,
+    reverse  =&gt; $reverse,
+    format   =&gt; scalar $cgi-&gt;param('format'),
+    product  =&gt; [map { $_-&gt;name } @query_products],
+    sortvisible  =&gt; $sortvisible,
+    changedsince =&gt; $changedsince,
</ins><span class="cx"> );
</span><span class="cx"> 
</span><ins>+my $format = $template-&gt;get_format(&quot;reports/duplicates&quot;, $vars{'format'});
+print $cgi-&gt;header;
+
</ins><span class="cx"> # Generate and return the UI (HTML page) from the appropriate template.
</span><del>-$template-&gt;process($format-&gt;{'template'}, $vars)
</del><ins>+$template-&gt;process($format-&gt;{'template'}, \%vars)
</ins><span class="cx">   || ThrowTemplateError($template-&gt;error());
</span><del>-
-
-sub days_ago {
-    my ($dom, $mon, $year) = (localtime(time - ($_[0]*24*60*60)))[3, 4, 5];
-    return sprintf &quot;%04d-%02d-%02d&quot;, 1900 + $year, ++$mon, $dom;
-}
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgeditclassificationscgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/editclassifications.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/editclassifications.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/editclassifications.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -40,7 +40,7 @@
</span><span class="cx">     my $cgi = Bugzilla-&gt;cgi;
</span><span class="cx">     my $template = Bugzilla-&gt;template;
</span><span class="cx"> 
</span><del>-    $vars-&gt;{'classifications'} = [Bugzilla::Classification::get_all_classifications()]
</del><ins>+    $vars-&gt;{'classifications'} = [Bugzilla::Classification-&gt;get_all]
</ins><span class="cx">       if ($action eq 'select');
</span><span class="cx">     # There is currently only one section about classifications,
</span><span class="cx">     # so all pages point to it. Let's define it here.
</span><span class="lines">@@ -62,7 +62,7 @@
</span><span class="cx"> 
</span><span class="cx"> print $cgi-&gt;header();
</span><span class="cx"> 
</span><del>-exists Bugzilla-&gt;user-&gt;groups-&gt;{'editclassifications'}
</del><ins>+Bugzilla-&gt;user-&gt;in_group('editclassifications')
</ins><span class="cx">   || ThrowUserError(&quot;auth_failure&quot;, {group  =&gt; &quot;editclassifications&quot;,
</span><span class="cx">                                      action =&gt; &quot;edit&quot;,
</span><span class="cx">                                      object =&gt; &quot;classifications&quot;});
</span><span class="lines">@@ -100,36 +100,16 @@
</span><span class="cx"> if ($action eq 'new') {
</span><span class="cx">     check_token_data($token, 'add_classification');
</span><span class="cx"> 
</span><del>-    $class_name || ThrowUserError(&quot;classification_not_specified&quot;);
-
</del><span class="cx">     my $classification =
</span><del>-        new Bugzilla::Classification({name =&gt; $class_name});
</del><ins>+      Bugzilla::Classification-&gt;create({name        =&gt; $class_name,
+                                        description =&gt; scalar $cgi-&gt;param('description'),
+                                        sortkey     =&gt; scalar $cgi-&gt;param('sortkey')});
</ins><span class="cx"> 
</span><del>-    if ($classification) {
-        ThrowUserError(&quot;classification_already_exists&quot;,
-                       { name =&gt; $classification-&gt;name });
-    }
-
-    my $description = trim($cgi-&gt;param('description')  || '');
-
-    my $sortkey = trim($cgi-&gt;param('sortkey') || 0);
-    my $stored_sortkey = $sortkey;
-    detaint_natural($sortkey)
-      || ThrowUserError('classification_invalid_sortkey', {'name' =&gt; $class_name,
-                                                           'sortkey' =&gt; $stored_sortkey});
-
-    trick_taint($description);
-    trick_taint($class_name);
-
-    # Add the new classification.
-    $dbh-&gt;do(&quot;INSERT INTO classifications (name, description, sortkey)
-              VALUES (?, ?, ?)&quot;, undef, ($class_name, $description, $sortkey));
-
</del><span class="cx">     delete_token($token);
</span><span class="cx"> 
</span><span class="cx">     $vars-&gt;{'message'} = 'classification_created';
</span><del>-    $vars-&gt;{'classification'} = new Bugzilla::Classification({name =&gt; $class_name});
-    $vars-&gt;{'classifications'} = [Bugzilla::Classification::get_all_classifications];
</del><ins>+    $vars-&gt;{'classification'} = $classification;
+    $vars-&gt;{'classifications'} = [Bugzilla::Classification-&gt;get_all];
</ins><span class="cx">     $vars-&gt;{'token'} = issue_session_token('reclassify_classifications');
</span><span class="cx">     LoadTemplate('reclassify');
</span><span class="cx"> }
</span><span class="lines">@@ -142,8 +122,7 @@
</span><span class="cx"> 
</span><span class="cx"> if ($action eq 'del') {
</span><span class="cx"> 
</span><del>-    my $classification =
-        Bugzilla::Classification::check_classification($class_name);
</del><ins>+    my $classification = Bugzilla::Classification-&gt;check($class_name);
</ins><span class="cx"> 
</span><span class="cx">     if ($classification-&gt;id == 1) {
</span><span class="cx">         ThrowUserError(&quot;classification_not_deletable&quot;);
</span><span class="lines">@@ -166,29 +145,12 @@
</span><span class="cx"> if ($action eq 'delete') {
</span><span class="cx">     check_token_data($token, 'delete_classification');
</span><span class="cx"> 
</span><del>-    my $classification =
-        Bugzilla::Classification::check_classification($class_name);
</del><ins>+    my $classification = Bugzilla::Classification-&gt;check($class_name);
+    $classification-&gt;remove_from_db;
+    delete_token($token);
</ins><span class="cx"> 
</span><del>-    if ($classification-&gt;id == 1) {
-        ThrowUserError(&quot;classification_not_deletable&quot;);
-    }
-
-    # lock the tables before we start to change everything:
-    $dbh-&gt;bz_start_transaction();
-
-    # update products just in case
-    $dbh-&gt;do(&quot;UPDATE products SET classification_id = 1
-              WHERE classification_id = ?&quot;, undef, $classification-&gt;id);
-
-    # delete
-    $dbh-&gt;do(&quot;DELETE FROM classifications WHERE id = ?&quot;, undef,
-             $classification-&gt;id);
-
-    $dbh-&gt;bz_commit_transaction();
-
</del><span class="cx">     $vars-&gt;{'message'} = 'classification_deleted';
</span><del>-    $vars-&gt;{'classification'} = $class_name;
-    delete_token($token);
</del><ins>+    $vars-&gt;{'classification'} = $classification;
</ins><span class="cx">     LoadTemplate('select');
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -199,10 +161,8 @@
</span><span class="cx"> #
</span><span class="cx"> 
</span><span class="cx"> if ($action eq 'edit') {
</span><ins>+    my $classification = Bugzilla::Classification-&gt;check($class_name);
</ins><span class="cx"> 
</span><del>-    my $classification =
-        Bugzilla::Classification::check_classification($class_name);
-
</del><span class="cx">     $vars-&gt;{'classification'} = $classification;
</span><span class="cx">     $vars-&gt;{'token'} = issue_session_token('edit_classification');
</span><span class="cx"> 
</span><span class="lines">@@ -216,59 +176,19 @@
</span><span class="cx"> if ($action eq 'update') {
</span><span class="cx">     check_token_data($token, 'edit_classification');
</span><span class="cx"> 
</span><del>-    $class_name || ThrowUserError(&quot;classification_not_specified&quot;);
-
</del><span class="cx">     my $class_old_name = trim($cgi-&gt;param('classificationold') || '');
</span><ins>+    my $classification = Bugzilla::Classification-&gt;check($class_old_name);
</ins><span class="cx"> 
</span><del>-    my $class_old =
-        Bugzilla::Classification::check_classification($class_old_name);
</del><ins>+    $classification-&gt;set_name($class_name);
+    $classification-&gt;set_description(scalar $cgi-&gt;param('description'));
+    $classification-&gt;set_sortkey(scalar $cgi-&gt;param('sortkey'));
</ins><span class="cx"> 
</span><del>-    my $description = trim($cgi-&gt;param('description') || '');
</del><ins>+    my $changes = $classification-&gt;update;
+    delete_token($token);
</ins><span class="cx"> 
</span><del>-    my $sortkey = trim($cgi-&gt;param('sortkey') || 0);
-    my $stored_sortkey = $sortkey;
-    detaint_natural($sortkey)
-      || ThrowUserError('classification_invalid_sortkey', {'name' =&gt; $class_old-&gt;name,
-                                                           'sortkey' =&gt; $stored_sortkey});
-
-    $dbh-&gt;bz_start_transaction();
-
-    if ($class_name ne $class_old-&gt;name) {
-
-        my $class = new Bugzilla::Classification({name =&gt; $class_name});
-        if ($class) {
-            ThrowUserError(&quot;classification_already_exists&quot;,
-                           { name =&gt; $class-&gt;name });
-        }
-        trick_taint($class_name);
-        $dbh-&gt;do(&quot;UPDATE classifications SET name = ? WHERE id = ?&quot;,
-                 undef, ($class_name, $class_old-&gt;id));
-
-        $vars-&gt;{'updated_classification'} = 1;
-    }
-
-    if ($description ne $class_old-&gt;description) {
-        trick_taint($description);
-        $dbh-&gt;do(&quot;UPDATE classifications SET description = ?
-                  WHERE id = ?&quot;, undef,
-                 ($description, $class_old-&gt;id));
-
-        $vars-&gt;{'updated_description'} = 1;
-    }
-
-    if ($sortkey ne $class_old-&gt;sortkey) {
-        $dbh-&gt;do(&quot;UPDATE classifications SET sortkey = ?
-                  WHERE id = ?&quot;, undef,
-                 ($sortkey, $class_old-&gt;id));
-
-        $vars-&gt;{'updated_sortkey'} = 1;
-    }
-
-    $dbh-&gt;bz_commit_transaction();
-
</del><span class="cx">     $vars-&gt;{'message'} = 'classification_updated';
</span><del>-    $vars-&gt;{'classification'} = $class_name;
-    delete_token($token);
</del><ins>+    $vars-&gt;{'classification'} = $classification;
+    $vars-&gt;{'changes'} = $changes;
</ins><span class="cx">     LoadTemplate('select');
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -277,9 +197,7 @@
</span><span class="cx"> #
</span><span class="cx"> 
</span><span class="cx"> if ($action eq 'reclassify') {
</span><del>-
-    my $classification =
-        Bugzilla::Classification::check_classification($class_name);
</del><ins>+    my $classification = Bugzilla::Classification-&gt;check($class_name);
</ins><span class="cx">    
</span><span class="cx">     my $sth = $dbh-&gt;prepare(&quot;UPDATE products SET classification_id = ?
</span><span class="cx">                              WHERE name = ?&quot;);
</span><span class="lines">@@ -304,9 +222,7 @@
</span><span class="cx">         delete_token($token);
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    my @classifications = 
-        Bugzilla::Classification::get_all_classifications;
-    $vars-&gt;{'classifications'} = \@classifications;
</del><ins>+    $vars-&gt;{'classifications'} = [Bugzilla::Classification-&gt;get_all];
</ins><span class="cx">     $vars-&gt;{'classification'} = $classification;
</span><span class="cx">     $vars-&gt;{'token'} = issue_session_token('reclassify_classifications');
</span><span class="cx"> 
</span><span class="lines">@@ -317,4 +233,4 @@
</span><span class="cx"> # No valid action found
</span><span class="cx"> #
</span><span class="cx"> 
</span><del>-ThrowCodeError(&quot;action_unrecognized&quot;, {action =&gt; $action});
</del><ins>+ThrowUserError('unknown_action', {action =&gt; $action});
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgeditcomponentscgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/editcomponents.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/editcomponents.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/editcomponents.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -118,7 +118,7 @@
</span><span class="cx"> if ($action eq 'new') {
</span><span class="cx">     check_token_data($token, 'add_component');
</span><span class="cx">     # Do the user matching
</span><del>-    Bugzilla::User::match_field ($cgi, {
</del><ins>+    Bugzilla::User::match_field ({
</ins><span class="cx">         'initialowner'     =&gt; { 'type' =&gt; 'single' },
</span><span class="cx">         'initialqacontact' =&gt; { 'type' =&gt; 'single' },
</span><span class="cx">         'initialcc'        =&gt; { 'type' =&gt; 'multi'  },
</span><span class="lines">@@ -128,14 +128,19 @@
</span><span class="cx">     my $default_qa_contact = trim($cgi-&gt;param('initialqacontact') || '');
</span><span class="cx">     my $description        = trim($cgi-&gt;param('description')      || '');
</span><span class="cx">     my @initial_cc         = $cgi-&gt;param('initialcc');
</span><ins>+    my $isactive           = $cgi-&gt;param('isactive');
</ins><span class="cx"> 
</span><del>-    my $component =
-      Bugzilla::Component-&gt;create({ name             =&gt; $comp_name,
-                                    product          =&gt; $product,
-                                    description      =&gt; $description,
-                                    initialowner     =&gt; $default_assignee,
-                                    initialqacontact =&gt; $default_qa_contact,
-                                    initial_cc       =&gt; \@initial_cc });
</del><ins>+    my $component = Bugzilla::Component-&gt;create({
+        name             =&gt; $comp_name,
+        product          =&gt; $product,
+        description      =&gt; $description,
+        initialowner     =&gt; $default_assignee,
+        initialqacontact =&gt; $default_qa_contact,
+        initial_cc       =&gt; \@initial_cc,
+        # XXX We should not be creating series for products that we
+        # didn't create series for.
+        create_series    =&gt; 1,
+   });
</ins><span class="cx"> 
</span><span class="cx">     $vars-&gt;{'message'} = 'component_created';
</span><span class="cx">     $vars-&gt;{'comp'} = $component;
</span><span class="lines">@@ -215,7 +220,7 @@
</span><span class="cx"> if ($action eq 'update') {
</span><span class="cx">     check_token_data($token, 'edit_component');
</span><span class="cx">     # Do the user matching
</span><del>-    Bugzilla::User::match_field ($cgi, {
</del><ins>+    Bugzilla::User::match_field ({
</ins><span class="cx">         'initialowner'     =&gt; { 'type' =&gt; 'single' },
</span><span class="cx">         'initialqacontact' =&gt; { 'type' =&gt; 'single' },
</span><span class="cx">         'initialcc'        =&gt; { 'type' =&gt; 'multi'  },
</span><span class="lines">@@ -226,7 +231,8 @@
</span><span class="cx">     my $default_qa_contact    = trim($cgi-&gt;param('initialqacontact') || '');
</span><span class="cx">     my $description           = trim($cgi-&gt;param('description')      || '');
</span><span class="cx">     my @initial_cc            = $cgi-&gt;param('initialcc');
</span><del>-
</del><ins>+    my $isactive              = $cgi-&gt;param('isactive');
+  
</ins><span class="cx">     my $component =
</span><span class="cx">         Bugzilla::Component-&gt;check({ product =&gt; $product, name =&gt; $comp_old_name });
</span><span class="cx"> 
</span><span class="lines">@@ -235,6 +241,7 @@
</span><span class="cx">     $component-&gt;set_default_assignee($default_assignee);
</span><span class="cx">     $component-&gt;set_default_qa_contact($default_qa_contact);
</span><span class="cx">     $component-&gt;set_cc_list(\@initial_cc);
</span><ins>+    $component-&gt;set_is_active($isactive);
</ins><span class="cx">     my $changes = $component-&gt;update();
</span><span class="cx"> 
</span><span class="cx">     $vars-&gt;{'message'} = 'component_updated';
</span><span class="lines">@@ -248,7 +255,5 @@
</span><span class="cx">     exit;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-#
</del><span class="cx"> # No valid action found
</span><del>-#
-ThrowUserError('no_valid_action', {'field' =&gt; &quot;component&quot;});
</del><ins>+ThrowUserError('unknown_action', {action =&gt; $action});
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgeditfieldscgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/editfields.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/editfields.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/editfields.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -55,7 +55,6 @@
</span><span class="cx"> }
</span><span class="cx"> elsif ($action eq 'new') {
</span><span class="cx">     check_token_data($token, 'add_field');
</span><del>-
</del><span class="cx">     $vars-&gt;{'field'} = Bugzilla::Field-&gt;create({
</span><span class="cx">         name        =&gt; scalar $cgi-&gt;param('name'),
</span><span class="cx">         description =&gt; scalar $cgi-&gt;param('desc'),
</span><span class="lines">@@ -65,6 +64,12 @@
</span><span class="cx">         enter_bug   =&gt; scalar $cgi-&gt;param('enter_bug'),
</span><span class="cx">         obsolete    =&gt; scalar $cgi-&gt;param('obsolete'),
</span><span class="cx">         custom      =&gt; 1,
</span><ins>+        buglist     =&gt; 1,
+        visibility_field_id =&gt; scalar $cgi-&gt;param('visibility_field_id'),
+        visibility_values =&gt; [ $cgi-&gt;param('visibility_values') ],
+        value_field_id =&gt; scalar $cgi-&gt;param('value_field_id'),
+        reverse_desc =&gt; scalar $cgi-&gt;param('reverse_desc'),
+        is_mandatory =&gt; scalar $cgi-&gt;param('is_mandatory'),
</ins><span class="cx">     });
</span><span class="cx"> 
</span><span class="cx">     delete_token($token);
</span><span class="lines">@@ -107,6 +112,11 @@
</span><span class="cx">     $field-&gt;set_in_new_bugmail($cgi-&gt;param('new_bugmail'));
</span><span class="cx">     $field-&gt;set_enter_bug($cgi-&gt;param('enter_bug'));
</span><span class="cx">     $field-&gt;set_obsolete($cgi-&gt;param('obsolete'));
</span><ins>+    $field-&gt;set_is_mandatory($cgi-&gt;param('is_mandatory'));
+    $field-&gt;set_visibility_field($cgi-&gt;param('visibility_field_id'));
+    $field-&gt;set_visibility_values([ $cgi-&gt;param('visibility_values') ]);
+    $field-&gt;set_value_field($cgi-&gt;param('value_field_id'));
+    $field-&gt;set_reverse_desc($cgi-&gt;param('reverse_desc'));
</ins><span class="cx">     $field-&gt;update();
</span><span class="cx"> 
</span><span class="cx">     delete_token($token);
</span><span class="lines">@@ -161,5 +171,5 @@
</span><span class="cx">         || ThrowTemplateError($template-&gt;error());
</span><span class="cx"> }
</span><span class="cx"> else {
</span><del>-    ThrowUserError('no_valid_action', {'field' =&gt; 'custom_field'});
</del><ins>+    ThrowUserError('unknown_action', {action =&gt; $action});
</ins><span class="cx"> }
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgeditflagtypescgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/editflagtypes.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/editflagtypes.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/editflagtypes.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -38,73 +38,125 @@
</span><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> use Bugzilla::Error;
</span><span class="cx"> use Bugzilla::Product;
</span><del>-use Bugzilla::Component;
-use Bugzilla::Bug;
-use Bugzilla::Attachment;
</del><span class="cx"> use Bugzilla::Token;
</span><span class="cx"> 
</span><del>-local our $cgi = Bugzilla-&gt;cgi;
-local our $template = Bugzilla-&gt;template;
-local our $vars = {};
-
-# Make sure the user is logged in and is an administrator.
</del><ins>+# Make sure the user is logged in and has the right privileges.
</ins><span class="cx"> my $user = Bugzilla-&gt;login(LOGIN_REQUIRED);
</span><ins>+my $cgi = Bugzilla-&gt;cgi;
+my $template = Bugzilla-&gt;template;
+
+print $cgi-&gt;header();
+
</ins><span class="cx"> $user-&gt;in_group('editcomponents')
</span><ins>+  || scalar(@{$user-&gt;get_products_by_permission('editcomponents')})
</ins><span class="cx">   || ThrowUserError(&quot;auth_failure&quot;, {group  =&gt; &quot;editcomponents&quot;,
</span><span class="cx">                                      action =&gt; &quot;edit&quot;,
</span><span class="cx">                                      object =&gt; &quot;flagtypes&quot;});
</span><span class="cx"> 
</span><del>-################################################################################
-# Main Body Execution
-################################################################################
</del><ins>+# We need this everywhere.
+my $vars = get_products_and_components();
+my @products = @{$vars-&gt;{products}};
</ins><span class="cx"> 
</span><del>-# All calls to this script should contain an &quot;action&quot; variable whose value
-# determines what the user wants to do.  The code below checks the value of
-# that variable and runs the appropriate code.
-
-# Determine whether to use the action specified by the user or the default.
</del><span class="cx"> my $action = $cgi-&gt;param('action') || 'list';
</span><span class="cx"> my $token  = $cgi-&gt;param('token');
</span><del>-my @categoryActions;
</del><ins>+my $product = $cgi-&gt;param('product');
+my $component = $cgi-&gt;param('component');
+my $flag_id = $cgi-&gt;param('id');
</ins><span class="cx"> 
</span><del>-if (@categoryActions = grep(/^categoryAction-.+/, $cgi-&gt;param())) {
-    $categoryActions[0] =~ s/^categoryAction-//;
-    processCategoryChange($categoryActions[0], $token);
-    exit;
</del><ins>+if ($product) {
+    # Make sure the user is allowed to view this product name.
+    # Users with global editcomponents privs can see all product names.
+    ($product) = grep { lc($_-&gt;name) eq lc($product) } @products;
+    $product || ThrowUserError('product_access_denied', { name =&gt; $cgi-&gt;param('product') });
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-if    ($action eq 'list')           { list();           }
-elsif ($action eq 'enter')          { edit($action);    }
-elsif ($action eq 'copy')           { edit($action);    }
-elsif ($action eq 'edit')           { edit($action);    }
-elsif ($action eq 'insert')         { insert($token);   }
-elsif ($action eq 'update')         { update($token);   }
-elsif ($action eq 'confirmdelete')  { confirmDelete();  } 
-elsif ($action eq 'delete')         { deleteType($token); }
-elsif ($action eq 'deactivate')     { deactivate($token); }
-else { 
-    ThrowCodeError(&quot;action_unrecognized&quot;, { action =&gt; $action });
</del><ins>+if ($component) {
+    ($product &amp;&amp; $product-&gt;id)
+      || ThrowUserError('flag_type_component_without_product');
+    ($component) = grep { lc($_-&gt;name) eq lc($component) } @{$product-&gt;components};
+    $component || ThrowUserError('product_unknown_component', { product =&gt; $product-&gt;name,
+                                                                comp =&gt; $cgi-&gt;param('component') });
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-exit;
</del><ins>+# If 'categoryAction' is set, it has priority over 'action'.
+if (my ($category_action) = grep { $_ =~ /^categoryAction-(?:\w+)$/ } $cgi-&gt;param()) {
+    $category_action =~ s/^categoryAction-//;
</ins><span class="cx"> 
</span><del>-################################################################################
-# Functions
-################################################################################
</del><ins>+    my @inclusions = $cgi-&gt;param('inclusions');
+    my @exclusions = $cgi-&gt;param('exclusions');
+    my @categories;
+    if ($category_action =~ /^(in|ex)clude$/) {
+        if (!$user-&gt;in_group('editcomponents') &amp;&amp; !$product) {
+            # The user can only add the flag type to products he can administrate.
+            foreach my $prod (@products) {
+                push(@categories, $prod-&gt;id . ':0')
+            }
+        }
+        else {
+            my $category = ($product ? $product-&gt;id : 0) . ':' .
+                           ($component ? $component-&gt;id : 0);
+            push(@categories, $category);
+        }
+    }
</ins><span class="cx"> 
</span><del>-sub list {
-    # Restrict the list to the given product and component, if given.
-    $vars = get_products_and_components($vars);
</del><ins>+    if ($category_action eq 'include') {
+        foreach my $category (@categories) {
+            push(@inclusions, $category) unless grep($_ eq $category, @inclusions);
+        }
+    }
+    elsif ($category_action eq 'exclude') {
+        foreach my $category (@categories) {
+            push(@exclusions, $category) unless grep($_ eq $category, @exclusions);
+        }
+    }
+    elsif ($category_action eq 'removeInclusion') {
+        my @inclusion_to_remove = $cgi-&gt;param('inclusion_to_remove');
+        foreach my $remove (@inclusion_to_remove) {
+            @inclusions = grep { $_ ne $remove } @inclusions;
+        }
+    }
+    elsif ($category_action eq 'removeExclusion') {
+        my @exclusion_to_remove = $cgi-&gt;param('exclusion_to_remove');
+        foreach my $remove (@exclusion_to_remove) {
+            @exclusions = grep { $_ ne $remove } @exclusions;
+        }
+    }
</ins><span class="cx"> 
</span><del>-    my $product = validateProduct(scalar $cgi-&gt;param('product'));
-    my $component = validateComponent($product, scalar $cgi-&gt;param('component'));
</del><ins>+    $vars-&gt;{'groups'} = get_settable_groups();
+    $vars-&gt;{'action'} = $action;
+
+    my $type = {};
+    $type-&gt;{$_} = $cgi-&gt;param($_) foreach $cgi-&gt;param();
+    # Make sure boolean fields are defined, else they fall back to 1.
+    foreach my $boolean (qw(is_active is_requestable is_requesteeble is_multiplicable)) {
+        $type-&gt;{$boolean} ||= 0;
+    }
+
+    # That's what I call a big hack. The template expects to see a group object.
+    $type-&gt;{'grant_group'} = {};
+    $type-&gt;{'grant_group'}-&gt;{'name'} = $cgi-&gt;param('grant_group');
+    $type-&gt;{'request_group'} = {};
+    $type-&gt;{'request_group'}-&gt;{'name'} = $cgi-&gt;param('request_group');
+
+    $vars-&gt;{'inclusions'} = clusion_array_to_hash(\@inclusions, \@products);
+    $vars-&gt;{'exclusions'} = clusion_array_to_hash(\@exclusions, \@products);
+
+    $vars-&gt;{'type'} = $type;
+    $vars-&gt;{'token'} = $token;
+    $vars-&gt;{'check_clusions'} = 1;
+    $vars-&gt;{'can_fully_edit'} = $cgi-&gt;param('can_fully_edit');
+
+    $template-&gt;process(&quot;admin/flag-type/edit.html.tmpl&quot;, $vars)
+      || ThrowTemplateError($template-&gt;error());
+    exit;
+}
+
+if ($action eq 'list') {
</ins><span class="cx">     my $product_id = $product ? $product-&gt;id : 0;
</span><span class="cx">     my $component_id = $component ? $component-&gt;id : 0;
</span><ins>+    my $show_flag_counts = $cgi-&gt;param('show_flag_counts') ? 1 : 0;
+    my $group_id = $cgi-&gt;param('group');
</ins><span class="cx"> 
</span><del>-    # Define the variables and functions that will be passed to the UI template.
-    $vars-&gt;{'selected_product'} = $cgi-&gt;param('product');
-    $vars-&gt;{'selected_component'} = $cgi-&gt;param('component');
-
</del><span class="cx">     my $bug_flagtypes;
</span><span class="cx">     my $attach_flagtypes;
</span><span class="cx"> 
</span><span class="lines">@@ -115,8 +167,8 @@
</span><span class="cx">         $attach_flagtypes = $component-&gt;flag_types-&gt;{'attachment'};
</span><span class="cx"> 
</span><span class="cx">         # Filter flag types if a group ID is given.
</span><del>-        $bug_flagtypes = filter_group($bug_flagtypes);
-        $attach_flagtypes = filter_group($attach_flagtypes);
</del><ins>+        $bug_flagtypes = filter_group($bug_flagtypes, $group_id);
+        $attach_flagtypes = filter_group($attach_flagtypes, $group_id);
</ins><span class="cx"> 
</span><span class="cx">     }
</span><span class="cx">     # If only a product is specified but no component, then restrict the list
</span><span class="lines">@@ -126,48 +178,77 @@
</span><span class="cx">         $attach_flagtypes = $product-&gt;flag_types-&gt;{'attachment'};
</span><span class="cx"> 
</span><span class="cx">         # Filter flag types if a group ID is given.
</span><del>-        $bug_flagtypes = filter_group($bug_flagtypes);
-        $attach_flagtypes = filter_group($attach_flagtypes);
</del><ins>+        $bug_flagtypes = filter_group($bug_flagtypes, $group_id);
+        $attach_flagtypes = filter_group($attach_flagtypes, $group_id);
</ins><span class="cx">     }
</span><span class="cx">     # If no product is given, then show all flag types available.
</span><span class="cx">     else {
</span><del>-        $bug_flagtypes =
-            Bugzilla::FlagType::match({'target_type' =&gt; 'bug',
-                                       'group' =&gt; scalar $cgi-&gt;param('group')});
</del><ins>+        my $flagtypes = get_editable_flagtypes(\@products, $group_id);
+        $bug_flagtypes = [grep { $_-&gt;target_type eq 'bug' } @$flagtypes];
+        $attach_flagtypes = [grep { $_-&gt;target_type eq 'attachment' } @$flagtypes];
+    }
</ins><span class="cx"> 
</span><del>-        $attach_flagtypes =
-            Bugzilla::FlagType::match({'target_type' =&gt; 'attachment',
-                                         'group' =&gt; scalar $cgi-&gt;param('group')});
</del><ins>+    if ($show_flag_counts) {
+        my %bug_lists;
+        my %map = ('+' =&gt; 'granted', '-' =&gt; 'denied', '?' =&gt; 'pending');
+
+        foreach my $flagtype (@$bug_flagtypes, @$attach_flagtypes) {
+            $bug_lists{$flagtype-&gt;id} = {};
+            my $flags = Bugzilla::Flag-&gt;match({type_id =&gt; $flagtype-&gt;id});
+            # Build lists of bugs, triaged by flag status.
+            push(@{$bug_lists{$flagtype-&gt;id}-&gt;{$map{$_-&gt;status}}}, $_-&gt;bug_id) foreach @$flags;
+        }
+        $vars-&gt;{'bug_lists'} = \%bug_lists;
+        $vars-&gt;{'show_flag_counts'} = 1;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    $vars-&gt;{'selected_product'} = $product ? $product-&gt;name : '';
+    $vars-&gt;{'selected_component'} = $component ? $component-&gt;name : '';
</ins><span class="cx">     $vars-&gt;{'bug_types'} = $bug_flagtypes;
</span><span class="cx">     $vars-&gt;{'attachment_types'} = $attach_flagtypes;
</span><span class="cx"> 
</span><del>-    # Return the appropriate HTTP response headers.
-    print $cgi-&gt;header();
-
-    # Generate and return the UI (HTML page) from the appropriate template.
</del><span class="cx">     $template-&gt;process(&quot;admin/flag-type/list.html.tmpl&quot;, $vars)
</span><span class="cx">       || ThrowTemplateError($template-&gt;error());
</span><ins>+    exit;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+if ($action eq 'enter') {
+    my $type = $cgi-&gt;param('target_type');
+    ($type eq 'bug' || $type eq 'attachment')
+      || ThrowCodeError('flag_type_target_type_invalid', { target_type =&gt; $type });
</ins><span class="cx"> 
</span><del>-sub edit {
-    my ($action) = @_;
</del><ins>+    $vars-&gt;{'action'} = 'insert';
+    $vars-&gt;{'token'} = issue_session_token('add_flagtype');
+    $vars-&gt;{'type'} = { 'target_type' =&gt; $type };
+    # Only users with global editcomponents privs can add a flagtype
+    # to all products.
+    $vars-&gt;{'inclusions'} = { '__Any__:__Any__' =&gt; '0:0' }
+      if $user-&gt;in_group('editcomponents');
+    $vars-&gt;{'can_fully_edit'} = 1;
+    # Get a list of groups available to restrict this flag type against.
+    $vars-&gt;{'groups'} = get_settable_groups();
</ins><span class="cx"> 
</span><del>-    my $flag_type;
-    if ($action eq 'enter') {
-        validateTargetType();
</del><ins>+    $template-&gt;process(&quot;admin/flag-type/edit.html.tmpl&quot;, $vars)
+      || ThrowTemplateError($template-&gt;error());
+    exit;
+}
+
+if ($action eq 'edit' || $action eq 'copy') {
+    my ($flagtype, $can_fully_edit) = $user-&gt;check_can_admin_flagtype($flag_id);
+    $vars-&gt;{'type'} = $flagtype;
+    $vars-&gt;{'can_fully_edit'} = $can_fully_edit;
+
+    if ($user-&gt;in_group('editcomponents')) {
+        $vars-&gt;{'inclusions'} = $flagtype-&gt;inclusions;
+        $vars-&gt;{'exclusions'} = $flagtype-&gt;exclusions;
</ins><span class="cx">     }
</span><span class="cx">     else {
</span><del>-        $flag_type = validateID();
</del><ins>+        # Filter products the user shouldn't know about.
+        $vars-&gt;{'inclusions'} = clusion_array_to_hash([values %{$flagtype-&gt;inclusions}], \@products);
+        $vars-&gt;{'exclusions'} = clusion_array_to_hash([values %{$flagtype-&gt;exclusions}], \@products);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    # Fill $vars with products and components data.
-    $vars = get_products_and_components($vars);
-
-    $vars-&gt;{'last_action'} = $cgi-&gt;param('action');
-    if ($cgi-&gt;param('action') eq 'enter' || $cgi-&gt;param('action') eq 'copy') {
</del><ins>+    if ($action eq 'copy') {
</ins><span class="cx">         $vars-&gt;{'action'} = &quot;insert&quot;;
</span><span class="cx">         $vars-&gt;{'token'} = issue_session_token('add_flagtype');
</span><span class="cx">     }
</span><span class="lines">@@ -176,352 +257,204 @@
</span><span class="cx">         $vars-&gt;{'token'} = issue_session_token('edit_flagtype');
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    # If copying or editing an existing flag type, retrieve it.
-    if ($cgi-&gt;param('action') eq 'copy' || $cgi-&gt;param('action') eq 'edit') { 
-        $vars-&gt;{'type'} = $flag_type;
-    }
-    # Otherwise set the target type (the minimal information about the type
-    # that the template needs to know) from the URL parameter and default
-    # the list of inclusions to all categories.
-    else {
-        my %inclusions;
-        $inclusions{&quot;__Any__:__Any__&quot;} = &quot;0:0&quot;;
-        $vars-&gt;{'type'} = { 'target_type' =&gt; scalar $cgi-&gt;param('target_type'),
-                            'inclusions'  =&gt; \%inclusions };
-    }
</del><span class="cx">     # Get a list of groups available to restrict this flag type against.
</span><del>-    my @groups = Bugzilla::Group-&gt;get_all;
-    $vars-&gt;{'groups'} = \@groups;
-    # Return the appropriate HTTP response headers.
-    print $cgi-&gt;header();
</del><ins>+    $vars-&gt;{'groups'} = get_settable_groups();
</ins><span class="cx"> 
</span><del>-    # Generate and return the UI (HTML page) from the appropriate template.
</del><span class="cx">     $template-&gt;process(&quot;admin/flag-type/edit.html.tmpl&quot;, $vars)
</span><span class="cx">       || ThrowTemplateError($template-&gt;error());
</span><ins>+    exit;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub processCategoryChange {
-    my ($categoryAction, $token) = @_;
-    validateIsActive();
-    validateIsRequestable();
-    validateIsRequesteeble();
-    validateAllowMultiple();
-    
-    my @inclusions = $cgi-&gt;param('inclusions');
-    my @exclusions = $cgi-&gt;param('exclusions');
-    if ($categoryAction eq 'include') {
-        my $product = validateProduct(scalar $cgi-&gt;param('product'));
-        my $component = validateComponent($product, scalar $cgi-&gt;param('component'));
-        my $category = ($product ? $product-&gt;id : 0) . &quot;:&quot; .
-                       ($component ? $component-&gt;id : 0);
-        push(@inclusions, $category) unless grep($_ eq $category, @inclusions);
-    }
-    elsif ($categoryAction eq 'exclude') {
-        my $product = validateProduct(scalar $cgi-&gt;param('product'));
-        my $component = validateComponent($product, scalar $cgi-&gt;param('component'));
-        my $category = ($product ? $product-&gt;id : 0) . &quot;:&quot; .
-                       ($component ? $component-&gt;id : 0);
-        push(@exclusions, $category) unless grep($_ eq $category, @exclusions);
-    }
-    elsif ($categoryAction eq 'removeInclusion') {
-        my @inclusion_to_remove = $cgi-&gt;param('inclusion_to_remove');
-        @inclusions = map {(lsearch(\@inclusion_to_remove, $_) &lt; 0) ? $_ : ()} @inclusions;
-    }
-    elsif ($categoryAction eq 'removeExclusion') {
-        my @exclusion_to_remove = $cgi-&gt;param('exclusion_to_remove');
-        @exclusions = map {(lsearch(\@exclusion_to_remove, $_) &lt; 0) ? $_ : ()} @exclusions;
-    }
-    
-    # Convert the array @clusions('prod_ID:comp_ID') back to a hash of
-    # the form %clusions{'prod_name:comp_name'} = 'prod_ID:comp_ID'
-    my %inclusions = clusion_array_to_hash(\@inclusions);
-    my %exclusions = clusion_array_to_hash(\@exclusions);
</del><ins>+if ($action eq 'insert') {
+    check_token_data($token, 'add_flagtype');
</ins><span class="cx"> 
</span><del>-    # Fill $vars with products and components data.
-    $vars = get_products_and_components($vars);
</del><ins>+    my $name             = $cgi-&gt;param('name');
+    my $description      = $cgi-&gt;param('description');
+    my $target_type      = $cgi-&gt;param('target_type');
+    my $cc_list          = $cgi-&gt;param('cc_list');
+    my $sortkey          = $cgi-&gt;param('sortkey');
+    my $is_active        = $cgi-&gt;param('is_active');
+    my $is_requestable   = $cgi-&gt;param('is_requestable');
+    my $is_specifically  = $cgi-&gt;param('is_requesteeble');
+    my $is_multiplicable = $cgi-&gt;param('is_multiplicable');
+    my $grant_group      = $cgi-&gt;param('grant_group');
+    my $request_group    = $cgi-&gt;param('request_group');
+    my @inclusions       = $cgi-&gt;param('inclusions');
+    my @exclusions       = $cgi-&gt;param('exclusions');
</ins><span class="cx"> 
</span><del>-    my @groups = Bugzilla::Group-&gt;get_all;
-    $vars-&gt;{'groups'} = \@groups;
-    $vars-&gt;{'action'} = $cgi-&gt;param('action');
-
-    my $type = {};
-    foreach my $key ($cgi-&gt;param()) { $type-&gt;{$key} = $cgi-&gt;param($key) }
-    # That's what I call a big hack. The template expects to see a group object.
-    # This script needs some rewrite anyway.
-    $type-&gt;{'grant_group'} = {};
-    $type-&gt;{'grant_group'}-&gt;{'name'} = $cgi-&gt;param('grant_group');
-    $type-&gt;{'request_group'} = {};
-    $type-&gt;{'request_group'}-&gt;{'name'} = $cgi-&gt;param('request_group');
-
-    $type-&gt;{'inclusions'} = \%inclusions;
-    $type-&gt;{'exclusions'} = \%exclusions;
-    $vars-&gt;{'type'} = $type;
-    $vars-&gt;{'token'} = $token;
-
-    # Return the appropriate HTTP response headers.
-    print $cgi-&gt;header();
-
-    # Generate and return the UI (HTML page) from the appropriate template.
-    $template-&gt;process(&quot;admin/flag-type/edit.html.tmpl&quot;, $vars)
-      || ThrowTemplateError($template-&gt;error());
-}
-
-# Convert the array @clusions('prod_ID:comp_ID') back to a hash of
-# the form %clusions{'prod_name:comp_name'} = 'prod_ID:comp_ID'
-sub clusion_array_to_hash {
-    my $array = shift;
-    my %hash;
-    my %products;
-    my %components;
-    foreach my $ids (@$array) {
-        trick_taint($ids);
-        my ($product_id, $component_id) = split(&quot;:&quot;, $ids);
-        my $product_name = &quot;__Any__&quot;;
-        if ($product_id) {
-            $products{$product_id} ||= new Bugzilla::Product($product_id);
-            $product_name = $products{$product_id}-&gt;name if $products{$product_id};
-        }
-        my $component_name = &quot;__Any__&quot;;
-        if ($component_id) {
-            $components{$component_id} ||= new Bugzilla::Component($component_id);
-            $component_name = $components{$component_id}-&gt;name if $components{$component_id};
-        }
-        $hash{&quot;$product_name:$component_name&quot;} = $ids;
</del><ins>+    # Filter inclusion and exclusion lists to products the user can see.
+    unless ($user-&gt;in_group('editcomponents')) {
+        @inclusions = values %{clusion_array_to_hash(\@inclusions, \@products)};
+        @exclusions = values %{clusion_array_to_hash(\@exclusions, \@products)};
</ins><span class="cx">     }
</span><del>-    return %hash;
-}
</del><span class="cx"> 
</span><del>-sub insert {
-    my $token = shift;
-    check_token_data($token, 'add_flagtype');
-    my $name = validateName();
-    my $description = validateDescription();
-    my $cc_list = validateCCList();
-    validateTargetType();
-    validateSortKey();
-    validateIsActive();
-    validateIsRequestable();
-    validateIsRequesteeble();
-    validateAllowMultiple();
-    validateGroups();
</del><ins>+    my $flagtype = Bugzilla::FlagType-&gt;create({
+        name        =&gt; $name,
+        description =&gt; $description,
+        target_type =&gt; $target_type,
+        cc_list     =&gt; $cc_list,
+        sortkey     =&gt; $sortkey,
+        is_active   =&gt; $is_active,
+        is_requestable   =&gt; $is_requestable,
+        is_requesteeble  =&gt; $is_specifically,
+        is_multiplicable =&gt; $is_multiplicable,
+        grant_group      =&gt; $grant_group,
+        request_group    =&gt; $request_group,
+        inclusions       =&gt; \@inclusions,
+        exclusions       =&gt; \@exclusions
+    });
</ins><span class="cx"> 
</span><del>-    my $dbh = Bugzilla-&gt;dbh;
</del><ins>+    delete_token($token);
</ins><span class="cx"> 
</span><del>-    my $target_type = $cgi-&gt;param('target_type') eq &quot;bug&quot; ? &quot;b&quot; : &quot;a&quot;;
-
-    $dbh-&gt;bz_start_transaction();
-
-    # Insert a record for the new flag type into the database.
-    $dbh-&gt;do('INSERT INTO flagtypes
-                          (name, description, cc_list, target_type,
-                           sortkey, is_active, is_requestable, 
-                           is_requesteeble, is_multiplicable, 
-                           grant_group_id, request_group_id) 
-                   VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
-              undef, ($name, $description, $cc_list, $target_type,
-                      $cgi-&gt;param('sortkey'), $cgi-&gt;param('is_active'),
-                      $cgi-&gt;param('is_requestable'), $cgi-&gt;param('is_requesteeble'),
-                      $cgi-&gt;param('is_multiplicable'), scalar($cgi-&gt;param('grant_gid')),
-                      scalar($cgi-&gt;param('request_gid'))));
-
-    # Get the ID of the new flag type.
-    my $id = $dbh-&gt;bz_last_key('flagtypes', 'id');
-
-    # Populate the list of inclusions/exclusions for this flag type.
-    validateAndSubmit($id);
-
-    $dbh-&gt;bz_commit_transaction();
-
-    $vars-&gt;{'name'} = $name;
</del><ins>+    $vars-&gt;{'name'} = $flagtype-&gt;name;
</ins><span class="cx">     $vars-&gt;{'message'} = &quot;flag_type_created&quot;;
</span><del>-    delete_token($token);
</del><span class="cx"> 
</span><del>-    $vars-&gt;{'bug_types'} = Bugzilla::FlagType::match({'target_type' =&gt; 'bug'});
-    $vars-&gt;{'attachment_types'} = Bugzilla::FlagType::match({'target_type' =&gt; 'attachment'});
</del><ins>+    my $flagtypes = get_editable_flagtypes(\@products);
+    $vars-&gt;{'bug_types'} = [grep { $_-&gt;target_type eq 'bug' } @$flagtypes];
+    $vars-&gt;{'attachment_types'} = [grep { $_-&gt;target_type eq 'attachment' } @$flagtypes];
</ins><span class="cx"> 
</span><del>-    # Return the appropriate HTTP response headers.
-    print $cgi-&gt;header();
-
</del><span class="cx">     $template-&gt;process(&quot;admin/flag-type/list.html.tmpl&quot;, $vars)
</span><span class="cx">       || ThrowTemplateError($template-&gt;error());
</span><ins>+    exit;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-
-sub update {
-    my $token = shift;
</del><ins>+if ($action eq 'update') {
</ins><span class="cx">     check_token_data($token, 'edit_flagtype');
</span><del>-    my $flag_type = validateID();
-    my $id = $flag_type-&gt;id;
-    my $name = validateName();
-    my $description = validateDescription();
-    my $cc_list = validateCCList();
-    validateTargetType();
-    validateSortKey();
-    validateIsActive();
-    validateIsRequestable();
-    validateIsRequesteeble();
-    validateAllowMultiple();
-    validateGroups();
</del><span class="cx"> 
</span><del>-    my $dbh = Bugzilla-&gt;dbh;
-    my $user = Bugzilla-&gt;user;
-    $dbh-&gt;bz_start_transaction();
-    $dbh-&gt;do('UPDATE flagtypes
-                 SET name = ?, description = ?, cc_list = ?,
-                     sortkey = ?, is_active = ?, is_requestable = ?,
-                     is_requesteeble = ?, is_multiplicable = ?,
-                     grant_group_id = ?, request_group_id = ?
-               WHERE id = ?',
-              undef, ($name, $description, $cc_list, $cgi-&gt;param('sortkey'),
-                      $cgi-&gt;param('is_active'), $cgi-&gt;param('is_requestable'),
-                      $cgi-&gt;param('is_requesteeble'), $cgi-&gt;param('is_multiplicable'),
-                      scalar($cgi-&gt;param('grant_gid')), scalar($cgi-&gt;param('request_gid')),
-                      $id));
-    
-    # Update the list of inclusions/exclusions for this flag type.
-    validateAndSubmit($id);
</del><ins>+    my $name             = $cgi-&gt;param('name');
+    my $description      = $cgi-&gt;param('description');
+    my $cc_list          = $cgi-&gt;param('cc_list');
+    my $sortkey          = $cgi-&gt;param('sortkey');
+    my $is_active        = $cgi-&gt;param('is_active');
+    my $is_requestable   = $cgi-&gt;param('is_requestable');
+    my $is_specifically  = $cgi-&gt;param('is_requesteeble');
+    my $is_multiplicable = $cgi-&gt;param('is_multiplicable');
+    my $grant_group      = $cgi-&gt;param('grant_group');
+    my $request_group    = $cgi-&gt;param('request_group');
+    my @inclusions       = $cgi-&gt;param('inclusions');
+    my @exclusions       = $cgi-&gt;param('exclusions');
</ins><span class="cx"> 
</span><del>-    $dbh-&gt;bz_commit_transaction();
-
-    # Clear existing flags for bugs/attachments in categories no longer on 
-    # the list of inclusions or that have been added to the list of exclusions.
-    my $flag_ids = $dbh-&gt;selectcol_arrayref('SELECT DISTINCT flags.id
-                                               FROM flags
-                                         INNER JOIN bugs
-                                                 ON flags.bug_id = bugs.bug_id
-                                    LEFT OUTER JOIN flaginclusions AS i
-                                                 ON (flags.type_id = i.type_id 
-                                                     AND (bugs.product_id = i.product_id
-                                                          OR i.product_id IS NULL)
-                                                     AND (bugs.component_id = i.component_id
-                                                          OR i.component_id IS NULL))
-                                              WHERE flags.type_id = ?
-                                                AND i.type_id IS NULL',
-                                             undef, $id);
-    my $flags = Bugzilla::Flag-&gt;new_from_list($flag_ids);
-    foreach my $flag (@$flags) {
-        my $bug = new Bugzilla::Bug($flag-&gt;bug_id);
-        Bugzilla::Flag::clear($flag, $bug, $flag-&gt;attachment);
</del><ins>+    my ($flagtype, $can_fully_edit) = $user-&gt;check_can_admin_flagtype($flag_id);
+    if ($cgi-&gt;param('check_clusions') &amp;&amp; !$user-&gt;in_group('editcomponents')) {
+        # Filter inclusion and exclusion lists to products the user can edit.
+        @inclusions = values %{clusion_array_to_hash(\@inclusions, \@products)};
+        @exclusions = values %{clusion_array_to_hash(\@exclusions, \@products)};
+        # Bring back the products the user cannot edit.
+        foreach my $item (values %{$flagtype-&gt;inclusions}) {
+            my ($prod_id, $comp_id) = split(':', $item);
+            push(@inclusions, $item) unless grep { $_-&gt;id == $prod_id } @products;
+        }
+        foreach my $item (values %{$flagtype-&gt;exclusions}) {
+            my ($prod_id, $comp_id) = split(':', $item);
+            push(@exclusions, $item) unless grep { $_-&gt;id == $prod_id } @products;
+        }
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    $flag_ids = $dbh-&gt;selectcol_arrayref('SELECT DISTINCT flags.id
-                                            FROM flags
-                                      INNER JOIN bugs 
-                                              ON flags.bug_id = bugs.bug_id
-                                      INNER JOIN flagexclusions AS e
-                                              ON flags.type_id = e.type_id
-                                           WHERE flags.type_id = ?
-                                             AND (bugs.product_id = e.product_id
-                                                  OR e.product_id IS NULL)
-                                             AND (bugs.component_id = e.component_id
-                                                  OR e.component_id IS NULL)',
-                                          undef, $id);
-    $flags = Bugzilla::Flag-&gt;new_from_list($flag_ids);
-    foreach my $flag (@$flags) {
-        my $bug = new Bugzilla::Bug($flag-&gt;bug_id);
-        Bugzilla::Flag::clear($flag, $bug, $flag-&gt;attachment);
</del><ins>+    if ($can_fully_edit) {
+        $flagtype-&gt;set_name($name);
+        $flagtype-&gt;set_description($description);
+        $flagtype-&gt;set_cc_list($cc_list);
+        $flagtype-&gt;set_sortkey($sortkey);
+        $flagtype-&gt;set_is_active($is_active);
+        $flagtype-&gt;set_is_requestable($is_requestable);
+        $flagtype-&gt;set_is_specifically_requestable($is_specifically);
+        $flagtype-&gt;set_is_multiplicable($is_multiplicable);
+        $flagtype-&gt;set_grant_group($grant_group);
+        $flagtype-&gt;set_request_group($request_group);
</ins><span class="cx">     }
</span><ins>+    $flagtype-&gt;set_clusions({ inclusions =&gt; \@inclusions, exclusions =&gt; \@exclusions})
+      if $cgi-&gt;param('check_clusions');
+    my $changes = $flagtype-&gt;update();
</ins><span class="cx"> 
</span><del>-    # Now silently remove requestees from flags which are no longer
-    # specifically requestable.
-    if (!$cgi-&gt;param('is_requesteeble')) {
-        $dbh-&gt;do('UPDATE flags SET requestee_id = NULL WHERE type_id = ?',
-                 undef, $id);
-    }
-
-    $vars-&gt;{'name'} = $name;
-    $vars-&gt;{'message'} = &quot;flag_type_changes_saved&quot;;
</del><span class="cx">     delete_token($token);
</span><span class="cx"> 
</span><del>-    $vars-&gt;{'bug_types'} = Bugzilla::FlagType::match({'target_type' =&gt; 'bug'});
-    $vars-&gt;{'attachment_types'} = Bugzilla::FlagType::match({'target_type' =&gt; 'attachment'});
</del><ins>+    $vars-&gt;{'flagtype'} = $flagtype;
+    $vars-&gt;{'changes'} = $changes;
+    $vars-&gt;{'message'} = 'flag_type_updated';
</ins><span class="cx"> 
</span><del>-    # Return the appropriate HTTP response headers.
-    print $cgi-&gt;header();
</del><ins>+    my $flagtypes = get_editable_flagtypes(\@products);
+    $vars-&gt;{'bug_types'} = [grep { $_-&gt;target_type eq 'bug' } @$flagtypes];
+    $vars-&gt;{'attachment_types'} = [grep { $_-&gt;target_type eq 'attachment' } @$flagtypes];
</ins><span class="cx"> 
</span><span class="cx">     $template-&gt;process(&quot;admin/flag-type/list.html.tmpl&quot;, $vars)
</span><span class="cx">       || ThrowTemplateError($template-&gt;error());
</span><ins>+    exit;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+if ($action eq 'confirmdelete') {
+    my ($flagtype, $can_fully_edit) = $user-&gt;check_can_admin_flagtype($flag_id);
+    ThrowUserError('flag_type_cannot_delete', { flagtype =&gt; $flagtype }) unless $can_fully_edit;
</ins><span class="cx"> 
</span><del>-sub confirmDelete {
-    my $flag_type = validateID();
-
-    $vars-&gt;{'flag_type'} = $flag_type;
</del><ins>+    $vars-&gt;{'flag_type'} = $flagtype;
</ins><span class="cx">     $vars-&gt;{'token'} = issue_session_token('delete_flagtype');
</span><del>-    # Return the appropriate HTTP response headers.
-    print $cgi-&gt;header();
</del><span class="cx"> 
</span><del>-    # Generate and return the UI (HTML page) from the appropriate template.
</del><span class="cx">     $template-&gt;process(&quot;admin/flag-type/confirm-delete.html.tmpl&quot;, $vars)
</span><span class="cx">       || ThrowTemplateError($template-&gt;error());
</span><ins>+    exit;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-
-sub deleteType {
-    my $token = shift;
</del><ins>+if ($action eq 'delete') {
</ins><span class="cx">     check_token_data($token, 'delete_flagtype');
</span><del>-    my $flag_type = validateID();
-    my $id = $flag_type-&gt;id;
-    my $dbh = Bugzilla-&gt;dbh;
</del><span class="cx"> 
</span><del>-    $dbh-&gt;bz_start_transaction();
</del><ins>+    my ($flagtype, $can_fully_edit) = $user-&gt;check_can_admin_flagtype($flag_id);
+    ThrowUserError('flag_type_cannot_delete', { flagtype =&gt; $flagtype }) unless $can_fully_edit;
</ins><span class="cx"> 
</span><del>-    # Get the name of the flag type so we can tell users
-    # what was deleted.
-    $vars-&gt;{'name'} = $flag_type-&gt;name;
</del><ins>+    $flagtype-&gt;remove_from_db();
</ins><span class="cx"> 
</span><del>-    $dbh-&gt;do('DELETE FROM flags WHERE type_id = ?', undef, $id);
-    $dbh-&gt;do('DELETE FROM flaginclusions WHERE type_id = ?', undef, $id);
-    $dbh-&gt;do('DELETE FROM flagexclusions WHERE type_id = ?', undef, $id);
-    $dbh-&gt;do('DELETE FROM flagtypes WHERE id = ?', undef, $id);
-    $dbh-&gt;bz_commit_transaction();
</del><ins>+    delete_token($token);
</ins><span class="cx"> 
</span><ins>+    $vars-&gt;{'name'} = $flagtype-&gt;name;
</ins><span class="cx">     $vars-&gt;{'message'} = &quot;flag_type_deleted&quot;;
</span><del>-    delete_token($token);
</del><span class="cx"> 
</span><del>-    $vars-&gt;{'bug_types'} = Bugzilla::FlagType::match({'target_type' =&gt; 'bug'});
-    $vars-&gt;{'attachment_types'} = Bugzilla::FlagType::match({'target_type' =&gt; 'attachment'});
</del><ins>+    my @flagtypes = Bugzilla::FlagType-&gt;get_all;
+    $vars-&gt;{'bug_types'} = [grep { $_-&gt;target_type eq 'bug' } @flagtypes];
+    $vars-&gt;{'attachment_types'} = [grep { $_-&gt;target_type eq 'attachment' } @flagtypes];
</ins><span class="cx"> 
</span><del>-    # Return the appropriate HTTP response headers.
-    print $cgi-&gt;header();
-
</del><span class="cx">     $template-&gt;process(&quot;admin/flag-type/list.html.tmpl&quot;, $vars)
</span><span class="cx">       || ThrowTemplateError($template-&gt;error());
</span><ins>+    exit;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-
-sub deactivate {
-    my $token = shift;
</del><ins>+if ($action eq 'deactivate') {
</ins><span class="cx">     check_token_data($token, 'delete_flagtype');
</span><del>-    my $flag_type = validateID();
-    validateIsActive();
</del><span class="cx"> 
</span><del>-    my $dbh = Bugzilla-&gt;dbh;
</del><ins>+    my ($flagtype, $can_fully_edit) = $user-&gt;check_can_admin_flagtype($flag_id);
+    ThrowUserError('flag_type_cannot_deactivate', { flagtype =&gt; $flagtype }) unless $can_fully_edit;
</ins><span class="cx"> 
</span><del>-    $dbh-&gt;bz_start_transaction();
-    $dbh-&gt;do('UPDATE flagtypes SET is_active = 0 WHERE id = ?', undef, $flag_type-&gt;id);
-    $dbh-&gt;bz_commit_transaction();
</del><ins>+    $flagtype-&gt;set_is_active(0);
+    $flagtype-&gt;update();
</ins><span class="cx"> 
</span><del>-    $vars-&gt;{'message'} = &quot;flag_type_deactivated&quot;;
-    $vars-&gt;{'flag_type'} = $flag_type;
</del><span class="cx">     delete_token($token);
</span><span class="cx"> 
</span><del>-    $vars-&gt;{'bug_types'} = Bugzilla::FlagType::match({'target_type' =&gt; 'bug'});
-    $vars-&gt;{'attachment_types'} = Bugzilla::FlagType::match({'target_type' =&gt; 'attachment'});
</del><ins>+    $vars-&gt;{'message'} = &quot;flag_type_deactivated&quot;;
+    $vars-&gt;{'flag_type'} = $flagtype;
</ins><span class="cx"> 
</span><del>-    # Return the appropriate HTTP response headers.
-    print $cgi-&gt;header();
</del><ins>+    my @flagtypes = Bugzilla::FlagType-&gt;get_all;
+    $vars-&gt;{'bug_types'} = [grep { $_-&gt;target_type eq 'bug' } @flagtypes];
+    $vars-&gt;{'attachment_types'} = [grep { $_-&gt;target_type eq 'attachment' } @flagtypes];
</ins><span class="cx"> 
</span><del>-    # Generate and return the UI (HTML page) from the appropriate template.
</del><span class="cx">     $template-&gt;process(&quot;admin/flag-type/list.html.tmpl&quot;, $vars)
</span><span class="cx">       || ThrowTemplateError($template-&gt;error());
</span><ins>+    exit;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+ThrowUserError('unknown_action', {action =&gt; $action});
+
+#####################
+# Helper subroutines
+#####################
+
</ins><span class="cx"> sub get_products_and_components {
</span><del>-    my $vars = shift;
</del><ins>+    my $vars = {};
+    my $user = Bugzilla-&gt;user;
</ins><span class="cx"> 
</span><del>-    my @products = Bugzilla::Product-&gt;get_all;
</del><ins>+    my @products;
+    if ($user-&gt;in_group('editcomponents')) {
+        @products = Bugzilla::Product-&gt;get_all;
+    }
+    else {
+        @products = @{$user-&gt;get_products_by_permission('editcomponents')};
+    }
</ins><span class="cx">     # We require all unique component names.
</span><span class="cx">     my %components;
</span><span class="cx">     foreach my $product (@products) {
</span><span class="lines">@@ -534,171 +467,80 @@
</span><span class="cx">     return $vars;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-################################################################################
-# Data Validation / Security Authorization
-################################################################################
</del><ins>+sub get_editable_flagtypes {
+    my ($products, $group_id) = @_;
+    my $flagtypes;
</ins><span class="cx"> 
</span><del>-sub validateID {
-    my $id = $cgi-&gt;param('id');
-    my $flag_type = new Bugzilla::FlagType($id)
-        || ThrowCodeError('flag_type_nonexistent', { id =&gt; $id });
</del><ins>+    if (Bugzilla-&gt;user-&gt;in_group('editcomponents')) {
+        $flagtypes = Bugzilla::FlagType::match({ group =&gt; $group_id });
+        return $flagtypes;
+    }
</ins><span class="cx"> 
</span><del>-    return $flag_type;
-}
-
-sub validateName {
-    my $name = $cgi-&gt;param('name');
-    ($name &amp;&amp; $name !~ /[ ,]/ &amp;&amp; length($name) &lt;= 50)
-      || ThrowUserError(&quot;flag_type_name_invalid&quot;,
-                        { name =&gt; $name });
-    trick_taint($name);
-    return $name;
-}
-
-sub validateDescription {
-    my $description = $cgi-&gt;param('description');
-    length($description) &lt; 2**16-1
-      || ThrowUserError(&quot;flag_type_description_invalid&quot;);
-    trick_taint($description);
-    return $description;
-}
-
-sub validateCCList {
-    my $cc_list = $cgi-&gt;param('cc_list');
-    length($cc_list) &lt;= 200
-      || ThrowUserError(&quot;flag_type_cc_list_invalid&quot;, 
-                        { cc_list =&gt; $cc_list });
-
-    my @addresses = split(/[, ]+/, $cc_list);
-    # We do not call Util::validate_email_syntax because these
-    # addresses do not require to match 'emailregexp' and do not
-    # depend on 'emailsuffix'. So we limit ourselves to a simple
-    # sanity check:
-    # - match the syntax of a fully qualified email address;
-    # - do not contain any illegal character.
-    foreach my $address (@addresses) {
-        ($address =~ /^[\w\.\+\-=]+@[\w\.\-]+\.[\w\-]+$/
-           &amp;&amp; $address !~ /[\\\(\)&lt;&gt;&amp;,;:&quot;\[\] \t\r\n]/)
-          || ThrowUserError('illegal_email_address',
-                            {addr =&gt; $address, default =&gt; 1});
</del><ins>+    my %visible_flagtypes;
+    foreach my $product (@$products) {
+        foreach my $target ('bug', 'attachment') {
+            my $prod_flagtypes = $product-&gt;flag_types-&gt;{$target};
+            $visible_flagtypes{$_-&gt;id} ||= $_ foreach @$prod_flagtypes;
+        }
</ins><span class="cx">     }
</span><del>-    trick_taint($cc_list);
-    return $cc_list;
</del><ins>+    @$flagtypes = sort { $a-&gt;sortkey &lt;=&gt; $b-&gt;sortkey || $a-&gt;name cmp $b-&gt;name }
+                    values %visible_flagtypes;
+    # Filter flag types if a group ID is given.
+    $flagtypes = filter_group($flagtypes, $group_id);
+    return $flagtypes;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub validateProduct {
-    my $product_name = shift;
-    return unless $product_name;
-
-    my $product = Bugzilla::Product::check_product($product_name);
-    return $product;
</del><ins>+sub get_settable_groups {
+    my $user = Bugzilla-&gt;user;
+    my $groups = $user-&gt;in_group('editcomponents') ? [Bugzilla::Group-&gt;get_all] : $user-&gt;groups;
+    return $groups;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub validateComponent {
-    my ($product, $component_name) = @_;
-    return unless $component_name;
</del><ins>+sub filter_group {
+    my ($flag_types, $gid) = @_;
+    return $flag_types unless $gid;
</ins><span class="cx"> 
</span><del>-    ($product &amp;&amp; $product-&gt;id)
-      || ThrowUserError(&quot;flag_type_component_without_product&quot;);
</del><ins>+    my @flag_types = grep {($_-&gt;grant_group &amp;&amp; $_-&gt;grant_group-&gt;id == $gid)
+                           || ($_-&gt;request_group &amp;&amp; $_-&gt;request_group-&gt;id == $gid)} @$flag_types;
</ins><span class="cx"> 
</span><del>-    my $component = Bugzilla::Component-&gt;check({ product =&gt; $product,
-                                                 name =&gt; $component_name });
-    return $component;
</del><ins>+    return \@flag_types;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub validateSortKey {
-    # $sortkey is destroyed if detaint_natural fails.
-    my $sortkey = $cgi-&gt;param('sortkey');
-    detaint_natural($sortkey)
-      &amp;&amp; $sortkey &lt; 32768
-      || ThrowUserError(&quot;flag_type_sortkey_invalid&quot;, 
-                        { sortkey =&gt; scalar $cgi-&gt;param('sortkey') });
-    $cgi-&gt;param('sortkey', $sortkey);
-}
</del><ins>+# Convert the array @clusions('prod_ID:comp_ID') back to a hash of
+# the form %clusions{'prod_name:comp_name'} = 'prod_ID:comp_ID'
+sub clusion_array_to_hash {
+    my ($array, $visible_products) = @_;
+    my $user = Bugzilla-&gt;user;
+    my $has_privs = $user-&gt;in_group('editcomponents');
</ins><span class="cx"> 
</span><del>-sub validateTargetType {
-    grep($cgi-&gt;param('target_type') eq $_, (&quot;bug&quot;, &quot;attachment&quot;))
-      || ThrowCodeError(&quot;flag_type_target_type_invalid&quot;, 
-                        { target_type =&gt; scalar $cgi-&gt;param('target_type') });
-}
</del><ins>+    my %hash;
+    my %products;
+    my %components;
</ins><span class="cx"> 
</span><del>-sub validateIsActive {
-    $cgi-&gt;param('is_active', $cgi-&gt;param('is_active') ? 1 : 0);
-}
</del><ins>+    foreach my $ids (@$array) {
+        my ($product_id, $component_id) = split(&quot;:&quot;, $ids);
+        my $product_name = &quot;__Any__&quot;;
+        my $component_name = &quot;__Any__&quot;;
</ins><span class="cx"> 
</span><del>-sub validateIsRequestable {
-    $cgi-&gt;param('is_requestable', $cgi-&gt;param('is_requestable') ? 1 : 0);
-}
</del><ins>+        if ($product_id) {
+            ($products{$product_id}) = grep { $_-&gt;id == $product_id } @$visible_products;
+            next unless $products{$product_id};
+            $product_name = $products{$product_id}-&gt;name;
</ins><span class="cx"> 
</span><del>-sub validateIsRequesteeble {
-    $cgi-&gt;param('is_requesteeble', $cgi-&gt;param('is_requesteeble') ? 1 : 0);
-}
-
-sub validateAllowMultiple {
-    $cgi-&gt;param('is_multiplicable', $cgi-&gt;param('is_multiplicable') ? 1 : 0);
-}
-
-sub validateGroups {
-    my $dbh = Bugzilla-&gt;dbh;
-    # Convert group names to group IDs
-    foreach my $col ('grant', 'request') {
-        my $name = $cgi-&gt;param($col . '_group');
-        if ($name) {
-            trick_taint($name);
-            my $gid = $dbh-&gt;selectrow_array('SELECT id FROM groups
-                                             WHERE name = ?', undef, $name);
-            $gid || ThrowUserError(&quot;group_unknown&quot;, { name =&gt; $name });
-            $cgi-&gt;param($col . '_gid', $gid);
-        }
-    }
-}
-
-# At this point, values either come the DB itself or have been recently
-# added by the user and have passed all validation tests.
-# The only way to have invalid product/component combinations is to
-# hack the URL. So we silently ignore them, if any.
-sub validateAndSubmit {
-    my ($id) = @_;
-    my $dbh = Bugzilla-&gt;dbh;
-
-    # Cache product objects.
-    my %products;
-    foreach my $category_type (&quot;inclusions&quot;, &quot;exclusions&quot;) {
-        # Will be used several times below.
-        my $sth = $dbh-&gt;prepare(&quot;INSERT INTO flag$category_type &quot; .
-                                &quot;(type_id, product_id, component_id) &quot; .
-                                &quot;VALUES (?, ?, ?)&quot;);
-
-        $dbh-&gt;do(&quot;DELETE FROM flag$category_type WHERE type_id = ?&quot;, undef, $id);
-        foreach my $category ($cgi-&gt;param($category_type)) {
-            trick_taint($category);
-            my ($product_id, $component_id) = split(&quot;:&quot;, $category);
-            # Does the product exist?
-            if ($product_id) {
-                $products{$product_id} ||= new Bugzilla::Product($product_id);
-                next unless defined $products{$product_id};
-            }
-            # A component was selected without a product being selected.
-            next if (!$product_id &amp;&amp; $component_id);
-            # Does the component belong to this product?
</del><span class="cx">             if ($component_id) {
</span><del>-                my @match = grep {$_-&gt;id == $component_id} @{$products{$product_id}-&gt;components};
-                next unless scalar(@match);
</del><ins>+                ($components{$component_id}) =
+                  grep { $_-&gt;id == $component_id } @{$products{$product_id}-&gt;components};
+                next unless $components{$component_id};
+                $component_name = $components{$component_id}-&gt;name;
</ins><span class="cx">             }
</span><del>-            $product_id ||= undef;
-            $component_id ||= undef;
-            $sth-&gt;execute($id, $product_id, $component_id);
</del><span class="cx">         }
</span><ins>+        else {
+            # Users with local editcomponents privs cannot use __Any__:__Any__.
+            next unless $has_privs;
+            # It's illegal to select a component without a product.
+            next if $component_id;
+        }
+        $hash{&quot;$product_name:$component_name&quot;} = $ids;
</ins><span class="cx">     }
</span><ins>+    return \%hash;
</ins><span class="cx"> }
</span><del>-
-sub filter_group {
-    my $flag_types = shift;
-    return $flag_types unless Bugzilla-&gt;cgi-&gt;param('group');
-
-    my $gid = scalar $cgi-&gt;param('group');
-    my @flag_types = grep {($_-&gt;grant_group &amp;&amp; $_-&gt;grant_group-&gt;id == $gid)
-                           || ($_-&gt;request_group &amp;&amp; $_-&gt;request_group-&gt;id == $gid)} @$flag_types;
-
-    return \@flag_types;
-}
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgeditgroupscgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/editgroups.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/editgroups.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/editgroups.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -72,41 +72,6 @@
</span><span class="cx">     return $group_id;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-# This subroutine is called when:
-# - a new group is created. CheckGroupName checks that its name
-#   is not empty and is not already used by any existing group.
-# - an existing group is edited. CheckGroupName checks that its
-#   name has not been deleted or renamed to another existing
-#   group name (whose group ID is different from $group_id).
-# In both cases, an error message is returned to the user if any
-# test fails! Else, the trimmed group name is returned.
-
-sub CheckGroupName {
-    my ($name, $group_id) = @_;
-    $name = trim($name || '');
-    trick_taint($name);
-    ThrowUserError(&quot;empty_group_name&quot;) unless $name;
-    my $excludeself = (defined $group_id) ? &quot; AND id != $group_id&quot; : &quot;&quot;;
-    my $name_exists = Bugzilla-&gt;dbh-&gt;selectrow_array(&quot;SELECT name FROM groups &quot; .
-                                                     &quot;WHERE name = ? $excludeself&quot;,
-                                                     undef, $name);
-    if ($name_exists) {
-        ThrowUserError(&quot;group_exists&quot;, { name =&gt; $name });
-    }
-    return $name;
-}
-
-# CheckGroupDesc checks that a non empty description is given. The
-# trimmed description is returned.
-
-sub CheckGroupDesc {
-    my ($desc) = @_;
-    $desc = trim($desc || '');
-    trick_taint($desc);
-    ThrowUserError(&quot;empty_group_description&quot;) unless $desc;
-    return $desc;
-}
-
</del><span class="cx"> # CheckGroupRegexp checks that the regular expression is valid
</span><span class="cx"> # (the regular expression being optional, the test is successful
</span><span class="cx"> # if none is given, as expected). The trimmed regular expression
</span><span class="lines">@@ -148,16 +113,19 @@
</span><span class="cx">                 if !grep($_-&gt;id == $group_option-&gt;id, @visible_to_me_current);
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        # The group itself should never show up in the bless or 
-        # membership lists.
</del><ins>+        push(@bless_from_available, $group_option)
+            if !grep($_-&gt;id == $group_option-&gt;id, @bless_from_current);
+
+        # The group itself should never show up in the membership lists,
+        # and should show up in only one of the bless lists (otherwise
+        # you can try to allow it to bless itself twice, leading to a
+        # database unique constraint error).
</ins><span class="cx">         next if $group_option-&gt;id == $group-&gt;id;
</span><span class="cx"> 
</span><span class="cx">         push(@members_available, $group_option)
</span><span class="cx">             if !grep($_-&gt;id == $group_option-&gt;id, @members_current);
</span><span class="cx">         push(@member_of_available, $group_option)
</span><span class="cx">             if !grep($_-&gt;id == $group_option-&gt;id, @member_of_current);
</span><del>-        push(@bless_from_available, $group_option)
-            if !grep($_-&gt;id == $group_option-&gt;id, @bless_from_current);
</del><span class="cx">         push(@bless_to_available, $group_option)
</span><span class="cx">            if !grep($_-&gt;id == $group_option-&gt;id, @bless_to_current);
</span><span class="cx">     }
</span><span class="lines">@@ -237,47 +205,22 @@
</span><span class="cx"> 
</span><span class="cx"> if ($action eq 'new') {
</span><span class="cx">     check_token_data($token, 'add_group');
</span><del>-    # Check that a not already used group name is given, that
-    # a description is also given and check if the regular
-    # expression is valid (if any).
-    my $name = CheckGroupName($cgi-&gt;param('name'));
-    my $desc = CheckGroupDesc($cgi-&gt;param('desc'));
-    my $regexp = CheckGroupRegexp($cgi-&gt;param('regexp'));
-    my $isactive = $cgi-&gt;param('isactive') ? 1 : 0;
-    # This is an admin page. The URL is considered safe.
-    my $icon_url;
-    if ($cgi-&gt;param('icon_url')) {
-        $icon_url = clean_text($cgi-&gt;param('icon_url'));
-        trick_taint($icon_url);
-    }
</del><ins>+    my $group = Bugzilla::Group-&gt;create({
+        name        =&gt; scalar $cgi-&gt;param('name'),
+        description =&gt; scalar $cgi-&gt;param('desc'),
+        userregexp  =&gt; scalar $cgi-&gt;param('regexp'),
+        isactive    =&gt; scalar $cgi-&gt;param('isactive'),
+        icon_url    =&gt; scalar $cgi-&gt;param('icon_url'),
+        isbuggroup  =&gt; 1,
+    });
</ins><span class="cx"> 
</span><del>-    # Add the new group
-    $dbh-&gt;do('INSERT INTO groups
-              (name, description, isbuggroup, userregexp, isactive, icon_url)
-              VALUES (?, ?, 1, ?, ?, ?)',
-              undef, ($name, $desc, $regexp, $isactive, $icon_url));
-
-    my $group = new Bugzilla::Group({name =&gt; $name});
-    my $admin = Bugzilla::Group-&gt;new({name =&gt; 'admin'})-&gt;id();
-    # Since we created a new group, give the &quot;admin&quot; group all privileges
-    # initially.
-    my $sth = $dbh-&gt;prepare('INSERT INTO group_group_map
-                             (member_id, grantor_id, grant_type)
-                             VALUES (?, ?, ?)');
-
-    $sth-&gt;execute($admin, $group-&gt;id, GROUP_MEMBERSHIP);
-    $sth-&gt;execute($admin, $group-&gt;id, GROUP_BLESS);
-    $sth-&gt;execute($admin, $group-&gt;id, GROUP_VISIBLE);
-
</del><span class="cx">     # Permit all existing products to use the new group if makeproductgroups.
</span><span class="cx">     if ($cgi-&gt;param('insertnew')) {
</span><span class="cx">         $dbh-&gt;do('INSERT INTO group_control_map
</span><del>-                  (group_id, product_id, entry, membercontrol,
-                   othercontrol, canedit)
-                  SELECT ?, products.id, 0, ?, ?, 0 FROM products',
</del><ins>+                  (group_id, product_id, membercontrol, othercontrol)
+                  SELECT ?, products.id, ?, ? FROM products',
</ins><span class="cx">                   undef, ($group-&gt;id, CONTROLMAPSHOWN, CONTROLMAPNA));
</span><span class="cx">     }
</span><del>-    Bugzilla::Group::RederiveRegexp($regexp, $group-&gt;id);
</del><span class="cx">     delete_token($token);
</span><span class="cx"> 
</span><span class="cx">     $vars-&gt;{'message'} = 'group_created';
</span><span class="lines">@@ -299,65 +242,16 @@
</span><span class="cx"> 
</span><span class="cx"> if ($action eq 'del') {
</span><span class="cx">     # Check that an existing group ID is given
</span><del>-    my $gid = CheckGroupID($cgi-&gt;param('group'));
-    my ($name, $desc, $isbuggroup) =
-        $dbh-&gt;selectrow_array(&quot;SELECT name, description, isbuggroup &quot; .
-                              &quot;FROM groups WHERE id = ?&quot;, undef, $gid);
-
-    # System groups cannot be deleted!
-    if (!$isbuggroup) {
-        ThrowUserError(&quot;system_group_not_deletable&quot;, { name =&gt; $name });
-    }
-    # Groups having a special role cannot be deleted.
-    my @special_groups;
-    foreach my $special_group (SPECIAL_GROUPS) {
-        if ($name eq Bugzilla-&gt;params-&gt;{$special_group}) {
-            push(@special_groups, $special_group);
-        }
-    }
-    if (scalar(@special_groups)) {
-        ThrowUserError('group_has_special_role', {'name'  =&gt; $name,
-                                                  'groups' =&gt; \@special_groups});
-    }
-
-    # Group inheritance no longer appears in user_group_map.
-    my $grouplist = join(',', @{Bugzilla::User-&gt;flatten_group_membership($gid)});
-    my $hasusers =
-        $dbh-&gt;selectrow_array(&quot;SELECT 1 FROM user_group_map
-                               WHERE group_id IN ($grouplist) AND isbless = 0 &quot; .
-                               $dbh-&gt;sql_limit(1)) || 0;
-
-    my ($shared_queries) =
</del><ins>+    my $group = Bugzilla::Group-&gt;check({ id =&gt; $cgi-&gt;param('group') });
+    $group-&gt;check_remove({ test_only =&gt; 1 });
+    $vars-&gt;{'shared_queries'} =
</ins><span class="cx">         $dbh-&gt;selectrow_array('SELECT COUNT(*)
</span><span class="cx">                                  FROM namedquery_group_map
</span><del>-                                WHERE group_id = ?',
-                              undef, $gid);
</del><ins>+                                WHERE group_id = ?', undef, $group-&gt;id);
</ins><span class="cx"> 
</span><del>-    my $bug_ids = $dbh-&gt;selectcol_arrayref('SELECT bug_id FROM bug_group_map
-                                            WHERE group_id = ?', undef, $gid);
</del><ins>+    $vars-&gt;{'group'} = $group;
+    $vars-&gt;{'token'} = issue_session_token('delete_group');
</ins><span class="cx"> 
</span><del>-    my $hasbugs = scalar(@$bug_ids) ? 1 : 0;
-    my $buglist = join(',', @$bug_ids);
-
-    my $hasproduct = Bugzilla::Product-&gt;new({'name' =&gt; $name}) ? 1 : 0;
-
-    my $hasflags = $dbh-&gt;selectrow_array('SELECT 1 FROM flagtypes 
-                                           WHERE grant_group_id = ?
-                                              OR request_group_id = ? ' .
-                                          $dbh-&gt;sql_limit(1),
-                                          undef, ($gid, $gid)) || 0;
-
-    $vars-&gt;{'gid'}            = $gid;
-    $vars-&gt;{'name'}           = $name;
-    $vars-&gt;{'description'}    = $desc;
-    $vars-&gt;{'hasusers'}       = $hasusers;
-    $vars-&gt;{'hasbugs'}        = $hasbugs;
-    $vars-&gt;{'hasproduct'}     = $hasproduct;
-    $vars-&gt;{'hasflags'}       = $hasflags;
-    $vars-&gt;{'shared_queries'} = $shared_queries;
-    $vars-&gt;{'buglist'}        = $buglist;
-    $vars-&gt;{'token'}          = issue_session_token('delete_group');
-
</del><span class="cx">     print $cgi-&gt;header();
</span><span class="cx">     $template-&gt;process(&quot;admin/groups/delete.html.tmpl&quot;, $vars)
</span><span class="cx">       || ThrowTemplateError($template-&gt;error());
</span><span class="lines">@@ -372,91 +266,14 @@
</span><span class="cx"> if ($action eq 'delete') {
</span><span class="cx">     check_token_data($token, 'delete_group');
</span><span class="cx">     # Check that an existing group ID is given
</span><del>-    my $gid = CheckGroupID($cgi-&gt;param('group'));
-    my ($name, $isbuggroup) =
-        $dbh-&gt;selectrow_array(&quot;SELECT name, isbuggroup FROM groups &quot; .
-                              &quot;WHERE id = ?&quot;, undef, $gid);
-
-    # System groups cannot be deleted!
-    if (!$isbuggroup) {
-        ThrowUserError(&quot;system_group_not_deletable&quot;, { name =&gt; $name });
-    }
-    # Groups having a special role cannot be deleted.
-    my @special_groups;
-    foreach my $special_group (SPECIAL_GROUPS) {
-        if ($name eq Bugzilla-&gt;params-&gt;{$special_group}) {
-            push(@special_groups, $special_group);
-        }
-    }
-    if (scalar(@special_groups)) {
-        ThrowUserError('group_has_special_role', {'name'  =&gt; $name,
-                                                  'groups' =&gt; \@special_groups});
-    }
-
-    my $cantdelete = 0;
-
-    # Group inheritance no longer appears in user_group_map.
-    my $grouplist = join(',', @{Bugzilla::User-&gt;flatten_group_membership($gid)});
-    my $hasusers =
-        $dbh-&gt;selectrow_array(&quot;SELECT 1 FROM user_group_map
-                               WHERE group_id IN ($grouplist) AND isbless = 0 &quot; .
-                               $dbh-&gt;sql_limit(1)) || 0;
-
-    if ($hasusers &amp;&amp; !defined $cgi-&gt;param('removeusers')) {
-        $cantdelete = 1;
-    }
-
-    my $hasbugs = $dbh-&gt;selectrow_array('SELECT 1 FROM bug_group_map
-                                         WHERE group_id = ? ' .
-                                         $dbh-&gt;sql_limit(1),
-                                         undef, $gid) || 0;
-    if ($hasbugs &amp;&amp; !defined $cgi-&gt;param('removebugs')) {
-        $cantdelete = 1;
-    }
-
-    if (Bugzilla::Product-&gt;new({'name' =&gt; $name})
-        &amp;&amp; !defined $cgi-&gt;param('unbind'))
-    {
-        $cantdelete = 1;
-    }
-
-    my $hasflags = $dbh-&gt;selectrow_array('SELECT 1 FROM flagtypes 
-                                           WHERE grant_group_id = ?
-                                              OR request_group_id = ? ' .
-                                          $dbh-&gt;sql_limit(1),
-                                          undef, ($gid, $gid)) || 0;
-    if ($hasflags &amp;&amp; !defined $cgi-&gt;param('removeflags')) {
-        $cantdelete = 1;
-    }
-
-    $vars-&gt;{'gid'}        = $gid;
-    $vars-&gt;{'name'}       = $name;
-
-    ThrowUserError('group_cannot_delete', $vars) if $cantdelete;
-
-    $dbh-&gt;do('UPDATE flagtypes SET grant_group_id = ?
-               WHERE grant_group_id = ?',
-              undef, (undef, $gid));
-    $dbh-&gt;do('UPDATE flagtypes SET request_group_id = ?
-               WHERE request_group_id = ?',
-              undef, (undef, $gid));
-    $dbh-&gt;do('DELETE FROM namedquery_group_map WHERE group_id = ?',
-              undef, $gid);
-    $dbh-&gt;do('DELETE FROM user_group_map WHERE group_id = ?',
-              undef, $gid);
-    $dbh-&gt;do('DELETE FROM group_group_map 
-               WHERE grantor_id = ? OR member_id = ?',
-              undef, ($gid, $gid));
-    $dbh-&gt;do('DELETE FROM bug_group_map WHERE group_id = ?',
-              undef, $gid);
-    $dbh-&gt;do('DELETE FROM group_control_map WHERE group_id = ?',
-              undef, $gid);
-    $dbh-&gt;do('DELETE FROM whine_schedules
-               WHERE mailto_type = ? AND mailto = ?',
-              undef, (MAILTO_GROUP, $gid));
-    $dbh-&gt;do('DELETE FROM groups WHERE id = ?',
-              undef, $gid);
-
</del><ins>+    my $group = Bugzilla::Group-&gt;check({ id =&gt; $cgi-&gt;param('group') });
+    $vars-&gt;{'name'} = $group-&gt;name;
+    $group-&gt;remove_from_db({
+        remove_from_users =&gt; scalar $cgi-&gt;param('removeusers'),
+        remove_from_bugs  =&gt; scalar $cgi-&gt;param('removebugs'),
+        remove_from_flags =&gt; scalar $cgi-&gt;param('removeflags'),
+        remove_from_products =&gt; scalar $cgi-&gt;param('unbind'),
+    });
</ins><span class="cx">     delete_token($token);
</span><span class="cx"> 
</span><span class="cx">     $vars-&gt;{'message'} = 'group_deleted';
</span><span class="lines">@@ -540,14 +357,9 @@
</span><span class="cx">     exit;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-
-#
</del><span class="cx"> # No valid action found
</span><del>-#
</del><ins>+ThrowUserError('unknown_action', {action =&gt; $action});
</ins><span class="cx"> 
</span><del>-ThrowCodeError(&quot;action_unrecognized&quot;, $vars);
-
-
</del><span class="cx"> # Helper sub to handle the making of changes to a group
</span><span class="cx"> sub doGroupChanges {
</span><span class="cx">     my $cgi = Bugzilla-&gt;cgi;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgeditkeywordscgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/editkeywords.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/editkeywords.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/editkeywords.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -131,8 +131,10 @@
</span><span class="cx">     my $keyword = new Bugzilla::Keyword($key_id)
</span><span class="cx">         || ThrowCodeError('invalid_keyword_id', { id =&gt; $key_id });
</span><span class="cx"> 
</span><del>-    $keyword-&gt;set_name($cgi-&gt;param('name'));
-    $keyword-&gt;set_description($cgi-&gt;param('description'));
</del><ins>+    $keyword-&gt;set_all({
+        name        =&gt; scalar $cgi-&gt;param('name'),
+        description =&gt; scalar $cgi-&gt;param('description'),
+    });
</ins><span class="cx">     my $changes = $keyword-&gt;update();
</span><span class="cx"> 
</span><span class="cx">     delete_token($token);
</span><span class="lines">@@ -167,14 +169,14 @@
</span><span class="cx">     my $keyword =  new Bugzilla::Keyword($key_id)
</span><span class="cx">         || ThrowCodeError('invalid_keyword_id', { id =&gt; $key_id });
</span><span class="cx"> 
</span><del>-    $dbh-&gt;do('DELETE FROM keywords WHERE keywordid = ?', undef, $keyword-&gt;id);
-    $dbh-&gt;do('DELETE FROM keyworddefs WHERE id = ?', undef, $keyword-&gt;id);
</del><ins>+    $keyword-&gt;remove_from_db();
</ins><span class="cx"> 
</span><span class="cx">     delete_token($token);
</span><span class="cx"> 
</span><span class="cx">     print $cgi-&gt;header();
</span><span class="cx"> 
</span><span class="cx">     $vars-&gt;{'message'} = 'keyword_deleted';
</span><ins>+    $vars-&gt;{'keyword'} = $keyword;
</ins><span class="cx">     $vars-&gt;{'keywords'} = Bugzilla::Keyword-&gt;get_all_with_bug_count();
</span><span class="cx"> 
</span><span class="cx">     $template-&gt;process(&quot;admin/keywords/list.html.tmpl&quot;, $vars)
</span><span class="lines">@@ -182,4 +184,4 @@
</span><span class="cx">     exit;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-ThrowCodeError(&quot;action_unrecognized&quot;, $vars);
</del><ins>+ThrowUserError('unknown_action', {action =&gt; $action});
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgeditmilestonescgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/editmilestones.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/editmilestones.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/editmilestones.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -60,6 +60,7 @@
</span><span class="cx"> my $action         = trim($cgi-&gt;param('action')      || '');
</span><span class="cx"> my $showbugcounts = (defined $cgi-&gt;param('showbugcounts'));
</span><span class="cx"> my $token          = $cgi-&gt;param('token');
</span><ins>+my $isactive       = $cgi-&gt;param('isactive');
</ins><span class="cx"> 
</span><span class="cx"> #
</span><span class="cx"> # product = '' -&gt; Show nice list of products
</span><span class="lines">@@ -115,9 +116,11 @@
</span><span class="cx"> 
</span><span class="cx"> if ($action eq 'new') {
</span><span class="cx">     check_token_data($token, 'add_milestone');
</span><del>-    my $milestone = Bugzilla::Milestone-&gt;create({ name    =&gt; $milestone_name,
-                                                  product =&gt; $product,
-                                                  sortkey =&gt; $sortkey });
</del><ins>+
+    my $milestone = Bugzilla::Milestone-&gt;create({ value    =&gt; $milestone_name,
+                                                  product  =&gt; $product,
+                                                  sortkey  =&gt; $sortkey });
+
</ins><span class="cx">     delete_token($token);
</span><span class="cx"> 
</span><span class="cx">     $vars-&gt;{'message'} = 'milestone_created';
</span><span class="lines">@@ -205,7 +208,11 @@
</span><span class="cx"> 
</span><span class="cx">     $milestone-&gt;set_name($milestone_name);
</span><span class="cx">     $milestone-&gt;set_sortkey($sortkey);
</span><ins>+    $milestone-&gt;set_is_active($isactive);
</ins><span class="cx">     my $changes = $milestone-&gt;update();
</span><ins>+    # Reloading the product since the default milestone name
+    # could have been changed.
+    $product = new Bugzilla::Product({ name =&gt; $product_name });
</ins><span class="cx"> 
</span><span class="cx">     delete_token($token);
</span><span class="cx"> 
</span><span class="lines">@@ -218,7 +225,5 @@
</span><span class="cx">     exit;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-#
</del><span class="cx"> # No valid action found
</span><del>-#
-ThrowUserError('no_valid_action', {'field' =&gt; &quot;target_milestone&quot;});
</del><ins>+ThrowUserError('unknown_action', {action =&gt; $action});
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgeditparamscgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/editparams.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/editparams.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/editparams.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -67,22 +67,28 @@
</span><span class="cx">                  param_list =&gt; \@module_param_list,
</span><span class="cx">                  sortkey =&gt; eval &quot;\$${module}::sortkey;&quot;
</span><span class="cx">                };
</span><ins>+    defined($item-&gt;{'sortkey'}) || ($item-&gt;{'sortkey'} = 100000);
</ins><span class="cx">     push(@panels, $item);
</span><span class="cx">     $current_module = $panel if ($current_panel eq lc($panel));
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+my %hook_panels = map { $_-&gt;{name} =&gt; { params =&gt; $_-&gt;{param_list} } }
+                      @panels;
+# Note that this hook is also called in Bugzilla::Config.
+Bugzilla::Hook::process('config_modify_panels', { panels =&gt; \%hook_panels });
+
</ins><span class="cx"> $vars-&gt;{panels} = \@panels;
</span><span class="cx"> 
</span><span class="cx"> if ($action eq 'save' &amp;&amp; $current_module) {
</span><span class="cx">     check_token_data($token, 'edit_parameters');
</span><span class="cx">     my @changes = ();
</span><del>-    my @module_param_list = &quot;$param_panels-&gt;{$current_module}&quot;-&gt;get_param_list();
</del><ins>+    my @module_param_list = @{ $hook_panels{lc($current_module)}-&gt;{params} };
</ins><span class="cx"> 
</span><span class="cx">     foreach my $i (@module_param_list) {
</span><span class="cx">         my $name = $i-&gt;{'name'};
</span><span class="cx">         my $value = $cgi-&gt;param($name);
</span><span class="cx"> 
</span><del>-        if (defined $cgi-&gt;param(&quot;reset-$name&quot;)) {
</del><ins>+        if (defined $cgi-&gt;param(&quot;reset-$name&quot;) &amp;&amp; !$i-&gt;{'no_reset'}) {
</ins><span class="cx">             $value = $i-&gt;{'default'};
</span><span class="cx">         } else {
</span><span class="cx">             if ($i-&gt;{'type'} eq 'm') {
</span><span class="lines">@@ -94,6 +100,11 @@
</span><span class="cx">                 # assume single linefeed is an empty string
</span><span class="cx">                 $value =~ s/^\n$//;
</span><span class="cx">             }
</span><ins>+            # Stop complaining if the URL has no trailing slash.
+            # XXX - This hack can go away once bug 303662 is implemented.
+            if ($name =~ /(?&lt;!webdot)base$/) {
+                $value = &quot;$value/&quot; if ($value &amp;&amp; $value !~ m#/$#);
+            }
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         my $changed;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgeditproductscgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/editproducts.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/editproducts.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/editproducts.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -35,17 +35,10 @@
</span><span class="cx"> use Bugzilla::Constants;
</span><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> use Bugzilla::Error;
</span><del>-use Bugzilla::Bug;
-use Bugzilla::Series;
-use Bugzilla::Mailer;
</del><ins>+use Bugzilla::Group;
</ins><span class="cx"> use Bugzilla::Product;
</span><span class="cx"> use Bugzilla::Classification;
</span><del>-use Bugzilla::Milestone;
-use Bugzilla::Group;
-use Bugzilla::User;
-use Bugzilla::Field;
</del><span class="cx"> use Bugzilla::Token;
</span><del>-use Bugzilla::Status;
</del><span class="cx"> 
</span><span class="cx"> #
</span><span class="cx"> # Preliminary checks:
</span><span class="lines">@@ -76,7 +69,6 @@
</span><span class="cx"> my $classification_name = trim($cgi-&gt;param('classification') || '');
</span><span class="cx"> my $product_name = trim($cgi-&gt;param('product') || '');
</span><span class="cx"> my $action  = trim($cgi-&gt;param('action')  || '');
</span><del>-my $showbugcounts = (defined $cgi-&gt;param('showbugcounts'));
</del><span class="cx"> my $token = $cgi-&gt;param('token');
</span><span class="cx"> 
</span><span class="cx"> #
</span><span class="lines">@@ -88,8 +80,18 @@
</span><span class="cx">     &amp;&amp; !$classification_name
</span><span class="cx">     &amp;&amp; !$product_name)
</span><span class="cx"> {
</span><del>-    $vars-&gt;{'classifications'} = $user-&gt;in_group('editcomponents') ?
-      [Bugzilla::Classification::get_all_classifications] : $user-&gt;get_selectable_classifications;
</del><ins>+    my $class;
+    if ($user-&gt;in_group('editcomponents')) {
+        $class = [Bugzilla::Classification-&gt;get_all];
+    }
+    else {
+        # Only keep classifications containing at least one product
+        # which you can administer.
+        my $products = $user-&gt;get_products_by_permission('editcomponents');
+        my %class_ids = map { $_-&gt;classification_id =&gt; 1 } @$products;
+        $class = Bugzilla::Classification-&gt;new_from_list([keys %class_ids]);
+    }
+    $vars-&gt;{'classifications'} = $class;
</ins><span class="cx"> 
</span><span class="cx">     $template-&gt;process(&quot;admin/products/list-classifications.html.tmpl&quot;, $vars)
</span><span class="cx">         || ThrowTemplateError($template-&gt;error());
</span><span class="lines">@@ -107,9 +109,7 @@
</span><span class="cx">     my $products;
</span><span class="cx"> 
</span><span class="cx">     if (Bugzilla-&gt;params-&gt;{'useclassification'}) {
</span><del>-        $classification =
-            Bugzilla::Classification::check_classification($classification_name);
-
</del><ins>+        $classification = Bugzilla::Classification-&gt;check($classification_name);
</ins><span class="cx">         $products = $user-&gt;get_selectable_products($classification-&gt;id);
</span><span class="cx">         $vars-&gt;{'classification'} = $classification;
</span><span class="cx">     } else {
</span><span class="lines">@@ -125,7 +125,7 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     $vars-&gt;{'products'} = $products;
</span><del>-    $vars-&gt;{'showbugcounts'} = $showbugcounts;
</del><ins>+    $vars-&gt;{'showbugcounts'} = $cgi-&gt;param('showbugcounts') ? 1 : 0;
</ins><span class="cx"> 
</span><span class="cx">     $template-&gt;process(&quot;admin/products/list.html.tmpl&quot;, $vars)
</span><span class="cx">       || ThrowTemplateError($template-&gt;error());
</span><span class="lines">@@ -150,8 +150,7 @@
</span><span class="cx">                                          object =&gt; &quot;products&quot;});
</span><span class="cx"> 
</span><span class="cx">     if (Bugzilla-&gt;params-&gt;{'useclassification'}) {
</span><del>-        my $classification = 
-            Bugzilla::Classification::check_classification($classification_name);
</del><ins>+        my $classification = Bugzilla::Classification-&gt;check($classification_name);
</ins><span class="cx">         $vars-&gt;{'classification'} = $classification;
</span><span class="cx">     }
</span><span class="cx">     $vars-&gt;{'token'} = issue_session_token('add_product');
</span><span class="lines">@@ -176,171 +175,26 @@
</span><span class="cx">                                          object =&gt; &quot;products&quot;});
</span><span class="cx"> 
</span><span class="cx">     check_token_data($token, 'add_product');
</span><del>-    # Cleanups and validity checks
</del><span class="cx"> 
</span><del>-    my $classification_id = 1;
-    if (Bugzilla-&gt;params-&gt;{'useclassification'}) {
-        my $classification = 
-            Bugzilla::Classification::check_classification($classification_name);
-        $classification_id = $classification-&gt;id;
-        $vars-&gt;{'classification'} = $classification;
-    }
</del><ins>+    my %create_params = (
+        classification   =&gt; $classification_name,
+        name             =&gt; $product_name,
+        description      =&gt; scalar $cgi-&gt;param('description'),
+        version          =&gt; scalar $cgi-&gt;param('version'),
+        defaultmilestone =&gt; scalar $cgi-&gt;param('defaultmilestone'),
+        isactive         =&gt; scalar $cgi-&gt;param('is_active'),
+        create_series    =&gt; scalar $cgi-&gt;param('createseries'),
+        allows_unconfirmed =&gt; scalar $cgi-&gt;param('allows_unconfirmed'),
+    );
+    my $product = Bugzilla::Product-&gt;create(\%create_params);
</ins><span class="cx"> 
</span><del>-    unless ($product_name) {
-        ThrowUserError(&quot;product_blank_name&quot;);  
-    }
-
-    my $product = new Bugzilla::Product({name =&gt; $product_name});
-
-    if ($product) {
-
-        # Check for exact case sensitive match:
-        if ($product-&gt;name eq $product_name) {
-            ThrowUserError(&quot;product_name_already_in_use&quot;,
-                           {'product' =&gt; $product-&gt;name});
-        }
-
-        # Next check for a case-insensitive match:
-        if (lc($product-&gt;name) eq lc($product_name)) {
-            ThrowUserError(&quot;product_name_diff_in_case&quot;,
-                           {'product' =&gt; $product_name,
-                            'existing_product' =&gt; $product-&gt;name}); 
-        }
-    }
-
-    my $version = trim($cgi-&gt;param('version') || '');
-
-    if ($version eq '') {
-        ThrowUserError(&quot;product_must_have_version&quot;,
-                       {'product' =&gt; $product_name});
-    }
-
-    my $description  = trim($cgi-&gt;param('description')  || '');
-
-    if ($description eq '') {
-        ThrowUserError('product_must_have_description',
-                       {'product' =&gt; $product_name});
-    }
-
-    my $milestoneurl = trim($cgi-&gt;param('milestoneurl') || '');
-    my $disallownew = $cgi-&gt;param('disallownew') ? 1 : 0;
-    my $votesperuser = $cgi-&gt;param('votesperuser') || 0;
-    my $maxvotesperbug = defined($cgi-&gt;param('maxvotesperbug')) ?
-        $cgi-&gt;param('maxvotesperbug') : 10000;
-    my $votestoconfirm = $cgi-&gt;param('votestoconfirm') || 0;
-    my $defaultmilestone = $cgi-&gt;param('defaultmilestone') || &quot;---&quot;;
-
-    # The following variables are used in placeholders only.
-    trick_taint($product_name);
-    trick_taint($version);
-    trick_taint($description);
-    trick_taint($milestoneurl);
-    trick_taint($defaultmilestone);
-    detaint_natural($disallownew);
-    detaint_natural($votesperuser);
-    detaint_natural($maxvotesperbug);
-    detaint_natural($votestoconfirm);
-
-    # Add the new product.
-    $dbh-&gt;do('INSERT INTO products
-              (name, description, milestoneurl, disallownew, votesperuser,
-               maxvotesperbug, votestoconfirm, defaultmilestone, classification_id)
-              VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)',
-             undef, ($product_name, $description, $milestoneurl, $disallownew,
-             $votesperuser, $maxvotesperbug, $votestoconfirm, $defaultmilestone,
-             $classification_id));
-
-    $product = new Bugzilla::Product({name =&gt; $product_name});
-    
-    $dbh-&gt;do('INSERT INTO versions (value, product_id) VALUES (?, ?)',
-             undef, ($version, $product-&gt;id));
-
-    $dbh-&gt;do('INSERT INTO milestones (product_id, value) VALUES (?, ?)',
-             undef, ($product-&gt;id, $defaultmilestone));
-
-    # If we're using bug groups, then we need to create a group for this
-    # product as well.  -JMR, 2/16/00
-    if (Bugzilla-&gt;params-&gt;{&quot;makeproductgroups&quot;}) {
-        # Next we insert into the groups table
-        my $productgroup = $product-&gt;name;
-        while (new Bugzilla::Group({name =&gt; $productgroup})) {
-            $productgroup .= '_';
-        }
-        my $group_description = &quot;Access to bugs in the &quot; .
-                                $product-&gt;name . &quot; product&quot;;
-
-        $dbh-&gt;do('INSERT INTO groups (name, description, isbuggroup)
-                  VALUES (?, ?, ?)',
-                  undef, ($productgroup, $group_description, 1));
-
-        my $gid = $dbh-&gt;bz_last_key('groups', 'id');
-
-        # If we created a new group, give the &quot;admin&quot; group privileges
-        # initially.
-        my $admin = Bugzilla::Group-&gt;new({name =&gt; 'admin'})-&gt;id();
-        
-        my $sth = $dbh-&gt;prepare('INSERT INTO group_group_map
-                                 (member_id, grantor_id, grant_type)
-                                 VALUES (?, ?, ?)');
-
-        $sth-&gt;execute($admin, $gid, GROUP_MEMBERSHIP);
-        $sth-&gt;execute($admin, $gid, GROUP_BLESS);
-        $sth-&gt;execute($admin, $gid, GROUP_VISIBLE);
-
-        # Associate the new group and new product.
-        $dbh-&gt;do('INSERT INTO group_control_map
-                  (group_id, product_id, entry, membercontrol,
-                   othercontrol, canedit)
-                  VALUES (?, ?, ?, ?, ?, ?)',
-                 undef, ($gid, $product-&gt;id, 
-                         Bugzilla-&gt;params-&gt;{'useentrygroupdefault'},
-                 CONTROLMAPDEFAULT, CONTROLMAPNA, 0));
-    }
-
-    if ($cgi-&gt;param('createseries')) {
-        # Insert default charting queries for this product.
-        # If they aren't using charting, this won't do any harm.
-        #
-        # $open_name and $product are sqlquoted by the series code 
-        # and never used again here, so we can trick_taint them.
-        my $open_name = $cgi-&gt;param('open_name');
-        trick_taint($open_name);
-    
-        my @series;
-    
-        # We do every status, every resolution, and an &quot;opened&quot; one as well.
-        foreach my $bug_status (@{get_legal_field_values('bug_status')}) {
-            push(@series, [$bug_status, 
-                           &quot;bug_status=&quot; . url_quote($bug_status)]);
-        }
-
-        foreach my $resolution (@{get_legal_field_values('resolution')}) {
-            next if !$resolution;
-            push(@series, [$resolution, &quot;resolution=&quot; .url_quote($resolution)]);
-        }
-
-        # For localization reasons, we get the name of the &quot;global&quot; subcategory
-        # and the title of the &quot;open&quot; query from the submitted form.
-        my @openedstatuses = BUG_STATE_OPEN;
-        my $query = 
-               join(&quot;&amp;&quot;, map { &quot;bug_status=&quot; . url_quote($_) } @openedstatuses);
-        push(@series, [$open_name, $query]);
-    
-        foreach my $sdata (@series) {
-            my $series = new Bugzilla::Series(undef, $product-&gt;name, 
-                            scalar $cgi-&gt;param('subcategory'),
-                            $sdata-&gt;[0], $whoid, 1,
-                            $sdata-&gt;[1] . &quot;&amp;product=&quot; .
-                            url_quote($product-&gt;name), 1);
-            $series-&gt;writeToDatabase();
-        }
-    }
</del><span class="cx">     delete_token($token);
</span><span class="cx"> 
</span><span class="cx">     $vars-&gt;{'message'} = 'product_created';
</span><span class="cx">     $vars-&gt;{'product'} = $product;
</span><del>-    $vars-&gt;{'classification'} = new Bugzilla::Classification($product-&gt;classification_id)
-      if Bugzilla-&gt;params-&gt;{'useclassification'};
</del><ins>+    if (Bugzilla-&gt;params-&gt;{'useclassification'}) {
+        $vars-&gt;{'classification'} = new Bugzilla::Classification($product-&gt;classification_id);
+    }
</ins><span class="cx">     $vars-&gt;{'token'} = issue_session_token('edit_product');
</span><span class="cx"> 
</span><span class="cx">     $template-&gt;process(&quot;admin/products/edit.html.tmpl&quot;, $vars)
</span><span class="lines">@@ -358,20 +212,12 @@
</span><span class="cx">     my $product = $user-&gt;check_can_admin_product($product_name);
</span><span class="cx"> 
</span><span class="cx">     if (Bugzilla-&gt;params-&gt;{'useclassification'}) {
</span><del>-        my $classification = 
-            Bugzilla::Classification::check_classification($classification_name);
-        if ($classification-&gt;id != $product-&gt;classification_id) {
-            ThrowUserError('classification_doesnt_exist_for_product',
-                           { product =&gt; $product-&gt;name,
-                             classification =&gt; $classification-&gt;name });
-        }
-        $vars-&gt;{'classification'} = $classification;
</del><ins>+        $vars-&gt;{'classification'} = new Bugzilla::Classification($product-&gt;classification_id);
</ins><span class="cx">     }
</span><del>-
</del><span class="cx">     $vars-&gt;{'product'} = $product;
</span><span class="cx">     $vars-&gt;{'token'} = issue_session_token('delete_product');
</span><span class="cx">     
</span><del>-    Bugzilla::Hook::process(&quot;product-confirm_delete&quot;, { vars =&gt; $vars });
</del><ins>+    Bugzilla::Hook::process('product_confirm_delete', { vars =&gt; $vars });
</ins><span class="cx">     
</span><span class="cx">     $template-&gt;process(&quot;admin/products/confirm-delete.html.tmpl&quot;, $vars)
</span><span class="cx">         || ThrowTemplateError($template-&gt;error());
</span><span class="lines">@@ -386,69 +232,7 @@
</span><span class="cx">     my $product = $user-&gt;check_can_admin_product($product_name);
</span><span class="cx">     check_token_data($token, 'delete_product');
</span><span class="cx"> 
</span><del>-    if (Bugzilla-&gt;params-&gt;{'useclassification'}) {
-        my $classification = 
-            Bugzilla::Classification::check_classification($classification_name);
-        if ($classification-&gt;id != $product-&gt;classification_id) {
-            ThrowUserError('classification_doesnt_exist_for_product',
-                           { product =&gt; $product-&gt;name,
-                             classification =&gt; $classification-&gt;name });
-        }
-        $vars-&gt;{'classification'} = $classification;
-    }
-
-    if ($product-&gt;bug_count) {
-        if (Bugzilla-&gt;params-&gt;{&quot;allowbugdeletion&quot;}) {
-            foreach my $bug_id (@{$product-&gt;bug_ids}) {
-                # Note that we allow the user to delete bugs he can't see,
-                # which is okay, because he's deleting the whole Product.
-                my $bug = new Bugzilla::Bug($bug_id);
-                $bug-&gt;remove_from_db();
-            }
-        }
-        else {
-            ThrowUserError(&quot;product_has_bugs&quot;, 
-                           { nb =&gt; $product-&gt;bug_count });
-        }
-    }
-
-    $dbh-&gt;bz_start_transaction();
-
-    my $comp_ids = $dbh-&gt;selectcol_arrayref('SELECT id FROM components
-                                             WHERE product_id = ?',
-                                             undef, $product-&gt;id);
-
-    $dbh-&gt;do('DELETE FROM component_cc WHERE component_id IN
-              (' . join(',', @$comp_ids) . ')') if scalar(@$comp_ids);
-
-    $dbh-&gt;do(&quot;DELETE FROM components WHERE product_id = ?&quot;,
-             undef, $product-&gt;id);
-
-    $dbh-&gt;do(&quot;DELETE FROM versions WHERE product_id = ?&quot;,
-             undef, $product-&gt;id);
-
-    $dbh-&gt;do(&quot;DELETE FROM milestones WHERE product_id = ?&quot;,
-             undef, $product-&gt;id);
-
-    $dbh-&gt;do(&quot;DELETE FROM group_control_map WHERE product_id = ?&quot;,
-             undef, $product-&gt;id);
-
-    $dbh-&gt;do(&quot;DELETE FROM flaginclusions WHERE product_id = ?&quot;,
-             undef, $product-&gt;id);
-             
-    $dbh-&gt;do(&quot;DELETE FROM flagexclusions WHERE product_id = ?&quot;,
-             undef, $product-&gt;id);
-             
-    $dbh-&gt;do(&quot;DELETE FROM products WHERE id = ?&quot;,
-             undef, $product-&gt;id);
-
-    $dbh-&gt;bz_commit_transaction();
-
-    # We have to delete these internal variables, else we get
-    # the old lists of products and classifications again.
-    delete $user-&gt;{selectable_products};
-    delete $user-&gt;{selectable_classifications};
-
</del><ins>+    $product-&gt;remove_from_db({ delete_series =&gt; scalar $cgi-&gt;param('delete_series')});
</ins><span class="cx">     delete_token($token);
</span><span class="cx"> 
</span><span class="cx">     $vars-&gt;{'message'} = 'product_deleted';
</span><span class="lines">@@ -457,7 +241,7 @@
</span><span class="cx"> 
</span><span class="cx">     if (Bugzilla-&gt;params-&gt;{'useclassification'}) {
</span><span class="cx">         $vars-&gt;{'classifications'} = $user-&gt;in_group('editcomponents') ?
</span><del>-          [Bugzilla::Classification::get_all_classifications] : $user-&gt;get_selectable_classifications;
</del><ins>+          [Bugzilla::Classification-&gt;get_all] : $user-&gt;get_selectable_classifications;
</ins><span class="cx"> 
</span><span class="cx">         $template-&gt;process(&quot;admin/products/list-classifications.html.tmpl&quot;, $vars)
</span><span class="cx">           || ThrowTemplateError($template-&gt;error());
</span><span class="lines">@@ -488,20 +272,7 @@
</span><span class="cx">     my $product = $user-&gt;check_can_admin_product($product_name);
</span><span class="cx"> 
</span><span class="cx">     if (Bugzilla-&gt;params-&gt;{'useclassification'}) {
</span><del>-        my $classification; 
-        if (!$classification_name) {
-            $classification = 
-                new Bugzilla::Classification($product-&gt;classification_id);
-        } else {
-            $classification = 
-                Bugzilla::Classification::check_classification($classification_name);
-            if ($classification-&gt;id != $product-&gt;classification_id) {
-                ThrowUserError('classification_doesnt_exist_for_product',
-                               { product =&gt; $product-&gt;name,
-                                 classification =&gt; $classification-&gt;name });
-            }
-        }
-        $vars-&gt;{'classification'} = $classification;
</del><ins>+        $vars-&gt;{'classification'} = new Bugzilla::Classification($product-&gt;classification_id);
</ins><span class="cx">     }
</span><span class="cx">     $vars-&gt;{'product'} = $product;
</span><span class="cx">     $vars-&gt;{'token'} = issue_session_token('edit_product');
</span><span class="lines">@@ -512,9 +283,55 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #
</span><del>-# action='updategroupcontrols' -&gt; update the product
</del><ins>+# action='update' -&gt; update the product
</ins><span class="cx"> #
</span><ins>+if ($action eq 'update') {
+    check_token_data($token, 'edit_product');
+    my $product_old_name = trim($cgi-&gt;param('product_old_name') || '');
+    my $product = $user-&gt;check_can_admin_product($product_old_name);
</ins><span class="cx"> 
</span><ins>+    $product-&gt;set_all({
+        name        =&gt; $product_name,
+        description =&gt; scalar $cgi-&gt;param('description'),
+        is_active   =&gt; scalar $cgi-&gt;param('is_active'),
+        allows_unconfirmed =&gt; scalar $cgi-&gt;param('allows_unconfirmed'),
+        default_milestone  =&gt; scalar $cgi-&gt;param('defaultmilestone'),
+    });
+
+    my $changes = $product-&gt;update();
+
+    delete_token($token);
+
+    if (Bugzilla-&gt;params-&gt;{'useclassification'}) {
+        $vars-&gt;{'classification'} = new Bugzilla::Classification($product-&gt;classification_id);
+    }
+    $vars-&gt;{'product'} = $product;
+    $vars-&gt;{'changes'} = $changes;
+
+    $template-&gt;process(&quot;admin/products/updated.html.tmpl&quot;, $vars)
+        || ThrowTemplateError($template-&gt;error());
+    exit;
+}
+
+#
+# action='editgroupcontrols' -&gt; display product group controls
+#
+
+if ($action eq 'editgroupcontrols') {
+    my $product = $user-&gt;check_can_admin_product($product_name);
+
+    $vars-&gt;{'product'} = $product;
+    $vars-&gt;{'token'} = issue_session_token('edit_group_controls');
+
+    $template-&gt;process(&quot;admin/products/groupcontrol/edit.html.tmpl&quot;, $vars)
+        || ThrowTemplateError($template-&gt;error());
+    exit;
+}
+
+#
+# action='updategroupcontrols' -&gt; update product group controls
+#
+
</ins><span class="cx"> if ($action eq 'updategroupcontrols') {
</span><span class="cx">     my $product = $user-&gt;check_can_admin_product($product_name);
</span><span class="cx">     check_token_data($token, 'edit_group_controls');
</span><span class="lines">@@ -547,10 +364,9 @@
</span><span class="cx">                    {'Slice' =&gt; {}}, $product-&gt;id);
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-#
-# return the mandatory groups which need to have bug entries added to the bug_group_map
-# and the corresponding bug count
-#
</del><ins>+        # return the mandatory groups which need to have bug entries
+        # added to the bug_group_map and the corresponding bug count
+
</ins><span class="cx">         my $mandatory_groups;
</span><span class="cx">         if (@now_mandatory) {
</span><span class="cx">             $mandatory_groups = $dbh-&gt;selectall_arrayref(
</span><span class="lines">@@ -578,516 +394,33 @@
</span><span class="cx">             $vars-&gt;{'mandatory_groups'} = $mandatory_groups;
</span><span class="cx">             $template-&gt;process(&quot;admin/products/groupcontrol/confirm-edit.html.tmpl&quot;, $vars)
</span><span class="cx">                 || ThrowTemplateError($template-&gt;error());
</span><del>-            exit;                
</del><ins>+            exit;
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    my $groups = $dbh-&gt;selectall_arrayref('SELECT id, name FROM groups
-                                           WHERE isbuggroup != 0
-                                           AND isactive != 0');
</del><ins>+    my $groups = Bugzilla::Group-&gt;match({isactive =&gt; 1, isbuggroup =&gt; 1});
</ins><span class="cx">     foreach my $group (@$groups) {
</span><del>-        my ($groupid, $groupname) = @$group;
-        my $newmembercontrol = $cgi-&gt;param(&quot;membercontrol_$groupid&quot;) || 0;
-        my $newothercontrol = $cgi-&gt;param(&quot;othercontrol_$groupid&quot;) || 0;
-        #  Legality of control combination is a function of
-        #  membercontrol\othercontrol
-        #                 NA SH DE MA
-        #              NA  +  -  -  -
-        #              SH  +  +  +  +
-        #              DE  +  -  +  +
-        #              MA  -  -  -  +
-        unless (($newmembercontrol == $newothercontrol)
-              || ($newmembercontrol == CONTROLMAPSHOWN)
-              || (($newmembercontrol == CONTROLMAPDEFAULT)
-               &amp;&amp; ($newothercontrol != CONTROLMAPSHOWN))) {
-            ThrowUserError('illegal_group_control_combination',
-                            {groupname =&gt; $groupname});
-        }
</del><ins>+        my $group_id = $group-&gt;id;
+        $product-&gt;set_group_controls($group,
+                                     {entry          =&gt; scalar $cgi-&gt;param(&quot;entry_$group_id&quot;) || 0,
+                                      membercontrol  =&gt; scalar $cgi-&gt;param(&quot;membercontrol_$group_id&quot;) || CONTROLMAPNA,
+                                      othercontrol   =&gt; scalar $cgi-&gt;param(&quot;othercontrol_$group_id&quot;) || CONTROLMAPNA,
+                                      canedit        =&gt; scalar $cgi-&gt;param(&quot;canedit_$group_id&quot;) || 0,
+                                      editcomponents =&gt; scalar $cgi-&gt;param(&quot;editcomponents_$group_id&quot;) || 0,
+                                      editbugs       =&gt; scalar $cgi-&gt;param(&quot;editbugs_$group_id&quot;) || 0,
+                                      canconfirm     =&gt; scalar $cgi-&gt;param(&quot;canconfirm_$group_id&quot;) || 0});
</ins><span class="cx">     }
</span><del>-    $dbh-&gt;bz_start_transaction();
</del><ins>+    my $changes = $product-&gt;update;
</ins><span class="cx"> 
</span><del>-    my $sth_Insert = $dbh-&gt;prepare('INSERT INTO group_control_map
-                                    (group_id, product_id, entry, membercontrol,
-                                     othercontrol, canedit, editcomponents,
-                                     canconfirm, editbugs)
-                                    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)');
-
-    my $sth_Update = $dbh-&gt;prepare('UPDATE group_control_map
-                                       SET entry = ?, membercontrol = ?,
-                                           othercontrol = ?, canedit = ?,
-                                           editcomponents = ?, canconfirm = ?,
-                                           editbugs = ?
-                                     WHERE group_id = ? AND product_id = ?');
-
-    my $sth_Delete = $dbh-&gt;prepare('DELETE FROM group_control_map
-                                     WHERE group_id = ? AND product_id = ?');
-
-    $groups = $dbh-&gt;selectall_arrayref('SELECT id, name, entry, membercontrol,
-                                               othercontrol, canedit,
-                                               editcomponents, canconfirm, editbugs
-                                          FROM groups
-                                     LEFT JOIN group_control_map
-                                            ON group_control_map.group_id = id
-                                           AND product_id = ?
-                                         WHERE isbuggroup != 0
-                                           AND isactive != 0',
-                                         undef, $product-&gt;id);
-
-    foreach my $group (@$groups) {
-        my ($groupid, $groupname, $entry, $membercontrol, $othercontrol,
-            $canedit, $editcomponents, $canconfirm, $editbugs) = @$group;
-        my $newentry = $cgi-&gt;param(&quot;entry_$groupid&quot;) || 0;
-        my $newmembercontrol = $cgi-&gt;param(&quot;membercontrol_$groupid&quot;) || 0;
-        my $newothercontrol = $cgi-&gt;param(&quot;othercontrol_$groupid&quot;) || 0;
-        my $newcanedit = $cgi-&gt;param(&quot;canedit_$groupid&quot;) || 0;
-        my $new_editcomponents = $cgi-&gt;param(&quot;editcomponents_$groupid&quot;) || 0;
-        my $new_canconfirm = $cgi-&gt;param(&quot;canconfirm_$groupid&quot;) || 0;
-        my $new_editbugs = $cgi-&gt;param(&quot;editbugs_$groupid&quot;) || 0;
-
-        my $oldentry = $entry;
-        # Set undefined values to 0.
-        $entry ||= 0;
-        $membercontrol ||= 0;
-        $othercontrol ||= 0;
-        $canedit ||= 0;
-        $editcomponents ||= 0;
-        $canconfirm ||= 0;
-        $editbugs ||= 0;
-
-        # We use them in placeholders only. So it's safe to detaint them.
-        detaint_natural($newentry);
-        detaint_natural($newothercontrol);
-        detaint_natural($newmembercontrol);
-        detaint_natural($newcanedit);
-        detaint_natural($new_editcomponents);
-        detaint_natural($new_canconfirm);
-        detaint_natural($new_editbugs);
-
-        if (!defined($oldentry)
-            &amp;&amp; ($newentry || $newmembercontrol || $newcanedit
-                || $new_editcomponents || $new_canconfirm || $new_editbugs))
-        {
-            $sth_Insert-&gt;execute($groupid, $product-&gt;id, $newentry,
-                                 $newmembercontrol, $newothercontrol, $newcanedit,
-                                 $new_editcomponents, $new_canconfirm, $new_editbugs);
-        }
-        elsif (($newentry != $entry)
-               || ($newmembercontrol != $membercontrol)
-               || ($newothercontrol != $othercontrol)
-               || ($newcanedit != $canedit)
-               || ($new_editcomponents != $editcomponents)
-               || ($new_canconfirm != $canconfirm)
-               || ($new_editbugs != $editbugs))
-        {
-            $sth_Update-&gt;execute($newentry, $newmembercontrol, $newothercontrol,
-                                 $newcanedit, $new_editcomponents, $new_canconfirm,
-                                 $new_editbugs, $groupid, $product-&gt;id);
-        }
-
-        if (!$newentry &amp;&amp; !$newmembercontrol &amp;&amp; !$newothercontrol
-            &amp;&amp; !$newcanedit &amp;&amp; !$new_editcomponents &amp;&amp; !$new_canconfirm
-            &amp;&amp; !$new_editbugs)
-        {
-            $sth_Delete-&gt;execute($groupid, $product-&gt;id);
-        }
-    }
-
-    my $sth_Select = $dbh-&gt;prepare(
-                     'SELECT bugs.bug_id,
-                   CASE WHEN (lastdiffed &gt;= delta_ts) THEN 1 ELSE 0 END
-                        FROM bugs
-                  INNER JOIN bug_group_map
-                          ON bug_group_map.bug_id = bugs.bug_id
-                       WHERE group_id = ?
-                         AND bugs.product_id = ?
-                    ORDER BY bugs.bug_id');
-
-    my $sth_Select2 = $dbh-&gt;prepare('SELECT name, NOW() FROM groups WHERE id = ?');
-
-    $sth_Update = $dbh-&gt;prepare('UPDATE bugs SET delta_ts = ? WHERE bug_id = ?');
-
-    my $sth_Update2 = $dbh-&gt;prepare('UPDATE bugs SET delta_ts = ?, lastdiffed = ?
-                                     WHERE bug_id = ?');
-
-    $sth_Delete = $dbh-&gt;prepare('DELETE FROM bug_group_map
-                                 WHERE bug_id = ? AND group_id = ?');
-
-    my @removed_na;
-    foreach my $groupid (@now_na) {
-        my $count = 0;
-        my $bugs = $dbh-&gt;selectall_arrayref($sth_Select, undef,
-                                            ($groupid, $product-&gt;id));
-
-        my ($removed, $timestamp) =
-            $dbh-&gt;selectrow_array($sth_Select2, undef, $groupid);
-
-        foreach my $bug (@$bugs) {
-            my ($bugid, $mailiscurrent) = @$bug;
-            $sth_Delete-&gt;execute($bugid, $groupid);
-
-            LogActivityEntry($bugid, &quot;bug_group&quot;, $removed, &quot;&quot;,
-                             $whoid, $timestamp);
-
-            if ($mailiscurrent) {
-                $sth_Update2-&gt;execute($timestamp, $timestamp, $bugid);
-            }
-            else {
-                $sth_Update-&gt;execute($timestamp, $bugid);
-            }
-            $count++;
-        }
-        my %group = (name =&gt; $removed, bug_count =&gt; $count);
-
-        push(@removed_na, \%group);
-    }
-
-    $sth_Select = $dbh-&gt;prepare(
-                  'SELECT bugs.bug_id,
-                CASE WHEN (lastdiffed &gt;= delta_ts) THEN 1 ELSE 0 END
-                     FROM bugs
-                LEFT JOIN bug_group_map
-                       ON bug_group_map.bug_id = bugs.bug_id
-                      AND group_id = ?
-                    WHERE bugs.product_id = ?
-                      AND bug_group_map.bug_id IS NULL
-                 ORDER BY bugs.bug_id');
-
-    $sth_Insert = $dbh-&gt;prepare('INSERT INTO bug_group_map
-                                 (bug_id, group_id) VALUES (?, ?)');
-
-    my @added_mandatory;
-    foreach my $groupid (@now_mandatory) {
-        my $count = 0;
-        my $bugs = $dbh-&gt;selectall_arrayref($sth_Select, undef,
-                                            ($groupid, $product-&gt;id));
-
-        my ($added, $timestamp) =
-            $dbh-&gt;selectrow_array($sth_Select2, undef, $groupid);
-
-        foreach my $bug (@$bugs) {
-            my ($bugid, $mailiscurrent) = @$bug;
-            $sth_Insert-&gt;execute($bugid, $groupid);
-
-            LogActivityEntry($bugid, &quot;bug_group&quot;, &quot;&quot;, $added,
-                             $whoid, $timestamp);
-
-            if ($mailiscurrent) {
-                $sth_Update2-&gt;execute($timestamp, $timestamp, $bugid);
-            }
-            else {
-                $sth_Update-&gt;execute($timestamp, $bugid);
-            }
-            $count++;
-        }
-        my %group = (name =&gt; $added, bug_count =&gt; $count);
-
-        push(@added_mandatory, \%group);
-    }
-    $dbh-&gt;bz_commit_transaction();
-
</del><span class="cx">     delete_token($token);
</span><span class="cx"> 
</span><del>-    $vars-&gt;{'removed_na'} = \@removed_na;
-    $vars-&gt;{'added_mandatory'} = \@added_mandatory;
</del><span class="cx">     $vars-&gt;{'product'} = $product;
</span><ins>+    $vars-&gt;{'changes'} = $changes;
</ins><span class="cx"> 
</span><span class="cx">     $template-&gt;process(&quot;admin/products/groupcontrol/updated.html.tmpl&quot;, $vars)
</span><span class="cx">         || ThrowTemplateError($template-&gt;error());
</span><span class="cx">     exit;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-#
-# action='update' -&gt; update the product
-#
-if ($action eq 'update') {
-    check_token_data($token, 'edit_product');
-    my $product_old_name    = trim($cgi-&gt;param('product_old_name')    || '');
-    my $description         = trim($cgi-&gt;param('description')         || '');
-    my $disallownew         = trim($cgi-&gt;param('disallownew')         || '');
-    my $milestoneurl        = trim($cgi-&gt;param('milestoneurl')        || '');
-    my $votesperuser        = trim($cgi-&gt;param('votesperuser')        || 0);
-    my $maxvotesperbug      = trim($cgi-&gt;param('maxvotesperbug')      || 0);
-    my $votestoconfirm      = trim($cgi-&gt;param('votestoconfirm')      || 0);
-    my $defaultmilestone    = trim($cgi-&gt;param('defaultmilestone')    || '---');
-
-    my $checkvotes = 0;
-
-    my $product_old = $user-&gt;check_can_admin_product($product_old_name);
-
-    if (Bugzilla-&gt;params-&gt;{'useclassification'}) {
-        my $classification; 
-        if (!$classification_name) {
-            $classification = 
-                new Bugzilla::Classification($product_old-&gt;classification_id);
-        } else {
-            $classification = 
-                Bugzilla::Classification::check_classification($classification_name);
-            if ($classification-&gt;id != $product_old-&gt;classification_id) {
-                ThrowUserError('classification_doesnt_exist_for_product',
-                               { product =&gt; $product_old-&gt;name,
-                                 classification =&gt; $classification-&gt;name });
-            }
-        }
-        $vars-&gt;{'classification'} = $classification;
-    }
-
-    unless ($product_name) {
-        ThrowUserError('product_cant_delete_name',
-                       {product =&gt; $product_old-&gt;name});
-    }
-
-    unless ($description) {
-        ThrowUserError('product_cant_delete_description',
-                       {product =&gt; $product_old-&gt;name});
-    }
-
-    my $stored_maxvotesperbug = $maxvotesperbug;
-    if (!detaint_natural($maxvotesperbug)) {
-        ThrowUserError('product_votes_per_bug_must_be_nonnegative',
-                       {maxvotesperbug =&gt; $stored_maxvotesperbug});
-    }
-
-    my $stored_votesperuser = $votesperuser;
-    if (!detaint_natural($votesperuser)) {
-        ThrowUserError('product_votes_per_user_must_be_nonnegative',
-                       {votesperuser =&gt; $stored_votesperuser});
-    }
-
-    my $stored_votestoconfirm = $votestoconfirm;
-    if (!detaint_natural($votestoconfirm)) {
-        ThrowUserError('product_votes_to_confirm_must_be_nonnegative',
-                       {votestoconfirm =&gt; $stored_votestoconfirm});
-    }
-
-    $dbh-&gt;bz_start_transaction();
-
-    my $testproduct = 
-        new Bugzilla::Product({name =&gt; $product_name});
-    if (lc($product_name) ne lc($product_old-&gt;name) &amp;&amp;
-        $testproduct) {
-        ThrowUserError('product_name_already_in_use',
-                       {product =&gt; $product_name});
-    }
-
-    # Only update milestone related stuff if 'usetargetmilestone' is on.
-    if (Bugzilla-&gt;params-&gt;{'usetargetmilestone'}) {
-        my $milestone = new Bugzilla::Milestone(
-            { product =&gt; $product_old, name =&gt; $defaultmilestone });
-
-        unless ($milestone) {
-            ThrowUserError('product_must_define_defaultmilestone',
-                           {product          =&gt; $product_old-&gt;name,
-                            defaultmilestone =&gt; $defaultmilestone,
-                            classification   =&gt; $classification_name});
-        }
-
-        if ($milestoneurl ne $product_old-&gt;milestone_url) {
-            trick_taint($milestoneurl);
-            $dbh-&gt;do('UPDATE products SET milestoneurl = ? WHERE id = ?',
-                     undef, ($milestoneurl, $product_old-&gt;id));
-        }
-
-        if ($milestone-&gt;name ne $product_old-&gt;default_milestone) {
-            $dbh-&gt;do('UPDATE products SET defaultmilestone = ? WHERE id = ?',
-                     undef, ($milestone-&gt;name, $product_old-&gt;id));
-        }
-    }
-
-    $disallownew = $disallownew ? 1 : 0;
-    if ($disallownew ne $product_old-&gt;disallow_new) {
-        $dbh-&gt;do('UPDATE products SET disallownew = ? WHERE id = ?',
-                 undef, ($disallownew, $product_old-&gt;id));
-    }
-
-    if ($description ne $product_old-&gt;description) {
-        trick_taint($description);
-        $dbh-&gt;do('UPDATE products SET description = ? WHERE id = ?',
-                 undef, ($description, $product_old-&gt;id));
-    }
-
-    if ($votesperuser ne $product_old-&gt;votes_per_user) {
-        $dbh-&gt;do('UPDATE products SET votesperuser = ? WHERE id = ?',
-                 undef, ($votesperuser, $product_old-&gt;id));
-        $checkvotes = 1;
-    }
-
-    if ($maxvotesperbug ne $product_old-&gt;max_votes_per_bug) {
-        $dbh-&gt;do('UPDATE products SET maxvotesperbug = ? WHERE id = ?',
-                 undef, ($maxvotesperbug, $product_old-&gt;id));
-        $checkvotes = 1;
-    }
-
-    if ($votestoconfirm ne $product_old-&gt;votes_to_confirm) {
-        $dbh-&gt;do('UPDATE products SET votestoconfirm = ? WHERE id = ?',
-                 undef, ($votestoconfirm, $product_old-&gt;id));
-        $checkvotes = 1;
-    }
-
-    if ($product_name ne $product_old-&gt;name) {
-        trick_taint($product_name);
-        $dbh-&gt;do('UPDATE products SET name = ? WHERE id = ?',
-                 undef, ($product_name, $product_old-&gt;id));
-    }
-
-    $dbh-&gt;bz_commit_transaction();
-
-    my $product = new Bugzilla::Product({name =&gt; $product_name});
-
-    if ($checkvotes) {
-        $vars-&gt;{'checkvotes'} = 1;
-
-        # 1. too many votes for a single user on a single bug.
-        my @toomanyvotes_list = ();
-        if ($maxvotesperbug &lt; $votesperuser) {
-            my $votes = $dbh-&gt;selectall_arrayref(
-                        'SELECT votes.who, votes.bug_id
-                           FROM votes
-                     INNER JOIN bugs
-                             ON bugs.bug_id = votes.bug_id
-                          WHERE bugs.product_id = ?
-                            AND votes.vote_count &gt; ?',
-                         undef, ($product-&gt;id, $maxvotesperbug));
-
-            foreach my $vote (@$votes) {
-                my ($who, $id) = (@$vote);
-                # If some votes are removed, RemoveVotes() returns a list
-                # of messages to send to voters.
-                my $msgs = RemoveVotes($id, $who, 'votes_too_many_per_bug');
-                foreach my $msg (@$msgs) {
-                    MessageToMTA($msg);
-                }
-                my $name = user_id_to_login($who);
-
-                push(@toomanyvotes_list,
-                     {id =&gt; $id, name =&gt; $name});
-            }
-        }
-        $vars-&gt;{'toomanyvotes'} = \@toomanyvotes_list;
-
-        # 2. too many total votes for a single user.
-        # This part doesn't work in the general case because RemoveVotes
-        # doesn't enforce votesperuser (except per-bug when it's less
-        # than maxvotesperbug).  See Bugzilla::Bug::RemoveVotes().
-
-        my $votes = $dbh-&gt;selectall_arrayref(
-                    'SELECT votes.who, votes.vote_count
-                       FROM votes
-                 INNER JOIN bugs
-                         ON bugs.bug_id = votes.bug_id
-                      WHERE bugs.product_id = ?',
-                     undef, $product-&gt;id);
-
-        my %counts;
-        foreach my $vote (@$votes) {
-            my ($who, $count) = @$vote;
-            if (!defined $counts{$who}) {
-                $counts{$who} = $count;
-            } else {
-                $counts{$who} += $count;
-            }
-        }
-        my @toomanytotalvotes_list = ();
-        foreach my $who (keys(%counts)) {
-            if ($counts{$who} &gt; $votesperuser) {
-                my $bug_ids = $dbh-&gt;selectcol_arrayref(
-                              'SELECT votes.bug_id
-                                 FROM votes
-                           INNER JOIN bugs
-                                   ON bugs.bug_id = votes.bug_id
-                                WHERE bugs.product_id = ?
-                                  AND votes.who = ?',
-                               undef, ($product-&gt;id, $who));
-
-                foreach my $bug_id (@$bug_ids) {
-                    # RemoveVotes() returns a list of messages to send
-                    # in case some voters had too many votes.
-                    my $msgs = RemoveVotes($bug_id, $who, 'votes_too_many_per_user');
-                    foreach my $msg (@$msgs) {
-                        MessageToMTA($msg);
-                    }
-                    my $name = user_id_to_login($who);
-
-                    push(@toomanytotalvotes_list,
-                         {id =&gt; $bug_id, name =&gt; $name});
-                }
-            }
-        }
-        $vars-&gt;{'toomanytotalvotes'} = \@toomanytotalvotes_list;
-
-        # 3. enough votes to confirm
-        my $bug_list = $dbh-&gt;selectcol_arrayref(
-                       &quot;SELECT bug_id FROM bugs
-                         WHERE product_id = ?
-                           AND bug_status = 'UNCONFIRMED'
-                           AND votes &gt;= ?&quot;,
-                        undef, ($product-&gt;id, $votestoconfirm));
-
-        my @updated_bugs = ();
-        foreach my $bug_id (@$bug_list) {
-            my $confirmed = CheckIfVotedConfirmed($bug_id, $whoid);
-            push (@updated_bugs, $bug_id) if $confirmed;
-        }
-
-        $vars-&gt;{'confirmedbugs'} = \@updated_bugs;
-        $vars-&gt;{'changer'} = $user-&gt;login;
-    }
-    delete_token($token);
-
-    $vars-&gt;{'old_product'} = $product_old;
-    $vars-&gt;{'product'} = $product;
-
-    $template-&gt;process(&quot;admin/products/updated.html.tmpl&quot;, $vars)
-        || ThrowTemplateError($template-&gt;error());
-    exit;
-}
-
-#
-# action='editgroupcontrols' -&gt; update product group controls
-#
-
-if ($action eq 'editgroupcontrols') {
-    my $product = $user-&gt;check_can_admin_product($product_name);
-
-    # Display a group if it is either enabled or has bugs for this product.
-    my $groups = $dbh-&gt;selectall_arrayref(
-        'SELECT id, name, entry, membercontrol, othercontrol, canedit,
-                editcomponents, editbugs, canconfirm,
-                isactive, COUNT(bugs.bug_id) AS bugcount
-           FROM groups
-      LEFT JOIN group_control_map
-             ON group_control_map.group_id = groups.id
-            AND group_control_map.product_id = ?
-      LEFT JOIN bug_group_map
-             ON bug_group_map.group_id = groups.id
-      LEFT JOIN bugs
-             ON bugs.bug_id = bug_group_map.bug_id
-            AND bugs.product_id = ?
-          WHERE isbuggroup != 0
-            AND (isactive != 0 OR entry IS NOT NULL OR bugs.bug_id IS NOT NULL) ' .
-           $dbh-&gt;sql_group_by('name', 'id, entry, membercontrol,
-                              othercontrol, canedit, isactive,
-                              editcomponents, canconfirm, editbugs'),
-        {'Slice' =&gt; {}}, ($product-&gt;id, $product-&gt;id));
-
-    $vars-&gt;{'product'} = $product;
-    $vars-&gt;{'groups'} = $groups;
-    $vars-&gt;{'token'} = issue_session_token('edit_group_controls');
-
-    $vars-&gt;{'const'} = {
-        'CONTROLMAPNA' =&gt; CONTROLMAPNA,
-        'CONTROLMAPSHOWN' =&gt; CONTROLMAPSHOWN,
-        'CONTROLMAPDEFAULT' =&gt; CONTROLMAPDEFAULT,
-        'CONTROLMAPMANDATORY' =&gt; CONTROLMAPMANDATORY,
-    };
-
-    $template-&gt;process(&quot;admin/products/groupcontrol/edit.html.tmpl&quot;, $vars)
-        || ThrowTemplateError($template-&gt;error());
-    exit;                
-}
-
-
-#
</del><span class="cx"> # No valid action found
</span><del>-#
-
-ThrowUserError('no_valid_action', {field =&gt; &quot;product&quot;});
</del><ins>+ThrowUserError('unknown_action', {action =&gt; $action});
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgedituserscgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/editusers.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/editusers.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/editusers.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -64,6 +64,9 @@
</span><span class="cx"> $vars-&gt;{'editusers'} = $editusers;
</span><span class="cx"> mirrorListSelectionValues();
</span><span class="cx"> 
</span><ins>+Bugzilla::Hook::process('admin_editusers_action',
+    { vars =&gt; $vars, user =&gt; $user, action =&gt; $action });
+
</ins><span class="cx"> ###########################################################################
</span><span class="cx"> if ($action eq 'search') {
</span><span class="cx">     # Allow to restrict the search to any group the user is allowed to bless.
</span><span class="lines">@@ -74,10 +77,10 @@
</span><span class="cx"> ###########################################################################
</span><span class="cx"> } elsif ($action eq 'list') {
</span><span class="cx">     my $matchvalue    = $cgi-&gt;param('matchvalue') || '';
</span><del>-    my $matchstr      = $cgi-&gt;param('matchstr');
</del><ins>+    my $matchstr      = trim($cgi-&gt;param('matchstr'));
</ins><span class="cx">     my $matchtype     = $cgi-&gt;param('matchtype');
</span><span class="cx">     my $grouprestrict = $cgi-&gt;param('grouprestrict') || '0';
</span><del>-    my $query = 'SELECT DISTINCT userid, login_name, realname, disabledtext ' .
</del><ins>+    my $query = 'SELECT DISTINCT userid, login_name, realname, is_enabled ' .
</ins><span class="cx">                 'FROM profiles';
</span><span class="cx">     my @bindValues;
</span><span class="cx">     my $nextCondition;
</span><span class="lines">@@ -136,30 +139,35 @@
</span><span class="cx">             } else {
</span><span class="cx">                 $expr = &quot;profiles.login_name&quot;;
</span><span class="cx">             }
</span><ins>+
+            if ($matchtype =~ /^(regexp|notregexp|exact)$/) {
+                $matchstr ||= '.';
+            }
+            else {
+                $matchstr = '' unless defined $matchstr;
+            }
+            # We can trick_taint because we use the value in a SELECT only,
+            # using a placeholder.
+            trick_taint($matchstr);
+
</ins><span class="cx">             if ($matchtype eq 'regexp') {
</span><del>-                $query .= $dbh-&gt;sql_regexp($expr, '?');
-                $matchstr = '.' unless $matchstr;
</del><ins>+                $query .= $dbh-&gt;sql_regexp($expr, '?', 0, $dbh-&gt;quote($matchstr));
</ins><span class="cx">             } elsif ($matchtype eq 'notregexp') {
</span><del>-                $query .= $dbh-&gt;sql_not_regexp($expr, '?');
-                $matchstr = '.' unless $matchstr;
</del><ins>+                $query .= $dbh-&gt;sql_not_regexp($expr, '?', 0, $dbh-&gt;quote($matchstr));
</ins><span class="cx">             } elsif ($matchtype eq 'exact') {
</span><span class="cx">                 $query .= $expr . ' = ?';
</span><del>-                $matchstr = '.' unless $matchstr;
</del><span class="cx">             } else { # substr or unknown
</span><span class="cx">                 $query .= $dbh-&gt;sql_istrcmp($expr, '?', 'LIKE');
</span><span class="cx">                 $matchstr = &quot;%$matchstr%&quot;;
</span><span class="cx">             }
</span><span class="cx">             $nextCondition = 'AND';
</span><del>-            # We can trick_taint because we use the value in a SELECT only,
-            # using a placeholder.
-            trick_taint($matchstr);
</del><span class="cx">             push(@bindValues, $matchstr);
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         # Handle selection by group.
</span><span class="cx">         if ($grouprestrict eq '1') {
</span><span class="cx">             my $grouplist = join(',',
</span><del>-                @{Bugzilla::User-&gt;flatten_group_membership($group-&gt;id)});
</del><ins>+                @{Bugzilla::Group-&gt;flatten_group_membership($group-&gt;id)});
</ins><span class="cx">             $query .= &quot; $nextCondition ugm.group_id IN($grouplist) &quot;;
</span><span class="cx">         }
</span><span class="cx">         $query .= ' ORDER BY profiles.login_name';
</span><span class="lines">@@ -198,12 +206,19 @@
</span><span class="cx"> 
</span><span class="cx">     check_token_data($token, 'add_user');
</span><span class="cx"> 
</span><ins>+    # When e.g. the 'Env' auth method is used, the password field
+    # is not displayed. In that case, set the password to *.
+    my $password = $cgi-&gt;param('password');
+    $password = '*' if !defined $password;
+
</ins><span class="cx">     my $new_user = Bugzilla::User-&gt;create({
</span><span class="cx">         login_name    =&gt; scalar $cgi-&gt;param('login'),
</span><del>-        cryptpassword =&gt; scalar $cgi-&gt;param('password'),
</del><ins>+        cryptpassword =&gt; $password,
</ins><span class="cx">         realname      =&gt; scalar $cgi-&gt;param('name'),
</span><span class="cx">         disabledtext  =&gt; scalar $cgi-&gt;param('disabledtext'),
</span><del>-        disable_mail  =&gt; scalar $cgi-&gt;param('disable_mail')});
</del><ins>+        disable_mail  =&gt; scalar $cgi-&gt;param('disable_mail'),
+        extern_id     =&gt; scalar $cgi-&gt;param('extern_id'),
+        });
</ins><span class="cx"> 
</span><span class="cx">     userDataToVars($new_user-&gt;id);
</span><span class="cx"> 
</span><span class="lines">@@ -238,7 +253,7 @@
</span><span class="cx"> 
</span><span class="cx">     # Update profiles table entry; silently skip doing this if the user
</span><span class="cx">     # is not authorized.
</span><del>-    my %changes;
</del><ins>+    my $changes = {};
</ins><span class="cx">     if ($editusers) {
</span><span class="cx">         $otherUser-&gt;set_login($cgi-&gt;param('login'));
</span><span class="cx">         $otherUser-&gt;set_name($cgi-&gt;param('name'));
</span><span class="lines">@@ -246,7 +261,9 @@
</span><span class="cx">             if $cgi-&gt;param('password');
</span><span class="cx">         $otherUser-&gt;set_disabledtext($cgi-&gt;param('disabledtext'));
</span><span class="cx">         $otherUser-&gt;set_disable_mail($cgi-&gt;param('disable_mail'));
</span><del>-        %changes = %{$otherUser-&gt;update()};
</del><ins>+        $otherUser-&gt;set_extern_id($cgi-&gt;param('extern_id'))
+            if defined($cgi-&gt;param('extern_id'));
+        $changes = $otherUser-&gt;update();
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # Update group settings.
</span><span class="lines">@@ -276,9 +293,9 @@
</span><span class="cx">     #      would allow to display a friendlier error message on page reloads.
</span><span class="cx">     userDataToVars($otherUserID);
</span><span class="cx">     my $permissions = $vars-&gt;{'permissions'};
</span><del>-    foreach (@{$user-&gt;bless_groups()}) {
-        my $id = $$_{'id'};
-        my $name = $$_{'name'};
</del><ins>+    foreach my $blessable (@{$user-&gt;bless_groups()}) {
+        my $id = $blessable-&gt;id;
+        my $name = $blessable-&gt;name;
</ins><span class="cx"> 
</span><span class="cx">         # Change memberships.
</span><span class="cx">         my $groupid = $cgi-&gt;param(&quot;group_$id&quot;) || 0;
</span><span class="lines">@@ -334,7 +351,7 @@
</span><span class="cx">     delete_token($token);
</span><span class="cx"> 
</span><span class="cx">     $vars-&gt;{'message'} = 'account_updated';
</span><del>-    $vars-&gt;{'changed_fields'} = [keys %changes];
</del><ins>+    $vars-&gt;{'changed_fields'} = [keys %$changes];
</ins><span class="cx">     $vars-&gt;{'groups_added_to'} = \@groupsAddedTo;
</span><span class="cx">     $vars-&gt;{'groups_removed_from'} = \@groupsRemovedFrom;
</span><span class="cx">     $vars-&gt;{'groups_granted_rights_to_bless'} = \@groupsGrantedRightsToBless;
</span><span class="lines">@@ -414,9 +431,6 @@
</span><span class="cx">     $vars-&gt;{'series'} = $dbh-&gt;selectrow_array(
</span><span class="cx">         'SELECT COUNT(*) FROM series WHERE creator = ?',
</span><span class="cx">         undef, $otherUserID);
</span><del>-    $vars-&gt;{'votes'} = $dbh-&gt;selectrow_array(
-        'SELECT COUNT(*) FROM votes WHERE who = ?',
-        undef, $otherUserID);
</del><span class="cx">     $vars-&gt;{'watch'}{'watched'} = $dbh-&gt;selectrow_array(
</span><span class="cx">         'SELECT COUNT(*) FROM watch WHERE watched = ?',
</span><span class="cx">         undef, $otherUserID);
</span><span class="lines">@@ -476,35 +490,36 @@
</span><span class="cx">     my $sth_set_bug_timestamp =
</span><span class="cx">         $dbh-&gt;prepare('UPDATE bugs SET delta_ts = ? WHERE bug_id = ?');
</span><span class="cx"> 
</span><del>-    # Reference removals which need LogActivityEntry.
-    my $statement_flagupdate = 'UPDATE flags set requestee_id = NULL
-                                 WHERE bug_id = ?
-                                   AND attach_id %s
-                                   AND requestee_id = ?';
-    my $sth_flagupdate_attachment =
-        $dbh-&gt;prepare(sprintf($statement_flagupdate, '= ?'));
-    my $sth_flagupdate_bug =
-        $dbh-&gt;prepare(sprintf($statement_flagupdate, 'IS NULL'));
</del><ins>+    my $sth_updateFlag = $dbh-&gt;prepare('INSERT INTO bugs_activity
+                  (bug_id, attach_id, who, bug_when, fieldid, removed, added)
+                  VALUES (?, ?, ?, ?, ?, ?, ?)');
</ins><span class="cx"> 
</span><del>-    my $buglist = $dbh-&gt;selectall_arrayref('SELECT DISTINCT bug_id, attach_id
-                                              FROM flags
-                                             WHERE requestee_id = ?',
-                                           undef, $otherUserID);
</del><ins>+    # Flags
+    my $flag_ids =
+      $dbh-&gt;selectcol_arrayref('SELECT id FROM flags WHERE requestee_id = ?',
+                                undef, $otherUserID);
</ins><span class="cx"> 
</span><del>-    foreach (@$buglist) {
-        my ($bug_id, $attach_id) = @$_;
-        my @old_summaries = Bugzilla::Flag-&gt;snapshot($bug_id, $attach_id);
-        if ($attach_id) {
-            $sth_flagupdate_attachment-&gt;execute($bug_id, $attach_id, $otherUserID);
</del><ins>+    my $flags = Bugzilla::Flag-&gt;new_from_list($flag_ids);
+
+    $dbh-&gt;do('UPDATE flags SET requestee_id = NULL, modification_date = ?
+              WHERE requestee_id = ?', undef, ($timestamp, $otherUserID));
+
+    # We want to remove the requestee but leave the requester alone,
+    # so we have to log these changes manually.
+    my %bugs;
+    push(@{$bugs{$_-&gt;bug_id}-&gt;{$_-&gt;attach_id || 0}}, $_) foreach @$flags;
+    my $fieldid = get_field_id('flagtypes.name');
+    foreach my $bug_id (keys %bugs) {
+        foreach my $attach_id (keys %{$bugs{$bug_id}}) {
+            my @old_summaries = Bugzilla::Flag-&gt;snapshot($bugs{$bug_id}-&gt;{$attach_id});
+            $_-&gt;_set_requestee() foreach @{$bugs{$bug_id}-&gt;{$attach_id}};
+            my @new_summaries = Bugzilla::Flag-&gt;snapshot($bugs{$bug_id}-&gt;{$attach_id});
+            my ($removed, $added) =
+              Bugzilla::Flag-&gt;update_activity(\@old_summaries, \@new_summaries);
+            $sth_updateFlag-&gt;execute($bug_id, $attach_id || undef, $userid,
+                                     $timestamp, $fieldid, $removed, $added);
</ins><span class="cx">         }
</span><del>-        else {
-            $sth_flagupdate_bug-&gt;execute($bug_id, $otherUserID);
-        }
-        my @new_summaries = Bugzilla::Flag-&gt;snapshot($bug_id, $attach_id);
-        # Let update_activity do all the dirty work, including setting
-        # the bug timestamp.
-        Bugzilla::Flag::update_activity($bug_id, $attach_id, $timestamp,
-                                        \@old_summaries, \@new_summaries);
</del><ins>+        $sth_set_bug_timestamp-&gt;execute($timestamp, $bug_id);
</ins><span class="cx">         $updatedbugs{$bug_id} = 1;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -523,18 +538,15 @@
</span><span class="cx">              $otherUserID);
</span><span class="cx">     $dbh-&gt;do('DELETE FROM profiles_activity WHERE userid = ? OR who = ?', undef,
</span><span class="cx">              ($otherUserID, $otherUserID));
</span><del>-    $dbh-&gt;do('UPDATE quips SET userid = NULL where userid = ?', undef, $otherUserID);
</del><span class="cx">     $dbh-&gt;do('DELETE FROM tokens WHERE userid = ?', undef, $otherUserID);
</span><span class="cx">     $dbh-&gt;do('DELETE FROM user_group_map WHERE user_id = ?', undef,
</span><span class="cx">              $otherUserID);
</span><del>-    $dbh-&gt;do('DELETE FROM votes WHERE who = ?', undef, $otherUserID);
</del><span class="cx">     $dbh-&gt;do('DELETE FROM watch WHERE watcher = ? OR watched = ?', undef,
</span><span class="cx">              ($otherUserID, $otherUserID));
</span><span class="cx"> 
</span><span class="cx">     # Deletions in referred tables which need LogActivityEntry.
</span><del>-    $buglist = $dbh-&gt;selectcol_arrayref('SELECT bug_id FROM cc
-                                          WHERE who = ?',
-                                        undef, $otherUserID);
</del><ins>+    my $buglist = $dbh-&gt;selectcol_arrayref('SELECT bug_id FROM cc WHERE who = ?',
+                                            undef, $otherUserID);
</ins><span class="cx">     $dbh-&gt;do('DELETE FROM cc WHERE who = ?', undef, $otherUserID);
</span><span class="cx">     foreach my $bug_id (@$buglist) {
</span><span class="cx">         LogActivityEntry($bug_id, 'cc', $otherUser-&gt;login, '', $userid,
</span><span class="lines">@@ -642,7 +654,7 @@
</span><span class="cx">     # Send mail about what we've done to bugs.
</span><span class="cx">     # The deleted user is not notified of the changes.
</span><span class="cx">     foreach (keys(%updatedbugs)) {
</span><del>-        Bugzilla::BugMail::Send($_, {'changer' =&gt; $user-&gt;login} );
</del><ins>+        Bugzilla::BugMail::Send($_, {'changer' =&gt; $user} );
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> ###########################################################################
</span><span class="lines">@@ -652,7 +664,7 @@
</span><span class="cx">     $vars-&gt;{'profile_changes'} = $dbh-&gt;selectall_arrayref(
</span><span class="cx">         &quot;SELECT profiles.login_name AS who, &quot; .
</span><span class="cx">                 $dbh-&gt;sql_date_format('profiles_activity.profiles_when') . &quot; AS activity_when,
</span><del>-                fielddefs.description AS what,
</del><ins>+                fielddefs.name AS what,
</ins><span class="cx">                 profiles_activity.oldvalue AS removed,
</span><span class="cx">                 profiles_activity.newvalue AS added
</span><span class="cx">          FROM profiles_activity
</span><span class="lines">@@ -670,8 +682,7 @@
</span><span class="cx"> 
</span><span class="cx"> ###########################################################################
</span><span class="cx"> } else {
</span><del>-    $vars-&gt;{'action'} = $action;
-    ThrowCodeError('action_unrecognized', $vars);
</del><ins>+    ThrowUserError('unknown_action', {action =&gt; $action});
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> exit;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgeditvaluescgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/editvalues.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/editvalues.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/editvalues.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -25,81 +25,23 @@
</span><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> use Bugzilla::Error;
</span><span class="cx"> use Bugzilla::Constants;
</span><del>-use Bugzilla::Config qw(:admin);
</del><span class="cx"> use Bugzilla::Token;
</span><span class="cx"> use Bugzilla::Field;
</span><del>-use Bugzilla::Bug;
-use Bugzilla::Status;
</del><ins>+use Bugzilla::Field::Choice;
</ins><span class="cx"> 
</span><del>-# List of different tables that contain the changeable field values
-# (the old &quot;enums.&quot;) Keep them in alphabetical order by their 
-# English name from field-descs.html.tmpl.
-# Format: Array of valid field names.
-our @valid_fields = ('op_sys', 'rep_platform', 'priority', 'bug_severity',
-                     'bug_status', 'resolution');
</del><ins>+###############
+# Subroutines #
+###############
</ins><span class="cx"> 
</span><del>-# Add custom select fields.
-my @custom_fields = Bugzilla-&gt;get_fields({custom =&gt; 1,
-                                          type =&gt; FIELD_TYPE_SINGLE_SELECT});
-push(@custom_fields, Bugzilla-&gt;get_fields({custom =&gt; 1,
-                                          type =&gt; FIELD_TYPE_MULTI_SELECT}));
-
-push(@valid_fields, map { $_-&gt;name } @custom_fields);
-
-######################################################################
-# Subroutines
-######################################################################
-
-# Returns whether or not the specified table exists in the @tables array.
-sub FieldExists {
-  my ($field) = @_;
-
-  return lsearch(\@valid_fields, $field) &gt;= 0;
</del><ins>+sub display_field_values {
+    my $vars = shift;
+    my $template = Bugzilla-&gt;template;
+    $vars-&gt;{'values'} = $vars-&gt;{'field'}-&gt;legal_values;
+    $template-&gt;process(&quot;admin/fieldvalues/list.html.tmpl&quot;, $vars)
+      || ThrowTemplateError($template-&gt;error());
+    exit;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-# Same as FieldExists, but emits and error and dies if it fails.
-sub FieldMustExist {
-    my ($field)= @_;
-
-    $field ||
-        ThrowUserError('fieldname_not_specified');
-
-    # Is it a valid field to be editing?
-    FieldExists($field) ||
-        ThrowUserError('fieldname_invalid', {'field' =&gt; $field});
-
-    return new Bugzilla::Field({name =&gt; $field});
-}
-
-# Returns if the specified value exists for the field specified.
-sub ValueExists {
-    my ($field, $value) = @_;
-    # Value is safe because it's being passed only to a SELECT
-    # statement via a placeholder.
-    trick_taint($value);
-
-    my $dbh = Bugzilla-&gt;dbh;
-    my $value_count = 
-        $dbh-&gt;selectrow_array(&quot;SELECT COUNT(*) FROM $field &quot;
-                           .  &quot; WHERE value = ?&quot;, undef, $value);
-
-    return $value_count;
-}
-
-# Same check as ValueExists, emits an error text and dies if it fails.
-sub ValueMustExist {
-    my ($field, $value)= @_;
-
-    # Values may not be empty (it's very difficult to deal 
-    # with empty values in the admin interface).
-    trim($value) || ThrowUserError('fieldvalue_not_specified');
-
-    # Does it exist in the DB?
-    ValueExists($field, $value) ||
-        ThrowUserError('fieldvalue_doesnt_exist', {'value' =&gt; $value,
-                                                   'field' =&gt; $field});
-}
-
</del><span class="cx"> ######################################################################
</span><span class="cx"> # Main Body Execution
</span><span class="cx"> ######################################################################
</span><span class="lines">@@ -110,7 +52,7 @@
</span><span class="cx"> my $dbh      = Bugzilla-&gt;dbh;
</span><span class="cx"> my $cgi      = Bugzilla-&gt;cgi;
</span><span class="cx"> my $template = Bugzilla-&gt;template;
</span><del>-local our $vars = {};
</del><ins>+my $vars = {};
</ins><span class="cx"> 
</span><span class="cx"> # Replace this entry by separate entries in templates when
</span><span class="cx"> # the documentation about legal values becomes bigger.
</span><span class="lines">@@ -118,7 +60,7 @@
</span><span class="cx"> 
</span><span class="cx"> print $cgi-&gt;header();
</span><span class="cx"> 
</span><del>-exists Bugzilla-&gt;user-&gt;groups-&gt;{'admin'} ||
</del><ins>+Bugzilla-&gt;user-&gt;in_group('admin') ||
</ins><span class="cx">     ThrowUserError('auth_failure', {group  =&gt; &quot;admin&quot;,
</span><span class="cx">                                     action =&gt; &quot;edit&quot;,
</span><span class="cx">                                     object =&gt; &quot;field_values&quot;});
</span><span class="lines">@@ -126,177 +68,81 @@
</span><span class="cx"> #
</span><span class="cx"> # often-used variables
</span><span class="cx"> #
</span><del>-my $field   = trim($cgi-&gt;param('field')   || '');
-my $value   = trim($cgi-&gt;param('value')   || '');
-my $sortkey = trim($cgi-&gt;param('sortkey') || '0');
-my $action  = trim($cgi-&gt;param('action')  || '');
-my $token   = $cgi-&gt;param('token');
</del><ins>+my $action = trim($cgi-&gt;param('action')  || '');
+my $token  = $cgi-&gt;param('token');
</ins><span class="cx"> 
</span><del>-# Gives the name of the parameter associated with the field
-# and representing its default value.
-local our %defaults;
-$defaults{'op_sys'} = 'defaultopsys';
-$defaults{'rep_platform'} = 'defaultplatform';
-$defaults{'priority'} = 'defaultpriority';
-$defaults{'bug_severity'} = 'defaultseverity';
-
-# Alternatively, a list of non-editable values can be specified.
-# In this case, only the sortkey can be altered.
-local our %static;
-$static{'bug_status'} = ['UNCONFIRMED', Bugzilla-&gt;params-&gt;{'duplicate_or_move_bug_status'}];
-$static{'resolution'} = ['', 'FIXED', 'MOVED', 'DUPLICATE'];
-$static{$_-&gt;name} = ['---'] foreach (@custom_fields);
-
</del><span class="cx"> #
</span><span class="cx"> # field = '' -&gt; Show nice list of fields
</span><span class="cx"> #
</span><del>-unless ($field) {
-    # Convert @valid_fields into the format that select-field wants.
-    my @field_list = ();
-    foreach my $field_name (@valid_fields) {
-        push(@field_list, {name =&gt; $field_name});
-    }
</del><ins>+if (!$cgi-&gt;param('field')) {
+    my @field_list =
+        @{ Bugzilla-&gt;fields({ is_select =&gt; 1, is_abnormal =&gt; 0 }) };
</ins><span class="cx"> 
</span><span class="cx">     $vars-&gt;{'fields'} = \@field_list;
</span><del>-    $template-&gt;process(&quot;admin/fieldvalues/select-field.html.tmpl&quot;,
-                       $vars)
</del><ins>+    $template-&gt;process(&quot;admin/fieldvalues/select-field.html.tmpl&quot;, $vars)
</ins><span class="cx">       || ThrowTemplateError($template-&gt;error());
</span><span class="cx">     exit;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-# At this point, the field is defined.
-my $field_obj = FieldMustExist($field);
-$vars-&gt;{'field'} = $field_obj;
-trick_taint($field);
-
-sub display_field_values {
-    my $template = Bugzilla-&gt;template;
-    my $field = $vars-&gt;{'field'}-&gt;name;
-    my $fieldvalues =
-      Bugzilla-&gt;dbh-&gt;selectall_arrayref(&quot;SELECT value AS name, sortkey&quot;
-                                      . &quot;  FROM $field ORDER BY sortkey, value&quot;,
-                                        {Slice =&gt;{}});
-
-    $vars-&gt;{'values'} = $fieldvalues;
-    $vars-&gt;{'default'} = Bugzilla-&gt;params-&gt;{$defaults{$field}} if defined $defaults{$field};
-    $vars-&gt;{'static'} = $static{$field} if exists $static{$field};
-
-    $template-&gt;process(&quot;admin/fieldvalues/list.html.tmpl&quot;, $vars)
-      || ThrowTemplateError($template-&gt;error());
-    exit;
</del><ins>+# At this point, the field must be defined.
+my $field = Bugzilla::Field-&gt;check($cgi-&gt;param('field'));
+if (!$field-&gt;is_select || $field-&gt;is_abnormal) {
+    ThrowUserError('fieldname_invalid', { field =&gt; $field });
</ins><span class="cx"> }
</span><ins>+$vars-&gt;{'field'} = $field;
</ins><span class="cx"> 
</span><span class="cx"> #
</span><span class="cx"> # action='' -&gt; Show nice list of values.
</span><span class="cx"> #
</span><del>-display_field_values() unless $action;
</del><ins>+display_field_values($vars) unless $action;
</ins><span class="cx"> 
</span><span class="cx"> #
</span><span class="cx"> # action='add' -&gt; show form for adding new field value.
</span><span class="cx"> # (next action will be 'new')
</span><span class="cx"> #
</span><span class="cx"> if ($action eq 'add') {
</span><del>-    $vars-&gt;{'value'} = $value;
</del><span class="cx">     $vars-&gt;{'token'} = issue_session_token('add_field_value');
</span><del>-    $template-&gt;process(&quot;admin/fieldvalues/create.html.tmpl&quot;,
-                       $vars)
</del><ins>+    $template-&gt;process(&quot;admin/fieldvalues/create.html.tmpl&quot;, $vars)
</ins><span class="cx">       || ThrowTemplateError($template-&gt;error());
</span><del>-
</del><span class="cx">     exit;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-
</del><span class="cx"> #
</span><span class="cx"> # action='new' -&gt; add field value entered in the 'action=add' screen
</span><span class="cx"> #
</span><span class="cx"> if ($action eq 'new') {
</span><span class="cx">     check_token_data($token, 'add_field_value');
</span><span class="cx"> 
</span><del>-    # Cleanups and validity checks
-    $value || ThrowUserError('fieldvalue_undefined');
</del><ins>+    my $created_value = Bugzilla::Field::Choice-&gt;type($field)-&gt;create({
+        value   =&gt; scalar $cgi-&gt;param('value'), 
+        sortkey =&gt; scalar $cgi-&gt;param('sortkey'),
+        is_open =&gt; scalar $cgi-&gt;param('is_open'),
+        visibility_value_id =&gt; scalar $cgi-&gt;param('visibility_value_id'),
+    });
</ins><span class="cx"> 
</span><del>-    if (length($value) &gt; 60) {
-        ThrowUserError('fieldvalue_name_too_long',
-                       {'value' =&gt; $value});
-    }
-    # Need to store in case detaint_natural() clears the sortkey
-    my $stored_sortkey = $sortkey;
-    if (!detaint_natural($sortkey)) {
-        ThrowUserError('fieldvalue_sortkey_invalid',
-                       {'name' =&gt; $field,
-                        'sortkey' =&gt; $stored_sortkey});
-    }
-    if (ValueExists($field, $value)) {
-        ThrowUserError('fieldvalue_already_exists',
-                       {'field' =&gt; $field_obj,
-                        'value' =&gt; $value});
-    }
-    if ($field eq 'bug_status'
-        &amp;&amp; (grep { lc($value) eq $_ } SPECIAL_STATUS_WORKFLOW_ACTIONS))
-    {
-        $vars-&gt;{'value'} = $value;
-        ThrowUserError('fieldvalue_reserved_word', $vars);
-    }
-
-    # Value is only used in a SELECT placeholder and through the HTML filter.
-    trick_taint($value);
-
-    # Add the new field value.
-    $dbh-&gt;do(&quot;INSERT INTO $field (value, sortkey) VALUES (?, ?)&quot;,
-             undef, ($value, $sortkey));
-
-    if ($field eq 'bug_status') {
-        unless ($cgi-&gt;param('is_open')) {
-            # The bug status is a closed state, but they are open by default.
-            $dbh-&gt;do('UPDATE bug_status SET is_open = 0 WHERE value = ?', undef, $value);
-        }
-        # Allow the transition from this new bug status to the one used
-        # by the 'duplicate_or_move_bug_status' parameter.
-        Bugzilla::Status::add_missing_bug_status_transitions();
-    }
-
</del><span class="cx">     delete_token($token);
</span><span class="cx"> 
</span><span class="cx">     $vars-&gt;{'message'} = 'field_value_created';
</span><del>-    $vars-&gt;{'value'} = $value;
-    display_field_values();
</del><ins>+    $vars-&gt;{'value'} = $created_value;
+    display_field_values($vars);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# After this, we always have a value
+my $value = Bugzilla::Field::Choice-&gt;type($field)-&gt;check($cgi-&gt;param('value'));
+$vars-&gt;{'value'} = $value;
</ins><span class="cx"> 
</span><span class="cx"> #
</span><span class="cx"> # action='del' -&gt; ask if user really wants to delete
</span><span class="cx"> # (next action would be 'delete')
</span><span class="cx"> #
</span><span class="cx"> if ($action eq 'del') {
</span><del>-    ValueMustExist($field, $value);
-    trick_taint($value);
-
-    # See if any bugs are still using this value.
-    if ($field_obj-&gt;type != FIELD_TYPE_MULTI_SELECT) {
-        $vars-&gt;{'bug_count'} =
-            $dbh-&gt;selectrow_array(&quot;SELECT COUNT(*) FROM bugs WHERE $field = ?&quot;,
-                                  undef, $value);
-    }
-    else {
-        $vars-&gt;{'bug_count'} =
-            $dbh-&gt;selectrow_array(&quot;SELECT COUNT(*) FROM bug_$field WHERE value = ?&quot;,
-                                  undef, $value);
-    }
-
-    $vars-&gt;{'value_count'} =
-        $dbh-&gt;selectrow_array(&quot;SELECT COUNT(*) FROM $field&quot;);
-
-    $vars-&gt;{'value'} = $value;
-    $vars-&gt;{'param_name'} = $defaults{$field};
-
</del><span class="cx">     # If the value cannot be deleted, throw an error.
</span><del>-    if (lsearch($static{$field}, $value) &gt;= 0) {
</del><ins>+    if ($value-&gt;is_static) {
</ins><span class="cx">         ThrowUserError('fieldvalue_not_deletable', $vars);
</span><span class="cx">     }
</span><span class="cx">     $vars-&gt;{'token'} = issue_session_token('delete_field_value');
</span><span class="cx"> 
</span><del>-    $template-&gt;process(&quot;admin/fieldvalues/confirm-delete.html.tmpl&quot;,
-                       $vars)
</del><ins>+    $template-&gt;process(&quot;admin/fieldvalues/confirm-delete.html.tmpl&quot;, $vars)
</ins><span class="cx">       || ThrowTemplateError($template-&gt;error());
</span><span class="cx"> 
</span><span class="cx">     exit;
</span><span class="lines">@@ -308,63 +154,11 @@
</span><span class="cx"> #
</span><span class="cx"> if ($action eq 'delete') {
</span><span class="cx">     check_token_data($token, 'delete_field_value');
</span><del>-    ValueMustExist($field, $value);
-
-    $vars-&gt;{'value'} = $value;
-    $vars-&gt;{'param_name'} = $defaults{$field};
-
-    if (defined $defaults{$field}
-        &amp;&amp; ($value eq Bugzilla-&gt;params-&gt;{$defaults{$field}}))
-    {
-        ThrowUserError('fieldvalue_is_default', $vars);
-    }
-    # If the value cannot be deleted, throw an error.
-    if (lsearch($static{$field}, $value) &gt;= 0) {
-        ThrowUserError('fieldvalue_not_deletable', $vars);
-    }
-
-    trick_taint($value);
-
-    $dbh-&gt;bz_start_transaction();
-
-    # Check if there are any bugs that still have this value.
-    my $bug_count;
-    if ($field_obj-&gt;type != FIELD_TYPE_MULTI_SELECT) {
-        $bug_count =
-            $dbh-&gt;selectrow_array(&quot;SELECT COUNT(*) FROM bugs WHERE $field = ?&quot;,
-                                  undef, $value);
-    }
-    else {
-        $bug_count =
-            $dbh-&gt;selectrow_array(&quot;SELECT COUNT(*) FROM bug_$field WHERE value = ?&quot;,
-                                  undef, $value);
-    }
-
-
-    if ($bug_count) {
-        # You tried to delete a field that bugs are still using.
-        # You can't just delete the bugs. That's ridiculous. 
-        ThrowUserError(&quot;fieldvalue_still_has_bugs&quot;, 
-                       { field =&gt; $field, value =&gt; $value,
-                         count =&gt; $bug_count });
-    }
-
-    if ($field eq 'bug_status') {
-        my ($status_id) = $dbh-&gt;selectrow_array(
-            'SELECT id FROM bug_status WHERE value = ?', undef, $value);
-        $dbh-&gt;do('DELETE FROM status_workflow
-                  WHERE old_status = ? OR new_status = ?',
-                  undef, ($status_id, $status_id));
-    }
-
-    $dbh-&gt;do(&quot;DELETE FROM $field WHERE value = ?&quot;, undef, $value);
-
-    $dbh-&gt;bz_commit_transaction();
</del><ins>+    $value-&gt;remove_from_db();
</ins><span class="cx">     delete_token($token);
</span><del>-
</del><span class="cx">     $vars-&gt;{'message'} = 'field_value_deleted';
</span><span class="cx">     $vars-&gt;{'no_edit_link'} = 1;
</span><del>-    display_field_values();
</del><ins>+    display_field_values($vars);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -373,20 +167,7 @@
</span><span class="cx"> # (next action would be 'update')
</span><span class="cx"> #
</span><span class="cx"> if ($action eq 'edit') {
</span><del>-    ValueMustExist($field, $value);
-    trick_taint($value);
-
-    $vars-&gt;{'sortkey'} = $dbh-&gt;selectrow_array(
-        &quot;SELECT sortkey FROM $field WHERE value = ?&quot;, undef, $value) || 0;
-
-    $vars-&gt;{'value'} = $value;
-    $vars-&gt;{'is_static'} = (lsearch($static{$field}, $value) &gt;= 0) ? 1 : 0;
</del><span class="cx">     $vars-&gt;{'token'} = issue_session_token('edit_field_value');
</span><del>-    if ($field eq 'bug_status') {
-        $vars-&gt;{'is_open'} = $dbh-&gt;selectrow_array('SELECT is_open FROM bug_status
-                                                    WHERE value = ?', undef, $value);
-    }
-
</del><span class="cx">     $template-&gt;process(&quot;admin/fieldvalues/edit.html.tmpl&quot;, $vars)
</span><span class="cx">       || ThrowTemplateError($template-&gt;error());
</span><span class="cx"> 
</span><span class="lines">@@ -399,99 +180,18 @@
</span><span class="cx"> #
</span><span class="cx"> if ($action eq 'update') {
</span><span class="cx">     check_token_data($token, 'edit_field_value');
</span><del>-    my $valueold   = trim($cgi-&gt;param('valueold')   || '');
-    my $sortkeyold = trim($cgi-&gt;param('sortkeyold') || '0');
-
-    ValueMustExist($field, $valueold);
-    trick_taint($valueold);
-
-    $vars-&gt;{'value'} = $value;
-    # If the value cannot be renamed, throw an error.
-    if (lsearch($static{$field}, $valueold) &gt;= 0 &amp;&amp; $value ne $valueold) {
-        $vars-&gt;{'old_value'} = $valueold;
-        ThrowUserError('fieldvalue_not_editable', $vars);
</del><ins>+    $vars-&gt;{'value_old'} = $value-&gt;name;
+    if ($cgi-&gt;should_set('is_active')) {
+        $value-&gt;set_is_active($cgi-&gt;param('is_active'));
</ins><span class="cx">     }
</span><del>-
-    if (length($value) &gt; 60) {
-        ThrowUserError('fieldvalue_name_too_long', $vars);
-    }
-
-    $dbh-&gt;bz_start_transaction();
-
-    # Need to store because detaint_natural() will delete this if
-    # invalid
-    my $stored_sortkey = $sortkey;
-    if ($sortkey != $sortkeyold) {
-
-        if (!detaint_natural($sortkey)) {
-            ThrowUserError('fieldvalue_sortkey_invalid',
-                           {'name' =&gt; $field,
-                            'sortkey' =&gt; $stored_sortkey});
-
-        }
-
-        $dbh-&gt;do(&quot;UPDATE $field SET sortkey = ? WHERE value = ?&quot;,
-                 undef, $sortkey, $valueold);
-
-        $vars-&gt;{'updated_sortkey'} = 1;
-        $vars-&gt;{'sortkey'} = $sortkey;
-    }
-
-    if ($value ne $valueold) {
-
-        unless ($value) {
-            ThrowUserError('fieldvalue_undefined');
-        }
-        if (ValueExists($field, $value)) {
-            ThrowUserError('fieldvalue_already_exists', $vars);
-        }
-        if ($field eq 'bug_status'
-            &amp;&amp; (grep { lc($value) eq $_ } SPECIAL_STATUS_WORKFLOW_ACTIONS))
-        {
-            $vars-&gt;{'value'} = $value;
-            ThrowUserError('fieldvalue_reserved_word', $vars);
-        }
-        trick_taint($value);
-
-        if ($field_obj-&gt;type != FIELD_TYPE_MULTI_SELECT) {
-            $dbh-&gt;do(&quot;UPDATE bugs SET $field = ? WHERE $field = ?&quot;,
-                     undef, $value, $valueold);
-        }
-        else {
-            $dbh-&gt;do(&quot;UPDATE bug_$field SET value = ? WHERE value = ?&quot;,
-                     undef, $value, $valueold);
-        }
-
-        $dbh-&gt;do(&quot;UPDATE $field SET value = ? WHERE value = ?&quot;,
-                 undef, $value, $valueold);
-
-        $vars-&gt;{'updated_value'} = 1;
-    }
-
-    $dbh-&gt;bz_commit_transaction();
-
-    # If the old value was the default value for the field,
-    # update data/params accordingly.
-    # This update is done while tables are unlocked due to the
-    # annoying calls in Bugzilla/Config/Common.pm.
-    if (defined $defaults{$field}
-        &amp;&amp; $value ne $valueold
-        &amp;&amp; $valueold eq Bugzilla-&gt;params-&gt;{$defaults{$field}})
-    {
-        SetParam($defaults{$field}, $value);
-        write_params();
-        $vars-&gt;{'default_value_updated'} = 1;
-    }
</del><ins>+    $value-&gt;set_name($cgi-&gt;param('value_new'));
+    $value-&gt;set_sortkey($cgi-&gt;param('sortkey'));
+    $value-&gt;set_visibility_value($cgi-&gt;param('visibility_value_id'));
+    $vars-&gt;{'changes'} = $value-&gt;update();
</ins><span class="cx">     delete_token($token);
</span><del>-
</del><span class="cx">     $vars-&gt;{'message'} = 'field_value_updated';
</span><del>-    display_field_values();
</del><ins>+    display_field_values($vars);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-
-#
</del><span class="cx"> # No valid action found
</span><del>-#
-# We can't get here without $field being defined --
-# See the unless($field) block at the top.
-ThrowUserError('no_valid_action', { field =&gt; $field } );
</del><ins>+ThrowUserError('unknown_action', {action =&gt; $action});
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgeditversionscgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/editversions.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/editversions.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/editversions.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -63,6 +63,7 @@
</span><span class="cx"> my $action       = trim($cgi-&gt;param('action')  || '');
</span><span class="cx"> my $showbugcounts = (defined $cgi-&gt;param('showbugcounts'));
</span><span class="cx"> my $token        = $cgi-&gt;param('token');
</span><ins>+my $isactive     = $cgi-&gt;param('isactive');
</ins><span class="cx"> 
</span><span class="cx"> #
</span><span class="cx"> # product = '' -&gt; Show nice list of products
</span><span class="lines">@@ -119,7 +120,8 @@
</span><span class="cx"> 
</span><span class="cx"> if ($action eq 'new') {
</span><span class="cx">     check_token_data($token, 'add_version');
</span><del>-    my $version = Bugzilla::Version::create($version_name, $product);
</del><ins>+    my $version = Bugzilla::Version-&gt;create(
+        { value =&gt; $version_name, product =&gt; $product });
</ins><span class="cx">     delete_token($token);
</span><span class="cx"> 
</span><span class="cx">     $vars-&gt;{'message'} = 'version_created';
</span><span class="lines">@@ -202,7 +204,9 @@
</span><span class="cx"> 
</span><span class="cx">     $dbh-&gt;bz_start_transaction();
</span><span class="cx"> 
</span><del>-    $vars-&gt;{'updated'} = $version-&gt;update($version_name, $product);
</del><ins>+    $version-&gt;set_name($version_name);
+    $version-&gt;set_is_active($isactive);
+    my $changes = $version-&gt;update();
</ins><span class="cx"> 
</span><span class="cx">     $dbh-&gt;bz_commit_transaction();
</span><span class="cx">     delete_token($token);
</span><span class="lines">@@ -210,13 +214,12 @@
</span><span class="cx">     $vars-&gt;{'message'} = 'version_updated';
</span><span class="cx">     $vars-&gt;{'version'} = $version;
</span><span class="cx">     $vars-&gt;{'product'} = $product;
</span><ins>+    $vars-&gt;{'changes'} = $changes;
</ins><span class="cx">     $template-&gt;process(&quot;admin/versions/list.html.tmpl&quot;, $vars)
</span><span class="cx">       || ThrowTemplateError($template-&gt;error());
</span><span class="cx"> 
</span><span class="cx">     exit;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-#
</del><span class="cx"> # No valid action found
</span><del>-#
-ThrowUserError('no_valid_action', {'field' =&gt; &quot;version&quot;});
</del><ins>+ThrowUserError('unknown_action', {action =&gt; $action});
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgeditwhinescgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/editwhines.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/editwhines.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/editwhines.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -36,6 +36,9 @@
</span><span class="cx"> use Bugzilla::User;
</span><span class="cx"> use Bugzilla::Group;
</span><span class="cx"> use Bugzilla::Token;
</span><ins>+use Bugzilla::Whine::Schedule;
+use Bugzilla::Whine::Query;
+use Bugzilla::Whine;
</ins><span class="cx"> 
</span><span class="cx"> # require the user to have logged in
</span><span class="cx"> my $user = Bugzilla-&gt;login(LOGIN_REQUIRED);
</span><span class="lines">@@ -53,10 +56,8 @@
</span><span class="cx"> my $token    = $cgi-&gt;param('token');
</span><span class="cx"> my $sth; # database statement handle
</span><span class="cx"> 
</span><del>-# $events is a hash ref, keyed by event id, that stores the active user's
-# events.  It starts off with:
-#  'subject' - the subject line for the email message
-#  'body'    - the text to be sent at the top of the message
</del><ins>+# $events is a hash ref of Bugzilla::Whine objects keyed by event id,
+# that stores the active user's events.
</ins><span class="cx"> #
</span><span class="cx"> # Eventually, it winds up with:
</span><span class="cx"> #  'queries'  - array ref containing hashes of:
</span><span class="lines">@@ -104,20 +105,11 @@
</span><span class="cx">                 # otherwise we could simply delete whatever matched that ID.
</span><span class="cx">                 #
</span><span class="cx">                 # schedules
</span><del>-                $sth = $dbh-&gt;prepare(&quot;SELECT whine_schedules.id &quot; .
-                                     &quot;FROM whine_schedules &quot; .
-                                     &quot;LEFT JOIN whine_events &quot; .
-                                     &quot;ON whine_events.id = &quot; .
-                                     &quot;whine_schedules.eventid &quot; .
-                                     &quot;WHERE whine_events.id = ? &quot; .
-                                     &quot;AND whine_events.owner_userid = ?&quot;);
-                $sth-&gt;execute($eventid, $userid);
-                my @ids = @{$sth-&gt;fetchall_arrayref};
</del><ins>+                my $schedules = Bugzilla::Whine::Schedule-&gt;match({ eventid =&gt; $eventid });
</ins><span class="cx">                 $sth = $dbh-&gt;prepare(&quot;DELETE FROM whine_schedules &quot;
</span><span class="cx">                     . &quot;WHERE id=?&quot;);
</span><del>-                for (@ids) {
-                    my $delete_id = $_-&gt;[0];
-                    $sth-&gt;execute($delete_id);
</del><ins>+                foreach my $schedule (@$schedules) {                    
+                    $sth-&gt;execute($schedule-&gt;id);
</ins><span class="cx">                 }
</span><span class="cx"> 
</span><span class="cx">                 # queries
</span><span class="lines">@@ -129,7 +121,7 @@
</span><span class="cx">                                      &quot;WHERE whine_events.id = ? &quot; .
</span><span class="cx">                                      &quot;AND whine_events.owner_userid = ?&quot;);
</span><span class="cx">                 $sth-&gt;execute($eventid, $userid);
</span><del>-                @ids = @{$sth-&gt;fetchall_arrayref};
</del><ins>+                my @ids = @{$sth-&gt;fetchall_arrayref};
</ins><span class="cx">                 $sth = $dbh-&gt;prepare(&quot;DELETE FROM whine_queries &quot; .
</span><span class="cx">                                      &quot;WHERE id=?&quot;);
</span><span class="cx">                 for (@ids) {
</span><span class="lines">@@ -143,20 +135,22 @@
</span><span class="cx">                 $sth-&gt;execute($eventid, $userid);
</span><span class="cx">             }
</span><span class="cx">             else {
</span><del>-                # check the subject and body for changes
</del><ins>+                # check the subject, body and mailifnobugs for changes
</ins><span class="cx">                 my $subject = ($cgi-&gt;param(&quot;event_${eventid}_subject&quot;) or '');
</span><span class="cx">                 my $body    = ($cgi-&gt;param(&quot;event_${eventid}_body&quot;)    or '');
</span><ins>+                my $mailifnobugs = $cgi-&gt;param(&quot;event_${eventid}_mailifnobugs&quot;) ? 1 : 0;
</ins><span class="cx"> 
</span><span class="cx">                 trick_taint($subject) if $subject;
</span><span class="cx">                 trick_taint($body)    if $body;
</span><span class="cx"> 
</span><del>-                if ( ($subject ne $events-&gt;{$eventid}-&gt;{'subject'})
-                  || ($body    ne $events-&gt;{$eventid}-&gt;{'body'}) ) {
</del><ins>+                if ( ($subject ne $events-&gt;{$eventid}-&gt;subject)
+                  || ($mailifnobugs != $events-&gt;{$eventid}-&gt;mail_if_no_bugs)
+                  || ($body    ne $events-&gt;{$eventid}-&gt;body) ) {
</ins><span class="cx"> 
</span><span class="cx">                     $sth = $dbh-&gt;prepare(&quot;UPDATE whine_events &quot; .
</span><del>-                                         &quot;SET subject=?, body=? &quot; .
</del><ins>+                                         &quot;SET subject=?, body=?, mailifnobugs=? &quot; .
</ins><span class="cx">                                          &quot;WHERE id=?&quot;);
</span><del>-                    $sth-&gt;execute($subject, $body, $eventid);
</del><ins>+                    $sth-&gt;execute($subject, $body, $mailifnobugs, $eventid);
</ins><span class="cx">                 }
</span><span class="cx"> 
</span><span class="cx">                 # add a schedule
</span><span class="lines">@@ -181,13 +175,10 @@
</span><span class="cx">             # to be altered or deleted
</span><span class="cx"> 
</span><span class="cx">             # Check schedules for changes
</span><del>-            $sth = $dbh-&gt;prepare(&quot;SELECT id &quot; .
-                                 &quot;FROM whine_schedules &quot; .
-                                 &quot;WHERE eventid=?&quot;);
-            $sth-&gt;execute($eventid);
</del><ins>+            my $schedules = Bugzilla::Whine::Schedule-&gt;match({ eventid =&gt; $eventid });
</ins><span class="cx">             my @scheduleids = ();
</span><del>-            while (my ($sid) = $sth-&gt;fetchrow_array) {
-                push @scheduleids, $sid;
</del><ins>+            foreach my $schedule (@$schedules) {
+                push @scheduleids, $schedule-&gt;id;
</ins><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             # we need to double-check all of the user IDs in mailto to make
</span><span class="lines">@@ -201,7 +192,7 @@
</span><span class="cx">                 }
</span><span class="cx">             }
</span><span class="cx">             if (scalar %{$arglist}) {
</span><del>-                &amp;Bugzilla::User::match_field($cgi, $arglist);
</del><ins>+                Bugzilla::User::match_field($arglist);
</ins><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             for my $sid (@scheduleids) {
</span><span class="lines">@@ -238,7 +229,6 @@
</span><span class="cx">                     # get an id for the mailto address
</span><span class="cx">                     if ($can_mail_others &amp;&amp; $mailto) {
</span><span class="cx">                         if ($mailto_type == MAILTO_USER) {
</span><del>-                            # The user login has already been validated.
</del><span class="cx">                             $mailto_id = login_to_id($mailto);
</span><span class="cx">                         }
</span><span class="cx">                         elsif ($mailto_type == MAILTO_GROUP) {
</span><span class="lines">@@ -277,16 +267,9 @@
</span><span class="cx">             }
</span><span class="cx"> 
</span><span class="cx">             # Check queries for changes
</span><del>-            $sth = $dbh-&gt;prepare(&quot;SELECT id &quot; .
-                                 &quot;FROM whine_queries &quot; .
-                                 &quot;WHERE eventid=?&quot;);
-            $sth-&gt;execute($eventid);
-            my @queries = ();
-            while (my ($qid) = $sth-&gt;fetchrow_array) {
-                push @queries, $qid;
-            }
-
-            for my $qid (@queries) {
</del><ins>+            my $queries = Bugzilla::Whine::Query-&gt;match({ eventid =&gt; $eventid });
+            for my $query (@$queries) {
+                my $qid = $query-&gt;id;
</ins><span class="cx">                 if ($cgi-&gt;param(&quot;remove_query_$qid&quot;)) {
</span><span class="cx"> 
</span><span class="cx">                     $sth = $dbh-&gt;prepare(&quot;SELECT whine_queries.id &quot; .
</span><span class="lines">@@ -364,55 +347,43 @@
</span><span class="cx"> #
</span><span class="cx"> # build the whine list by event id
</span><span class="cx"> for my $event_id (keys %{$events}) {
</span><del>-
</del><span class="cx">     $events-&gt;{$event_id}-&gt;{'schedule'} = [];
</span><span class="cx">     $events-&gt;{$event_id}-&gt;{'queries'} = [];
</span><span class="cx"> 
</span><span class="cx">     # schedules
</span><del>-    $sth = $dbh-&gt;prepare(&quot;SELECT run_day, run_time, mailto_type, mailto, id &quot; .
-                         &quot;FROM whine_schedules &quot; .
-                         &quot;WHERE eventid=?&quot;);
-    $sth-&gt;execute($event_id);
-    for my $row (@{$sth-&gt;fetchall_arrayref}) {
-        my $mailto_type = $row-&gt;[2];
</del><ins>+    my $schedules = Bugzilla::Whine::Schedule-&gt;match({ eventid =&gt; $event_id });
+    foreach my $schedule (@$schedules) {
+        my $mailto_type = $schedule-&gt;mailto_is_group ? MAILTO_GROUP 
+                                                     : MAILTO_USER;
</ins><span class="cx">         my $mailto = '';
</span><span class="cx">         if ($mailto_type == MAILTO_USER) {
</span><del>-            my $mailto_user = new Bugzilla::User($row-&gt;[3]);
-            $mailto = $mailto_user-&gt;login;
</del><ins>+            $mailto = $schedule-&gt;mailto-&gt;login;
</ins><span class="cx">         }
</span><span class="cx">         elsif ($mailto_type == MAILTO_GROUP) {
</span><del>-            $sth = $dbh-&gt;prepare(&quot;SELECT name FROM groups WHERE id=?&quot;);
-            $sth-&gt;execute($row-&gt;[3]);
-            $mailto = $sth-&gt;fetch-&gt;[0];
-            $mailto = &quot;&quot; unless Bugzilla::Group::ValidateGroupName(
-                                $mailto, ($user));
</del><ins>+            $mailto = $schedule-&gt;mailto-&gt;name;
</ins><span class="cx">         }
</span><del>-        my $this_schedule = {
-            'day'         =&gt; $row-&gt;[0],
-            'time'        =&gt; $row-&gt;[1],
-            'mailto_type' =&gt; $mailto_type,
-            'mailto'      =&gt; $mailto,
-            'id'          =&gt; $row-&gt;[4],
-        };
-        push @{$events-&gt;{$event_id}-&gt;{'schedule'}}, $this_schedule;
</del><ins>+
+        push @{$events-&gt;{$event_id}-&gt;{'schedule'}},
+             {
+                 'day'         =&gt; $schedule-&gt;run_day,
+                 'time'        =&gt; $schedule-&gt;run_time,
+                 'mailto_type' =&gt; $mailto_type,
+                 'mailto'      =&gt; $mailto,
+                 'id'          =&gt; $schedule-&gt;id,
+             };
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # queries
</span><del>-    $sth = $dbh-&gt;prepare(&quot;SELECT query_name, title, sortkey, id, &quot; .
-                         &quot;onemailperbug &quot; .
-                         &quot;FROM whine_queries &quot; .
-                         &quot;WHERE eventid=? &quot; .
-                         &quot;ORDER BY sortkey&quot;);
-    $sth-&gt;execute($event_id);
-    for my $row (@{$sth-&gt;fetchall_arrayref}) {
-        my $this_query = {
-            'name'          =&gt; $row-&gt;[0],
-            'title'         =&gt; $row-&gt;[1],
-            'sort'          =&gt; $row-&gt;[2],
-            'id'            =&gt; $row-&gt;[3],
-            'onemailperbug' =&gt; $row-&gt;[4],
-        };
-        push @{$events-&gt;{$event_id}-&gt;{'queries'}}, $this_query;
</del><ins>+    my $queries = Bugzilla::Whine::Query-&gt;match({ eventid =&gt; $event_id });
+    for my $query (@$queries) {
+        push @{$events-&gt;{$event_id}-&gt;{'queries'}}, 
+             {
+                 'name'          =&gt; $query-&gt;name,
+                 'title'         =&gt; $query-&gt;title,
+                 'sort'          =&gt; $query-&gt;sortkey,
+                 'id'            =&gt; $query-&gt;id,
+                 'onemailperbug' =&gt; $query-&gt;one_email_per_bug,
+             };
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -427,27 +398,18 @@
</span><span class="cx">     push @{$vars-&gt;{'available_queries'}}, $query;
</span><span class="cx"> }
</span><span class="cx"> $vars-&gt;{'token'} = issue_session_token('edit_whine');
</span><ins>+$vars-&gt;{'local_timezone'} = Bugzilla-&gt;local_timezone-&gt;short_name_for_datetime(DateTime-&gt;now());
</ins><span class="cx"> 
</span><span class="cx"> $template-&gt;process(&quot;whine/schedule.html.tmpl&quot;, $vars)
</span><span class="cx">   || ThrowTemplateError($template-&gt;error());
</span><span class="cx"> 
</span><del>-# get_events takes a userid and returns a hash, keyed by event ID, containing
-# the subject and body of each event that user owns
</del><ins>+# get_events takes a userid and returns a hash of
+# Bugzilla::Whine objects keyed by event ID.
</ins><span class="cx"> sub get_events {
</span><span class="cx">     my $userid = shift;
</span><del>-    my $dbh = Bugzilla-&gt;dbh;
-    my $events = {};
</del><ins>+    my $event_rows = Bugzilla::Whine-&gt;match({ owner_userid =&gt; $userid });
+    my %events = map { $_-&gt;{id} =&gt; $_ } @$event_rows;
</ins><span class="cx"> 
</span><del>-    my $sth = $dbh-&gt;prepare(&quot;SELECT DISTINCT id, subject, body &quot; .
-                            &quot;FROM whine_events &quot; .
-                            &quot;WHERE owner_userid=?&quot;);
-    $sth-&gt;execute($userid);
-    while (my ($ev, $sub, $bod) = $sth-&gt;fetchrow_array) {
-        $events-&gt;{$ev} = {
-            'subject' =&gt; $sub || '',
-            'body' =&gt; $bod || '',
-        };
-    }
-    return $events;
</del><ins>+    return \%events;
</ins><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgeditworkflowcgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/editworkflow.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/editworkflow.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/editworkflow.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -147,5 +147,5 @@
</span><span class="cx">     load_template('comment', 'workflow_updated');
</span><span class="cx"> }
</span><span class="cx"> else {
</span><del>-    ThrowCodeError(&quot;action_unrecognized&quot;, {action =&gt; $action});
</del><ins>+    ThrowUserError('unknown_action', {action =&gt; $action});
</ins><span class="cx"> }
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgemail_inpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/email_in.pl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/email_in.pl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/email_in.pl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +1,4 @@
</span><del>-#!/usr/bin/env perl -w
</del><ins>+#!/usr/bin/env perl -wT
</ins><span class="cx"> # -*- Mode: perl; indent-tabs-mode: nil -*-
</span><span class="cx"> #
</span><span class="cx"> # The contents of this file are subject to the Mozilla Public
</span><span class="lines">@@ -24,9 +24,12 @@
</span><span class="cx"> 
</span><span class="cx"> # MTAs may call this script from any directory, but it should always
</span><span class="cx"> # run from this one so that it can find its modules.
</span><ins>+use Cwd qw(abs_path);
+use File::Basename qw(dirname);
</ins><span class="cx"> BEGIN {
</span><del>-    require File::Basename;
-    chdir(File::Basename::dirname($0)); 
</del><ins>+    # Untaint the abs_path.
+    my ($a) = abs_path($0) =~ /^(.*)$/;
+    chdir dirname($a);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> use lib qw(. lib);
</span><span class="lines">@@ -39,15 +42,19 @@
</span><span class="cx"> use Getopt::Long qw(:config bundling);
</span><span class="cx"> use Pod::Usage;
</span><span class="cx"> use Encode;
</span><ins>+use Scalar::Util qw(blessed);
</ins><span class="cx"> 
</span><span class="cx"> use Bugzilla;
</span><del>-use Bugzilla::Bug qw(ValidateBugID);
-use Bugzilla::Constants qw(USAGE_MODE_EMAIL);
</del><ins>+use Bugzilla::Attachment;
+use Bugzilla::Bug;
+use Bugzilla::BugMail;
+use Bugzilla::Constants;
</ins><span class="cx"> use Bugzilla::Error;
</span><span class="cx"> use Bugzilla::Mailer;
</span><ins>+use Bugzilla::Token;
</ins><span class="cx"> use Bugzilla::User;
</span><span class="cx"> use Bugzilla::Util;
</span><del>-use Bugzilla::Token;
</del><ins>+use Bugzilla::Hook;
</ins><span class="cx"> 
</span><span class="cx"> #############
</span><span class="cx"> # Constants #
</span><span class="lines">@@ -69,17 +76,24 @@
</span><span class="cx">     debug_print('Parsing Email');
</span><span class="cx">     $input_email = Email::MIME-&gt;new($mail_text);
</span><span class="cx">     
</span><del>-    my %fields;
</del><ins>+    my %fields = %{ $switch{'default'} || {} };
+    Bugzilla::Hook::process('email_in_before_parse', { mail =&gt; $input_email,
+                                                       fields =&gt; \%fields });
</ins><span class="cx"> 
</span><del>-    # Email::Address-&gt;parse returns an array
-    my ($reporter) = Email::Address-&gt;parse($input_email-&gt;header('From'));
-    $fields{'reporter'} = $reporter-&gt;address;
</del><span class="cx">     my $summary = $input_email-&gt;header('Subject');
</span><del>-    if ($summary =~ /\[Bug (\d+)\](.*)/i) {
</del><ins>+    if ($summary =~ /\[\S+ (\d+)\](.*)/i) {
</ins><span class="cx">         $fields{'bug_id'} = $1;
</span><span class="cx">         $summary = trim($2);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    # Ignore automatic replies.
+    # XXX - Improve the way to detect such subjects in different languages.
+    my $auto_submitted = $input_email-&gt;header('Auto-Submitted') || '';
+    if ($summary =~ /out of( the)? office/i || $auto_submitted eq 'auto-replied') {
+        debug_print(&quot;Automatic reply detected: $summary&quot;);
+        exit;
+    }
+
</ins><span class="cx">     my ($body, $attachments) = get_body_and_attachments($input_email);
</span><span class="cx">     if (@$attachments) {
</span><span class="cx">         $fields{'attachments'} = $attachments;
</span><span class="lines">@@ -104,19 +118,8 @@
</span><span class="cx">             # Otherwise, we stop parsing fields on the first blank line.
</span><span class="cx">             $line = trim($line);
</span><span class="cx">             last if !$line;
</span><del>-            
-            if ($line =~ /^@(\S+)\s*=\s*(.*)\s*/) {
</del><ins>+            if ($line =~ /^\@(\w+)\s*(?:=|\s|$)\s*(.*)\s*/) {
</ins><span class="cx">                 $current_field = lc($1);
</span><del>-                # It's illegal to pass the reporter field as you could
-                # override the &quot;From:&quot; field of the message and bypass
-                # authentication checks, such as PGP.
-                if ($current_field eq 'reporter') {
-                    # We reset the $current_field variable to something
-                    # post_bug and process_bug will ignore, in case the
-                    # attacker splits the reporter field on several lines.
-                    $current_field = 'illegal_field';
-                    next;
-                }
</del><span class="cx">                 $fields{$current_field} = $2;
</span><span class="cx">             }
</span><span class="cx">             else {
</span><span class="lines">@@ -125,7 +128,11 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    %fields = %{ Bugzilla::Bug::map_fields(\%fields) };
</ins><span class="cx"> 
</span><ins>+    my ($reporter) = Email::Address-&gt;parse($input_email-&gt;header('From'));
+    $fields{'reporter'} = $reporter-&gt;address;
+
</ins><span class="cx">     # The summary line only affects us if we're doing a post_bug.
</span><span class="cx">     # We have to check it down here because there might have been
</span><span class="cx">     # a bug_id specified in the body of the email.
</span><span class="lines">@@ -141,30 +148,47 @@
</span><span class="cx">     }
</span><span class="cx">     $fields{'comment'} = $comment;
</span><span class="cx"> 
</span><ins>+    my %override = %{ $switch{'override'} || {} };
+    foreach my $key (keys %override) {
+        $fields{$key} = $override{$key};
+    }
+
</ins><span class="cx">     debug_print(&quot;Parsed Fields:\n&quot; . Dumper(\%fields), 2);
</span><span class="cx"> 
</span><span class="cx">     return \%fields;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub post_bug {
-    my ($fields_in) = @_;
-    my %fields = %$fields_in;
</del><ins>+sub check_email_fields {
+    my ($fields) = @_;
</ins><span class="cx"> 
</span><del>-    debug_print('Posting a new bug...');
</del><ins>+    my ($retval, $non_conclusive_fields) =
+      Bugzilla::User::match_field({
+        'assigned_to'   =&gt; { 'type' =&gt; 'single' },
+        'qa_contact'    =&gt; { 'type' =&gt; 'single' },
+        'cc'            =&gt; { 'type' =&gt; 'multi'  },
+        'newcc'         =&gt; { 'type' =&gt; 'multi'  }
+      }, $fields, MATCH_SKIP_CONFIRM);
</ins><span class="cx"> 
</span><del>-    my $cgi = Bugzilla-&gt;cgi;
-    foreach my $field (keys %fields) {
-        $cgi-&gt;param(-name =&gt; $field, -value =&gt; $fields{$field});
</del><ins>+    if ($retval != USER_MATCH_SUCCESS) {
+        ThrowUserError('user_match_too_many', {fields =&gt; $non_conclusive_fields});
</ins><span class="cx">     }
</span><ins>+}
</ins><span class="cx"> 
</span><del>-    $cgi-&gt;param(-name =&gt; 'inbound_email', -value =&gt; 1);
</del><ins>+sub post_bug {
+    my ($fields) = @_;
+    debug_print('Posting a new bug...');
</ins><span class="cx"> 
</span><del>-    require 'post_bug.cgi';
</del><ins>+    my $user = Bugzilla-&gt;user;
+
+    check_email_fields($fields);
+
+    my $bug = Bugzilla::Bug-&gt;create($fields);
+    debug_print(&quot;Created bug &quot; . $bug-&gt;id);
+    return ($bug, $bug-&gt;comments-&gt;[0]);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub process_bug {
</span><span class="cx">     my ($fields_in) = @_; 
</span><del>-
</del><span class="cx">     my %fields = %$fields_in;
</span><span class="cx"> 
</span><span class="cx">     my $bug_id = $fields{'bug_id'};
</span><span class="lines">@@ -173,8 +197,7 @@
</span><span class="cx"> 
</span><span class="cx">     debug_print(&quot;Updating Bug $fields{id}...&quot;);
</span><span class="cx"> 
</span><del>-    ValidateBugID($bug_id);
-    my $bug = new Bugzilla::Bug($bug_id);
</del><ins>+    my $bug = Bugzilla::Bug-&gt;check($bug_id);
</ins><span class="cx"> 
</span><span class="cx">     if ($fields{'bug_status'}) {
</span><span class="cx">         $fields{'knob'} = $fields{'bug_status'};
</span><span class="lines">@@ -198,16 +221,65 @@
</span><span class="cx">         $fields{'removecc'} = 1;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    check_email_fields(\%fields);
+
</ins><span class="cx">     my $cgi = Bugzilla-&gt;cgi;
</span><span class="cx">     foreach my $field (keys %fields) {
</span><span class="cx">         $cgi-&gt;param(-name =&gt; $field, -value =&gt; $fields{$field});
</span><span class="cx">     }
</span><del>-    $cgi-&gt;param('longdesclength', scalar $bug-&gt;longdescs);
</del><ins>+    $cgi-&gt;param('longdesclength', scalar @{ $bug-&gt;comments });
</ins><span class="cx">     $cgi-&gt;param('token', issue_hash_token([$bug-&gt;id, $bug-&gt;delta_ts]));
</span><span class="cx"> 
</span><span class="cx">     require 'process_bug.cgi';
</span><ins>+    debug_print(&quot;Bug processed.&quot;);
+
+    my $added_comment;
+    if (trim($fields{'comment'})) {
+        $added_comment = $bug-&gt;comments-&gt;[-1];
+    }
+    return ($bug, $added_comment);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+sub handle_attachments {
+    my ($bug, $attachments, $comment) = @_;
+    return if !$attachments;
+    debug_print(&quot;Handling attachments...&quot;);
+    my $dbh = Bugzilla-&gt;dbh;
+    $dbh-&gt;bz_start_transaction();
+    my ($update_comment, $update_bug);
+    foreach my $attachment (@$attachments) {
+        my $data = delete $attachment-&gt;{payload};
+        debug_print(&quot;Inserting Attachment: &quot; . Dumper($attachment), 2);
+        $attachment-&gt;{content_type} ||= 'application/octet-stream';
+        my $obj = Bugzilla::Attachment-&gt;create({
+            bug         =&gt; $bug,
+            description =&gt; $attachment-&gt;{filename},
+            filename    =&gt; $attachment-&gt;{filename},
+            mimetype    =&gt; $attachment-&gt;{content_type},
+            data        =&gt; $data,
+        });
+        # If we added a comment, and our comment does not already have a type,
+        # and this is our first attachment, then we make the comment an 
+        # &quot;attachment created&quot; comment.
+        if ($comment and !$comment-&gt;type and !$update_comment) {
+            $comment-&gt;set_all({ type       =&gt; CMT_ATTACHMENT_CREATED, 
+                                extra_data =&gt; $obj-&gt;id });
+            $update_comment = 1;
+        }
+        else {
+            $bug-&gt;add_comment('', { type =&gt; CMT_ATTACHMENT_CREATED,
+                                    extra_data =&gt; $obj-&gt;id });
+            $update_bug = 1;
+        }
+    }
+    # We only update the comments and bugs at the end of the transaction,
+    # because doing so modifies bugs_fulltext, which is a non-transactional
+    # table.
+    $bug-&gt;update() if $update_bug;
+    $comment-&gt;update() if $update_comment;
+    $dbh-&gt;bz_commit_transaction();
+}
+
</ins><span class="cx"> ######################
</span><span class="cx"> # Helper Subroutines #
</span><span class="cx"> ######################
</span><span class="lines">@@ -226,7 +298,7 @@
</span><span class="cx"> 
</span><span class="cx">     my $body;
</span><span class="cx">     my $attachments = [];
</span><del>-    if ($ct =~ /^multipart\/alternative/i) {
</del><ins>+    if ($ct =~ /^multipart\/(alternative|signed)/i) {
</ins><span class="cx">         $body = get_text_alternative($email);
</span><span class="cx">     }
</span><span class="cx">     else {
</span><span class="lines">@@ -301,7 +373,8 @@
</span><span class="cx">     # In Template-Toolkit, [% RETURN %] is implemented as a call to &quot;die&quot;.
</span><span class="cx">     # But of course, we really don't want to actually *die* just because
</span><span class="cx">     # the user-error or code-error template ended. So we don't really die.
</span><del>-    return if $msg-&gt;isa('Template::Exception') &amp;&amp; $msg-&gt;type eq 'return';
</del><ins>+    return if blessed($msg) &amp;&amp; $msg-&gt;isa('Template::Exception')
+              &amp;&amp; $msg-&gt;type eq 'return';
</ins><span class="cx"> 
</span><span class="cx">     # If this is inside an eval, then we should just act like...we're
</span><span class="cx">     # in an eval (instead of printing the error and exiting).
</span><span class="lines">@@ -330,7 +403,7 @@
</span><span class="cx"> 
</span><span class="cx"> $SIG{__DIE__} = \&amp;die_handler;
</span><span class="cx"> 
</span><del>-GetOptions(\%switch, 'help|h', 'verbose|v+');
</del><ins>+GetOptions(\%switch, 'help|h', 'verbose|v+', 'default=s%', 'override=s%');
</ins><span class="cx"> $switch{'verbose'} ||= 0;
</span><span class="cx"> 
</span><span class="cx"> # Print the help message if that switch was selected.
</span><span class="lines">@@ -338,29 +411,44 @@
</span><span class="cx"> 
</span><span class="cx"> Bugzilla-&gt;usage_mode(USAGE_MODE_EMAIL);
</span><span class="cx"> 
</span><del>-
</del><span class="cx"> my @mail_lines = &lt;STDIN&gt;;
</span><span class="cx"> my $mail_text = join(&quot;&quot;, @mail_lines);
</span><span class="cx"> my $mail_fields = parse_mail($mail_text);
</span><span class="cx"> 
</span><ins>+Bugzilla::Hook::process('email_in_after_parse', { fields =&gt; $mail_fields });
+
+my $attachments = delete $mail_fields-&gt;{'attachments'};
+
</ins><span class="cx"> my $username = $mail_fields-&gt;{'reporter'};
</span><span class="cx"> # If emailsuffix is in use, we have to remove it from the email address.
</span><span class="cx"> if (my $suffix = Bugzilla-&gt;params-&gt;{'emailsuffix'}) {
</span><span class="cx">     $username =~ s/\Q$suffix\E$//i;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-my $user = Bugzilla::User-&gt;new({ name =&gt; $username })
-    || ThrowUserError('invalid_username', { name =&gt; $username });
-
</del><ins>+my $user = Bugzilla::User-&gt;check($username);
</ins><span class="cx"> Bugzilla-&gt;set_user($user);
</span><span class="cx"> 
</span><ins>+my ($bug, $comment);
</ins><span class="cx"> if ($mail_fields-&gt;{'bug_id'}) {
</span><del>-    process_bug($mail_fields);
</del><ins>+    ($bug, $comment) = process_bug($mail_fields);
</ins><span class="cx"> }
</span><span class="cx"> else {
</span><del>-    post_bug($mail_fields);
</del><ins>+    ($bug, $comment) = post_bug($mail_fields);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+handle_attachments($bug, $attachments, $comment);
+
+# This is here for post_bug and handle_attachments, so that when posting a bug
+# with an attachment, any comment goes out as an attachment comment.
+#
+# Eventually this should be sending the mail for process_bug, too, but we have
+# to wait for $bug-&gt;update() to be fully used in email_in.pl first. So
+# currently, process_bug.cgi does the mail sending for bugs, and this does
+# any mail sending for attachments after the first one.
+Bugzilla::BugMail::Send($bug-&gt;id, { changer =&gt; Bugzilla-&gt;user });
+debug_print(&quot;Sent bugmail&quot;);
+
+
</ins><span class="cx"> __END__
</span><span class="cx"> 
</span><span class="cx"> =head1 NAME
</span><span class="lines">@@ -369,14 +457,23 @@
</span><span class="cx"> 
</span><span class="cx"> =head1 SYNOPSIS
</span><span class="cx"> 
</span><del>- ./email_in.pl [-vvv] &lt; email.txt
</del><ins>+./email_in.pl [-vvv] [--default name=value] [--override name=value] &lt; email.txt
</ins><span class="cx"> 
</span><del>- Reads an email on STDIN (the standard input).
</del><ins>+Reads an email on STDIN (the standard input).
</ins><span class="cx"> 
</span><del>-  Options:
-    --verbose (-v) - Make the script print more to STDERR.
-                     Specify multiple times to print even more.
</del><ins>+Options:
</ins><span class="cx"> 
</span><ins>+   --verbose (-v)        - Make the script print more to STDERR.
+                           Specify multiple times to print even more.
+
+   --default name=value  - Specify defaults for field values, like
+                           product=TestProduct. Can be specified multiple
+                           times to specify defaults for multiple fields.
+
+   --override name=value - Override field values specified in the email,
+                           like product=TestProduct. Can be specified
+                           multiple times to override multiple fields.
+
</ins><span class="cx"> =head1 DESCRIPTION
</span><span class="cx"> 
</span><span class="cx"> This script processes inbound email and creates a bug, or appends data
</span><span class="lines">@@ -389,9 +486,9 @@
</span><span class="cx">  From: account@domain.com
</span><span class="cx">  Subject: Bug Summary
</span><span class="cx"> 
</span><del>- @product = ProductName
- @component = ComponentName
- @version = 1.0
</del><ins>+ @product ProductName
+ @component ComponentName
+ @version 1.0
</ins><span class="cx"> 
</span><span class="cx">  This is a bug description. It will be entered into the bug exactly as
</span><span class="cx">  written here.
</span><span class="lines">@@ -402,39 +499,25 @@
</span><span class="cx">  This is a signature line, and will be removed automatically, It will not
</span><span class="cx">  be included in the bug description.
</span><span class="cx"> 
</span><del>-The C&lt;@&gt; labels can be any valid field name in Bugzilla that can be
-set on C&lt;enter_bug.cgi&gt;. For the list of required field names, see 
-L&lt;Bugzilla::WebService::Bug/Create&gt;. Note, that there is some difference
-in the names of the required input fields between web and email interfaces, 
-as listed below:
</del><ins>+For the list of valid field names for the C&lt;@&gt; fields, including
+a list of which ones are required, see L&lt;Bugzilla::WebService::Bug/create&gt;.
+(Note, however, that you cannot specify C&lt;@description&gt; as a field--
+you just add a comment by adding text after the C&lt;@&gt; fields.)
</ins><span class="cx"> 
</span><del>-=over
-
-=item *
-
-C&lt;platform&gt; in web is C&lt;@rep_platform&gt; in email
-
-=item *
-
-C&lt;severity&gt; in web is C&lt;@bug_severity&gt; in email
-
-=back
-
-For the list of all field names, see the C&lt;fielddefs&gt; table in the database. 
-
</del><span class="cx"> The values for the fields can be split across multiple lines, but
</span><span class="cx"> note that a newline will be parsed as a single space, for the value.
</span><span class="cx"> So, for example:
</span><span class="cx"> 
</span><del>- @short_desc = This is a very long
</del><ins>+ @summary This is a very long
</ins><span class="cx">  description
</span><span class="cx"> 
</span><span class="cx"> Will be parsed as &quot;This is a very long description&quot;.
</span><span class="cx"> 
</span><del>-If you specify C&lt;@short_desc&gt;, it will override the summary you specify
</del><ins>+If you specify C&lt;@summary&gt;, it will override the summary you specify
</ins><span class="cx"> in the Subject header.
</span><span class="cx"> 
</span><del>-C&lt;account@domain.com&gt; must be a valid Bugzilla account.
</del><ins>+C&lt;account@domain.com&gt; (the value of the C&lt;From&gt; header) must be a valid
+Bugzilla account.
</ins><span class="cx"> 
</span><span class="cx"> Note that signatures must start with '-- ', the standard signature
</span><span class="cx"> border.
</span><span class="lines">@@ -451,11 +534,11 @@
</span><span class="cx"> 
</span><span class="cx"> =item *
</span><span class="cx"> 
</span><del>-You include C&lt;@bug_id = 123456&gt; in the first lines of the email.
</del><ins>+You include C&lt;@id 123456&gt; in the first lines of the email.
</ins><span class="cx"> 
</span><span class="cx"> =back
</span><span class="cx"> 
</span><del>-If you do both, C&lt;@bug_id&gt; takes precedence.
</del><ins>+If you do both, C&lt;@id&gt; takes precedence.
</ins><span class="cx"> 
</span><span class="cx"> You send your email in the same format as for creating a bug, except
</span><span class="cx"> that you only specify the fields you want to change. If the very
</span><span class="lines">@@ -464,7 +547,7 @@
</span><span class="cx"> 
</span><span class="cx"> Note that when updating a bug, the C&lt;Subject&gt; header is ignored,
</span><span class="cx"> except for getting the bug ID. If you want to change the bug's summary,
</span><del>-you have to specify C&lt;@short_desc&gt; as one of the fields to change.
</del><ins>+you have to specify C&lt;@summary&gt; as one of the fields to change.
</ins><span class="cx"> 
</span><span class="cx"> Please remember not to include any extra text in your emails, as that
</span><span class="cx"> text will also be added as a comment. This includes any text that your
</span><span class="lines">@@ -474,8 +557,6 @@
</span><span class="cx"> =head3 Adding/Removing CCs
</span><span class="cx"> 
</span><span class="cx"> To add CCs, you can specify them in a comma-separated list in C&lt;@cc&gt;.
</span><del>-For backward compatibility, C&lt;@newcc&gt; can also be used. If both are
-present, C&lt;@cc&gt; takes precedence.
</del><span class="cx"> 
</span><span class="cx"> To remove CCs, specify them as a comma-separated list in C&lt;@removecc&gt;.
</span><span class="cx"> 
</span><span class="lines">@@ -488,8 +569,6 @@
</span><span class="cx"> If any part of your request fails, all of it will fail. No partial
</span><span class="cx"> changes will happen.
</span><span class="cx"> 
</span><del>-There is no attachment support yet.
-
</del><span class="cx"> =head1 CAUTION
</span><span class="cx"> 
</span><span class="cx"> The script does not do any validation that the user is who they say
</span><span class="lines">@@ -500,12 +579,8 @@
</span><span class="cx"> 
</span><span class="cx"> =head1 LIMITATIONS
</span><span class="cx"> 
</span><del>-Note that the email interface has the same limitations as the
-normal Bugzilla interface. So, for example, you cannot reassign
-a bug and change its status at the same time.
-
</del><span class="cx"> The email interface only accepts emails that are correctly formatted
</span><del>-perl RFC2822. If you send it an incorrectly formatted message, it
</del><ins>+per RFC2822. If you send it an incorrectly formatted message, it
</ins><span class="cx"> may behave in an unpredictable fashion.
</span><span class="cx"> 
</span><span class="cx"> You cannot send an HTML mail along with attachments. If you do, Bugzilla
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgenter_bugcgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/enter_bug.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/enter_bug.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/enter_bug.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -22,6 +22,7 @@
</span><span class="cx"> #                 Joe Robins &lt;jmrobins@tgix.com&gt;
</span><span class="cx"> #                 Gervase Markham &lt;gerv@gerv.net&gt;
</span><span class="cx"> #                 Shane H. W. Travis &lt;travis@sedsystems.ca&gt;
</span><ins>+#                 Nitish Bezzala &lt;nbezzala@yahoo.com&gt;
</ins><span class="cx"> 
</span><span class="cx"> ##############################################################################
</span><span class="cx"> #
</span><span class="lines">@@ -152,15 +153,10 @@
</span><span class="cx">         $product = $enterable_products[0];
</span><span class="cx">     }
</span><span class="cx"> }
</span><del>-else {
-    # Do not use Bugzilla::Product::check_product() here, else the user
-    # could know whether the product doesn't exist or is not accessible.
-    $product = new Bugzilla::Product({'name' =&gt; $product_name});
-}
</del><span class="cx"> 
</span><span class="cx"> # We need to check and make sure that the user has permission
</span><span class="cx"> # to enter a bug against this product.
</span><del>-$user-&gt;can_enter_product($product ? $product-&gt;name : $product_name, THROW_ERROR);
</del><ins>+$product = $user-&gt;can_enter_product($product || $product_name, THROW_ERROR);
</ins><span class="cx"> 
</span><span class="cx"> ##############################################################################
</span><span class="cx"> # Useful Subroutines
</span><span class="lines">@@ -199,44 +195,54 @@
</span><span class="cx">         # no choice is valid, we return &quot;Other&quot;.
</span><span class="cx">         for ($ENV{'HTTP_USER_AGENT'}) {
</span><span class="cx">         #PowerPC
</span><del>-            /\(.*PowerPC.*\)/i &amp;&amp; do {@platform = &quot;Macintosh&quot;; last;};
-            /\(.*PPC.*\)/ &amp;&amp; do {@platform = &quot;Macintosh&quot;; last;};
-            /\(.*AIX.*\)/ &amp;&amp; do {@platform = &quot;Macintosh&quot;; last;};
</del><ins>+            /\(.*PowerPC.*\)/i &amp;&amp; do {push @platform, (&quot;PowerPC&quot;, &quot;Macintosh&quot;);};
+        #AMD64, Intel x86_64
+            /\(.*amd64.*\)/ &amp;&amp; do {push @platform, (&quot;AMD64&quot;, &quot;x86_64&quot;, &quot;PC&quot;);};
+            /\(.*x86_64.*\)/ &amp;&amp; do {push @platform, (&quot;AMD64&quot;, &quot;x86_64&quot;, &quot;PC&quot;);};
+        #Intel Itanium
+            /\(.*IA64.*\)/ &amp;&amp; do {push @platform, &quot;IA64&quot;;};
</ins><span class="cx">         #Intel x86
</span><del>-            /\(.*Intel.*\)/ &amp;&amp; do {@platform = &quot;PC&quot;; last;};
-            /\(.*[ix0-9]86.*\)/ &amp;&amp; do {@platform = &quot;PC&quot;; last;};
</del><ins>+            /\(.*Intel.*\)/ &amp;&amp; do {push @platform, (&quot;IA32&quot;, &quot;x86&quot;, &quot;PC&quot;);};
+            /\(.*[ix0-9]86.*\)/ &amp;&amp; do {push @platform, (&quot;IA32&quot;, &quot;x86&quot;, &quot;PC&quot;);};
</ins><span class="cx">         #Versions of Windows that only run on Intel x86
</span><del>-            /\(.*Win(?:dows |)[39M].*\)/ &amp;&amp; do {@platform = &quot;PC&quot;; last};
-            /\(.*Win(?:dows |)16.*\)/ &amp;&amp; do {@platform = &quot;PC&quot;; last;};
</del><ins>+            /\(.*Win(?:dows |)[39M].*\)/ &amp;&amp; do {push @platform, (&quot;IA32&quot;, &quot;x86&quot;, &quot;PC&quot;);};
+            /\(.*Win(?:dows |)16.*\)/ &amp;&amp; do {push @platform, (&quot;IA32&quot;, &quot;x86&quot;, &quot;PC&quot;);};
</ins><span class="cx">         #Sparc
</span><del>-            /\(.*sparc.*\)/ &amp;&amp; do {@platform = &quot;Sun&quot;; last;};
-            /\(.*sun4.*\)/ &amp;&amp; do {@platform = &quot;Sun&quot;; last;};
</del><ins>+            /\(.*sparc.*\)/ &amp;&amp; do {push @platform, (&quot;Sparc&quot;, &quot;Sun&quot;);};
+            /\(.*sun4.*\)/ &amp;&amp; do {push @platform, (&quot;Sparc&quot;, &quot;Sun&quot;);};
</ins><span class="cx">         #Alpha
</span><del>-            /\(.*AXP.*\)/i &amp;&amp; do {@platform = &quot;DEC&quot;; last;};
-            /\(.*[ _]Alpha.\D/i &amp;&amp; do {@platform = &quot;DEC&quot;; last;};
-            /\(.*[ _]Alpha\)/i &amp;&amp; do {@platform = &quot;DEC&quot;; last;};
</del><ins>+            /\(.*AXP.*\)/i &amp;&amp; do {push @platform, (&quot;Alpha&quot;, &quot;DEC&quot;);};
+            /\(.*[ _]Alpha.\D/i &amp;&amp; do {push @platform, (&quot;Alpha&quot;, &quot;DEC&quot;);};
+            /\(.*[ _]Alpha\)/i &amp;&amp; do {push @platform, (&quot;Alpha&quot;, &quot;DEC&quot;);};
</ins><span class="cx">         #MIPS
</span><del>-            /\(.*IRIX.*\)/i &amp;&amp; do {@platform = &quot;SGI&quot;; last;};
-            /\(.*MIPS.*\)/i &amp;&amp; do {@platform = &quot;SGI&quot;; last;};
</del><ins>+            /\(.*IRIX.*\)/i &amp;&amp; do {push @platform, (&quot;MIPS&quot;, &quot;SGI&quot;);};
+            /\(.*MIPS.*\)/i &amp;&amp; do {push @platform, (&quot;MIPS&quot;, &quot;SGI&quot;);};
</ins><span class="cx">         #68k
</span><del>-            /\(.*68K.*\)/ &amp;&amp; do {@platform = &quot;Macintosh&quot;; last;};
-            /\(.*680[x0]0.*\)/ &amp;&amp; do {@platform = &quot;Macintosh&quot;; last;};
</del><ins>+            /\(.*68K.*\)/ &amp;&amp; do {push @platform, (&quot;68k&quot;, &quot;Macintosh&quot;);};
+            /\(.*680[x0]0.*\)/ &amp;&amp; do {push @platform, (&quot;68k&quot;, &quot;Macintosh&quot;);};
</ins><span class="cx">         #HP
</span><del>-            /\(.*9000.*\)/ &amp;&amp; do {@platform = &quot;HP&quot;; last;};
</del><ins>+            /\(.*9000.*\)/ &amp;&amp; do {push @platform, (&quot;PA-RISC&quot;, &quot;HP&quot;);};
</ins><span class="cx">         #ARM
</span><del>-#            /\(.*ARM.*\) &amp;&amp; do {$platform = &quot;ARM&quot;;};
</del><ins>+            /\(.*ARM.*\)/ &amp;&amp; do {push @platform, (&quot;ARM&quot;, &quot;PocketPC&quot;);};
+        #PocketPC intentionally before PowerPC
+            /\(.*Windows CE.*PPC.*\)/ &amp;&amp; do {push @platform, (&quot;ARM&quot;, &quot;PocketPC&quot;);};
+        #PowerPC
+            /\(.*PPC.*\)/ &amp;&amp; do {push @platform, (&quot;PowerPC&quot;, &quot;Macintosh&quot;);};
+            /\(.*AIX.*\)/ &amp;&amp; do {push @platform, (&quot;PowerPC&quot;, &quot;Macintosh&quot;);};
</ins><span class="cx">         #Stereotypical and broken
</span><del>-            /\(.*Macintosh.*\)/ &amp;&amp; do {@platform = &quot;Macintosh&quot;; last;};
-            /\(.*Mac OS [89].*\)/ &amp;&amp; do {@platform = &quot;Macintosh&quot;; last;};
-            /\(Win.*\)/ &amp;&amp; do {@platform = &quot;PC&quot;; last;};
-            /\(.*Win(?:dows[ -])NT.*\)/ &amp;&amp; do {@platform = &quot;PC&quot;; last;};
-            /\(.*OSF.*\)/ &amp;&amp; do {@platform = &quot;DEC&quot;; last;};
-            /\(.*HP-?UX.*\)/i &amp;&amp; do {@platform = &quot;HP&quot;; last;};
-            /\(.*IRIX.*\)/i &amp;&amp; do {@platform = &quot;SGI&quot;; last;};
-            /\(.*(SunOS|Solaris).*\)/ &amp;&amp; do {@platform = &quot;Sun&quot;; last;};
</del><ins>+            /\(.*Windows CE.*\)/ &amp;&amp; do {push @platform, (&quot;ARM&quot;, &quot;PocketPC&quot;);};
+            /\(.*Macintosh.*\)/ &amp;&amp; do {push @platform, (&quot;68k&quot;, &quot;Macintosh&quot;);};
+            /\(.*Mac OS [89].*\)/ &amp;&amp; do {push @platform, (&quot;68k&quot;, &quot;Macintosh&quot;);};
+            /\(.*Win64.*\)/ &amp;&amp; do {push @platform, &quot;IA64&quot;;};
+            /\(Win.*\)/ &amp;&amp; do {push @platform, (&quot;IA32&quot;, &quot;x86&quot;, &quot;PC&quot;);};
+            /\(.*Win(?:dows[ -])NT.*\)/ &amp;&amp; do {push @platform, (&quot;IA32&quot;, &quot;x86&quot;, &quot;PC&quot;);};
+            /\(.*OSF.*\)/ &amp;&amp; do {push @platform, (&quot;Alpha&quot;, &quot;DEC&quot;);};
+            /\(.*HP-?UX.*\)/i &amp;&amp; do {push @platform, (&quot;PA-RISC&quot;, &quot;HP&quot;);};
+            /\(.*IRIX.*\)/i &amp;&amp; do {push @platform, (&quot;MIPS&quot;, &quot;SGI&quot;);};
+            /\(.*(SunOS|Solaris).*\)/ &amp;&amp; do {push @platform, (&quot;Sparc&quot;, &quot;Sun&quot;);};
</ins><span class="cx">         #Braindead old browsers who didn't follow convention:
</span><del>-            /Amiga/ &amp;&amp; do {@platform = &quot;Macintosh&quot;; last;};
-            /WinMosaic/ &amp;&amp; do {@platform = &quot;PC&quot;; last;};
</del><ins>+            /Amiga/ &amp;&amp; do {push @platform, (&quot;68k&quot;, &quot;Macintosh&quot;);};
+            /WinMosaic/ &amp;&amp; do {push @platform, (&quot;IA32&quot;, &quot;x86&quot;, &quot;PC&quot;);};
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -257,7 +263,7 @@
</span><span class="cx">         # item in @os that is a valid platform choice. If
</span><span class="cx">         # no choice is valid, we return &quot;Other&quot;.
</span><span class="cx">         for ($ENV{'HTTP_USER_AGENT'}) {
</span><del>-            /\(.*IRIX.*\)/ &amp;&amp; do {push @os, &quot;IRIX&quot;; };
</del><ins>+            /\(.*IRIX.*\)/ &amp;&amp; do {push @os, &quot;IRIX&quot;;};
</ins><span class="cx">             /\(.*OSF.*\)/ &amp;&amp; do {push @os, &quot;OSF/1&quot;;};
</span><span class="cx">             /\(.*Linux.*\)/ &amp;&amp; do {push @os, &quot;Linux&quot;;};
</span><span class="cx">             /\(.*Solaris.*\)/ &amp;&amp; do {push @os, &quot;Solaris&quot;;};
</span><span class="lines">@@ -288,6 +294,8 @@
</span><span class="cx">             /\(.*VMS.*\)/ &amp;&amp; do {push @os, &quot;OpenVMS&quot;;};
</span><span class="cx">             /\(.*Win.*\)/ &amp;&amp; do {
</span><span class="cx">               /\(.*Windows XP.*\)/ &amp;&amp; do {push @os, &quot;Windows XP&quot;;};
</span><ins>+              /\(.*Windows NT 6\.2.*\)/ &amp;&amp; do {push @os, &quot;Windows 8&quot;;};
+              /\(.*Windows NT 6\.1.*\)/ &amp;&amp; do {push @os, &quot;Windows 7&quot;;};
</ins><span class="cx">               /\(.*Windows NT 6\.0.*\)/ &amp;&amp; do {push @os, &quot;Windows Vista&quot;;};
</span><span class="cx">               /\(.*Windows NT 5\.2.*\)/ &amp;&amp; do {push @os, &quot;Windows Server 2003&quot;;};
</span><span class="cx">               /\(.*Windows NT 5\.1.*\)/ &amp;&amp; do {push @os, &quot;Windows XP&quot;;};
</span><span class="lines">@@ -302,8 +310,19 @@
</span><span class="cx">               /\(.*Windows.*NT.*\)/ &amp;&amp; do {push @os, &quot;Windows NT&quot;;};
</span><span class="cx">             };
</span><span class="cx">             /\(.*Mac OS X.*\)/ &amp;&amp; do {
</span><del>-              /\(.*Intel.*Mac OS X 10.5.*\)/ &amp;&amp; do {push @os, &quot;Mac OS X 10.5&quot;;};
</del><ins>+              /\(.*Mac OS X (?:|Mach-O |\()10.7.*\)/ &amp;&amp; do {push @os, &quot;Mac OS X 10.7&quot;;};
+              /\(.*Mac OS X (?:|Mach-O |\()10.6.*\)/ &amp;&amp; do {push @os, &quot;Mac OS X 10.6&quot;;};
+              /\(.*Mac OS X (?:|Mach-O |\()10.5.*\)/ &amp;&amp; do {push @os, &quot;Mac OS X 10.5&quot;;};
+              /\(.*Mac OS X (?:|Mach-O |\()10.4.*\)/ &amp;&amp; do {push @os, &quot;Mac OS X 10.4&quot;;};
+              /\(.*Mac OS X (?:|Mach-O |\()10.3.*\)/ &amp;&amp; do {push @os, &quot;Mac OS X 10.3&quot;;};
+              /\(.*Mac OS X (?:|Mach-O |\()10.2.*\)/ &amp;&amp; do {push @os, &quot;Mac OS X 10.2&quot;;};
+              /\(.*Mac OS X (?:|Mach-O |\()10.1.*\)/ &amp;&amp; do {push @os, &quot;Mac OS X 10.1&quot;;};
+        # Unfortunately, OS X 10.4 was the first to support Intel. This is
+        # fallback support because some browsers refused to include the OS
+        # Version.
</ins><span class="cx">               /\(.*Intel.*Mac OS X.*\)/ &amp;&amp; do {push @os, &quot;Mac OS X 10.4&quot;;};
</span><ins>+        # OS X 10.3 is the most likely default version of PowerPC Macs
+        # OS X 10.0 is more for configurations which didn't setup 10.x versions
</ins><span class="cx">               /\(.*Mac OS X.*\)/ &amp;&amp; do {push @os, (&quot;Mac OS X 10.3&quot;, &quot;Mac OS X 10.0&quot;, &quot;Mac OS X&quot;);};
</span><span class="cx">             };
</span><span class="cx">             /\(.*32bit.*\)/ &amp;&amp; do {push @os, &quot;Windows 95&quot;;};
</span><span class="lines">@@ -351,8 +370,8 @@
</span><span class="cx"> $cloned_bug_id = $cgi-&gt;param('cloned_bug_id');
</span><span class="cx"> 
</span><span class="cx"> if ($cloned_bug_id) {
</span><del>-    ValidateBugID($cloned_bug_id);
-    $cloned_bug = new Bugzilla::Bug($cloned_bug_id);
</del><ins>+    $cloned_bug = Bugzilla::Bug-&gt;check($cloned_bug_id);
+    $cloned_bug_id = $cloned_bug-&gt;id;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> if (scalar(@{$product-&gt;components}) == 1) {
</span><span class="lines">@@ -369,8 +388,6 @@
</span><span class="cx"> $vars-&gt;{'rep_platform'}          = get_legal_field_values('rep_platform');
</span><span class="cx"> $vars-&gt;{'op_sys'}                = get_legal_field_values('op_sys');
</span><span class="cx"> 
</span><del>-$vars-&gt;{'use_keywords'}          = 1 if Bugzilla::Keyword::keyword_count();
-
</del><span class="cx"> $vars-&gt;{'assigned_to'}           = formvalue('assigned_to');
</span><span class="cx"> $vars-&gt;{'assigned_to_disabled'}  = !$has_editbugs;
</span><span class="cx"> $vars-&gt;{'cc_disabled'}           = 0;
</span><span class="lines">@@ -380,14 +397,26 @@
</span><span class="cx"> 
</span><span class="cx"> $vars-&gt;{'cloned_bug_id'}         = $cloned_bug_id;
</span><span class="cx"> 
</span><del>-$vars-&gt;{'token'}             = issue_session_token('createbug:');
</del><ins>+$vars-&gt;{'token'} = issue_session_token('create_bug');
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> my @enter_bug_fields = grep { $_-&gt;enter_bug } Bugzilla-&gt;active_custom_fields;
</span><span class="cx"> foreach my $field (@enter_bug_fields) {
</span><del>-    $vars-&gt;{$field-&gt;name} = formvalue($field-&gt;name);
</del><ins>+    my $cf_name = $field-&gt;name;
+    my $cf_value = $cgi-&gt;param($cf_name);
+    if (defined $cf_value) {
+        if ($field-&gt;type == FIELD_TYPE_MULTI_SELECT) {
+            $cf_value = [$cgi-&gt;param($cf_name)];
+        }
+        $default{$cf_name} = $vars-&gt;{$cf_name} = $cf_value;
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# This allows the Field visibility and value controls to work with the
+# Classification and Product fields as a parent.
+$default{'classification'} = $product-&gt;classification-&gt;name;
+$default{'product'} = $product-&gt;name;
+
</ins><span class="cx"> if ($cloned_bug_id) {
</span><span class="cx"> 
</span><span class="cx">     $default{'component_'}    = $cloned_bug-&gt;component;
</span><span class="lines">@@ -399,15 +428,20 @@
</span><span class="cx">     $vars-&gt;{'short_desc'}     = $cloned_bug-&gt;short_desc;
</span><span class="cx">     $vars-&gt;{'bug_file_loc'}   = $cloned_bug-&gt;bug_file_loc;
</span><span class="cx">     $vars-&gt;{'keywords'}       = $cloned_bug-&gt;keywords;
</span><del>-    $vars-&gt;{'dependson'}      = $cloned_bug_id;
-    $vars-&gt;{'blocked'}        = &quot;&quot;;
</del><ins>+    $vars-&gt;{'dependson'}      = join (&quot;, &quot;, $cloned_bug_id, @{$cloned_bug-&gt;dependson});
+    $vars-&gt;{'blocked'}        = join (&quot;, &quot;, @{$cloned_bug-&gt;blocked});
</ins><span class="cx">     $vars-&gt;{'deadline'}       = $cloned_bug-&gt;deadline;
</span><ins>+    $vars-&gt;{'estimated_time'} = $cloned_bug-&gt;estimated_time;
</ins><span class="cx"> 
</span><span class="cx">     if (defined $cloned_bug-&gt;cc) {
</span><span class="cx">         $vars-&gt;{'cc'}         = join (&quot;, &quot;, @{$cloned_bug-&gt;cc});
</span><span class="cx">     } else {
</span><span class="cx">         $vars-&gt;{'cc'}         = formvalue('cc');
</span><span class="cx">     }
</span><ins>+    
+    if ($cloned_bug-&gt;reporter-&gt;id != $user-&gt;id) {
+        $vars-&gt;{'cc'} = join (&quot;, &quot;, $cloned_bug-&gt;reporter-&gt;login, $vars-&gt;{'cc'}); 
+    }
</ins><span class="cx"> 
</span><span class="cx">     foreach my $field (@enter_bug_fields) {
</span><span class="cx">         my $field_name = $field-&gt;name;
</span><span class="lines">@@ -417,18 +451,17 @@
</span><span class="cx">     # We need to ensure that we respect the 'insider' status of
</span><span class="cx">     # the first comment, if it has one. Either way, make a note
</span><span class="cx">     # that this bug was cloned from another bug.
</span><del>-    # We cannot use $cloned_bug-&gt;longdescs because this method
-    # depends on the &quot;comment_sort_order&quot; user pref, and we
-    # really want the first comment of the bug.
-    my $bug_desc = Bugzilla::Bug::GetComments($cloned_bug_id, 'oldest_to_newest');
-    my $isprivate = $bug_desc-&gt;[0]-&gt;{'isprivate'};
</del><ins>+    my $bug_desc = $cloned_bug-&gt;comments({ order =&gt; 'oldest_to_newest' })-&gt;[0];
+    my $isprivate = $bug_desc-&gt;is_private;
</ins><span class="cx"> 
</span><del>-    $vars-&gt;{'comment'}        = &quot;&quot;;
-    $vars-&gt;{'commentprivacy'} = 0;
</del><ins>+    $vars-&gt;{'comment'} = &quot;&quot;;
+    $vars-&gt;{'comment_is_private'} = 0;
</ins><span class="cx"> 
</span><span class="cx">     if (!$isprivate || Bugzilla-&gt;user-&gt;is_insider) {
</span><del>-        $vars-&gt;{'comment'}        = $bug_desc-&gt;[0]-&gt;{'body'};
-        $vars-&gt;{'commentprivacy'} = $isprivate;
</del><ins>+        # We use &quot;body&quot; to avoid any format_comment text, which would be
+        # pointless to clone.
+        $vars-&gt;{'comment'} = $bug_desc-&gt;body;
+        $vars-&gt;{'comment_is_private'} = $isprivate;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> } # end of cloned bug entry form
</span><span class="lines">@@ -441,17 +474,19 @@
</span><span class="cx">     $default{'rep_platform'}  = pickplatform();
</span><span class="cx">     $default{'op_sys'}        = pickos();
</span><span class="cx"> 
</span><ins>+    $vars-&gt;{'alias'}          = formvalue('alias');
</ins><span class="cx">     $vars-&gt;{'short_desc'}     = formvalue('short_desc');
</span><span class="cx">     $vars-&gt;{'bug_file_loc'}   = formvalue('bug_file_loc', &quot;http://&quot;);
</span><span class="cx">     $vars-&gt;{'keywords'}       = formvalue('keywords');
</span><span class="cx">     $vars-&gt;{'dependson'}      = formvalue('dependson');
</span><span class="cx">     $vars-&gt;{'blocked'}        = formvalue('blocked');
</span><span class="cx">     $vars-&gt;{'deadline'}       = formvalue('deadline');
</span><ins>+    $vars-&gt;{'estimated_time'} = formvalue('estimated_time');
</ins><span class="cx"> 
</span><span class="cx">     $vars-&gt;{'cc'}             = join(', ', $cgi-&gt;param('cc'));
</span><span class="cx"> 
</span><span class="cx">     $vars-&gt;{'comment'}        = formvalue('comment');
</span><del>-    $vars-&gt;{'commentprivacy'} = formvalue('commentprivacy');
</del><ins>+    $vars-&gt;{'comment_is_private'} = formvalue('comment_is_private');
</ins><span class="cx"> 
</span><span class="cx"> } # end of normal/bookmarked entry form
</span><span class="cx"> 
</span><span class="lines">@@ -469,23 +504,26 @@
</span><span class="cx"> #
</span><span class="cx"> # Eventually maybe each product should have a &quot;current version&quot;
</span><span class="cx"> # parameter.
</span><del>-$vars-&gt;{'version'} = [map($_-&gt;name, @{$product-&gt;versions})];
</del><ins>+$vars-&gt;{'version'} = $product-&gt;versions;
</ins><span class="cx"> 
</span><ins>+my $version_cookie = $cgi-&gt;cookie(&quot;VERSION-&quot; . $product-&gt;name);
+
</ins><span class="cx"> if ( ($cloned_bug_id) &amp;&amp;
</span><span class="cx">      ($product-&gt;name eq $cloned_bug-&gt;product ) ) {
</span><span class="cx">     $default{'version'} = $cloned_bug-&gt;version;
</span><span class="cx"> } elsif (formvalue('version')) {
</span><span class="cx">     $default{'version'} = formvalue('version');
</span><del>-} elsif (defined $cgi-&gt;cookie(&quot;VERSION-&quot; . $product-&gt;name) &amp;&amp;
-    lsearch($vars-&gt;{'version'}, $cgi-&gt;cookie(&quot;VERSION-&quot; . $product-&gt;name)) != -1) {
-    $default{'version'} = $cgi-&gt;cookie(&quot;VERSION-&quot; . $product-&gt;name);
</del><ins>+} elsif (defined $version_cookie
+         and grep { $_-&gt;name eq $version_cookie } @{ $vars-&gt;{'version'} })
+{
+    $default{'version'} = $version_cookie;
</ins><span class="cx"> } else {
</span><del>-    $default{'version'} = $vars-&gt;{'version'}-&gt;[$#{$vars-&gt;{'version'}}];
</del><ins>+    $default{'version'} = $vars-&gt;{'version'}-&gt;[$#{$vars-&gt;{'version'}}]-&gt;name;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> # Get list of milestones.
</span><span class="cx"> if ( Bugzilla-&gt;params-&gt;{'usetargetmilestone'} ) {
</span><del>-    $vars-&gt;{'target_milestone'} = [map($_-&gt;name, @{$product-&gt;milestones})];
</del><ins>+    $vars-&gt;{'target_milestone'} = $product-&gt;milestones;
</ins><span class="cx">     if (formvalue('target_milestone')) {
</span><span class="cx">        $default{'target_milestone'} = formvalue('target_milestone');
</span><span class="cx">     } else {
</span><span class="lines">@@ -494,101 +532,55 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> # Construct the list of allowable statuses.
</span><del>-my $initial_statuses = Bugzilla::Status-&gt;can_change_to();
</del><ins>+my @statuses = @{ Bugzilla::Status-&gt;can_change_to() };
</ins><span class="cx"> # Exclude closed states from the UI, even if the workflow allows them.
</span><span class="cx"> # The back-end code will still accept them, though.
</span><del>-@$initial_statuses = grep { $_-&gt;is_open } @$initial_statuses;
</del><ins>+@statuses = grep { $_-&gt;is_open } @statuses;
</ins><span class="cx"> 
</span><del>-my @status = map { $_-&gt;name } @$initial_statuses;
-# UNCONFIRMED is illegal if votes_to_confirm = 0.
-@status = grep {$_ ne 'UNCONFIRMED'} @status unless $product-&gt;votes_to_confirm;
-scalar(@status) || ThrowUserError('no_initial_bug_status');
</del><ins>+# UNCONFIRMED is illegal if allows_unconfirmed is false.
+if (!$product-&gt;allows_unconfirmed) {
+    @statuses = grep { $_-&gt;name ne 'UNCONFIRMED' } @statuses;
+}
+scalar(@statuses) || ThrowUserError('no_initial_bug_status');
</ins><span class="cx"> 
</span><span class="cx"> # If the user has no privs...
</span><span class="cx"> unless ($has_editbugs || $has_canconfirm) {
</span><span class="cx">     # ... use UNCONFIRMED if available, else use the first status of the list.
</span><del>-    my $bug_status = (grep {$_ eq 'UNCONFIRMED'} @status) ? 'UNCONFIRMED' : $status[0];
-    @status = ($bug_status);
</del><ins>+    my ($unconfirmed) = grep { $_-&gt;name eq 'UNCONFIRMED' } @statuses;
+
+    # Because of an apparent Perl bug, &quot;$unconfirmed || $statuses[0]&quot; doesn't
+    # work, so we're using an &quot;?:&quot; operator. See bug 603314 for details.
+    @statuses = ($unconfirmed ? $unconfirmed : $statuses[0]);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-$vars-&gt;{'bug_status'} = \@status;
</del><ins>+$vars-&gt;{'bug_status'} = \@statuses;
</ins><span class="cx"> 
</span><span class="cx"> # Get the default from a template value if it is legitimate.
</span><span class="cx"> # Otherwise, and only if the user has privs, set the default
</span><span class="cx"> # to the first confirmed bug status on the list, if available.
</span><span class="cx"> 
</span><del>-if (formvalue('bug_status') &amp;&amp; (lsearch(\@status, formvalue('bug_status')) &gt;= 0)) {
</del><ins>+my $picked_status = formvalue('bug_status');
+if ($picked_status and grep($_-&gt;name eq $picked_status, @statuses)) {
</ins><span class="cx">     $default{'bug_status'} = formvalue('bug_status');
</span><del>-} elsif (scalar @status == 1) {
-    $default{'bug_status'} = $status[0];
</del><ins>+} elsif (scalar @statuses == 1) {
+    $default{'bug_status'} = $statuses[0]-&gt;name;
</ins><span class="cx"> }
</span><span class="cx"> else {
</span><del>-    $default{'bug_status'} = ($status[0] ne 'UNCONFIRMED') ? $status[0] : $status[1];
</del><ins>+    $default{'bug_status'} = ($statuses[0]-&gt;name ne 'UNCONFIRMED') 
+                             ? $statuses[0]-&gt;name : $statuses[1]-&gt;name;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-my $grouplist = $dbh-&gt;selectall_arrayref(
-                  q{SELECT DISTINCT groups.id, groups.name, groups.description,
-                                    membercontrol, othercontrol
-                      FROM groups
-                 LEFT JOIN group_control_map
-                        ON group_id = id AND product_id = ?
-                     WHERE isbuggroup != 0 AND isactive != 0
-                  ORDER BY description}, undef, $product-&gt;id);
-
-my @groups;
-
-foreach my $row (@$grouplist) {
-    my ($id, $groupname, $description, $membercontrol, $othercontrol) = @$row;
-    # Only include groups if the entering user will have an option.
-    next if ((!$membercontrol) 
-               || ($membercontrol == CONTROLMAPNA) 
-               || ($membercontrol == CONTROLMAPMANDATORY)
-               || (($othercontrol != CONTROLMAPSHOWN) 
-                    &amp;&amp; ($othercontrol != CONTROLMAPDEFAULT)
-                    &amp;&amp; (!Bugzilla-&gt;user-&gt;in_group($groupname)))
-             );
-    my $check;
-
-    # If this is a cloned bug, 
-    # AND the product for this bug is the same as for the original
-    #   THEN set a group's checkbox if the original also had it on
-    # ELSE IF this is a bookmarked template
-    #   THEN set a group's checkbox if was set in the bookmark
-    # ELSE
-    #   set a groups's checkbox based on the group control map
-    #
-    if ( ($cloned_bug_id) &amp;&amp;
-         ($product-&gt;name eq $cloned_bug-&gt;product ) ) {
-        foreach my $i (0..(@{$cloned_bug-&gt;groups} - 1) ) {
-            if ($cloned_bug-&gt;groups-&gt;[$i]-&gt;{'bit'} == $id) {
-                $check = $cloned_bug-&gt;groups-&gt;[$i]-&gt;{'ison'};
-            }
-        }
-    }
-    elsif(formvalue(&quot;maketemplate&quot;) ne &quot;&quot;) {
-        $check = formvalue(&quot;bit-$id&quot;, 0);
-    }
-    else {
-        # Checkbox is checked by default if $control is a default state.
-        $check = (($membercontrol == CONTROLMAPDEFAULT)
-                 || (($othercontrol == CONTROLMAPDEFAULT)
-                      &amp;&amp; (!Bugzilla-&gt;user-&gt;in_group($groupname))));
-    }
-
-    my $group = 
-    {
-        'bit' =&gt; $id , 
-        'checked' =&gt; $check , 
-        'description' =&gt; $description 
-    };
-
-    push @groups, $group;        
</del><ins>+my @groups = $cgi-&gt;param('groups');
+if ($cloned_bug) {
+    my @clone_groups = map { $_-&gt;name } @{ $cloned_bug-&gt;groups_in };
+    # It doesn't matter if there are duplicate names, since all we check
+    # for in the template is whether or not the group is set.
+    push(@groups, @clone_groups);
</ins><span class="cx"> }
</span><ins>+$default{'groups'} = \@groups;
</ins><span class="cx"> 
</span><del>-$vars-&gt;{'group'} = \@groups;
</del><ins>+Bugzilla::Hook::process('enter_bug_entrydefaultvars', { vars =&gt; $vars });
</ins><span class="cx"> 
</span><del>-Bugzilla::Hook::process(&quot;enter_bug-entrydefaultvars&quot;, { vars =&gt; $vars });
-
</del><span class="cx"> $vars-&gt;{'default'} = \%default;
</span><span class="cx"> 
</span><span class="cx"> my $format = $template-&gt;get_format(&quot;bug/create/create&quot;,
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsBmpConvertConfigpmfromrev173253trunkWebsitesbugswebkitorgextensionsexamplecodewebservicepl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/BmpConvert/Config.pm (from rev 173253, trunk/Websites/bugs.webkit.org/extensions/example/code/webservice.pl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/BmpConvert/Config.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/BmpConvert/Config.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,33 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Everything Solved, Inc.
+# Portions created by the Initial Developer are Copyright (C) 2009
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s): 
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+package Bugzilla::Extension::BmpConvert;
+use strict;
+use constant NAME =&gt; 'BmpConvert';
+use constant REQUIRED_MODULES =&gt; [
+  {
+      package =&gt; 'PerlMagick',
+      module  =&gt; 'Image::Magick',
+      version =&gt; 0,
+  },
+];
+
+__PACKAGE__-&gt;NAME;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsBmpConvertExtensionpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/extensions/BmpConvert/Extension.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/BmpConvert/Extension.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/BmpConvert/Extension.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,57 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Frédéric Buclin.
+# Portions created by Frédéric Buclin are Copyright (C) 2009
+# Frédéric Buclin. All Rights Reserved.
+#
+# Contributor(s): 
+#   Frédéric Buclin &lt;LpSolit@gmail.com&gt;
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+package Bugzilla::Extension::BmpConvert;
+use strict;
+use base qw(Bugzilla::Extension);
+
+use Image::Magick;
+
+our $VERSION = '1.0';
+
+sub attachment_process_data {
+    my ($self, $args) = @_;
+    return unless $args-&gt;{attributes}-&gt;{mimetype} eq 'image/bmp';
+
+    my $data = ${$args-&gt;{data}};
+    my $img = Image::Magick-&gt;new(magick =&gt; 'bmp');
+
+    # $data is a filehandle.
+    if (ref $data) {
+        $img-&gt;Read(file =&gt; \*$data);
+        $img-&gt;set(magick =&gt; 'png');
+        $img-&gt;Write(file =&gt; \*$data);
+    }
+    # $data is a blob.
+    else {
+        $img-&gt;BlobToImage($data);
+        $img-&gt;set(magick =&gt; 'png');
+        $data = $img-&gt;ImageToBlob();
+    }
+    undef $img;
+
+    ${$args-&gt;{data}} = $data;
+    $args-&gt;{attributes}-&gt;{mimetype} = 'image/png';
+    $args-&gt;{attributes}-&gt;{filename} =~ s/^(.+)\.bmp$/$1.png/i;
+}
+
+ __PACKAGE__-&gt;NAME;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsBmpConvertdisabledfromrev173253trunkWebsitesbugswebkitorgextensionsexampledisabled"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/BmpConvert/disabled (from rev 173253, trunk/Websites/bugs.webkit.org/extensions/example/disabled) ( => )</h4>
<pre class="diff"><span>
<span class="info">Copied: trunk/Websites/bugs.webkit.org/extensions/Example/Config.pm (from rev 173253, trunk/Websites/bugs.webkit.org/extensions/example/lib/WSExample.pm)
===================================================================
</span><del>--- trunk/Websites/bugs.webkit.org/extensions/Example/Config.pm                                (rev 0)
</del><ins>+++ trunk/Websites/bugs.webkit.org/extensions/Example/Config.pm        2014-10-16 16:00:58 UTC (rev 174764)
</ins><span class="lines">@@ -0,0 +1,42 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Everything Solved, Inc.
+# Portions created by the Initial Developers are Copyright (C) 2009 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+package Bugzilla::Extension::Example;
+use strict;
+use constant NAME =&gt; 'Example';
+use constant REQUIRED_MODULES =&gt; [
+    {
+        package =&gt; 'Data-Dumper',
+        module  =&gt; 'Data::Dumper',
+        version =&gt; 0,
+    },
+];
+
+use constant OPTIONAL_MODULES =&gt; [
+    {
+        package =&gt; 'Acme',
+        module  =&gt; 'Acme',
+        version =&gt; 1.11,
+        feature =&gt; ['example_acme'],
+    },
+];
+
+__PACKAGE__-&gt;NAME;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsExampleExtensionpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/extensions/Example/Extension.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Example/Extension.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Example/Extension.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,909 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Everything Solved, Inc.
+# Portions created by the Initial Developers are Copyright (C) 2009 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+#   Frédéric Buclin &lt;LpSolit@gmail.com&gt;
+
+package Bugzilla::Extension::Example;
+use strict;
+use base qw(Bugzilla::Extension);
+
+use Bugzilla::Constants;
+use Bugzilla::Error;
+use Bugzilla::Group;
+use Bugzilla::User;
+use Bugzilla::User::Setting;
+use Bugzilla::Util qw(diff_arrays html_quote);
+use Bugzilla::Status qw(is_open_state);
+use Bugzilla::Install::Filesystem;
+
+# This is extensions/Example/lib/Util.pm. I can load this here in my
+# Extension.pm only because I have a Config.pm.
+use Bugzilla::Extension::Example::Util;
+
+use Data::Dumper;
+
+# See bugmail_relationships.
+use constant REL_EXAMPLE =&gt; -127;
+
+our $VERSION = '1.0';
+
+sub attachment_process_data {
+    my ($self, $args) = @_;
+    my $type     = $args-&gt;{attributes}-&gt;{mimetype};
+    my $filename = $args-&gt;{attributes}-&gt;{filename};
+
+    # Make sure images have the correct extension.
+    # Uncomment the two lines below to make this check effective.
+    if ($type =~ /^image\/(\w+)$/) {
+        my $format = $1;
+        if ($filename =~ /^(.+)(:?\.[^\.]+)$/) {
+            my $name = $1;
+            #$args-&gt;{attributes}-&gt;{filename} = &quot;${name}.$format&quot;;
+        }
+        else {
+            # The file has no extension. We append it.
+            #$args-&gt;{attributes}-&gt;{filename} .= &quot;.$format&quot;;
+        }
+    }
+}
+
+sub auth_login_methods {
+    my ($self, $args) = @_;
+    my $modules = $args-&gt;{modules};
+    if (exists $modules-&gt;{Example}) {
+        $modules-&gt;{Example} = 'Bugzilla/Extension/Example/Auth/Login.pm';
+    }
+}
+
+sub auth_verify_methods {
+    my ($self, $args) = @_;
+    my $modules = $args-&gt;{modules};
+    if (exists $modules-&gt;{Example}) {
+        $modules-&gt;{Example} = 'Bugzilla/Extension/Example/Auth/Verify.pm';
+    }
+}
+
+sub bug_columns {
+    my ($self, $args) = @_;
+    my $columns = $args-&gt;{'columns'};
+    push (@$columns, &quot;delta_ts AS example&quot;)
+}
+
+sub bug_end_of_create {
+    my ($self, $args) = @_;
+
+    # This code doesn't actually *do* anything, it's just here to show you
+    # how to use this hook.
+    my $bug = $args-&gt;{'bug'};
+    my $timestamp = $args-&gt;{'timestamp'};
+    
+    my $bug_id = $bug-&gt;id;
+    # Uncomment this line to see a line in your webserver's error log whenever
+    # you file a bug.
+    # warn &quot;Bug $bug_id has been filed!&quot;;
+}
+
+sub bug_end_of_create_validators {
+    my ($self, $args) = @_;
+    
+    # This code doesn't actually *do* anything, it's just here to show you
+    # how to use this hook.
+    my $bug_params = $args-&gt;{'params'};
+    
+    # Uncomment this line below to see a line in your webserver's error log
+    # containing all validated bug field values every time you file a bug.
+    # warn Dumper($bug_params);
+    
+    # This would remove all ccs from the bug, preventing ANY ccs from being
+    # added on bug creation.
+    # $bug_params-&gt;{cc} = [];
+}
+
+sub bug_end_of_update {
+    my ($self, $args) = @_;
+    
+    # This code doesn't actually *do* anything, it's just here to show you
+    # how to use this hook.
+    my ($bug, $old_bug, $timestamp, $changes) = 
+        @$args{qw(bug old_bug timestamp changes)};
+    
+    foreach my $field (keys %$changes) {
+        my $used_to_be = $changes-&gt;{$field}-&gt;[0];
+        my $now_it_is  = $changes-&gt;{$field}-&gt;[1];
+    }
+
+    my $old_summary = $old_bug-&gt;short_desc;
+
+    my $status_message;
+    if (my $status_change = $changes-&gt;{'bug_status'}) {
+        my $old_status = new Bugzilla::Status({ name =&gt; $status_change-&gt;[0] });
+        my $new_status = new Bugzilla::Status({ name =&gt; $status_change-&gt;[1] });
+        if ($new_status-&gt;is_open &amp;&amp; !$old_status-&gt;is_open) {
+            $status_message = &quot;Bug re-opened!&quot;;
+        }
+        if (!$new_status-&gt;is_open &amp;&amp; $old_status-&gt;is_open) {
+            $status_message = &quot;Bug closed!&quot;;
+        }
+    }
+    
+    my $bug_id = $bug-&gt;id;
+    my $num_changes = scalar keys %$changes;
+    my $result = &quot;There were $num_changes changes to fields on bug $bug_id&quot;
+                 . &quot; at $timestamp.&quot;;
+    # Uncomment this line to see $result in your webserver's error log whenever
+    # you update a bug.
+    # warn $result;
+}
+
+sub bug_fields {
+    my ($self, $args) = @_;
+
+    my $fields = $args-&gt;{'fields'};
+    push (@$fields, &quot;example&quot;)
+}
+
+sub bug_format_comment {
+    my ($self, $args) = @_;
+    
+    # This replaces every occurrence of the word &quot;foo&quot; with the word
+    # &quot;bar&quot;
+    
+    my $regexes = $args-&gt;{'regexes'};
+    push(@$regexes, { match =&gt; qr/\bfoo\b/, replace =&gt; 'bar' });
+    
+    # And this links every occurrence of the word &quot;bar&quot; to example.com,
+    # but it won't affect &quot;foo&quot;s that have already been turned into &quot;bar&quot;
+    # above (because each regex is run in order, and later regexes don't modify
+    # earlier matches, due to some cleverness in Bugzilla's internals).
+    #
+    # For example, the phrase &quot;foo bar&quot; would become:
+    # bar &lt;a href=&quot;http://example.com/bar&quot;&gt;bar&lt;/a&gt;
+    my $bar_match = qr/\b(bar)\b/;
+    push(@$regexes, { match =&gt; $bar_match, replace =&gt; \&amp;_replace_bar });
+}
+
+# Used by bug_format_comment--see its code for an explanation.
+sub _replace_bar {
+    my $args = shift;
+    # $match is the first parentheses match in the $bar_match regex 
+    # in bug-format_comment.pl. We get up to 10 regex matches as 
+    # arguments to this function.
+    my $match = $args-&gt;{matches}-&gt;[0];
+    # Remember, you have to HTML-escape any data that you are returning!
+    $match = html_quote($match);
+    return qq{&lt;a href=&quot;http://example.com/&quot;&gt;$match&lt;/a&gt;};
+};
+
+sub buglist_columns {
+    my ($self, $args) = @_;
+    
+    my $columns = $args-&gt;{'columns'};
+    $columns-&gt;{'example'} = { 'name' =&gt; 'bugs.delta_ts' , 'title' =&gt; 'Example' };
+    $columns-&gt;{'product_desc'} = { 'name'  =&gt; 'prod_desc.description',
+                                   'title' =&gt; 'Product Description' };
+}
+
+sub buglist_column_joins {
+    my ($self, $args) = @_;
+    my $joins = $args-&gt;{'column_joins'};
+
+    # This column is added using the &quot;buglist_columns&quot; hook
+    $joins-&gt;{'product_desc'} = {
+        from  =&gt; 'product_id',
+        to    =&gt; 'id',
+        table =&gt; 'products',
+        as    =&gt; 'prod_desc',
+        join  =&gt; 'INNER',
+    };
+}
+
+sub search_operator_field_override {
+    my ($self, $args) = @_;
+    
+    my $operators = $args-&gt;{'operators'};
+
+    my $original = $operators-&gt;{component}-&gt;{_non_changed};
+    $operators-&gt;{component} = {
+        _non_changed =&gt; sub { _component_nonchanged($original, @_) }
+    };
+}
+
+sub _component_nonchanged {
+    my $original = shift;
+    my ($invocant, $args) = @_;
+
+    $invocant-&gt;$original($args);
+    # Actually, it does not change anything in the result,
+    # just an example.
+    $args-&gt;{term} = $args-&gt;{term} . &quot; OR 1=2&quot;;
+}
+
+sub bugmail_recipients {
+    my ($self, $args) = @_;
+    my $recipients = $args-&gt;{recipients};
+    my $bug = $args-&gt;{bug};
+
+    my $user = 
+        new Bugzilla::User({ name =&gt; Bugzilla-&gt;params-&gt;{'maintainer'} });
+
+    if ($bug-&gt;id == 1) {
+        # Uncomment the line below to add the maintainer to the recipients
+        # list of every bugmail from bug 1 as though that the maintainer
+        # were on the CC list.
+        #$recipients-&gt;{$user-&gt;id}-&gt;{+REL_CC} = 1;
+
+        # And this line adds the maintainer as though he had the &quot;REL_EXAMPLE&quot;
+        # relationship from the bugmail_relationships hook below.
+        #$recipients-&gt;{$user-&gt;id}-&gt;{+REL_EXAMPLE} = 1;
+    }
+}
+
+sub bugmail_relationships {
+    my ($self, $args) = @_;
+    my $relationships = $args-&gt;{relationships};
+    $relationships-&gt;{+REL_EXAMPLE} = 'Example';
+}
+
+sub config_add_panels {
+    my ($self, $args) = @_;
+    
+    my $modules = $args-&gt;{panel_modules};
+    $modules-&gt;{Example} = &quot;Bugzilla::Extension::Example::Config&quot;;
+}
+
+sub config_modify_panels {
+    my ($self, $args) = @_;
+    
+    my $panels = $args-&gt;{panels};
+    
+    # Add the &quot;Example&quot; auth methods.
+    my $auth_params = $panels-&gt;{'auth'}-&gt;{params};
+    my ($info_class)   = grep($_-&gt;{name} eq 'user_info_class', @$auth_params);
+    my ($verify_class) = grep($_-&gt;{name} eq 'user_verify_class', @$auth_params);
+
+    push(@{ $info_class-&gt;{choices} },   'CGI,Example');
+    push(@{ $verify_class-&gt;{choices} }, 'Example');
+
+    push(@$auth_params, { name =&gt; 'param_example',
+                          type =&gt; 't',
+                          default =&gt; 0,
+                          checker =&gt; \&amp;check_numeric });    
+}
+
+sub db_schema_abstract_schema {
+    my ($self, $args) = @_;
+#    $args-&gt;{'schema'}-&gt;{'example_table'} = {
+#        FIELDS =&gt; [
+#            id       =&gt; {TYPE =&gt; 'SMALLSERIAL', NOTNULL =&gt; 1,
+#                     PRIMARYKEY =&gt; 1},
+#            for_key  =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+#                           REFERENCES  =&gt; {TABLE  =&gt;  'example_table2',
+#                                           COLUMN =&gt;  'id',
+#                                           DELETE =&gt; 'CASCADE'}},
+#            col_3    =&gt; {TYPE =&gt; 'varchar(64)', NOTNULL =&gt; 1},
+#        ],
+#        INDEXES =&gt; [
+#            id_index_idx   =&gt; {FIELDS =&gt; ['col_3'], TYPE =&gt; 'UNIQUE'},
+#            for_id_idx =&gt; ['for_key'],
+#        ],
+#    };
+}
+
+sub email_in_before_parse {
+    my ($self, $args) = @_;
+
+    my $subject = $args-&gt;{mail}-&gt;header('Subject');
+    # Correctly extract the bug ID from email subjects of the form [Bug comp/NNN].
+    if ($subject =~ /\[.*(\d+)\].*/) {
+        $args-&gt;{fields}-&gt;{bug_id} = $1;
+    }
+}
+
+sub email_in_after_parse {
+    my ($self, $args) = @_;
+    my $reporter = $args-&gt;{fields}-&gt;{reporter};
+    my $dbh = Bugzilla-&gt;dbh;
+
+    # No other check needed if this is a valid regular user.
+    return if login_to_id($reporter);
+
+    # The reporter is not a regular user. We create an account for him,
+    # but he can only comment on existing bugs.
+    # This is useful for people who reply by email to bugmails received
+    # in mailing-lists.
+    if ($args-&gt;{fields}-&gt;{bug_id}) {
+        # WARNING: we return now to skip the remaining code below.
+        # You must understand that removing this line would make the code
+        # below effective! Do it only if you are OK with the behavior
+        # described here.
+        return;
+
+        Bugzilla::User-&gt;create({ login_name =&gt; $reporter, cryptpassword =&gt; '*' });
+
+        # For security reasons, delete all fields unrelated to comments.
+        foreach my $field (keys %{$args-&gt;{fields}}) {
+            next if $field =~ /^(?:bug_id|comment|reporter)$/;
+            delete $args-&gt;{fields}-&gt;{$field};
+        }
+    }
+    else {
+        ThrowUserError('invalid_username', { name =&gt; $reporter });
+    }
+}
+
+sub enter_bug_entrydefaultvars {
+    my ($self, $args) = @_;
+    
+    my $vars = $args-&gt;{vars};
+    $vars-&gt;{'example'} = 1;
+}
+
+sub error_catch {
+    my ($self, $args) = @_;
+    # Customize the error message displayed when someone tries to access
+    # page.cgi with an invalid page ID, and keep track of this attempt
+    # in the web server log.
+    return unless Bugzilla-&gt;error_mode == ERROR_MODE_WEBPAGE;
+    return unless $args-&gt;{error} eq 'bad_page_cgi_id';
+
+    my $page_id = $args-&gt;{vars}-&gt;{page_id};
+    my $login = Bugzilla-&gt;user-&gt;identity || &quot;Someone&quot;;
+    warn &quot;$login attempted to access page.cgi with id = $page_id&quot;;
+
+    my $page = $args-&gt;{message};
+    my $new_error_msg = &quot;Ah ah, you tried to access $page_id? Good try!&quot;;
+    $new_error_msg = html_quote($new_error_msg);
+    # There are better tools to parse an HTML page, but it's just an example.
+    $$page =~ s/(?&lt;=&lt;td id=&quot;error_msg&quot; class=&quot;throw_error&quot;&gt;).*(?=&lt;\/td&gt;)/$new_error_msg/si;
+}
+
+sub flag_end_of_update {
+    my ($self, $args) = @_;
+    
+    # This code doesn't actually *do* anything, it's just here to show you
+    # how to use this hook.
+    my $flag_params = $args;
+    my ($object, $timestamp, $old_flags, $new_flags) =
+        @$flag_params{qw(object timestamp old_flags new_flags)};
+    my ($removed, $added) = diff_arrays($old_flags, $new_flags);
+    my ($granted, $denied) = (0, 0);
+    foreach my $new_flag (@$added) {
+        $granted++ if $new_flag =~ /\+$/;
+        $denied++ if $new_flag =~ /-$/;
+    }
+    my $bug_id = $object-&gt;isa('Bugzilla::Bug') ? $object-&gt;id 
+                                               : $object-&gt;bug_id;
+    my $result = &quot;$granted flags were granted and $denied flags were denied&quot;
+                 . &quot; on bug $bug_id at $timestamp.&quot;;
+    # Uncomment this line to see $result in your webserver's error log whenever
+    # you update flags.
+    # warn $result;
+}
+
+sub group_before_delete {
+    my ($self, $args) = @_;
+    # This code doesn't actually *do* anything, it's just here to show you
+    # how to use this hook.
+
+    my $group = $args-&gt;{'group'};
+    my $group_id = $group-&gt;id;
+    # Uncomment this line to see a line in your webserver's error log whenever
+    # you file a bug.
+    # warn &quot;Group $group_id is about to be deleted!&quot;;
+}
+
+sub group_end_of_create {
+    my ($self, $args) = @_;
+    # This code doesn't actually *do* anything, it's just here to show you
+    # how to use this hook.
+    my $group = $args-&gt;{'group'};
+
+    my $group_id = $group-&gt;id;
+    # Uncomment this line to see a line in your webserver's error log whenever
+    # you create a new group.
+    #warn &quot;Group $group_id has been created!&quot;;
+}
+
+sub group_end_of_update {
+    my ($self, $args) = @_;
+    # This code doesn't actually *do* anything, it's just here to show you
+    # how to use this hook.
+
+    my ($group, $changes) = @$args{qw(group changes)};
+
+    foreach my $field (keys %$changes) {
+        my $used_to_be = $changes-&gt;{$field}-&gt;[0];
+        my $now_it_is  = $changes-&gt;{$field}-&gt;[1];
+    }
+
+    my $group_id = $group-&gt;id;
+    my $num_changes = scalar keys %$changes;
+    my $result = 
+        &quot;There were $num_changes changes to fields on group $group_id.&quot;;
+    # Uncomment this line to see $result in your webserver's error log whenever
+    # you update a group.
+    #warn $result;
+}
+
+sub install_before_final_checks {
+    my ($self, $args) = @_;
+    print &quot;Install-before_final_checks hook\n&quot; unless $args-&gt;{silent};
+    
+    # Add a new user setting like this:
+    #
+    # add_setting('product_chooser',           # setting name
+    #             ['pretty', 'full', 'small'], # options
+    #             'pretty');                   # default
+    #
+    # To add descriptions for the setting and choices, add extra values to 
+    # the hash defined in global/setting-descs.none.tmpl. Do this in a hook: 
+    # hook/global/setting-descs-settings.none.tmpl .
+}
+
+sub install_filesystem {
+    my ($self, $args) = @_;
+    my $create_dirs  = $args-&gt;{'create_dirs'};
+    my $recurse_dirs = $args-&gt;{'recurse_dirs'};
+    my $htaccess     = $args-&gt;{'htaccess'};
+
+    # Create a new directory in datadir specifically for this extension.
+    # The directory will need to allow files to be created by the extension
+    # code as well as allow the webserver to server content from it.
+    # my $data_path = bz_locations-&gt;{'datadir'} . &quot;/&quot; . __PACKAGE__-&gt;NAME;
+    # $create_dirs-&gt;{$data_path} = Bugzilla::Install::Filesystem::DIR_CGI_WRITE;
+   
+    # Update the permissions of any files and directories that currently reside
+    # in the extension's directory. 
+    # $recurse_dirs-&gt;{$data_path} = {
+    #     files =&gt; Bugzilla::Install::Filesystem::CGI_READ,
+    #     dirs  =&gt; Bugzilla::Install::Filesystem::DIR_CGI_WRITE
+    # };
+    
+    # Create a htaccess file that allows specific content to be served from the 
+    # extension's directory.
+    # $htaccess-&gt;{&quot;$data_path/.htaccess&quot;} = {
+    #     perms    =&gt; Bugzilla::Install::Filesystem::WS_SERVE,
+    #     contents =&gt; Bugzilla::Install::Filesystem::HT_DEFAULT_DENY
+    # };
+}
+
+sub install_update_db {
+    my $dbh = Bugzilla-&gt;dbh;
+#    $dbh-&gt;bz_add_column('example', 'new_column',
+#                        {TYPE =&gt; 'INT2', NOTNULL =&gt; 1, DEFAULT =&gt; 0});
+#    $dbh-&gt;bz_add_index('example', 'example_new_column_idx', [qw(value)]);
+}
+
+sub install_update_db_fielddefs {
+    my $dbh = Bugzilla-&gt;dbh;
+#    $dbh-&gt;bz_add_column('fielddefs', 'example_column', 
+#                        {TYPE =&gt; 'MEDIUMTEXT', NOTNULL =&gt; 1, DEFAULT =&gt; ''});
+}
+
+sub job_map {
+    my ($self, $args) = @_;
+    
+    my $job_map = $args-&gt;{job_map};
+    
+    # This adds the named class (an instance of TheSchwartz::Worker) as a
+    # handler for when a job is added with the name &quot;some_task&quot;.
+    $job_map-&gt;{'some_task'} = 'Bugzilla::Extension::Example::Job::SomeClass';
+    
+    # Schedule a job like this:
+    # my $queue = Bugzilla-&gt;job_queue();
+    # $queue-&gt;insert('some_task', { some_parameter =&gt; $some_variable });
+}
+
+sub mailer_before_send {
+    my ($self, $args) = @_;
+    
+    my $email = $args-&gt;{email};
+    # If you add a header to an email, it's best to start it with
+    # 'X-Bugzilla-&lt;Extension&gt;' so that you don't conflict with
+    # other extensions.
+    $email-&gt;header_set('X-Bugzilla-Example-Header', 'Example');
+}
+
+sub object_before_create {
+    my ($self, $args) = @_;
+    
+    my $class = $args-&gt;{'class'};
+    my $object_params = $args-&gt;{'params'};
+    
+    # Note that this is a made-up class, for this example.
+    if ($class-&gt;isa('Bugzilla::ExampleObject')) {
+        warn &quot;About to create an ExampleObject!&quot;;
+        warn &quot;Got the following parameters: &quot; 
+             . join(', ', keys(%$object_params));
+    }
+}
+
+sub object_before_delete {
+    my ($self, $args) = @_;
+
+    my $object = $args-&gt;{'object'};
+
+    # Note that this is a made-up class, for this example.
+    if ($object-&gt;isa('Bugzilla::ExampleObject')) {
+        my $id = $object-&gt;id;
+        warn &quot;An object with id $id is about to be deleted!&quot;;
+    } 
+}
+
+sub object_before_set {
+    my ($self, $args) = @_;
+    
+    my ($object, $field, $value) = @$args{qw(object field value)};
+    
+    # Note that this is a made-up class, for this example.
+    if ($object-&gt;isa('Bugzilla::ExampleObject')) {
+        warn &quot;The field $field is changing from &quot; . $object-&gt;{$field} 
+             . &quot; to $value!&quot;;
+    }
+}
+
+sub object_columns {
+    my ($self, $args) = @_;
+    my ($class, $columns) = @$args{qw(class columns)};
+
+    if ($class-&gt;isa('Bugzilla::ExampleObject')) {
+        push(@$columns, 'example');
+    }
+}
+
+sub object_end_of_create {
+    my ($self, $args) = @_;
+    
+    my $class  = $args-&gt;{'class'};
+    my $object = $args-&gt;{'object'};
+
+    warn &quot;Created a new $class object!&quot;;
+}
+
+sub object_end_of_create_validators {
+    my ($self, $args) = @_;
+    
+    my $class = $args-&gt;{'class'};
+    my $object_params = $args-&gt;{'params'};
+    
+    # Note that this is a made-up class, for this example.
+    if ($class-&gt;isa('Bugzilla::ExampleObject')) {
+        # Always set example_field to 1, even if the validators said otherwise.
+        $object_params-&gt;{example_field} = 1;
+    }
+    
+}
+
+sub object_end_of_set {
+    my ($self, $args) = @_;
+
+    my ($object, $field) = @$args{qw(object field)};
+
+    # Note that this is a made-up class, for this example.
+    if ($object-&gt;isa('Bugzilla::ExampleObject')) {
+        warn &quot;The field $field has changed to &quot; . $object-&gt;{$field};
+    }
+}
+
+sub object_end_of_set_all {
+    my ($self, $args) = @_;
+    
+    my $object = $args-&gt;{'object'};
+    my $object_params = $args-&gt;{'params'};
+    
+    # Note that this is a made-up class, for this example.
+    if ($object-&gt;isa('Bugzilla::ExampleObject')) {
+        if ($object_params-&gt;{example_field} == 1) {
+            $object-&gt;{example_field} = 1;
+        }
+    }
+    
+}
+
+sub object_end_of_update {
+    my ($self, $args) = @_;
+    
+    my ($object, $old_object, $changes) = 
+        @$args{qw(object old_object changes)};
+    
+    # Note that this is a made-up class, for this example.
+    if ($object-&gt;isa('Bugzilla::ExampleObject')) {
+        if (defined $changes-&gt;{'name'}) {
+            my ($old, $new) = @{ $changes-&gt;{'name'} };
+            print &quot;The name field changed from $old to $new!&quot;;
+        }
+    }
+}
+
+sub object_update_columns {
+    my ($self, $args) = @_;
+    my ($object, $columns) = @$args{qw(object columns)};
+
+    if ($object-&gt;isa('Bugzilla::ExampleObject')) {
+        push(@$columns, 'example');
+    }
+}
+
+sub object_validators {
+    my ($self, $args) = @_;
+    my ($class, $validators) = @$args{qw(class validators)};
+
+    if ($class-&gt;isa('Bugzilla::Bug')) {
+        # This is an example of adding a new validator.
+        # See the _check_example subroutine below.
+        $validators-&gt;{example} = \&amp;_check_example;
+
+        # This is an example of overriding an existing validator.
+        # See the check_short_desc validator below.
+        my $original = $validators-&gt;{short_desc};
+        $validators-&gt;{short_desc} = sub { _check_short_desc($original, @_) };
+    }
+}
+
+sub _check_example {
+    my ($invocant, $value, $field) = @_;
+    warn &quot;I was called to validate the value of $field.&quot;;
+    warn &quot;The value of $field that I was passed in is: $value&quot;;
+
+    # Make the value always be 1.
+    my $fixed_value = 1;
+    return $fixed_value;
+}
+
+sub _check_short_desc {
+    my $original = shift;
+    my $invocant = shift;
+    my $value = $invocant-&gt;$original(@_);
+    if ($value !~ /example/i) {
+        # Uncomment this line to make Bugzilla throw an error every time
+        # you try to file a bug or update a bug without the word &quot;example&quot;
+        # in the summary.
+        #ThrowUserError('example_short_desc_invalid');
+    }
+    return $value;
+}
+
+sub page_before_template {
+    my ($self, $args) = @_;
+    
+    my ($vars, $page) = @$args{qw(vars page_id)};
+    
+    # You can see this hook in action by loading page.cgi?id=example.html
+    if ($page eq 'example.html') {
+        $vars-&gt;{cgi_variables} = { Bugzilla-&gt;cgi-&gt;Vars };
+    }
+}
+
+sub post_bug_after_creation {
+    my ($self, $args) = @_;
+    
+    my $vars = $args-&gt;{vars};
+    $vars-&gt;{'example'} = 1;
+}
+
+sub product_confirm_delete {
+    my ($self, $args) = @_;
+    
+    my $vars = $args-&gt;{vars};
+    $vars-&gt;{'example'} = 1;
+}
+
+
+sub product_end_of_create {
+    my ($self, $args) = @_;
+
+    my $product = $args-&gt;{product};
+
+    # For this example, any lines of code that actually make changes to your
+    # database have been commented out.
+
+    # This section will take a group that exists in your installation
+    # (possible called test_group) and automatically makes the new
+    # product hidden to only members of the group. Just remove
+    # the restriction if you want the new product to be public.
+
+    my $example_group = new Bugzilla::Group({ name =&gt; 'example_group' });
+
+    if ($example_group) {
+        $product-&gt;set_group_controls($example_group, 
+                { entry          =&gt; 1,
+                  membercontrol  =&gt; CONTROLMAPMANDATORY,
+                  othercontrol   =&gt; CONTROLMAPMANDATORY });
+#        $product-&gt;update();
+    }
+
+    # This section will automatically add a default component
+    # to the new product called 'No Component'.
+
+    my $default_assignee = new Bugzilla::User(
+        { name =&gt; Bugzilla-&gt;params-&gt;{maintainer} });
+
+    if ($default_assignee) {
+#        Bugzilla::Component-&gt;create(
+#            { name             =&gt; 'No Component',
+#              product          =&gt; $product,
+#              description      =&gt; 'Select this component if one does not ' . 
+#                                  'exist in the current list of components',
+#              initialowner     =&gt; $default_assignee });
+    }
+}
+
+sub quicksearch_map {
+    my ($self, $args) = @_;
+    my $map = $args-&gt;{'map'};
+
+    # This demonstrates adding a shorter alias for a long custom field name.
+    $map-&gt;{'impact'} = $map-&gt;{'cf_long_field_name_for_impact_field'};
+}
+
+sub sanitycheck_check {
+    my ($self, $args) = @_;
+    
+    my $dbh = Bugzilla-&gt;dbh;
+    my $sth;
+    
+    my $status = $args-&gt;{'status'};
+    
+    # Check that all users are Australian
+    $status-&gt;('example_check_au_user');
+    
+    $sth = $dbh-&gt;prepare(&quot;SELECT userid, login_name
+                            FROM profiles
+                           WHERE login_name NOT LIKE '%.au'&quot;);
+    $sth-&gt;execute;
+    
+    my $seen_nonau = 0;
+    while (my ($userid, $login, $numgroups) = $sth-&gt;fetchrow_array) {
+        $status-&gt;('example_check_au_user_alert',
+                  { userid =&gt; $userid, login =&gt; $login },
+                  'alert');
+        $seen_nonau = 1;
+    }
+    
+    $status-&gt;('example_check_au_user_prompt') if $seen_nonau;
+}
+
+sub sanitycheck_repair {
+    my ($self, $args) = @_;
+    
+    my $cgi = Bugzilla-&gt;cgi;
+    my $dbh = Bugzilla-&gt;dbh;
+    
+    my $status = $args-&gt;{'status'};
+    
+    if ($cgi-&gt;param('example_repair_au_user')) {
+        $status-&gt;('example_repair_au_user_start');
+    
+        #$dbh-&gt;do(&quot;UPDATE profiles
+        #             SET login_name = CONCAT(login_name, '.au')
+        #           WHERE login_name NOT LIKE '%.au'&quot;);
+    
+        $status-&gt;('example_repair_au_user_end');
+    }
+}
+
+sub template_before_create {
+    my ($self, $args) = @_;
+    
+    my $config = $args-&gt;{'config'};
+    # This will be accessible as &quot;example_global_variable&quot; in every
+    # template in Bugzilla. See Bugzilla/Template.pm's create() function
+    # for more things that you can set.
+    $config-&gt;{VARIABLES}-&gt;{example_global_variable} = sub { return 'value' };
+}
+
+sub template_before_process {
+    my ($self, $args) = @_;
+    
+    my ($vars, $file, $context) = @$args{qw(vars file context)};
+
+    if ($file eq 'bug/edit.html.tmpl') {
+        $vars-&gt;{'viewing_the_bug_form'} = 1;
+    }
+}
+
+sub bug_check_can_change_field {
+    my ($self, $args) = @_;
+
+    my ($bug, $field, $new_value, $old_value, $priv_results)
+        = @$args{qw(bug field new_value old_value priv_results)};
+
+    my $user = Bugzilla-&gt;user;
+
+    # Disallow a bug from being reopened if currently closed unless user 
+    # is in 'admin' group
+    if ($field eq 'bug_status' &amp;&amp; $bug-&gt;product_obj-&gt;name eq 'Example') {
+        if (!is_open_state($old_value) &amp;&amp; is_open_state($new_value) 
+            &amp;&amp; !$user-&gt;in_group('admin')) 
+        {
+            push(@$priv_results, PRIVILEGES_REQUIRED_EMPOWERED);
+            return;
+        }
+    }
+
+    # Disallow a bug's keywords from being edited unless user is the
+    # reporter of the bug 
+    if ($field eq 'keywords' &amp;&amp; $bug-&gt;product_obj-&gt;name eq 'Example' 
+        &amp;&amp; $user-&gt;login ne $bug-&gt;reporter-&gt;login) 
+    {
+        push(@$priv_results, PRIVILEGES_REQUIRED_REPORTER);
+        return;
+    }
+
+    # Allow updating of priority even if user cannot normally edit the bug 
+    # and they are in group 'engineering'
+    if ($field eq 'priority' &amp;&amp; $bug-&gt;product_obj-&gt;name eq 'Example'
+        &amp;&amp; $user-&gt;in_group('engineering')) 
+    {
+        push(@$priv_results, PRIVILEGES_REQUIRED_NONE);
+        return;
+    }
+}
+
+sub admin_editusers_action {
+    my ($self, $args) = @_;
+    my ($vars, $action, $user) = @$args{qw(vars action user)};
+    my $template = Bugzilla-&gt;template;
+
+    if ($action eq 'my_action') {
+        # Allow to restrict the search to any group the user is allowed to bless.
+        $vars-&gt;{'restrictablegroups'} = $user-&gt;bless_groups();
+        $template-&gt;process('admin/users/search.html.tmpl', $vars)
+            || ThrowTemplateError($template-&gt;error());
+        exit;
+    }
+}
+
+sub user_preferences {
+    my ($self, $args) = @_;
+    my $tab = $args-&gt;{current_tab};
+    my $save = $args-&gt;{save_changes};
+    my $handled = $args-&gt;{handled};
+
+    return unless $tab eq 'my_tab';
+
+    my $value = Bugzilla-&gt;input_params-&gt;{'example_pref'};
+    if ($save) {
+        # Validate your data and update the DB accordingly.
+        $value =~ s/\s+/:/g;
+    }
+    $args-&gt;{'vars'}-&gt;{example_pref} = $value;
+
+    # Set the 'handled' scalar reference to true so that the caller
+    # knows the panel name is valid and that an extension took care of it.
+    $$handled = 1;
+}
+
+sub webservice {
+    my ($self, $args) = @_;
+
+    my $dispatch = $args-&gt;{dispatch};
+    $dispatch-&gt;{Example} = &quot;Bugzilla::Extension::Example::WebService&quot;;
+}
+
+sub webservice_error_codes {
+    my ($self, $args) = @_;
+    
+    my $error_map = $args-&gt;{error_map};
+    $error_map-&gt;{'example_my_error'} = 10001;
+}
+
+# This must be the last line of your extension.
+__PACKAGE__-&gt;NAME;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsExampledisabledfromrev173253trunkWebsitesbugswebkitorgextensionsexampledisabled"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/Example/disabled (from rev 173253, trunk/Websites/bugs.webkit.org/extensions/example/disabled) ( => )</h4>
<pre class="diff"><span>
<span class="info">Copied: trunk/Websites/bugs.webkit.org/extensions/Example/lib/Auth/Login.pm (from rev 173253, trunk/Websites/bugs.webkit.org/extensions/example/code/install-before_final_checks.pl)
===================================================================
</span><del>--- trunk/Websites/bugs.webkit.org/extensions/Example/lib/Auth/Login.pm                                (rev 0)
</del><ins>+++ trunk/Websites/bugs.webkit.org/extensions/Example/lib/Auth/Login.pm        2014-10-16 16:00:58 UTC (rev 174764)
</ins><span class="lines">@@ -0,0 +1,32 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Example Plugin.
+#
+# The Initial Developer of the Original Code is Canonical Ltd.
+# Portions created by Canonical are Copyright (C) 2008 Canonical Ltd.
+# All Rights Reserved.
+#
+# Contributor(s): Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+package Bugzilla::Extension::Example::Auth::Login;
+use strict;
+use base qw(Bugzilla::Auth::Login);
+use constant user_can_create_account =&gt; 0;
+use Bugzilla::Constants;
+
+# Always returns no data.
+sub get_login_info {
+    return { failure =&gt; AUTH_NODATA };
+}
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsExamplelibAuthVerifypmfromrev173253trunkWebsitesbugswebkitorgextensionsexamplecodeconfigpl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/Example/lib/Auth/Verify.pm (from rev 173253, trunk/Websites/bugs.webkit.org/extensions/example/code/config.pl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Example/lib/Auth/Verify.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Example/lib/Auth/Verify.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,31 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Example Plugin.
+#
+# The Initial Developer of the Original Code is Canonical Ltd.
+# Portions created by Canonical are Copyright (C) 2008 Canonical Ltd.
+# All Rights Reserved.
+#
+# Contributor(s): Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+package Bugzilla::Extension::Example::Auth::Verify;
+use strict;
+use base qw(Bugzilla::Auth::Verify);
+use Bugzilla::Constants;
+
+# A verifier that always fails.
+sub check_credentials {
+    return { failure =&gt; AUTH_NO_SUCH_USER };
+}
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsExamplelibConfigpmfromrev173253trunkWebsitesbugswebkitorgextensionsexamplelibConfigExamplepm"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/Example/lib/Config.pm (from rev 173253, trunk/Websites/bugs.webkit.org/extensions/example/lib/ConfigExample.pm) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Example/lib/Config.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Example/lib/Config.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,43 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Example Plugin.
+#
+# The Initial Developer of the Original Code is Canonical Ltd.
+# Portions created by Canonical Ltd. are Copyright (C) 2008
+# Canonical Ltd. All Rights Reserved.
+#
+# Contributor(s): Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+#                 Bradley Baetz &lt;bbaetz@acm.org&gt;
+
+package Bugzilla::Extension::Example::Config;
+use strict;
+use warnings;
+
+use Bugzilla::Config::Common;
+
+our $sortkey = 5000;
+
+sub get_param_list {
+    my ($class) = @_;
+
+    my @param_list = (
+    {
+        name =&gt; 'example_string',
+        type =&gt; 't',
+        default =&gt; 'EXAMPLE',
+    },
+    );
+    return @param_list;
+}
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsExamplelibUtilpmfromrev173253trunkWebsitesbugswebkitorgextensionsexamplecodewebserviceerror_codespl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/Example/lib/Util.pm (from rev 173253, trunk/Websites/bugs.webkit.org/extensions/example/code/webservice-error_codes.pl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Example/lib/Util.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Example/lib/Util.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,28 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Everything Solved, Inc.
+# Portions created by Everything Solved, Inc. are Copyright (C) 2009 
+# Everything Solved, Inc. All Rights Reserved.
+#
+# Contributor(s): Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+package Bugzilla::Extension::Example::Util;
+use strict;
+use warnings;
+
+# This file exists only to demonstrate how to use and name your
+# modules in an extension.
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsExamplelibWebServicepmfromrev173253trunkWebsitesbugswebkitorgextensionsexamplelibWSExamplepm"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/Example/lib/WebService.pm (from rev 173253, trunk/Websites/bugs.webkit.org/extensions/example/lib/WSExample.pm) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Example/lib/WebService.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Example/lib/WebService.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,32 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Everything Solved, Inc.
+# Portions created by Everything Solved, Inc. are Copyright (C) 2007 
+# Everything Solved, Inc. All Rights Reserved.
+#
+# Contributor(s): Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+package Bugzilla::Extension::Example::WebService;
+use strict;
+use warnings;
+use base qw(Bugzilla::WebService);
+use Bugzilla::Error;
+
+# This can be called as Example.hello() from the WebService.
+sub hello { return 'Hello!'; }
+
+sub throw_an_error { ThrowUserError('example_my_error') }
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsExampletemplateendefaultaccountprefsmy_tabhtmltmplfromrev173253trunkWebsitesbugswebkitorgextensionsexampletemplateendefaultadminparamsexamplehtmltmpl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/account/prefs/my_tab.html.tmpl (from rev 173253, trunk/Websites/bugs.webkit.org/extensions/example/template/en/default/admin/params/example.html.tmpl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/account/prefs/my_tab.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/account/prefs/my_tab.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,30 @@
</span><ins>+[%#
+  # The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Example Plugin.
+  #
+  # The Initial Developer of the Original Code is Frédéric Buclin.
+  # Portions created by the Initial Developer are Copyright (C) 2010
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s): Frédéric Buclin &lt;LpSolit@gmail.com&gt;
+  #%]
+
+&lt;p&gt;
+  Type some short text in the field below. Whitespaces will be replaced
+  by colons.
+&lt;/p&gt;
+
+&lt;p&gt;
+  &lt;label for=&quot;example_pref&quot;&gt;Short text:&lt;/label&gt;
+  &lt;input type=&quot;text&quot; id=&quot;example_pref&quot; name=&quot;example_pref&quot; size=&quot;30&quot;
+         maxlength=&quot;50&quot; value=&quot;[% example_pref FILTER html %]&quot;&gt;
+&lt;/p&gt;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsExampletemplateendefaultadminparamsexamplehtmltmplfromrev173253trunkWebsitesbugswebkitorgextensionsexampletemplateendefaultadminparamsexamplehtmltmpl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/admin/params/example.html.tmpl (from rev 173253, trunk/Websites/bugs.webkit.org/extensions/example/template/en/default/admin/params/example.html.tmpl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/admin/params/example.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/admin/params/example.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,28 @@
</span><ins>+[%#
+  # The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Example Plugin.
+  #
+  # The Initial Developer of the Original Code is Canonical Ltd.
+  # Portions created by Canonical Ltd. are Copyright (C) 2008
+  # Canonical Ltd. All Rights Reserved.
+  #
+  # Contributor(s): Bradley Baetz &lt;bbaetz@acm.org&gt;
+  #%]
+[%
+    title = &quot;Example Extension&quot;
+    desc = &quot;Configure example extension&quot;
+%]
+
+[% param_descs = {
+  example_string =&gt; &quot;Example string&quot;,
+}
+%]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsExampletemplateendefaulthookaccountprefsprefstabshtmltmplfromrev173253trunkWebsitesbugswebkitorgextensionsexampletemplateendefaultadminparamsexamplehtmltmpl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/hook/account/prefs/prefs-tabs.html.tmpl (from rev 173253, trunk/Websites/bugs.webkit.org/extensions/example/template/en/default/admin/params/example.html.tmpl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/hook/account/prefs/prefs-tabs.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/hook/account/prefs/prefs-tabs.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,23 @@
</span><ins>+[%#
+  # The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Example Plugin.
+  #
+  # The Initial Developer of the Original Code is Frédéric Buclin.
+  # Portions created by the Initial Developer are Copyright (C) 2010
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s): Frédéric Buclin &lt;LpSolit@gmail.com&gt;
+  #%]
+
+[% tabs = tabs.import([{ name =&gt; &quot;my_tab&quot;, label =&gt; &quot;Example Custom Preferences&quot;,
+                         link =&gt; &quot;userprefs.cgi?tab=my_tab&quot;, saveable =&gt; 1 }
+                      ]) %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsExampletemplateendefaulthookadminparamseditparamscurrent_panelhtmltmplfromrev173253trunkWebsitesbugswebkitorgtemplateendefaultattachmentdifffooterhtmltmpl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/hook/admin/params/editparams-current_panel.html.tmpl (from rev 173253, trunk/Websites/bugs.webkit.org/template/en/default/attachment/diff-footer.html.tmpl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/hook/admin/params/editparams-current_panel.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/hook/admin/params/editparams-current_panel.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,23 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Example Bugzilla Extension.
+  #
+  # The Initial Developer of the Original Code is Ali Ustek
+  # Portions created by the Initial Developer are Copyright (C) 2011 the
+  # Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s):
+  #   Ali Ustek &lt;aliustek@gmail.com&gt;
+  #%]
+
+[% IF panel.name == &quot;auth&quot; %]
+    [% panel.param_descs.param_example = 'Example new parameter' %]
+[% END -%]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsExampletemplateendefaulthookadminsanitycheckmessagesstatuseshtmltmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/hook/admin/sanitycheck/messages-statuses.html.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/hook/admin/sanitycheck/messages-statuses.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/hook/admin/sanitycheck/messages-statuses.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,36 @@
</span><ins>+[%# -*- Mode: perl; indent-tabs-mode: nil -*-
+  #
+  # The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Example Plugin.
+  #
+  # The Initial Developer of the Original Code is ITA Software
+  # Portions created by the Initial Developer are Copyright (C) 2009
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s): Bradley Baetz &lt;bbaetz@everythingsolved.com&gt;
+  #%]
+
+[% IF    san_tag == &quot;example_check_au_user&quot; %]
+  &lt;em&gt;EXAMPLE PLUGIN&lt;/em&gt; - Checking for non-Australian users.
+[% ELSIF san_tag == &quot;example_check_au_user_alert&quot; %]
+  User &amp;lt;[% login FILTER html %]&amp;gt; isn't Australian.
+  [% IF user.in_group('editusers') %]
+    &lt;a href=&quot;editusers.cgi?id=[% userid FILTER none %]&quot;&gt;Edit this user&lt;/a&gt;.
+  [% END %]
+[% ELSIF san_tag == &quot;example_check_au_user_prompt&quot; %]
+  &lt;a href=&quot;sanitycheck.cgi?example_repair_au_user=1&amp;amp;token=
+     [%- issue_hash_token(['sanitycheck']) FILTER uri %]&quot;&gt;Fix these users&lt;/a&gt;.
+[% ELSIF san_tag == &quot;example_repair_au_user_start&quot; %]
+  &lt;em&gt;EXAMPLE PLUGIN&lt;/em&gt; - OK, would now make users Australian.
+[% ELSIF san_tag == &quot;example_repair_au_user_end&quot; %]
+  &lt;em&gt;EXAMPLE PLUGIN&lt;/em&gt; - Users would now be Australian.
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsExampletemplateendefaulthookglobalsettingdescssettingsnonetmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/hook/global/setting-descs-settings.none.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/hook/global/setting-descs-settings.none.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/hook/global/setting-descs-settings.none.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,6 @@
</span><ins>+[% 
+    setting_descs.product_chooser = &quot;Product chooser to use when entering $terms.bugs&quot;,
+    setting_descs.pretty = &quot;Pretty chooser with common products and icons&quot;,
+    setting_descs.full   = &quot;Full chooser with all products&quot;,
+    setting_descs.small  = &quot;Product chooser for mobile devices&quot;,
+%]
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsExampletemplateendefaulthookglobalusererrorerrorshtmltmplfromrev173253trunkWebsitesbugswebkitorgextensionsexampletemplateenglobalusererrorerrorshtmltmpl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/hook/global/user-error-errors.html.tmpl (from rev 173253, trunk/Websites/bugs.webkit.org/extensions/example/template/en/global/user-error-errors.html.tmpl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/hook/global/user-error-errors.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/hook/global/user-error-errors.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,15 @@
</span><ins>+[%# Note that error messages should generally be indented four spaces, like
+  # below, because when Bugzilla translates an error message into plain
+  # text, it takes four spaces off the beginning of the lines. 
+  #
+  # Note also that I prefixed my error name with &quot;example&quot;, the name of my
+  # extension, so that I wouldn't conflict with other error names in
+  # Bugzilla or other extensions.
+  #%]
+[% IF error == &quot;example_my_error&quot; %]
+   [% title = &quot;Example Error Title&quot; %]
+   This is the error message! It contains &lt;em&gt;some html&lt;/em&gt;.
+[% ELSIF error == &quot;example_short_desc_invalid&quot; %]
+  [% title = &quot;Bad Summary&quot; %]
+  The Summary must contain the word &quot;example&quot;.
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsExampletemplateendefaultpagesexamplehtmltmplfromrev173253trunkWebsitesbugswebkitorgextensionsexampletemplateendefaultadminparamsexamplehtmltmpl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/pages/example.html.tmpl (from rev 173253, trunk/Websites/bugs.webkit.org/extensions/example/template/en/default/admin/params/example.html.tmpl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/pages/example.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/pages/example.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,32 @@
</span><ins>+[%#
+  # The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Example Plugin.
+  #
+  # The Initial Developer of the Original Code is Canonical Ltd.
+  # Portions created by Canonical Ltd. are Copyright (C) 2009
+  # Canonical Ltd. All Rights Reserved.
+  #
+  # Contributor(s): 
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[% PROCESS global/header.html.tmpl
+    title = &quot;Example Page&quot; 
+%]
+
+&lt;p&gt;Here's what you passed me:&lt;/p&gt;
+[% USE Dumper %]
+&lt;pre&gt;
+  [% Dumper.dump_html(cgi_variables) FILTER none %]
+&lt;/pre&gt;
+
+[% PROCESS global/footer.html.tmpl %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsExampletemplateendefaultsetupstringstxtplfromrev173253trunkWebsitesbugswebkitorgextensionsexamplecodewebserviceerror_codespl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/setup/strings.txt.pl (from rev 173253, trunk/Websites/bugs.webkit.org/extensions/example/code/webservice-error_codes.pl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/setup/strings.txt.pl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Example/template/en/default/setup/strings.txt.pl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,24 @@
</span><ins>+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Initial Developer of the Original Code is Everything Solved, Inc.
+# Portions created by the Initial Developer are Copyright (C) 2009 the
+# Initial Developer. All Rights Reserved.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# Contributor(s): 
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+%strings = (
+  feature_example_acme =&gt; 'Example Extension: Acme Feature',
+);
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsOldBugMoveConfigpmfromrev173253trunkWebsitesbugswebkitorgextensionsexamplecodeproductconfirm_deletepl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/OldBugMove/Config.pm (from rev 173253, trunk/Websites/bugs.webkit.org/extensions/example/code/product-confirm_delete.pl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/OldBugMove/Config.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/OldBugMove/Config.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,25 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the OldBugMove Bugzilla Extension.
+#
+# The Initial Developer of the Original Code is Everything Solved, Inc.
+# Portions created by the Initial Developer is Copyright (C) 2010 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+package Bugzilla::Extension::OldBugMove;
+use strict;
+use constant NAME =&gt; 'OldBugMove';
+__PACKAGE__-&gt;NAME;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsOldBugMoveExtensionpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/extensions/OldBugMove/Extension.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/OldBugMove/Extension.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/OldBugMove/Extension.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,208 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the OldBugMove Bugzilla Extension.
+#
+# The Initial Developer of the Original Code is Everything Solved, Inc.
+# Portions created by the Initial Developer are Copyright (C) 2010 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+package Bugzilla::Extension::OldBugMove;
+use strict;
+use base qw(Bugzilla::Extension);
+use Bugzilla::Constants;
+use Bugzilla::Error;
+use Bugzilla::Field::Choice;
+use Bugzilla::Mailer;
+use Bugzilla::User;
+use Bugzilla::Util qw(trim);
+
+use Scalar::Util qw(blessed);
+use Storable qw(dclone);
+
+use constant VERSION =&gt; BUGZILLA_VERSION;
+
+# This is 4 because that's what it originally was when this code was
+# a part of Bugzilla.
+use constant CMT_MOVED_TO =&gt; 4;
+
+sub install_update_db {
+    my $reso_type = Bugzilla::Field::Choice-&gt;type('resolution');
+    my $moved_reso = $reso_type-&gt;new({ name =&gt; 'MOVED' });
+    # We make the MOVED resolution inactive, so that it doesn't show up
+    # as a valid drop-down option.
+    if ($moved_reso) {
+        $moved_reso-&gt;set_is_active(0);
+        $moved_reso-&gt;update();
+    }
+    else {
+        print &quot;Creating the MOVED resolution...\n&quot;;
+        $reso_type-&gt;create(
+           { value   =&gt; 'MOVED', sortkey =&gt; '30000', isactive =&gt; 0 });
+    }
+}
+
+sub config_add_panels {
+    my ($self, $args) = @_;
+    my $modules = $args-&gt;{'panel_modules'};
+    $modules-&gt;{'OldBugMove'} = 'Bugzilla::Extension::OldBugMove::Params';
+}
+
+sub template_before_create {
+    my ($self, $args) = @_;
+    my $config = $args-&gt;{config};
+
+    my $constants = $config-&gt;{CONSTANTS};
+    $constants-&gt;{CMT_MOVED_TO} = CMT_MOVED_TO;
+
+    my $vars = $config-&gt;{VARIABLES};
+    $vars-&gt;{oldbugmove_user_is_mover} = \&amp;_user_is_mover;
+}
+
+sub object_before_delete {
+    my ($self, $args) = @_;
+    my $object = $args-&gt;{'object'};
+    if ($object-&gt;isa('Bugzilla::Field::Choice::resolution')) {
+        if ($object-&gt;name eq 'MOVED') {
+            ThrowUserError('oldbugmove_no_delete_moved');
+        }
+    }
+}
+
+sub object_before_set {
+    my ($self, $args) = @_;
+    my ($object, $field) = @$args{qw(object field)};
+    if ($field eq 'resolution' and $object-&gt;isa('Bugzilla::Bug')) {
+        # Store the old value so that end_of_set can check it.
+        $object-&gt;{'_oldbugmove_old_resolution'} = $object-&gt;resolution;
+    }
+}
+
+sub object_end_of_set {
+    my ($self, $args) = @_;
+    my ($object, $field) = @$args{qw(object field)};
+    if ($field eq 'resolution' and $object-&gt;isa('Bugzilla::Bug')) {
+        my $old_value = delete $object-&gt;{'_oldbugmove_old_resolution'};
+        return if $old_value eq $object-&gt;resolution;
+        if ($object-&gt;resolution eq 'MOVED') {
+            $object-&gt;add_comment('', { type =&gt; CMT_MOVED_TO,
+                                       extra_data =&gt; Bugzilla-&gt;user-&gt;login });
+        }
+    }
+}
+
+sub object_end_of_set_all {
+    my ($self, $args) = @_;
+    my $object = $args-&gt;{'object'};
+
+    if ($object-&gt;isa('Bugzilla::Bug') and Bugzilla-&gt;input_params-&gt;{'oldbugmove'}) {
+        my $new_status = Bugzilla-&gt;params-&gt;{'duplicate_or_move_bug_status'};
+        $object-&gt;set_bug_status($new_status, { resolution =&gt; 'MOVED' });
+    }
+}
+
+sub object_validators {
+    my ($self, $args) = @_;
+    my ($class, $validators) = @$args{qw(class validators)};
+    if ($class-&gt;isa('Bugzilla::Comment')) {
+        my $extra_data_validator = $validators-&gt;{extra_data};
+        $validators-&gt;{extra_data} = 
+            sub { _check_comment_extra_data($extra_data_validator, @_) };
+    }
+    elsif ($class-&gt;isa('Bugzilla::Bug')) {
+        my $reso_validator = $validators-&gt;{resolution};
+        $validators-&gt;{resolution} =
+            sub { _check_bug_resolution($reso_validator, @_) };
+    }
+}
+
+sub _check_bug_resolution {
+    my $original_validator = shift;
+    my ($invocant, $resolution) = @_;
+
+    if ($resolution eq 'MOVED' and !Bugzilla-&gt;input_params-&gt;{'oldbugmove'}) {
+        # MOVED has a special meaning and can only be used when
+        # really moving bugs to another installation.
+        ThrowUserError('oldbugmove_no_manual_move');
+    }
+
+    return $original_validator-&gt;(@_);
+}
+
+sub _check_comment_extra_data {
+    my $original_validator = shift;
+    my ($invocant, $extra_data, undef, $params) = @_;
+    my $type = blessed($invocant) ? $invocant-&gt;type : $params-&gt;{type};
+
+    if ($type == CMT_MOVED_TO) {
+        return Bugzilla::User-&gt;check($extra_data)-&gt;login;
+    }
+    return $original_validator-&gt;(@_);
+}
+
+sub bug_end_of_update {
+    my ($self, $args) = @_;
+    my ($bug, $old_bug, $changes) = @$args{qw(bug old_bug changes)};
+    if (defined $changes-&gt;{'resolution'}
+        and $changes-&gt;{'resolution'}-&gt;[1] eq 'MOVED')
+    {
+        $self-&gt;_move_bug($bug, $old_bug);
+    }
+}
+
+sub _move_bug {
+    my ($self, $bug, $old_bug) = @_;
+
+    my $dbh = Bugzilla-&gt;dbh;
+    my $template = Bugzilla-&gt;template;
+
+    _user_is_mover(Bugzilla-&gt;user) 
+        or ThrowUserError(&quot;auth_failure&quot;, { action =&gt; 'move',
+                                            object =&gt; 'bugs' });
+
+    # Don't export the new status and resolution. We want the current
+    # ones.
+    local $Storable::forgive_me = 1;
+    my $export_me = dclone($bug);
+    $export_me-&gt;{bug_status} = $old_bug-&gt;bug_status;
+    delete $export_me-&gt;{status};
+    $export_me-&gt;{resolution} = $old_bug-&gt;resolution;
+
+    # Prepare and send all data about these bugs to the new database
+    my $to = Bugzilla-&gt;params-&gt;{'move-to-address'};
+    $to =~ s/@/\@/;
+    my $from = Bugzilla-&gt;params-&gt;{'mailfrom'};
+    $from =~ s/@/\@/;
+    my $msg = &quot;To: $to\n&quot;;
+    $msg .= &quot;From: Bugzilla &lt;&quot; . $from . &quot;&gt;\n&quot;;
+    $msg .= &quot;Subject: Moving bug &quot; . $bug-&gt;id . &quot;\n\n&quot;;
+    my @fieldlist = (Bugzilla::Bug-&gt;fields, 'group', 'long_desc',
+                     'attachment', 'attachmentdata');
+    my %displayfields = map { $_ =&gt; 1 } @fieldlist;
+    my $vars = { bugs =&gt; [$export_me], displayfields =&gt; \%displayfields };
+    $template-&gt;process(&quot;bug/show.xml.tmpl&quot;, $vars, \$msg)
+      || ThrowTemplateError($template-&gt;error());
+    $msg .= &quot;\n&quot;;
+    MessageToMTA($msg);
+}
+
+sub _user_is_mover {
+    my $user = shift;
+
+    my @movers = map { trim($_) } split(',', Bugzilla-&gt;params-&gt;{'movers'});
+    return ($user-&gt;id and grep($_ eq $user-&gt;login, @movers)) ? 1 : 0;
+}
+
+__PACKAGE__-&gt;NAME;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsOldBugMovedisabledfromrev173253trunkWebsitesbugswebkitorgextensionsexampledisabled"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/OldBugMove/disabled (from rev 173253, trunk/Websites/bugs.webkit.org/extensions/example/disabled) ( => )</h4>
<pre class="diff"><span>
<span class="info">Copied: trunk/Websites/bugs.webkit.org/extensions/OldBugMove/lib/Params.pm (from rev 173253, trunk/Websites/bugs.webkit.org/Bugzilla/Config/BugMove.pm)
===================================================================
</span><del>--- trunk/Websites/bugs.webkit.org/extensions/OldBugMove/lib/Params.pm                                (rev 0)
</del><ins>+++ trunk/Websites/bugs.webkit.org/extensions/OldBugMove/lib/Params.pm        2014-10-16 16:00:58 UTC (rev 174764)
</ins><span class="lines">@@ -0,0 +1,60 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Netscape Communications
+# Corporation. Portions created by Netscape are
+# Copyright (C) 1998 Netscape Communications Corporation. All
+# Rights Reserved.
+#
+# Contributor(s): Terry Weissman &lt;terry@mozilla.org&gt;
+#                 Dawn Endico &lt;endico@mozilla.org&gt;
+#                 Dan Mosedale &lt;dmose@mozilla.org&gt;
+#                 Joe Robins &lt;jmrobins@tgix.com&gt;
+#                 Jacob Steenhagen &lt;jake@bugzilla.org&gt;
+#                 J. Paul Reed &lt;preed@sigkill.com&gt;
+#                 Bradley Baetz &lt;bbaetz@student.usyd.edu.au&gt;
+#                 Joseph Heenan &lt;joseph@heenan.me.uk&gt;
+#                 Erik Stambaugh &lt;erik@dasbistro.com&gt;
+#                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
+#
+
+package Bugzilla::Extension::OldBugMove::Params;
+
+use strict;
+
+use Bugzilla::Config::Common;
+
+our $sortkey = 700;
+
+use constant get_param_list =&gt; (
+  {
+   name =&gt; 'move-to-url',
+   type =&gt; 't',
+   default =&gt; ''
+  },
+
+  {
+   name =&gt; 'move-to-address',
+   type =&gt; 't',
+   default =&gt; 'bugzilla-import'
+  },
+
+  {
+   name =&gt; 'movers',
+   type =&gt; 't',
+   default =&gt; ''
+  },
+);
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsOldBugMovetemplateendefaultadminparamsoldbugmovehtmltmplfromrev173253trunkWebsitesbugswebkitorgtemplateendefaultsearchtabshtmltmpl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/admin/params/oldbugmove.html.tmpl (from rev 173253, trunk/Websites/bugs.webkit.org/template/en/default/search/tabs.html.tmpl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/admin/params/oldbugmove.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/admin/params/oldbugmove.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,40 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Netscape Communications
+  # Corporation. Portions created by Netscape are
+  # Copyright (C) 1998 Netscape Communications Corporation. All
+  # Rights Reserved.
+  #
+  # Contributor(s): Dave Miller &lt;justdave@bugzilla.org&gt;
+  #                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
+  #%]
+[%
+   title = &quot;$terms.Bug Moving&quot;
+   desc = &quot;Set up parameters to move $terms.bugs to/from another installation&quot;
+%]
+
+[% param_descs = {
+
+  &quot;move-to-url&quot; =&gt; 
+    &quot;The URL of the database we allow some of our $terms.bugs to&quot;
+    _ &quot; be moved to.&quot;,
+
+  &quot;move-to-address&quot; =&gt; 
+    &quot;To move ${terms.bugs}, an email is sent to the target database.&quot;
+    _ &quot; This is the email address that that database uses to listen&quot;
+    _ &quot; for incoming ${terms.bugs}.&quot;,
+
+  movers =&gt; 
+    &quot;A list of people with permission to move $terms.bugs &quot;,
+
+} %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsOldBugMovetemplateendefaulthookbugeditafter_comment_textareahtmltmplfromrev173253trunkWebsitesbugswebkitorgtemplateendefaultglobalhelphtmltmpl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/hook/bug/edit-after_comment_textarea.html.tmpl (from rev 173253, trunk/Websites/bugs.webkit.org/template/en/default/global/help.html.tmpl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/hook/bug/edit-after_comment_textarea.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/hook/bug/edit-after_comment_textarea.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,27 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2010
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s):
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[% IF oldbugmove_user_is_mover(user) AND bug.resolution != 'MOVED' %]
+  &lt;p&gt;
+    &lt;input type=&quot;submit&quot; id=&quot;oldbugmove&quot; name=&quot;oldbugmove&quot;
+           value=&quot;Move [% terms.Bug FILTER html %] to 
+                  [%= Param('move-to-url') FILTER html %]&quot;&gt;
+  &lt;/p&gt;
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsOldBugMovetemplateendefaulthookbugformat_commenttypetxttmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/hook/bug/format_comment-type.txt.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/hook/bug/format_comment-type.txt.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/hook/bug/format_comment-type.txt.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,29 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2010
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s):
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[% IF comment.type == constants.CMT_MOVED_TO %]
+[% comment.body %]
+
+[%+ terms.Bug %] moved to [% Param(&quot;move-to-url&quot;) %].
+If the move succeeded, [% comment.extra_data FILTER email %] will receive a mail
+containing the number of the new [% terms.bug %] in the other database.
+If all went well, please paste in a link to the new [% terms.bug %]. 
+Otherwise, reopen this [% terms.bug %].
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsOldBugMovetemplateendefaulthookglobalusererrorauth_failure_actionhtmltmplfromrev173253trunkWebsitesbugswebkitorgtemplateendefaultattachmentdifffooterhtmltmpl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/hook/global/user-error-auth_failure_action.html.tmpl (from rev 173253, trunk/Websites/bugs.webkit.org/template/en/default/attachment/diff-footer.html.tmpl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/hook/global/user-error-auth_failure_action.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/hook/global/user-error-auth_failure_action.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,23 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2010
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s):
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[% IF action == &quot;move&quot; %]
+  move
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsOldBugMovetemplateendefaulthookglobalusererrorerrorshtmltmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/hook/global/user-error-errors.html.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/hook/global/user-error-errors.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/hook/global/user-error-errors.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,29 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2010
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s):
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[% IF error == &quot;oldbugmove_no_delete_moved&quot; %]
+    As long as the OldBugMove extension is active, you cannot
+    delete the [%+ display_value(&quot;resolution&quot;, &quot;MOVED&quot;) FILTER html %]
+    resolution.
+[% ELSIF error == &quot;oldbugmove_no_manual_move&quot; %]
+    You cannot set the resolution of [% terms.abug %] to 
+    [%+ display_value(&quot;resolution&quot;, &quot;MOVED&quot;) FILTER html %] without
+    moving the [% terms.bug %].
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsOldBugMovetemplateendefaulthooklisteditmultipleafter_groupshtmltmplfromrev173253trunkWebsitesbugswebkitorgtemplateendefaultattachmentdifffooterhtmltmpl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/hook/list/edit-multiple-after_groups.html.tmpl (from rev 173253, trunk/Websites/bugs.webkit.org/template/en/default/attachment/diff-footer.html.tmpl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/hook/list/edit-multiple-after_groups.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/OldBugMove/template/en/default/hook/list/edit-multiple-after_groups.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,28 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2010
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s):
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #   Frédéric Buclin &lt;LpSolit@gmail.com&gt;
+  #%]
+
+[% IF oldbugmove_user_is_mover(user) %]
+  &lt;p&gt;
+    &lt;input type=&quot;submit&quot; id=&quot;oldbugmove&quot; name=&quot;oldbugmove&quot;
+           value=&quot;Move [% terms.Bugs FILTER html %] to 
+                  [%= Param('move-to-url') FILTER html %]&quot;&gt;
+  &lt;/p&gt;
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsVotingExtensionpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/extensions/Voting/Extension.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Voting/Extension.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Voting/Extension.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,888 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Netscape Communications
+# Corporation. Portions created by Netscape are
+# Copyright (C) 1998 Netscape Communications Corporation. All
+# Rights Reserved.
+#
+# Contributor(s): Terry Weissman &lt;terry@mozilla.org&gt;
+#                 Stephan Niemz  &lt;st.n@gmx.net&gt;
+#                 Christopher Aillon &lt;christopher@aillon.com&gt;
+#                 Gervase Markham &lt;gerv@gerv.net&gt;
+#                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
+#                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+package Bugzilla::Extension::Voting;
+use strict;
+use base qw(Bugzilla::Extension);
+
+use Bugzilla::Bug;
+use Bugzilla::BugMail;
+use Bugzilla::Constants;
+use Bugzilla::Error;
+use Bugzilla::Field;
+use Bugzilla::Mailer;
+use Bugzilla::User;
+use Bugzilla::Util qw(detaint_natural);
+use Bugzilla::Token;
+
+use List::Util qw(min);
+
+use constant NAME =&gt; 'Voting';
+use constant VERSION =&gt; BUGZILLA_VERSION;
+use constant DEFAULT_VOTES_PER_BUG =&gt; 1;
+# These came from Bugzilla itself, so they maintain the old numbers
+# they had before.
+use constant CMT_POPULAR_VOTES =&gt; 3;
+use constant REL_VOTER =&gt; 4;
+
+################
+# Installation #
+################
+
+BEGIN {
+    *Bugzilla::Bug::votes = \&amp;votes;
+}
+
+sub votes {
+    my $self = shift;
+    my $dbh = Bugzilla-&gt;dbh;
+
+    return $self-&gt;{votes} if exists $self-&gt;{votes};
+
+    $self-&gt;{votes} = $dbh-&gt;selectrow_array('SELECT votes FROM bugs WHERE bug_id = ?',
+                                           undef, $self-&gt;id);
+    return $self-&gt;{votes};
+}
+
+sub db_schema_abstract_schema {
+    my ($self, $args) = @_;
+    $args-&gt;{'schema'}-&gt;{'votes'} = {
+        FIELDS =&gt; [
+            who        =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                           REFERENCES =&gt; {TABLE  =&gt; 'profiles',
+                                          COLUMN =&gt; 'userid',
+                                          DELETE =&gt; 'CASCADE'}},
+            bug_id     =&gt; {TYPE =&gt; 'INT3', NOTNULL =&gt; 1,
+                           REFERENCES  =&gt; {TABLE  =&gt;  'bugs',
+                                           COLUMN =&gt;  'bug_id',
+                                           DELETE =&gt; 'CASCADE'}},
+            vote_count =&gt; {TYPE =&gt; 'INT2', NOTNULL =&gt; 1},
+        ],
+        INDEXES =&gt; [
+            votes_who_idx    =&gt; ['who'],
+            votes_bug_id_idx =&gt; ['bug_id'],
+        ],
+    };
+}
+
+sub install_update_db {
+    my $dbh = Bugzilla-&gt;dbh;
+    # Note that before Bugzilla 4.0, voting was a built-in part of Bugzilla,
+    # so updates to the columns for old versions of Bugzilla happen in
+    # Bugzilla::Install::DB, and can't safely be moved to this extension.
+
+    my $field = new Bugzilla::Field({ name =&gt; 'votes' });
+    if (!$field) {
+        Bugzilla::Field-&gt;create(
+            { name =&gt; 'votes', description =&gt; 'Votes', buglist =&gt; 1 });
+    }
+
+    $dbh-&gt;bz_add_column('products', 'votesperuser',
+        {TYPE =&gt; 'INT2', NOTNULL =&gt; 1, DEFAULT =&gt; 0});
+    $dbh-&gt;bz_add_column('products', 'maxvotesperbug', 
+        {TYPE =&gt; 'INT2', NOTNULL =&gt; 1, DEFAULT =&gt; DEFAULT_VOTES_PER_BUG});
+    $dbh-&gt;bz_add_column('products', 'votestoconfirm',
+        {TYPE =&gt; 'INT2', NOTNULL =&gt; 1, DEFAULT =&gt; 0});
+
+    $dbh-&gt;bz_add_column('bugs', 'votes',
+        {TYPE =&gt; 'INT3', NOTNULL =&gt; 1, DEFAULT =&gt; 0});
+    $dbh-&gt;bz_add_index('bugs', 'bugs_votes_idx', ['votes']);
+
+    # maxvotesperbug used to default to 10,000, which isn't very sensible.
+    my $per_bug = $dbh-&gt;bz_column_info('products', 'maxvotesperbug');
+    if ($per_bug-&gt;{DEFAULT} != DEFAULT_VOTES_PER_BUG) {
+        $dbh-&gt;bz_alter_column('products', 'maxvotesperbug',
+            {TYPE =&gt; 'INT2', NOTNULL =&gt; 1, DEFAULT =&gt; DEFAULT_VOTES_PER_BUG});
+    }
+}
+
+###########
+# Objects #
+###########
+
+sub object_columns {
+    my ($self, $args) = @_;
+    my ($class, $columns) = @$args{qw(class columns)};
+    if ($class-&gt;isa('Bugzilla::Bug')) {
+        push(@$columns, 'votes');
+    }
+    elsif ($class-&gt;isa('Bugzilla::Product')) {
+        push(@$columns, qw(votesperuser maxvotesperbug votestoconfirm));
+    }
+}
+
+sub bug_fields {
+    my ($self, $args) = @_;
+    my $fields = $args-&gt;{fields};
+    push(@$fields, 'votes');
+}
+
+sub object_update_columns {
+    my ($self, $args) = @_;
+    my ($object, $columns) = @$args{qw(object columns)};
+    if ($object-&gt;isa('Bugzilla::Product')) {
+        push(@$columns, qw(votesperuser maxvotesperbug votestoconfirm));
+    }
+}
+
+sub object_validators {
+    my ($self, $args) = @_;
+    my ($class, $validators) = @$args{qw(class validators)};
+    if ($class-&gt;isa('Bugzilla::Product')) {
+        $validators-&gt;{'votesperuser'}   = \&amp;_check_votesperuser;
+        $validators-&gt;{'maxvotesperbug'} = \&amp;_check_maxvotesperbug;
+        $validators-&gt;{'votestoconfirm'} = \&amp;_check_votestoconfirm;
+    }
+}
+
+sub object_before_create {
+    my ($self, $args) = @_;
+    my ($class, $params) = @$args{qw(class params)};
+    if ($class-&gt;isa('Bugzilla::Bug')) {
+        # Don't ever allow people to directly specify &quot;votes&quot; into the bugs
+        # table.
+        delete $params-&gt;{votes};
+    }
+    elsif ($class-&gt;isa('Bugzilla::Product')) {
+        my $input = Bugzilla-&gt;input_params;
+        $params-&gt;{votesperuser}   = $input-&gt;{'votesperuser'};
+        $params-&gt;{maxvotesperbug} = $input-&gt;{'maxvotesperbug'};
+        $params-&gt;{votestoconfirm} = $input-&gt;{'votestoconfirm'};
+    }
+}
+
+sub object_end_of_set_all {
+    my ($self, $args) = @_;
+    my ($object) = $args-&gt;{object};
+    if ($object-&gt;isa('Bugzilla::Product')) {
+        my $input = Bugzilla-&gt;input_params;
+        $object-&gt;set('votesperuser',   $input-&gt;{'votesperuser'});
+        $object-&gt;set('maxvotesperbug', $input-&gt;{'maxvotesperbug'});
+        $object-&gt;set('votestoconfirm', $input-&gt;{'votestoconfirm'});
+    }
+}
+
+sub object_end_of_update {
+    my ($self, $args) = @_;
+    my ($object, $changes) = @$args{qw(object changes)};
+    if ( $object-&gt;isa('Bugzilla::Product')
+         and ($changes-&gt;{maxvotesperbug} or $changes-&gt;{votesperuser} 
+              or $changes-&gt;{votestoconfirm}) ) 
+    {
+        _modify_bug_votes($object, $changes);
+    }
+}
+
+sub bug_end_of_update {
+    my ($self, $args) = @_;
+    my ($bug, $changes) = @$args{qw(bug changes)};
+
+    if ($changes-&gt;{'product'}) {
+        my @msgs;
+        # If some votes have been removed, RemoveVotes() returns
+        # a list of messages to send to voters.
+        @msgs = _remove_votes($bug-&gt;id, 0, 'votes_bug_moved');
+        _confirm_if_vote_confirmed($bug-&gt;id);
+
+        foreach my $msg (@msgs) {
+            MessageToMTA($msg);
+        }
+    }
+}
+
+#############
+# Templates #
+#############
+
+sub template_before_create {
+    my ($self, $args) = @_;
+    my $config = $args-&gt;{config};
+    my $constants = $config-&gt;{CONSTANTS};
+    $constants-&gt;{REL_VOTER} = REL_VOTER;
+    $constants-&gt;{CMT_POPULAR_VOTES} = CMT_POPULAR_VOTES;
+    $constants-&gt;{DEFAULT_VOTES_PER_BUG} = DEFAULT_VOTES_PER_BUG;
+}
+
+
+sub template_before_process {
+    my ($self, $args) = @_;
+    my ($vars, $file) = @$args{qw(vars file)};
+    if ($file eq 'admin/users/confirm-delete.html.tmpl') {
+        my $who = $vars-&gt;{otheruser};
+        my $votes = Bugzilla-&gt;dbh-&gt;selectrow_array(
+            'SELECT COUNT(*) FROM votes WHERE who = ?', undef, $who-&gt;id);
+        if ($votes) {
+            $vars-&gt;{other_safe} = 1;
+            $vars-&gt;{votes} = $votes;
+        }
+    }
+}
+
+###########
+# Bugmail #
+###########
+
+sub bugmail_recipients {
+    my ($self, $args) = @_;
+    my ($bug, $recipients) = @$args{qw(bug recipients)};
+    my $dbh = Bugzilla-&gt;dbh;
+
+    my $voters = $dbh-&gt;selectcol_arrayref(
+        &quot;SELECT who FROM votes WHERE bug_id = ?&quot;, undef, $bug-&gt;id);
+    $recipients-&gt;{$_}-&gt;{+REL_VOTER} = 1 foreach (@$voters);
+}
+
+sub bugmail_relationships {
+    my ($self, $args) = @_;
+    my $relationships = $args-&gt;{relationships};
+    $relationships-&gt;{+REL_VOTER} = 'Voter';
+}
+
+###############
+# Sanitycheck #
+###############
+
+sub sanitycheck_check {
+    my ($self, $args) = @_;
+    my $status = $args-&gt;{status};
+
+    # Vote Cache
+    $status-&gt;('voting_count_start');
+    my $dbh = Bugzilla-&gt;dbh;
+    my %cached_counts = @{ $dbh-&gt;selectcol_arrayref(
+        'SELECT bug_id, votes FROM bugs', {Columns=&gt;[1,2]}) };
+
+    my %real_counts = @{ $dbh-&gt;selectcol_arrayref(
+        'SELECT bug_id, SUM(vote_count) FROM votes '
+        . $dbh-&gt;sql_group_by('bug_id'), {Columns=&gt;[1,2]}) };
+
+    my $needs_rebuild;
+    foreach my $id (keys %cached_counts) {
+        my $cached_count = $cached_counts{$id};
+        my $real_count = $real_counts{$id} || 0;
+        if ($cached_count &lt; 0) {
+            $status-&gt;('voting_count_alert', { id =&gt; $id }, 'alert');
+        }
+        elsif ($cached_count != $real_count) {
+            $status-&gt;('voting_cache_alert', { id =&gt; $id }, 'alert');
+            $needs_rebuild = 1;
+        }
+    }
+
+    $status-&gt;('voting_cache_rebuild_fix') if $needs_rebuild;
+}
+
+sub sanitycheck_repair {
+    my ($self, $args) = @_;
+    my $status = $args-&gt;{status};
+    my $input = Bugzilla-&gt;input_params;
+    my $dbh = Bugzilla-&gt;dbh;
+
+    return if !$input-&gt;{rebuild_vote_cache};
+
+    $status-&gt;('voting_cache_rebuild_start');
+    $dbh-&gt;bz_start_transaction();
+    $dbh-&gt;do('UPDATE bugs SET votes = 0');
+
+    my $sth = $dbh-&gt;prepare(
+        'SELECT bug_id, SUM(vote_count) FROM votes '
+        . $dbh-&gt;sql_group_by('bug_id'));
+    $sth-&gt;execute();
+
+    my $sth_update = $dbh-&gt;prepare(
+        'UPDATE bugs SET votes = ? WHERE bug_id = ?');
+    while (my ($id, $count) = $sth-&gt;fetchrow_array) {
+        $sth_update-&gt;execute($count, $id);
+    }
+    $dbh-&gt;bz_commit_transaction();
+    $status-&gt;('voting_cache_rebuild_end');
+}
+
+
+##############
+# Validators #
+##############
+
+sub _check_votesperuser {
+    return _check_votes(0, @_);
+}
+
+sub _check_maxvotesperbug {
+    return _check_votes(DEFAULT_VOTES_PER_BUG, @_);
+}
+
+sub _check_votestoconfirm {
+    return _check_votes(0, @_);
+}
+
+# This subroutine is only used internally by other _check_votes_* validators.
+sub _check_votes {
+    my ($default, $invocant, $votes, $field) = @_;
+
+    detaint_natural($votes) if defined $votes;
+    # On product creation, if the number of votes is not a valid integer,
+    # we silently fall back to the given default value.
+    # If the product already exists and the change is illegal, we complain.
+    if (!defined $votes) {
+        if (ref $invocant) {
+            ThrowUserError('voting_product_illegal_votes',
+                           { field =&gt; $field, votes =&gt; $_[2] });
+        }
+        else {
+            $votes = $default;
+        }
+    }
+    return $votes;
+}
+
+#########
+# Pages #
+#########
+
+sub page_before_template {
+    my ($self, $args) = @_;
+    my $page = $args-&gt;{page_id};
+    my $vars = $args-&gt;{vars};
+
+    if ($page =~ m{^voting/bug\.}) {
+        _page_bug($vars);
+    }
+    elsif ($page =~ m{^voting/user\.}) {
+        _page_user($vars);
+    }
+}
+
+sub _page_bug {
+    my ($vars) = @_;
+    my $dbh = Bugzilla-&gt;dbh;
+    my $input = Bugzilla-&gt;input_params;
+
+    my $bug_id = $input-&gt;{bug_id};
+    my $bug = Bugzilla::Bug-&gt;check($bug_id);
+
+    $vars-&gt;{'bug'} = $bug;
+    $vars-&gt;{'users'} =
+        $dbh-&gt;selectall_arrayref('SELECT profiles.login_name,
+                                         profiles.userid AS id,
+                                         votes.vote_count
+                                    FROM votes
+                              INNER JOIN profiles
+                                      ON profiles.userid = votes.who
+                                   WHERE votes.bug_id = ?',
+                                  {Slice=&gt;{}}, $bug-&gt;id);
+}
+
+sub _page_user {
+    my ($vars) = @_;
+    my $dbh = Bugzilla-&gt;dbh;
+    my $user = Bugzilla-&gt;user;
+    my $input = Bugzilla-&gt;input_params;
+
+    my $action = $input-&gt;{action};
+    if ($action and $action eq 'vote') {
+        _update_votes($vars);
+    }
+
+    # If a bug_id is given, and we're editing, we'll add it to the votes list.
+    
+    my $bug_id = $input-&gt;{bug_id};
+    my $bug = Bugzilla::Bug-&gt;check($bug_id) if $bug_id;
+    my $who_id = $input-&gt;{user_id} || $user-&gt;id;
+
+    # Logged-out users must specify a user_id.
+    Bugzilla-&gt;login(LOGIN_REQUIRED) if !$who_id;
+
+    my $who = Bugzilla::User-&gt;check({ id =&gt; $who_id });
+
+    my $canedit = $user-&gt;id == $who-&gt;id;
+
+    $dbh-&gt;bz_start_transaction();
+
+    if ($canedit &amp;&amp; $bug) {
+        # Make sure there is an entry for this bug
+        # in the vote table, just so that things display right.
+        my $has_votes = $dbh-&gt;selectrow_array('SELECT vote_count FROM votes 
+                                               WHERE bug_id = ? AND who = ?',
+                                               undef, ($bug-&gt;id, $who-&gt;id));
+        if (!$has_votes) {
+            $dbh-&gt;do('INSERT INTO votes (who, bug_id, vote_count) 
+                      VALUES (?, ?, 0)', undef, ($who-&gt;id, $bug-&gt;id));
+        }
+    }
+
+    my (@products, @all_bug_ids);
+    # Read the votes data for this user for each product.
+    foreach my $product (@{ $user-&gt;get_selectable_products }) {
+        next unless ($product-&gt;{votesperuser} &gt; 0);
+
+        my @bugs;
+        my @bug_ids;
+        my $total = 0;
+        my $onevoteonly = 0;
+
+        my $vote_list =
+            $dbh-&gt;selectall_arrayref('SELECT votes.bug_id, votes.vote_count,
+                                             bugs.short_desc
+                                        FROM votes
+                                  INNER JOIN bugs
+                                          ON votes.bug_id = bugs.bug_id
+                                       WHERE votes.who = ?
+                                         AND bugs.product_id = ?
+                                    ORDER BY votes.bug_id',
+                                      undef, ($who-&gt;id, $product-&gt;id));
+
+        foreach (@$vote_list) {
+            my ($id, $count, $summary) = @$_;
+            $total += $count;
+
+            # Next if user can't see this bug. So, the totals will be correct
+            # and they can see there are votes 'missing', but not on what bug
+            # they are. This seems a reasonable compromise; the alternative is
+            # to lie in the totals.
+            next if !$user-&gt;can_see_bug($id);
+
+            push (@bugs, { id =&gt; $id,
+                           summary =&gt; $summary,
+                           count =&gt; $count });
+            push (@bug_ids, $id);
+            push (@all_bug_ids, $id);
+        }
+
+        $onevoteonly = 1 if (min($product-&gt;{votesperuser},
+                                 $product-&gt;{maxvotesperbug}) == 1);
+
+        # Only add the product for display if there are any bugs in it.
+        if ($#bugs &gt; -1) {
+            push (@products, { name =&gt; $product-&gt;name,
+                               bugs =&gt; \@bugs,
+                               bug_ids =&gt; \@bug_ids,
+                               onevoteonly =&gt; $onevoteonly,
+                               total =&gt; $total,
+                               maxvotes =&gt; $product-&gt;{votesperuser},
+                               maxperbug =&gt; $product-&gt;{maxvotesperbug} });
+        }
+    }
+
+    if ($canedit &amp;&amp; $bug) {
+        $dbh-&gt;do('DELETE FROM votes WHERE vote_count = 0 AND who = ?',
+                 undef, $who-&gt;id);
+    }
+    $dbh-&gt;bz_commit_transaction();
+
+    $vars-&gt;{'canedit'} = $canedit;
+    $vars-&gt;{'voting_user'} = { &quot;login&quot; =&gt; $who-&gt;name };
+    $vars-&gt;{'products'} = \@products;
+    $vars-&gt;{'this_bug'} = $bug;
+    $vars-&gt;{'all_bug_ids'} = \@all_bug_ids;
+}
+
+sub _update_votes {
+    my ($vars) = @_;
+
+    ############################################################################
+    # Begin Data/Security Validation
+    ############################################################################
+
+    my $cgi = Bugzilla-&gt;cgi;
+    my $dbh = Bugzilla-&gt;dbh;
+    my $template = Bugzilla-&gt;template;
+    my $user = Bugzilla-&gt;login(LOGIN_REQUIRED);
+    my $input = Bugzilla-&gt;input_params;
+
+    # Build a list of bug IDs for which votes have been submitted.  Votes
+    # are submitted in form fields in which the field names are the bug 
+    # IDs and the field values are the number of votes.
+
+    my @buglist = grep {/^\d+$/} keys %$input;
+
+    # If no bugs are in the buglist, let's make sure the user gets notified
+    # that their votes will get nuked if they continue.
+    if (scalar(@buglist) == 0) {
+        if (!defined $cgi-&gt;param('delete_all_votes')) {
+            print $cgi-&gt;header();
+            $template-&gt;process(&quot;voting/delete-all.html.tmpl&quot;, $vars)
+              || ThrowTemplateError($template-&gt;error());
+            exit;
+        }
+        elsif ($cgi-&gt;param('delete_all_votes') == 0) {
+            print $cgi-&gt;redirect(&quot;page.cgi?id=voting/user.html&quot;);
+            exit;
+        }
+    }
+
+    # Call check() on each bug ID to make sure it is a positive
+    # integer representing an existing bug that the user is authorized 
+    # to access, and make sure the number of votes submitted is also
+    # a non-negative integer (a series of digits not preceded by a
+    # minus sign).
+    my (%votes, @bugs);
+    foreach my $id (@buglist) {
+      my $bug = Bugzilla::Bug-&gt;check($id);
+      push(@bugs, $bug);
+      $id = $bug-&gt;id;
+      $votes{$id} = $input-&gt;{$id};
+      detaint_natural($votes{$id})
+        || ThrowUserError(&quot;voting_must_be_nonnegative&quot;);
+    }
+
+    my $token = $cgi-&gt;param('token');
+    check_hash_token($token, ['vote']);
+
+    ############################################################################
+    # End Data/Security Validation
+    ############################################################################
+    my $who = $user-&gt;id;
+
+    # If the user is voting for bugs, make sure they aren't overstuffing
+    # the ballot box.
+    if (scalar @bugs) {
+        my (%prodcount, %products);
+        foreach my $bug (@bugs) {
+            my $bug_id = $bug-&gt;id;
+            my $prod = $bug-&gt;product;
+            $products{$prod} ||= $bug-&gt;product_obj;
+            $prodcount{$prod} ||= 0;
+            $prodcount{$prod} += $votes{$bug_id};
+
+            # Make sure we haven't broken the votes-per-bug limit
+            ($votes{$bug_id} &lt;= $products{$prod}-&gt;{maxvotesperbug})
+              || ThrowUserError(&quot;voting_too_many_votes_for_bug&quot;,
+                                {max =&gt; $products{$prod}-&gt;{maxvotesperbug},
+                                 product =&gt; $prod,
+                                 votes =&gt; $votes{$bug_id}});
+        }
+
+        # Make sure we haven't broken the votes-per-product limit
+        foreach my $prod (keys(%prodcount)) {
+            ($prodcount{$prod} &lt;= $products{$prod}-&gt;{votesperuser})
+              || ThrowUserError(&quot;voting_too_many_votes_for_product&quot;,
+                                {max =&gt; $products{$prod}-&gt;{votesperuser},
+                                 product =&gt; $prod,
+                                 votes =&gt; $prodcount{$prod}});
+        }
+    }
+
+    # Update the user's votes in the database.  If the user did not submit 
+    # any votes, they may be using a form with checkboxes to remove all their
+    # votes (checkboxes are not submitted along with other form data when
+    # they are not checked, and Bugzilla uses them to represent single votes
+    # for products that only allow one vote per bug).  In that case, we still
+    # need to clear the user's votes from the database.
+    my %affected;
+    $dbh-&gt;bz_start_transaction();
+
+    # Take note of, and delete the user's old votes from the database.
+    my $bug_list = $dbh-&gt;selectcol_arrayref('SELECT bug_id FROM votes
+                                             WHERE who = ?', undef, $who);
+
+    foreach my $id (@$bug_list) {
+        $affected{$id} = 1;
+    }
+    $dbh-&gt;do('DELETE FROM votes WHERE who = ?', undef, $who);
+
+    my $sth_insertVotes = $dbh-&gt;prepare('INSERT INTO votes (who, bug_id, vote_count)
+                                         VALUES (?, ?, ?)');
+
+    # Insert the new values in their place
+    foreach my $id (@buglist) {
+        if ($votes{$id} &gt; 0) {
+            $sth_insertVotes-&gt;execute($who, $id, $votes{$id});
+        }
+        $affected{$id} = 1;
+    }
+
+    # Update the cached values in the bugs table
+    print $cgi-&gt;header();
+    my @updated_bugs = ();
+
+    my $sth_getVotes = $dbh-&gt;prepare(&quot;SELECT SUM(vote_count) FROM votes
+                                      WHERE bug_id = ?&quot;);
+
+    my $sth_updateVotes = $dbh-&gt;prepare(&quot;UPDATE bugs SET votes = ?
+                                         WHERE bug_id = ?&quot;);
+
+    foreach my $id (keys %affected) {
+        $sth_getVotes-&gt;execute($id);
+        my $v = $sth_getVotes-&gt;fetchrow_array || 0;
+        $sth_updateVotes-&gt;execute($v, $id);
+
+        my $confirmed = _confirm_if_vote_confirmed($id);
+        push (@updated_bugs, $id) if $confirmed;
+    }
+
+    $dbh-&gt;bz_commit_transaction();
+
+    $vars-&gt;{'type'} = &quot;votes&quot;;
+    $vars-&gt;{'title_tag'} = 'change_votes';
+    foreach my $bug_id (@updated_bugs) {
+        $vars-&gt;{'id'} = $bug_id;
+        $vars-&gt;{'sent_bugmail'} = 
+            Bugzilla::BugMail::Send($bug_id, { 'changer' =&gt; $user });
+        
+        $template-&gt;process(&quot;bug/process/results.html.tmpl&quot;, $vars)
+          || ThrowTemplateError($template-&gt;error());
+        # Set header_done to 1 only after the first bug.
+        $vars-&gt;{'header_done'} = 1;
+    }
+    $vars-&gt;{'votes_recorded'} = 1;
+}
+
+######################
+# Helper Subroutines #
+######################
+
+sub _modify_bug_votes {
+    my ($product, $changes) = @_;
+    my $dbh = Bugzilla-&gt;dbh;
+    my @msgs;
+
+    # 1. too many votes for a single user on a single bug.
+    my @toomanyvotes_list;
+    if ($product-&gt;{maxvotesperbug} &lt; $product-&gt;{votesperuser}) {
+        my $votes = $dbh-&gt;selectall_arrayref(
+            'SELECT votes.who, votes.bug_id
+               FROM votes
+                    INNER JOIN bugs ON bugs.bug_id = votes.bug_id
+              WHERE bugs.product_id = ?
+                    AND votes.vote_count &gt; ?',
+            undef, ($product-&gt;id, $product-&gt;{maxvotesperbug}));
+
+        foreach my $vote (@$votes) {
+            my ($who, $id) = (@$vote);
+            # If some votes are removed, _remove_votes() returns a list
+            # of messages to send to voters.
+            push(@msgs, _remove_votes($id, $who, 'votes_too_many_per_bug'));
+            my $name = user_id_to_login($who);
+
+            push(@toomanyvotes_list, {id =&gt; $id, name =&gt; $name});
+        }
+    }
+
+    $changes-&gt;{'_too_many_votes'} = \@toomanyvotes_list;
+
+    # 2. too many total votes for a single user.
+    # This part doesn't work in the general case because _remove_votes
+    # doesn't enforce votesperuser (except per-bug when it's less
+    # than maxvotesperbug).  See _remove_votes().
+
+    my $votes = $dbh-&gt;selectall_arrayref(
+        'SELECT votes.who, votes.vote_count
+           FROM votes
+                INNER JOIN bugs ON bugs.bug_id = votes.bug_id
+          WHERE bugs.product_id = ?',
+         undef, $product-&gt;id);
+
+    my %counts;
+    foreach my $vote (@$votes) {
+        my ($who, $count) = @$vote;
+        if (!defined $counts{$who}) {
+            $counts{$who} = $count;
+        } else {
+            $counts{$who} += $count;
+        }
+    }
+
+    my @toomanytotalvotes_list;
+    foreach my $who (keys(%counts)) {
+        if ($counts{$who} &gt; $product-&gt;{votesperuser}) {
+            my $bug_ids = $dbh-&gt;selectcol_arrayref(
+                'SELECT votes.bug_id
+                   FROM votes
+                        INNER JOIN bugs ON bugs.bug_id = votes.bug_id
+                  WHERE bugs.product_id = ?
+                        AND votes.who = ?',
+                undef, $product-&gt;id, $who);
+
+            foreach my $bug_id (@$bug_ids) {
+                # _remove_votes returns a list of messages to send
+                # in case some voters had too many votes.
+                push(@msgs, _remove_votes($bug_id, $who, 
+                                          'votes_too_many_per_user'));
+                my $name = user_id_to_login($who);
+
+                push(@toomanytotalvotes_list, {id =&gt; $bug_id, name =&gt; $name});
+            }
+        }
+    }
+
+    $changes-&gt;{'_too_many_total_votes'} = \@toomanytotalvotes_list;
+
+    # 3. enough votes to confirm
+    my $bug_list = $dbh-&gt;selectcol_arrayref(
+        'SELECT bug_id FROM bugs 
+          WHERE product_id = ? AND bug_status = ? AND votes &gt;= ?',
+        undef, ($product-&gt;id, 'UNCONFIRMED', $product-&gt;{votestoconfirm}));
+
+    my @updated_bugs;
+    foreach my $bug_id (@$bug_list) {
+        my $confirmed = _confirm_if_vote_confirmed($bug_id);
+        push (@updated_bugs, $bug_id) if $confirmed;
+    }
+    $changes-&gt;{'_confirmed_bugs'} = \@updated_bugs;
+
+    # Now that changes are done, we can send emails to voters.
+    foreach my $msg (@msgs) {
+        MessageToMTA($msg);
+    }
+    # And send out emails about changed bugs
+    foreach my $bug_id (@updated_bugs) {
+        my $sent_bugmail = Bugzilla::BugMail::Send(
+            $bug_id, { changer =&gt; Bugzilla-&gt;user });
+        $changes-&gt;{'_confirmed_bugs_sent_bugmail'}-&gt;{$bug_id} = $sent_bugmail;
+    }
+}
+
+# If a bug is moved to a product which allows less votes per bug
+# compared to the previous product, extra votes need to be removed.
+sub _remove_votes {
+    my ($id, $who, $reason) = (@_);
+    my $dbh = Bugzilla-&gt;dbh;
+
+    my $whopart = ($who) ? &quot; AND votes.who = $who&quot; : &quot;&quot;;
+
+    my $sth = $dbh-&gt;prepare(&quot;SELECT profiles.login_name, &quot; .
+                            &quot;profiles.userid, votes.vote_count, &quot; .
+                            &quot;products.votesperuser, products.maxvotesperbug &quot; .
+                            &quot;FROM profiles &quot; .
+                            &quot;LEFT JOIN votes ON profiles.userid = votes.who &quot; .
+                            &quot;LEFT JOIN bugs ON votes.bug_id = bugs.bug_id &quot; .
+                            &quot;LEFT JOIN products ON products.id = bugs.product_id &quot; .
+                            &quot;WHERE votes.bug_id = ? &quot; . $whopart);
+    $sth-&gt;execute($id);
+    my @list;
+    while (my ($name, $userid, $oldvotes, $votesperuser, $maxvotesperbug) = $sth-&gt;fetchrow_array()) {
+        push(@list, [$name, $userid, $oldvotes, $votesperuser, $maxvotesperbug]);
+    }
+
+    # @messages stores all emails which have to be sent, if any.
+    # This array is passed to the caller which will send these emails itself.
+    my @messages = ();
+
+    if (scalar(@list)) {
+        foreach my $ref (@list) {
+            my ($name, $userid, $oldvotes, $votesperuser, $maxvotesperbug) = (@$ref);
+
+            $maxvotesperbug = min($votesperuser, $maxvotesperbug);
+
+            # If this product allows voting and the user's votes are in
+            # the acceptable range, then don't do anything.
+            next if $votesperuser &amp;&amp; $oldvotes &lt;= $maxvotesperbug;
+
+            # If the user has more votes on this bug than this product
+            # allows, then reduce the number of votes so it fits
+            my $newvotes = $maxvotesperbug;
+
+            my $removedvotes = $oldvotes - $newvotes;
+
+            if ($newvotes) {
+                $dbh-&gt;do(&quot;UPDATE votes SET vote_count = ? &quot; .
+                         &quot;WHERE bug_id = ? AND who = ?&quot;,
+                         undef, ($newvotes, $id, $userid));
+            } else {
+                $dbh-&gt;do(&quot;DELETE FROM votes WHERE bug_id = ? AND who = ?&quot;,
+                         undef, ($id, $userid));
+            }
+
+            # Notice that we did not make sure that the user fit within the $votesperuser
+            # range.  This is considered to be an acceptable alternative to losing votes
+            # during product moves.  Then next time the user attempts to change their votes,
+            # they will be forced to fit within the $votesperuser limit.
+
+            # Now lets send the e-mail to alert the user to the fact that their votes have
+            # been reduced or removed.
+            my $vars = {
+                'to' =&gt; $name . Bugzilla-&gt;params-&gt;{'emailsuffix'},
+                'bugid' =&gt; $id,
+                'reason' =&gt; $reason,
+
+                'votesremoved' =&gt; $removedvotes,
+                'votesold' =&gt; $oldvotes,
+                'votesnew' =&gt; $newvotes,
+            };
+
+            my $voter = new Bugzilla::User($userid);
+            my $template = Bugzilla-&gt;template_inner($voter-&gt;setting('lang'));
+
+            my $msg;
+            $template-&gt;process(&quot;voting/votes-removed.txt.tmpl&quot;, $vars, \$msg);
+            push(@messages, $msg);
+        }
+
+        my $votes = $dbh-&gt;selectrow_array(&quot;SELECT SUM(vote_count) &quot; .
+                                          &quot;FROM votes WHERE bug_id = ?&quot;,
+                                          undef, $id) || 0;
+        $dbh-&gt;do(&quot;UPDATE bugs SET votes = ? WHERE bug_id = ?&quot;,
+                 undef, ($votes, $id));
+    }
+    # Now return the array containing emails to be sent.
+    return @messages;
+}
+
+# If a user votes for a bug, or the number of votes required to
+# confirm a bug has been reduced, check if the bug is now confirmed.
+sub _confirm_if_vote_confirmed {
+    my $id = shift;
+    my $bug = new Bugzilla::Bug($id);
+
+    my $ret = 0;
+    if (!$bug-&gt;everconfirmed
+        and $bug-&gt;product_obj-&gt;{votestoconfirm}
+        and $bug-&gt;votes &gt;= $bug-&gt;product_obj-&gt;{votestoconfirm})
+    {
+        $bug-&gt;add_comment('', { type =&gt; CMT_POPULAR_VOTES });
+
+        if ($bug-&gt;bug_status eq 'UNCONFIRMED') {
+            # Get a valid open state.
+            my $new_status;
+            foreach my $state (@{$bug-&gt;status-&gt;can_change_to}) {
+                if ($state-&gt;is_open &amp;&amp; $state-&gt;name ne 'UNCONFIRMED') {
+                    $new_status = $state-&gt;name;
+                    last;
+                }
+            }
+            ThrowCodeError('voting_no_open_bug_status') unless $new_status;
+
+            # We cannot call $bug-&gt;set_bug_status() here, because a user without
+            # canconfirm privs should still be able to confirm a bug by
+            # popular vote. We already know the new status is valid, so it's safe.
+            $bug-&gt;{bug_status} = $new_status;
+            $bug-&gt;{everconfirmed} = 1;
+            delete $bug-&gt;{'status'}; # Contains the status object.
+        }
+        else {
+            # If the bug is in a closed state, only set everconfirmed to 1.
+            # Do not call $bug-&gt;_set_everconfirmed(), for the same reason as above.
+            $bug-&gt;{everconfirmed} = 1;
+        }
+        $bug-&gt;update();
+
+        $ret = 1;
+    }
+    return $ret;
+}
+
+
+__PACKAGE__-&gt;NAME;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsVotingdisabledfromrev173253trunkWebsitesbugswebkitorgextensionsexampledisabled"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/Voting/disabled (from rev 173253, trunk/Websites/bugs.webkit.org/extensions/example/disabled) ( => )</h4>
<pre class="diff"><span>
<span class="info">Copied: trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/account/prefs/email-relationships.html.tmpl (from rev 173253, trunk/Websites/bugs.webkit.org/template/en/default/attachment/diff-footer.html.tmpl)
===================================================================
</span><del>--- trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/account/prefs/email-relationships.html.tmpl                                (rev 0)
</del><ins>+++ trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/account/prefs/email-relationships.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</ins><span class="lines">@@ -0,0 +1,22 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2010
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s): 
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[% relationships.push({ id = constants.REL_VOTER, description = &quot;Voter&quot; }) %]
+[% no_added_removed.push(constants.REL_VOTER) %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthookadminproductseditcommonrowshtmltmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/admin/products/edit-common-rows.html.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/admin/products/edit-common-rows.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/admin/products/edit-common-rows.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,60 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2010
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s): 
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[% DEFAULT 
+  product.maxvotesperbug = constants.DEFAULT_VOTES_PER_BUG
+  product.votesperuser = 0
+  product.votestoconfirm = 0
+%]
+  
+&lt;tr&gt;
+  &lt;th align=&quot;right&quot;&gt;Maximum votes per person:&lt;/th&gt;
+  &lt;td&gt;&lt;input size=&quot;5&quot; maxlength=&quot;5&quot; name=&quot;votesperuser&quot; id=&quot;votesperuser&quot;
+             value=&quot;[% product.votesperuser FILTER html %]&quot;&gt;
+  &lt;/td&gt;
+&lt;/tr&gt;
+
+&lt;tr&gt;
+  &lt;th align=&quot;right&quot;&gt;
+    Maximum votes a person can put on a single [% terms.bug %]:
+  &lt;/th&gt;
+  &lt;td&gt;&lt;input size=&quot;5&quot; maxlength=&quot;5&quot; name=&quot;maxvotesperbug&quot; id=&quot;maxvotesperbug&quot;
+             value=&quot;[% product.maxvotesperbug FILTER html %]&quot;&gt;
+  &lt;/td&gt;
+&lt;/tr&gt;
+
+&lt;tr id=&quot;votes_to_confirm_container&quot;
+    [%- ' class=&quot;bz_default_hidden&quot;' IF !product.allows_unconfirmed %]&gt;
+  &lt;th align=&quot;right&quot;&gt;
+    Confirm [% terms.abug %] if it gets this many votes:
+  &lt;/th&gt;
+  &lt;td&gt;
+    &lt;input size=&quot;3&quot; maxlength=&quot;5&quot; name=&quot;votestoconfirm&quot; id=&quot;votestoconfirm&quot;
+           value=&quot;[% product.votestoconfirm FILTER html %]&quot;&gt;
+    &lt;br&gt;(Setting this to 0 disables auto-confirming [% terms.bugs %]
+    by vote.)
+    &lt;script type=&quot;text/javascript&quot;&gt;
+        YAHOO.util.Event.addListener('allows_unconfirmed', 'change',
+            function() { bz_toggleClass('votes_to_confirm_container',
+                                        'bz_default_hidden'); });
+    &lt;/script&gt;
+  &lt;/td&gt;
+&lt;/tr&gt;
+
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthookadminproductsupdatedchangeshtmltmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/admin/products/updated-changes.html.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/admin/products/updated-changes.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/admin/products/updated-changes.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,102 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2010
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s): 
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[% SET checkvotes = 0 %]
+
+[% IF changes.votesperuser.defined %]
+  &lt;p&gt;
+  Updated votes per user from
+  [%+ changes.votesperuser.0 FILTER html %] to
+  [%+ product.votesperuser FILTER html %].
+  &lt;/p&gt;
+  [% checkvotes = 1 %]
+[% END %]
+
+[% IF changes.maxvotesperbug.defined %]
+  &lt;p&gt;
+  Updated maximum votes per [% terms.bug %] from
+  [%+ changes.maxvotesperbug.0 FILTER html %] to
+  [%+ product.maxvotesperbug FILTER html %].
+  &lt;/p&gt;
+  [% checkvotes = 1 %]
+[% END %]
+
+[% IF changes.votestoconfirm.defined %]
+  &lt;p&gt;
+  Updated number of votes needed to confirm a [% terms.bug %] from
+  [%+ changes.votestoconfirm.0 FILTER html %] to
+  [%+ product.votestoconfirm FILTER html %].
+  &lt;/p&gt;
+  [% checkvotes = 1 %]
+[% END %]
+
+[%# Note that this display of changed votes and/or confirmed bugs is
+    not very scalable. We could have a _lot_, and we just list them all.
+    One day we should limit this perhaps, or have a more scalable display %]
+
+[% IF checkvotes %]
+  &lt;hr&gt;
+
+  &lt;p&gt;Checking existing votes in this product for anybody who now
+  has too many votes for [% terms.abug %]...&lt;br&gt;
+  [% IF changes._too_many_votes.size %]
+    [% FOREACH detail = changes._too_many_votes %]
+      &amp;rarr;removed votes for [% terms.bug %] &lt;a href=&quot;show_bug.cgi?id=
+     [%- detail.id FILTER uri %]&quot;&gt;
+     [%- detail.id FILTER html %]&lt;/a&gt; from [% detail.name FILTER html %]&lt;br&gt;
+    [% END %]
+  [% ELSE %]
+    &amp;rarr;there were none.
+  [% END %]
+  &lt;/p&gt;
+
+  &lt;p&gt;Checking existing votes in this product for anybody
+  who now has too many total votes...&lt;br&gt;
+  [% IF changes._too_many_total_votes.size %]
+    [% FOREACH detail = changes._too_many_total_votes %]
+      &amp;rarr;removed votes for [% terms.bug %] &lt;a href=&quot;show_bug.cgi?id=
+     [%- detail.id FILTER uri %]&quot;&gt;
+     [%- detail.id FILTER html %]&lt;/a&gt; from [% detail.name FILTER html %]&lt;br&gt;
+    [% END %]
+  [% ELSE %]
+    &amp;rarr;there were none.
+  [% END %]
+  &lt;/p&gt;
+
+  &lt;p&gt;Checking unconfirmed [% terms.bugs %] in this product for any which now have
+  sufficient votes...&lt;br&gt;
+  [% IF changes._confirmed_bugs.size %]
+    [% FOREACH id = changes._confirmed_bugs %]
+
+      [%# This is INCLUDED instead of PROCESSED to avoid variables getting
+          overwritten, which happens otherwise %]
+      [% INCLUDE bug/process/results.html.tmpl
+        type = 'votes'
+        header_done = 1
+        sent_bugmail = changes._confirmed_bugs_sent_bugmail.$id
+        id = id
+      %]
+    [% END %]
+  [% ELSE %]
+    &amp;rarr;there were none.
+  [% END %]
+  &lt;/p&gt;
+
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthookadminsanitycheckmessagesstatuseshtmltmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/admin/sanitycheck/messages-statuses.html.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/admin/sanitycheck/messages-statuses.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/admin/sanitycheck/messages-statuses.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,41 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2010
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s): 
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[% IF san_tag == &quot;voting_cache_rebuild_fix&quot; %]
+    &lt;a href=&quot;sanitycheck.cgi?rebuild_vote_cache=1&amp;amp;token=
+       [%- issue_hash_token(['sanitycheck']) FILTER uri %]&quot;&gt;Click here to
+    rebuild the vote cache&lt;/a&gt;
+
+[% ELSIF san_tag == &quot;voting_cache_alert&quot; %]
+    Bad vote cache for [% PROCESS bug_link bug_id = id %]
+
+[% ELSIF san_tag == &quot;voting_count_start&quot; %]
+    Checking cached vote counts.
+
+[% ELSIF san_tag == &quot;voting_count_alert&quot; %]
+    Bad vote sum for [% terms.bug %] [%+ id FILTER html %].
+
+[% ELSIF san_tag == &quot;voting_cache_rebuild_start&quot; %]
+    OK, now rebuilding vote cache.
+
+[% ELSIF san_tag == &quot;voting_cache_rebuild_end&quot; %]
+    Vote cache has been rebuilt
+
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthookadminusersconfirmdeletewarn_safehtmltmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/admin/users/confirm-delete-warn_safe.html.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/admin/users/confirm-delete-warn_safe.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/admin/users/confirm-delete-warn_safe.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,38 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2010
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s): 
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[% IF votes %]
+  &lt;li&gt;
+    [% otheruser.login FILTER html %] has voted on
+    [% IF votes == 1 %]
+      [%+ terms.abug %]
+    [% ELSE %]
+      [%+ votes FILTER html %] [%+ terms.bugs %]
+    [% END %].
+
+    If you delete the user account,
+    [% IF votes == 1 %]
+      this vote
+    [% ELSE %]
+      these votes
+    [% END %]
+    will be deleted along with the user account.
+  &lt;/li&gt;
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthookbugeditafter_importancehtmltmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/bug/edit-after_importance.html.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/bug/edit-after_importance.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/bug/edit-after_importance.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,37 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2010
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s): 
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+[% IF bug.product_obj.votesperuser %]
+  &lt;span id=&quot;votes_container&quot;&gt;
+    [% IF bug.votes %]
+      with
+      &lt;a href=&quot;page.cgi?id=voting/bug.html&amp;amp;bug_id=
+               [%- bug.id FILTER uri %]&quot;&gt;
+        [%- bug.votes FILTER html %] 
+        [% IF bug.votes == 1 %]
+            vote
+        [% ELSE %]
+            votes
+        [% END %]&lt;/a&gt;
+    [% END %]
+    (&lt;a href=&quot;page.cgi?id=voting/user.html&amp;amp;bug_id=
+              [%- bug.id FILTER uri %]#vote_
+              [%- bug.id FILTER uri %]&quot;&gt;vote&lt;/a&gt;)
+  &lt;/span&gt;
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthookbugformat_commenttypetxttmplfromrev173253trunkWebsitesbugswebkitorgtemplateendefaultattachmentdifffooterhtmltmpl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/bug/format_comment-type.txt.tmpl (from rev 173253, trunk/Websites/bugs.webkit.org/template/en/default/attachment/diff-footer.html.tmpl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/bug/format_comment-type.txt.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/bug/format_comment-type.txt.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,23 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2010
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s): 
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[% IF comment.type == constants.CMT_POPULAR_VOTES %]
+*** This [% terms.bug %] has been confirmed by popular vote. ***
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthookbugprocessheadertitlehtmltmplfromrev173253trunkWebsitesbugswebkitorgtemplateendefaultattachmentdifffooterhtmltmpl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/bug/process/header-title.html.tmpl (from rev 173253, trunk/Websites/bugs.webkit.org/template/en/default/attachment/diff-footer.html.tmpl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/bug/process/header-title.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/bug/process/header-title.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,24 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2010
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s): 
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[% IF title_tag == &quot;change_votes&quot; %]
+  [% title = &quot;Change Votes&quot; %]
+[% END %]
+
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthookbugprocessresultstitlehtmltmplfromrev173253trunkWebsitesbugswebkitorgtemplateendefaultattachmentdifffooterhtmltmpl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/bug/process/results-title.html.tmpl (from rev 173253, trunk/Websites/bugs.webkit.org/template/en/default/attachment/diff-footer.html.tmpl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/bug/process/results-title.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/bug/process/results-title.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,21 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2010
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s): 
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[% title.votes = &quot;$Link confirmed by number of votes&quot; %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthookbugshowheaderendhtmltmplfromrev173253trunkWebsitesbugswebkitorgtemplateendefaultattachmentdifffooterhtmltmpl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/bug/show-header-end.html.tmpl (from rev 173253, trunk/Websites/bugs.webkit.org/template/en/default/attachment/diff-footer.html.tmpl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/bug/show-header-end.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/bug/show-header-end.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,21 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2010
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s): 
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[% style_urls.push('extensions/Voting/web/style.css') %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthookglobalcodeerrorerrorshtmltmplfromrev173253trunkWebsitesbugswebkitorgtemplateendefaultattachmentdifffooterhtmltmpl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/global/code-error-errors.html.tmpl (from rev 173253, trunk/Websites/bugs.webkit.org/template/en/default/attachment/diff-footer.html.tmpl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/global/code-error-errors.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/global/code-error-errors.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,25 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2010
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s): 
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[% IF error == &quot;voting_no_open_bug_status&quot; %]
+    [% title = &quot;$terms.Bug Cannot Be Confirmed&quot; %]
+    There is no valid transition from
+    [%+ display_value(&quot;bug_status&quot;, &quot;UNCONFIRMED&quot;) FILTER html %] to an open state
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthookglobalfielddescsendnonetmplfromrev173253trunkWebsitesbugswebkitorgtemplateendefaultattachmentdifffooterhtmltmpl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/global/field-descs-end.none.tmpl (from rev 173253, trunk/Websites/bugs.webkit.org/template/en/default/attachment/diff-footer.html.tmpl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/global/field-descs-end.none.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/global/field-descs-end.none.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,23 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2010
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s): 
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[% IF in_template_var %]
+  [% vars.field_descs.votes = &quot;Votes&quot; %]
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthookglobalreasondescsendnonetmplfromrev173253trunkWebsitesbugswebkitorgtemplateendefaultattachmentdifffooterhtmltmpl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/global/reason-descs-end.none.tmpl (from rev 173253, trunk/Websites/bugs.webkit.org/template/en/default/attachment/diff-footer.html.tmpl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/global/reason-descs-end.none.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/global/reason-descs-end.none.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,23 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2010
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s): 
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[% reason_descs.${constants.REL_VOTER} = &quot;You voted for the ${terms.bug}.&quot; %]
+[% watch_reason_descs.${constants.REL_VOTER} = 
+  &quot;You are watching a voter for the ${terms.bug}.&quot; %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthookglobalusererrorerrorshtmltmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/global/user-error-errors.html.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/global/user-error-errors.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/global/user-error-errors.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,55 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2010
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s): 
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[% IF error == &quot;voting_must_be_nonnegative&quot; %]
+    [% title = &quot;Votes Must Be Non-negative&quot; %]
+    [% admindocslinks = {'voting.html' =&gt; 'Setting up the voting feature'} %]
+    Only use non-negative numbers for your [% terms.bug %] votes.
+
+[% ELSIF error == &quot;voting_product_illegal_votes&quot; %]
+    [% title = &quot;Votes Must Be Non-negative&quot; %]
+    [% admindocslinks = {'voting.html' =&gt; 'Setting up the voting feature'} %]
+    '[% votes FILTER html %]' is an invalid value for the
+    &lt;em&gt;
+    [% IF field == &quot;votesperuser&quot; %]
+      Votes Per User
+    [% ELSIF field == &quot;maxvotesperbug&quot; %]
+      Maximum Votes Per [% terms.Bug %]
+    [% ELSIF field == &quot;votestoconfirm&quot; %]
+      Votes To Confirm
+    [% END %]
+    &lt;/em&gt; field, which should contain a non-negative number.
+
+[% ELSIF error == &quot;voting_too_many_votes_for_bug&quot; %]
+    [% title = &quot;Illegal Vote&quot; %]
+    [% admindocslinks = {'voting.html' =&gt; 'Setting up the voting feature'} %]
+    You may only use at most [% max FILTER html %] votes for a single
+    [%+ terms.bug %] in the
+    &lt;tt&gt;[% product FILTER html %]&lt;/tt&gt; product, but you are trying to
+    use [% votes FILTER html %].
+
+[% ELSIF error == &quot;voting_too_many_votes_for_product&quot; %]
+    [% title = &quot;Illegal Vote&quot; %]
+    [% admindocslinks = {'voting.html' =&gt; 'Setting up the voting feature'} %]
+    You tried to use [% votes FILTER html %] votes in the
+    &lt;tt&gt;[% product FILTER html %]&lt;/tt&gt; product, which exceeds the maximum of
+    [%+ max FILTER html %] votes for this product.
+
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthooksearchformafter_freetext_fieldshtmltmplfromrev173253trunkWebsitesbugswebkitorgtemplateendefaultattachmentdifffooterhtmltmpl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/search/form-after_freetext_fields.html.tmpl (from rev 173253, trunk/Websites/bugs.webkit.org/template/en/default/attachment/diff-footer.html.tmpl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/search/form-after_freetext_fields.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/search/form-after_freetext_fields.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,28 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2010
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s): 
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+&lt;div class=&quot;search_field_row&quot;&gt;
+  &lt;span class=&quot;field_label &quot;&gt;
+    &lt;label for=&quot;votes&quot;&gt;Only [% terms.bugs %] with at least&lt;/label&gt;:
+  &lt;/span&gt;
+  &lt;input name=&quot;votes&quot; id=&quot;votes&quot; size=&quot;3&quot;
+         value=&quot;[% default.votes.0 FILTER html %]&quot;&gt; votes
+  &lt;input type=&quot;hidden&quot; name=&quot;votes_type&quot; value=&quot;greaterthaneq&quot;&gt;
+&lt;/div&gt;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaulthooksearchsearchreportselectrep_fieldshtmltmplfromrev173253trunkWebsitesbugswebkitorgtemplateendefaultattachmentdifffooterhtmltmpl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/search/search-report-select-rep_fields.html.tmpl (from rev 173253, trunk/Websites/bugs.webkit.org/template/en/default/attachment/diff-footer.html.tmpl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/search/search-report-select-rep_fields.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/hook/search/search-report-select-rep_fields.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,21 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2010
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s): 
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[% rep_fields.push('votes') %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaultpagesvotingbughtmltmplfromrev173253trunkWebsitesbugswebkitorgtemplateendefaultbugvoteslistforbughtmltmpl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/pages/voting/bug.html.tmpl (from rev 173253, trunk/Websites/bugs.webkit.org/template/en/default/bug/votes/list-for-bug.html.tmpl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/pages/voting/bug.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/pages/voting/bug.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,65 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Netscape Communications
+  # Corporation. Portions created by Netscape are
+  # Copyright (C) 1998 Netscape Communications Corporation. All
+  # Rights Reserved.
+  #
+  # Contributor(s): Gervase Markham &lt;gerv@gerv.net&gt;
+  #                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[%# INTERFACE:
+  # bug: Bugzilla::Bug that we are listing the votes for.
+  # users: list of hashes. May be empty. Each hash has two members:
+  #   login_name: string. The login name of the user whose vote is attached
+  #   vote_count: integer. The number of times that user has votes for this bug.
+  #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% subheader = BLOCK %]
+  [% &quot;$terms.Bug $bug.id&quot; FILTER bug_link(bug) FILTER none %] - [% bug.short_desc FILTER html %]
+[% END %]
+
+[% PROCESS global/header.html.tmpl
+           title = &quot;Show Votes&quot;
+           subheader = subheader
+ %]
+
+[% total = 0 %]
+&lt;table cellspacing=&quot;4&quot;&gt;
+  &lt;tr&gt;
+    &lt;th&gt;Who&lt;/th&gt;
+    &lt;th&gt;Number of votes&lt;/th&gt;
+  &lt;/tr&gt;
+
+  [% FOREACH voter = users %]
+    [% total = total + voter.vote_count %]
+    &lt;tr&gt;
+      &lt;td&gt;
+          &lt;a href=&quot;page.cgi?id=voting/user.html&amp;amp;user_id=
+                  [%- voter.id FILTER uri %]&quot;&gt;
+          [% voter.login_name FILTER email FILTER html %]
+        &lt;/a&gt;
+      &lt;/td&gt;
+      &lt;td align=&quot;right&quot;&gt;
+        [% voter.vote_count FILTER html %]
+      &lt;/td&gt;
+    &lt;/tr&gt;
+  [% END %]
+&lt;/table&gt;
+
+&lt;p&gt;Total votes: [% total FILTER html %]&lt;/p&gt;
+
+[% PROCESS global/footer.html.tmpl %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaultpagesvotinguserhtmltmplfromrev173253trunkWebsitesbugswebkitorgtemplateendefaultbugvoteslistforuserhtmltmpl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/pages/voting/user.html.tmpl (from rev 173253, trunk/Websites/bugs.webkit.org/template/en/default/bug/votes/list-for-user.html.tmpl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/pages/voting/user.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/pages/voting/user.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,193 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Netscape Communications
+  # Corporation. Portions created by Netscape are
+  # Copyright (C) 1998 Netscape Communications Corporation. All
+  # Rights Reserved.
+  #
+  # Contributor(s): Gervase Markham &lt;gerv@gerv.net&gt;
+  #%]
+
+[%# INTERFACE:
+  # voting_user: hash containing a 'login' field
+  #
+  # products: list of hashes containing details of products relating to
+  #           voting: 
+  #            name: name of product
+  #            bugs: list of bugs the user has voted for
+  #            bug_ids: list of bug ids the user has voted for
+  #            onevoteonly: one or more votes allowed per bug?
+  #            total: users current vote count for the product
+  #            maxvotes: max votes allowed for a user in this product
+  #            maxperbug: max votes per bug allowed for a user in this product
+  #
+  # this_bug: Bugzilla::Bug; if the user is voting for a bug, this is the bug
+  #
+  # canedit: boolean; Should the votes be presented in a form, or readonly? 
+  #
+  # all_bug_ids: List of all bug ids the user has voted for, across all products
+  #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% IF !header_done %]
+  [% subheader = voting_user.login FILTER html %]
+  [% IF canedit %]
+    [% title = &quot;Change Votes&quot; %]
+    [% IF this_bug %]
+      [%# We .select and .focus the input so it works for textbox and 
+          checkbox %]
+      [% onload = &quot;document.forms['voting_form'].bug_&quot; _ this_bug.id _
+                  &quot;.select();document.forms['voting_form'].bug_&quot; _ this_bug.id _
+                  &quot;.focus()&quot; %]
+    [% END %]
+  [% ELSE %]
+    [% title = &quot;Show Votes&quot; %]
+  [% END %]
+  [% PROCESS global/header.html.tmpl
+             style_urls = [ &quot;extensions/Voting/web/style.css&quot; ] 
+  %]
+[% ELSE %]
+  &lt;hr&gt;
+[% END %]
+
+[% IF votes_recorded %]
+  &lt;p&gt;
+    &lt;font color=&quot;red&quot;&gt;
+      The changes to your votes have been saved.
+    &lt;/font&gt;
+  &lt;/p&gt;
+[% ELSE %]
+  &lt;br&gt;
+[% END %]
+
+[% IF products.size %]
+  &lt;form name=&quot;voting_form&quot; method=&quot;post&quot; action=&quot;page.cgi?id=voting/user.html&quot;&gt;
+    &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;vote&quot;&gt;
+    &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% issue_hash_token(['vote']) FILTER html %]&quot;&gt;
+    &lt;table cellspacing=&quot;4&quot;&gt;
+      &lt;tr&gt;
+        &lt;td&gt;&lt;/td&gt;
+        &lt;th&gt;Votes&lt;/th&gt;
+        &lt;th&gt;[% terms.Bug %] #&lt;/th&gt;
+        &lt;th&gt;Summary&lt;/th&gt;
+      &lt;/tr&gt;
+
+      [% onevoteproduct = 0 %]
+      [% multivoteproduct = 0 %]
+      [% FOREACH product = products %]
+        [% IF product.onevoteonly %]
+          [% onevoteproduct = 1 %]
+        [% ELSE %]
+          [% multivoteproduct = 1 %]
+        [% END %]
+        &lt;tr&gt;
+          &lt;th&gt;[% product.name FILTER html %]&lt;/th&gt;
+          &lt;td colspan=&quot;2&quot; &gt;&lt;a href=&quot;buglist.cgi?bug_id=
+              [%- product.bug_ids.join(&quot;,&quot;) FILTER uri %]&quot;&gt;([% terms.bug %] list)&lt;/a&gt;
+          &lt;/td&gt;
+          &lt;td&gt;
+            [% IF product.maxperbug &lt; product.maxvotes AND
+                  product.maxperbug &gt; 1 %]
+              &lt;font size=&quot;-1&quot;&gt;
+                (Note: only [% product.maxperbug FILTER html %] vote
+                [% &quot;s&quot; IF product.maxperbug != 1 %] allowed per [% terms.bug %] in
+                this product.)
+              &lt;/font&gt;
+            [% END %]
+          &lt;/td&gt;
+        &lt;/tr&gt;
+
+        [% FOREACH bug = product.bugs %]
+          &lt;tr [% IF bug.id == this_bug.id &amp;&amp; canedit %] 
+            class=&quot;bz_bug_being_voted_on&quot; [% END %]&gt;
+            &lt;td&gt;
+              [% IF bug.id == this_bug.id &amp;&amp; canedit %]
+                [% IF product.onevoteonly %]
+                  Vote For This [% terms.Bug %] &amp;rarr;
+                [% ELSE %]
+                  Enter Votes Here &amp;rarr;
+                [% END %]
+              [%- END %]
+            &lt;/td&gt;
+            &lt;td align=&quot;right&quot;&gt;&lt;a name=&quot;vote_[% bug.id FILTER html %]&quot;&gt;
+              [% IF canedit %]
+                [% IF product.onevoteonly %]
+                  &lt;input type=&quot;checkbox&quot; name=&quot;[% bug.id FILTER html %]&quot; value=&quot;1&quot;
+                    [% &quot; checked&quot; IF bug.count %] id=&quot;bug_[% bug.id FILTER html %]&quot;&gt;
+                [% ELSE %]
+                  &lt;input name=&quot;[% bug.id FILTER html %]&quot; value=&quot;[% bug.count FILTER html %]&quot;
+                         size=&quot;2&quot; id=&quot;bug_[% bug.id FILTER html %]&quot;&gt;
+                [% END %]
+              [% ELSE %]
+                [% bug.count FILTER html %]
+              [% END %]
+            &lt;/a&gt;&lt;/td&gt;
+            &lt;td align=&quot;center&quot;&gt;
+              [% bug.id FILTER bug_link(bug) FILTER none %]
+            &lt;/td&gt;
+            &lt;td&gt;
+              [% bug.summary FILTER html %]
+              (&lt;a href=&quot;page.cgi?id=voting/bug.html&amp;amp;bug_id=[% bug.id FILTER uri %]&quot;&gt;Show Votes&lt;/a&gt;)
+            &lt;/td&gt;
+          &lt;/tr&gt;
+        [% END %]
+
+        &lt;tr&gt;
+          &lt;td&gt;&lt;/td&gt;
+          &lt;td colspan=&quot;3&quot;&gt;[% product.total FILTER html %] vote
+            [% &quot;s&quot; IF product.total != 1 %] used out of [% product.maxvotes FILTER html %]
+            allowed.
+            &lt;br&gt;
+            &lt;br&gt;
+          &lt;/td&gt;
+        &lt;/tr&gt;
+      [% END %]
+    &lt;/table&gt;
+
+    [% IF canedit %]
+      &lt;input type=&quot;submit&quot; value=&quot;Change My Votes&quot; id=&quot;change&quot;&gt; or 
+      &lt;a href=&quot;buglist.cgi?bug_id=[% all_bug_ids.join(&quot;,&quot;) FILTER uri %]&quot;&gt;view all
+        as [% terms.bug %] list&lt;/a&gt;
+      &lt;br&gt;
+      &lt;br&gt;
+      To change your votes,
+      [% IF multivoteproduct %]
+        type in new numbers (using zero to mean no votes)
+        [% &quot; or &quot; IF onevoteproduct %]
+      [% END %]
+      [% IF onevoteproduct %]
+        change the checkbox
+      [% END %]
+      and then click &lt;b&gt;Change My Votes&lt;/b&gt;.
+    [% ELSE %]
+       &lt;a href=&quot;buglist.cgi?bug_id=[% all_bug_ids.join(&quot;,&quot;) FILTER uri %]&quot;&gt;View all
+         as [% terms.bug %] list&lt;/a&gt;
+    [% END %]
+  &lt;/form&gt;
+[% ELSE %]
+  &lt;p&gt;
+    [% IF canedit %]
+    You are
+    [% ELSE %]
+    This user is
+    [% END %]
+    currently not voting on any [% terms.bugs %].
+  &lt;/p&gt;
+[% END %]
+
+&lt;p&gt;
+  &lt;a href=&quot;page.cgi?id=voting.html&quot;&gt;Help with voting&lt;/a&gt;.
+&lt;/p&gt;
+
+[% PROCESS global/footer.html.tmpl %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaultpagesvotinghtmltmplfromrev173253trunkWebsitesbugswebkitorgtemplateendefaultpagesvotinghtmltmpl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/pages/voting.html.tmpl (from rev 173253, trunk/Websites/bugs.webkit.org/template/en/default/pages/voting.html.tmpl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/pages/voting.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/pages/voting.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,69 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Netscape Communications
+  # Corporation. Portions created by Netscape are
+  # Copyright (C) 1998 Netscape Communications Corporation. All
+  # Rights Reserved.
+  #
+  # Contributor(s): Terry Weissman &lt;terry@mozilla.org&gt;
+  #                 Gervase Markham &lt;gerv@gerv.net&gt;
+  #%]
+
+[% PROCESS global/variables.none.tmpl %]
+[% INCLUDE global/header.html.tmpl title = &quot;Voting&quot; %]
+
+&lt;p&gt;[% terms.Bugzilla %] has a &quot;voting&quot; feature. Each product allows users to 
+have a certain number of votes. (Some products may not allow any, which means 
+you can't vote on things in those products at all.) With your vote, you 
+indicate which [% terms.bugs %] you think are the most important and 
+would like to see fixed. Note that voting is nowhere near as effective 
+as providing a fix yourself.&lt;/p&gt;
+
+&lt;p&gt;Depending on how the administrator has configured the relevant product,
+you may be able to vote for the same [% terms.bug %] more than once.
+Remember that you have a limited number of votes. When weighted voting 
+is allowed and a limited number of votes are available to you, you will 
+have to decide whether you want to distribute your votes among a large 
+number of [% terms.bugs %] indicating your minimal interest or focus on 
+a few [% terms.bugs %] indicating your strong support for them.
+&lt;/p&gt;
+
+&lt;p&gt;To look at votes:&lt;/p&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;Go to the query page. Do a normal query, but enter 1 in the &quot;At least
+  ___ votes&quot; field. This will show you items that match your query that
+  have at least one vote.&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;p&gt;To vote for [% terms.abug %]:&lt;/p&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;Bring up the [% terms.bug %] in question.&lt;/li&gt;
+
+  &lt;li&gt;Click on the &quot;(vote)&quot; link that appears on the right of the &quot;Importance&quot;
+  fields. (If no such link appears, then voting may not be allowed in
+  this [% terms.bug %]'s product.)&lt;/li&gt;
+
+  &lt;li&gt;Indicate how many votes you want to give this [% terms.bug %]. This page 
+  also displays how many votes you've given to other [% terms.bugs %], so you 
+  may rebalance your votes as necessary.&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;p&gt;You will automatically get email notifying you of any changes that occur
+on [% terms.bugs %] you vote for.&lt;/p&gt;
+
+&lt;p&gt;You may review your votes at any time by clicking on the &quot;&lt;a href=
+&quot;page.cgi?id=voting/user.html&quot;&gt;My Votes&lt;/a&gt;&quot; link in the page footer.&lt;/p&gt;
+
+[% INCLUDE global/footer.html.tmpl %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaultvotingdeleteallhtmltmplfromrev173253trunkWebsitesbugswebkitorgtemplateendefaultbugvotesdeleteallhtmltmpl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/voting/delete-all.html.tmpl (from rev 173253, trunk/Websites/bugs.webkit.org/template/en/default/bug/votes/delete-all.html.tmpl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/voting/delete-all.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/voting/delete-all.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,52 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Netscape Communications
+  # Corporation. Portions created by Netscape are
+  # Copyright (C) 1998 Netscape Communications Corporation. All
+  # Rights Reserved.
+  #
+  # Contributor(s): Gervase Markham &lt;gerv@gerv.net&gt;
+  #%]
+
+[%# INTERFACE:
+  # This template has no interface.
+  #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% PROCESS global/header.html.tmpl
+           title = &quot;Remove your votes?&quot;
+ %]
+
+&lt;p&gt;
+  You are about to remove all of your [% terms.bug %] votes. Are you sure you wish to
+  remove your vote from every [% terms.bug %] you've voted on?
+&lt;/p&gt;
+
+&lt;form action=&quot;page.cgi?id=voting/user.html&quot; method=&quot;post&quot;&gt;
+    &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;vote&quot;&gt;
+    &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% issue_hash_token(['vote']) FILTER html %]&quot;&gt;
+  &lt;p&gt;
+    &lt;input type=&quot;radio&quot; name=&quot;delete_all_votes&quot; value=&quot;1&quot;&gt;
+    Yes, delete all my votes
+  &lt;/p&gt;
+  &lt;p&gt;
+    &lt;input type=&quot;radio&quot; name=&quot;delete_all_votes&quot; value=&quot;0&quot; checked=&quot;checked&quot;&gt;
+    No, go back and review my votes
+  &lt;/p&gt;
+  &lt;p&gt;
+    &lt;input type=&quot;submit&quot; id=&quot;vote&quot; value=&quot;Submit&quot;&gt;
+  &lt;/p&gt;
+&lt;/form&gt;
+
+[% PROCESS global/footer.html.tmpl %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsVotingtemplateendefaultvotingvotesremovedtxttmplfromrev173253trunkWebsitesbugswebkitorgtemplateendefaultemailvotesremovedtxttmpl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/voting/votes-removed.txt.tmpl (from rev 173253, trunk/Websites/bugs.webkit.org/template/en/default/email/votes-removed.txt.tmpl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/voting/votes-removed.txt.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Voting/template/en/default/voting/votes-removed.txt.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,55 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Netscape Communications
+  # Corporation. Portions created by Netscape are
+  # Copyright (C) 1998 Netscape Communications Corporation. All
+  # Rights Reserved.
+  #
+  # Contributor(s): Emmanuel Seyman &lt;eseyman@linagora.com&gt;
+  #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+From: [% Param('mailfrom') %]
+To: [% to %]
+Subject: [% terms.Bug %] [%+ bugid %] Some or all of your votes have been removed.
+X-Bugzilla-Type: voteremoved
+
+Some or all of your votes have been removed from [% terms.bug %] [%+ bugid %].
+
+You had [% votesold FILTER html %] [%+ IF votesold == 1 %]vote[% ELSE %]votes[% END
+%] on this [% terms.bug %], but [% votesremoved FILTER html %] have been removed.
+
+[% IF votesnew %]
+You still have [% votesnew FILTER html %] [%+ IF votesnew == 1 %]vote[% ELSE %]votes[% END %] on this [% terms.bug %].
+[% ELSE %]
+You have no more votes remaining on this [% terms.bug %].
+[% END %]
+
+Reason:
+[% IF reason == &quot;votes_bug_moved&quot; %]
+  This [% terms.bug %] has been moved to a different product.
+
+[% ELSIF reason == &quot;votes_too_many_per_bug&quot; %]
+  The rules for voting on this product has changed;
+  you had too many votes for a single [% terms.bug %].
+
+[% ELSIF reason == &quot;votes_too_many_per_user&quot; %]
+  The rules for voting on this product has changed; you had
+  too many total votes, so all votes have been removed.
+[% END %]
+
+
+
+[% urlbase %]show_bug.cgi?id=[% bugid %]
+
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionsVotingwebstylecssfromrev173253trunkWebsitesbugswebkitorgskinsstandardvotingcss"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/extensions/Voting/web/style.css (from rev 173253, trunk/Websites/bugs.webkit.org/skins/standard/voting.css) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/Voting/web/style.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/Voting/web/style.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,28 @@
</span><ins>+/* The contents of this file are subject to the Mozilla Public
+  * License Version 1.1 (the &quot;License&quot;); you may not use this file
+  * except in compliance with the License. You may obtain a copy of
+  * the License at http://www.mozilla.org/MPL/
+  *
+  * Software distributed under the License is distributed on an &quot;AS
+  * IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  * implied. See the License for the specific language governing
+  * rights and limitations under the License.
+  *
+  * The Original Code is the Bugzilla Bug Tracking System.
+  *
+  * Contributor(s): Gavin Shelley &lt;bugzilla@chimpychompy.org&gt;
+  */
+
+/* Highlight the row for the bug being voted on */
+tr.bz_bug_being_voted_on {
+    background-color: #e2e2e2;
+}
+
+tr.bz_bug_being_voted_on td {
+    border-style: solid none solid none;
+    border-width: thin;
+}
+
+#votes_container { 
+    white-space: nowrap; 
+}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgextensionscreatepl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/extensions/create.pl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/extensions/create.pl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/extensions/create.pl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,86 @@
</span><ins>+#!/usr/bin/env perl -w
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Everything Solved, Inc.
+# Portions created by the Initial Developer are Copyright (C) 2009 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+use strict;
+use lib qw(. lib);
+use Bugzilla;
+use Bugzilla::Constants;
+use Bugzilla::Error;
+use Bugzilla::Util qw(get_text);
+
+use File::Path qw(mkpath);
+use DateTime;
+
+my $base_dir = bz_locations()-&gt;{'extensionsdir'};
+
+my $name = $ARGV[0] or ThrowUserError('extension_create_no_name');
+if ($name !~ /^[A-Z]/) {
+    ThrowUserError('extension_first_letter_caps', { name =&gt; $name });
+}
+
+my $extension_dir = &quot;$base_dir/$name&quot;; 
+mkpath($extension_dir) 
+  || die &quot;$extension_dir already exists or cannot be created.\n&quot;;
+
+my $lcname = lc($name);
+foreach my $path (qw(lib web template/en/default/hook), 
+                  &quot;template/en/default/$lcname&quot;)
+{
+    mkpath(&quot;$extension_dir/$path&quot;) || die &quot;$extension_dir/$path: $!&quot;;
+}
+
+my $year = DateTime-&gt;now()-&gt;year;
+
+my $template = Bugzilla-&gt;template;
+my $vars = { year =&gt; $year, name =&gt; $name, path =&gt; $extension_dir };
+my %create_files = (
+    'config.pm.tmpl'       =&gt; 'Config.pm',
+    'extension.pm.tmpl'    =&gt; 'Extension.pm',
+    'util.pm.tmpl'         =&gt; 'lib/Util.pm',
+    'web-readme.txt.tmpl'  =&gt; 'web/README',
+    'hook-readme.txt.tmpl' =&gt; 'template/en/default/hook/README',
+    'name-readme.txt.tmpl' =&gt; &quot;template/en/default/$lcname/README&quot;,
+);
+
+foreach my $template_file (keys %create_files) {
+    my $target = $create_files{$template_file};
+    my $output;
+    $template-&gt;process(&quot;extensions/$template_file&quot;, $vars, \$output)
+      or ThrowTemplateError($template-&gt;error());
+   open(my $fh, '&gt;', &quot;$extension_dir/$target&quot;);
+   print $fh $output;
+   close($fh);
+}
+
+print get_text('extension_created', $vars), &quot;\n&quot;;
+
+__END__
+
+=head1 NAME
+
+extensions/create.pl - Create a framework for a new Bugzilla Extension.
+
+=head1 SYNOPSIS
+
+ extensions/create.pl NAME
+
+ Creates a framework for an extension called NAME in the F&lt;extensions/&gt;
+ directory.
</ins><span class="cx">Property changes on: trunk/Websites/bugs.webkit.org/extensions/create.pl
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkWebsitesbugswebkitorgimportxmlpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/importxml.pl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/importxml.pl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/importxml.pl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -70,6 +70,7 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla;
</span><ins>+use Bugzilla::Object;
</ins><span class="cx"> use Bugzilla::Bug;
</span><span class="cx"> use Bugzilla::Product;
</span><span class="cx"> use Bugzilla::Version;
</span><span class="lines">@@ -87,25 +88,23 @@
</span><span class="cx"> 
</span><span class="cx"> use MIME::Base64;
</span><span class="cx"> use MIME::Parser;
</span><del>-use Date::Format;
</del><span class="cx"> use Getopt::Long;
</span><span class="cx"> use Pod::Usage;
</span><span class="cx"> use XML::Twig;
</span><span class="cx"> 
</span><del>-# We want to capture errors and handle them here rather than have the Template
-# code barf all over the place.
-Bugzilla-&gt;usage_mode(Bugzilla::Constants::USAGE_MODE_CMDLINE);
-
</del><span class="cx"> my $debug = 0;
</span><span class="cx"> my $mail  = '';
</span><span class="cx"> my $attach_path = '';
</span><span class="cx"> my $help  = 0;
</span><ins>+my ($default_product_name, $default_component_name);
</ins><span class="cx"> 
</span><span class="cx"> my $result = GetOptions(
</span><span class="cx">     &quot;verbose|debug+&quot; =&gt; \$debug,
</span><span class="cx">     &quot;mail|sendmail!&quot; =&gt; \$mail,
</span><span class="cx">     &quot;attach_path=s&quot;  =&gt; \$attach_path,
</span><del>-    &quot;help|?&quot;         =&gt; \$help
</del><ins>+    &quot;help|?&quot;         =&gt; \$help,
+    &quot;product=s&quot;      =&gt; \$default_product_name,
+    &quot;component=s&quot;    =&gt; \$default_component_name,
</ins><span class="cx"> );
</span><span class="cx"> 
</span><span class="cx"> pod2usage(0) if $help;
</span><span class="lines">@@ -122,6 +121,9 @@
</span><span class="cx"> my $params = Bugzilla-&gt;params;
</span><span class="cx"> my ($timestamp) = $dbh-&gt;selectrow_array(&quot;SELECT NOW()&quot;);
</span><span class="cx"> 
</span><ins>+$default_product_name = '' if !defined $default_product_name;
+$default_component_name = '' if !defined $default_component_name;
+
</ins><span class="cx"> ###############################################################################
</span><span class="cx"> # Helper sub routines                                                         #
</span><span class="cx"> ###############################################################################
</span><span class="lines">@@ -131,7 +133,7 @@
</span><span class="cx">     my $subject    = shift;
</span><span class="cx">     my $message    = shift;
</span><span class="cx">     my @recipients = @_;
</span><del>-    my $from   = $params-&gt;{&quot;moved-from-address&quot;};
</del><ins>+    my $from   = $params-&gt;{&quot;mailfrom&quot;};
</ins><span class="cx">     $from =~ s/@/\@/g;
</span><span class="cx"> 
</span><span class="cx">     foreach my $to (@recipients){
</span><span class="lines">@@ -171,7 +173,7 @@
</span><span class="cx">     my (
</span><span class="cx">         $name,            $status,      $setter_login,
</span><span class="cx">         $requestee_login, $exporterid,  $bugid,
</span><del>-        $productid,       $componentid, $attachid
</del><ins>+        $componentid,     $productid,   $attachid
</ins><span class="cx">       )
</span><span class="cx">       = @_;
</span><span class="cx"> 
</span><span class="lines">@@ -321,22 +323,8 @@
</span><span class="cx">     }
</span><span class="cx">     Error( &quot;no maintainer&quot;, &quot;REOPEN&quot;, $exporter ) unless ($maintainer);
</span><span class="cx">     Error( &quot;no exporter&quot;,   &quot;REOPEN&quot;, $exporter ) unless ($exporter);
</span><del>-    Error( &quot;bug importing is disabled here&quot;, undef, $exporter ) unless ( $params-&gt;{&quot;move-enabled&quot;} );
</del><span class="cx">     Error( &quot;invalid exporter: $exporter&quot;, &quot;REOPEN&quot;, $exporter ) if ( !login_to_id($exporter) );
</span><span class="cx">     Error( &quot;no urlbase set&quot;, &quot;REOPEN&quot;, $exporter ) unless ($urlbase);
</span><del>-    my $def_product =
-        new Bugzilla::Product( { name =&gt; $params-&gt;{&quot;moved-default-product&quot;} } )
-        || Error(&quot;an invalid default product was defined for the target DB. &quot; .
-                  $params-&gt;{&quot;maintainer&quot;} . &quot; needs to fix the definitions of &quot; .
-                 &quot;moved-default-product. \n&quot;, &quot;REOPEN&quot;, $exporter);
-    my $def_component = new Bugzilla::Component(
-        {
-            product =&gt; $def_product,
-            name    =&gt; $params-&gt;{&quot;moved-default-component&quot;}
-        })
-    || Error(&quot;an invalid default component was defined for the target DB. &quot; .
-             $params-&gt;{&quot;maintainer&quot;} . &quot; needs to fix the definitions of &quot; .
-             &quot;moved-default-component.\n&quot;, &quot;REOPEN&quot;, $exporter);
</del><span class="cx"> }
</span><span class="cx">     
</span><span class="cx"> 
</span><span class="lines">@@ -505,21 +493,17 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    my @long_descs;
-    my $private = 0;
-
</del><span class="cx">     # Parse long descriptions
</span><ins>+    my @long_descs;
</ins><span class="cx">     foreach my $comment ( $bug-&gt;children('long_desc') ) {
</span><span class="cx">         Debug( &quot;Parsing Long Description&quot;, DEBUG_LEVEL );
</span><del>-        my %long_desc;
-        $long_desc{'who'}       = $comment-&gt;field('who');
-        $long_desc{'bug_when'}  = $comment-&gt;field('bug_when');
-        $long_desc{'isprivate'} = $comment-&gt;{'att'}-&gt;{'isprivate'} || 0;
</del><ins>+        my %long_desc = ( who       =&gt; $comment-&gt;field('who'),
+                          bug_when  =&gt; $comment-&gt;field('bug_when'),
+                          isprivate =&gt; $comment-&gt;{'att'}-&gt;{'isprivate'} || 0 );
</ins><span class="cx"> 
</span><del>-        # if one of the comments is private we need to set this flag
-        if ( $long_desc{'isprivate'} &amp;&amp; $exporter-&gt;in_group($params-&gt;{'insidergroup'})) {
-            $private = 1;
-        }
</del><ins>+        # If the exporter is not in the insidergroup, keep the comment public.
+        $long_desc{isprivate} = 0 unless $exporter-&gt;is_insider;
+
</ins><span class="cx">         my $data = $comment-&gt;field('thetext');
</span><span class="cx">         if ( defined $comment-&gt;first_child('thetext')-&gt;{'att'}-&gt;{'encoding'}
</span><span class="cx">             &amp;&amp; $comment-&gt;first_child('thetext')-&gt;{'att'}-&gt;{'encoding'} =~
</span><span class="lines">@@ -528,6 +512,8 @@
</span><span class="cx">             $data = decode_base64($data);
</span><span class="cx">         }
</span><span class="cx"> 
</span><ins>+        # For backwards-compatibility with Bugzillas before 3.6:
+        #
</ins><span class="cx">         # If we leave the attachment ID in the comment it will be made a link
</span><span class="cx">         # to the wrong attachment. Since the new attachment ID is unknown yet
</span><span class="cx">         # let's strip it out for now. We will make a comment with the right ID
</span><span class="lines">@@ -540,42 +526,22 @@
</span><span class="cx">         my $url = $urlbase . &quot;show_bug.cgi?id=&quot;;
</span><span class="cx">         $data =~ s/([Bb]ugs?\s*\#?\s*(\d+))/$url$2/g;
</span><span class="cx"> 
</span><ins>+        # Keep the original commenter if possible, else we will fall back
+        # to the exporter account.
+        $long_desc{whoid} = login_to_id($long_desc{who});
+
+        if (!$long_desc{whoid}) {
+            $data = &quot;The original author of this comment is $long_desc{who}.\n\n&quot; . $data;
+        }
+
</ins><span class="cx">         $long_desc{'thetext'} = $data;
</span><span class="cx">         push @long_descs, \%long_desc;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    # instead of giving each comment its own item in the longdescs
-    # table like it should have, lets cat them all into one big
-    # comment otherwise we would have to lie often about who
-    # authored the comment since commenters in one bugzilla probably
-    # don't have accounts in the other one.
-    # If one of the comments is private the whole comment will be
-    # private since we don't want to expose these unnecessarily
-    sub by_date { my @a; my @b; $a-&gt;{'bug_when'} cmp $b-&gt;{'bug_when'}; }
-    my @sorted_descs     = sort by_date @long_descs;
-    my $long_description = &quot;&quot;;
-    for ( my $z = 0 ; $z &lt;= $#sorted_descs ; $z++ ) {
-        if ( $z == 0 ) {
-            $long_description .= &quot;\n\n\n---- Reported by &quot;;
-        }
-        else {
-            $long_description .= &quot;\n\n\n---- Additional Comments From &quot;;
-        }
-        $long_description .= &quot;$sorted_descs[$z]-&gt;{'who'} &quot;;
-        $long_description .= &quot;$sorted_descs[$z]-&gt;{'bug_when'}&quot;;
-        $long_description .= &quot; ----&quot;;
-        $long_description .= &quot;\n\n&quot;;
-        $long_description .= &quot;THIS COMMENT IS PRIVATE \n&quot;
-          if ( $sorted_descs[$z]-&gt;{'isprivate'} );
-        $long_description .= $sorted_descs[$z]-&gt;{'thetext'};
-        $long_description .= &quot;\n&quot;;
-    }
</del><ins>+    my @sorted_descs = sort { $a-&gt;{'bug_when'} cmp $b-&gt;{'bug_when'} } @long_descs;
</ins><span class="cx"> 
</span><del>-    my $comments;
-
-    $comments .= &quot;\n\n--- Bug imported by $exporter_login &quot;;
-    $comments .= time2str( &quot;%Y-%m-%d %H:%M&quot;, time ) . &quot; &quot;;
-    $comments .= $params-&gt;{'timezone'};
</del><ins>+    my $comments = &quot;\n\n--- Bug imported by $exporter_login &quot;;
+    $comments .= format_time(scalar localtime(time()), '%Y-%m-%d %R %Z') . &quot; &quot;;
</ins><span class="cx">     $comments .= &quot; ---\n\n&quot;;
</span><span class="cx">     $comments .= &quot;This bug was previously known as _bug_ $bug_fields{'bug_id'} at &quot;;
</span><span class="cx">     $comments .= $urlbase . &quot;show_bug.cgi?id=&quot; . $bug_fields{'bug_id'} . &quot;\n&quot;;
</span><span class="lines">@@ -623,12 +589,12 @@
</span><span class="cx">     # Timestamps
</span><span class="cx">     push( @query, &quot;creation_ts&quot; );
</span><span class="cx">     push( @values,
</span><del>-        format_time( $bug_fields{'creation_ts'}, &quot;%Y-%m-%d %X&quot; )
</del><ins>+        format_time( $bug_fields{'creation_ts'}, &quot;%Y-%m-%d %T&quot; )
</ins><span class="cx">           || $timestamp );
</span><span class="cx"> 
</span><span class="cx">     push( @query, &quot;delta_ts&quot; );
</span><span class="cx">     push( @values,
</span><del>-        format_time( $bug_fields{'delta_ts'}, &quot;%Y-%m-%d %X&quot; )
</del><ins>+        format_time( $bug_fields{'delta_ts'}, &quot;%Y-%m-%d %T&quot; )
</ins><span class="cx">           || $timestamp );
</span><span class="cx"> 
</span><span class="cx">     # Bug Access
</span><span class="lines">@@ -638,49 +604,34 @@
</span><span class="cx">     push( @query,  &quot;reporter_accessible&quot; );
</span><span class="cx">     push( @values, $bug_fields{'reporter_accessible'} ? 1 : 0 );
</span><span class="cx"> 
</span><del>-    # Product and Component if there is no valid default product and
-    # component defined in the parameters, we wouldn't be here
-    my $def_product =
-      new Bugzilla::Product( { name =&gt; $params-&gt;{&quot;moved-default-product&quot;} } );
-    my $def_component = new Bugzilla::Component(
-        {
-            product =&gt; $def_product,
-            name    =&gt; $params-&gt;{&quot;moved-default-component&quot;}
-        }
-    );
-    my $product;
-    my $component;
</del><ins>+    my $product = new Bugzilla::Product(
+        { name =&gt; $bug_fields{'product'} || '' });
+    if (!$product) {
+        $err .= &quot;Unknown Product &quot; . $bug_fields{'product'} . &quot;\n&quot;;
+        $err .= &quot;   Using default product set at the command line.\n&quot;;
+        $product = new Bugzilla::Product({ name =&gt; $default_product_name })
+            or Error(&quot;an invalid default product was defined for the target&quot;
+                     . &quot; DB. &quot; . $params-&gt;{&quot;maintainer&quot;} . &quot; needs to specify &quot;
+                     . &quot;--product when calling importxml.pl&quot;, &quot;REOPEN&quot;, 
+                     $exporter);
+    }
+    my $component = new Bugzilla::Component({
+        product =&gt; $product, name =&gt; $bug_fields{'component'} || '' });
+    if (!$component) {
+        $err .= &quot;Unknown Component &quot; . $bug_fields{'component'} . &quot;\n&quot;;
+        $err .= &quot;   Using default product and component set &quot;;
+        $err .= &quot;at the command line.\n&quot;;
</ins><span class="cx"> 
</span><del>-    if ( defined $bug_fields{'product'} ) {
-        $product = new Bugzilla::Product( { name =&gt; $bug_fields{'product'} } );
-        unless ($product) {
-            $product = $def_product;
-            $err .= &quot;Unknown Product &quot; . $bug_fields{'product'} . &quot;\n&quot;;
-            $err .= &quot;   Using default product set in Parameters \n&quot;;
</del><ins>+        $product = new Bugzilla::Product({ name =&gt; $default_product_name });
+        $component = new Bugzilla::Component({
+           name =&gt; $default_component_name, product =&gt; $product });
+        if (!$component) {
+            Error(&quot;an invalid default component was defined for the target&quot; 
+                  . &quot; DB. &quot;.  $params-&gt;{&quot;maintainer&quot;} . &quot; needs to specify &quot; 
+                  . &quot;--component when calling importxml.pl&quot;, &quot;REOPEN&quot;, 
+                  $exporter);
</ins><span class="cx">         }
</span><span class="cx">     }
</span><del>-    else {
-        $product = $def_product;
-    }
-    if ( defined $bug_fields{'component'} ) {
-        $component = new Bugzilla::Component(
-            {
-                product =&gt; $product,
-                name    =&gt; $bug_fields{'component'}
-            }
-        );
-        unless ($component) {
-            $component = $def_component;
-            $product   = $def_product;
-            $err .= &quot;Unknown Component &quot; . $bug_fields{'component'} . &quot;\n&quot;;
-            $err .= &quot;   Using default product and component set &quot;;
-            $err .= &quot;in Parameters \n&quot;;
-        }
-    }
-    else {
-        $component = $def_component;
-        $product   = $def_product;
-    }
</del><span class="cx"> 
</span><span class="cx">     my $prod_id = $product-&gt;id;
</span><span class="cx">     my $comp_id = $component-&gt;id;
</span><span class="lines">@@ -808,13 +759,12 @@
</span><span class="cx"> 
</span><span class="cx">     # Process time fields
</span><span class="cx">     if ( $params-&gt;{&quot;timetrackinggroup&quot;} ) {
</span><del>-        my $date = format_time( $bug_fields{'deadline'}, &quot;%Y-%m-%d&quot; )
-          || undef;
</del><ins>+        my $date = validate_date( $bug_fields{'deadline'} ) ? $bug_fields{'deadline'} : undef;
</ins><span class="cx">         push( @values, $date );
</span><span class="cx">         push( @query,  &quot;deadline&quot; );
</span><span class="cx">         if ( defined $bug_fields{'estimated_time'} ) {
</span><span class="cx">             eval {
</span><del>-                Bugzilla::Bug::ValidateTime($bug_fields{'estimated_time'}, &quot;e&quot;);
</del><ins>+                Bugzilla::Object::_validate_time($bug_fields{'estimated_time'}, &quot;e&quot;);
</ins><span class="cx">             };
</span><span class="cx">             if (!$@){
</span><span class="cx">                 push( @values, $bug_fields{'estimated_time'} );
</span><span class="lines">@@ -823,7 +773,7 @@
</span><span class="cx">         }
</span><span class="cx">         if ( defined $bug_fields{'remaining_time'} ) {
</span><span class="cx">             eval {
</span><del>-                Bugzilla::Bug::ValidateTime($bug_fields{'remaining_time'}, &quot;r&quot;);
</del><ins>+                Bugzilla::Object::_validate_time($bug_fields{'remaining_time'}, &quot;r&quot;);
</ins><span class="cx">             };
</span><span class="cx">             if (!$@){
</span><span class="cx">                 push( @values, $bug_fields{'remaining_time'} );
</span><span class="lines">@@ -832,7 +782,7 @@
</span><span class="cx">         }
</span><span class="cx">         if ( defined $bug_fields{'actual_time'} ) {
</span><span class="cx">             eval {
</span><del>-                Bugzilla::Bug::ValidateTime($bug_fields{'actual_time'}, &quot;a&quot;);
</del><ins>+                Bugzilla::Object::_validate_time($bug_fields{'actual_time'}, &quot;a&quot;);
</ins><span class="cx">             };
</span><span class="cx">             if ($@){
</span><span class="cx">                 $bug_fields{'actual_time'} = 0.0;
</span><span class="lines">@@ -904,8 +854,6 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # Status &amp; Resolution
</span><del>-    my $has_res = defined($bug_fields{'resolution'});
-    my $has_status = defined($bug_fields{'bug_status'});
</del><span class="cx">     my $valid_res = check_field('resolution',  
</span><span class="cx">                                   scalar $bug_fields{'resolution'}, 
</span><span class="cx">                                   undef, ERR_LEVEL );
</span><span class="lines">@@ -918,7 +866,7 @@
</span><span class="cx">     
</span><span class="cx">     # Check everconfirmed 
</span><span class="cx">     my $everconfirmed;
</span><del>-    if ($product-&gt;votes_to_confirm) {
</del><ins>+    if ($product-&gt;allows_unconfirmed) {
</ins><span class="cx">         $everconfirmed = $bug_fields{'everconfirmed'} || 0;
</span><span class="cx">     }
</span><span class="cx">     else {
</span><span class="lines">@@ -932,9 +880,9 @@
</span><span class="cx">     # that might not yet be in the database we have no way of populating
</span><span class="cx">     # this table. Change the resolution instead.
</span><span class="cx">     if ( $valid_res  &amp;&amp; ( $bug_fields{'resolution'} eq &quot;DUPLICATE&quot; ) ) {
</span><del>-        $resolution = &quot;MOVED&quot;;
</del><ins>+        $resolution = &quot;INVALID&quot;;
</ins><span class="cx">         $err .= &quot;This bug was marked DUPLICATE in the database &quot;;
</span><del>-        $err .= &quot;it was moved from.\n    Changing resolution to \&quot;MOVED\&quot;\n&quot;;
</del><ins>+        $err .= &quot;it was moved from.\n    Changing resolution to \&quot;INVALID\&quot;\n&quot;;
</ins><span class="cx">     } 
</span><span class="cx"> 
</span><span class="cx">     # If there is at least 1 initial bug status different from UNCO, use it,
</span><span class="lines">@@ -947,7 +895,7 @@
</span><span class="cx">         $initial_status = $bug_statuses[0]-&gt;name;
</span><span class="cx">     }
</span><span class="cx">     else {
</span><del>-        @bug_statuses = @{Bugzilla::Status-&gt;get_all()};
</del><ins>+        @bug_statuses = Bugzilla::Status-&gt;get_all();
</ins><span class="cx">         # Exclude UNCO and inactive bug statuses.
</span><span class="cx">         @bug_statuses = grep { $_-&gt;is_active &amp;&amp; $_-&gt;name ne 'UNCONFIRMED'} @bug_statuses;
</span><span class="cx">         my @open_statuses = grep { $_-&gt;is_open } @bug_statuses;
</span><span class="lines">@@ -960,10 +908,10 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if($has_status){
</del><ins>+    if ($status) {
</ins><span class="cx">         if($valid_status){
</span><span class="cx">             if($is_open){
</span><del>-                if($has_res){
</del><ins>+                if ($resolution) {
</ins><span class="cx">                     $err .= &quot;Resolution set on an open status.\n&quot;;
</span><span class="cx">                     $err .= &quot;   Dropping resolution $resolution\n&quot;;
</span><span class="cx">                     $resolution = undef;
</span><span class="lines">@@ -985,7 +933,6 @@
</span><span class="cx">                     if($status eq &quot;UNCONFIRMED&quot;){
</span><span class="cx">                         $err .= &quot;Bug Status was UNCONFIRMED but everconfirmed was true\n&quot;;
</span><span class="cx">                         $err .= &quot;   Setting status to $initial_status\n&quot;;
</span><del>-                        $err .= &quot;Resetting votes to 0\n&quot; if ( $bug_fields{'votes'} );
</del><span class="cx">                         $status = $initial_status;
</span><span class="cx">                     }
</span><span class="cx">                 }
</span><span class="lines">@@ -998,7 +945,7 @@
</span><span class="cx">                 }
</span><span class="cx">             }
</span><span class="cx">             else{ # $is_open is false
</span><del>-               if(!$has_res){
</del><ins>+               if (!$resolution) {
</ins><span class="cx">                    $err .= &quot;Missing Resolution. Setting status to &quot;;
</span><span class="cx">                    if($everconfirmed){
</span><span class="cx">                        $status = $initial_status;
</span><span class="lines">@@ -1009,10 +956,10 @@
</span><span class="cx">                        $err .= &quot;UNCONFIRMED\n&quot;;
</span><span class="cx">                    }
</span><span class="cx">                }
</span><del>-               if(!$valid_res){
</del><ins>+               elsif (!$valid_res) {
</ins><span class="cx">                    $err .= &quot;Unknown resolution \&quot;$resolution\&quot;.\n&quot;;
</span><del>-                   $err .= &quot;   Setting resolution to MOVED\n&quot;;
-                   $resolution = &quot;MOVED&quot;;
</del><ins>+                   $err .= &quot;   Setting resolution to INVALID\n&quot;;
+                   $resolution = &quot;INVALID&quot;;
</ins><span class="cx">                }
</span><span class="cx">             }   
</span><span class="cx">         }
</span><span class="lines">@@ -1028,9 +975,8 @@
</span><span class="cx">             $err .=  $bug_fields{'bug_status'} . &quot;\&quot;.\n&quot;;
</span><span class="cx">             $resolution = undef;
</span><span class="cx">         }
</span><del>-                
</del><span class="cx">     }
</span><del>-    else{ #has_status is false
</del><ins>+    else {
</ins><span class="cx">         if($everconfirmed){  
</span><span class="cx">             $status = $initial_status;
</span><span class="cx">         }
</span><span class="lines">@@ -1041,8 +987,8 @@
</span><span class="cx">         $err .= &quot;   Previous status was unknown\n&quot;;
</span><span class="cx">         $resolution = undef;
</span><span class="cx">     }
</span><del>-                                 
-    if (defined $resolution){
</del><ins>+
+    if ($resolution) {
</ins><span class="cx">         push( @query,  &quot;resolution&quot; );
</span><span class="cx">         push( @values, $resolution );
</span><span class="cx">     }
</span><span class="lines">@@ -1166,15 +1112,6 @@
</span><span class="cx">                 $keywordseen{$keyword_obj-&gt;id} = 1;
</span><span class="cx">             }
</span><span class="cx">         }
</span><del>-        my ($keywordarray) = $dbh-&gt;selectcol_arrayref(
-            &quot;SELECT d.name FROM keyworddefs d
-                    INNER JOIN keywords k 
-                    ON d.id = k.keywordid 
-                    WHERE k.bug_id = ? 
-                    ORDER BY d.name&quot;, undef, $id);
-        my $keywordstring = join( &quot;, &quot;, @{$keywordarray} );
-        $dbh-&gt;do( &quot;UPDATE bugs SET keywords = ? WHERE bug_id = ?&quot;,
-            undef, $keywordstring, $id )
</del><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # Insert values of custom multi-select fields. They have already
</span><span class="lines">@@ -1205,7 +1142,7 @@
</span><span class="cx">             $err .= &quot;No attachment ID specified, dropping attachment\n&quot;;
</span><span class="cx">             next;
</span><span class="cx">         }
</span><del>-        if (!$exporter-&gt;in_group($params-&gt;{'insidergroup'}) &amp;&amp; $att-&gt;{'isprivate'}){
</del><ins>+        if (!$exporter-&gt;is_insider &amp;&amp; $att-&gt;{'isprivate'}) {
</ins><span class="cx">             $err .= &quot;Exporter not in insidergroup and attachment marked private.\n&quot;;
</span><span class="cx">             $err .= &quot;   Marking attachment public\n&quot;;
</span><span class="cx">             $att-&gt;{'isprivate'} = 0;
</span><span class="lines">@@ -1256,19 +1193,21 @@
</span><span class="cx">     # Clear the attachments array for the next bug
</span><span class="cx">     @attachments = ();
</span><span class="cx"> 
</span><del>-    # Insert longdesc and append any errors
</del><ins>+    # Insert comments and append any errors
</ins><span class="cx">     my $worktime = $bug_fields{'actual_time'} || 0.0;
</span><del>-    $worktime = 0.0 if (!$exporter-&gt;in_group($params-&gt;{'timetrackinggroup'}));
-    $long_description .= &quot;\n&quot; . $comments;
-    if ($err) {
-        $long_description .= &quot;\n$err\n&quot;;
</del><ins>+    $worktime = 0.0 if (!$exporter-&gt;is_timetracker);
+    $comments .= &quot;\n$err\n&quot; if $err;
+
+    my $sth_comment =
+      $dbh-&gt;prepare('INSERT INTO longdescs (bug_id, who, bug_when, isprivate,
+                                            thetext, work_time)
+                     VALUES (?, ?, ?, ?, ?, ?)');
+
+    foreach my $c (@sorted_descs) {
+        $sth_comment-&gt;execute($id, $c-&gt;{whoid} || $exporterid, $c-&gt;{bug_when},
+                              $c-&gt;{isprivate}, $c-&gt;{thetext}, 0);
</ins><span class="cx">     }
</span><del>-    trick_taint($long_description);
-    $dbh-&gt;do(&quot;INSERT INTO longdescs 
-                     (bug_id, who, bug_when, work_time, isprivate, thetext) 
-                     VALUES (?,?,?,?,?,?)&quot;, undef,
-        $id, $exporterid, $timestamp, $worktime, $private, $long_description
-    );
</del><ins>+    $sth_comment-&gt;execute($id, $exporterid, $timestamp, 0, $comments, $worktime);
</ins><span class="cx">     Bugzilla::Bug-&gt;new($id)-&gt;_sync_fulltext('new_bug');
</span><span class="cx"> 
</span><span class="cx">     # Add this bug to each group of which its product is a member.
</span><span class="lines">@@ -1291,7 +1230,7 @@
</span><span class="cx">     }
</span><span class="cx">     Debug( $log, OK_LEVEL );
</span><span class="cx">     push(@logs, $log);
</span><del>-    Bugzilla::BugMail::Send( $id, { 'changer' =&gt; $exporter_login } ) if ($mail);
</del><ins>+    Bugzilla::BugMail::Send( $id, { 'changer' =&gt; $exporter } ) if ($mail);
</ins><span class="cx"> 
</span><span class="cx">     # done with the xml data. Lets clear it from memory
</span><span class="cx">     $twig-&gt;purge;
</span><span class="lines">@@ -1352,32 +1291,39 @@
</span><span class="cx"> 
</span><span class="cx"> =head1 SYNOPSIS
</span><span class="cx"> 
</span><del>-    importxml.pl [options] [file ...]
</del><ins>+ importxml.pl [options] [file ...]
</ins><span class="cx"> 
</span><del>- Options:
-       -? --help        brief help message
-       -v --verbose     print error and debug information. 
-                        Multiple -v increases verbosity
-       -m --sendmail    send mail to recipients with log of bugs imported
-       --attach_path    The path to the attachment files.
-                        (Required if encoding=&quot;filename&quot; is used for attachments.)
-
</del><span class="cx"> =head1 OPTIONS
</span><span class="cx"> 
</span><del>-=over 8
</del><ins>+=over
</ins><span class="cx"> 
</span><span class="cx"> =item B&lt;-?&gt;
</span><span class="cx"> 
</span><del>-    Print a brief help message and exits.
</del><ins>+Print a brief help message and exit.
</ins><span class="cx"> 
</span><span class="cx"> =item B&lt;-v&gt;
</span><span class="cx"> 
</span><del>-    Print error and debug information. Mulltiple -v increases verbosity
</del><ins>+Print error and debug information. Mulltiple -v increases verbosity
</ins><span class="cx"> 
</span><del>-=item B&lt;-m&gt;
</del><ins>+=item B&lt;-m&gt; B&lt;--sendmail&gt;
</ins><span class="cx"> 
</span><del>-    Send mail to exporter with a log of bugs imported and any errors.
</del><ins>+Send mail to exporter with a log of bugs imported and any errors.
</ins><span class="cx"> 
</span><ins>+=item B&lt;--attach_path&gt;
+
+The path to the attachment files. (Required if encoding=&quot;filename&quot;
+is used for attachments.)
+
+=item B&lt;--product=name&gt;
+
+The product to put the bug in if the product specified in the
+XML doesn't exist.
+
+=item B&lt;--component=name&gt;
+
+The component to put the bug in if the component specified in the
+XML doesn't exist.
+
</ins><span class="cx"> =back
</span><span class="cx"> 
</span><span class="cx"> =head1 DESCRIPTION
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgindexcgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/index.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/index.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/index.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -38,23 +38,24 @@
</span><span class="cx"> 
</span><span class="cx"> # Check whether or not the user is logged in
</span><span class="cx"> my $user = Bugzilla-&gt;login(LOGIN_OPTIONAL);
</span><ins>+my $cgi = Bugzilla-&gt;cgi;
+my $template = Bugzilla-&gt;template;
+my $vars = {};
</ins><span class="cx"> 
</span><ins>+# And log out the user if requested. We do this first so that nothing
+# else accidentally relies on the current login.
+if ($cgi-&gt;param('logout')) {
+    Bugzilla-&gt;logout();
+    $user = Bugzilla-&gt;user;
+    $vars-&gt;{'message'} = &quot;logged_out&quot;;
+    # Make sure that templates or other code doesn't get confused about this.
+    $cgi-&gt;delete('logout');
+}
+
</ins><span class="cx"> ###############################################################################
</span><span class="cx"> # Main Body Execution
</span><span class="cx"> ###############################################################################
</span><span class="cx"> 
</span><del>-my $cgi = Bugzilla-&gt;cgi;
-# Force to use HTTPS unless Bugzilla-&gt;params-&gt;{'ssl'} equals 'never'.
-# This is required because the user may want to log in from here.
-if ($cgi-&gt;protocol ne 'https' &amp;&amp; Bugzilla-&gt;params-&gt;{'sslbase'} ne ''
-    &amp;&amp; Bugzilla-&gt;params-&gt;{'ssl'} ne 'never')
-{
-    $cgi-&gt;require_https(Bugzilla-&gt;params-&gt;{'sslbase'});
-}
-
-my $template = Bugzilla-&gt;template;
-my $vars = {};
-
</del><span class="cx"> # Return the appropriate HTTP response headers.
</span><span class="cx"> print $cgi-&gt;header();
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorginstallmodulepl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/install-module.pl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/install-module.pl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/install-module.pl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -26,7 +26,7 @@
</span><span class="cx"> # CPAN has chdir'ed around. We do all of this in this funny order to
</span><span class="cx"> # make sure that we use the lib/ modules instead of the base Perl modules,
</span><span class="cx"> # in case the lib/ modules are newer.
</span><del>-use Cwd qw(abs_path);
</del><ins>+use Cwd qw(abs_path cwd);
</ins><span class="cx"> use lib abs_path('.');
</span><span class="cx"> use Bugzilla::Constants;
</span><span class="cx"> use lib abs_path(bz_locations()-&gt;{ext_libpath});
</span><span class="lines">@@ -35,21 +35,28 @@
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla::Constants;
</span><span class="cx"> use Bugzilla::Install::Requirements;
</span><ins>+use Bugzilla::Install::Util qw(bin_loc init_console vers_cmp);
</ins><span class="cx"> 
</span><span class="cx"> use Data::Dumper;
</span><span class="cx"> use Getopt::Long;
</span><span class="cx"> use Pod::Usage;
</span><span class="cx"> 
</span><ins>+init_console();
+
+my @original_args = @ARGV;
+my $original_dir = cwd();
</ins><span class="cx"> our %switch;
</span><del>-
</del><span class="cx"> GetOptions(\%switch, 'all|a', 'upgrade-all|u', 'show-config|s', 'global|g',
</span><del>-                     'help|h');
</del><ins>+                     'shell', 'help|h');
</ins><span class="cx"> 
</span><span class="cx"> pod2usage({ -verbose =&gt; 1 }) if $switch{'help'};
</span><span class="cx"> 
</span><del>-if (ON_WINDOWS) {
-    print &quot;\nYou cannot run this script on Windows. Please follow instructions\n&quot;;
-    print &quot;given by checksetup.pl to install missing Perl modules.\n\n&quot;;
</del><ins>+if (ON_ACTIVESTATE) {
+    print &lt;&lt;END;
+You cannot run this script when using ActiveState Perl. Please follow
+the instructions given by checksetup.pl to install missing Perl modules.
+
+END
</ins><span class="cx">     exit;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -58,15 +65,15 @@
</span><span class="cx"> set_cpan_config($switch{'global'});
</span><span class="cx"> 
</span><span class="cx"> if ($switch{'show-config'}) {
</span><del>-  print Dumper($CPAN::Config);
-  exit;
</del><ins>+    print Dumper($CPAN::Config);
+    exit;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-my $can_notest = 1;
-if (substr(CPAN-&gt;VERSION, 0, 3) &lt; 1.8) {
-    $can_notest = 0;
-    print &quot;* Note: If you upgrade your CPAN module, installs will be faster.\n&quot;;
-    print &quot;* You can upgrade CPAN by doing: $^X install-module.pl CPAN\n&quot;;
</del><ins>+check_cpan_requirements($original_dir, \@original_args);
+
+if ($switch{'shell'}) {
+    CPAN::shell();
+    exit;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> if ($switch{'all'} || $switch{'upgrade-all'}) {
</span><span class="lines">@@ -93,12 +100,13 @@
</span><span class="cx">         # configuration, and really should be installed on its own.
</span><span class="cx">         next if $cpan_name eq 'mod_perl2';
</span><span class="cx">         next if $cpan_name eq 'DBD::Oracle' and !$ENV{ORACLE_HOME};
</span><del>-        install_module($cpan_name, $can_notest);
</del><ins>+        next if $cpan_name eq 'DBD::Pg' and !bin_loc('pg_config');
+        install_module($cpan_name);
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> foreach my $module (@ARGV) {
</span><del>-    install_module($module, $can_notest);
</del><ins>+    install_module($module);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> __END__
</span><span class="lines">@@ -112,8 +120,9 @@
</span><span class="cx"> 
</span><span class="cx">   ./install-module.pl Module::Name [--global]
</span><span class="cx">   ./install-module.pl --all [--global]
</span><del>-  ./install-module.pl --all-upgrade [--global]
</del><ins>+  ./install-module.pl --upgrade-all [--global]
</ins><span class="cx">   ./install-module.pl --show-config
</span><ins>+  ./install-module.pl --shell
</ins><span class="cx"> 
</span><span class="cx">   Do &quot;./install-module.pl --help&quot; for more information.
</span><span class="cx"> 
</span><span class="lines">@@ -154,6 +163,10 @@
</span><span class="cx"> 
</span><span class="cx"> Prints out the CPAN configuration in raw Perl format. Useful for debugging.
</span><span class="cx"> 
</span><ins>+=item B&lt;--shell&gt;
+
+Starts a CPAN shell using the configuration of F&lt;install-module.pl&gt;.
+
</ins><span class="cx"> =item B&lt;--help&gt;
</span><span class="cx"> 
</span><span class="cx"> Shows this help.
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjobqueuepl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/jobqueue.pl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/jobqueue.pl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/jobqueue.pl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,81 @@
</span><ins>+#!/usr/bin/env perl -w
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Mozilla Corporation.
+# Portions created by the Initial Developer are Copyright (C) 2008
+# Mozilla Corporation. All Rights Reserved.
+#
+# Contributor(s): 
+#   Mark Smith &lt;mark@mozilla.com&gt;
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+use strict;
+use File::Basename;
+BEGIN { chdir dirname($0); }
+
+use lib qw(. lib);
+use Bugzilla;
+use Bugzilla::JobQueue::Runner;
+
+Bugzilla::JobQueue::Runner-&gt;new();
+
+=head1 NAME
+
+jobqueue.pl - Runs jobs in the background for Bugzilla.
+
+=head1 SYNOPSIS
+
+ ./jobqueue.pl [OPTIONS] COMMAND
+
+   OPTIONS:
+   -f        Run in the foreground (don't detach)
+   -d        Output a lot of debugging information
+   -p file   Specify the file where jobqueue.pl should store its current
+             process id. Defaults to F&lt;data/jobqueue.pl.pid&gt;.
+   -n name   What should this process call itself in the system log?
+             Defaults to the full path you used to invoke the script.
+
+   COMMANDS:
+   start     Starts a new jobqueue daemon if there isn't one running already
+   stop      Stops a running jobqueue daemon
+   restart   Stops a running jobqueue if one is running, and then
+             starts a new one.
+   once      Checks the job queue once, executes the first item found (if
+             any) and then exits
+   check     Report the current status of the daemon.
+   install   On some *nix systems, this automatically installs and
+             configures jobqueue.pl as a system service so that it will
+             start every time the machine boots.
+   uninstall Removes the system service for jobqueue.pl.
+   help      Display this usage info
+   version   Display the version of jobqueue.pl
+
+=head1 DESCRIPTION
+
+See L&lt;Bugzilla::JobQueue&gt; and L&lt;Bugzilla::JobQueue::Runner&gt;.
+
+=head1 Running jobqueue.pl as a System Service
+
+For systems that use Upstart or SysV Init, there is a SysV/Upstart init
+script included with Bugzilla for jobqueue.pl: F&lt;contrib/bugzilla-queue&gt;.
+It should work out-of-the-box on RHEL, Fedora, CentOS etc.
+
+You can install it by doing C&lt;./jobqueue.pl install&gt; as root, after
+already having run L&lt;checksetup&gt; at least once to completion
+on this Bugzilla installation.
+
+If you are using a system that isn't RHEL, Fedora, CentOS, etc., then you
+may have to modify F&lt;contrib/bugzilla-queue&gt; and install it yourself
+manually in order to get C&lt;jobqueue.pl&gt; running as a system service.
</ins><span class="cx">Property changes on: trunk/Websites/bugs.webkit.org/jobqueue.pl
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkWebsitesbugswebkitorgjsTUIjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/js/TUI.js (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/TUI.js        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/js/TUI.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -16,153 +16,94 @@
</span><span class="cx">  * Rights Reserved.
</span><span class="cx">  * 
</span><span class="cx">  * Contributor(s): Dennis Melentyev &lt;dennis.melentyev@infopulse.com.ua&gt;
</span><ins>+ *                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
</ins><span class="cx">  */
</span><span class="cx"> 
</span><del>- /* This file provides JavaScript functions to be included once one wish
-  * to add a hide/reveal/collapse per-class functionality
-  *
-  * 
-  * This file contains hide/reveal API for customizable page views
-  * TUI stands for Tweak UI.
-  *
-  * See bug 262592 for usage examples.
-  * 
-  * Note: this interface is experimental and under development.
-  * We may and probably will make breaking changes to it in the future.
-  */
</del><ins>+/* This file provides JavaScript functions to be included when one wishes
+ * to show/hide certain UI elements, and have the state of them being
+ * shown/hidden stored in a cookie.
+ * 
+ * TUI stands for Tweak UI.
+ *
+ * Requires js/util.js and the YUI Dom and Cookie libraries.
+ *
+ * See template/en/default/bug/create/create.html.tmpl for a usage example.
+ */
</ins><span class="cx"> 
</span><del>-  var TUIClasses = new Array;
-  var TUICookiesEnabled = -1;
</del><ins>+var TUI_HIDDEN_CLASS = 'bz_tui_hidden';
+var TUI_COOKIE_NAME  = 'TUI';
</ins><span class="cx"> 
</span><del>-  // Internal function to demangle cookies
-  function TUI_demangle(value) {
-    var pair;
-    var pairs = value.split(&quot;,&quot;);
-    for (i = 0; i &lt; pairs.length; i++) {
-      pair = pairs[i].split(&quot;:&quot;);
-      if (pair[0] != null &amp;&amp; pair[1] != null)
-        TUIClasses[pair[0]] = pair[1];
</del><ins>+var TUI_alternates = new Array();
+
+/** 
+ * Hides a particular class of elements if they are shown, 
+ * or shows them if they are hidden. Then it stores whether that
+ * class is now hidden or shown.
+ *
+ * @param className   The name of the CSS class to hide.
+ */
+function TUI_toggle_class(className) {
+    var elements = YAHOO.util.Dom.getElementsByClassName(className);
+    for (var i = 0; i &lt; elements.length; i++) {
+        bz_toggleClass(elements[i], TUI_HIDDEN_CLASS);
</ins><span class="cx">     }
</span><del>-  }
</del><ins>+    _TUI_save_class_state(elements, className);
+    _TUI_toggle_control_link(className);
+}
</ins><span class="cx"> 
</span><del>- /*  TUI_tweak: Function to redraw whole document. 
-  *  Also, initialize TUIClasses array with defaults, then override it 
-  *  with values from cookie
-  */
</del><span class="cx"> 
</span><del>-  function TUI_tweak( cookiesuffix, classes  ) {
-    var dc = document.cookie;
-    var begin = -1;
-    var end = 0;
</del><ins>+/**
+ * Specifies that a certain class of items should be hidden by default,
+ * if the user doesn't have a TUI cookie.
+ * 
+ * @param className   The class to hide by default.
+ */
+function TUI_hide_default(className) {
+    YAHOO.util.Event.onDOMReady(function () {
+        if (!YAHOO.util.Cookie.getSub('TUI', className)) {
+            TUI_toggle_class(className);
+        }
+    });
+}
</ins><span class="cx"> 
</span><del>-    // Register classes and their defaults
-    TUI_demangle(classes);
</del><ins>+function _TUI_toggle_control_link(className) {
+    var link = document.getElementById(className + &quot;_controller&quot;);
+    if (!link) return;
+    var original_text = link.innerHTML;
+    link.innerHTML = TUI_alternates[className];
+    TUI_alternates[className] = original_text;
+}
</ins><span class="cx"> 
</span><del>-    if (TUICookiesEnabled &gt; 0) {
-      // If cookies enabled, process them
-      TUI_demangle(TUI_getCookie(cookiesuffix));
</del><ins>+function _TUI_save_class_state(elements, aClass) {
+    // We just check the first element to see if it's hidden or not, and
+    // consider that all elements are the same.
+    if (YAHOO.util.Dom.hasClass(elements[0], TUI_HIDDEN_CLASS)) {
+        _TUI_store(aClass, 0);
</ins><span class="cx">     }
</span><del>-    else if (TUICookiesEnabled == -1) {
-      // If cookies availability not checked yet since browser does 
-      // not has navigator.cookieEnabled property, let's check it manualy
-      var cookie = TUI_getCookie(cookiesuffix);
-      if (cookie.length == 0)
-      {
-        TUI_setCookie(cookiesuffix);
-        // Cookies are definitely disabled for JS.
-        if (TUI_getCookie(cookiesuffix).length == 0)
-          TUICookiesEnabled = 0;
-        else
-          TUICookiesEnabled = 1;
-      }
-      else {
-        // Have cookie set, pretend to be able to reset them later on
-        TUI_demangle(cookie);
-        TUICookiesEnabled = 1;
-      }
</del><ins>+    else {
+        _TUI_store(aClass, 1);
</ins><span class="cx">     }
</span><del>-      
-    if (TUICookiesEnabled &gt; 0) {
-      var els = document.getElementsByTagName('*');
-      for (i = 0; i &lt; els.length; i++) {
-        if (null != TUIClasses[els[i].className]) {
-          TUI_apply(els[i], TUIClasses[els[i].className]);
-        }
-      }
-    }
-    return;
-  }
</del><ins>+}
</ins><span class="cx"> 
</span><del>-  // TUI_apply: Function to draw certain element. 
-  // Receives element itself and style value: hide, reveal or collapse
</del><ins>+function _TUI_store(aClass, state) {
+    YAHOO.util.Cookie.setSub(TUI_COOKIE_NAME, aClass, state,
+    {
+        expires: new Date('January 1, 2038'),
+        path: BUGZILLA.param.cookie_path
+    });
+}
</ins><span class="cx"> 
</span><del>-  function TUI_apply(element, value) {
-    if (TUICookiesEnabled &gt; 0 &amp;&amp; element != null) {
-      switch (value)
-      {
-        case 'hide':
-          element.style.visibility=&quot;hidden&quot;;
-          break;
-        case 'collapse':
-          element.style.visibility=&quot;hidden&quot;;
-          element.style.display=&quot;none&quot;;
-          break;
-        case 'reveal': // Shown item must expand
-        default:     // The default is to show &amp; expand
-          element.style.visibility=&quot;visible&quot;;
-          element.style.display=&quot;&quot;;
-          break;
-      }
-    }
-  }
-
-  // TUI_change: Function to process class. 
-  // Usualy called from onclick event of button
-
-  function TUI_change(cookiesuffix, clsname, action) {
-    if (TUICookiesEnabled &gt; 0) {
-      var els, i;
-      els = document.getElementsByTagName('*');
-      for (i=0; i&lt;els.length; i++) {
-        if (els[i].className.match(clsname)) {
-          TUI_apply(els[i], action);
</del><ins>+function _TUI_restore() {
+    var yui_classes = YAHOO.util.Cookie.getSubs(TUI_COOKIE_NAME);
+    for (yui_item in yui_classes) {
+        if (yui_classes[yui_item] == 0) {
+            var elements = YAHOO.util.Dom.getElementsByClassName(yui_item);
+            for (var i = 0; i &lt; elements.length; i++) {
+                YAHOO.util.Dom.addClass(elements[i], 'bz_tui_hidden');
+            }
+            _TUI_toggle_control_link(yui_item);
</ins><span class="cx">         }
</span><del>-      }
-      TUIClasses[clsname]=action;
-      TUI_setCookie(cookiesuffix);
</del><span class="cx">     }
</span><del>-  }
-  
-  // TUI_setCookie: Function to set TUI cookie. 
-  // Used internally
</del><ins>+}
</ins><span class="cx"> 
</span><del>-  function TUI_setCookie(cookiesuffix) {
-    var cookieval = &quot;&quot;;
-    var expireOn = new Date();
-    expireOn.setYear(expireOn.getFullYear() + 25); 
-    for (clsname in TUIClasses) {
-      if (cookieval.length &gt; 0)
-        cookieval += &quot;,&quot;;
-      cookieval += clsname+&quot;:&quot;+TUIClasses[clsname];
-    }
-    document.cookie=&quot;Bugzilla_TUI_&quot;+cookiesuffix+&quot;=&quot;+cookieval+&quot;; expires=&quot;+expireOn.toString();
-  }
-
-  // TUI_getCookie: Function to get TUI cookie. 
-  // Used internally
-
-  function TUI_getCookie(cookiesuffix) {
-    var dc = document.cookie;
-    var begin, end;
-    var cookiePrefix = &quot;Bugzilla_TUI_&quot;+cookiesuffix+&quot;=&quot;; 
-    begin = dc.indexOf(cookiePrefix, end);
-    if (begin != -1) {
-      begin += cookiePrefix.length;
-      end = dc.indexOf(&quot;;&quot;, begin);
-      if (end == -1) {
-        end = dc.length;
-      }
-      return unescape(dc.substring(begin, end));
-    }
-    return &quot;&quot;;
-  }
</del><ins>+YAHOO.util.Event.onDOMReady(_TUI_restore);
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsattachmentjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/js/attachment.js (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/attachment.js        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/js/attachment.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -19,8 +19,18 @@
</span><span class="cx">  *                 Joel Peshkin &lt;bugreport@peshkin.net&gt;
</span><span class="cx">  *                 Erik Stambaugh &lt;erik@dasbistro.com&gt;
</span><span class="cx">  *                 Marc Schumann &lt;wurblzap@gmail.com&gt;
</span><ins>+ *                 Guy Pyrzak &lt;guy.pyrzak@gmail.com&gt;
</ins><span class="cx">  */
</span><span class="cx"> 
</span><ins>+function validateAttachmentForm(theform) {
+    var desc_value = YAHOO.lang.trim(theform.description.value);
+    if (desc_value == '') {
+        alert(BUGZILLA.string.attach_desc_required);
+        return false;
+    }
+    return true;
+}
+
</ins><span class="cx"> function updateCommentPrivacy(checkbox) {
</span><span class="cx">     var text_elem = document.getElementById('comment');
</span><span class="cx">     if (checkbox.checked) {
</span><span class="lines">@@ -53,14 +63,13 @@
</span><span class="cx"> // endif WEBKIT_CHANGES
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-function URLFieldHandler() {
-    var field_attachurl = document.getElementById(&quot;attachurl&quot;);
</del><ins>+function TextFieldHandler() {
+    var field_text = document.getElementById(&quot;attach_text&quot;);
</ins><span class="cx">     var greyfields = new Array(&quot;data&quot;, &quot;ispatch&quot;, &quot;autodetect&quot;,
</span><del>-                               &quot;list&quot;, &quot;manual&quot;, &quot;bigfile&quot;,
-                               &quot;contenttypeselection&quot;,
</del><ins>+                               &quot;list&quot;, &quot;manual&quot;, &quot;contenttypeselection&quot;,
</ins><span class="cx">                                &quot;contenttypeentry&quot;);
</span><span class="cx">     var i, thisfield;
</span><del>-    if (field_attachurl.value.match(/^\s*$/)) {
</del><ins>+    if (field_text.value.match(/^\s*$/)) {
</ins><span class="cx">         for (i = 0; i &lt; greyfields.length; i++) {
</span><span class="cx">             thisfield = document.getElementById(greyfields[i]);
</span><span class="cx">             if (thisfield) {
</span><span class="lines">@@ -79,7 +88,7 @@
</span><span class="cx"> 
</span><span class="cx"> function DataFieldHandler() {
</span><span class="cx">     var field_data = document.getElementById(&quot;data&quot;);
</span><del>-    var greyfields = new Array(&quot;attachurl&quot;);
</del><ins>+    var greyfields = new Array(&quot;attach_text&quot;);
</ins><span class="cx">     var i, thisfield;
</span><span class="cx">     if (field_data.value.match(/^\s*$/)) {
</span><span class="cx">         for (i = 0; i &lt; greyfields.length; i++) {
</span><span class="lines">@@ -103,14 +112,284 @@
</span><span class="cx"> 
</span><span class="cx">     document.getElementById('data').value = '';
</span><span class="cx">     DataFieldHandler();
</span><del>-    if ((element = document.getElementById('bigfile')))
-        element.checked = '';
-    if ((element = document.getElementById('attachurl'))) {
</del><ins>+    if ((element = document.getElementById('attach_text'))) {
</ins><span class="cx">         element.value = '';
</span><del>-        URLFieldHandler();
</del><ins>+        TextFieldHandler();
</ins><span class="cx">     }
</span><span class="cx">     document.getElementById('description').value = '';
</span><del>-    document.getElementById('ispatch').checked = '';
</del><ins>+    /* Fire onchange so that the disabled state of the content-type
+     * radio buttons are also reset 
+     */
+    element = document.getElementById('ispatch');
+    element.checked = '';
+    bz_fireEvent(element, 'change');
</ins><span class="cx">     if ((element = document.getElementById('isprivate')))
</span><span class="cx">         element.checked = '';
</span><span class="cx"> }
</span><ins>+
+/* Functions used when viewing patches in Diff mode. */
+
+function collapse_all() {
+  var elem = document.checkboxform.firstChild;
+  while (elem != null) {
+    if (elem.firstChild != null) {
+      var tbody = elem.firstChild.nextSibling;
+      if (tbody.className == 'file') {
+        tbody.className = 'file_collapse';
+        twisty = get_twisty_from_tbody(tbody);
+        twisty.firstChild.nodeValue = '(+)';
+        twisty.nextSibling.checked = false;
+      }
+    }
+    elem = elem.nextSibling;
+  }
+  return false;
+}
+
+function expand_all() {
+  var elem = document.checkboxform.firstChild;
+  while (elem != null) {
+    if (elem.firstChild != null) {
+      var tbody = elem.firstChild.nextSibling;
+      if (tbody.className == 'file_collapse') {
+        tbody.className = 'file';
+        twisty = get_twisty_from_tbody(tbody);
+        twisty.firstChild.nodeValue = '(-)';
+        twisty.nextSibling.checked = true;
+      }
+    }
+    elem = elem.nextSibling;
+  }
+  return false;
+}
+
+var current_restore_elem;
+
+function restore_all() {
+  current_restore_elem = null;
+  incremental_restore();
+}
+
+function incremental_restore() {
+  if (!document.checkboxform.restore_indicator.checked) {
+    return;
+  }
+  var next_restore_elem;
+  if (current_restore_elem) {
+    next_restore_elem = current_restore_elem.nextSibling;
+  } else {
+    next_restore_elem = document.checkboxform.firstChild;
+  }
+  while (next_restore_elem != null) {
+    current_restore_elem = next_restore_elem;
+    if (current_restore_elem.firstChild != null) {
+      restore_elem(current_restore_elem.firstChild.nextSibling);
+    }
+    next_restore_elem = current_restore_elem.nextSibling;
+  }
+}
+
+function restore_elem(elem, alertme) {
+  if (elem.className == 'file_collapse') {
+    twisty = get_twisty_from_tbody(elem);
+    if (twisty.nextSibling.checked) {
+      elem.className = 'file';
+      twisty.firstChild.nodeValue = '(-)';
+    }
+  } else if (elem.className == 'file') {
+    twisty = get_twisty_from_tbody(elem);
+    if (!twisty.nextSibling.checked) {
+      elem.className = 'file_collapse';
+      twisty.firstChild.nodeValue = '(+)';
+    }
+  }
+}
+
+function twisty_click(twisty) {
+  tbody = get_tbody_from_twisty(twisty);
+  if (tbody.className == 'file') {
+    tbody.className = 'file_collapse';
+    twisty.firstChild.nodeValue = '(+)';
+    twisty.nextSibling.checked = false;
+  } else {
+    tbody.className = 'file';
+    twisty.firstChild.nodeValue = '(-)';
+    twisty.nextSibling.checked = true;
+  }
+  return false;
+}
+
+function get_tbody_from_twisty(twisty) {
+  return twisty.parentNode.parentNode.parentNode.nextSibling;
+}
+function get_twisty_from_tbody(tbody) {
+  return tbody.previousSibling.firstChild.nextSibling.firstChild.firstChild;
+}
+
+var prev_mode = 'raw';
+var current_mode = 'raw';
+var has_edited = 0;
+var has_viewed_as_diff = 0;
+// if WEBKIT_CHANGES
+var viewing_formatted_diff = false;
+// endif WEBKIT_CHANGES
+function editAsComment(patchviewerinstalled)
+{
+    switchToMode('edit', patchviewerinstalled);
+    has_edited = 1;
+}
+function undoEditAsComment(patchviewerinstalled)
+{
+    switchToMode(prev_mode, patchviewerinstalled);
+}
+function redoEditAsComment(patchviewerinstalled)
+{
+    switchToMode('edit', patchviewerinstalled);
+}
+
+// if WEBKIT_CHANGES
+function viewPrettyPatch(attachment_id)
+{
+    viewing_formatted_diff = !viewing_formatted_diff;
+    var src = &quot;attachment.cgi?id=&quot; . $attachment_id;
+    var buttonText = &quot;View Formatted Diff&quot;;
+    if (viewing_formatted_diff) {
+      src += &quot;&amp;action=prettypatch&quot;
+      buttonText = &quot;View Plain Diff&quot;;
+    }
+
+    document.getElementById('viewFrame').src = src;
+    document.getElementById('viewPrettyPatchButton').innerHTML = buttonText;
+}
+// endif WEBKIT_CHANGES
+
+function viewDiff(attachment_id, patchviewerinstalled)
+{
+    switchToMode('diff', patchviewerinstalled);
+
+    // If we have not viewed as diff before, set the view diff frame URL
+    if (!has_viewed_as_diff) {
+      var viewDiffFrame = document.getElementById('viewDiffFrame');
+      viewDiffFrame.src =
+          'attachment.cgi?id=' + attachment_id + '&amp;action=diff&amp;headers=0';
+      has_viewed_as_diff = 1;
+    }
+}
+
+function viewRaw(patchviewerinstalled)
+{
+    switchToMode('raw', patchviewerinstalled);
+}
+
+function switchToMode(mode, patchviewerinstalled)
+{
+    if (mode == current_mode) {
+      alert('switched to same mode!  This should not happen.');
+      return;
+    }
+
+    // Switch out of current mode
+    if (current_mode == 'edit') {
+      hideElementById('editFrame');
+      hideElementById('undoEditButton');
+    } else if (current_mode == 'raw') {
+      hideElementById('viewFrame');
+// if WEBKIT_CHANGES
+      hideElementById('viewPrettyPatchButton');
+// endif WEBKIT_CHANGES
+      if (patchviewerinstalled)
+          hideElementById('viewDiffButton');
+      hideElementById(has_edited ? 'redoEditButton' : 'editButton');
+      hideElementById('smallCommentFrame');
+    } else if (current_mode == 'diff') {
+      if (patchviewerinstalled)
+          hideElementById('viewDiffFrame');
+      hideElementById('viewRawButton');
+      hideElementById(has_edited ? 'redoEditButton' : 'editButton');
+      hideElementById('smallCommentFrame');
+    }
+
+    // Switch into new mode
+    if (mode == 'edit') {
+      showElementById('editFrame');
+      showElementById('undoEditButton');
+    } else if (mode == 'raw') {
+      showElementById('viewFrame');
+// if WEBKIT_CHANGES
+      showElementById('viewPrettyPatchButton');
+// endif WEBKIT_CHANGES
+      if (patchviewerinstalled) 
+          showElementById('viewDiffButton');
+
+      showElementById(has_edited ? 'redoEditButton' : 'editButton');
+      showElementById('smallCommentFrame');
+    } else if (mode == 'diff') {
+      if (patchviewerinstalled) 
+        showElementById('viewDiffFrame');
+
+      showElementById('viewRawButton');
+      showElementById(has_edited ? 'redoEditButton' : 'editButton');
+      showElementById('smallCommentFrame');
+    }
+
+    prev_mode = current_mode;
+    current_mode = mode;
+}
+
+function hideElementById(id)
+{
+  var elm = document.getElementById(id);
+  if (elm) {
+    YAHOO.util.Dom.addClass(elm, 'bz_default_hidden');
+  }
+}
+
+function showElementById(id)
+{
+  var elm = document.getElementById(id);
+  if (elm) {
+    YAHOO.util.Dom.removeClass(elm, 'bz_default_hidden');
+  }
+}
+
+function normalizeComments()
+{
+  // Remove the unused comment field from the document so its contents
+  // do not get transmitted back to the server.
+
+  var small = document.getElementById('smallCommentFrame');
+  var big = document.getElementById('editFrame');
+  if ( (small) &amp;&amp; YAHOO.util.Dom.hasClass(small, 'bz_default_hidden') )
+  {
+    small.parentNode.removeChild(small);
+  }
+  if ( (big) &amp;&amp; YAHOO.util.Dom.hasClass(big, 'bz_default_hidden') )
+  {
+    big.parentNode.removeChild(big);
+  }
+}
+
+function toggle_attachment_details_visibility ( ) 
+{
+    // show hide classes
+    var container = document.getElementById('attachment_info');
+    if( YAHOO.util.Dom.hasClass(container, 'read') ){
+        YAHOO.util.Dom.replaceClass(container, 'read', 'edit');
+    }else{
+        YAHOO.util.Dom.replaceClass(container, 'edit', 'read');
+    }
+}
+
+/* Used in bug/create.html.tmpl to show/hide the attachment field. */
+
+function handleWantsAttachment(wants_attachment) {
+    if (wants_attachment) {
+        hideElementById('attachment_false');
+        showElementById('attachment_true');
+    }
+    else {
+        showElementById('attachment_false');
+        hideElementById('attachment_true');
+        clearAttachmentFields();
+    }
+}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsbugjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/bug.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/bug.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/bug.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,131 @@
</span><ins>+/* The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the &quot;License&quot;); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an &quot;AS
+ * IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Bugzilla Bug Tracking System.
+ *
+ * The Initial Developer of the Original Code is Everything Solved, Inc.
+ * Portions created by Everything Solved are Copyright (C) 2010 Everything
+ * Solved, Inc. All Rights Reserved.
+ *
+ * Contributor(s): Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+ */
+
+/* This library assumes that the needed YUI libraries have been loaded 
+   already. */
+
+YAHOO.bugzilla.dupTable = {
+    counter: 0,
+    dataSource: null,
+    updateTable: function(dataTable, product_name, summary_field) {
+        if (summary_field.value.length &lt; 4) return;
+
+        YAHOO.bugzilla.dupTable.counter = YAHOO.bugzilla.dupTable.counter + 1;
+        YAHOO.util.Connect.setDefaultPostHeader('application/json', true);
+        var json_object = {
+            version : &quot;1.1&quot;,
+            method : &quot;Bug.possible_duplicates&quot;,
+            id : YAHOO.bugzilla.dupTable.counter,
+            params : {
+                product : product_name,
+                summary : summary_field.value,
+                limit : 7,
+                include_fields : [ &quot;id&quot;, &quot;summary&quot;, &quot;status&quot;, &quot;resolution&quot;,
+                                   &quot;update_token&quot; ]
+            }
+        };
+        var post_data = YAHOO.lang.JSON.stringify(json_object);
+
+        var callback = {
+            success: dataTable.onDataReturnInitializeTable,
+            failure: dataTable.onDataReturnInitializeTable,
+            scope:   dataTable,
+            argument: dataTable.getState() 
+        };
+        dataTable.showTableMessage(dataTable.get(&quot;MSG_LOADING&quot;),
+                                   YAHOO.widget.DataTable.CLASS_LOADING);
+        YAHOO.util.Dom.removeClass('possible_duplicates_container',
+                                   'bz_default_hidden');
+        dataTable.getDataSource().sendRequest(post_data, callback);
+    },
+    // This is the keyup event handler. It calls updateTable with a relatively
+    // long delay, to allow additional input. However, the delay is short
+    // enough that nobody could get from the summary field to the Submit
+    // Bug button before the table is shown (which is important, because
+    // the showing of the table causes the Submit Bug button to move, and
+    // if the table shows at the exact same time as the button is clicked,
+    // the click on the button won't register.)
+    doUpdateTable: function(e, args) {
+        var dt = args[0];
+        var product_name = args[1];
+        var summary = YAHOO.util.Event.getTarget(e);
+        clearTimeout(YAHOO.bugzilla.dupTable.lastTimeout);
+        YAHOO.bugzilla.dupTable.lastTimeout = setTimeout(function() {
+            YAHOO.bugzilla.dupTable.updateTable(dt, product_name, summary) },
+            600);
+    },
+    formatBugLink: function(el, oRecord, oColumn, oData) {
+        el.innerHTML = '&lt;a href=&quot;show_bug.cgi?id=' + oData + '&quot;&gt;' 
+                       + oData + '&lt;/a&gt;';
+    },
+    formatStatus: function(el, oRecord, oColumn, oData) {
+        var resolution = oRecord.getData('resolution');
+        var bug_status = display_value('bug_status', oData);
+        if (resolution) {
+            el.innerHTML = bug_status + ' ' 
+                           + display_value('resolution', resolution);
+        }
+        else {
+            el.innerHTML = bug_status;
+        }
+    },
+    formatCcButton: function(el, oRecord, oColumn, oData) {
+        var url = 'process_bug.cgi?id=' + oRecord.getData('id') 
+                  + '&amp;addselfcc=1&amp;token=' + escape(oData);
+        var button = document.createElement('a');
+        button.setAttribute('href',  url);
+        button.innerHTML = YAHOO.bugzilla.dupTable.addCcMessage;
+        el.appendChild(button);
+        new YAHOO.widget.Button(button);
+    },
+    init_ds: function() {
+        var new_ds = new YAHOO.util.XHRDataSource(&quot;jsonrpc.cgi&quot;);
+        new_ds.connTimeout = 30000;
+        new_ds.connMethodPost = true;
+        new_ds.connXhrMode = &quot;cancelStaleRequests&quot;;
+        new_ds.maxCacheEntries = 3;
+        new_ds.responseSchema = {
+            resultsList : &quot;result.bugs&quot;,
+            metaFields : { error: &quot;error&quot;, jsonRpcId: &quot;id&quot; }
+        };
+        // DataSource can't understand a JSON-RPC error response, so
+        // we have to modify the result data if we get one.
+        new_ds.doBeforeParseData = 
+            function(oRequest, oFullResponse, oCallback) {
+                if (oFullResponse.error) {
+                    oFullResponse.result = {};
+                    oFullResponse.result.bugs = [];
+                    if (console) {
+                        console.log(&quot;JSON-RPC error:&quot;, oFullResponse.error);
+                    }
+                }
+                return oFullResponse;
+        }
+
+        this.dataSource = new_ds;
+    },
+    init: function(data) {
+        if (this.dataSource == null) this.init_ds();
+        data.options.initialLoad = false;
+        var dt = new YAHOO.widget.DataTable(data.container, data.columns, 
+            this.dataSource, data.options); 
+        YAHOO.util.Event.on(data.summary_field, 'keyup', this.doUpdateTable,
+                            [dt, data.product_name]);
+    }
+};
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjschangecolumnsjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/change-columns.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/change-columns.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/change-columns.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,142 @@
</span><ins>+/*# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Pascal Held.
+  #
+  # Contributor(s): Pascal Held &lt;paheld@gmail.com&gt;
+  #
+*/
+
+function initChangeColumns() {
+    window.onunload = unload;
+    var av_select = document.getElementById(&quot;available_columns&quot;);
+    var sel_select = document.getElementById(&quot;selected_columns&quot;);
+    YAHOO.util.Dom.removeClass(
+        ['avail_header', av_select, 'select_button', 
+         'deselect_button', 'up_button', 'down_button'], 'bz_default_hidden');
+    switch_options(sel_select, av_select, false);
+    sel_select.selectedIndex = -1;
+    updateView();
+}
+
+function switch_options(from_box, to_box, selected) {
+    for (var i = 0; i&lt;from_box.options.length; i++) {
+        var opt = from_box.options[i];
+        if (opt.selected == selected) {
+            var newopt = new Option(opt.text, opt.value, opt.defaultselected, opt.selected);
+            to_box.options[to_box.options.length] = newopt;
+            from_box.options[i] = null;
+            i = i - 1;
+        }
+        
+    }
+}
+
+function move_select() {
+    var av_select = document.getElementById(&quot;available_columns&quot;);
+    var sel_select = document.getElementById(&quot;selected_columns&quot;);
+    switch_options(av_select, sel_select, true);
+    updateView();
+}
+
+function move_deselect() {
+    var av_select = document.getElementById(&quot;available_columns&quot;);
+    var sel_select = document.getElementById(&quot;selected_columns&quot;);
+    switch_options(sel_select, av_select, true);
+    updateView();
+}
+
+function move_up() {
+    var sel_select = document.getElementById(&quot;selected_columns&quot;);
+    var last = sel_select.options[0];
+    var dummy = new Option(&quot;&quot;, &quot;&quot;, false, false);
+    for (var i = 1; i&lt;sel_select.options.length; i++) {
+        var opt = sel_select.options[i];
+        if (opt.selected) {
+            sel_select.options[i] = dummy;
+            sel_select.options[i-1] = opt;
+            sel_select.options[i] = last;
+        }
+        else{
+            last = opt;
+        }        
+    }
+    updateView();
+}
+
+function move_down() {
+    var sel_select = document.getElementById(&quot;selected_columns&quot;);
+    var last = sel_select.options[sel_select.options.length-1];
+    var dummy = new Option(&quot;&quot;, &quot;&quot;, false, false);
+    for (var i = sel_select.options.length-2; i &gt;= 0; i--) {
+        var opt = sel_select.options[i];
+        if (opt.selected) {
+            sel_select.options[i] = dummy;
+            sel_select.options[i + 1] = opt;
+            sel_select.options[i] = last;
+        }
+        else{
+            last = opt;
+        }        
+    }
+    updateView();
+}
+
+function updateView() {
+    var select_button = document.getElementById(&quot;select_button&quot;);
+    var deselect_button = document.getElementById(&quot;deselect_button&quot;);
+    var up_button = document.getElementById(&quot;up_button&quot;);
+    var down_button = document.getElementById(&quot;down_button&quot;);
+    select_button.disabled = true;
+    deselect_button.disabled = true;
+    up_button.disabled = true;
+    down_button.disabled = true;
+    var av_select = document.getElementById(&quot;available_columns&quot;);
+    var sel_select = document.getElementById(&quot;selected_columns&quot;);
+    for (var i = 0; i &lt; av_select.options.length;  i++) {
+        if (av_select.options[i].selected) {
+            select_button.disabled = false;
+            break;
+        }
+    }
+    for (var i = 0; i &lt; sel_select.options.length; i++) {
+        if (sel_select.options[i].selected) {
+            deselect_button.disabled = false;
+            up_button.disabled = false;
+            down_button.disabled = false;
+            break;
+        }
+    }
+    if (sel_select.options.length &gt; 0) {
+        if (sel_select.options[0].selected) {
+            up_button.disabled = true;
+        }
+        if (sel_select.options[sel_select.options.length - 1].selected) {
+            down_button.disabled = true;
+        }
+    }
+}
+
+function change_submit() {
+    var sel_select = document.getElementById(&quot;selected_columns&quot;);
+    for (var i = 0; i &lt; sel_select.options.length; i++) {
+        sel_select.options[i].selected = true;
+    }
+    return false;
+}
+
+function unload() {
+    var sel_select = document.getElementById(&quot;selected_columns&quot;);
+    for (var i = 0; i &lt; sel_select.options.length; i++) {
+        sel_select.options[i].selected = true;
+    }
+}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjscommentsjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/comments.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/comments.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/comments.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,145 @@
</span><ins>+/* The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the &quot;License&quot;); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an &quot;AS
+ * IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Bugzilla Bug Tracking System.
+ *
+ * The Initial Developer of the Original Code is Netscape Communications
+ * Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All
+ * Rights Reserved.
+ *
+ * Contributor(s): Frédéric Buclin &lt;LpSolit@gmail.com&gt;
+ *                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+ *                 Edmund Wong &lt;ewong@pw-wspx.org&gt;
+ *                 Anthony Pipkin &lt;a.pipkin@yahoo.com&gt;
+ */
+
+function updateCommentPrivacy(checkbox, id) {
+    var comment_elem = document.getElementById('comment_text_'+id).parentNode;
+    if (checkbox.checked) {
+      if (!comment_elem.className.match('bz_private')) {
+        comment_elem.className = comment_elem.className.concat(' bz_private');
+      }
+    }
+    else {
+      comment_elem.className =
+        comment_elem.className.replace(/(\s*|^)bz_private(\s*|$)/, '$2');
+    }
+}
+
+/* The functions below expand and collapse comments  */
+
+function toggle_comment_display(link, comment_id) {
+    var comment = document.getElementById('comment_text_' + comment_id);
+    var re = new RegExp(/\bcollapsed\b/);
+    if (comment.className.match(re))
+        expand_comment(link, comment);
+    else
+        collapse_comment(link, comment);
+}
+
+function toggle_all_comments(action) {
+    // If for some given ID the comment doesn't exist, this doesn't mean
+    // there are no more comments, but that the comment is private and
+    // the user is not allowed to view it.
+
+    var comments = YAHOO.util.Dom.getElementsByClassName('bz_comment_text');
+    for (var i = 0; i &lt; comments.length; i++) {
+        var comment = comments[i];
+        if (!comment)
+            continue;
+
+        var id = comments[i].id.match(/\d*$/);
+        var link = document.getElementById('comment_link_' + id);
+        if (action == 'collapse')
+            collapse_comment(link, comment);
+        else
+            expand_comment(link, comment);
+    }
+}
+
+function collapse_comment(link, comment) {
+    link.innerHTML = &quot;[+]&quot;;
+    YAHOO.util.Dom.addClass(comment, 'collapsed');
+}
+
+function expand_comment(link, comment) {
+    link.innerHTML = &quot;[-]&quot;;
+    YAHOO.util.Dom.removeClass(comment, 'collapsed');
+}
+
+function wrapReplyText(text) {
+    // This is -3 to account for &quot;\n&gt; &quot;
+    var maxCol = BUGZILLA.constant.COMMENT_COLS - 3;
+    var text_lines = text.replace(/[\s\n]+$/, '').split(&quot;\n&quot;);
+    var wrapped_lines = new Array();
+
+    for (var i = 0; i &lt; text_lines.length; i++) {
+        var paragraph = text_lines[i];
+        // Don't wrap already-quoted text.
+        if (paragraph.indexOf('&gt;') == 0) {
+            wrapped_lines.push('&gt; ' + paragraph);
+            continue;
+        }
+
+        var replace_lines = new Array();
+        while (paragraph.length &gt; maxCol) {
+            var testLine = paragraph.substring(0, maxCol);
+            var pos = testLine.search(/\s\S*$/);
+
+            if (pos &lt; 1) {
+                // Try to find some ASCII punctuation that's reasonable
+                // to break on.
+                var punct = '\\-\\./,!;:';
+                var punctRe = new RegExp('[' + punct + '][^' + punct + ']+$');
+                pos = testLine.search(punctRe) + 1;
+                // Try to find some CJK Punctuation that's reasonable
+                // to break on.
+                if (pos == 0)
+                    pos = testLine.search(/[\u3000\u3001\u3002\u303E\u303F]/) + 1;
+                // If we can't find any break point, we simply break long
+                // words. This makes long, punctuation-less CJK text wrap,
+                // even if it wraps incorrectly.
+                if (pos == 0) pos = maxCol;
+            }
+
+            var wrapped_line = paragraph.substring(0, pos);
+            replace_lines.push(wrapped_line);
+            paragraph = paragraph.substring(pos);
+            // Strip whitespace from the start of the line
+            paragraph = paragraph.replace(/^\s+/, '');
+        }
+        replace_lines.push(paragraph);
+        wrapped_lines.push(&quot;&gt; &quot; + replace_lines.join(&quot;\n&gt; &quot;));
+    }
+    return wrapped_lines.join(&quot;\n&quot;) + &quot;\n\n&quot;;
+}
+
+/* This way, we are sure that browsers which do not support JS
+   * won't display this link  */
+
+function addCollapseLink(count, title) {
+    document.write(' &lt;a href=&quot;#&quot; class=&quot;bz_collapse_comment&quot;' +
+                   ' id=&quot;comment_link_' + count +
+                   '&quot; onclick=&quot;toggle_comment_display(this, ' +  count +
+                   '); return false;&quot; title=&quot;' + title + '&quot;&gt;[-]&lt;\/a&gt; ');
+}
+
+function goto_add_comments( anchor ){
+    anchor =  (anchor || &quot;add_comment&quot;);
+    // we need this line to expand the comment box
+    document.getElementById('comment').focus();
+    setTimeout(function(){ 
+        document.location.hash = anchor;
+        // firefox doesn't seem to keep focus through the anchor change
+        document.getElementById('comment').focus();
+    },10);
+    return false;
+}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjscustomsearchjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/custom-search.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/custom-search.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/custom-search.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,208 @@
</span><ins>+/* The contents of this file are subject to the Mozilla Public
+ * License Version 1.1 (the &quot;License&quot;); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an &quot;AS
+ * IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * rights and limitations under the License.
+ *
+ * The Original Code is the Bugzilla Bug Tracking System.
+ *
+ * The Initial Developer of the Original Code is BugzillaSource, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2011 
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s): 
+ *   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+ */
+
+var PAREN_INDENT_EM = 2;
+var ANY_ALL_SELECT_CLASS = 'any_all_select';
+
+// When somebody chooses to &quot;Hide Advanced Features&quot; for Custom Search,
+// we don't want to hide &quot;Not&quot; checkboxes if they've been checked. We
+// accomplish this by removing the custom_search_advanced class from Not
+// checkboxes when they are checked.
+//
+// We never add the custom_search_advanced class back. If we did, TUI
+// would get confused in this case: Check Not, Hide Advanced Features,
+// Uncheck Not, Show Advanced Features. (It hides &quot;Not&quot; when it shouldn't.)
+function custom_search_not_changed(id) {
+    var container = document.getElementById('custom_search_not_container_' + id);
+    YAHOO.util.Dom.removeClass(container, 'custom_search_advanced');
+
+    fix_query_string(container);
+}
+
+function custom_search_new_row() {
+    var row = document.getElementById('custom_search_last_row');
+    var clone = row.cloneNode(true);
+    
+    _cs_fix_ids(clone);
+   
+    // We only want one copy of the buttons, in the new row. So the old
+    // ones get deleted.
+    var op_button = document.getElementById('op_button');
+    row.removeChild(op_button);
+    var cp_button = document.getElementById('cp_container');
+    row.removeChild(cp_button);
+    var add_button = document.getElementById('add_button');
+    row.removeChild(add_button);
+    _remove_any_all(clone);
+
+    // Always make sure there's only one row with this id.
+    row.id = null;
+    row.parentNode.appendChild(clone);
+    fix_query_string(row);
+    return clone;
+}
+
+function custom_search_open_paren() {
+    var row = document.getElementById('custom_search_last_row');
+
+    // If there's an &quot;Any/All&quot; select in this row, it needs to stay as
+    // part of the parent paren set.
+    var old_any_all = _remove_any_all(row);
+    if (old_any_all) {
+        var any_all_row = row.cloneNode(false);
+        any_all_row.id = null;
+        any_all_row.appendChild(old_any_all);
+        row.parentNode.insertBefore(any_all_row, row);
+    }
+
+    // We also need a &quot;Not&quot; checkbox to stay in the parent paren set.
+    var new_not = YAHOO.util.Dom.getElementsByClassName(
+        'custom_search_not_container', null, row);
+    var not_for_paren = new_not[0].cloneNode(true);
+
+    // Preserve the values when modifying the row.
+    var id = _cs_fix_ids(row, true);
+    var prev_id = id - 1;
+
+    var paren_row = row.cloneNode(false);
+    paren_row.id = null;
+    paren_row.innerHTML = '(&lt;input type=&quot;hidden&quot; name=&quot;f' + prev_id
+                        + '&quot; value=&quot;OP&quot;&gt;';
+    paren_row.insertBefore(not_for_paren, paren_row.firstChild);
+    row.parentNode.insertBefore(paren_row, row);
+    
+    // New paren set needs a new &quot;Any/All&quot; select.
+    var any_all_container = document.createElement('div');
+    YAHOO.util.Dom.addClass(any_all_container, ANY_ALL_SELECT_CLASS);
+    var j_top = document.getElementById('j_top');
+    var any_all = j_top.cloneNode(true);
+    any_all.name = 'j' + prev_id;
+    any_all.id = any_all.name;
+    any_all_container.appendChild(any_all);
+    row.insertBefore(any_all_container, row.firstChild);
+
+    var margin = YAHOO.util.Dom.getStyle(row, 'margin-left');
+    var int_match = margin.match(/\d+/);
+    var new_margin = parseInt(int_match[0]) + PAREN_INDENT_EM;
+    YAHOO.util.Dom.setStyle(row, 'margin-left', new_margin + 'em');
+    YAHOO.util.Dom.removeClass('cp_container', 'bz_default_hidden');
+
+    fix_query_string(any_all_container);
+}
+
+function custom_search_close_paren() {
+    var new_row = custom_search_new_row();
+    
+    // We need to up the new row's id by one more, because we're going
+    // to insert a &quot;CP&quot; before it.
+    var id = _cs_fix_ids(new_row);
+
+    var margin = YAHOO.util.Dom.getStyle(new_row, 'margin-left');
+    var int_match = margin.match(/\d+/);
+    var new_margin = parseInt(int_match[0]) - PAREN_INDENT_EM;
+    YAHOO.util.Dom.setStyle(new_row, 'margin-left', new_margin + 'em');
+
+    var paren_row = new_row.cloneNode(false);
+    paren_row.id = null;
+    paren_row.innerHTML = ')&lt;input type=&quot;hidden&quot; name=&quot;f' + (id - 1)
+                        + '&quot; value=&quot;CP&quot;&gt;';
+  
+    new_row.parentNode.insertBefore(paren_row, new_row);
+
+    if (new_margin == 0) {
+        YAHOO.util.Dom.addClass('cp_container', 'bz_default_hidden');
+    }
+
+    fix_query_string(new_row);
+}
+
+// When a user goes Back in their browser after searching, some browsers
+// (Chrome, as of September 2011) do not remember the DOM that was created
+// by the Custom Search JS. (In other words, their whole entered Custom
+// Search disappears.) The solution is to update the History object,
+// using the query string, which query.cgi can read to re-create the page
+// exactly as the user had it before.
+function fix_query_string(form_member) {
+    // window.History comes from history.js.
+    // It falls back to the normal window.history object for HTML5 browsers.
+    if (!(window.History &amp;&amp; window.History.replaceState))
+        return;
+
+    var form = YAHOO.util.Dom.getAncestorByTagName(form_member, 'form');
+    var query = YAHOO.util.Connect.setForm(form);
+    window.History.replaceState(null, document.title, '?' + query);
+}
+
+// Browsers that do not support HTML5's history.replaceState gain an emulated
+// version via history.js, with the full query_string in the location's hash.
+// We rewrite the URL to include the hash and redirect to the new location,
+// which causes custom search fields to work.
+function redirect_html4_browsers() {
+    var hash = document.location.hash;
+    if (hash == '') return;
+    hash = hash.substring(1);
+    if (hash.substring(0, 10) != 'query.cgi?') return;
+    var url = document.location + &quot;&quot;;
+    url = url.substring(0, url.indexOf('query.cgi#')) + hash;
+    document.location = url;
+}
+
+function _cs_fix_ids(parent, preserve_values) {
+    // Update the label of the checkbox.
+    var label = YAHOO.util.Dom.getElementBy(function() { return true },
+                                            'label', parent);
+    var id_match = label.htmlFor.match(/\d+$/);
+    var id = parseInt(id_match[0]) + 1;
+    label.htmlFor = label.htmlFor.replace(/\d+$/, id);
+
+    // Sets all the inputs in the parent back to their default
+    // and fixes their id.
+    var fields =
+        YAHOO.util.Dom.getElementsByClassName('custom_search_form_field', null,
+                                              parent);
+    for (var i = 0; i &lt; fields.length; i++) {
+        var field = fields[i];
+
+        if (!preserve_values) {
+            if (field.type == &quot;checkbox&quot;) {
+                field.checked = false;
+            }
+            else {
+                field.value = '';
+            }
+        }
+        
+        // Update the numeric id for the new row.
+        field.name = field.name.replace(/\d+$/, id);
+        field.id = field.name;
+    }
+    
+    return id;
+}
+
+function _remove_any_all(parent) {
+    var any_all = YAHOO.util.Dom.getElementsByClassName(
+        ANY_ALL_SELECT_CLASS, null, parent);
+    if (any_all[0]) {
+        parent.removeChild(any_all[0]);
+        return any_all[0];
+    }
+    return null;
+}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsfieldjs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/js/field.js (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/field.js        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/js/field.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -16,11 +16,86 @@
</span><span class="cx">  *
</span><span class="cx">  * Contributor(s): Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
</span><span class="cx">  *                 Guy Pyrzak &lt;guy.pyrzak@gmail.com&gt;
</span><ins>+ *                 Reed Loden &lt;reed@reedloden.com&gt;
</ins><span class="cx">  */
</span><span class="cx"> 
</span><span class="cx"> /* This library assumes that the needed YUI libraries have been loaded 
</span><span class="cx">    already. */
</span><span class="cx"> 
</span><ins>+var bz_no_validate_enter_bug = false;
+function validateEnterBug(theform) {
+    // This is for the &quot;bookmarkable templates&quot; button.
+    if (bz_no_validate_enter_bug) {
+        // Set it back to false for people who hit the &quot;back&quot; button
+        bz_no_validate_enter_bug = false;
+        return true;
+    }
+
+    var component = theform.component;
+    var short_desc = theform.short_desc;
+    var version = theform.version;
+    var bug_status = theform.bug_status;
+    var description = theform.comment;
+    var attach_data = theform.data;
+    var attach_desc = theform.description;
+
+    var current_errors = YAHOO.util.Dom.getElementsByClassName(
+        'validation_error_text', null, theform);
+    for (var i = 0; i &lt; current_errors.length; i++) {
+        current_errors[i].parentNode.removeChild(current_errors[i]);
+    }
+    var current_error_fields = YAHOO.util.Dom.getElementsByClassName(
+        'validation_error_field', null, theform);
+    for (var i = 0; i &lt; current_error_fields.length; i++) {
+        var field = current_error_fields[i];
+        YAHOO.util.Dom.removeClass(field, 'validation_error_field');
+    }
+
+    var focus_me;
+
+    // These are checked in the reverse order that they appear on the page,
+    // so that the one closest to the top of the form will be focused.
+    if (attach_data.value &amp;&amp; YAHOO.lang.trim(attach_desc.value) == '') {
+        _errorFor(attach_desc, 'attach_desc');
+        focus_me = attach_desc;
+    }
+    var check_description = status_comment_required[bug_status.value];
+    if (check_description &amp;&amp; YAHOO.lang.trim(description.value) == '') {
+        _errorFor(description, 'description');
+        focus_me = description;
+    }
+    if (YAHOO.lang.trim(short_desc.value) == '') {
+        _errorFor(short_desc);
+        focus_me = short_desc;
+    }
+    if (version.selectedIndex &lt; 0) {
+        _errorFor(version);
+        focus_me = version;
+    }
+    if (component.selectedIndex &lt; 0) {
+        _errorFor(component);
+        focus_me = component;
+    }
+
+    if (focus_me) {
+        focus_me.focus();
+        return false;
+    }
+
+    return true;
+}
+
+function _errorFor(field, name) {
+    if (!name) name = field.id;
+    var string_name = name + '_required';
+    var error_text = BUGZILLA.string[string_name];
+    var new_node = document.createElement('div');
+    YAHOO.util.Dom.addClass(new_node, 'validation_error_text');
+    new_node.innerHTML = error_text;
+    YAHOO.util.Dom.insertAfter(new_node, field);
+    YAHOO.util.Dom.addClass(field, 'validation_error_field');
+}
+
</ins><span class="cx"> function createCalendar(name) {
</span><span class="cx">     var cal = new YAHOO.widget.Calendar('calendar_' + name, 
</span><span class="cx">                                         'con_calendar_' + name);
</span><span class="lines">@@ -136,32 +211,34 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+function setupEditLink(id) {
+    var link_container = 'container_showhide_' + id;
+    var input_container = 'container_' + id;
+    var link = 'showhide_' + id;
+    hideEditableField(link_container, input_container, link);
+}
</ins><span class="cx"> 
</span><del>-/* Hide input fields and show the text with (edit) next to it */  
-function hideEditableField( container, input, action, field1_id, field2_id, original_value ) {
-    YAHOO.util.Dom.setStyle(container, 'display', 'inline');
-    YAHOO.util.Dom.setStyle(input, 'display', 'none');
</del><ins>+/* Hide input/select fields and show the text with (edit) next to it */
+function hideEditableField( container, input, action, field_id, original_value, new_value ) {
+    YAHOO.util.Dom.removeClass(container, 'bz_default_hidden');
+    YAHOO.util.Dom.addClass(input, 'bz_default_hidden');
</ins><span class="cx">     YAHOO.util.Event.addListener(action, 'click', showEditableField,
</span><del>-                                 new Array(container, input, field2_id));
-    YAHOO.util.Event.addListener(field1_id + '_nonedit_display', 'click', showEditableField,
-                                 new Array(container, input, field1_id));
-    YAHOO.util.Event.addListener(field2_id + '_nonedit_display', 'click', showEditableField,
-                                 new Array(container, input, field2_id));
-    if(field2_id != &quot;&quot;){
</del><ins>+                                 new Array(container, input, field_id, new_value));
+    if(field_id != &quot;&quot;){
</ins><span class="cx">         YAHOO.util.Event.addListener(window, 'load', checkForChangedFieldValues,
</span><del>-                        new Array(container, input, field2_id, original_value));
</del><ins>+                        new Array(container, input, field_id, original_value));
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> /* showEditableField (e, ContainerInputArray)
</span><del>- * Function hides the (edit) link and the text and displays the input
</del><ins>+ * Function hides the (edit) link and the text and displays the input/select field
</ins><span class="cx">  *
</span><span class="cx">  * var e: the event
</span><span class="cx">  * var ContainerInputArray: An array containing the (edit) and text area and the input being displayed
</span><del>- * var ContainerInputArray[0]: the conainer that will be hidden usually shows the (edit) text
</del><ins>+ * var ContainerInputArray[0]: the container that will be hidden usually shows the (edit) or (take) text
</ins><span class="cx">  * var ContainerInputArray[1]: the input area and label that will be displayed
</span><del>- * var ContainerInputArray[2]: [optional] the id of the input element to focus
- *
</del><ins>+ * var ContainerInputArray[2]: the input/select field id for which the new value must be set
+ * var ContainerInputArray[3]: the new value to set the input/select field to when (take) is clicked
</ins><span class="cx">  */
</span><span class="cx"> function showEditableField (e, ContainerInputArray) {
</span><span class="cx">     var inputs = new Array();
</span><span class="lines">@@ -170,22 +247,34 @@
</span><span class="cx">         YAHOO.util.Event.preventDefault(e);
</span><span class="cx">         return;
</span><span class="cx">     }
</span><del>-    YAHOO.util.Dom.setStyle(ContainerInputArray[0], 'display', 'none');
-    YAHOO.util.Dom.setStyle(inputArea, 'display', 'inline');
</del><ins>+    YAHOO.util.Dom.addClass(ContainerInputArray[0], 'bz_default_hidden');
+    YAHOO.util.Dom.removeClass(inputArea, 'bz_default_hidden');
</ins><span class="cx">     if ( inputArea.tagName.toLowerCase() == &quot;input&quot; ) {
</span><span class="cx">         inputs.push(inputArea);
</span><ins>+    } else if (ContainerInputArray[2]) {
+        inputs.push(document.getElementById(ContainerInputArray[2]));
</ins><span class="cx">     } else {
</span><span class="cx">         inputs = inputArea.getElementsByTagName('input');
</span><span class="cx">     }
</span><span class="cx">     if ( inputs.length &gt; 0 ) {
</span><del>-        var elementToFocus = YAHOO.util.Dom.get(ContainerInputArray[2]);
-        if (elementToFocus) {
-            // focus on the requested field
-            elementToFocus.focus();
-            elementToFocus.select();
-        } else {
-            // focus on the first field, this makes it easier to edit
-            inputs[0].focus();
</del><ins>+        // Change the first field's value to ContainerInputArray[2]
+        // if present before focusing.
+        var type = inputs[0].tagName.toLowerCase();
+        if (ContainerInputArray[3]) {
+            if ( type == &quot;input&quot; ) {
+                inputs[0].value = ContainerInputArray[3];
+            } else {
+                for (var i = 0; inputs[0].length; i++) {
+                    if ( inputs[0].options[i].value == ContainerInputArray[3] ) {
+                        inputs[0].options[i].selected = true;
+                        break;
+                    }
+                }
+            }
+        }
+        // focus on the first field, this makes it easier to edit
+        inputs[0].focus();
+        if ( type == &quot;input&quot; ) {
</ins><span class="cx">             inputs[0].select();
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -224,8 +313,8 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     if(unhide){
</span><del>-        YAHOO.util.Dom.setStyle(ContainerInputArray[0], 'display', 'none');
-        YAHOO.util.Dom.setStyle(ContainerInputArray[1], 'display', 'inline');
</del><ins>+        YAHOO.util.Dom.addClass(ContainerInputArray[0], 'bz_default_hidden');
+        YAHOO.util.Dom.removeClass(ContainerInputArray[1], 'bz_default_hidden');
</ins><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx"> }
</span><span class="lines">@@ -233,7 +322,7 @@
</span><span class="cx"> function hideAliasAndSummary(short_desc_value, alias_value) {
</span><span class="cx">     // check the short desc field
</span><span class="cx">     hideEditableField( 'summary_alias_container','summary_alias_input',
</span><del>-                       'editme_action', 'alias', 'short_desc', short_desc_value);
</del><ins>+                       'editme_action','short_desc', short_desc_value);  
</ins><span class="cx">     // check that the alias hasn't changed
</span><span class="cx">     var bz_alias_check_array = new Array('summary_alias_container',
</span><span class="cx">                                      'summary_alias_input', 'alias', alias_value);
</span><span class="lines">@@ -279,20 +368,41 @@
</span><span class="cx">     // finish doing stuff based on the selection.
</span><span class="cx">     if ( el ) {
</span><span class="cx">         showDuplicateItem(el);
</span><del>-        YAHOO.util.Dom.setStyle('resolution_settings', 'display', 'none');
</del><ins>+
+        // Make sure that fields whose visibility or values are controlled
+        // by &quot;resolution&quot; behave properly when resolution is hidden.
+        var resolution = document.getElementById('resolution');
+        if (resolution &amp;&amp; resolution.options[0].value != '') {
+            resolution.bz_lastSelected = resolution.selectedIndex;
+            var emptyOption = new Option('', '');
+            resolution.insertBefore(emptyOption, resolution.options[0]);
+            emptyOption.selected = true;
+        }
+        YAHOO.util.Dom.addClass('resolution_settings', 'bz_default_hidden');
</ins><span class="cx">         if (document.getElementById('resolution_settings_warning')) {
</span><del>-            YAHOO.util.Dom.setStyle('resolution_settings_warning', 'display', 'none');
</del><ins>+            YAHOO.util.Dom.addClass('resolution_settings_warning',
+                                    'bz_default_hidden');
</ins><span class="cx">         }
</span><del>-        YAHOO.util.Dom.setStyle('duplicate_display', 'display', 'none');
</del><ins>+        YAHOO.util.Dom.addClass('duplicate_display', 'bz_default_hidden');
</ins><span class="cx"> 
</span><del>-        if ( el.value == dupArrayInfo[1] &amp;&amp; dupArrayInfo[0] == &quot;is_duplicate&quot; ) {
-            YAHOO.util.Dom.setStyle('resolution_settings', 'display', 'inline');
-            YAHOO.util.Dom.setStyle('resolution_settings_warning', 'display', 'block');  
</del><ins>+
+        if ( (el.value == dupArrayInfo[1] &amp;&amp; dupArrayInfo[0] == &quot;is_duplicate&quot;)
+             || bz_isValueInArray(close_status_array, el.value) ) 
+        {
+            YAHOO.util.Dom.removeClass('resolution_settings', 
+                                       'bz_default_hidden');
+            YAHOO.util.Dom.removeClass('resolution_settings_warning', 
+                                       'bz_default_hidden');
+
+            // Remove the blank option we inserted.
+            if (resolution &amp;&amp; resolution.options[0].value == '') {
+                resolution.removeChild(resolution.options[0]);
+                resolution.selectedIndex = resolution.bz_lastSelected;
+            }
</ins><span class="cx">         }
</span><del>-        else if ( bz_isValueInArray(close_status_array, el.value) ) {
-            // hide duplicate and show resolution
-            YAHOO.util.Dom.setStyle('resolution_settings', 'display', 'inline');
-            YAHOO.util.Dom.setStyle('resolution_settings_warning', 'display', 'block');
</del><ins>+
+        if (resolution) {
+            bz_fireEvent(resolution, 'change');
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="lines">@@ -304,14 +414,19 @@
</span><span class="cx">     if (resolution) {
</span><span class="cx">         if (resolution.value == 'DUPLICATE' &amp;&amp; bz_isValueInArray( close_status_array, bug_status.value) ) {
</span><span class="cx">             // hide resolution show duplicate
</span><del>-            YAHOO.util.Dom.setStyle('duplicate_settings', 'display', 'inline');
-            YAHOO.util.Dom.setStyle('dup_id_discoverable', 'display', 'none');
-            dup_id.focus();
-            dup_id.select();
</del><ins>+            YAHOO.util.Dom.removeClass('duplicate_settings', 
+                                       'bz_default_hidden');
+            YAHOO.util.Dom.addClass('dup_id_discoverable', 'bz_default_hidden');
+            // check to make sure the field is visible or IE throws errors
+            if( ! YAHOO.util.Dom.hasClass( dup_id, 'bz_default_hidden' ) ){
+                dup_id.focus();
+                dup_id.select();
+            }
</ins><span class="cx">         }
</span><span class="cx">         else {
</span><del>-            YAHOO.util.Dom.setStyle('duplicate_settings', 'display', 'none');
-            YAHOO.util.Dom.setStyle('dup_id_discoverable', 'display', 'block');
</del><ins>+            YAHOO.util.Dom.addClass('duplicate_settings', 'bz_default_hidden');
+            YAHOO.util.Dom.removeClass('dup_id_discoverable', 
+                                       'bz_default_hidden');
</ins><span class="cx">             dup_id.blur();
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -321,18 +436,11 @@
</span><span class="cx"> function setResolutionToDuplicate(e, duplicate_or_move_bug_status) {
</span><span class="cx">     var status = document.getElementById('bug_status');
</span><span class="cx">     var resolution = document.getElementById('resolution');
</span><del>-    YAHOO.util.Dom.setStyle('dup_id_discoverable', 'display', 'none');
</del><ins>+    YAHOO.util.Dom.addClass('dup_id_discoverable', 'bz_default_hidden');
</ins><span class="cx">     status.value = duplicate_or_move_bug_status;
</span><ins>+    bz_fireEvent(status, 'change');
</ins><span class="cx">     resolution.value = &quot;DUPLICATE&quot;;
</span><del>-    showHideStatusItems(&quot;&quot;, [&quot;&quot;,&quot;&quot;]);
-
-    // Show edit field for bug number, so that the user doesn't have to click on &quot;(edit)&quot;.
-    YAHOO.util.Dom.setStyle('dup_id', 'display', 'inline');
-    YAHOO.util.Dom.setStyle('dup_id_container', 'display', 'none');
-    var dup_id = document.getElementById('dup_id');
-    dup_id.focus();
-    dup_id.select();
-
</del><ins>+    bz_fireEvent(resolution, 'change');
</ins><span class="cx">     YAHOO.util.Event.preventDefault(e);
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -357,3 +465,326 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> }
</span><ins>+
+function updateCommentTagControl(checkbox, field) {
+    if (checkbox.checked) {
+        YAHOO.util.Dom.addClass(field, 'bz_private');
+    } else {
+        YAHOO.util.Dom.removeClass(field, 'bz_private');
+    }
+}
+
+/**
+ * Reset the value of the classification field and fire an event change
+ * on it.  Called when the product changes, in case the classification
+ * field (which is hidden) controls the visibility of any other fields.
+ */
+function setClassification() {
+    var classification = document.getElementById('classification');
+    var product = document.getElementById('product');
+    var selected_product = product.value; 
+    var select_classification = all_classifications[selected_product];
+    classification.value = select_classification;
+    bz_fireEvent(classification, 'change');
+}
+
+/**
+ * Says that a field should only be displayed when another field has
+ * a certain value. May only be called after the controller has already
+ * been added to the DOM.
+ */
+function showFieldWhen(controlled_id, controller_id, values) {
+    var controller = document.getElementById(controller_id);
+    // Note that we don't get an object for &quot;controlled&quot; here, because it
+    // might not yet exist in the DOM. We just pass along its id.
+    YAHOO.util.Event.addListener(controller, 'change',
+        handleVisControllerValueChange, [controlled_id, controller, values]);
+}
+
+/**
+ * Called by showFieldWhen when a field's visibility controller 
+ * changes values. 
+ */
+function handleVisControllerValueChange(e, args) {
+    var controlled_id = args[0];
+    var controller = args[1];
+    var values = args[2];
+
+    var label_container = 
+        document.getElementById('field_label_' + controlled_id);
+    var field_container =
+        document.getElementById('field_container_' + controlled_id);
+    var selected = false;
+    for (var i = 0; i &lt; values.length; i++) {
+        if (bz_valueSelected(controller, values[i])) {
+            selected = true;
+            break;
+        }
+    }
+
+    if (selected) {
+        YAHOO.util.Dom.removeClass(label_container, 'bz_hidden_field');
+        YAHOO.util.Dom.removeClass(field_container, 'bz_hidden_field');
+    }
+    else {
+        YAHOO.util.Dom.addClass(label_container, 'bz_hidden_field');
+        YAHOO.util.Dom.addClass(field_container, 'bz_hidden_field');
+    }
+}
+
+function showValueWhen(controlled_field_id, controlled_value_ids, 
+                       controller_field_id, controller_value_id)
+{
+    var controller_field = document.getElementById(controller_field_id);
+    // Note that we don't get an object for the controlled field here, 
+    // because it might not yet exist in the DOM. We just pass along its id.
+    YAHOO.util.Event.addListener(controller_field, 'change',
+        handleValControllerChange, [controlled_field_id, controlled_value_ids,
+                                    controller_field, controller_value_id]);
+}
+
+function handleValControllerChange(e, args) {
+    var controlled_field = document.getElementById(args[0]);
+    var controlled_value_ids = args[1];
+    var controller_field = args[2];
+    var controller_value_id = args[3];
+
+    var controller_item = document.getElementById(
+        _value_id(controller_field.id, controller_value_id));
+
+    for (var i = 0; i &lt; controlled_value_ids.length; i++) {
+        var item = getPossiblyHiddenOption(controlled_field,
+                                           controlled_value_ids[i]);
+        if (item.disabled &amp;&amp; controller_item &amp;&amp; controller_item.selected) {
+            item = showOptionInIE(item, controlled_field);
+            YAHOO.util.Dom.removeClass(item, 'bz_hidden_option');
+            item.disabled = false;
+        }
+        else if (!item.disabled &amp;&amp; controller_item &amp;&amp; !controller_item.selected) {
+            YAHOO.util.Dom.addClass(item, 'bz_hidden_option');
+            if (item.selected) {
+                item.selected = false;
+                bz_fireEvent(controlled_field, 'change');
+            }
+            item.disabled = true;
+            hideOptionInIE(item, controlled_field);
+        }
+    }
+}
+
+// A convenience function to generate the &quot;id&quot; tag of an &lt;option&gt;
+// based on the numeric id that Bugzilla uses for that value.
+function _value_id(field_name, id) {
+    return 'v' + id + '_' + field_name;
+}
+
+/*********************************/
+/* Code for Hiding Options in IE */
+/*********************************/
+
+/* IE 7 and below (and some other browsers) don't respond to &quot;display: none&quot;
+ * on &lt;option&gt; tags. However, you *can* insert a Comment Node as a
+ * child of a &lt;select&gt; tag. So we just insert a Comment where the &lt;option&gt;
+ * used to be. */
+var ie_hidden_options = new Array();
+function hideOptionInIE(anOption, aSelect) {
+    if (browserCanHideOptions(aSelect)) return;
+
+    var commentNode = document.createComment(anOption.value);
+    commentNode.id = anOption.id;
+    // This keeps the interface of Comments and Options the same for
+    // our other functions.
+    commentNode.disabled = true;
+    // replaceChild is very slow on IE in a &lt;select&gt; that has a lot of
+    // options, so we use replaceNode when we can.
+    if (anOption.replaceNode) {
+        anOption.replaceNode(commentNode);
+    }
+    else {
+        aSelect.replaceChild(commentNode, anOption);
+    }
+
+    // Store the comment node for quick access for getPossiblyHiddenOption
+    if (!ie_hidden_options[aSelect.id]) {
+        ie_hidden_options[aSelect.id] = new Array();
+    }
+    ie_hidden_options[aSelect.id][anOption.id] = commentNode;
+}
+
+function showOptionInIE(aNode, aSelect) {
+    if (browserCanHideOptions(aSelect)) return aNode;
+
+    // We do this crazy thing with innerHTML and createElement because
+    // this is the ONLY WAY that this works properly in IE.
+    var optionNode = document.createElement('option');
+    optionNode.innerHTML = aNode.data;
+    optionNode.value = aNode.data;
+    optionNode.id = aNode.id;
+    // replaceChild is very slow on IE in a &lt;select&gt; that has a lot of
+    // options, so we use replaceNode when we can.
+    if (aNode.replaceNode) {
+        aNode.replaceNode(optionNode);
+    }
+    else {
+        aSelect.replaceChild(optionNode, aNode);
+    }
+    delete ie_hidden_options[aSelect.id][optionNode.id];
+    return optionNode;
+}
+
+function initHidingOptionsForIE(select_name) {
+    var aSelect = document.getElementById(select_name);
+    if (browserCanHideOptions(aSelect)) return;
+
+    for (var i = 0; ;i++) {
+        var item = aSelect.options[i];
+        if (!item) break;
+        if (item.disabled) {
+          hideOptionInIE(item, aSelect);
+          i--; // Hiding an option means that the options array has changed.
+        }
+    }
+}
+
+function getPossiblyHiddenOption(aSelect, optionId) {
+    // Works always for &lt;option&gt; tags, and works for commentNodes
+    // in IE (but not in Webkit).
+    var id = _value_id(aSelect.id, optionId);
+    var val = document.getElementById(id);
+
+    // This is for WebKit and other browsers that can't &quot;display: none&quot;
+    // an &lt;option&gt; and also can't getElementById for a commentNode.
+    if (!val &amp;&amp; ie_hidden_options[aSelect.id]) {
+        val = ie_hidden_options[aSelect.id][id];
+    }
+
+    return val;
+}
+
+var browser_can_hide_options;
+function browserCanHideOptions(aSelect) {
+    /* As far as I can tell, browsers that don't hide &lt;option&gt; tags
+     * also never have a X position for &lt;option&gt; tags, even if
+     * they're visible. This is the only reliable way I found to
+     * differentiate browsers. So we create a visible option, see
+     * if it has a position, and then remove it. */
+    if (typeof(browser_can_hide_options) == &quot;undefined&quot;) {
+        var new_opt = bz_createOptionInSelect(aSelect, '', '');
+        var opt_pos = YAHOO.util.Dom.getX(new_opt);
+        aSelect.removeChild(new_opt);
+        if (opt_pos) {
+            browser_can_hide_options = true;
+        }
+        else {
+            browser_can_hide_options = false;
+        }
+    }
+    return browser_can_hide_options;
+}
+
+/* (end) option hiding code */
+
+/**
+ * The Autoselect
+ */
+YAHOO.bugzilla.userAutocomplete = {
+    counter : 0,
+    dataSource : null,
+    generateRequest : function ( enteredText ){ 
+      YAHOO.bugzilla.userAutocomplete.counter = 
+                                   YAHOO.bugzilla.userAutocomplete.counter + 1;
+      YAHOO.util.Connect.setDefaultPostHeader('application/json', true);
+      var json_object = {
+          method : &quot;User.get&quot;,
+          id : YAHOO.bugzilla.userAutocomplete.counter,
+          params : [ { 
+            match : [ decodeURIComponent(enteredText) ],
+            include_fields : [ &quot;name&quot;, &quot;real_name&quot; ]
+          } ]
+      };
+      var stringified =  YAHOO.lang.JSON.stringify(json_object);
+      var debug = { msg: &quot;json-rpc obj debug info&quot;, &quot;json obj&quot;: json_object, 
+                    &quot;param&quot; : stringified}
+      YAHOO.bugzilla.userAutocomplete.debug_helper( debug );
+      return stringified;
+    },
+    resultListFormat : function(oResultData, enteredText, sResultMatch) {
+        return ( YAHOO.lang.escapeHTML(oResultData.real_name) + &quot; (&quot;
+                 + YAHOO.lang.escapeHTML(oResultData.name) + &quot;)&quot;);
+    },
+    debug_helper : function ( ){
+        /* used to help debug any errors that might happen */
+        if( typeof(console) !== 'undefined' &amp;&amp; console != null &amp;&amp; arguments.length &gt; 0 ){
+            console.log(&quot;debug helper info:&quot;, arguments);
+        }
+        return true;
+    },    
+    init_ds : function(){
+        this.dataSource = new YAHOO.util.XHRDataSource(&quot;jsonrpc.cgi&quot;);
+        this.dataSource.connTimeout = 30000;
+        this.dataSource.connMethodPost = true;
+        this.dataSource.connXhrMode = &quot;cancelStaleRequests&quot;;
+        this.dataSource.maxCacheEntries = 5;
+        this.dataSource.responseSchema = {
+            resultsList : &quot;result.users&quot;,
+            metaFields : { error: &quot;error&quot;, jsonRpcId: &quot;id&quot;},
+            fields : [
+                { key : &quot;name&quot; },
+                { key : &quot;real_name&quot;}
+            ]
+        };
+    },
+    init : function( field, container, multiple ) {
+        if( this.dataSource == null ){
+            this.init_ds();  
+        }            
+        var userAutoComp = new YAHOO.widget.AutoComplete( field, container, 
+                                this.dataSource );
+        // other stuff we might want to do with the autocomplete goes here
+        userAutoComp.maxResultsDisplayed = BUGZILLA.param.maxusermatches;
+        userAutoComp.generateRequest = this.generateRequest;
+        userAutoComp.formatResult = this.resultListFormat;
+        userAutoComp.doBeforeLoadData = this.debug_helper;
+        userAutoComp.minQueryLength = 3;
+        userAutoComp.autoHighlight = false;
+        // this is a throttle to determine the delay of the query from typing
+        // set this higher to cause fewer calls to the server
+        userAutoComp.queryDelay = 0.05;
+        userAutoComp.useIFrame = true;
+        userAutoComp.resultTypeList = false;
+        if( multiple == true ){
+            userAutoComp.delimChar = [&quot;,&quot;];
+        }
+        
+    }
+};
+
+YAHOO.bugzilla.keywordAutocomplete = {
+    dataSource : null,
+    init_ds : function(){
+        this.dataSource = new YAHOO.util.LocalDataSource( YAHOO.bugzilla.keyword_array );
+    },
+    init : function( field, container ) {
+        if( this.dataSource == null ){
+            this.init_ds();
+        }
+        var keywordAutoComp = new YAHOO.widget.AutoComplete(field, container, this.dataSource);
+        keywordAutoComp.maxResultsDisplayed = YAHOO.bugzilla.keyword_array.length;
+        keywordAutoComp.minQueryLength = 0;
+        keywordAutoComp.useIFrame = true;
+        keywordAutoComp.delimChar = [&quot;,&quot;,&quot; &quot;];
+        keywordAutoComp.resultTypeList = false;
+        keywordAutoComp.queryDelay = 0;
+        /*  Causes all the possibilities in the keyword to appear when a user 
+         *  focuses on the textbox 
+         */
+        keywordAutoComp.textboxFocusEvent.subscribe( function(){
+            var sInputValue = YAHOO.util.Dom.get('keywords').value;
+            if( sInputValue.length === 0 ){
+                this.sendQuery(sInputValue);
+                this.collapseContainer();
+                this.expandContainer();
+            }
+        });
+    }
+};
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsflagjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/flag.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/flag.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/flag.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,75 @@
</span><ins>+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the &quot;License&quot;); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an &quot;AS IS&quot; basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Bugzilla Bug Tracking System.
+ *
+ * The Initial Developer of the Original Code is Netscape Communications
+ * Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *  Myk Melez &lt;myk@mozilla.org&gt;
+ *  Frédéric Buclin &lt;LpSolit@gmail.com&gt;
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// Shows or hides a requestee field depending on whether or not
+// the user is requesting the corresponding flag.
+function toggleRequesteeField(flagField, no_focus)
+{
+  // Convert the ID of the flag field into the ID of its corresponding
+  // requestee field and then use the ID to get the field.
+  var id = flagField.name.replace(/flag(_type)?-(\d+)/, &quot;requestee$1-$2&quot;);
+  var requesteeField = document.getElementById(id);
+  if (!requesteeField) return;
+
+  // Show or hide the requestee field based on the value
+  // of the flag field.
+  if (flagField.value == &quot;?&quot;) {
+      YAHOO.util.Dom.removeClass(requesteeField.parentNode, 'bz_default_hidden');
+      if (!no_focus) requesteeField.focus();
+  } else
+      YAHOO.util.Dom.addClass(requesteeField.parentNode, 'bz_default_hidden');
+}
+
+// Hides requestee fields when the window is loaded since they shouldn't
+// be enabled until the user requests that flag type.
+function hideRequesteeFields()
+{
+  var inputElements = document.getElementsByTagName(&quot;input&quot;);
+  var selectElements = document.getElementsByTagName(&quot;select&quot;);
+  //You cannot update Node lists, so you must create an array to combine the NodeLists
+  var allElements = [];
+  for( var i=0; i &lt; inputElements.length; i++ ) {
+      allElements[allElements.length] = inputElements.item(i);
+  }
+  for( var i=0; i &lt; selectElements.length; i++ ) { //Combine inputs with selects
+      allElements[allElements.length] = selectElements.item(i);
+  }
+  var inputElement, id, flagField;
+  for ( var i=0 ; i&lt;allElements.length ; i++ )
+  {
+    inputElement = allElements[i];
+    if (inputElement.name.search(/^requestee(_type)?-(\d+)$/) != -1)
+    {
+      // Convert the ID of the requestee field into the ID of its corresponding
+      // flag field and then use the ID to get the field.
+      id = inputElement.name.replace(/requestee(_type)?-(\d+)/, &quot;flag$1-$2&quot;);
+      flagField = document.getElementById(id);
+      if (flagField &amp;&amp; flagField.value != &quot;?&quot;)
+          YAHOO.util.Dom.addClass(inputElement.parentNode, 'bz_default_hidden');
+    }
+  }
+}
+YAHOO.util.Event.onDOMReady(hideRequesteeFields);
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsglobaljs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/global.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/global.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/global.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,131 @@
</span><ins>+/* The contents of this file are subject to the Mozilla Public
+* License Version 1.1 (the &quot;License&quot;); you may not use this file
+* except in compliance with the License. You may obtain a copy of
+* the License at http://www.mozilla.org/MPL/
+*
+* Software distributed under the License is distributed on an &quot;AS
+* IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+* implied. See the License for the specific language governing
+* rights and limitations under the License.
+*
+* The Original Code is the Bugzilla Bug Tracking System.
+*
+* Contributor(s): 
+*   Guy Pyrzak &lt;guy.pyrzak@gmail.com&gt;
+*   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+*                 
+*/
+
+var mini_login_constants;
+
+function show_mini_login_form( suffix ) {
+    var login_link = document.getElementById('login_link' + suffix);
+    var login_form = document.getElementById('mini_login' + suffix);
+    var account_container = document.getElementById('new_account_container'
+                                                    + suffix);
+
+    YAHOO.util.Dom.addClass(login_link, 'bz_default_hidden');
+    YAHOO.util.Dom.removeClass(login_form, 'bz_default_hidden');
+    YAHOO.util.Dom.addClass(account_container, 'bz_default_hidden');
+    return false;
+}
+
+function hide_mini_login_form( suffix ) {
+    var login_link = document.getElementById('login_link' + suffix);
+    var login_form = document.getElementById('mini_login' + suffix);
+    var account_container = document.getElementById('new_account_container'
+                                                    + suffix);
+
+    YAHOO.util.Dom.removeClass(login_link, 'bz_default_hidden');
+    YAHOO.util.Dom.addClass(login_form, 'bz_default_hidden');
+    YAHOO.util.Dom.removeClass(account_container, 'bz_default_hidden');
+    return false;
+}
+
+function show_forgot_form( suffix ) {
+    var forgot_link = document.getElementById('forgot_link' + suffix);
+    var forgot_form = document.getElementById('forgot_form' + suffix);
+    var login_container = document.getElementById('mini_login_container' 
+                                                  + suffix);
+    YAHOO.util.Dom.addClass(forgot_link, 'bz_default_hidden');
+    YAHOO.util.Dom.removeClass(forgot_form, 'bz_default_hidden');
+    YAHOO.util.Dom.addClass(login_container, 'bz_default_hidden');
+    return false;
+}
+
+function hide_forgot_form( suffix ) {
+    var forgot_link = document.getElementById('forgot_link' + suffix);
+    var forgot_form = document.getElementById('forgot_form' + suffix);
+    var login_container = document.getElementById('mini_login_container'
+                                                  + suffix);
+    YAHOO.util.Dom.removeClass(forgot_link, 'bz_default_hidden');
+    YAHOO.util.Dom.addClass(forgot_form, 'bz_default_hidden');
+    YAHOO.util.Dom.removeClass(login_container, 'bz_default_hidden');
+    return false;
+}
+
+function init_mini_login_form( suffix ) {
+    var mini_login = document.getElementById('Bugzilla_login' +  suffix );
+    var mini_password = document.getElementById('Bugzilla_password' +  suffix );
+    var mini_dummy = document.getElementById(
+        'Bugzilla_password_dummy' + suffix);
+    // If the login and password are blank when the page loads, we display
+    // &quot;login&quot; and &quot;password&quot; in the boxes by default.
+    if (mini_login.value == &quot;&quot; &amp;&amp; mini_password.value == &quot;&quot;) {
+        mini_login.value = mini_login_constants.login;
+        YAHOO.util.Dom.addClass(mini_login, &quot;bz_mini_login_help&quot;);
+        YAHOO.util.Dom.addClass(mini_password, 'bz_default_hidden');
+        YAHOO.util.Dom.removeClass(mini_dummy, 'bz_default_hidden');
+    }
+    else {
+        show_mini_login_form(suffix);
+    }
+}
+
+// Clear the words &quot;login&quot; and &quot;password&quot; from the form when you click
+// in one of the boxes. We clear them both when you click in either box
+// so that the browser's password-autocomplete can work.
+function mini_login_on_focus( suffix ) {
+    var mini_login = document.getElementById('Bugzilla_login' +  suffix );
+    var mini_password = document.getElementById('Bugzilla_password' +  suffix );
+    var mini_dummy = document.getElementById(
+        'Bugzilla_password_dummy' + suffix);
+
+    YAHOO.util.Dom.removeClass(mini_login, &quot;bz_mini_login_help&quot;);
+    if (mini_login.value == mini_login_constants.login) {
+        mini_login.value = '';
+    }
+    YAHOO.util.Dom.removeClass(mini_password, 'bz_default_hidden');
+    YAHOO.util.Dom.addClass(mini_dummy, 'bz_default_hidden');
+}
+
+function check_mini_login_fields( suffix ) {
+    var mini_login = document.getElementById('Bugzilla_login' +  suffix );
+    var mini_password = document.getElementById('Bugzilla_password' +  suffix );
+    if( (mini_login.value != &quot;&quot; &amp;&amp; mini_password.value != &quot;&quot;) 
+         &amp;&amp;  mini_login.value != mini_login_constants.login )
+    {
+      return true;
+    }
+    window.alert( mini_login_constants.warning );
+    return false;
+}
+
+function set_language( value ) {
+    YAHOO.util.Cookie.set('LANG', value,
+    {
+        expires: new Date('January 1, 2038'),
+        path: BUGZILLA.param.cookie_path
+    });
+    window.location.reload()
+}
+
+// This basically duplicates Bugzilla::Util::display_value for code that
+// can't go through the template and has to be in JS.
+function display_value(field, value) {
+    var field_trans = BUGZILLA.value_descs[field];
+    if (!field_trans) return value;
+    var translated = field_trans[value];
+    if (translated) return translated;
+    return value;
+}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjshelpjs"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/js/help.js (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/help.js        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/js/help.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,108 +0,0 @@
</span><del>-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the &quot;License&quot;); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an &quot;AS IS&quot; basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is the Bugzilla Bug Tracking System.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Gervase Markham &lt;gerv@gerv.net&gt;
- *
- * ***** END LICENSE BLOCK ***** */
-
-var g_helpTexts = new Object();
-var g_helpIframe;
-var g_helpDiv;
-
-/**
- * Generate help controls during page construction.
- *
- * @return Boolean; true if controls were created and false if not.
- */
-function generateHelp()
-{
-    // Only enable help if controls can be hidden
-    if (!document.body.style)
-        return false;
-
-    // Create help controls (a div to hold help text and an iframe
-    // to mask any and all controls under the popup)
-    document.write('&lt;div id=&quot;helpDiv&quot; style=&quot;display: none;&quot;&gt;&lt;\/div&gt;');
-    document.write('&lt;iframe id=&quot;helpIframe&quot; src=&quot;about:blank&quot;');
-    document.write('        frameborder=&quot;0&quot; scrolling=&quot;no&quot;&gt;&lt;\/iframe&gt;');
-
-    return true;
-}
-
-/**
- * Enable help popups for all form elements after the page has finished loading.
- *
- * @return Boolean; true if help was enabled and false if not.
- */
-function enableHelp()
-{
-    g_helpIframe = document.getElementById('helpIframe');
-    g_helpDiv = document.getElementById('helpDiv');
-    if (!g_helpIframe || !g_helpDiv) // Disabled if no controls found
-        return false;
-
-    // MS decided to add fieldsets to the elements array; and
-    // Mozilla decided to copy this brokenness. Grr.
-    for (var i = 0; i &lt; document.forms.length; i++) {
-        for (var j = 0; j &lt; document.forms[i].elements.length; j++) {
-            if (document.forms[i].elements[j].tagName != 'FIELDSET') {
-                document.forms[i].elements[j].onmouseover = showHelp;
-            }
-        }
-    }
-
-    document.body.onclick = hideHelp;
-    return true;
-}
-
-/**
- * Show the help popup for a form element.
- */
-function showHelp() {
-    if (!g_helpIframe || !g_helpDiv || !g_helpTexts[this.name])
-        return;
-
-    // Get the position and size of the form element in the document
-    var elemY = bz_findPosY(this);
-    var elemX = bz_findPosX(this);
-    var elemH = this.offsetHeight;
-
-    // Update help text displayed in the div
-    g_helpDiv.innerHTML = ''; // Helps IE 5 Mac
-    g_helpDiv.innerHTML = g_helpTexts[this.name];
-
-    // Position and display the help popup
-    g_helpIframe.style.top = g_helpDiv.style.top = elemY + elemH + 5 + &quot;px&quot;;
-    g_helpIframe.style.left = g_helpDiv.style.left = elemX + &quot;px&quot;;
-    g_helpIframe.style.display = g_helpDiv.style.display = '';
-    g_helpIframe.style.width = g_helpDiv.offsetWidth + &quot;px&quot;;
-    g_helpIframe.style.height = g_helpDiv.offsetHeight + &quot;px&quot;;
-}
-
-/**
- * Hide the help popup.
- */
-function hideHelp() {
-    if (!g_helpIframe || !g_helpDiv)
-        return;
-
-    g_helpIframe.style.display = g_helpDiv.style.display = 'none';
-}
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjshistoryjslicensetxt"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/history.js/license.txt (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/history.js/license.txt                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/history.js/license.txt        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+Copyright (c) 2011, Benjamin Arthur Lupton
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+  â€¢ Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+  â€¢ Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+  â€¢ Neither the name of Benjamin Arthur Lupton nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjshistoryjsnativehistoryjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/history.js/native.history.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/history.js/native.history.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/history.js/native.history.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1 @@
</span><ins>+window.JSON||(window.JSON={}),function(){function f(a){return a&lt;10?&quot;0&quot;+a:a}function quote(a){return escapable.lastIndex=0,escapable.test(a)?'&quot;'+a.replace(escapable,function(a){var b=meta[a];return typeof b==&quot;string&quot;?b:&quot;\\u&quot;+(&quot;0000&quot;+a.charCodeAt(0).toString(16)).slice(-4)})+'&quot;':'&quot;'+a+'&quot;'}function str(a,b){var c,d,e,f,g=gap,h,i=b[a];i&amp;&amp;typeof i==&quot;object&quot;&amp;&amp;typeof i.toJSON==&quot;function&quot;&amp;&amp;(i=i.toJSON(a)),typeof rep==&quot;function&quot;&amp;&amp;(i=rep.call(b,a,i));switch(typeof i){case&quot;string&quot;:return quote(i);case&quot;number&quot;:return isFinite(i)?String(i):&quot;null&quot;;case&quot;boolean&quot;:case&quot;null&quot;:return String(i);case&quot;object&quot;:if(!i)return&quot;null&quot;;gap+=indent,h=[];if(Object.prototype.toString.apply(i)===&quot;[object Array]&quot;){f=i.length;for(c=0;c&lt;f;c+=1)h[c]=str(c,i)||&quot;null&quot;;return e=h.length===
 0?&quot;[]&quot;:gap?&quot;[\n&quot;+gap+h.join(&quot;,\n&quot;+gap)+&quot;\n&quot;+g+&quot;]&quot;:&quot;[&quot;+h.join(&quot;,&quot;)+&quot;]&quot;,gap=g,e}if(rep&amp;&amp;typeof rep==&quot;object&quot;){f=rep.length;for(c=0;c&lt;f;c+=1)d=rep[c],typeof d==&quot;string&quot;&amp;&amp;(e=str(d,i),e&amp;&amp;h.push(quote(d)+(gap?&quot;: &quot;:&quot;:&quot;)+e))}else for(d in i)Object.hasOwnProperty.call(i,d)&amp;&amp;(e=str(d,i),e&amp;&amp;h.push(quote(d)+(gap?&quot;: &quot;:&quot;:&quot;)+e));return e=h.length===0?&quot;{}&quot;:gap?&quot;{\n&quot;+gap+h.join(&quot;,\n&quot;+gap)+&quot;\n&quot;+g+&quot;}&quot;:&quot;{&quot;+h.join(&quot;,&quot;)+&quot;}&quot;,gap=g,e}}&quot;use strict&quot;,typeof Date.prototype.toJSON!=&quot;function&quot;&amp;&amp;(Date.prototype.toJSON=function(a){return isFinite(this.valueOf())?this.getUTCFullYear()+&quot;-&quot;+f(this.getUTCMonth()+1)+&quot;-&quot;+f(this.getUTCDate())+&quot;T&quot;+f(this.getUTCHours())+&quot;:&quot;+f(this.getUTCMin
 utes())+&quot;:&quot;+f(this.getUTCSeconds())+&quot;Z&quot;:null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(a){return this.valueOf()});var JSON=window.JSON,cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\&quot;\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={&quot;\b&quot;:&quot;\\b&quot;,&quot;\t&quot;:&quot;\\t&quot;,&quot;\n&quot;:&quot;\\n&quot;,&quot;\f&quot;:&quot;\\f&quot;,&quot;\r&quot;:&quot;\\r&quot;,'&quot;':'\\&quot;',&quot;\\&quot;:&quot;\\\\&quot;},rep;typeof JSON.stringify!=&quot;function&quot;&amp;&amp;(JSON.stringify=function(a,b,c){var d;gap=&quot;&quot;,indent=&quot;&quot;;if(typeof c==&quot;number&quot;)for(d=0;d&lt;c;d+=1)indent+=&quot; &quot;;else typeof c==&quot;string&quot;&amp;&amp;(indent=c);rep=b;if(!b||typeof b==&quot;function&quot;||typeof b==&quot
 ;object&quot;&amp;&amp;typeof b.length==&quot;number&quot;)return str(&quot;&quot;,{&quot;&quot;:a});throw new Error(&quot;JSON.stringify&quot;)}),typeof JSON.parse!=&quot;function&quot;&amp;&amp;(JSON.parse=function(text,reviver){function walk(a,b){var c,d,e=a[b];if(e&amp;&amp;typeof e==&quot;object&quot;)for(c in e)Object.hasOwnProperty.call(e,c)&amp;&amp;(d=walk(e,c),d!==undefined?e[c]=d:delete e[c]);return reviver.call(a,b,e)}var j;text=String(text),cx.lastIndex=0,cx.test(text)&amp;&amp;(text=text.replace(cx,function(a){return&quot;\\u&quot;+(&quot;0000&quot;+a.charCodeAt(0).toString(16)).slice(-4)}));if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:[&quot;\\\/bfnrt]|u[0-9a-fA-F]{4})/g,&quot;@&quot;).replace(/&quot;[^&quot;\\\n\r]*&quot;|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,&quot;]&quot;).replace(/(?:^|:|,)(?:\s*\[)+/g,&quot;&quot;)))return j=eval(&quot;(&quot;+text+&quot;)&quot;),typeof reviver==&quot;function&quot;?walk({&quot;&quot;:j},&quot;&quot;):j;throw n
 ew SyntaxError(&quot;JSON.parse&quot;)})}(),function(a,b){&quot;use strict&quot;;var c=a.History=a.History||{};if(typeof c.Adapter!=&quot;undefined&quot;)throw new Error(&quot;History.js Adapter has already been loaded...&quot;);c.Adapter={handlers:{},_uid:1,uid:function(a){return a._uid||(a._uid=c.Adapter._uid++)},bind:function(a,b,d){var e=c.Adapter.uid(a);c.Adapter.handlers[e]=c.Adapter.handlers[e]||{},c.Adapter.handlers[e][b]=c.Adapter.handlers[e][b]||[],c.Adapter.handlers[e][b].push(d),a[&quot;on&quot;+b]=function(a,b){return function(d){c.Adapter.trigger(a,b,d)}}(a,b)},trigger:function(a,b,d){d=d||{};var e=c.Adapter.uid(a),f,g;c.Adapter.handlers[e]=c.Adapter.handlers[e]||{},c.Adapter.handlers[e][b]=c.Adapter.handlers[e][b]||[];for(f=0,g=c.Adapter.handlers[e][b].length;f&lt;g;++f)c.Adapter.handlers[e][b][f].apply(this,[d])},extractEventData:function(a,c){var d=c&amp;&amp;c[a]||b;return d},onDomLoad:function(b){var c=a.setTimeout(function(){b()},2e3);a.onload=function(){
 clearTimeout(c),b()}}},typeof c.init!=&quot;undefined&quot;&amp;&amp;c.init()}(window),function(a,b){&quot;use strict&quot;;var c=a.document,d=a.setTimeout||d,e=a.clearTimeout||e,f=a.setInterval||f,g=a.History=a.History||{};if(typeof g.initHtml4!=&quot;undefined&quot;)throw new Error(&quot;History.js HTML4 Support has already been loaded...&quot;);g.initHtml4=function(){if(typeof g.initHtml4.initialized!=&quot;undefined&quot;)return!1;g.initHtml4.initialized=!0,g.enabled=!0,g.savedHashes=[],g.isLastHash=function(a){var b=g.getHashByIndex(),c;return c=a===b,c},g.saveHash=function(a){return g.isLastHash(a)?!1:(g.savedHashes.push(a),!0)},g.getHashByIndex=function(a){var b=null;return typeof a==&quot;undefined&quot;?b=g.savedHashes[g.savedHashes.length-1]:a&lt;0?b=g.savedHashes[g.savedHashes.length+a]:b=g.savedHashes[a],b},g.discardedHashes={},g.discardedStates={},g.discardState=function(a,b,c){var d=g.getHashByState(a),e;return e={discardedState:a,backState:c,forwardState:b},g.
 discardedStates[d]=e,!0},g.discardHash=function(a,b,c){var d={discardedHash:a,backState:c,forwardState:b};return g.discardedHashes[a]=d,!0},g.discardedState=function(a){var b=g.getHashByState(a),c;return c=g.discardedStates[b]||!1,c},g.discardedHash=function(a){var b=g.discardedHashes[a]||!1;return b},g.recycleState=function(a){var b=g.getHashByState(a);return g.discardedState(a)&amp;&amp;delete g.discardedStates[b],!0},g.emulated.hashChange&amp;&amp;(g.hashChangeInit=function(){g.checkerFunction=null;var b=&quot;&quot;,d,e,h,i;return g.isInternetExplorer()?(d=&quot;historyjs-iframe&quot;,e=c.createElement(&quot;iframe&quot;),e.setAttribute(&quot;id&quot;,d),e.style.display=&quot;none&quot;,c.body.appendChild(e),e.contentWindow.document.open(),e.contentWindow.document.close(),h=&quot;&quot;,i=!1,g.checkerFunction=function(){if(i)return!1;i=!0;var c=g.getHash()||&quot;&quot;,d=g.unescapeHash(e.contentWindow.document.location.hash)||&quot;&quot;;return c!==b?(b=c,d!==c&amp;&am
 p;(h=d=c,e.contentWindow.document.open(),e.contentWindow.document.close(),e.contentWindow.document.location.hash=g.escapeHash(c)),g.Adapter.trigger(a,&quot;hashchange&quot;)):d!==h&amp;&amp;(h=d,g.setHash(d,!1)),i=!1,!0}):g.checkerFunction=function(){var c=g.getHash();return c!==b&amp;&amp;(b=c,g.Adapter.trigger(a,&quot;hashchange&quot;)),!0},g.intervalList.push(f(g.checkerFunction,g.options.hashChangeInterval)),!0},g.Adapter.onDomLoad(g.hashChangeInit)),g.emulated.pushState&amp;&amp;(g.onHashChange=function(b){var d=b&amp;&amp;b.newURL||c.location.href,e=g.getHashByUrl(d),f=null,h=null,i=null,j;return g.isLastHash(e)?(g.busy(!1),!1):(g.doubleCheckComplete(),g.saveHash(e),e&amp;&amp;g.isTraditionalAnchor(e)?(g.Adapter.trigger(a,&quot;anchorchange&quot;),g.busy(!1),!1):(f=g.extractState(g.getFullUrl(e||c.location.href,!1),!0),g.isLastSavedState(f)?(g.busy(!1),!1):(h=g.getHashByState(f),j=g.discardedState(f),j?(g.getHashByIndex(-2)===g.getHashByState(j.forwardState)?g.back(!1)
 :g.forward(!1),!1):(g.pushState(f.data,f.title,f.url,!1),!0))))},g.Adapter.bind(a,&quot;hashchange&quot;,g.onHashChange),g.pushState=function(b,d,e,f){if(g.getHashByUrl(e))throw new Error(&quot;History.js does not support states with fragement-identifiers (hashes/anchors).&quot;);if(f!==!1&amp;&amp;g.busy())return g.pushQueue({scope:g,callback:g.pushState,args:arguments,queue:f}),!1;g.busy(!0);var h=g.createStateObject(b,d,e),i=g.getHashByState(h),j=g.getState(!1),k=g.getHashByState(j),l=g.getHash();return g.storeState(h),g.expectedStateId=h.id,g.recycleState(h),g.setTitle(h),i===k?(g.busy(!1),!1):i!==l&amp;&amp;i!==g.getShortUrl(c.location.href)?(g.setHash(i,!1),!1):(g.saveState(h),g.Adapter.trigger(a,&quot;statechange&quot;),g.busy(!1),!0)},g.replaceState=function(a,b,c,d){if(g.getHashByUrl(c))throw new Error(&quot;History.js does not support states with fragement-identifiers (hashes/anchors).&quot;);if(d!==!1&amp;&amp;g.busy())return g.pushQueue({scope:g,callback:g.replac
 eState,args:arguments,queue:d}),!1;g.busy(!0);var e=g.createStateObject(a,b,c),f=g.getState(!1),h=g.getStateByIndex(-2);return g.discardState(f,e,h),g.pushState(e.data,e.title,e.url,!1),!0}),g.emulated.pushState&amp;&amp;g.getHash()&amp;&amp;!g.emulated.hashChange&amp;&amp;g.Adapter.onDomLoad(function(){g.Adapter.trigger(a,&quot;hashchange&quot;)})},typeof g.init!=&quot;undefined&quot;&amp;&amp;g.init()}(window),function(a,b){&quot;use strict&quot;;var c=a.console||b,d=a.document,e=a.navigator,f=a.sessionStorage||!1,g=a.setTimeout,h=a.clearTimeout,i=a.setInterval,j=a.clearInterval,k=a.JSON,l=a.alert,m=a.History=a.History||{},n=a.history;k.stringify=k.stringify||k.encode,k.parse=k.parse||k.decode;if(typeof m.init!=&quot;undefined&quot;)throw new Error(&quot;History.js Core has already been loaded...&quot;);m.init=function(){return typeof m.Adapter==&quot;undefined&quot;?!1:(typeof m.initCore!=&quot;undefined&quot;&amp;&amp;m.initCore(),typeof m.initHtml4!=&quot;undefined&quot
 ;&amp;&amp;m.initHtml4(),!0)},m.initCore=function(){if(typeof m.initCore.initialized!=&quot;undefined&quot;)return!1;m.initCore.initialized=!0,m.options=m.options||{},m.options.hashChangeInterval=m.options.hashChangeInterval||100,m.options.safariPollInterval=m.options.safariPollInterval||500,m.options.doubleCheckInterval=m.options.doubleCheckInterval||500,m.options.storeInterval=m.options.storeInterval||1e3,m.options.busyDelay=m.options.busyDelay||250,m.options.debug=m.options.debug||!1,m.options.initialTitle=m.options.initialTitle||d.title,m.intervalList=[],m.clearAllIntervals=function(){var a,b=m.intervalList;if(typeof b!=&quot;undefined&quot;&amp;&amp;b!==null){for(a=0;a&lt;b.length;a++)j(b[a]);m.intervalList=null}},m.debug=function(){(m.options.debug||!1)&amp;&amp;m.log.apply(m,arguments)},m.log=function(){var a=typeof c!=&quot;undefined&quot;&amp;&amp;typeof c.log!=&quot;undefined&quot;&amp;&amp;typeof c.log.apply!=&quot;undefined&quot;,b=d.getElementById(&quot;log&quot
 ;),e,f,g,h,i;a?(h=Array.prototype.slice.call(arguments),e=h.shift(),typeof c.debug!=&quot;undefined&quot;?c.debug.apply(c,[e,h]):c.log.apply(c,[e,h])):e=&quot;\n&quot;+arguments[0]+&quot;\n&quot;;for(f=1,g=arguments.length;f&lt;g;++f){i=arguments[f];if(typeof i==&quot;object&quot;&amp;&amp;typeof k!=&quot;undefined&quot;)try{i=k.stringify(i)}catch(j){}e+=&quot;\n&quot;+i+&quot;\n&quot;}return b?(b.value+=e+&quot;\n-----\n&quot;,b.scrollTop=b.scrollHeight-b.clientHeight):a||l(e),!0},m.getInternetExplorerMajorVersion=function(){var a=m.getInternetExplorerMajorVersion.cached=typeof m.getInternetExplorerMajorVersion.cached!=&quot;undefined&quot;?m.getInternetExplorerMajorVersion.cached:function(){var a=3,b=d.createElement(&quot;div&quot;),c=b.getElementsByTagName(&quot;i&quot;);while((b.innerHTML=&quot;&lt;!--[if gt IE &quot;+ ++a+&quot;]&gt;&lt;i&gt;&lt;/i&gt;&lt;![endif]--&gt;&quot;)&amp;&amp;c[0]);return a&gt;4?a:!1}();return a},m.isInternetExplorer=function(){var a=m.isInter
 netExplorer.cached=typeof m.isInternetExplorer.cached!=&quot;undefined&quot;?m.isInternetExplorer.cached:Boolean(m.getInternetExplorerMajorVersion());return a},m.emulated={pushState:!Boolean(a.history&amp;&amp;a.history.pushState&amp;&amp;a.history.replaceState&amp;&amp;!/ Mobile\/([1-7][a-z]|(8([abcde]|f(1[0-8]))))/i.test(e.userAgent)&amp;&amp;!/AppleWebKit\/5([0-2]|3[0-2])/i.test(e.userAgent)),hashChange:Boolean(!(&quot;onhashchange&quot;in a||&quot;onhashchange&quot;in d)||m.isInternetExplorer()&amp;&amp;m.getInternetExplorerMajorVersion()&lt;8)},m.enabled=!m.emulated.pushState,m.bugs={setHash:Boolean(!m.emulated.pushState&amp;&amp;e.vendor===&quot;Apple Computer, Inc.&quot;&amp;&amp;/AppleWebKit\/5([0-2]|3[0-3])/.test(e.userAgent)),safariPoll:Boolean(!m.emulated.pushState&amp;&amp;e.vendor===&quot;Apple Computer, Inc.&quot;&amp;&amp;/AppleWebKit\/5([0-2]|3[0-3])/.test(e.userAgent)),ieDoubleCheck:Boolean(m.isInternetExplorer()&amp;&amp;m.getInternetExplorerMajorVersion()&
 lt;8),hashEscape:Boolean(m.isInternetExplorer()&amp;&amp;m.getInternetExplorerMajorVersion()&lt;7)},m.isEmptyObject=function(a){for(var b in a)return!1;return!0},m.cloneObject=function(a){var b,c;return a?(b=k.stringify(a),c=k.parse(b)):c={},c},m.getRootUrl=function(){var a=d.location.protocol+&quot;//&quot;+(d.location.hostname||d.location.host);if(d.location.port||!1)a+=&quot;:&quot;+d.location.port;return a+=&quot;/&quot;,a},m.getBaseHref=function(){var a=d.getElementsByTagName(&quot;base&quot;),b=null,c=&quot;&quot;;return a.length===1&amp;&amp;(b=a[0],c=b.href.replace(/[^\/]+$/,&quot;&quot;)),c=c.replace(/\/+$/,&quot;&quot;),c&amp;&amp;(c+=&quot;/&quot;),c},m.getBaseUrl=function(){var a=m.getBaseHref()||m.getBasePageUrl()||m.getRootUrl();return a},m.getPageUrl=function(){var a=m.getState(!1,!1),b=(a||{}).url||d.location.href,c;return c=b.replace(/\/+$/,&quot;&quot;).replace(/[^\/]+$/,function(a,b,c){return/\./.test(a)?a:a+&quot;/&quot;}),c},m.getBasePageUrl=function(){v
 ar a=d.location.href.replace(/[#\?].*/,&quot;&quot;).replace(/[^\/]+$/,function(a,b,c){return/[^\/]$/.test(a)?&quot;&quot;:a}).replace(/\/+$/,&quot;&quot;)+&quot;/&quot;;return a},m.getFullUrl=function(a,b){var c=a,d=a.substring(0,1);return b=typeof b==&quot;undefined&quot;?!0:b,/[a-z]+\:\/\//.test(a)||(d===&quot;/&quot;?c=m.getRootUrl()+a.replace(/^\/+/,&quot;&quot;):d===&quot;#&quot;?c=m.getPageUrl().replace(/#.*/,&quot;&quot;)+a:d===&quot;?&quot;?c=m.getPageUrl().replace(/[\?#].*/,&quot;&quot;)+a:b?c=m.getBaseUrl()+a.replace(/^(\.\/)+/,&quot;&quot;):c=m.getBasePageUrl()+a.replace(/^(\.\/)+/,&quot;&quot;)),c.replace(/\#$/,&quot;&quot;)},m.getShortUrl=function(a){var b=a,c=m.getBaseUrl(),d=m.getRootUrl();return m.emulated.pushState&amp;&amp;(b=b.replace(c,&quot;&quot;)),b=b.replace(d,&quot;/&quot;),m.isTraditionalAnchor(b)&amp;&amp;(b=&quot;./&quot;+b),b=b.replace(/^(\.\/)+/g,&quot;./&quot;).replace(/\#$/,&quot;&quot;),b},m.store={},m.idToState=m.idToState||{},m.stateToId=m
 .stateToId||{},m.urlToId=m.urlToId||{},m.storedStates=m.storedStates||[],m.savedStates=m.savedStates||[],m.normalizeStore=function(){m.store.idToState=m.store.idToState||{},m.store.urlToId=m.store.urlToId||{},m.store.stateToId=m.store.stateToId||{}},m.getState=function(a,b){typeof a==&quot;undefined&quot;&amp;&amp;(a=!0),typeof b==&quot;undefined&quot;&amp;&amp;(b=!0);var c=m.getLastSavedState();return!c&amp;&amp;b&amp;&amp;(c=m.createStateObject()),a&amp;&amp;(c=m.cloneObject(c),c.url=c.cleanUrl||c.url),c},m.getIdByState=function(a){var b=m.extractId(a.url),c;if(!b){c=m.getStateString(a);if(typeof m.stateToId[c]!=&quot;undefined&quot;)b=m.stateToId[c];else if(typeof m.store.stateToId[c]!=&quot;undefined&quot;)b=m.store.stateToId[c];else{for(;;){b=(new Date).getTime()+String(Math.random()).replace(/\D/g,&quot;&quot;);if(typeof m.idToState[b]==&quot;undefined&quot;&amp;&amp;typeof m.store.idToState[b]==&quot;undefined&quot;)break}m.stateToId[c]=b,m.idToState[b]=a}}return b},m
 .normalizeState=function(a){var b,c;if(!a||typeof a!=&quot;object&quot;)a={};if(typeof a.normalized!=&quot;undefined&quot;)return a;if(!a.data||typeof a.data!=&quot;object&quot;)a.data={};b={},b.normalized=!0,b.title=a.title||&quot;&quot;,b.url=m.getFullUrl(m.unescapeString(a.url||d.location.href)),b.hash=m.getShortUrl(b.url),b.data=m.cloneObject(a.data),b.id=m.getIdByState(b),b.cleanUrl=b.url.replace(/\??\&amp;_suid.*/,&quot;&quot;),b.url=b.cleanUrl,c=!m.isEmptyObject(b.data);if(b.title||c)b.hash=m.getShortUrl(b.url).replace(/\??\&amp;_suid.*/,&quot;&quot;),/\?/.test(b.hash)||(b.hash+=&quot;?&quot;),b.hash+=&quot;&amp;_suid=&quot;+b.id;return b.hashedUrl=m.getFullUrl(b.hash),(m.emulated.pushState||m.bugs.safariPoll)&amp;&amp;m.hasUrlDuplicate(b)&amp;&amp;(b.url=b.hashedUrl),b},m.createStateObject=function(a,b,c){var d={data:a,title:b,url:c};return d=m.normalizeState(d),d},m.getStateById=function(a){a=String(a);var c=m.idToState[a]||m.store.idToState[a]||b;return c},m.getSta
 teString=function(a){var b,c,d;return b=m.normalizeState(a),c={data:b.data,title:a.title,url:a.url},d=k.stringify(c),d},m.getStateId=function(a){var b,c;return b=m.normalizeState(a),c=b.id,c},m.getHashByState=function(a){var b,c;return b=m.normalizeState(a),c=b.hash,c},m.extractId=function(a){var b,c,d;return c=/(.*)\&amp;_suid=([0-9]+)$/.exec(a),d=c?c[1]||a:a,b=c?String(c[2]||&quot;&quot;):&quot;&quot;,b||!1},m.isTraditionalAnchor=function(a){var b=!/[\/\?\.]/.test(a);return b},m.extractState=function(a,b){var c=null,d,e;return b=b||!1,d=m.extractId(a),d&amp;&amp;(c=m.getStateById(d)),c||(e=m.getFullUrl(a),d=m.getIdByUrl(e)||!1,d&amp;&amp;(c=m.getStateById(d)),!c&amp;&amp;b&amp;&amp;!m.isTraditionalAnchor(a)&amp;&amp;(c=m.createStateObject(null,null,e))),c},m.getIdByUrl=function(a){var c=m.urlToId[a]||m.store.urlToId[a]||b;return c},m.getLastSavedState=function(){return m.savedStates[m.savedStates.length-1]||b},m.getLastStoredState=function(){return m.storedStates[m.storedS
 tates.length-1]||b},m.hasUrlDuplicate=function(a){var b=!1,c;return c=m.extractState(a.url),b=c&amp;&amp;c.id!==a.id,b},m.storeState=function(a){return m.urlToId[a.url]=a.id,m.storedStates.push(m.cloneObject(a)),a},m.isLastSavedState=function(a){var b=!1,c,d,e;return m.savedStates.length&amp;&amp;(c=a.id,d=m.getLastSavedState(),e=d.id,b=c===e),b},m.saveState=function(a){return m.isLastSavedState(a)?!1:(m.savedStates.push(m.cloneObject(a)),!0)},m.getStateByIndex=function(a){var b=null;return typeof a==&quot;undefined&quot;?b=m.savedStates[m.savedStates.length-1]:a&lt;0?b=m.savedStates[m.savedStates.length+a]:b=m.savedStates[a],b},m.getHash=function(){var a=m.unescapeHash(d.location.hash);return a},m.unescapeString=function(b){var c=b,d;for(;;){d=a.unescape(c);if(d===c)break;c=d}return c},m.unescapeHash=function(a){var b=m.normalizeHash(a);return b=m.unescapeString(b),b},m.normalizeHash=function(a){var b=a.replace(/[^#]*#/,&quot;&quot;).replace(/#.*/,&quot;&quot;);return b},m.
 setHash=function(a,b){var c,e,f;return b!==!1&amp;&amp;m.busy()?(m.pushQueue({scope:m,callback:m.setHash,args:arguments,queue:b}),!1):(c=m.escapeHash(a),m.busy(!0),e=m.extractState(a,!0),e&amp;&amp;!m.emulated.pushState?m.pushState(e.data,e.title,e.url,!1):d.location.hash!==c&amp;&amp;(m.bugs.setHash?(f=m.getPageUrl(),m.pushState(null,null,f+&quot;#&quot;+c,!1)):d.location.hash=c),m)},m.escapeHash=function(b){var c=m.normalizeHash(b);return c=a.escape(c),m.bugs.hashEscape||(c=c.replace(/\%21/g,&quot;!&quot;).replace(/\%26/g,&quot;&amp;&quot;).replace(/\%3D/g,&quot;=&quot;).replace(/\%3F/g,&quot;?&quot;)),c},m.getHashByUrl=function(a){var b=String(a).replace(/([^#]*)#?([^#]*)#?(.*)/,&quot;$2&quot;);return b=m.unescapeHash(b),b},m.setTitle=function(a){var b=a.title,c;b||(c=m.getStateByIndex(0),c&amp;&amp;c.url===a.url&amp;&amp;(b=c.title||m.options.initialTitle));try{d.getElementsByTagName(&quot;title&quot;)[0].innerHTML=b.replace(&quot;&lt;&quot;,&quot;&amp;lt;&quot;).replace
 (&quot;&gt;&quot;,&quot;&amp;gt;&quot;).replace(&quot; &amp; &quot;,&quot; &amp;amp; &quot;)}catch(e){}return d.title=b,m},m.queues=[],m.busy=function(a){typeof a!=&quot;undefined&quot;?m.busy.flag=a:typeof m.busy.flag==&quot;undefined&quot;&amp;&amp;(m.busy.flag=!1);if(!m.busy.flag){h(m.busy.timeout);var b=function(){var a,c,d;if(m.busy.flag)return;for(a=m.queues.length-1;a&gt;=0;--a){c=m.queues[a];if(c.length===0)continue;d=c.shift(),m.fireQueueItem(d),m.busy.timeout=g(b,m.options.busyDelay)}};m.busy.timeout=g(b,m.options.busyDelay)}return m.busy.flag},m.busy.flag=!1,m.fireQueueItem=function(a){return a.callback.apply(a.scope||m,a.args||[])},m.pushQueue=function(a){return m.queues[a.queue||0]=m.queues[a.queue||0]||[],m.queues[a.queue||0].push(a),m},m.queue=function(a,b){return typeof a==&quot;function&quot;&amp;&amp;(a={callback:a}),typeof b!=&quot;undefined&quot;&amp;&amp;(a.queue=b),m.busy()?m.pushQueue(a):m.fireQueueItem(a),m},m.clearQueue=function(){return m.busy.flag=
 !1,m.queues=[],m},m.stateChanged=!1,m.doubleChecker=!1,m.doubleCheckComplete=function(){return m.stateChanged=!0,m.doubleCheckClear(),m},m.doubleCheckClear=function(){return m.doubleChecker&amp;&amp;(h(m.doubleChecker),m.doubleChecker=!1),m},m.doubleCheck=function(a){return m.stateChanged=!1,m.doubleCheckClear(),m.bugs.ieDoubleCheck&amp;&amp;(m.doubleChecker=g(function(){return m.doubleCheckClear(),m.stateChanged||a(),!0},m.options.doubleCheckInterval)),m},m.safariStatePoll=function(){var b=m.extractState(d.location.href),c;if(!m.isLastSavedState(b))c=b;else return;return c||(c=m.createStateObject()),m.Adapter.trigger(a,&quot;popstate&quot;),m},m.back=function(a){return a!==!1&amp;&amp;m.busy()?(m.pushQueue({scope:m,callback:m.back,args:arguments,queue:a}),!1):(m.busy(!0),m.doubleCheck(function(){m.back(!1)}),n.go(-1),!0)},m.forward=function(a){return a!==!1&amp;&amp;m.busy()?(m.pushQueue({scope:m,callback:m.forward,args:arguments,queue:a}),!1):(m.busy(!0),m.doubleCheck(func
 tion(){m.forward(!1)}),n.go(1),!0)},m.go=function(a,b){var c;if(a&gt;0)for(c=1;c&lt;=a;++c)m.forward(b);else{if(!(a&lt;0))throw new Error(&quot;History.go: History.go requires a positive or negative integer passed.&quot;);for(c=-1;c&gt;=a;--c)m.back(b)}return m};if(m.emulated.pushState){var o=function(){};m.pushState=m.pushState||o,m.replaceState=m.replaceState||o}else m.onPopState=function(b,c){var e=!1,f=!1,g,h;return m.doubleCheckComplete(),g=m.getHash(),g?(h=m.extractState(g||d.location.href,!0),h?m.replaceState(h.data,h.title,h.url,!1):(m.Adapter.trigger(a,&quot;anchorchange&quot;),m.busy(!1)),m.expectedStateId=!1,!1):(e=m.Adapter.extractEventData(&quot;state&quot;,b,c)||!1,e?f=m.getStateById(e):m.expectedStateId?f=m.getStateById(m.expectedStateId):f=m.extractState(d.location.href),f||(f=m.createStateObject(null,null,d.location.href)),m.expectedStateId=!1,m.isLastSavedState(f)?(m.busy(!1),!1):(m.storeState(f),m.saveState(f),m.setTitle(f),m.Adapter.trigger(a,&quot;statec
 hange&quot;),m.busy(!1),!0))},m.Adapter.bind(a,&quot;popstate&quot;,m.onPopState),m.pushState=function(b,c,d,e){if(m.getHashByUrl(d)&amp;&amp;m.emulated.pushState)throw new Error(&quot;History.js does not support states with fragement-identifiers (hashes/anchors).&quot;);if(e!==!1&amp;&amp;m.busy())return m.pushQueue({scope:m,callback:m.pushState,args:arguments,queue:e}),!1;m.busy(!0);var f=m.createStateObject(b,c,d);return m.isLastSavedState(f)?m.busy(!1):(m.storeState(f),m.expectedStateId=f.id,n.pushState(f.id,f.title,f.url),m.Adapter.trigger(a,&quot;popstate&quot;)),!0},m.replaceState=function(b,c,d,e){if(m.getHashByUrl(d)&amp;&amp;m.emulated.pushState)throw new Error(&quot;History.js does not support states with fragement-identifiers (hashes/anchors).&quot;);if(e!==!1&amp;&amp;m.busy())return m.pushQueue({scope:m,callback:m.replaceState,args:arguments,queue:e}),!1;m.busy(!0);var f=m.createStateObject(b,c,d);return m.isLastSavedState(f)?m.busy(!1):(m.storeState(f),m.expec
 tedStateId=f.id,n.replaceState(f.id,f.title,f.url),m.Adapter.trigger(a,&quot;popstate&quot;)),!0};if(f){try{m.store=k.parse(f.getItem(&quot;History.store&quot;))||{}}catch(p){m.store={}}m.normalizeStore()}else m.store={},m.normalizeStore();m.Adapter.bind(a,&quot;beforeunload&quot;,m.clearAllIntervals),m.Adapter.bind(a,&quot;unload&quot;,m.clearAllIntervals),m.saveState(m.storeState(m.extractState(d.location.href,!0))),f&amp;&amp;(m.onUnload=function(){var a,b;try{a=k.parse(f.getItem(&quot;History.store&quot;))||{}}catch(c){a={}}a.idToState=a.idToState||{},a.urlToId=a.urlToId||{},a.stateToId=a.stateToId||{};for(b in m.idToState){if(!m.idToState.hasOwnProperty(b))continue;a.idToState[b]=m.idToState[b]}for(b in m.urlToId){if(!m.urlToId.hasOwnProperty(b))continue;a.urlToId[b]=m.urlToId[b]}for(b in m.stateToId){if(!m.stateToId.hasOwnProperty(b))continue;a.stateToId[b]=m.stateToId[b]}m.store=a,m.normalizeStore(),f.setItem(&quot;History.store&quot;,k.stringify(a))},m.intervalList.p
 ush(i(m.onUnload,m.options.storeInterval)),m.Adapter.bind(a,&quot;beforeunload&quot;,m.onUnload),m.Adapter.bind(a,&quot;unload&quot;,m.onUnload));if(!m.emulated.pushState){m.bugs.safariPoll&amp;&amp;m.intervalList.push(i(m.safariStatePoll,m.options.safariPollInterval));if(e.vendor===&quot;Apple Computer, Inc.&quot;||(e.appCodeName||&quot;&quot;)===&quot;Mozilla&quot;)m.Adapter.bind(a,&quot;hashchange&quot;,function(){m.Adapter.trigger(a,&quot;popstate&quot;)}),m.getHash()&amp;&amp;m.Adapter.onDomLoad(function(){m.Adapter.trigger(a,&quot;hashchange&quot;)})}},m.init()}(window)
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjshistoryjsreadmetxt"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/history.js/readme.txt (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/history.js/readme.txt                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/history.js/readme.txt        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,2 @@
</span><ins>+History.js (v1.7.1 - October 4 2011)
+http://github.com/balupton/history.js
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsutiljs"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/js/util.js (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/util.js        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/js/util.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -154,3 +154,121 @@
</span><span class="cx"> 
</span><span class="cx">   return false;
</span><span class="cx"> }
</span><ins>+
+/**
+ * Create wanted options in a select form control.
+ *
+ * @param  aSelect        Select form control to manipulate.
+ * @param  aValue         Value attribute of the new option element.
+ * @param  aTextValue     Value of a text node appended to the new option
+ *                        element.
+ * @return                Created option element.
+ */
+function bz_createOptionInSelect(aSelect, aTextValue, aValue) {
+  var myOption = new Option(aTextValue, aValue);
+  aSelect.options[aSelect.length] = myOption;
+  return myOption;
+}
+
+/**
+ * Clears all options from a select form control.
+ *
+ * @param  aSelect    Select form control of which options to clear.
+ */
+function bz_clearOptions(aSelect) {
+
+  var length = aSelect.options.length;
+
+  for (var i = 0; i &lt; length; i++) {
+    aSelect.removeChild(aSelect.options[0]);
+  }
+}
+
+/**
+ * Takes an array and moves all the values to an select.
+ *
+ * @param aSelect         Select form control to populate. Will be cleared
+ *                        before array values are created in it.
+ * @param aArray          Array with values to populate select with.
+ */
+function bz_populateSelectFromArray(aSelect, aArray) {
+  // Clear the field
+  bz_clearOptions(aSelect);
+
+  for (var i = 0; i &lt; aArray.length; i++) {
+    var item = aArray[i];
+    bz_createOptionInSelect(aSelect, item[1], item[0]);
+  }
+}
+
+/**
+ * Tells you whether or not a particular value is selected in a select,
+ * whether it's a multi-select or a single-select. The check is 
+ * case-sensitive.
+ *
+ * @param aSelect        The select you're checking.
+ * @param aValue         The value that you want to know about.
+ */
+function bz_valueSelected(aSelect, aValue) {
+    var options = aSelect.options;
+    for (var i = 0; i &lt; options.length; i++) {
+        if (options[i].selected &amp;&amp; options[i].value == aValue) {
+            return true;
+        }
+    }
+    return false;
+}
+
+/**
+ * Tells you where (what index) in a &lt;select&gt; a particular option is.
+ * Returns -1 if the value is not in the &lt;select&gt;
+ *
+ * @param aSelect       The select you're checking.
+ * @param aValue        The value you want to know the index of.
+ */
+function bz_optionIndex(aSelect, aValue) {
+    for (var i = 0; i &lt; aSelect.options.length; i++) {
+        if (aSelect.options[i].value == aValue) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+/**
+ * Used to fire an event programmatically.
+ * 
+ * @param anElement      The element you want to fire the event of.
+ * @param anEvent        The name of the event you want to fire, 
+ *                       without the word &quot;on&quot; in front of it.
+ */
+function bz_fireEvent(anElement, anEvent) {
+    if (document.createEvent) {
+        // DOM-compliant browser
+        var evt = document.createEvent(&quot;HTMLEvents&quot;);
+        evt.initEvent(anEvent, true, true);
+        return !anElement.dispatchEvent(evt);
+    } else {
+        // IE
+        var evt = document.createEventObject();
+        return anElement.fireEvent('on' + anEvent, evt);
+    }
+}
+
+/**
+ * Adds a CSS class to an element if it doesn't have it. Removes the
+ * CSS class from the element if the element does have the class.
+ *
+ * Requires YUI's Dom library.
+ *
+ * @param anElement  The element to toggle the class on
+ * @param aClass     The name of the CSS class to toggle.
+ */
+function bz_toggleClass(anElement, aClass) {
+    if (YAHOO.util.Dom.hasClass(anElement, aClass)) {
+        YAHOO.util.Dom.removeClass(anElement, aClass);
+    }
+    else {
+        YAHOO.util.Dom.addClass(anElement, aClass);
+    }
+}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuianimationanimationminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/animation/animation-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/animation/animation-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/animation/animation-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,23 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+(function(){var b=YAHOO.util;var a=function(d,c,e,f){if(!d){}this.init(d,c,e,f);};a.NAME=&quot;Anim&quot;;a.prototype={toString:function(){var c=this.getEl()||{};var d=c.id||c.tagName;return(this.constructor.NAME+&quot;: &quot;+d);},patterns:{noNegatives:/width|height|opacity|padding/i,offsetAttribute:/^((width|height)|(top|left))$/,defaultUnit:/width|height|top$|bottom$|left$|right$/i,offsetUnit:/\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i},doMethod:function(c,e,d){return this.method(this.currentFrame,e,d-e,this.totalFrames);},setAttribute:function(c,f,e){var d=this.getEl();if(this.patterns.noNegatives.test(c)){f=(f&gt;0)?f:0;}if(c in d&amp;&amp;!(&quot;style&quot; in d&amp;&amp;c in d.style)){d[c]=f;}else{b.Dom.setStyle(d,c,f+e);}},getAttribute:function(c){var e=this.getEl();var g=b.Dom.getStyle(e,c);if(g!==&quot;auto&quot;&amp;&amp;!this.patterns.offsetUnit.test(g)){return parseFloat(g);}var d=this.patterns.offsetAttribute.exec(c)||[];var h=!!(d[3]);var f=!!(d[2]);if(&quot;style&qu
 ot; in e){if(f||(b.Dom.getStyle(e,&quot;position&quot;)==&quot;absolute&quot;&amp;&amp;h)){g=e[&quot;offset&quot;+d[0].charAt(0).toUpperCase()+d[0].substr(1)];}else{g=0;}}else{if(c in e){g=e[c];}}return g;},getDefaultUnit:function(c){if(this.patterns.defaultUnit.test(c)){return&quot;px&quot;;}return&quot;&quot;;},setRuntimeAttribute:function(d){var j;var e;var f=this.attributes;this.runtimeAttributes[d]={};var h=function(i){return(typeof i!==&quot;undefined&quot;);};if(!h(f[d][&quot;to&quot;])&amp;&amp;!h(f[d][&quot;by&quot;])){return false;}j=(h(f[d][&quot;from&quot;]))?f[d][&quot;from&quot;]:this.getAttribute(d);if(h(f[d][&quot;to&quot;])){e=f[d][&quot;to&quot;];}else{if(h(f[d][&quot;by&quot;])){if(j.constructor==Array){e=[];for(var g=0,c=j.length;g&lt;c;++g){e[g]=j[g]+f[d][&quot;by&quot;][g]*1;}}else{e=j+f[d][&quot;by&quot;]*1;}}}this.runtimeAttributes[d].start=j;this.runtimeAttributes[d].end=e;this.runtimeAttributes[d].unit=(h(f[d].unit))?f[d][&quot;unit&quot;]:this.getD
 efaultUnit(d);return true;},init:function(f,c,h,i){var d=false;var e=null;var g=0;f=b.Dom.get(f);this.attributes=c||{};this.duration=!YAHOO.lang.isUndefined(h)?h:1;this.method=i||b.Easing.easeNone;this.useSeconds=true;this.currentFrame=0;this.totalFrames=b.AnimMgr.fps;this.setEl=function(j){f=b.Dom.get(j);};this.getEl=function(){return f;};this.isAnimated=function(){return d;};this.getStartTime=function(){return e;};this.runtimeAttributes={};this.animate=function(){if(this.isAnimated()){return false;}this.currentFrame=0;this.totalFrames=(this.useSeconds)?Math.ceil(b.AnimMgr.fps*this.duration):this.duration;if(this.duration===0&amp;&amp;this.useSeconds){this.totalFrames=1;}b.AnimMgr.registerElement(this);return true;};this.stop=function(j){if(!this.isAnimated()){return false;}if(j){this.currentFrame=this.totalFrames;this._onTween.fire();}b.AnimMgr.stop(this);};this._handleStart=function(){this.onStart.fire();this.runtimeAttributes={};for(var j in this.attributes){if(this.attr
 ibutes.hasOwnProperty(j)){this.setRuntimeAttribute(j);}}d=true;g=0;e=new Date();};this._handleTween=function(){var l={duration:new Date()-this.getStartTime(),currentFrame:this.currentFrame};l.toString=function(){return(&quot;duration: &quot;+l.duration+&quot;, currentFrame: &quot;+l.currentFrame);};this.onTween.fire(l);var k=this.runtimeAttributes;for(var j in k){if(k.hasOwnProperty(j)){this.setAttribute(j,this.doMethod(j,k[j].start,k[j].end),k[j].unit);}}this.afterTween.fire(l);g+=1;};this._handleComplete=function(){var j=(new Date()-e)/1000;var k={duration:j,frames:g,fps:g/j};k.toString=function(){return(&quot;duration: &quot;+k.duration+&quot;, frames: &quot;+k.frames+&quot;, fps: &quot;+k.fps);};d=false;g=0;this.onComplete.fire(k);};this._onStart=new b.CustomEvent(&quot;_start&quot;,this,true);this.onStart=new b.CustomEvent(&quot;start&quot;,this);this.onTween=new b.CustomEvent(&quot;tween&quot;,this);this.afterTween=new b.CustomEvent(&quot;afterTween&quot;,this);this._o
 nTween=new b.CustomEvent(&quot;_tween&quot;,this,true);this.onComplete=new b.CustomEvent(&quot;complete&quot;,this);this._onComplete=new b.CustomEvent(&quot;_complete&quot;,this,true);this._onStart.subscribe(this._handleStart);this._onTween.subscribe(this._handleTween);this._onComplete.subscribe(this._handleComplete);}};b.Anim=a;})();YAHOO.util.AnimMgr=new function(){var e=null;var c=[];var g=0;this.fps=1000;this.delay=20;this.registerElement=function(j){c[c.length]=j;g+=1;j._onStart.fire();this.start();};var f=[];var d=false;var h=function(){var j=f.shift();b.apply(YAHOO.util.AnimMgr,j);if(f.length){arguments.callee();}};var b=function(k,j){j=j||a(k);if(!k.isAnimated()||j===-1){return false;}k._onComplete.fire();c.splice(j,1);g-=1;if(g&lt;=0){this.stop();}return true;};this.unRegister=function(){f.push(arguments);if(!d){d=true;h();d=false;}};this.start=function(){if(e===null){e=setInterval(this.run,this.delay);}};this.stop=function(l){if(!l){clearInterval(e);for(var k=0,j=c
 .length;k&lt;j;++k){this.unRegister(c[0],0);}c=[];e=null;g=0;}else{this.unRegister(l);}};this.run=function(){for(var l=0,j=c.length;l&lt;j;++l){var k=c[l];if(!k||!k.isAnimated()){continue;}if(k.currentFrame&lt;k.totalFrames||k.totalFrames===null){k.currentFrame+=1;if(k.useSeconds){i(k);}k._onTween.fire();}else{YAHOO.util.AnimMgr.stop(k,l);}}};var a=function(l){for(var k=0,j=c.length;k&lt;j;++k){if(c[k]===l){return k;}}return -1;};var i=function(k){var n=k.totalFrames;var m=k.currentFrame;var l=(k.currentFrame*k.duration*1000/k.totalFrames);var j=(new Date()-k.getStartTime());var o=0;if(j&lt;k.duration*1000){o=Math.round((j/l-1)*k.currentFrame);}else{o=n-(m+1);}if(o&gt;0&amp;&amp;isFinite(o)){if(k.currentFrame+o&gt;=n){o=n-(m+1);}k.currentFrame+=o;}};this._queue=c;this._getIndex=a;};YAHOO.util.Bezier=new function(){this.getPosition=function(e,d){var f=e.length;var c=[];for(var b=0;b&lt;f;++b){c[b]=[e[b][0],e[b][1]];}for(var a=1;a&lt;f;++a){for(b=0;b&lt;f-a;++b){c[b][0]=(1-d)*
 c[b][0]+d*c[parseInt(b+1,10)][0];c[b][1]=(1-d)*c[b][1]+d*c[parseInt(b+1,10)][1];}}return[c[0][0],c[0][1]];};};(function(){var a=function(f,e,g,h){a.superclass.constructor.call(this,f,e,g,h);};a.NAME=&quot;ColorAnim&quot;;a.DEFAULT_BGCOLOR=&quot;#fff&quot;;var c=YAHOO.util;YAHOO.extend(a,c.Anim);var d=a.superclass;var b=a.prototype;b.patterns.color=/color$/i;b.patterns.rgb=/^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;b.patterns.hex=/^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;b.patterns.hex3=/^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
+b.patterns.transparent=/^transparent|rgba\(0, 0, 0, 0\)$/;b.parseColor=function(e){if(e.length==3){return e;}var f=this.patterns.hex.exec(e);if(f&amp;&amp;f.length==4){return[parseInt(f[1],16),parseInt(f[2],16),parseInt(f[3],16)];}f=this.patterns.rgb.exec(e);if(f&amp;&amp;f.length==4){return[parseInt(f[1],10),parseInt(f[2],10),parseInt(f[3],10)];}f=this.patterns.hex3.exec(e);if(f&amp;&amp;f.length==4){return[parseInt(f[1]+f[1],16),parseInt(f[2]+f[2],16),parseInt(f[3]+f[3],16)];}return null;};b.getAttribute=function(e){var g=this.getEl();if(this.patterns.color.test(e)){var i=YAHOO.util.Dom.getStyle(g,e);var h=this;if(this.patterns.transparent.test(i)){var f=YAHOO.util.Dom.getAncestorBy(g,function(j){return !h.patterns.transparent.test(i);});if(f){i=c.Dom.getStyle(f,e);}else{i=a.DEFAULT_BGCOLOR;}}}else{i=d.getAttribute.call(this,e);}return i;};b.doMethod=function(f,k,g){var j;if(this.patterns.color.test(f)){j=[];for(var h=0,e=k.length;h&lt;e;++h){j[h]=d.doMethod.call(this,f,k[
 h],g[h]);}j=&quot;rgb(&quot;+Math.floor(j[0])+&quot;,&quot;+Math.floor(j[1])+&quot;,&quot;+Math.floor(j[2])+&quot;)&quot;;}else{j=d.doMethod.call(this,f,k,g);}return j;};b.setRuntimeAttribute=function(f){d.setRuntimeAttribute.call(this,f);if(this.patterns.color.test(f)){var h=this.attributes;var k=this.parseColor(this.runtimeAttributes[f].start);var g=this.parseColor(this.runtimeAttributes[f].end);if(typeof h[f][&quot;to&quot;]===&quot;undefined&quot;&amp;&amp;typeof h[f][&quot;by&quot;]!==&quot;undefined&quot;){g=this.parseColor(h[f].by);for(var j=0,e=k.length;j&lt;e;++j){g[j]=k[j]+g[j];}}this.runtimeAttributes[f].start=k;this.runtimeAttributes[f].end=g;}};c.ColorAnim=a;})();
+/*!
+TERMS OF USE - EASING EQUATIONS
+Open source under the BSD License.
+Copyright 2001 Robert Penner All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ * Neither the name of the author nor the names of contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS &quot;AS IS&quot; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+YAHOO.util.Easing={easeNone:function(e,a,g,f){return g*e/f+a;},easeIn:function(e,a,g,f){return g*(e/=f)*e+a;},easeOut:function(e,a,g,f){return -g*(e/=f)*(e-2)+a;},easeBoth:function(e,a,g,f){if((e/=f/2)&lt;1){return g/2*e*e+a;}return -g/2*((--e)*(e-2)-1)+a;},easeInStrong:function(e,a,g,f){return g*(e/=f)*e*e*e+a;},easeOutStrong:function(e,a,g,f){return -g*((e=e/f-1)*e*e*e-1)+a;},easeBothStrong:function(e,a,g,f){if((e/=f/2)&lt;1){return g/2*e*e*e*e+a;}return -g/2*((e-=2)*e*e*e-2)+a;},elasticIn:function(g,e,k,j,f,i){if(g==0){return e;}if((g/=j)==1){return e+k;}if(!i){i=j*0.3;}if(!f||f&lt;Math.abs(k)){f=k;var h=i/4;}else{var h=i/(2*Math.PI)*Math.asin(k/f);}return -(f*Math.pow(2,10*(g-=1))*Math.sin((g*j-h)*(2*Math.PI)/i))+e;},elasticOut:function(g,e,k,j,f,i){if(g==0){return e;}if((g/=j)==1){return e+k;}if(!i){i=j*0.3;}if(!f||f&lt;Math.abs(k)){f=k;var h=i/4;}else{var h=i/(2*Math.PI)*Math.asin(k/f);}return f*Math.pow(2,-10*g)*Math.sin((g*j-h)*(2*Math.PI)/i)+k+e;},elasticBoth:functi
 on(g,e,k,j,f,i){if(g==0){return e;}if((g/=j/2)==2){return e+k;}if(!i){i=j*(0.3*1.5);}if(!f||f&lt;Math.abs(k)){f=k;var h=i/4;}else{var h=i/(2*Math.PI)*Math.asin(k/f);}if(g&lt;1){return -0.5*(f*Math.pow(2,10*(g-=1))*Math.sin((g*j-h)*(2*Math.PI)/i))+e;}return f*Math.pow(2,-10*(g-=1))*Math.sin((g*j-h)*(2*Math.PI)/i)*0.5+k+e;},backIn:function(e,a,h,g,f){if(typeof f==&quot;undefined&quot;){f=1.70158;}return h*(e/=g)*e*((f+1)*e-f)+a;},backOut:function(e,a,h,g,f){if(typeof f==&quot;undefined&quot;){f=1.70158;}return h*((e=e/g-1)*e*((f+1)*e+f)+1)+a;},backBoth:function(e,a,h,g,f){if(typeof f==&quot;undefined&quot;){f=1.70158;}if((e/=g/2)&lt;1){return h/2*(e*e*(((f*=(1.525))+1)*e-f))+a;}return h/2*((e-=2)*e*(((f*=(1.525))+1)*e+f)+2)+a;},bounceIn:function(e,a,g,f){return g-YAHOO.util.Easing.bounceOut(f-e,0,g,f)+a;},bounceOut:function(e,a,g,f){if((e/=f)&lt;(1/2.75)){return g*(7.5625*e*e)+a;}else{if(e&lt;(2/2.75)){return g*(7.5625*(e-=(1.5/2.75))*e+0.75)+a;}else{if(e&lt;(2.5/2.75)){return
  g*(7.5625*(e-=(2.25/2.75))*e+0.9375)+a;}}}return g*(7.5625*(e-=(2.625/2.75))*e+0.984375)+a;},bounceBoth:function(e,a,g,f){if(e&lt;f/2){return YAHOO.util.Easing.bounceIn(e*2,0,g,f)*0.5+a;}return YAHOO.util.Easing.bounceOut(e*2-f,0,g,f)*0.5+g*0.5+a;}};(function(){var a=function(h,g,i,j){if(h){a.superclass.constructor.call(this,h,g,i,j);}};a.NAME=&quot;Motion&quot;;var e=YAHOO.util;YAHOO.extend(a,e.ColorAnim);var f=a.superclass;var c=a.prototype;c.patterns.points=/^points$/i;c.setAttribute=function(g,i,h){if(this.patterns.points.test(g)){h=h||&quot;px&quot;;f.setAttribute.call(this,&quot;left&quot;,i[0],h);f.setAttribute.call(this,&quot;top&quot;,i[1],h);}else{f.setAttribute.call(this,g,i,h);}};c.getAttribute=function(g){if(this.patterns.points.test(g)){var h=[f.getAttribute.call(this,&quot;left&quot;),f.getAttribute.call(this,&quot;top&quot;)];}else{h=f.getAttribute.call(this,g);}return h;};c.doMethod=function(g,k,h){var j=null;if(this.patterns.points.test(g)){var i=this.meth
 od(this.currentFrame,0,100,this.totalFrames)/100;j=e.Bezier.getPosition(this.runtimeAttributes[g],i);
+}else{j=f.doMethod.call(this,g,k,h);}return j;};c.setRuntimeAttribute=function(q){if(this.patterns.points.test(q)){var h=this.getEl();var k=this.attributes;var g;var m=k[&quot;points&quot;][&quot;control&quot;]||[];var j;var n,p;if(m.length&gt;0&amp;&amp;!(m[0] instanceof Array)){m=[m];}else{var l=[];for(n=0,p=m.length;n&lt;p;++n){l[n]=m[n];}m=l;}if(e.Dom.getStyle(h,&quot;position&quot;)==&quot;static&quot;){e.Dom.setStyle(h,&quot;position&quot;,&quot;relative&quot;);}if(d(k[&quot;points&quot;][&quot;from&quot;])){e.Dom.setXY(h,k[&quot;points&quot;][&quot;from&quot;]);}else{e.Dom.setXY(h,e.Dom.getXY(h));}g=this.getAttribute(&quot;points&quot;);if(d(k[&quot;points&quot;][&quot;to&quot;])){j=b.call(this,k[&quot;points&quot;][&quot;to&quot;],g);var o=e.Dom.getXY(this.getEl());for(n=0,p=m.length;n&lt;p;++n){m[n]=b.call(this,m[n],g);}}else{if(d(k[&quot;points&quot;][&quot;by&quot;])){j=[g[0]+k[&quot;points&quot;][&quot;by&quot;][0],g[1]+k[&quot;points&quot;][&quot;by&quot;][1]];f
 or(n=0,p=m.length;n&lt;p;++n){m[n]=[g[0]+m[n][0],g[1]+m[n][1]];}}}this.runtimeAttributes[q]=[g];if(m.length&gt;0){this.runtimeAttributes[q]=this.runtimeAttributes[q].concat(m);}this.runtimeAttributes[q][this.runtimeAttributes[q].length]=j;}else{f.setRuntimeAttribute.call(this,q);}};var b=function(g,i){var h=e.Dom.getXY(this.getEl());g=[g[0]-h[0]+i[0],g[1]-h[1]+i[1]];return g;};var d=function(g){return(typeof g!==&quot;undefined&quot;);};e.Motion=a;})();(function(){var d=function(f,e,g,h){if(f){d.superclass.constructor.call(this,f,e,g,h);}};d.NAME=&quot;Scroll&quot;;var b=YAHOO.util;YAHOO.extend(d,b.ColorAnim);var c=d.superclass;var a=d.prototype;a.doMethod=function(e,h,f){var g=null;if(e==&quot;scroll&quot;){g=[this.method(this.currentFrame,h[0],f[0]-h[0],this.totalFrames),this.method(this.currentFrame,h[1],f[1]-h[1],this.totalFrames)];}else{g=c.doMethod.call(this,e,h,f);}return g;};a.getAttribute=function(e){var g=null;var f=this.getEl();if(e==&quot;scroll&quot;){g=[f.scrol
 lLeft,f.scrollTop];}else{g=c.getAttribute.call(this,e);}return g;};a.setAttribute=function(e,h,g){var f=this.getEl();if(e==&quot;scroll&quot;){f.scrollLeft=h[0];f.scrollTop=h[1];}else{c.setAttribute.call(this,e,h,g);}};b.Scroll=d;})();YAHOO.register(&quot;animation&quot;,YAHOO.util.Anim,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamajaxloadergif"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/ajax-loader.gif (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/ajax-loader.gif                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/ajax-loader.gif        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,41 @@
</span><ins>+GIF89a  \xF3\xFF\xFF\xFFfff\xDC\xDCÜ´\xB4\xB4\xD2\xD2\xD2\xC2\xC2†\x86\x86\x99\x99\x99\xE7\xE7\xE7\xEE\xEE\xEE\xD6\xD6\xD6wwwhhh!\xFF NETSCAPE2.0!\xFECreated with ajaxload.info!\xF9        
+,  \xE7\xC8Iia\xA5\xEA\xCD\xE7bK\x85$\x9DF \xA3RA\x94T\xB2,\xA52S\xE2*05//\xC9m\xA2p!z\x93\xC1\xCC0;$\xC50C\x9C.I*!\xFCHC(A@o\x83!39T5\xBA\\xD18)\xA8+\x87\xA0`\xC1î´²dwxG=Y
+g\x83wHb\x86vA=\x920        V\\x9C\\x88;        \xA4\xA5\x9C\x9F;\xA5\xAA\x9BH\xA8\x8A\xA2\xAB\xAC\x9D\xB3\x980\xB6\xB5t%\x91Hs\x89\x8BrY&lt;H.\x81ʼn\xB7\x96        \xBE\x92b\xBFZb\xC7OEg:\x98GY].\xC0=\xDAA\xDFOQ\x9Cs\x86\xE6\xEA\b\xC3h.9\xEC=sg\xF5\x9Ec\x8C\xF3e\xE2\xD8*\x8FÖ†f7D!\xF9        
+,  \xEA\xC8IiY\xA4\xEAͧYF5\x9DF\x90Ô¢RÔTbG\xBAJ\x85\xBB\xC0\xEC\xACL\xAA\x9Dd\xE1\xF0&amp;\x85Ymx莔\xC3  \ @\x98\x80\xEA\xC1\x9A \xB01\xFC&amp;R\x83\xB1\x92H
+41Q\xB4\xDB|V%zv#j0\x87
+\x8El\x8CGg{0~\x89&lt;\x81&lt;        \x84[\xA2[\x87h\x91x\xA5\xA1G\xA9
+y\xA9\xA2\xA9\xA7\xAF\x87\xA3\xB6\x96[\x9E0\x97\xBA\xBCG\xB4\x91\xA8\xA6P\x86z\x9C\xC7hɾ\xA1Ękz\xC2i\x97\xC9y\x8E\xA0\xD1\xCAh|z\xD5h\x92GÝ„\xE2VÅ¢\xAF\x81\xE9\xED\xB9\xEB\h\xE7[\xAF\x8E\xEFǤ\x88\x8A\xF5&amp;\x95+\x91\xA0W\x9E7\xB78\xE0\xC8!!\xF9        
+,  \xEE\xC8I)1\xA4\xEA\xCD\xE71G5d]\x85(\x95\xA1RDz\x94T2\x8C\x94jL\x84{\xC3\xD3&lt; [\xD05\xE0M\xBE\xE0
+0\xD0)\x85
+ L\xB8\xA4I\x86\xF0m\x85\xCDE\xA8\xC7`\xB4p\xA5U
+ \x81^f%\x82^\xB1\xC8\xE4u ;zz}0\x84X        
+\x89S0ewyk&lt;\x9C%        \x9FO\xA3\xA3\x89\x93        \x91\xA6z\xA4\xAA{\x92\xAD\xAC\xAA|\xA9\xAA\xA4\xB6\xA3\xA2%\xB9\x9A\xBB\xBDF\xAFi\x8C1”0\x88\x89\x80\x87\xA6˼Y\xB4\x9B\x9A\xC38\xC4x\x8A\xBF\x92\x8C        z\x9F\xC9@\x89\x89\xD7&lt;Ý«\xE2\x9A\xC7\xC1\xDE\xE3\xE8\xAF\xBE\xEC8\xF1\xE7Y&lt;\xAF\x8C\xEAÉ¥8\xF3\x87\xA7\\x87P$\xB5\xBB\xA5!\x92\xC1+!\xF9        
+,  \xE7\xC8I\xA9\xA2\xEA\xCDgEU\x9D\x96 Õ R\x87a\x94TBÙ¤\xE1\xBEp&gt;'\xB6\x95\xA4e\xF5$\x88\x99&quot;\x88\\x87#E1Cn\x80ÄŽ\x83\xC9~\xD7\xD5J,\xDC,Aa\x95\xAA\x9DUw^4I%P\xDD\xDEu Q33{0\x81i1T\x85Ggwy}%\x88%'R\x9C\x9D \xA0\xA1         \x8E\x85\x8C=\xA1\xAA \xA6\xA7\x9D\xAB \xA3\xA5\xA73\x9E\xB6G\x96%\xB9\x94p\xBA\xBD0\xA6
+\x99\xB3JRo\x855Ȇ0IĦmyk\x88\xC3x\xCDT\x88_}\xC8(\x8F\x85\xD7^\xE2\xE2yK\x9D\x8Es\xB5\xEC\x9C\xE9&gt;i_\xA8%\x8E\xD5\xEEn\xFA=\xD9\xE2\xDA\xCAq\xD84e\xCD-M¤D!\xF9        
+,  \xEE\xC8I)*\xA8\xEA\xCD')E\xA5d]\x95\x90\xA6\xC3PR        A\x94:!\xAD\xFBzr\x92\x82\x93\x9Cbw\x93+%6\x80&quot;G\xA4(d$[&quot;\x87\x92\xF8J\xB1\xC0Fh\xAD\x90aQP\x8D`p%†/BFP\cU+\xE2+?T\xD0tW/pG&amp;OtDa_sylD'M\x98\x99 \x9C\x9Dq        \x8Atc\x98\x9D\xA5 \xA1\xA2\x99\xA6 b\xA0\xA22\x9A\xB1D\x93\x90M :\x91\xB5\xB9\xB9 \x8Fd\xA1\x88%\xC0 \xA24%s) \xC0\xBB\x91u\x83\x83E3\xB8 \xA3YU\x80\x8BtÚ–\xE6\xE6\x91\xC6D\x8A$\xE6JiM\xED&lt;\xE0Y\xE0;\x8AØ°\x80\x98d&lt;\x93 O\x82tX\xF2&lt;q'+B!\xF9        
+,  \xF3\xC8IiR\xA9\xEAͧ&quot;J% \x9D\x96\x90\xA1\xA6EQZ\xAA\x90\xAE\xD2\xEFLd\x92\x8A\xF7-Y\xAE\xA6
+\xF5h\x82\x96k\xE8Q\xA1|\x80\x845\xE1u\xBE 4Y\xF8I\x83\xAB\xA0N+bW \x87\x8D\x80u\x91\x875\x9B
+\xEE\xC1r\x82\xF6        \xAC%yb&gt;^%o/rvl9'L\x92\x93\x96\x97;\x86\x879\x97\x9F\x9B\x9C\x93\xA0\x99\x85\xA3\x94\xAA9\x80%\x8D \x8Bi9\xB3\xB3\x9D\xA8 C\xB9 &quot;\x86B B\xB9\xB5Ds\x8F \xCE^Xf}$P        \xD7 {L\xDE?P\xCA \x94\x9BO4 \xD7\xD0\xC0E\xD3\xF3å’›V\xEB$\xB8\xE6\xCAdJ\xD0#)\x85pV\xC2\xC0$!\xF9        
+,  \xEB\xC8IiR\xA9\xEAͧ&quot;J\x85d]\x95 \xA1R\xC2ZN\x89*P*\xAB\xE1;\xD5$P{*\x94N\x82\xC0\xED\EÐ\xF2!1UO2\xDDD        \x99_r6I\xF6b
+\xA1\xA4\xE5\xD4\xC4H\x97\x9A8        B\x97;        \xB2\xAC&quot;'\xAA\x9CZ\xDB\xDAt\xBD\x92b\x80K#C'K\x88\x89\x8C\x8Dw}?\x88\x8D\x94\x91\x92K\x95\x8Fiz6\x8A\xA0:x\x82KAC\xA8\xA8\x9F&amp;}9\xAEtz\ \\xB6\xA8\xAAD5;x \xB9\xA8\xB1Q\x81d( \xD6        \xCB \xB1KW\xD6 \xCA \x8AMB\xE0\xCB\x88I\xB4\xE9ÚˆM=\xF1ˤs\xF8⸽8Da\x83\xA1J`@LG!\xF9        
+,  \xEF\xC8IiR\xA9\xEAͧ&quot;J\x85d]\x95 \xA1R\xC2ZN\x89*P*\xAB\xE1;\xD5$P{*\x94N\x82\xC0\xED\EÐ\xF2!1UO2\xDDD        \x99_r6I\xF6b
+\xA1\xA4\xE5\xD4\xC4H\x97\x9A8        B\x97;        \xB2\xAC&quot;'\xAA\x9CZ\xDB\xDAt\xBD\x92b\x80K#C'K\x88\x89Gziz6\x88\x8F8}z\x89\x92\x8D\x94~\x8A\x9B%X\x84K9\x83:\xA2\xA8\x810}\xA4%        \xA8tz\B\xB1\xA4lc L\xA2bQ\x81 \xC7 \xD1        \xC5\x90\x88\xCE \xD1 \xC5lj \xCE\xC2\xDDųK\xCE\xDE\xE8\xB8ň\xE4 \xEC\xE7\xD2\xE9\xC5x\xCE(È›P\xE0\x9AX ,\xC8\xE9Ö‚|/&quot;!\xF9        
+,  \xF0\xC8IiR\xA9\xEAͧ&quot;J\x85d]\x95 \xA1R\xC2ZN\x89*P*\xAB\xE1;\xD5$P{*\x94N\x82\xC0\xED\EÐ\xF2!1UO2\xDDD        \x99_r6I\xF6b
+\xA1\xA4\xE5\xD4\xC4H\x97\x9A8        B\x97;        \xB2\xAC&quot;'\xAA\x9CZ\xDB\xDAt\xBD\x92b\x80K#C'K\x88\x89Gziz6\x88\x8F8}z\x89\x92\x8D\x94~\x8A\x9B%\x85:\x84A/ C} \xA6\xA6\x86u\\xAF \xB3h}b\xA5\xA6 D\xC2\xC3]=\xA6\xA8 \xA8\xD6        \xC8\x81V)\xD3 \xD6
+ÚŠ\xD3\xD0\xE2\xC89C\xD3\xE3\xEBD\xE6K\xE8 \x90\xF5\xED\xBCK\xA6\x85\xA2u\x8D        \xB7\xC7*00\x90S\xCAtD!\xF9        
+,  \xEB\xC8IiR\xA9\xEAͧ&quot;J\x85d]\x95 \xA1R\xC2ZN\x89*P*\xAB\xE1;\xD5$P{*\x94N\x82\xC0\xED\EÐ\xF2!1UO2\xDDD        \x99_r6I\xF6b
+\xA1\xA4\xE5\xD4\xC4H\x97\x9A8        B\x97;        \xB2\xAC&quot;'\xAA\x9CZ\xDB\xDAt\xBD\x92b\x80K#C'K\x88\x89Gz \x90\x91\x89z5
+\x91\x97 \x93\x94\x8D\x8F\x98\x8A\x9FC\x85:        \x84A/ C}\xAA\xAA\x86u\\xB3 \xB7Eh}b\xA9\xAA6\xC5[=\xAA\xA5\xB8\xA5\xD7Wx&amp;)\xD4\xD7\xD2I9\x88Ô¬\xE1@oC\xD4\xEAT?K\xDE\xC6\xE9\xD8d\xDB\xEF\xF2]\xF8\xC1B7\xA1\xC0\x82\xA06ЫD!\xF9        
+,  \xE8\xC8IiR\xA9\xEAͧ&quot;J\x85d]\x95 \xA1R\xC2ZN\x89*P*\xAB\xE1;\xD5$P{*\x94N\x82\xC0\xED\EÐ\xF2!1UO2\xDDD        \x99_r6I\xF6 Æ€\xD4\xC4H\x97\x9A03\xAA\xB3\x94hÕ¸\x83\x9Ba\xC0\x97j U {CIkmbK#\x87cK\x91\x92\x808        \x84{a\x92\x958\x99n\x9B\x95\x98\x99\x93\xA5\x87\x82V\x90:\x88/q:M\x81
+\xAF\xAFCu\x80~\xB7\xB8\x89Eh\xB3k\xAE\xAF6        \xBD[_\xAF\xB1\x836P&lt;/U\xD9YHF\x92\xE19?M\xC2%
+\xE1G\xCB\xCC\xE9C\xE1k\xF3v\xA8\xD9\xF1&gt;.]\xFA6\xA9\xF0!\x87)V\x88!\xF9        
+,  \xF0\xC8IiR\xA9\xEAͧ&quot;J\x85d]U \xA1R\xC2ZN        \xC3\x94J\xC0j\xF8N2sK6\x8F
+\xB1\x9B d\x8BI\x80\xC8) 
+L\xD8H\xB0W\xA1G 6        \xCAKX\xA6\x83ì ±\x92.6\xA2d\xB0\xA8~z\x93h\xD9\xC2uur/6 X5\x83I;_\x86t O#E        {O\x9B\x9B\x889V\xA2\xA3\x9C\x9E9\xA3\xA84\x9D\x9E\xA1\xA9\x9C\xB1\x9B\x97;V\x96C/
+\x80\xB96\xBBØ~*\xBD'\xC3\x8AMo\xB8\xBA\xBB\x80n\xCE\xC7bX\xC2:~]+V*\xCDm\xE5K_\xE0O\xD1rK\xF1\xB3N@.\xEA\x9B\xD1d\xF9~\xCEqЦ\xE4\x81D\xA2BÖ‹ 5D;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamascgif"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/asc.gif (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/asc.gif                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/asc.gif        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,2 @@
</span><ins>+GIF89a        \xC4A@@zzzppp544ONNbaa\x8B\x8B\x8BdddWWW\x84\x84\x840//322\x90\x90\x90\x87\x87\x87KKKRRRonn\x8D\x8D\x8D988^^^&lt;;;~~~\x92\x92\x92\xFF\xFF\xFF!\xF9,        .\xE0%^\xC03\x9Eh\xD0,(\xEAXVÑŽJG\xD2|!0 \xCDCh\x86\xB0\x8A\xC2@\xC2\xA7IeJ\x9D
+N!;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamautocompletecss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/autocomplete.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/autocomplete.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/autocomplete.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+.yui-skin-sam .yui-ac{position:relative;font-family:arial;font-size:100%}.yui-skin-sam .yui-ac-input{position:absolute;width:100%}.yui-skin-sam .yui-ac-container{position:absolute;top:1.6em;width:100%}.yui-skin-sam .yui-ac-content{position:absolute;width:100%;border:1px solid #808080;background:#fff;overflow:hidden;z-index:9050}.yui-skin-sam .yui-ac-shadow{position:absolute;margin:.3em;width:100%;background:#000;-moz-opacity:.10;opacity:.10;filter:alpha(opacity=10);z-index:9049}.yui-skin-sam .yui-ac iframe{opacity:0;filter:alpha(opacity=0);padding-right:.3em;padding-bottom:.3em}.yui-skin-sam .yui-ac-content ul{margin:0;padding:0;width:100%}.yui-skin-sam .yui-ac-content li{margin:0;padding:2px 5px;cursor:default;white-space:nowrap;list-style:none;zoom:1}.yui-skin-sam .yui-ac-content li.yui-ac-prehighlight{background:#b3d4ff}.yui-skin-sam .yui-ac-content li.yui-ac-highlight{background:#426fd9;color:#FFF}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssambackhpng"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/back-h.png (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/back-h.png                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/back-h.png        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,6 @@
</span><ins>+\x89PNG
+
++IHDR(Q/\xB1s3sRGB\xAE\xCE\xE9gAMA\xB1\x8F \xFCa cHRMz&amp;\x80\x84\xFA\x80\xE8u0\xEA`:\x98p\x9C\xBAQ&lt;\xCCIDAThC\xED\xD5\xDD
+\x82P\xE0\xE9\xFD_P\xA2\x88\x8A$D\xC9$\x8D~\xF0T\x8F0C57\xB3\xCC\xE5. guQJ\x81\xA5Þ‹-\xCB\xD6\xB3m\xF1l*\x98\xF6\xCEx\x9A
+S\xE1n*\xDCL\x85i\xBAZ\x82\xCB8Z\x82\xF30X\x82S\xDF[\x82\xB6\xED,\xC1\xB1i,\xC1\xA1\xAE-\xC1v\xB7\xB7\xAB\xF5\xC6T\xD5Ò’,\xFE{\xA8C\xFD\xB3+\xCF\xE3\xCA\xE3\xCA\xE3\xFA\xDA?4\xE7\x94s\xCA9\xE5\x9C\xE4+\xC8D\xA6cCÍŠ\xC9\xFD\xA1\x96\xE9\xD8\xC1P\xB3br\xA8e:v0Ô¬\x98\xDCj\x99\x8E 5+&amp;\xF7\x87Z\xA6cCÍŠ\xC9\xFD\xA1\x96\xE9\xD8\xC1P\xB3br\xBF\x8D\xFA|F\xA9o\x8B ÒŒIEND\xAEB`\x82
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssambackvpng"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/back-v.png (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/back-v.png                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/back-v.png        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,6 @@
</span><ins>+\x89PNG
+
++IHDRQ(        \xC0\x81h        pHYs\xC3\xC3\xC7o\xA8dsRGB\xAE\xCE\xE9gAMA\xB1\x8F \xFCa cHRMz&amp;\x80\x84\xFA\x80\xE8u0\xEA`:\x98p\x9C\xBAQ&lt;\xBBIDAThC\xED\x98Q
+\xC20D\xEB\xFD/X\x8A&quot;V,R*\xD6b+\xC9f\x93\xAE{\x86\xDF\xC8\xE4#K\x92yC)\xA5\xEAW\x9B\x8E1\x9A\xD8J\xD5Q\xBFSԠ\xC1d\xB0R\x91D\x{18D149}\xBD=֘\x95\xF5$&quot;\xDE{\xE7ܲ|\xDE\xF3\xFC\x9A\xA6\xE78\xC3\xE3\xDE\x{1F7BBB}\xB4\xD7\xE3\xE9\\xD7M\xA1\xA3\xA2gΙ\xBB\xCD{\xC6Ê\xF2p|&gt;\x93I\xC8adϲ\x827\xBE\x8Do\xE3\xDB\xF86\xBE\x8Do\xE7\xFEg\xAB`\xAC\x82U\xB0
+V\xC1\xAA\xFC\xBE\xE13|\x86\xCF\xF0&gt;\xC3g\xF8 \x9Fsxd\x92\xFF\xC8$+Sy\x9D\xB0\xC4\xDFIEND\xAEB`\x82
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssambarhpng"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/bar-h.png (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/bar-h.png                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/bar-h.png        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,4 @@
</span><ins>+\x89PNG
+
++IHDR(P\xE4\x{D816}sRGB\xAE\xCE\xE9gAMA\xB1\x8F \xFCa cHRMz&amp;\x80\x84\xFA\x80\xE8u0\xEA`:\x98p\x9C\xBAQ&lt;\xEBIDAThC\xED\x95= \x81qÅ/#\xA5\xA4 \x92\xE4a\xB1\xC8`\xB0$Iy\xFDJ&amp;\x8B\xC5b3É \x94R^\xF2m\xF0\xEE        g9O\xBF\xF1\xDEN\xFD\xBA\xE7\xFF\xA4\xEA\x8B'$\xDF;X$\xA9Ͳ\xE0\xDA\xFC!\x92\xD4w(\x92\xD9]\x92\xE9M\x92\xC9U\xAA\xE3\x8B]pet\x96\x80\xF2\xF0$\xA5\xC1QJ\xFD\x83{{        (twt\xC1\xF9\xCEVr\xED\x8Dd[k        \xC84W\x90n,%8\xF8oÚ­Úª\xD6r\x97\x8F\xCB\xC7\xF5\xB5\xA8\xEB\xE4:\xB9N\xAE\xDD? \xB4\xBA\xE8\xA2UG\x8D\xD1\xF3VM\xAB\x8B.Zu\xD4=oÕ´\xBA\xE8\xA2UG\x8D\xD1\xF3VM\xAB\x8B.Zu\xD4=oÕ´\xBA\xE8\xA2UG\x8D\xD1\xF3VM\xAB\x8B.\xBE8vR\x87\xAEEIEND\xAEB`\x82
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssambarvpng"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/bar-v.png (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/bar-v.png                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/bar-v.png        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,5 @@
</span><ins>+\x89PNG
+
++IHDRP(\xE6\xEAV        pHYs\xC3\xC3\xC7o\xA8dsRGB\xAE\xCE\xE9gAMA\xB1\x8F \xFCa cHRMz&amp;\x80\x84\xFA\x80\xE8u0\xEA`:\x98p\x9C\xBAQ&lt;\xECIDAThC혽
+\xC20F\xEBˈ \x88\xE0 E\xC4\xEA\xE2&quot;.&quot;&quot;\x82\xBF\xAF\xE4\xE4\xE2\xE2\xE2\xE6$\x82 \xFE\xE0\xA3h\x9Bo]\xDC\Zñ„¯¤\xCDvIs\xCE%\x89\xCA\xF4漆\xB5\xA2\xAF\xD6Z}\xC2\xC9\xFDcD\xC28\x88H&lt;t\xD1\xF8w        |\xA3_\xFCp\xE5g\x86\xFCNyr\xD5x\xE3\x8B7:{\xC3Sip\xD4\xFB\x87Bo\xEFvwng\x9Boor\xAD\xB5&amp;\xDB\e\xCBt}\x91\xAAÍ“\xD5\xD9Å¡`v\x98_\x9A3 \xB4b\xCCm(\x8D\x87i&lt;\xE8\xB4b\x8C\xA8Ïžh-\xA0\xB4\x80V\x9C\xEF\xA04\x94\x86\xD2PJC\xE9\xDD\xA1%\xB4\x84\x96\xD0ZBKh)\xBAS\x80\x87\xF10\xC6\xC3\xD1\xE8 \xFF\xFD\xB4\x9EN\x81+\xB8H\xFF\xA2\xC3IEND\xAEB`\x82
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssambghgif"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/bg-h.gif (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/bg-h.gif                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/bg-h.gif        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1 @@
</span><ins>+GIF89a\xD1\xA2\xE1\xE1\xE1\xC9\xC9ɧ\xA7\xA7\x89\x89\x89\xB7\xB7\xB7\xD7\xD7\xD7\xFF\xFF\xFF!\xF9,\xD1\x99h\xBA\xDC\xFE0\xCAI\xAB\xBD8\xEBÍ»\xFF`(\x8Edi\x9Eh\xAA\xAEl\xEB\xBEp,\xCFtm\xDFx\xAE\xEF|\xEF\xFF\xC0\xA0pH,\x8FȤr\xC9l:E\x83\xA8tJ\xADZ\xAFجv\xCB\xEDz\xBF\xE0\xB08+x\xCE\xE8\xB4z\xCDn\xBB\xDF\xF0\xB8|N\xAF\xDB\xEF\xF88\xC0\x91\xEF\xFB\xFF\x80\x81\x82\x83s{\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x90O\x9D\x9E\x9F\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB88        
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssambgvgif"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/bg-v.gif (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/bg-v.gif                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/bg-v.gif        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,2 @@
</span><ins>+GIF89a$\xE0\xB3        \xEB\xEB\xEB\xF5\xF5\xF5\xED\xED\xED\xDB\xDB\xDB\xD3\xD3\xD3\xE9\xE9é··\xB7\xA7\xA7\xA7\xD7\xD7\xD7\xFF\xFF\xFF!\xF9        ,$\xE0\xFF0\xC9I\xAB\xBD8\xEBÍ»\xFF`(\x81\xF8&quot;\x98Ý‘,\xE7&quot;p\xAC͵\x8D\xE1z\xC6\xF7\x97\xB0&quot;N\x8A\xC6Ò¸6\x81\xCF^T7\xB5UcWVÖ´uC_P\xF83\xF6\x94[\xAF$\xE5,K\xAB%\xECM\xFC\xE6~\xCF}u\xF5}\x97O\xEE\x83}L\x81N\x83P\x85R\x87T\x89V\x8BX\x8DZ\x8F\\x91^\x93`\x95b\x97d\x99f\x9Bh4op\x9Dm\x9F\xA0\xA6D\xA2r\xAAt\xA4v\xACx\xAEz\xB0|\xB2~\xB4\x80\xB6\x82\xBA\x84\xBC\x86\xBE\x88\xC0\x8AŒĎÆȒʔ̖ΘКҜԞ9\xB3֣طګޭܻ\xE2\xBD\xE4\xBF\xE6\xC1\xE8\xC3\xEA\xC5\xEC\xC7\xEE\xC9\xF0\xCB\xF2\xCD\xF4\xCF\xF6\xD1\xF8\xD3\xFA\xD5\xFC× Jp\x9D\x98
+\,\xDB\xA2ZC\x90\xA1\xC1Z\xBFE \xA7\xB0\xE1\x8B\xA1\xE6\x9Ax\xB0\xA2Æ\x8E r\x84\xE8q\xE4Æ’(Ka Ò¡I\x90/E\xA6|\xD5\xF2bÍŒ1]\xCEÌ–\xD3fO\x9C;\xBB\xFDd9t\xA1Ï ã–Sz\x8Ei:\xA7ë ¶\x93\xFA\x8Ej&lt;\xAB\xF3\xB0\xD6\xD3z\x8Fk&gt;\xAF\xFB\xC0\xF6\xFBO\xE5M\xA2d\x9A-\xBA\xD2(еi%Æ¥\xB7.M\xB6gÝ¢\xB5\xCBsnG\xBEB\xFD\x92\x9C\x94\xF0R\xC3M?U\x95\xF1T\xC7UAH1`,k\xDE\xCCYM;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamblankimagepng"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/blankimage.png (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/blankimage.png                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/blankimage.png        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,16 @@
</span><ins>+\x89PNG
+
++IHDRKK\x90\x8A\xD8gAMA\xD6\xD8\xD4OX2tEXtSoftwareAdobe ImageReadyq\xC9e&lt;\x80PLTE\xEF\xEF\xEF\xE3\xDD\xC9\xE8\xE8\xE8\xCD\xCD\xCD\xFF\xFF\xFF\xA7\xBA̸\xB8\xB8\xD9\xD9\xD9\xE9\xF3\xF5\xE6\xE6\xE6\xE2Ƚ\xBDŹ\xC4\xC4\xC1\xCBÅ·\xB4\xD5\xDD\xC3\xDD\xE4\xE1\xE1\xE1\xC8\xDA\xDC\xD0\xD0\xD0\xD3\xD2\xCA\xEE\xEE\xEE\xDB\xE1\xE7\xE7\xE2\xCB\xD5\xD5Õ®\xD3\xDC\xE4\xE2\xDB\xCB\xCA\xC6\xD3̳\xB7\xC4\xC8ß¿\xB6\xA8\xB3\xA9\xF5\xF5\xF6\xDE\xDEÞ«\xC0\xD3\xD9\xE4\xED\xEC\xEC\xEC\xEC\xE8\xD5\xDD\xDC\xD5\xEA\xE5\xD0\xF9\xF9\xF9\xE3\xEFòš£š\xED\xEA\xD8\xDCÕ·\xAE\xC9Ü©\xBD\xCF\xE8\xE7\xE3\xCC\xE0\xE9\xD9\xE1\xDF\xEC\xE9\xE4\xEA\xE6Þ¼\xD9\xDF\xD2\xE4\xEA\xF1\xF2\xF2\xF6\xF6\xF7\xD1\xDE\xDD\xDB\xD9É­\xC6\xD9\xE6\xE5á´¾\xB0\xF5\xF8\xF9\xADÇ¿\xCF\xCE\xC8\xEF\xEC\xE7\xB0\xC6\xD4\xCD\xD0\xC8\xDC\xC0\xAF\xC5\xCA\xC2\xE2\xE1\xCF\xF3\xF1\xEE\xF0\xF5\xF6\xFB\xFD\xFD\xE5\xEC\xED\xDB\xE7\x{D96D}\xA4\xF8\xF8\xF7\xD5\xE2\xE3\xE1\xD7\xC1\x9B\xAD\xA5\xAE\xBCÆ·\xB7\xB7\xED\xED\xED
 \xD9\xDD\xD8\xF1\xF3\xF4\xE0\xE4\xE0\xC1\xCA\xCA\xC8\xC7\xC4\xD6\xDA\xD3\xD8\xD6\xCE\xED\xEE\xEF\xEE\xEF\xF0\xE1\xDE׸\xBD\xB6\xF4\xF4󯼴\xF8\xFB\xFB\xF1\xEE\xEA\xDD\xEC\xF0\xD6\xE8\xED\xFD\xFD\xFC\xEB\xEB\xEB\xF0\xEDÝŸ\xA7\x9E\xFC\xFB\xFA\xE1\xE2\xE4\xF7\xF6\xF5\xD1\xD5\xCF\xEA\xED\xEC\xDA\xD8\xD1\xD4\xD5\xCF\xF0\xF0Ý—\xA0\x97\xE8\xE8\xE5\xFA\xFB\xFB\xE7\xE8\xDF\xF7\xF7\xF7\xE3\xE3\xE3\xE4\xE4\xDE\xCC̹\xC2\xD1\xD3\xD3\xD2\xD2\xDB\xDCÛ¯\xB6\xAD\xCE\xD2\xC1\xEF\xF0\xF0\xD9Ö¾\xE9\xEA\xEB\xF6\xF3\xF0\xB8k\x88NIDATx\xDA\xEC\xD8k[\xDAX`H&quot;AI$E%\x84\x9A\x8E8\x82\xA0RM\x9DjÅŠ\x94\xE2!\xA5Ru\xDA`\x8F:\x95b\x91\xF9\xEB\xEF\xDA;\xA1Ph;\xED\x87\xF7C{\xB5.o\xD7Z{\xEF`j\xB1\xFD\xB8Xl\x96\x95\x9F\xD6O\xEB\xFF\xC1\xE2 \xA2\xFD\xFDÇ•\xA2ÑŽ\xA0\x92t\xE9\xFB, \x82\xAA\xD2i\xCA\xFD AÕŽ@:i i7\xB8\xFFh\x991N\xBA\xA3Q8\x9A\xFE\x9F,I\xBD\xE5\xF4\xCAÝ™{AQ\x8D*\xF7\xCD\x86\x8C\xCA5\x9D\x8C/\xA4\xA6\xA6\xDCu$|\xA3\x85\x87D0&lt;I\xE4qEBÙ¤(=\xFA+\x96YO62\xDA\xE
 CB\x90\x97\xD0$\xC1\xDD\xD0\xC25h\x95\xF4\x84\xF1\xAC7_\xF6 H\x8A\xA2\x8E&lt;7\xB2*E\xED\xB0#uz\xE1vM}hr\xC4v\xEDZx\xD9\xEC:\xC9\xEBi \xAD B\xAEn\x93n\xB4\x85 \x82\xA8\x84\xA1\x93\xE1\x8A6\xC7\xC7\xE7\\xB0\x92\xCF( I\xF7\xABtÔ€\xEE\xCC+BS\xEE\x85\\x9AN\xA5\xD0J\x8E\xB0\x9Ep\xD1j\x95a\xAAZ\xE4vϹ\xFBg\x9E\x837\xB5\xDC#\xAFw\x8B\xA2\x88\xAF\xAE$X\xA5*a\xC7\xC7+v\xA4Q\xD1z\xE2\xEDYs\xF8\xE7\xECx\xBDÞFX@y\xB5`~\xE7\xF8        \xAC}\x855F\xEEJ\xBDGTnË»\xB8\xB8\xF8,1\xCDq_\xB5:DC\xA0\x99ub\x8E\xE9|\xE7\xD1e\x99ua)O\xB5Í­G;A\xDEST\xD5\xF3 YvM3\x8AZ\xC0\xB3YX\xA1(K6QV\xCEJ\xA5\xBC\x8B\xE3[;\x8B^,\xED\xEF\xEF_hT\x8D\xB1\xF6^\x9C&gt;\xCB\xDF\xF2S\xD48Hw\xE0,\x9F\xB4\xF6ĥŸ{S^\xC3A\xD2\xFEe5I7bg\xB8n\x8F\xDD\xDF&quot;\xE3T.5\x95\xDA\xD4\xC6\xBC\xB1\xC4E@\x88\xF1\xFC\xF9&quot;\x9E\x91Q@\x97\x81l\xE0&gt;\xACd\x83 \xCDug\xDF\xD0i\x86$p\x93.\xB7\xCBU\xB6'\xB2g\xEC\xB9\xE2T\x9Ev[\xDB]\xE92\x99\xCC&amp;\xE7_SqZ\xB2J\xB6\xA2\x84]\xA0[ n\xD2\xE5r\xFD}\x96\x
 B8\xB8\x88\xB1lYq\xAA\xECS\xA3\xA2\xEC\xEE\xF1y&quot;\x99\x8C%!o5\x8A\xF6ι\xE7z+\x8A-[        \x9A\xA4\xFD Y\xA7rnWêž\xB8\xB8&lt;c\xCF\xF3\xEC.j+\xE28\xAE$\x93Ç¿'+\xB1\xFBU-\xD7\xD7~\xFD\x94\xDB`U+\x8B\xC3M\xB6H\x98‹\x94\xB7r\x91Xʼn\xC3+
+[(\x9BL:B,\xFA\xEB, \xC4sqR\xBA\xECY\x8F\xFA\xAC^\x93\x9B0\xF6D\xF6\x9C\xEDb\xAA²\xD4X`\xFD\xE0]\xA5\xE2|\xBC^\x89U\xFE\xC9i\xBA\xB5p\xF0\xB4\xB96lYJx%2Ci\xFBÙ„=c\xDEi\x86gË€\x89\xF9@\xA5\xE2x\xFC\x98\xAF\xC4\xE6k\xB5+\xC9\xD2\xDD/YP\xEC|\xDCd:\x9B\xC8\xF2\xBF\xB3\xCE^TX\x81rl~&gt;\x8B\xC5\xF8P\xE8\xF8,\xC73\x8C(J͵\xB5/X%Ô¤\x9Fa(*kh\xDBV\xA7\xE3I\x9Fdz\xA8mR\xCC?|\x9B\xAF\xD7\xF4\xA5?ÅŠ\xD5\xEC\xB2o\xF6 \)p\x93G\x94V\xCD\x9E\xCFl\xAB\xCA\xF3\xED+gu\xB0\xA6|\xB92\xFFO&gt;\xBF\x92\x8F\xD7\xFDeQ}\xCD\xE5a\xABÛ¤\x87\xD2fc\x8E\xAF\x9Ce5\xD4g\xA1%è·\xF5\xFAJ\xBE\xFE\xCCC\xAA\xB7\xAC&gt;\xF9\xF4\xD6r\xF2\xB9M\xA2-\xC6hZ&gt;\x91U_\xCDl+0\x9A'}\xD2YA\xF5\xFCJ\xDBCN&gt;x0=]\x90eqc\xA9\xFCuвpf\x93m*w\xFF\xE2\xFC\xD5\xCC\xCCs\xFE*r\xAA*\xA6\xA0\xA4\xA3L\xBE\xDF0\x93 !k\xC2'\x89\xB2h]_\xB6\x8C&amp;\x81\xCA=L\xE8Wff\x9E\x80\xF5\x9CeU'\x96h\xBFEP\xFB\x8D_\x99\x9C~`dzb\xC2\xE7\x93v\xFF^\xFBB]\xA5\x8E\xD1d\xBC\x96\xCF^ kf;
+9\x94\xF3J)\x9C\xC9d\xC2{v?[Þ°N\xF4\xAC\x82O\x94?׆\xACOMFs\xF1D M΄\xB6\xB7\xAF\xFBi\xA5\xED~\xB5\xB9$\xCAX\xD3\xFD\x96,\xDDBØ e6I\xE7\xE2ËŠ\xE3ÇW!\xC7\xEE\xFBz&amp;n\xDB\xE9\x83b\xD1q}*\x8B\xB2\xAF`ZТU\x84\xD9t\xAC./G,\x8B\xD9$\x8E\x87\xCFΔ\xABu\xDD#\x82\x8Ah&amp;8Y^[\xBD\xE7\xF8\xE8kU6m\x8C^\xDCh\xDE[]\x8DD&quot;\xB7\xE1*\xD4鳺 &quot;\x9F\xC9&amp;\xFFh\xA3\xEDuh\x9E\xAE\xC2\x8EDVW\xD72\x9C\xEB\xD2&amp;P\x87\xB0\x8C\xBE&amp;\xA2\xB0\xD5_ק\x8BE\xFD(\xBD\x87\xD2\xD1\xD2i\xABQ\x9Bk\x9C&amp;lN\xE8\xD2Z\x98(
+V\xC9'\xC9I\xE9V$\xF2\x85\xBA,\xDD+\xE2a:\xBD\x97\xEE I\xC2[^\xDB3\xACbs\xE9\xE9\x92 W\x9FO\x94D\x9F [\xF5: Ff!\x83u\x99M2dc\xEF\xBD\x94V\xAB\xC50*\xB6f\xCD\xAF\xA5SY%XQ\xB6n\xC8VGS\xB3\xB7_k\xFE\xCF-\xDC$|\xF9y\xA6\xE5\xF7\xD34&lt;\xE6m\x99\xDA^Ĥ&quot;\x8E\x82\xB8!\x89\xBD;7dy\xE3Þ»k\xA7\xF1\xC6Øe\\xA1\xCBrtA\x80\xC7$X\xEDȘ\x91\xD9\xE2z\xB0\xE9\xFB\xF3 (\x9D\xB2%\xDF\xF1X\xD1|cl\xE1um\xC0B\x85\x86!O\xA3á½K\xDA\xC2\xF1\xC3Ù±^&amp; cÅ»R\xB0ؼU콺\xB2\xA0\xB0\x86GB\x9F\xEBvØ»\xA4\xED\xA8\xFE\xAC\xDF*&quot;\xC19\x89\x8D\xF5[\xF1
+\xEB\xE6/\x9DjM\x8F\xB4\xA5\xC3\xED_r\xFB\x977\xAFl\x85\x87-\xF4[=\x86\xA2%c%\xC0\xDAK\x87\xC3\xE8t\xA3\xD4\xD1 }\x89\x9B\xFF\xE6\xEB\xE1xk\xC02\xEE\xA2q\xF8L!\xABZ\xEA\xE5\xCA!\xC4r\xD8\xC8\xD1`]\xE6'\xD7;\x9F-\x95d\x8CM\xDB+~\xC6\xC0\x8B\x8C\xF9\x941\xD2\xB6z\xC1\xC7\xCE\xD4+\xE2\xA7\xF51\xCAB\xC7@\x80\xFDz\x83\xC0\xB2\xD1Q\xDAm\xDEn\xFF]Dg\xA4\x9F\x99Ú±\xFF\xB4\xA3%nÔ½h\xA9J\xDC4L\x8D\xBA\xAF\x85+R\xBDQ\xA25\xEA~\x9B\xFB\x86\xFC\xFC\xFF\x9C\x9F\xD6׬\x97\xFF        0\xA2\x95\x8Dd\xEE\xB4\IEND\xAEB`\x82
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssambuttoncss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/button.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/button.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/button.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+.yui-button{display:-moz-inline-box;display:inline-block;vertical-align:text-bottom;}.yui-button .first-child{display:block;*display:inline-block;}.yui-button button,.yui-button a{display:block;*display:inline-block;border:none;margin:0;}.yui-button button{background-color:transparent;*overflow:visible;cursor:pointer;}.yui-button a{text-decoration:none;}.yui-skin-sam .yui-button{border-width:1px 0;border-style:solid;border-color:#808080;background:url(sprite.png) repeat-x 0 0;margin:auto .25em;}.yui-skin-sam .yui-button .first-child{border-width:0 1px;border-style:solid;border-color:#808080;margin:0 -1px;_margin:0;}.yui-skin-sam .yui-button button,.yui-skin-sam .yui-button a,.yui-skin-sam .yui-button a:visited{padding:0 10px;font-size:93%;line-height:2;*line-height:1.7;min-height:2em;*min-height:auto;color:#000;}.yui-skin-sam .yui-button a{*line-height:1.875;*padding-bottom:1px;}.yui-skin-sam .yui-split-button button,.yui-skin-sam .yui-menu-button button{padding-right:20px;b
 ackground-position:right center;background-repeat:no-repeat;}.yui-skin-sam .yui-menu-button button{background-image:url(menu-button-arrow.png);}.yui-skin-sam .yui-split-button button{background-image:url(split-button-arrow.png);}.yui-skin-sam .yui-button-focus{border-color:#7D98B8;background-position:0 -1300px;}.yui-skin-sam .yui-button-focus .first-child{border-color:#7D98B8;}.yui-skin-sam .yui-split-button-focus button{background-image:url(split-button-arrow-focus.png);}.yui-skin-sam .yui-button-hover{border-color:#7D98B8;background-position:0 -1300px;}.yui-skin-sam .yui-button-hover .first-child{border-color:#7D98B8;}.yui-skin-sam .yui-split-button-hover button{background-image:url(split-button-arrow-hover.png);}.yui-skin-sam .yui-button-active{border-color:#7D98B8;background-position:0 -1700px;}.yui-skin-sam .yui-button-active .first-child{border-color:#7D98B8;}.yui-skin-sam .yui-split-button-activeoption{border-color:#808080;background-position:0 0;}.yui-skin-sam .yui-s
 plit-button-activeoption .first-child{border-color:#808080;}.yui-skin-sam .yui-split-button-activeoption button{background-image:url(split-button-arrow-active.png);}.yui-skin-sam .yui-radio-button-checked,.yui-skin-sam .yui-checkbox-button-checked{border-color:#304369;background-position:0 -1400px;}.yui-skin-sam .yui-radio-button-checked .first-child,.yui-skin-sam .yui-checkbox-button-checked .first-child{border-color:#304369;}.yui-skin-sam .yui-radio-button-checked button,.yui-skin-sam .yui-checkbox-button-checked button{color:#fff;}.yui-skin-sam .yui-button-disabled{border-color:#ccc;background-position:0 -1500px;}.yui-skin-sam .yui-button-disabled .first-child{border-color:#ccc;}.yui-skin-sam .yui-button-disabled button,.yui-skin-sam .yui-button-disabled a,.yui-skin-sam .yui-button-disabled a:visited{color:#A6A6A6;cursor:default;}.yui-skin-sam .yui-menu-button-disabled button{background-image:url(menu-button-arrow-disabled.png);}.yui-skin-sam .yui-split-button-disabled bu
 tton{background-image:url(split-button-arrow-disabled.png);}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamcalendarcss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/calendar.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/calendar.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/calendar.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,8 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+.yui-calcontainer{position:relative;float:left;_overflow:hidden}.yui-calcontainer iframe{position:absolute;border:0;margin:0;padding:0;z-index:0;width:100%;height:100%;left:0;top:0}.yui-calcontainer iframe.fixedsize{width:50em;height:50em;top:-1px;left:-1px}.yui-calcontainer.multi .groupcal{z-index:1;float:left;position:relative}.yui-calcontainer .title{position:relative;z-index:1}.yui-calcontainer .close-icon{position:absolute;z-index:1;text-indent:-10000em;overflow:hidden}.yui-calendar{position:relative}.yui-calendar .calnavleft{position:absolute;z-index:1;text-indent:-10000em;overflow:hidden}.yui-calendar .calnavright{position:absolute;z-index:1;text-indent:-10000em;overflow:hidden}.yui-calendar .calheader{position:relative;width:100%;text-align:center}.yui-calcontainer .yui-cal-nav-mask{position:absolute;z-index:2;margin:0;padding:0;width:100%;height:100%;_width:0;_height:0;left:0;top:0;display:none}.yui-calcontainer .yui-cal-nav{position:absolute;z-index:3;top:0;display
 :none}.yui-calcontainer .yui-cal-nav .yui-cal-nav-btn{display:-moz-inline-box;display:inline-block}.yui-calcontainer .yui-cal-nav .yui-cal-nav-btn button{display:block;*display:inline-block;*overflow:visible;border:0;background-color:transparent;cursor:pointer}.yui-calendar .calbody a:hover{background:inherit}p#clear{clear:left;padding-top:10px}.yui-skin-sam .yui-calcontainer{background-color:#f2f2f2;border:1px solid #808080;padding:10px}.yui-skin-sam .yui-calcontainer.multi{padding:0 5px 0 5px}.yui-skin-sam .yui-calcontainer.multi .groupcal{background-color:transparent;border:0;padding:10px 5px 10px 5px;margin:0}.yui-skin-sam .yui-calcontainer .title{background:url(sprite.png) repeat-x 0 0;border-bottom:1px solid #ccc;font:100% sans-serif;color:#000;font-weight:bold;height:auto;padding:.4em;margin:0 -10px 10px -10px;top:0;left:0;text-align:left}.yui-skin-sam .yui-calcontainer.multi .title{margin:0 -5px 0 -5px}.yui-skin-sam .yui-calcontainer.withtitle{padding-top:0}.yui-skin
 -sam .yui-calcontainer .calclose{background:url(sprite.png) no-repeat 0 -300px;width:25px;height:15px;top:.4em;right:.4em;cursor:pointer}.yui-skin-sam .yui-calendar{border-spacing:0;border-collapse:collapse;font:100% sans-serif;text-align:center;margin:0}.yui-skin-sam .yui-calendar .calhead{background:transparent;border:0;vertical-align:middle;padding:0}.yui-skin-sam .yui-calendar .calheader{background:transparent;font-weight:bold;padding:0 0 .6em 0;text-align:center}.yui-skin-sam .yui-calendar .calheader img{border:0}.yui-skin-sam .yui-calendar .calnavleft{background:url(sprite.png) no-repeat 0 -450px;width:25px;height:15px;top:0;bottom:0;left:-10px;margin-left:.4em;cursor:pointer}.yui-skin-sam .yui-calendar .calnavright{background:url(sprite.png) no-repeat 0 -500px;width:25px;height:15px;top:0;bottom:0;right:-10px;margin-right:.4em;cursor:pointer}.yui-skin-sam .yui-calendar .calweekdayrow{height:2em}.yui-skin-sam .yui-calendar .calweekdayrow th{padding:0;border:0}.yui-skin
 -sam .yui-calendar .calweekdaycell{color:#000;font-weight:bold;text-align:center;width:2em}.yui-skin-sam .yui-calendar .calfoot{background-color:#f2f2f2}.yui-skin-sam .yui-calendar .calrowhead,.yui-skin-sam .yui-calendar .calrowfoot{color:#a6a6a6;font-size:85%;font-style:normal;font-weight:normal;border:0}.yui-skin-sam .yui-calendar .calrowhead{text-align:right;padding:0 2px 0 0}.yui-skin-sam .yui-calendar .calrowfoot{text-align:left;padding:0 0 0 2px}.yui-skin-sam .yui-calendar td.calcell{border:1px solid #ccc;background:#fff;padding:1px;height:1.6em;line-height:1.6em;text-align:center;white-space:nowrap}.yui-skin-sam .yui-calendar td.calcell a{color:#06c;display:block;height:100%;text-decoration:none}.yui-skin-sam .yui-calendar td.calcell.today{background-color:#000}.yui-skin-sam .yui-calendar td.calcell.today a{background-color:#fff}.yui-skin-sam .yui-calendar td.calcell.oom{background-color:#ccc;color:#a6a6a6;cursor:default}.yui-skin-sam .yui-calendar td.calcell.oom a{co
 lor:#a6a6a6}.yui-skin-sam .yui-calendar td.calcell.selected{background-color:#fff;color:#000}.yui-skin-sam .yui-calendar td.calcell.selected a{background-color:#b3d4ff;color:#000}.yui-skin-sam .yui-calendar td.calcell.calcellhover{background-color:#426fd9;color:#fff;cursor:pointer}.yui-skin-sam .yui-calendar td.calcell.calcellhover a{background-color:#426fd9;color:#fff}.yui-skin-sam .yui-calendar td.calcell.previous{color:#e0e0e0}.yui-skin-sam .yui-calendar td.calcell.restricted{text-decoration:line-through}.yui-skin-sam .yui-calendar td.calcell.highlight1{background-color:#cf9}.yui-skin-sam .yui-calendar td.calcell.highlight2{background-color:#9cf}.yui-skin-sam .yui-calendar td.calcell.highlight3{background-color:#fcc}.yui-skin-sam .yui-calendar td.calcell.highlight4{background-color:#cf9}.yui-skin-sam .yui-calendar a.calnav{border:1px solid #f2f2f2;padding:0 4px;text-decoration:none;color:#000;zoom:1}.yui-skin-sam .yui-calendar a.calnav:hover{background:url(sprite.png) rep
 eat-x 0 0;border-color:#a0a0a0;cursor:pointer}.yui-skin-sam .yui-calcontainer .yui-cal-nav-mask{background-color:#000;opacity:.25;filter:alpha(opacity=25)}.yui-skin-sam .yui-calcontainer .yui-cal-nav{font-family:arial,helvetica,clean,sans-serif;font-size:93%;border:1px solid #808080;left:50%;margin-left:-7em;width:14em;padding:0;top:2.5em;background-color:#f2f2f2}.yui-skin-sam .yui-calcontainer.withtitle .yui-cal-nav{top:4.5em}.yui-skin-sam .yui-calcontainer.multi .yui-cal-nav{width:16em;margin-left:-8em}.yui-skin-sam .yui-calcontainer .yui-cal-nav-y,.yui-skin-sam .yui-calcontainer .yui-cal-nav-m,.yui-skin-sam .yui-calcontainer .yui-cal-nav-b{padding:5px 10px 5px 10px}.yui-skin-sam .yui-calcontainer .yui-cal-nav-b{text-align:center}.yui-skin-sam .yui-calcontainer .yui-cal-nav-e{margin-top:5px;padding:5px;background-color:#edf5ff;border-top:1px solid black;display:none}.yui-skin-sam .yui-calcontainer .yui-cal-nav label{display:block;font-weight:bold}
+.yui-skin-sam .yui-calcontainer .yui-cal-nav-mc{width:100%;_width:auto}.yui-skin-sam .yui-calcontainer .yui-cal-nav-y input.yui-invalid{background-color:#ffee69;border:1px solid #000}.yui-skin-sam .yui-calcontainer .yui-cal-nav-yc{width:4em}.yui-skin-sam .yui-calcontainer .yui-cal-nav .yui-cal-nav-btn{border:1px solid #808080;background:url(sprite.png) repeat-x 0 0;background-color:#ccc;margin:auto .15em}.yui-skin-sam .yui-calcontainer .yui-cal-nav .yui-cal-nav-btn button{padding:0 8px;font-size:93%;line-height:2;*line-height:1.7;min-height:2em;*min-height:auto;color:#000}.yui-skin-sam .yui-calcontainer .yui-cal-nav .yui-cal-nav-btn.yui-default{border:1px solid #304369;background-color:#426fd9;background:url(sprite.png) repeat-x 0 -1400px}.yui-skin-sam .yui-calcontainer .yui-cal-nav .yui-cal-nav-btn.yui-default button{color:#fff}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamcarouselcss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/carousel.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/carousel.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/carousel.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+.yui-carousel{visibility:hidden;overflow:hidden;position:relative;text-align:left;zoom:1;}.yui-carousel.yui-carousel-visible{visibility:visible;}.yui-carousel-content{overflow:hidden;position:relative;text-align:center;}.yui-carousel-element li{border:1px solid #ccc;list-style:none;margin:1px;overflow:hidden;padding:0;position:absolute;text-align:center;}.yui-carousel-vertical .yui-carousel-element li{display:block;float:none;}.yui-log .carousel{background:#f2e886;}.yui-carousel-nav{zoom:1;}.yui-carousel-nav:after{content:&quot;.&quot;;display:block;height:0;clear:both;visibility:hidden;}.yui-carousel-button-focus{outline:1px dotted #000;}.yui-carousel-min-width{min-width:115px;}.yui-carousel-element{overflow:hidden;position:relative;margin:0 auto;padding:0;text-align:left;*margin:0;}.yui-carousel-horizontal .yui-carousel-element{width:320000px;}.yui-carousel-vertical .yui-carousel-element{height:320000px;}.yui-skin-sam .yui-carousel-nav select{position:static;}.yui-carousel
  .yui-carousel-item-selected{border:1px dashed #000;margin:1px;}.yui-skin-sam .yui-carousel,.yui-skin-sam .yui-carousel-vertical{border:1px solid #808080;}.yui-skin-sam .yui-carousel-nav{background:url(sprite.png) repeat-x 0 0;padding:3px;text-align:right;}.yui-skin-sam .yui-carousel-button{background:url(sprite.png) no-repeat 0 -600px;float:right;height:19px;margin:5px;overflow:hidden;width:40px;}.yui-skin-sam .yui-carousel-vertical .yui-carousel-button{background-position:0 -800px;}.yui-skin-sam .yui-carousel-button-disabled{background-position:0 -2000px;}.yui-skin-sam .yui-carousel-vertical .yui-carousel-button-disabled{background-position:0 -2100px;}.yui-skin-sam .yui-carousel-button input,.yui-skin-sam .yui-carousel-button button{background-color:transparent;border:0;cursor:pointer;display:block;height:44px;margin:-2px 0 0 -2px;padding:0 0 0 50px;}.yui-skin-sam span.yui-carousel-first-button{background-position:0 -550px;margin-left:-100px;margin-right:50px;*margin:5px 5
 px 5px -90px;}.yui-skin-sam .yui-carousel-vertical span.yui-carousel-first-button{background-position:0 -750px;}.yui-skin-sam span.yui-carousel-first-button-disabled{background-position:0 -1950px;}.yui-skin-sam .yui-carousel-vertical span.yui-carousel-first-button-disabled{background-position:0 -2050px;}.yui-skin-sam .yui-carousel-nav ul{float:right;height:19px;margin:0;margin-left:-220px;margin-right:100px;*margin-left:-160px;*margin-right:0;padding:0;}.yui-skin-sam .yui-carousel-min-width .yui-carousel-nav ul{*margin-left:-170px;}.yui-skin-sam .yui-carousel-nav select{position:relative;*right:50px;top:4px;}.yui-skin-sam .yui-carousel-vertical .yui-carousel-nav select{position:static;}.yui-skin-sam .yui-carousel-vertical .yui-carousel-nav ul,.yui-skin-sam .yui-carousel-vertical .yui-carousel-nav select{float:none;margin:0;*zoom:1;}.yui-skin-sam .yui-carousel-nav ul li{background:url(sprite.png) no-repeat 0 -650px;cursor:pointer;float:left;height:9px;list-style:none;margin:1
 0px 0 0 5px;overflow:hidden;padding:0;width:9px;}.yui-skin-sam .yui-carousel-nav ul:after{content:&quot;.&quot;;display:block;height:0;clear:both;visibility:hidden;}.yui-skin-sam .yui-carousel-nav ul li a{display:block;width:100%;height:100%;text-indent:-10000px;text-align:left;overflow:hidden;}.yui-skin-sam .yui-carousel-nav ul li.yui-carousel-nav-page-focus{outline:1px dotted #000;}.yui-skin-sam .yui-carousel-nav ul li.yui-carousel-nav-page-selected{background-position:0 -700px;}.yui-skin-sam .yui-carousel-item-loading{background:url(ajax-loader.gif) no-repeat 50% 50%;position:absolute;text-indent:-150px;}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamcheck0gif"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/check0.gif (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/check0.gif                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/check0.gif        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1 @@
</span><ins>+GIF89a\xE6B\xE5\xE5\xE5\xE9\xE9\xE9\xF7\xF7\xF7\xE7\xE7\xE7\xFE\xFE\xFE\x81\x81\x81\xF6\xF6\xF6\xEA\xEA\xEA\xF3\xF3ó‘‘‘---\xF0\xF0\xF0\xDD\xDDݲ\xB2\xB2\x84\x84\x84\xFD\xFD\xFD\xE0\xE0à³³\xB3\xE8\xE8è¹¹\xB9\xDE\xDE\xDE\xF1\xF1\xF1\xEF\xEF\xEF\xDC\xDCܤ\xA4\xA4\xD2\xD2\xD2\xF5\xF5\x{15E79E}\xE2\xE2\xE2\xD9\xD9\xD9\xDB\xDBÛœ\x9C\x9C\xB0\xB0\xB0ccc\xAD\xAD\xAD\xBB\xBB\xBB\xD7\xD7ת\xAA\xAA\xD1\xD1\xD1...\x82\x82\x82\xBA\xBA\xBA\xE6\xE6惃\x83\xD3\xD3\xD3\xE3\xE3㦦\xA6\x85\x85\x85///\xBC\xBC\xBC\xF8\xF8\x{F7DF57}\x97\x97\xB7\xB7\xB7\xA8\xA8\xA8\xD5\xD5\xD5bbb111222\xD8\xD8\xD8\xDA\xDA\xDA\xEE\xEE\xEE\xDF\xDF\xDF\xF2\xF2\xF2\xFF\xFF\xFF\xFF\xFF\xFF!\xF9B,\xBD\x80B\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x83A!)\x950,A\x82        8A\xA1\xA1A        \x82\xAD@\xAF
 @\xAA\x82        &gt;\xB9\xBA\xB9        \x82\xC4\xC5&lt;\x82-=\xD0\xD1\xD0'\x82?#=?\xDB\xDC?%&amp;?\x82 6.+\xE8\xE8   \x824\xAF \xF4 @&gt;$\x82 \xCC0 \xA0\xA0\x802(P\xC3@\x90\x87j\xF80@\x90\x81&quot;t\xA0PC\x81\xC79n\xF4H\x86        R6X\xA9&quot;\x90\x8DbÊœy(;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamcheck1gif"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/check1.gif (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/check1.gif                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/check1.gif        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,5 @@
</span><ins>+GIF89a\xE6^\xBD\xBD\xBD\xC1\xC1\xC1\xCD\xCD\xCD\xC6\xC6Ƹ\xB8\xB8\xB6\xB6\xB6```\xB2\xB2\xB2\x84\x84\x84\xC5\xC5ũ\xA9\xA9\xC2\xC2³\xB3\xB3\x81\x81\x81\xDD\xDD\xDD\xDC\xDCܾ\xBE\xBE\xBF\xBF\xBF\xF6\xF6\xF6mmm\xE5\xE5\xE5\xDE\xDE\xDE~~\x80\xFF\xFF\xFF\xEA\xEA\xEAPPP\xF2\xF2\xF2\xFD\xFD\xFD\xE0\xE0\xE0\xE7\xE7\xE7\xB9\xB9\xB9\xD9\xD9\xD9\xE2\xE2\xE2\xD2\xD2\xD2sss\xC0\xC0\xC0\xAA\xAA\xAA\xDF\xDF\xDF|||\x88\x88\x88\x86\x86\x869;?\xBA\xBA\xBA!&amp;\xF7\xF7\x{1C20C4}\xA2\xA2\xA2\xB7\xB7\xB7yz|\xA0\xA0\xA0\x8A\x8A\x8A\x85\x85\x85\x91\x92\x93acffffuuukkk\x8B\x8B\x8B\xAF\xAF\xAF\xA4\xA4\xA4\xAC\xAC\xAC\x91\x91\x93\xCC\xCC\xCC222\xC7\xC7\xC7Z\^\xF5\xF5\xF5\x82\x82\x82~\x80\xB5\xB5\xB5\]`\xA7\xA7\xA7\xB4\xB4\xB4\x8C\x8C\x8C\xAE\xAE\xAEyyy\xA0\xA0\xA1\x83\x83\x83\xBB\xBB\xBB{|~\xC4\xC4Ħ\xA6\xA6www\x96\x96\x97  opr111\xCE\xCE\xCE\xFF\xFF\xFF!\xF9
 ^,Ë€^\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x83 G+\x956Q \x82-&gt;\\xA1\xA1A\%E\x82 \xAD\xAFS\x82\xBA\xBAJ]R\x82!%\xC73]]PK!\x82#/
+Z.W1XH
+4#\x82&amp;'
+D],*Y7N=UO&amp;\x82)I2]L0?\x82MH\x82C`\x84j&lt;T\x84        \x86$@q@uÈ‘\x80\x8BÇ\xA9\xEC\xE8 H\x82!\xCBR.3\xB2ÅŠA4\x88\xF8\xC0\xA0æ›+Dh\xD8Ш\xA7ÏŸ\x87;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamcheck2gif"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/check2.gif (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/check2.gif                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/check2.gif        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,5 @@
</span><ins>+GIF89a\xE6M\xB8\xB8\xB8\xC6\xC6\xC6\xCD\xCDʹ\xB4\xB4```\xC2\xC2\xC2&quot;0\xB2\xB2\xB2\x84\x84\x84\xB9\xB9\xB9\xB3\xB3\xB3\x81\x81\x81\xB6\xB6\xB6\xBF\xBF\xBF\xC5\xC5\xC5PPP\xB7\xB7\xB7mmm\xBE\xBE\xBE\xEA\xEA\xEA\xD2\xD2\xD2\xFD\xFD\xFD\xE7\xE7\xE7sss\xFF\xFF\xFF\xE2\xE2\xE2\xF2\xF2\xF2\xC0\xC0\xC0\xE5\xE5\xE5\xDC\xDC\xDC\xD9\xD9\xD9\xE0\xE0\xE0\xDE\xDEު\xAA\xAA\xDF\xDF\xDF\xF6\xF6\xF6\xDD\xDDݧ\xA7\xA7\xA2\xA2\xA2\xAE\xAE\xAE\x82\x82\x82fffyyy\xB5\xB5\xB5\x88\x88\x88\xBA\xBA\xBAwww\xAC\xAC\xAC\x8A\x8A\x8A\x8B\x8B\x8B|||uuu\xAF\xAF\xAFrtzkkk\xCC\xCC\xCC222\x85\x85\x85\xC4\xC4\xC4\xF5\xF5\x{146186}111\xF7\xF7\x{1CC30C}\xC7\xC7Ǥ\xA4\xA4\xA0\xA0\xA0\xA6\xA6\xA6\x94\x95\x98\x83\x83\x83\xC1\xC1\xC1\xA9\xA9\xA9\xBD\xBD\xBD\xCE\xCE\xCE\xFF\xFF\xFF!\xF9M,\xBE\x80M\x82\x83\x84\x85\x86\x87\x88
 \x89\x8A\x8B\x8C\x83) \x95;G\x82@CK\xA1\xA19K&quot;=\x82\xADH\xAFH        \x82 J\xBA\xBB\xBA \x82&quot;\xC5\xC6        &amp;\x82 'I\xD1\xD2\xD1D \x82#4I(7\xDEF6E+#\x82%&gt;,\xEB\xEB 0%\x82A\xAF+\xF7+HJ1\x82!ZH\xE0@\x88\x834\x98B\x90\x96H\x9C(\x91 \x82H\xD4\xD0\xC1\xA4\xA3G&amp;2~\xBC !\xA8\x82
+        \xA8&lt;\xC0\xD2+ÉœI\xF3P ;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamcolorpickercss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/colorpicker.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/colorpicker.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/colorpicker.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+.yui-picker-panel{background:#e3e3e3;border-color:#888}.yui-picker-panel .hd{background-color:#ccc;font-size:100%;line-height:100%;border:1px solid #e3e3e3;font-weight:bold;overflow:hidden;padding:6px;color:#000}.yui-picker-panel .bd{background:#e8e8e8;margin:1px;height:200px}.yui-picker-panel .ft{background:#e8e8e8;margin:1px;padding:1px}.yui-picker{position:relative}.yui-picker-hue-thumb{cursor:default;width:18px;height:18px;top:-8px;left:-2px;z-index:9;position:absolute}.yui-picker-hue-bg{-moz-outline:0;outline:0 none;position:absolute;left:200px;height:183px;width:14px;background:url(hue_bg.png) no-repeat;top:4px}.yui-picker-bg{-moz-outline:0;outline:0 none;position:absolute;top:4px;left:4px;height:182px;width:182px;background-color:#F00;background-image:url(picker_mask.png)}*html .yui-picker-bg{background-image:none;filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='picker_mask.png',sizingMethod='scale')}.yui-picker-mask{position:absolute;z-index:1;top:0;lef
 t:0}.yui-picker-thumb{cursor:default;width:11px;height:11px;z-index:9;position:absolute;top:-4px;left:-4px}.yui-picker-swatch{position:absolute;left:240px;top:4px;height:60px;width:55px;border:1px solid #888}.yui-picker-websafe-swatch{position:absolute;left:304px;top:4px;height:24px;width:24px;border:1px solid #888}.yui-picker-controls{position:absolute;top:72px;left:226px;font:1em monospace}.yui-picker-controls .hd{background:transparent;border-width:0!important}.yui-picker-controls .bd{height:100px;border-width:0!important}.yui-picker-controls ul{float:left;padding:0 2px 0 0;margin:0}.yui-picker-controls li{padding:2px;list-style:none;margin:0}.yui-picker-controls input{font-size:.85em;width:2.4em}.yui-picker-hex-controls{clear:both;padding:2px}.yui-picker-hex-controls input{width:4.6em}.yui-picker-controls a{font:1em arial,helvetica,clean,sans-serif;display:block;*display:inline-block;padding:0;color:#000}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamcontainercss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/container.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/container.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/container.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+.yui-overlay,.yui-panel-container{visibility:hidden;position:absolute;z-index:2}.yui-panel{position:relative}.yui-panel-container form{margin:0}.mask{z-index:1;display:none;position:absolute;top:0;left:0;right:0;bottom:0}.mask.block-scrollbars{overflow:auto}.masked select,.drag select,.hide-select select{_visibility:hidden}.yui-panel-container select{_visibility:inherit}.hide-scrollbars,.hide-scrollbars *{overflow:hidden}.hide-scrollbars select{display:none}.show-scrollbars{overflow:auto}.yui-panel-container.show-scrollbars,.yui-tt.show-scrollbars{overflow:visible}.yui-panel-container.show-scrollbars .underlay,.yui-tt.show-scrollbars .yui-tt-shadow{overflow:auto}.yui-panel-container.shadow .underlay.yui-force-redraw{padding-bottom:1px}.yui-effect-fade .underlay,.yui-effect-fade .yui-tt-shadow{display:none}.yui-tt-shadow{position:absolute}.yui-override-padding{padding:0!important}.yui-panel-container .container-close{overflow:hidden;text-indent:-10000em;text-decoration:none}.
 yui-overlay.yui-force-redraw,.yui-panel-container.yui-force-redraw{margin-bottom:1px}.yui-skin-sam .mask{background-color:#000;opacity:.25;filter:alpha(opacity=25)}.yui-skin-sam .yui-panel-container{padding:0 1px;*padding:2px}.yui-skin-sam .yui-panel{position:relative;left:0;top:0;border-style:solid;border-width:1px 0;border-color:#808080;z-index:1;*border-width:1px;*zoom:1;_zoom:normal}.yui-skin-sam .yui-panel .hd,.yui-skin-sam .yui-panel .bd,.yui-skin-sam .yui-panel .ft{border-style:solid;border-width:0 1px;border-color:#808080;margin:0 -1px;*margin:0;*border:0}.yui-skin-sam .yui-panel .hd{border-bottom:solid 1px #ccc}.yui-skin-sam .yui-panel .bd,.yui-skin-sam .yui-panel .ft{background-color:#f2f2f2}.yui-skin-sam .yui-panel .hd{padding:0 10px;font-size:93%;line-height:2;*line-height:1.9;font-weight:bold;color:#000;background:url(sprite.png) repeat-x 0 -200px}.yui-skin-sam .yui-panel .bd{padding:10px}.yui-skin-sam .yui-panel .ft{border-top:solid 1px #808080;padding:5px 10px
 ;font-size:77%}.yui-skin-sam .container-close{position:absolute;top:5px;right:6px;width:25px;height:15px;background:url(sprite.png) no-repeat 0 -300px;cursor:pointer}.yui-skin-sam .yui-panel-container .underlay{right:-1px;left:-1px}.yui-skin-sam .yui-panel-container.matte{padding:9px 10px;background-color:#fff}.yui-skin-sam .yui-panel-container.shadow{_padding:2px 4px 0 2px}.yui-skin-sam .yui-panel-container.shadow .underlay{position:absolute;top:2px;left:-3px;right:-3px;bottom:-3px;*top:4px;*left:-1px;*right:-1px;*bottom:-1px;_top:0;_left:0;_right:0;_bottom:0;_margin-top:3px;_margin-left:-1px;background-color:#000;opacity:.12;filter:alpha(opacity=12)}.yui-skin-sam .yui-dialog .ft{border-top:0;padding:0 10px 10px 10px;font-size:100%}.yui-skin-sam .yui-dialog .ft .button-group{display:block;text-align:right}.yui-skin-sam .yui-dialog .ft button.default{font-weight:bold}.yui-skin-sam .yui-dialog .ft span.default{border-color:#304369;background-position:0 -1400px}.yui-skin-sam .
 yui-dialog .ft span.default .first-child{border-color:#304369}.yui-skin-sam .yui-dialog .ft span.default button{color:#fff}.yui-skin-sam .yui-dialog .ft span.yui-button-disabled{background-position:0 -1500px;border-color:#ccc}.yui-skin-sam .yui-dialog .ft span.yui-button-disabled .first-child{border-color:#ccc}.yui-skin-sam .yui-dialog .ft span.yui-button-disabled button{color:#a6a6a6}.yui-skin-sam .yui-simple-dialog .bd .yui-icon{background:url(sprite.png) no-repeat 0 0;width:16px;height:16px;margin-right:10px;float:left}.yui-skin-sam .yui-simple-dialog .bd span.blckicon{background-position:0 -1100px}.yui-skin-sam .yui-simple-dialog .bd span.alrticon{background-position:0 -1050px}.yui-skin-sam .yui-simple-dialog .bd span.hlpicon{background-position:0 -1150px}.yui-skin-sam .yui-simple-dialog .bd span.infoicon{background-position:0 -1200px}.yui-skin-sam .yui-simple-dialog .bd span.warnicon{background-position:0 -1900px}.yui-skin-sam .yui-simple-dialog .bd span.tipicon{backgro
 und-position:0 -1250px}.yui-skin-sam .yui-tt .bd{position:relative;top:0;left:0;z-index:1;color:#000;padding:2px 5px;border-color:#d4c237 #A6982b #a6982b #A6982B;border-width:1px;border-style:solid;background-color:#ffee69}.yui-skin-sam .yui-tt.show-scrollbars .bd{overflow:auto}.yui-skin-sam .yui-tt-shadow{top:2px;right:-3px;left:-3px;bottom:-3px;background-color:#000}.yui-skin-sam .yui-tt-shadow-visible{opacity:.12;filter:alpha(opacity=12)}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamdatatablecss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/datatable.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/datatable.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/datatable.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,8 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+.yui-skin-sam .yui-dt-mask{position:absolute;z-index:9500}.yui-dt-tmp{position:absolute;left:-9000px}.yui-dt-scrollable .yui-dt-bd{overflow:auto}.yui-dt-scrollable .yui-dt-hd{overflow:hidden;position:relative}.yui-dt-scrollable .yui-dt-bd thead tr,.yui-dt-scrollable .yui-dt-bd thead th{position:absolute;left:-1500px}.yui-dt-scrollable tbody{-moz-outline:0}.yui-skin-sam thead .yui-dt-sortable{cursor:pointer}.yui-skin-sam thead .yui-dt-draggable{cursor:move}.yui-dt-coltarget{position:absolute;z-index:999}.yui-dt-hd{zoom:1}th.yui-dt-resizeable .yui-dt-resizerliner{position:relative}.yui-dt-resizer{position:absolute;right:0;bottom:0;height:100%;cursor:e-resize;cursor:col-resize;background-color:#CCC;opacity:0;filter:alpha(opacity=0)}.yui-dt-resizerproxy{visibility:hidden;position:absolute;z-index:9000;background-color:#CCC;opacity:0;filter:alpha(opacity=0)}th.yui-dt-hidden .yui-dt-liner,td.yui-dt-hidden .yui-dt-liner,th.yui-dt-hidden .yui-dt-resizer{display:none}.yui-dt-editor,.
 yui-dt-editor-shim{position:absolute;z-index:9000}.yui-skin-sam .yui-dt table{margin:0;padding:0;font-family:arial;font-size:inherit;border-collapse:separate;*border-collapse:collapse;border-spacing:0;border:1px solid #7f7f7f}.yui-skin-sam .yui-dt thead{border-spacing:0}.yui-skin-sam .yui-dt caption{color:#000;font-size:85%;font-weight:normal;font-style:italic;line-height:1;padding:1em 0;text-align:center}.yui-skin-sam .yui-dt th{background:#d8d8da url(sprite.png) repeat-x 0 0}.yui-skin-sam .yui-dt th,.yui-skin-sam .yui-dt th a{font-weight:normal;text-decoration:none;color:#000;vertical-align:bottom}.yui-skin-sam .yui-dt th{margin:0;padding:0;border:0;border-right:1px solid #cbcbcb}.yui-skin-sam .yui-dt tr.yui-dt-first td{border-top:1px solid #7f7f7f}.yui-skin-sam .yui-dt th .yui-dt-liner{white-space:nowrap}.yui-skin-sam .yui-dt-liner{margin:0;padding:0;padding:4px 10px 4px 10px}.yui-skin-sam .yui-dt-coltarget{width:5px;background-color:red}.yui-skin-sam .yui-dt td{margin:0;
 padding:0;border:0;border-right:1px solid #cbcbcb;text-align:left}.yui-skin-sam .yui-dt-list td{border-right:0}.yui-skin-sam .yui-dt-resizer{width:6px}.yui-skin-sam .yui-dt-mask{background-color:#000;opacity:.25;filter:alpha(opacity=25)}.yui-skin-sam .yui-dt-message{background-color:#FFF}.yui-skin-sam .yui-dt-scrollable table{border:0}.yui-skin-sam .yui-dt-scrollable .yui-dt-hd{border-left:1px solid #7f7f7f;border-top:1px solid #7f7f7f;border-right:1px solid #7f7f7f}.yui-skin-sam .yui-dt-scrollable .yui-dt-bd{border-left:1px solid #7f7f7f;border-bottom:1px solid #7f7f7f;border-right:1px solid #7f7f7f;background-color:#FFF}.yui-skin-sam .yui-dt-scrollable .yui-dt-data tr.yui-dt-last td{border-bottom:1px solid #7f7f7f}.yui-skin-sam th.yui-dt-asc,.yui-skin-sam th.yui-dt-desc{background:url(sprite.png) repeat-x 0 -100px}.yui-skin-sam th.yui-dt-sortable .yui-dt-label{margin-right:10px}.yui-skin-sam th.yui-dt-asc .yui-dt-liner{background:url(dt-arrow-up.png) no-repeat right}.yui-s
 kin-sam th.yui-dt-desc .yui-dt-liner{background:url(dt-arrow-dn.png) no-repeat right}tbody .yui-dt-editable{cursor:pointer}.yui-dt-editor{text-align:left;background-color:#f2f2f2;border:1px solid #808080;padding:6px}.yui-dt-editor label{padding-left:4px;padding-right:6px}.yui-dt-editor .yui-dt-button{padding-top:6px;text-align:right}.yui-dt-editor .yui-dt-button button{background:url(sprite.png) repeat-x 0 0;border:1px solid #999;width:4em;height:1.8em;margin-left:6px}.yui-dt-editor .yui-dt-button button.yui-dt-default{background:url(sprite.png) repeat-x 0 -1400px;background-color:#5584e0;border:1px solid #304369;color:#FFF}.yui-dt-editor .yui-dt-button button:hover{background:url(sprite.png) repeat-x 0 -1300px;color:#000}.yui-dt-editor .yui-dt-button button:active{background:url(sprite.png) repeat-x 0 -1700px;color:#000}.yui-skin-sam tr.yui-dt-even{background-color:#FFF}.yui-skin-sam tr.yui-dt-odd{background-color:#edf5ff}.yui-skin-sam tr.yui-dt-even td.yui-dt-asc,.yui-skin
 -sam tr.yui-dt-even td.yui-dt-desc{background-color:#edf5ff}.yui-skin-sam tr.yui-dt-odd td.yui-dt-asc,.yui-skin-sam tr.yui-dt-odd td.yui-dt-desc{background-color:#dbeaff}.yui-skin-sam .yui-dt-list tr.yui-dt-even{background-color:#FFF}.yui-skin-sam .yui-dt-list tr.yui-dt-odd{background-color:#FFF}.yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-asc,.yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-desc{background-color:#edf5ff}.yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-asc,.yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-desc{background-color:#edf5ff}.yui-skin-sam th.yui-dt-highlighted,.yui-skin-sam th.yui-dt-highlighted a{background-color:#b2d2ff}.yui-skin-sam tr.yui-dt-highlighted,.yui-skin-sam tr.yui-dt-highlighted td.yui-dt-asc,.yui-skin-sam tr.yui-dt-highlighted td.yui-dt-desc,.yui-skin-sam tr.yui-dt-even td.yui-dt-highlighted,.yui-skin-sam tr.yui-dt-odd td.yui-dt-highlighted{cursor:pointer;background-color:#b2d2ff}.yui-skin-sam .yui-dt-list th.yui-dt-high
 lighted,.yui-skin-sam .yui-dt-list th.yui-dt-highlighted a{background-color:#b2d2ff}.yui-skin-sam .yui-dt-list tr.yui-dt-highlighted,.yui-skin-sam .yui-dt-list tr.yui-dt-highlighted td.yui-dt-asc,.yui-skin-sam .yui-dt-list tr.yui-dt-highlighted td.yui-dt-desc,.yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-highlighted,.yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-highlighted{cursor:pointer;background-color:#b2d2ff}.yui-skin-sam th.yui-dt-selected,.yui-skin-sam th.yui-dt-selected a{background-color:#446cd7}.yui-skin-sam tr.yui-dt-selected td,.yui-skin-sam tr.yui-dt-selected td.yui-dt-asc,.yui-skin-sam tr.yui-dt-selected td.yui-dt-desc{background-color:#426fd9;color:#FFF}.yui-skin-sam tr.yui-dt-even td.yui-dt-selected,.yui-skin-sam tr.yui-dt-odd td.yui-dt-selected{background-color:#446cd7;color:#FFF}.yui-skin-sam .yui-dt-list th.yui-dt-selected,.yui-skin-sam .yui-dt-list th.yui-dt-selected a{background-color:#446cd7}
+.yui-skin-sam .yui-dt-list tr.yui-dt-selected td,.yui-skin-sam .yui-dt-list tr.yui-dt-selected td.yui-dt-asc,.yui-skin-sam .yui-dt-list tr.yui-dt-selected td.yui-dt-desc{background-color:#426fd9;color:#FFF}.yui-skin-sam .yui-dt-list tr.yui-dt-even td.yui-dt-selected,.yui-skin-sam .yui-dt-list tr.yui-dt-odd td.yui-dt-selected{background-color:#446cd7;color:#FFF}.yui-skin-sam .yui-dt-paginator{display:block;margin:6px 0;white-space:nowrap}.yui-skin-sam .yui-dt-paginator .yui-dt-first,.yui-skin-sam .yui-dt-paginator .yui-dt-last,.yui-skin-sam .yui-dt-paginator .yui-dt-selected{padding:2px 6px}.yui-skin-sam .yui-dt-paginator a.yui-dt-first,.yui-skin-sam .yui-dt-paginator a.yui-dt-last{text-decoration:none}.yui-skin-sam .yui-dt-paginator .yui-dt-previous,.yui-skin-sam .yui-dt-paginator .yui-dt-next{display:none}.yui-skin-sam a.yui-dt-page{border:1px solid #cbcbcb;padding:2px 6px;text-decoration:none;background-color:#fff}.yui-skin-sam .yui-dt-selected{border:1px solid #fff;backgr
 ound-color:#fff}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamdescgif"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/desc.gif (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/desc.gif                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/desc.gif        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1 @@
</span><ins>+GIF89a        \xC4A@@zzzppp544ONNbaa\x8B\x8B\x8BdddWWW\x84\x84\x840//322\x90\x90\x90\x87\x87\x87KKKRRRonn\x8D\x8D\x8D988^^^&lt;;;~~~\x92\x92\x92\xFF\xFF\xFF!\xF9,        .\xA0P\x8D\xE48]\xE8EXlk1T\x8A.{\xC8(P\x8EB.\x84%\x89\xB0\x8A!\xAA\xC0r(Q\x8BF\xE0\x99z\x94!;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamdtarrowdnpng"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/dt-arrow-dn.png (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/dt-arrow-dn.png                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/dt-arrow-dn.png        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,5 @@
</span><ins>+\x89PNG
+
++IHDR+(\x8A]'        PLTE\xFF\xFF\xFFYYX\xF5\x83\xB9tRNS@\xE6\xD8fIDATx\xDAc\x98\xC6\xC0\xC0\xA0$8\x80S\x86T\xEEÄŽIEND\xAEB`\x82
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamdtarrowuppng"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/dt-arrow-up.png (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/dt-arrow-up.png                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/dt-arrow-up.png        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,5 @@
</span><ins>+\x89PNG
+
++IHDR+(\x8A]'        PLTE\xFF\xFF\xFFVY_\x86\xCDQ'tRNS@\xE6\xD8fIDATx\xDAc`j```\xE0L\xAA@bj\xFBT*\x89P{IEND\xAEB`\x82
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssameditorknobgif"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/editor-knob.gif (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/editor-knob.gif                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/editor-knob.gif        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,2 @@
</span><ins>+GIF89a!\xA2\xF2\xF2ò\x96\x96\x96\xEB\xEB\xEB\xCF\xCF\xCF!\xF9,!OX\xBA\xDC\xF1-ʹ\x82 &quot;\xD0=\xEDCÆ\x8A\x9C\xA1FR扊kÔº\xAF\x97\xC2G\xD3\xE9]\xCC;Wo
+a\x9C\xA2\xF1h\xEB\xE4\x96СD        \xE5!Ôª\xB5\xF9{j\xB5\xD2\xECw\xD7\x8FÉ¢\xB3\xFATH;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssameditorspriteactivegif"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/editor-sprite-active.gif (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/editor-sprite-active.gif                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/editor-sprite-active.gif        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,66 @@
</span><ins>+GIF89ad\xF7\xFF\xD4\xE1\xF3\xF8\xE8ȫ\xB4\xC3\xDA*\xF3\xB6P\xFB\xFB\xFB\xF8y&lt;=\xAFةz,\xD8\xD8\xDAsvy\x97\xCE`\xF6\x960\xB7\xB6\xB6\xF9\xE7\xB4\xF5׻\xDF\xE0\xE0H\xAA\xF1\xA49O\xA5aְ*\x93\x9A\xA4l\xD7\xFC3\x9A\xDB\xE9\xFC\xE9\xD9\xCE&lt;:;\xE3\xE3嵃-`abKJK\xA1\xAA\xB6\xC4\xC3\xC3\xED\xC66\xCE\xDB\xEDA\x8B\xA6\x8CxaՎGDCDk\xE1S\xE2z\xC5ɀ`\x82\xF5\xF3cRQS\x99\xA1\xAC\xC6f3jms\xCD\xD9\xEB\xEC\xEC셊\x94\x9AЪ523\xF2\xD4GyI-\xBB\xC6\xD6ZZ\\xA8u\xEF\xF0\xF0\xF4\xCCx\xF4\xC9n\xAF\x98r\xF5\xDBU\xA7\xA7\xA9ɺ\xB6\x82\x84\x879\xA6\xCC̲\x88.*+\x99\x97\x96\xFF\x88\x81}\x84\x8E\xD8\xE6\xF8\x8Borx\xF6\xEAf\xF7\xE8\x95[\xEEYē&lt;ijl^^aͤt%&quot;#\x93l3\xB2\x8DE\xB1\xBA\xC8{_`fܣ \xEE\xB1g\xD8Ⱥ\xF8\x93D\xFC\xF3\xDESTW\xF5\xF6\xF7\xF8\xF8spB\x84\xB3f6
+\xF5ÖŠå±\xF8pV\xA7\xB0\xBC\x9Cl\xB7\xA5\x84cdgx|\x821\x94*Ê™MLO&quot;\x8B\xB1\x9F\x87p\xF9\xD6|\xAE\xB4p\xE5\xB6!\xE4\xE9\xF4\x85R\xDCL\xF6\xE2Y\xA1\xA0\x9F\xF5R\x8C\x92\x9C\x9C\xDB\xF2\xCCtC\x95\xCB\xD9\xC0R\xC9\xD6\xE7\xED\x89\xF2\xF2\xF2\xF6Ûœ\xB6\xE4\xF5\xE5h\x8A\xCF\xD0Õ£;\xEA\xC2a\xC5\xD1\xE1\x91X&amp;\xB0\xAD=x\x99\xF0\x90i\xDB\xE3\xF1\xE1\xE6\xEAa\xBB\xC3\xC8x\xEB\x9AY\xD1\xDE\xF0\xE2\xB0T\xFFVU¡H\xD1Ƨ\xE0Ö¬\xFA\xE2v\xC1\xCD\xDDehl0-.\xEE\xD4V\xEC\xE6ts\x9CϨYÓŸ\x8BcZL\x80lTz\xA6FEH\xC7\xEB\xF7IGI\xA4\xDF'$%\xE6s\1Ô»P:79\xCA\xD7\xE83\x9A\xC0VX]\xE5\xCAMA@A\xDBÕº\xB6\xC1\xD0 \xA2NQU645+'(PPRk\x91\xE3p*αL37;1/0# \x91\xD7\xF0\xFF\xFF?=&gt;\xE7\xE8\xE8\x97\xEF\xD0\xF1\xD5g),/8;@\xC8\xE6\xB0\xFFl8C\xA2\xE4\xE4\x89-ONP\xBF\xE2\xCD\xD2\xEB݆\xD3\xEFl\xC8\xE2\xAC\xD9̨\xE0\xF3\xF7\xFC\xFE\xFD\xFB\xF0i\xAF\xB0@\xB9\xE4\xAAU&amp;&gt;6.(\xAB(\xD2\xD2\xD2\xCD\xCD\xCD辡j\x8ANZJEHN\xAD368&lt;\xD9\xF1\xFA\xA0WWY\x93\x9D]\xAE\xAEK\xE2^noq\xE1\xC
 0{L\x96C\xA0,\xF7\xCB[ezk\x8E\xD6\xF0S\xBE\xE0\xDFÉ\xDFÊŸ\xF0Õ—\xF3\xC0\x8B\xF5Ì¡\xE1\x97F\x97\xAA7\xCD\xC0\xA8\xBE\xBD\xBD\x92\xB1\x8DSbP\xC7\xD4\xE5\xFF\xFF\xFF\xDE\xEC\xFF!\xF9\xFF,d\xFF\xFF        H\xB0\xA0\xC1\x83*\\xA8pƉ\xCE\xF4h\x82\xE1b!\x96+j\xFA\x9D1\x97\x84\xC2W\x9Br\xC4he*&quot;\x80\x84^|ÕŠ!\x80U,\x92P\xFA*\xE2lJ \xFD\x92\xC8t\x93i\x86\xAF)\xA6t#)_\xBEN&quot;:\xE2_J_\xFD%*i\x93\xAFQ\xAEA\xEA+džMjp\xC4H(\xA9\x9F\xD9\xAD\xFEH\xCA\xC0\xB0\xADÛ·p\xE3ÊK\xB7\xAEÝ»x\xF3\xEA\xDDË·\xAFß¿%\x81X\xB0dÆ™\xB6\x96h\x9AC\xA9\xC2\xE6\x96\xE4l\xEB⃅\xB1msÄš\xE5Xa\xBF^^\xFA\xB1e\xA8g\xCA \xCC \x8FZ\xE9\x9C\xC7U\xD1 \x91e\xB5&amp;&amp;C1\xFA\xB50\xB0\xEF\xDF\xC0\x83 N\xBC\xB8\xF1\xE3\xC8\xEA        KO\xAB8\x90\x98 \x8APM\xB0~k\xFFÍ’l\xDB VY.\xFFAm0J\xAF\xF0\xFF`\x90/\xF8\xAAz(\xEB        zA\xFE\x8F\x9A\xA6K\xA1\xB4\x82%\xFE@$\xBE 1\x90&amp;z\xE0\x87\x90&amp;\xBE\x90\xE2\xC5k\x8C\xC0\xDA@gDh\xC1KX\xE0\x874\xC0\x86v\xA8\xD3A\x88\xF4\x83Ȉ$\x86\
 x98܉(\xA6\xA8\xE2\x8A,\xB6\xE8&quot;_\xEAx\xF4\x96\xBDU!C0\xD82Cz昲\xC4?\x99\xAC\xA1F\x8DÍ\xC9?Q\xFC\xA3ÆŽ\xB1\xB8\xA0I\x86\xD9&quot;\xE5\x94TVi\xCB@0|\xF0*\xB38\xB3\xC0?\xCD\x83\x85Az$\xE8 _a\xC3?\xF4\xCC/\xC6)\xE7\x9Ct\xD6ig\x9C3t\xB4\x84n-\x81\x85        !\x82A#\xA3A \xE4 \xE0@\xAFD\xB1\xC1\x83\xFF,\xE1\x863!\xE2+.La\x8AA8\xA3\xC6V\xB4\xC2툣\x85\x9A\xD3Ö¦\xFF\xB0\xB2\xC1 \x9D\xFFq\xC2 3\x98bË¡\xC1P\xD8 Ql\xB2\xA6B\x9B\xD8fE\xAC(\xABM\x81
+\x94\xD5\xE7@)\x8Dy\xD0Q\x9B&lt;\xEBBH\x91r\xE7\xB6\xDCv\xEB\xED\xB7,
+\xFAV\xA2\x8B\xB6%)\xA5mu\xFAi\xA8 \x8DZj[0\xA0\x8C\xAA \xB1\xEA*\xAC
+\xC9J\xAB\xAD\xB8\xA4+\xAD\xBD\xFE\x9AP\xB0+[\xEC? D\xE1\x80
+t,A\xCAf\x85\xAE9+\x9F/\xD2z(\xB5\xD6b\x9B\xE0?9x \xA4\xDEa:\x85\x96ব\xF2\xCA,\xB7\xC0Ë„\xA9jx\x80\x90V\xE4 \x85&amp;9 z\x81\xD0JIxE?Ü„\xC4sÙ–\x839Ut\xA0\x83T\xE4\xA3.\xE0O \xE4\x93\x8D d\xCA        \xFEt\x81\x87&gt;\xF2uwŲA\xA4Q\x82
+ \xA0S\xBD+\xC4J+\xFF\xE27
+N\x94sN\xC0&amp;E\xC8\xE37q\xA0p\x857\xE0[d,\xA8L\xA1\x8D(q\xF0\xC0\x88\xF7\xC8S\xD0\xFA\xA0\xC1\xC3\xE8=hq%\x80\xA2
+\xD0\xDC\xD41        + \x870\xC7+@\xFF\x93\x88\xFBij\xC8;\x93hADx\xC4Bu\xBC\xB3D\xC0\x86(\x93\xA4\x8F(cT\xAF\xCA+x`\x97Pe\x99\xA5[\xE1-\x87/\xFE\xF8\xE2G@D        \xE8\x80        \xF8\xA0\xC0A\x96&lt;\xF1\xC9&lt;h\xB0\xC5iPqwA[&lt;\xA1\xB55]\xB0\x84\xF0\x90\x8FH\xA1% \xC8.Q\xB6&lt;`\xA1\x85\xB0\x8AI\x84\xC1\xE9@\xD9\xC0\xC1\xC5n\xF8@\xC3+\x94\x92\x80uУx=AO\xBE*\xD1N\xED\x8C;\x84&quot;\xD8Q        C\x8C!+\x8DHC\xFA\xFF\xD4\xF7        L&quot;f\xD0\xC5$\x9E\xB0\xBA\x81d\xA0i@Cz0\x89C\xE1G~X\x90 T\xE1        \x93P$Ì€:&gt;&lt;Or\xA1B
+\xBBw0\x82        P\xD8&amp;\x90:&lt;\xE1\xBE{\xC7:\xAA\xA0\x8AD\x8F \x89\xA8\xF8QÔ¡\x8F\xDA3H+J\xEBa/\x91É€$Z\xE1\xBD\x80\x8F|\x98̤&amp;\xC1Å…N\xBA\x85 ,`\xC1\xB8\xC0P\xFA\xE3\xE0\xC2+bJTr\xE1\xB8CH+SyX\xE6\xEE\xB3|\xA5-s\x97\xCBZ\xE2\xEE\x96\8%-wy\x90``\x98\xBF,\xA6?X\xA0J_\x9AE\x967\xE8$,#wK\\x837\xD8e5\xB9\xC0 lÞ€\x9A
+\xF9\xE6/\x9F\x99`\x98\xF3\x9C\xE8L'0\xA2\xCEv\x9E3+Þ‹\xA7&lt;\xE3\xB9\xC9z\xDA\xF3\x9Ev\xE1\xCA-6Q\xFFV\x83h\x819\xA2\xA0\x86\x82\xCC\xF3\xA0\xD5l R\xA6\xB0\xCF~\xE3!        A(9\xEF\x82T\xA1\xFE&lt;AI\xBC\x90h \xA5']*zQ\xC6\xC2n\x88\xA8D\xF3\xF2\x93}\xDAb\xB1 \x85JP(\x804\xA4\x95KK{\xF1Ò˜T\xA5ŧP\x87JT\x85p\xB7\xE0iF!\xC2Q\x82\xA7\xF2\xCC'R\xBAT\xA0T\xAA \xE5gFQJS\xD8T P\xE9H}aQ\x8C&gt;\xA5V\x9D\xA7T\xCB\xEA*\x9F
+\xB4\xA3j\xF8\xEA?\xC2\xEA\xBD|2\x94\xA70h \xD2Õ¢\xFA\xF5\xAF\xF7Ô§V\xFFÐ\x94 teiK Q\x84\x84\xB4.$5\xABF\x9D\xC1Q\x8F\xDE\xA7\x8Ae\xEBYS\xEAØ•\x8E4\xAB=\x95)M\xE3z\xD9\xC7\xE2e\xA7\xA1\xFDig\x83
+\xD8Öº\xB6e\x82\xED\xA7[+[Z\xCF\xFF\xCEe\xA1u\xA8^i\x8BØ°B\x96\xA4\xBA-\xACS{ \xD5\xDF*\xAB\xC1mmY{[\xE0\xFAs\xB7\xC3}\xAAoÇŠ
+\x8C\x9E\xE5\xABX_\xCB\xDD\xEEz         \xCB(C\x961\x80e\xFC\x83\xACT\xDD\xEC^\xDEEaVN\xED} yÍ‹^\xC6r\xF5?\xE1\xABi\xE3_\xB7\xCC\xF7\xBCH\xB5\xEFL\xF1\xEB\xDE\xFDz\xF7\xC0.\xEA\xE0\x8EDe\xB1\xD5\xE8\x802D\xE8׶\x8EKB\xF1b\x8Ce.\x92@  l\xD2\xFBR\xD8\xCFy/\x87Hv\x90\xBA\xFE\xE5\xCB8\x\xC1\x8BgÕ¡'\x9D\xB0@\ â¹š\xB6\xC3\xC6\xD8pAF\xE2\x9F\xF9\xC8sÉ€\x92\x97\x9C\xB7\xB9\xE3\xC3n\xB1yS\xDF\x9B\xF8z\x85N0;= atLHc d\x81H&quot;BaF\xC8Ћp4\xFF!X\xC6        x1\x82*ou\xC2g0\x86z\x8CY\x947\xC8ny\xE2\x8A|@\xBC
+9\x86\xFE\xD0\xD8Y\xBD9\xC6 \x83Y\x90\xF7Kn@+v\x83\xE4N{:E\xBD\xE8\x85\xCD\xDE\x93\xD2\xC1E?\xF4\xF3\xDEPg\xD8-.fÈ‚\xE1RaZ@\xE7\xBD\xF1\x9D\xD7\xFB\x8F\xFC!\xC3*\xBEu\x99\xF2FF\xBE\xE8\xC5[l\x96SK\x98\xD7ç‘®g\xD5j\xB8\xC4\xFA\xD3\xD8ζp&lt;0\x80$-\xBBÙ¹]*\xAF)la_u \xA55\xACs\xAAn\x97\xDAÛ²F\xB3ÉŠÜ¥\xE2\x82 \xAE\xB5\xB9ÕŠ\xA4n@\xDD \xE9\xEB^&lt;\xE0 \x82\xBB\x9B!P\xC9\xF7\xAA5\xFB\x90{ $\xE1\xF2\xB6\xF0J=\xD0 \xF3\xA4\x9B!\xE7Ö¶\xC67ΗY[\x9B\xDEVmAfm[
+\xB1\x80\xFFY\xB0\xC7\xDB\x95\x85\xD7\xFB\xA1p8\x85{}a~ D\xE1oi\xB9_|A\xF3\x95{f\xAEs\xA5\xB7dc&gt;s\x95×¼\xAF\xF9\x96\xF7\xB0u~r\x8E;\xFDé¿­\xE8-.Z\x83\x972\x87\xA6@Ù¾\x8BK^/4\xBD\x8DER/0\xF3u\xC6~ *HF+P\xC1\xF3\xADGUj\xBF\x85~\x80\xD8\xC2{$\xED)\xB2\x92\x81d\xA5\xA2\x9B\xE8\xE9\xD9+\x82\xE6\xEA\xF4\xA8S\xEFE\xD57\xC0\x8Dj\x9D\xAE\xECv W\xD0Ku\xAB\xC7\xC2\xF1Òž.\xD47\xCFy\xC9#\xBE\xF2\x8C\x8Fi\xD63\xCF\xF5\xB9`\xFA\xBC\xCE\xD6\xFA?z\x81鲇\xFC\xC1\xD5e\xD0Ñ£JV7Õ†\xE55Xv\xF2Ó½ D\xF71\xBC\xE0s\xD7\xC3\xC7e\xF2H}\xE3G?{\xBF\xF9\x89_\xFC\xF2\xF9\xCE[\xFF\xFA96\xB6\x8F\x80\xEEa\xAE\xBF\xFF+\xDE\xF0O\xE4\xFEH\xBF\xFA׿\xFE7\x9C\xDF\xBF\xE8\xE4/\xE6O\xFA\xFB\x83\xEF\xE7B2\x92\xC1\x85\xFA\xCF\xC8p\xD1\xFE\xA0\xFC\xE7\xC8\xD0 W \x80\xFF@\x80\xF1\xD7\xBF\xC04\xF0 \xC8\xC0W\xB0\x80\x8B0\x80\xF0Gl \x8F\xF0 \xC3p\x81\xA8\x81\xF4\xA7J\xE0\x81\xC3\xD0&amp;\xA8\xFE\x90\x81\xFF HWp\x82\x8F0 p\x83Ђ\x83 \x83W\xD0 0 \xC3 D(:\xF8\
 x82\xFE \x84J(\x84 \xF0N\xF8G\x83\xC40\x85TX\x85Sx\x84\xA3\xC0~Z\xA8~.8
+\x9E\xE0        \xB9\x90 +0\x86dX\x86+\x80}h\x98\x86\xC48\xC04 \xB1\xCEp\xFDr\xA0F  k\xB0\x83\x92g\xFEpBQ {xz`\xFE\xB0!\x80nP        \xFFa \xE0K`5\xD3\xB7\xB0=B\xB0\xE0^p.`\x90\x92K\xB0F\xE0\xE9\xB7\xE0Q)\x88\xE0n\xA8\xE8\xD5\xF2\xE6)l\xE8!\xBD\xA0
+ 2gg\xB0\xEA\xB0S0x\xD0+E\xC0'\xF1\xA6\xD8+\xE4\xE5 \x81P\xA6rV`\x87\xFE\xB0\xFE\x90\xE0\xA1V\x90\x88\xF8\xB1P\x88        !-`
+P\x80Fj\xB8\x8EOG\x8C6!C)' {\xB3        \xB70Ò¶on\xD7t\xE1\x8Ej\x90$^\xE0 p\xADR\xF6\x88\x8FG\xA7\x8FbÐ\xF9\x90\xA3\xE0\x85bx\x86H\xA8~\xD5\xF0\xE4P
+\x83@+{\xD1 ++b\xB0$Y\x92&amp;i\x92!\xF9f\xB8\x92fO\xD5'\xEE\x88$\xF18\x90y\x90\xF9\xA8V \xFF\xF9\xFEh39\x90\xC1\xB0\xABw \xA8@zngn\xECx\x94\xAE\xE5\x8F\xF0Ø“\xF3\xC8
+\xB6`\x93Í·RJ2X3\x8F` \xBD \x94\xA4\xF7^\xF1+,9\x86A[\xE8)ib9pjydyKg\xA9 \xC02Ø–!\x96j\xF9&quot;H\x97f\xE9&amp;\xE8\x847\xA8\x97!\x96[X\x96\xF1\x95cXM6\x95LI\x8FOy\x8F[\xF9X\x8A)\x90MÙ˜\xB9\x8F%\x87\x94\x98)T\x91\xE9\x93N        \x95\x96T\x8AY\x95?\x89\x95Z\x95\xC6\xF7\x95
+\xB1ZH\x98\xB1h\xB9\x96\xC0\x9A\x859p)\x97W \x9B\xB1w)\x82\xB89+З\x8Fp\x83\xBD)\xAA\xC9~\xB2\x93_\xD9Sr\x93WUW\x9B9\x99\x9E        yQ\xF1\x9C\x8C\x9D/\x99\x99\xD8yO\xEA\x90'\xB0        \xFF\xA0}\xDC\xF7}\xAE\xFF@$@\x91\xFB\x86~c\x89\x9B\xE8\xB7=\xD0=@+I\x97\xEA`\xDD\xF9\x9D\xFE0+\x90+P
+\x85\xD0 zO\xE8G&lt;\xE0\x9E\xD3p\x81\x809\xE8w+Ï \x9A\x92\xDBY\x9F\xE8\xA7\xE0\x97&amp;\xF8\x9FÞƒ~EX\x849\xA8\x9Ec)\x9F\xDCé†y\x985\xF7\x99\x91\xD7\xD4Ù™\x8Ei\x9A)J\x99\x8Fy\x99\xD99\xA3\xE4\x9EØ€\xE2I\x9Eg\xA1\xDEi\x9F\xE9\xD9ru\xB5\x9E\xED\xF9\x9E\xF1\xE9\xA1\xF8\xA9\x9F\xFC\xE9\x9F!9\x9F\xF5i\x9FJ\xA0
+\xA4Ï”\xA0 Ú QjZ\xA1\xC1y\xA1K\xA2ï·¡DØ¡R\xE89\x98\xB93\xA2]Ú¤&amp;:\xA6\xA6'3\xFF8\x93й\xA2k\x9A\x93n\xF1\xA2Ö™X4\x9A\xA7\xD6\xA0\xC0/\xF0\xA7|
+as[\xE0\xA7\xF7p\x87P&amp;\xF0\xA7A\xFF`[\xF0&amp;\xD0M\xF0?`&quot; \x90+\x8D:\x8D\xC0&amp;\xD0MpL\xC0L\xC0? |\x90\x8Eѧ\xA0:\xAA`\xF0\xAA\xA4z\xAA\xFB#|P]0\xAAÊ `\xA0\xCA\xD0        L`:\xB0J\xF1\xF0\x98\x80        \xB9\xBA\xAB\xBD\x8A        ?\xE0C\xF1\xF0=\xD0\x98\xF0\xAA\xAF\xD3\xEA\xAC\xC3Z\xAC&amp;@\xAD\xD6
+q`\x93\xA0\xAD\xFF\xC0R \xF0        \xDF
+\x87@\xEE\xACѧd\xC0        \x89\xF0        LL\xB0 /\xE0&quot;p\xC0\xA9/PdЬ
+\xA9\x9C`h\x9D\xD9P=`w\xB1\xA7\x8Ac\xE0a:`\xABk\xB1\xB7S=cpp\xC0bz\x9A\xB2\xAD\xC5dJ\xA6L\x96,I\xE0\xEA\xF0O\xCE\xFF`в\x91 \x8B\xB0\xC1`0\xBB\xB3\x80 ^`E \x87#C\xDBE\xE0x\xBEp\x920L{I\xFF\x90I\xE0*\xC1\xB5\x92\xE0 UK\xB4k\xC0O\\xEB\xB5DC\xB4I\x805\xB5\x8EÆ´ov\xB5D\xE3hg\xB0\xB6M\xEB\xB4D\xA3\xB6dÛ¶W\x8B\xB5^+\xB7x\xBBd{{\xB7        \xA1dd \xB8!\xB8LK\xB8\x85\xABd0 \xB3x\xAB\xB2\x8E\xDB21\xAB\xF1\xF2\xD0D\xB2\x80 &gt;\xE2k\xE0b\xD2V\xA0-np0 \xE1u\xD1\xE6\x8D^\x903X\x80
+\xEC\x92\xA6 #\x82h\xB1\xBE\xB0\x92\xE0\xAC\xE0 \x9B\xB0\x87'V;\xE0\xCC\xF2\xAF;n\xFF\xA03 0\xE1 Gr^\xDA&quot;#p\x99 hd0\x90\xD9\xE20n\xB0n\x80hH\xFF \x8E\xDB\xFB\xE8\xE2\x9CE\x92`\xF3.` c1\xB6pX\xBD\x8F[\xBF\xE1\xF3\xA1[(\xF8\xAB\x85\xFA\xBB\xBF\xEB׿\xFE\x9B~\xC0\xEC\xBF\xBC\xBF\x8C\xBF        \xFC\xA1lP  \xC1  P`\xEA' \xE0 &lt;\xC1\xBE0\xC1\xC1p\x8C\xBE\xC0%\xBC\xC1 \xC1#\xC1\xF0\xC1S\xF0\xC1',\xC1 _p\xC37\xFC\xC2\xE2 \x80\xC37l\xC3&gt;\xFC
+\x80=\xC4H\x9CÄ\xA0
+\xA0\xC4I,;\xC5R&lt;\xC5T\xBC!X\x9C\xC5Z\xBC\xC52 \xC2\xF0\xC5`\xC6b, \x81\xC2f|\xC6h\x8C\xC2l\xDC\xC6n\xFC\xC6\xB0\xC6p&lt;\xC7l,\xC7t \xC7v|\xC7nl\xBF\x99d\xD2!P\x8E&lt;\xAF\x8B~\xCC!\x81\xCC~\xFFF\xC8o\x913|\xFCÈl\xBF\x87\x8CÈŠ\xCC!\x85\xEC\x8D\x90\xC8n\xA1É‘\xDCÉž\xFCÉ„~v\xC9        1Éœ gLÊ \xBCʬL\xA3\x97P\xB0\\x97\xB0~ d\xA9\xB0         q        \xB0`+p6`s \xCB\xE1M,p\xA7*sP        \xC5l?\xA0Ì–\xCA\xCC\xCE|\xAB \xC1\xC0\xCCÍŒ\x970\x97Z \xC50s\xD0\x96\x90\xBBPs \xCE\xE5\ \xB1 Y \xCEY\xD0 ! Yp\xCFY\xE0\xCE ! \xEB\xB3&gt;\xFA\xAC\x8E\xD0\xD0 \xB1:PY\xA0\xFF\x9C\x90m\xD0:\xB0n15\xAD\Ñ­\xA5\x84@\xD0t@+\xD0\x84@ Q\x80\xC0Z\x90
+e\xB0@P6\x80@q\x9C)\xE0\x9E\xE9\xFF\xA9\xA0         \xA1\xA90ZP\xD3/\xBD\xD1A;\xFD\xD1.+)\x90&quot;]Þ\x80\xE0\xE0Ô€\x90M\xDD\xD4N\xF5 \xD5)`I-e0\xD3R\xFD\xD1\m\xA00\xDDc+\xF6\x90n\xED\xD6\xC0`\xFD\xD6n}\xE9G\xD7GM\x91x\x9D\xF6Px\x9D
+z\xFD[\x90vp؈M\x8A\xBDØŠmÑŽ}1\xA0\xCA\x81Q\xF0Qm\x91        \xAF\xC0+\xA7\xE79\x81\xA0        \x8D \xBC \xE0\x81\xB0\xA0\xB7\x87.\xB0R\x8C\xC5\xDC\xE0\xC5 \xBCH\xB0\xDC\xC0+L_,\x97Kl\xAF\xFA\xA0p\xFA\xC0+\xC2\xF0\xBB\xFB\xE1 \xA0\xB8n\xDC\xBB\xCDw.\x80\xDC5\xE6\xFAP\x8D]tn\xE0Ë¡        \xFA\x80sHV`*\x9A\x9APn \x91@\xF0#m1P\x90\xA2z \xA0\xDE \x91\x99\x90f\x8F]T8\xBC        Ñ½\xFC}K00\xDF
+\xA1;\x800\x80\xB2\x80jX\xBC\xD4qg\xA0        M\x8C\xC5_l\xE48\x81 l\xAC\xB5+\xCCH\xB0K\xFCÛ¿\xEDF\x80a\xA6Ý @\x80 Q\xF0
+\xE0\xE1\xD0\xE1\xCEpjÄ‹H\x80Ý¿\xF2\xB5 \xD9\xFF \x81\xF8+\x9A\xC0\xE3\x91.\xBF \x81\xAF\xA0\xA7\xAC\xB3\xE30\xDE\xD1
+\x99\xE0H;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssameditorspritegif"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/editor-sprite.gif (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/editor-sprite.gif                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/editor-sprite.gif        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,85 @@
</span><ins>+GIF89ad\xF7\xFF\xF4\xF4\xF5\xEA\xEAê²²\xB2\xDA*\xEE\xB5R\xFB\xFB\xFB\xF8z&gt;\xF9eQbbc=\xAF\xD8Ò¨KA\x8B\xA6\x97\xCE`\xF6\x960\xABz+\x90xX\xF9\xEA\xB7H\xAA\xF1\xA49\xD7ȯO\xA5aKIKÕ­+l\xD7\xFCÒŽG3\x9A&lt;9;\xE2\xE2\xE2RRS\xB7\x84/jjl\xED\xC66\xCBk8\xEC\xEC\xEC\xDA\xDA\xDAZZ[sst\xAC\xAC\xACͯ\x85DBD\xE3z\xC5É€`\x83\xF5\xF3c\xA3\xA3\xA3\xA6\x88l523μ\xAA\x9AЪ\xEF\xD9È\x82\x82\x8D\x8C\x8D\xF2\xD4G\xCA\xCA\xCAzI,\xD2\xD2Ò¨u\xEF\xF0\xF0\xE5\xE5\xE6\xF4\xCCx\xF4\xC9n\xF5\xDBU\xC1\xA3s\x91\x91\x92\x9B\x9B\x9B9\xA6\xCC벇\x8B\xB8\xB8\xB8\xF6\xEAf\xC3\xC3\xC3\xF7\xE8\x95c\xE7VÔ;\xFA\xE9\xC6$!&quot;\xB3\x8ED-*+{\x96k0Ü£ \xEE\xB1g\xF8\x93D\xEB\xE3\xDA\xFB\xF4\xE6\xDD\xDD\xDD\xF8\xF8s\x84\xB3qB\xF5ÖŠf6
+~|}\x9Cl\xB0\xA3\x91\xBE\xBD\xBE1\x94*Ê™#\x8E\xB5\xF9\xD6|\xE5\xB6!\xDA\xC0P\xF1\xEA\xE6\x85R\xAE\xB4p\xDCL\xF6\xE2Y\xF5R\x9C\xDB\xF2\x95\xCB\xFB\xF2\xD8\xED\x89\xF6Ù—\xF1\xE1Ò¶\xE4\xF5\xE5h\x8A\xCF\xD0\xE5Ø¥\xEA\xC2a\xE7Ç·\x9D\xAE;w\x99\xF0\x90iq\xCB\xEC\xEC\xE6\xE3\x92Y%\xDEÊ a\xBB\xC3\xC8x0-.Qtw\xEB\x9AYcZL\xFA\xE2v\xF5×»\xB0\xAF\xAEnoq\xEE\xD4V\xEC\xE6ts\x9C\xFF\x88\x81z\xA6Ù¡\x82\xC7\xEB\xF7IGH\xA4\xDF\xF8\xE0\xA9^]_'$%\xE8t\x83mQ\1tvwFDF3\x9A\xC0\xE5\xCAM@?@\xDD\xD3\xC4978QPQ\xE2Ô±MLMUUVddfz\x9Bqpq\}645nmn&gt;&lt;=+'(ONOk\x91\xDFuXWYVTUgfg1/0&quot; \xDF\xE0\xE0\x91\xD7\xF0\xFF\xFF\xE8\xE8\xE8\xE3\xE3\xE5\xD0\x97\xEF\xF1\xD5g\xFFl\xC8æ°‰\x88\x888C\xA2\xBC\xBB\xBC\xE7\xE3\xE1\xE4\xE4\xBC\xBC\xBC\xB6\xB5\xB5``a\xEC\xE8\xDF\x89-\x86\xD3\xEF\xD2\xEB\xDDi\xBEά\xD9̨\xE0\xF3\xBF\xE2\xCD\xF7\xFC\xFE\xF6Ê›\x98\x98\x98\xB7\xB7\xB7@\xB9\xE4\xAD^*\xE0\xDBÔ’\xB1\x8D\xD9\xF1\xFA \x82\xA6j\x8A\xE7\xE7\xE7hhi\x9F\x9F\xA0\xB0\x99wSbP\xC0\xBF\xC0\xA0k|g\xE
 3\xE3\xE3\xE2^\xAD3\xE1\xC1\x80\x93\x9D]\x9B\x8Ffggi\xA8\xA8\xA8\xAC\xA8\xA3L\x96C\xA0,&gt;6.\xEE\xE2\xC8\xF7\xCB[\x8E\xD6\xF0\x86\x86\x86yxxS\xBE\xE0\x96\x95\x95\xB5\xACCØ¿\x8B\xF0Õ—NZJ\xF1\xC0\x90\xECÅ«\xF3ͦ(\xAB(\xBB\xBA\xBBÞ™D\xD7\xD7\xD7\xFF\xFF\xFF\xEF\xEF\xEF!\xF9\xFF,d\xFF\xFF        H\xB0\xA0\xC1\x83*\\xA8\x90
+ \x9F\x80\x98C\xD5b!\xB1+\xB0\xFA+p5\xE9\x9CBW\x81HXi\x95\xBC        _1\xF9de\xD8N\xE7n\xA5\x94\xE5d%'\xCF\xFAÙš\xB9\xCA+YL\xB4)|%k\x95\x99d\xC9B\x89\x90\xA8\xD1De\xF5K\xA9\xA8\x81d\xA1\x98z\x90\x8BRY$6\x82ecDB\xFDÒŽ1K÷p\xE3ÊK\xB7\xAEÝ»x\xF3\xEA\xDDË·\xAFß¿\x80\xB6bS        ÞŠ(a\xEE\xC8p G\xB8*\xD1O\xC0\xDB\xA1\x82\x98};\x89\xD3\xA6 \xFB\xC5\xEA\xD0\xCF-Cy\x94zmfX\xB5h\x856\xB4\x96fØ«\xAA'.Þ‚\xD1\xEF\xB1i\xC1\xC0\x83 N\xBC\xB8\xF1\xE3È“+G(\x8F
+ fm\xBCs$\xE1\xA8T\xFD8\xB8=B9\xF7\xC1\x9E\xB8
+\xFF,e%\xE1\xA4X\xE2\xFF!*\x8F\x90\x84\x93\xF4\xD8|EI|?X\xF2+ßX\xFE\x82\xBD\xC8\xF2\xCE@\xB0\xC8\xF3_AÈ’\xC9+pa\xC5k+ a%`D \xE7$vPv\xE8\xE1N\xF5\x83CZ#\x8A\x98\xD6r(\xA6\xA8\xE2\x8A,\xB6\xE8\xE2\x8B~!\xE2Q\\xA2TW        B-\x84\x8A'\xBD\xFC\x83
+        \x90\x94\xF0\$`\xA3@4\xE0\xF01\xFF\xC0\xD2#'-d\xA3\xE1@\xA7Ti\xE5\x95X\x9E2P)\xFCC\xC9\x9F\xC0\xF3'Ϥ\x92\x80A\xF2\xC8R*b%P\xCA?AÄ’
+0\xD6i\xE7\x9Dx\xE6\xA9g\x9D\xBD\x90pH        @\xC0\x85        13$\x84\x83+A\x93\x8A        \x9DC€\x910I*\x90TB(\xAB\xD4O\xB4\xC0D\x97ݲ
+,\xFC\xF2\x96        38(C\xA5 \xA3\xA8(oA\xFF&quot;\x90'\xA4w\xD0!(\xD0@\x83\xA7̘P)\xA5\xE8z* \xE2\xDDNx\xA2\xD0!\xB2D        %S\xEAG\xE7@*\x9DyPU\x81L\xDBBVj\xEE\xE9\xED\xB7\xE0\x86+n\x8B\x87\xC6\xE5(\xA4o]\x9A\xE9[\xA2\x92j*C\xA8\xAA\xFAV\xAB\xAF\xC6:k\xAD \xE1\xAA+\xAF\xBE&quot;\xAC\xB0\xB1\xAB\x90\xB1!\xAB\xEC?\x98\x90p*\x85
+\xC4,A\xCFj\xF8\xC1oR;\xAD@\xD5
++'\x8C
+\x84\xAD\xB6\xDC\xCAJ\xC2+\x94\xBE\x95\xC0\xDAP\xEA\xB8,\xB7\xEC\xF2\xCB\xC5a&quot;\xB3a\x88\xA0\x92\xCD(\xD6\xF4N7_t\xF3\x819\xBF\xECS\xC4\xB6
+t\xCE\xB6Ø’\xC0$\xFDtB:\xAB\xE4        \xA24\xF1@9&lt;\x83B\x9F\xACÂŽ?:\xDC\xC3P\x83$\x99\xF8\xE3F 3l#        \xD9\xDE\xC4I*nD\xE0*40\xCF.\xFC\xFF6\x90'/H&quot;8I$\xE1+9Y@N \x81\xD0Z\xF0\x90\xC4h\xDC\xB5C\x940\xB1\x8E%Z\xF4\xA0\xC7\xFC\x8Cs\x83\xAD0t\xC1\xC3\xE9&lt;H\xC18r\x89\xAD\x9D\x9CQ@ Q댸0\xBAA}\xE4@M&lt;y|3\xC1'd\xE1E\xD4Q\x90\xC5\xDFpq\xC2        .daI?\xD8\x83%[lq\xC9%7x\xD1\xCF,                0KZi\x8DP=\xCC觯\xFE\xFA\xD3У\xC4\xD5]t\xF1\xC06\xD3\xE4\x87 \xF8!;P\xF0|+(\x94\xF0\xB5*\xB8\xBD\xD0 \x96\xF0\x833@\x80 J\x85Ú–?\xC2hh@\x90\x85m \xC4j\x8B@G\xB8$\xE8]\xB8S0\x8Ezx\xC0J\xA8\xE4`8+(a \Y\xC0t\x88\xB5ha v\xC0C:\xFF\xE6\xC1
+d?\xB8Z\xBA\xB0`8@\x94\xF0\xBA\x81\xE8`?\xE8\x82\x9ChF0\x82         &quot;\x82&amp;(A
+\x80X\xE9!\xEFPxj'=8\xE2\x978\xF8
+r%$xßB.\x9D\xF0\xEE P\xE0\x86=,qBf\xE7 Ó€@\xB2\xC7=\xEF\xC9!&quot;\xE0o\xCA\xA2\xF5y\xF2\x93\xA0l\xD9F        \x97)\xB0\x80&gt;\x98CL\xE9`
+7P+]9\x85\xEC\xEE \xB3|\xE5lY\xB4ä²–\xBC,\xDA/w9\xBA^N\xA1\x95\xBA &amp;.\xFD!E`s\x99,\x80%1O\x84\xCB\x8CÒ–\xCF\xC4e-\x82q\x83`\xF6Ò—\xC1\xE0\xE6+\xB2\x89\x90q\x93\x9A\xA9\x85:\xD7\xC9\xCEv\xD6B \xEE\x8C\xE7:\xB9B\xBEzÚ³\x9E\xA1̧&gt;\xF7\x89\xFF\xA50A\x81x\x81'8\x91\x89P|\x82#9\xD3\xD4=zT\xA0]\x99AJ\xBE\xBD(\xE5&amp;\xB1\xF0D*\xB2
+Q\x90 \xE6(E\xEF\xD9PY`T\xA3(\x80D(2\xD2o\xCE(=\xC5KT\xDAWciK+j\x98\xC6B\xA6+EX:R~\xF5\xA8HU\xC8W(\xA1\x8A\x9F\xBE\x84\xA3\xBD\xE9@vj\xCF~\xC24\xA0}Q)j\xD5bu\xA34Eh6\xA6JU\x9E\xF6\x94        '\xEB\xBABTÔ†\xA2\xD5        /8E*8\xA1\xD2OD\xD59UhY]\xFA\x9F\xB5\xA0CEHK\x93J\xD8\xC2\xF2Ó¡X+\xEAA'\x91\xD0\xECÕ¢W\x85\xA8V\xDBÖº\\xD4        U\xEB]uJU\x8B\xBE5\xB3)]\xEBD+K\x97\xAB5\xAC\x93\xC0)gw\xEAÙ¦\xFEÕ [e\xA8agK[\x98\xFF!\xF6/,GF\xB1\xDA\xC1\xF6T)\xAA\x80\xEB@3\x84\xF6\x96\xB4/
+%K\xDC\xC56\x{1B1FD5}Ep!\xDA\\xE3\xBA\x96U.s\x8B\xCB\xD8\xE3r\xF5\xB7\x94\xC8(]?\xF1\xD1Ø’\xB4\xB6\xE8M\xEF\xB8\xDE!\xA0\xB8\xC8&quot;\xB2\xF8\x87I\x8AR\x9A\x84\xBD+c\xAD\x9DØ‹.\x86\xBC7\xBE\xF3\xFDjJ\x85z_Y\xE4×·u\xE2\xAF{\xE1+_\xA6
+ؾ\xC1\xAF^\xBF\xAB\xDE
+[\x98\xB0\x90\x8B0\x95\xC8Ö—\xC0\xE1\xF0\x84e\xFBË…\xAFyÉŠ\xE42\x8B\x8C\xC0\xC3`\xB1@\xA0\xC7\xFA\xB6CR\x88Y\xFF\x92
+Y\xA4B.\x9E8\x85`&lt;\xE0\xC0
+\xA4(\x8F~\x9D@dP\xBE\xB0\x94\xA7\xCC\x88@X\xB6r\x8A\x97/\xBC71h\x8CK\xB9\xC22\xAC+z\x80=2\xE4\xFFA;p\xF2?f!!7/d\x88\x85\xFC\x96\x90ah\xC5Cv\xB0\x98\x8B,\x908AI\xB6qQ\x87\xDF\xF7\xC0E\xBCy\xE3^\x90\x80\xFE*\x84\xD0\xE9\xC7\xC2\xFC\xE1\xC0\xA6\xA2\xE7S4W\xCF\xC1!1=z$\x95\xA2\xB2\xAAW\x8D\xA2XÄ‚Iq!\x87\x89 \xE1|\xA2R\xB5l]m\xE2\xB7\xECX!\x96K\xAF\xDF\xC2!b\xD1Z\xC6.\xB1~\x8B-g\x81@\xB9\xD9tA\x85,b\xA7\xE5\xD8FFYÛŠ
+W\x9F\x9D\xAC\xB7\xB8\x89#kX\xC3\xC5\xDA&amp;nD?a\x93v0\xB7\xAF\xC1Í—r\xC7\xFB\xDC\xFD@\xF7M\xA8 \x82p\xD8\xDDß…7\xBC\xE5\xADc|\xFA\x85\xB2@x\xB9\xFD\x9B\xB4\xFD\x88T\xFE=\x95\xA2#\xE78CH&lt;\xEE\x8E{\xBC/\xC1&gt;q\xBA\xF9\xCD\xEEv\x8F\xD8\xE0\xFE\xFF\x86\xB6\xA6\x93\xE1\x90\xFBÚ±#n\xC4C\\xE2\x93\xEF\x98\xE2q\xA98`\xE2\xDBr\xB8\xE8\xD7i}H\xC9k\xDEs]\x9C\xE2\xC3f\xA9c\x97\xFE\xF1\xA6;=8_Akpc×—T\xA5\xDB.\xEB]\x8C|Û¬\xAE\xEC&lt;\x9B\xE9zD\xA7\xF2\x8ET\xBC\x80\xF15:&gt;\xCDavU\xE4z!\xB7\x98\xC4 \xC8wY\x99\xA6\xB4 &quot; \x8D\xC4M\xBB[\xA0h\xAB\xA1pi\xFD\xC9T\xCCV}\xAE\x99\xC0\xBAÍ‘ \x97\xA8\x9E\xEA2E\xBC\xE2\xD5\xCE\xF8\xA7[\xFE\xF2J%\xFCԫΉ\xAB\xAFt\xF1\x82\x9F &amp;&quot;\xF6\xC9
+$\xA6;q;\xDET\x98\xAB&amp;\x95\xEC\xCC\xD2`\xE2{u\xDF\xC0\xDD \x8F\xEFÉ—\xEF~/\x9A\x9BC/\xC7o&gt;\xF2\x9E\xCFzg\xD1\xE3o@\xF2\x9F\xA7&lt;\xF11O\xFD\xEA\xFF#\xD1Ⱦ\xB6/\x84\xEEkBb\xFF\xFF&quot;        \x98\xFF\xFC\xE8G\xBF5\xC8\xEFZ\x8C\x92\xF0\x8F\xFC\xFD\xB1\xFE\xEB\xFBc
+\xBB\xD8\xC5\xE4^\xF0\x82\xFE\xD1\xF7\x97\xFB'\xBC` O\xE0\xA4\x80\xED\xF7~\xB4\xD01@ \xBCO\x90\x80 \xF8(` @ \xB9P\x81È€\xF1GD\xC0\x81\xB9\xA0$H
+(X\xD0~\xB4POP\x82\x90 P\x83\xE0y\xC0\x82\xFEP0\xF8\xEA\xD0\xB9\x90 0\x84\x80\x83:\x84H\x84+\xF0L\xF8F\xF8-\x88 R8\x85T(\x85O\xD8é—…ç—ƒ\xFF\xD0\x8B\xB0\xAC\xC0
++0\x86\xA6P\x86fX\x86Ö—\x86jh\xB7Pp\xB1\xAB\x90        \xA3A\x90\xCF \\xB0\x88\x92\xF0\xFEp3p\x93\xB2\x87!A\xE0\x92
+\xDA
+/\x90A\xFF\x80        \xFEP\xAE\x803\xA0
+        \x81+\xEF\x80
+\xB3P\xE0\xAF\x90        \xDA\x97T\xD8P\xF0\xA3`~\xA9\x90
+@ \xA3H8\x90\xAB\xC0X\xE6\x97-\xE0
+\xA9F;`\xDA@5\xE7\xA50\x9C0t1\x98\x80
+\xA9\xC0\xA0+6ph\x82\x85        Ï€\xF2        \xE0=\x82_0
+\x878\xFE@\xE1\xA1\xFB@\xF2\xE0\xC0        \x84\x98\xD0\xD0\x90@4kØŽ\x98\x87        \x88\x90S\xC4@5\x99\x82\x9C\xB0/\xAA\xC0\xDB&amp;jjW\xF0\xF8\xA3\xC0$\xA2\xB0
+\x80\xFF\x80\x8F\xFAÈ#\xE6\x8FUEX\x919\x91\x8D\xE0\x85b\xB8:x~\xCD\xD5\xF0r\xB0 l\xE0Ç°+0X\xC0(\x99\x92*\xA9\x92%\xF9c\xF8\x920\x93cHO{\xA5r\x90K\xFFB\x8F\x99\x90\xF9\xB8\x8F\xFDHR)z\xF18\x90P\xF1        \x90        \xF7\xF8\xB1\xA0
+\x94\xA0|F\xA7h\xEE\x95\xB4\x90\xA9\x93\xF6\xB8\xA7\xB0\x90\xCA\xC7ZT9\x8F\xAF`\x94H\x89\x95KÙ”\xA0\xC7q\xD7 \x93/\x89 \xA0\x85\xFEÐ’\xB1\x9600\x97Ж\xBD\x97!\x80`\x83vyk9\x97\x82}\xF9\x96\xFE\xA0D\xC0\x8458\x98\xB1\x96Z\xE8\x96\x81\x96/\xF9M\x860C9\x8Fy\x90\xF7\x98\x95&gt;Y\x96$Õ•V\x99\x99ZÉ™A)\x95\xA4yT\x9Ey\x99W\xA9\x99 )} \xE5\x99_y\x94\x999\x96[9\x99.\x89\x96
+\xB1Y\xE8\x98\xB1qI\x97\xA0\x9B\x8F9y\xB9\x97O\x9C\xB1\x80        \x82\xC69\xA6`\x98\x88\xA9\xCB)\xB8\x99~\xC0\x89\x93\x90\xD9V\xF2\x93 UQ\xA7i\x90\xA9\x9A\xACÙ™\x95\xFF\xF9\x99X        \x9E5i\x93\xA5\x99\x9E,\x83$\x80\\x86}\xDA\xE7} \xC09a\xE5Ç–\xC6Y~l\xD0\xD0\xCB0\x92}\x89\xAE\xE0\x9E\xF6'\xB0\xF0t` \x83YO\xE5&lt;П\xCAP\x81\x8A9\xE5\xF7\x80 \xCC@Ú’\xECI\xA0\xE5G\x80\x98$Ø \xE4S~DH\x847\x98\x9Fl\xA0\xED\xC9e\x90\x99\x9E9\x9E\xA8        \x9A\x9B\x9E\xA3݉\x99噣穞B\x9AO\xF0
+ \x9F\xF4\xA9/\xCA~\xF8Yq\xA5\x9F\xFC\xE9\x9FÊ¢\x8A\xA0
+Ê %)\xA0j*\xA1\xEA\xA4'r\xA1\xBA\xA1_j!:\xA2`\x98*\x98\xA5Kj):\x84+
+\xA6Sq\x9F\x8DY41:\x93\xCAe\x9C\xE9\x8FtÑ£\xDF        \xA45Y\xA3i\x99Þ‰\xA3\xAB\xA4C\x9A\xA8\xC6\x8E\xFF\x8Eꨎ\xC0q\x8E\xCAv`\x90\x8E\xBA5A\xA9\x80H\xA05\xE0 ! +\x9C*|\xE0\xA1j,`F@\xAA\xD0f#\x8DZH\xABWЫ\xB1J\xAA$!0\xA0,\xE0 *p*\xE0 \x8A`5\xF0\xB1$\xAC\x86\x85PȪ\xAC\xCCZ\xBAp[0! \x92\xD0=P\xBDÚ«c \xAEE\xE4\xAD\xE0\x9A\xE3Z\xAEW0P Э\xC2\xEAH\xE0 \xE0\xAEW`P\xD09\xAD\xFFШ\xF5\x90}\xB0Fp\x8AP\xD2P \x90.0| +\xA0&gt;\xB0\x8F\x9A\x89P]\x90\xB7*0\xD0\xD0\xA3\xEA$ ]\xB0\xA9:0pY\x90Jp\x90Y\x90À\xC0\xFF\xA0;Ù³7\xE0\xAB\xA8&gt;[aV\xB4|\x86wV\x86eF\xABeae-\x80\xA9\x90        \xAB\xE0
+         C\xFB&quot;Ä\xA9\xB0;\xC0        _\x80eI+\x9F\xD0\xA2\xE0\xC3\xB1P\xB6`x'\x89gLp\xC0Ã\xB6_K+=\xB7\xB20\xB7jKF&quot;\xC0% x\xAB\xB7_k \xEF\xF0\xB20\xE0\x90\xB7t;\xB8\x9B6\xB7\xA0\xB8{KFXf \x87\xBBi\x82{W&amp;yk\xB9\x8B\x9B\xB4W\x96\xB7\xD8\xB9        ae\x8A\x9B\xB7^\x8BI&quot;  \xD0@\xB9\xD0 \xB5
+\x91\xB9F\xEB\xBA?;\xBB\xA0$\xB4SK\xA8+q\xA1+\x9Fp$ 1\x9F$p\xC1\xDA\xC0        \x8D\x85\x8D\x99\xF0\xA1p0 \xF1
+\xAFОڦ\xBF\xF0
+\xBF\xF0         @        _\xB0\x90p ×ˆ\xFF  \xC0-\xBE\x81\xB0\x87\xC7j1 \xAB\xC0\xBDQad\xE3\xD1 3\xAB\xA0$\xFF\xC0\xCD\xF2V\xC0        8\xB0\xA1+p\x90J\xD1,\xE7
+\x98
+\xDF+3@\xC0\xDD\xF2\xEB\x82\xC1\xBF\xF0\xC0\xDA d\xFF@\xA7 \xD7B\xBB\xAC&gt;-\xAA\x85\xC2Y8\xC2$\x8C~&amp;|\xC2\xE6\x97\xC2*\xCC\xC2'\xEC\xC2$ \xC3!,\xC3-\x9A\xC2\xF0\xD8`:l\xD8\xF0p~\xB1\xC3\xD9L\xB0:\xBC\xCA\xE8\xC3:\xC4: \xCA\xC8\xE0\xE0\xC4\xF0\xC5;\xCC\xC4:&lt; \xEF\xC5OL\xC5U\xFC`_ \xF0^\xF05 a \xC6j\xBC\xC6/\xC6V\xB0\xC6k\x9C\xC6:s&lt;\xC7PF\xC7x&lt;\xC7\xA1|\xDC\xC7~\xFC\xC7: \xB6;ȶ+IsȈ\x9C\xC8I\xFF#\xB7\xD0ÈŽ\xFCÈ|I\xB30É”\É–\xBCG\x97\x9CÉ”,\x9A\xACÉœ\xDCÉ—\xFC\xC1\x9F\xF4 \xE2!\xF0\x8B\xFBP\xCA\x90\xBD
+\xF1\xA6\xFCE\xC0!\xAC\xFC°\xA2|˸\xFC\xC1\xA4\xFC\xCA \x91ʲ \xAE|\xCApa˹\\xCC\xC6|\xCC!Ì°\xEF\xC2\xC2\xD0!ÊŒ\xB1\xEC!€\xCC\xD6|Í´[@0[ Q\x9B B5\xB0        Q\x9B` \xAA\xA5z\xDE|e\x80\xC0j\xE0\xE3L\xF3\x80e0\xAA\xF5|\xCFd`\xCE\xF0 5PK\xE0 @d\xA0QdP\xAA\xBA\xA0 ~\x90 \xB0\xCDMa\xD0 \xB1Q\xF0\xD0Q\xE0 
+Q0\xD2Q\xA0\xD1 
+\xF1?&amp;\xAD\xC5\xD0\xD2.\xCD\x909\xFF\xB0\xD2        Aa\x90X\x83\xCD@=[20s oas\xE00f\xC0C\xF0\xA9S        C\xB0q0\xE0U\xF0s
+\x91o\xD0\xE6\xF7\x95\x90        !\x95PR\xD6oFm:P        J\xEDX\xFDo\x90\xE1\xC8q)0t\xEDK@\xD7k}\x81\xD4|M\xD7Kp\x80\x9Di\xD0\xD41)\xE0\x80+Ù‰\x9D\x8E0H-\xD9o\xE0\x86\x90)\x90\xAD\xD0\xD9@\xE1Ø\xDD\xD9\xFC`~\xA5\xDD\xD9\xE1@\x9F\x9D\xDA\xF9\xA0ן\xDD
+\xB4\xCD\xDA\xFF\x80\xE1\x90\xBA\xBD\xDB\xD0Û¾\xDD\xDBA\xDCy1\xD5 80        c\xF56@8`j\xA11        o \xB7;Ø€        \xFB\xC0\xC7\xC30
+\xB3\x97-P}\xFFle\xB1-!3\xC080&quot;#`i\xFB\xBE;U\xAEp\xC2  p_\x80\xD8p\xBC\xD1+\xABP\xC2\xF0        \xB0
+\xE7\x80r\xD0\x9F0c5 \xAEp_@\x984\xA1+\xFF\x90+_sx\xDDp\x8D\xD9pÙ€\xBF \xA10\xA3\xF7@\x90+\xD0\xFD\xCF        \xF0\xE0\xE1 !67\xC2=[6\x90c
+
+\xF0\xE0\xE2 Q C{        \x81:\xB0\xB4\xB9h\xE0\xF0\xB0p:\x80\x87Õ #\xA0\x99\x8B+\xAEp\x8E\xF1 \xE7\x99d&quot;\x82\xF0 I\x8B        :\xD0\xDD  AS\xF2\x90:6\xD0\xE7\xF0        \xF3X\x87\xD0Q
+;p\xAB         `\xED\x8B\xBD\xC0\xE0\x83)\xCDl\xD0\xD0 \xDD 0\xE5a \xA3p\xBC\xCB+ \xBA G\xF0\x9E\xE0\xBEo16\xD0IB;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssameditorcss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/editor.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/editor.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/editor.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+.yui-busy{cursor:wait!important;}.yui-toolbar-container fieldset,.yui-editor-container fieldset{padding:0;margin:0;border:0;}.yui-toolbar-container legend{display:none;}.yui-skin-sam .yui-toolbar-container .yui-button button,.yui-skin-sam .yui-toolbar-container .yui-button a,.yui-skin-sam .yui-toolbar-container .yui-button a:visited{font-size:0;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-select button,.yui-skin-sam .yui-toolbar-container .yui-toolbar-select a,.yui-skin-sam .yui-toolbar-container .yui-toolbar-select a:visited,.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton button,.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a,.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a:visited{font-size:12px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a.up,.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a.down{font-size:0;line-height:0;padding:0;}.yui-toolbar-container .yui-toolbar-subcont{padding:.25em 0;zo
 om:1;}.yui-toolbar-container-collapsed .yui-toolbar-subcont{display:none;}.yui-toolbar-container .yui-toolbar-subcont:after{display:block;clear:both;visibility:hidden;content:'.';height:0;}.yui-toolbar-container span.yui-toolbar-draghandle{cursor:move;border-left:1px solid #999;border-right:1px solid #999;overflow:hidden;text-indent:77777px;width:2px;height:20px;display:block;clear:none;float:left;margin:0 0 0 .2em;}.yui-toolbar-container .yui-toolbar-titlebar.draggable{cursor:move;}.yui-toolbar-container .yui-toolbar-titlebar{position:relative;}.yui-toolbar-container .yui-toolbar-titlebar h2{font-weight:bold;letter-spacing:0;border:none;color:#000;margin:0;padding:.2em;}.yui-toolbar-container .yui-toolbar-titlebar h2 a{text-decoration:none;color:#000;cursor:default;}.yui-toolbar-container.yui-toolbar-grouped span.yui-toolbar-draghandle{height:40px;}.yui-toolbar-container .yui-toolbar-group{float:left;margin-right:.5em;zoom:1;}.yui-toolbar-container .yui-toolbar-group:after{
 display:block;clear:both;visibility:hidden;content:'.';height:0;}.yui-toolbar-container .yui-toolbar-group h3{font-size:75%;padding:0 0 0 .25em;margin:0;}.yui-toolbar-container span.yui-toolbar-separator{width:2px;padding:0;height:18px;margin:.2em 0 .2em .1em;display:none;float:left;}.yui-toolbar-container.yui-toolbar-grouped span.yui-toolbar-separator{height:45px;*height:50px;}.yui-toolbar-container.yui-toolbar-grouped .yui-toolbar-group span.yui-toolbar-separator{height:18px;display:block;}.yui-toolbar-container ul li{margin:0;padding:0;list-style-type:none;}.yui-toolbar-container .yui-toolbar-nogrouplabels h3{display:none;}.yui-toolbar-container .yui-push-button,.yui-toolbar-container .yui-color-button,.yui-toolbar-container .yui-menu-button{position:relative;cursor:pointer;}.yui-toolbar-container .yui-button .first-child,.yui-toolbar-container .yui-button .first-child a{height:100%;width:100%;overflow:hidden;font-size:0;}.yui-toolbar-container .yui-button-disabled{cursor
 :default;}.yui-toolbar-container .yui-button-disabled .yui-toolbar-icon{opacity:.5;filter:alpha(opacity=50);}.yui-toolbar-container .yui-button-disabled .up,.yui-toolbar-container .yui-button-disabled .down{opacity:.5;filter:alpha(opacity=50);}.yui-toolbar-container .yui-button a{overflow:hidden;}.yui-toolbar-container .yui-toolbar-select .first-child a{cursor:pointer;}.yui-toolbar-fontname-arial{font-family:Arial;}.yui-toolbar-fontname-arial-black{font-family:Arial Black;}.yui-toolbar-fontname-comic-sans-ms{font-family:Comic Sans MS;}.yui-toolbar-fontname-courier-new{font-family:Courier New;}.yui-toolbar-fontname-times-new-roman{font-family:Times New Roman;}.yui-toolbar-fontname-verdana{font-family:Verdana;}.yui-toolbar-fontname-impact{font-family:Impact;}.yui-toolbar-fontname-lucida-console{font-family:Lucida Console;}.yui-toolbar-fontname-tahoma{font-family:Tahoma;}.yui-toolbar-fontname-trebuchet-ms{font-family:Trebuchet MS;}.yui-toolbar-container .yui-toolbar-spinbutton{
 position:relative;}.yui-toolbar-container .yui-toolbar-spinbutton .first-child a{z-index:0;opacity:1;}.yui-toolbar-container .yui-toolbar-spinbutton a.up,.yui-toolbar-container .yui-toolbar-spinbutton a.down{position:absolute;display:block;right:0;cursor:pointer;z-index:1;padding:0;margin:0;}.yui-toolbar-container .yui-overlay{position:absolute;}.yui-toolbar-container .yui-overlay ul li{margin:0;list-style-type:none;}.yui-toolbar-container{z-index:1;}.yui-editor-container .yui-editor-editable-container{position:relative;z-index:0;width:100%;}.yui-editor-container .yui-editor-masked{background-color:#CCC;height:100%;width:100%;position:absolute;top:0;left:0;opacity:.5;filter:alpha(opacity=50);}.yui-editor-container iframe{border:0;padding:0;margin:0;zoom:1;display:block;}.yui-editor-container .yui-editor-editable{padding:0;margin:0;}.yui-editor-container .dompath{font-size:85%;}.yui-editor-panel .hd{text-align:left;position:relative;}.yui-editor-panel .hd h3{font-weight:bold;
 padding:.25em 0 .25em .25em;margin:0;}.yui-editor-panel .bd{width:100%;zoom:1;position:relative;}.yui-editor-panel .bd div.yui-editor-body-cont{padding:.25em .1em;zoom:1;}.yui-editor-panel .bd .gecko form{overflow:auto;}.yui-editor-panel .bd div.yui-editor-body-cont:after{display:block;clear:both;visibility:hidden;content:'.';height:0;}.yui-editor-panel .ft{text-align:right;width:99%;float:left;clear:both;}.yui-editor-panel .ft span.tip{display:block;position:relative;padding:.5em .5em .5em 23px;text-align:left;zoom:1;}.yui-editor-panel label{clear:both;float:left;padding:0;width:100%;text-align:left;zoom:1;}.yui-editor-panel .gecko label{overflow:auto;}.yui-editor-panel label strong{float:left;width:6em;}.yui-editor-panel .removeLink{width:80%;text-align:right;}.yui-editor-panel label input{margin-left:.25em;float:left;}.yui-editor-panel .yui-toolbar-group{margin-bottom:.75em;}.yui-editor-panel .height-width{float:left;}.yui-editor-panel .height-width span{font-style:italic
 ;display:block;float:left;overflow:visible;}.yui-editor-panel .height-width span.info{font-size:70%;margin-top:3px;float:none;}
+.yui-editor-panel .yui-toolbar-bordersize,.yui-editor-panel .yui-toolbar-bordertype{font-size:75%;}.yui-editor-panel .yui-toolbar-container span.yui-toolbar-separator{border:none;}.yui-editor-panel .yui-toolbar-bordersize span a span,.yui-editor-panel .yui-toolbar-bordertype span a span{display:block;height:8px;left:4px;position:absolute;top:3px;_top:-5px;width:24px;text-indent:52px;font-size:0;}.yui-editor-panel .yui-toolbar-bordertype span a span.yui-toolbar-bordertype-solid{border-bottom:1px solid black;}.yui-editor-panel .yui-toolbar-bordertype span a span.yui-toolbar-bordertype-dotted{border-bottom:1px dotted black;}.yui-editor-panel .yui-toolbar-bordertype span a span.yui-toolbar-bordertype-dashed{border-bottom:1px dashed black;}.yui-editor-panel .yui-toolbar-bordersize span a span.yui-toolbar-bordersize-0{*top:0;text-indent:0;font-size:75%;}.yui-editor-panel .yui-toolbar-bordersize span a span.yui-toolbar-bordersize-1{border-bottom:1px solid black;}.yui-editor-panel .
 yui-toolbar-bordersize span a span.yui-toolbar-bordersize-2{border-bottom:2px solid black;}.yui-editor-panel .yui-toolbar-bordersize span a span.yui-toolbar-bordersize-3{top:2px;*top:-5px;border-bottom:3px solid black;}.yui-editor-panel .yui-toolbar-bordersize span a span.yui-toolbar-bordersize-4{top:1px;*top:-5px;border-bottom:4px solid black;}.yui-editor-panel .yui-toolbar-bordersize span a span.yui-toolbar-bordersize-5{top:1px;*top:-5px;border-bottom:5px solid black;}.yui-toolbar-container .yui-toolbar-bordersize-menu,.yui-toolbar-container .yui-toolbar-bordertype-menu{width:95px!important;}.yui-toolbar-bordersize-menu .yuimenuitemlabel,.yui-toolbar-bordertype-menu .yuimenuitemlabel,.yui-toolbar-bordersize-menu .yuimenuitemlabel,.yui-toolbar-bordertype-menu .yuimenuitemlabel:hover{margin:0 3px 7px 17px;}.yui-toolbar-bordersize-menu .yuimenuitemlabel .checkedindicator,.yui-toolbar-bordertype-menu .yuimenuitemlabel .checkedindicator{position:absolute;left:-12px;*top:14px;*l
 eft:0;}.yui-toolbar-bordersize-menu li.yui-toolbar-bordersize-1 a{border-bottom:1px solid black;height:14px;}.yui-toolbar-bordersize-menu li.yui-toolbar-bordersize-2 a{border-bottom:2px solid black;height:14px;}.yui-toolbar-bordersize-menu li.yui-toolbar-bordersize-3 a{border-bottom:3px solid black;height:14px;}.yui-toolbar-bordersize-menu li.yui-toolbar-bordersize-4 a{border-bottom:4px solid black;height:14px;}.yui-toolbar-bordersize-menu li.yui-toolbar-bordersize-5 a{border-bottom:5px solid black;height:14px;}.yui-toolbar-bordertype-menu li.yui-toolbar-bordertype-solid a{border-bottom:1px solid black;height:14px;}.yui-toolbar-bordertype-menu li.yui-toolbar-bordertype-dashed a{border-bottom:1px dashed black;height:14px;}.yui-toolbar-bordertype-menu li.yui-toolbar-bordertype-dotted a{border-bottom:1px dotted black;height:14px;}h2.yui-editor-skipheader,h3.yui-editor-skipheader{height:0;margin:0;padding:0;border:none;width:0;overflow:hidden;position:absolute;}.yui-toolbar-colo
 rs{width:133px;zoom:1;display:none;z-index:100;overflow:hidden;}.yui-toolbar-colors:after{display:block;clear:both;visibility:hidden;content:'.';height:0;}.yui-toolbar-colors a{height:9px;width:9px;float:left;display:block;overflow:hidden;text-indent:999px;margin:0;cursor:pointer;border:1px solid #F6F7EE;}.yui-toolbar-colors a:hover{border:1px solid black;}.yui-color-button-menu{overflow:visible;background-color:transparent;}.yui-toolbar-colors span{position:relative;display:block;padding:3px;overflow:hidden;float:left;width:100%;zoom:1;}.yui-toolbar-colors span:after{display:block;clear:both;visibility:hidden;content:'.';height:0;}.yui-toolbar-colors span em{height:35px;width:30px;float:left;display:block;overflow:hidden;text-indent:999px;margin:.75px;border:1px solid black;}.yui-toolbar-colors span strong{font-weight:normal;padding-left:3px;display:block;font-size:85%;float:left;width:65%;}.yui-toolbar-group-undoredo h3,.yui-toolbar-group-insertitem h3,.yui-toolbar-group-i
 ndentlist h3{width:68px;}.yui-toolbar-group-indentlist2 h3{width:122px;}.yui-toolbar-group-alignment h3{width:130px;}.yui-skin-sam .yui-editor-container{border:1px solid #808080;}.yui-skin-sam .yui-toolbar-container{zoom:1;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-titlebar{background:url(sprite.png) repeat-x 0 -200px;position:relative;}.yui-skin-sam .yui-editor-container .draggable .yui-toolbar-titlebar{cursor:move;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-titlebar h2{color:#000;font-weight:bold;margin:0;padding:.3em 1em;font-size:100%;text-align:left;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-group h3{color:#808080;font-size:75%;margin:1em 0 0;padding-bottom:0;padding-left:.25em;text-align:left;}.yui-toolbar-container span.yui-toolbar-separator{border:none;text-indent:33px;overflow:hidden;margin:0 .25em;}.yui-skin-sam .yui-toolbar-container{background-color:#F2F2F2;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-subcont{padding:0 1em .35em;borde
 r-bottom:1px solid #808080;}.yui-skin-sam .yui-toolbar-container-collapsed .yui-toolbar-titlebar{border-bottom:1px solid #808080;}.yui-skin-sam .yui-editor-container .visible .yui-menu-shadow,.yui-skin-sam .yui-editor-panel .visible .yui-menu-shadow{display:none;}.yui-skin-sam .yui-editor-container ul{list-style-type:none;margin:0;padding:0;}.yui-skin-sam .yui-editor-container ul li{list-style-type:none;margin:0;padding:0;}.yui-skin-sam .yui-toolbar-group ul li.yui-toolbar-groupitem{float:left;}.yui-skin-sam .yui-editor-container .dompath{background-color:#F2F2F2;border-top:1px solid #808080;color:#999;text-align:left;padding:.25em;}.yui-skin-sam .yui-toolbar-container .collapse{background:url(sprite.png) no-repeat 0 -400px;}.yui-skin-sam .yui-toolbar-container .collapsed{background:url(sprite.png) no-repeat 0 -350px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-titlebar span.collapse{cursor:pointer;position:absolute;top:4px;right:2px;display:block;overflow:hidden;heigh
 t:15px;width:15px;text-indent:9999px;}
+.yui-skin-sam .yui-toolbar-container .yui-push-button,.yui-skin-sam .yui-toolbar-container .yui-color-button,.yui-skin-sam .yui-toolbar-container .yui-menu-button{background:url(sprite.png) repeat-x 0 0;position:relative;display:block;height:22px;width:30px;_font-size:0;margin:0;border-color:#808080;color:#f2f2f2;border-style:solid;border-width:1px 0;zoom:1;}.yui-skin-sam .yui-toolbar-container .yui-push-button a,.yui-skin-sam .yui-toolbar-container .yui-color-button a,.yui-skin-sam .yui-toolbar-container .yui-menu-button a{padding-left:35px;height:20px;text-decoration:none;font-size:0;line-height:2;display:block;color:#000;overflow:hidden;white-space:nowrap;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a,.yui-skin-sam .yui-toolbar-container .yui-toolbar-select a{font-size:12px;}.yui-skin-sam .yui-toolbar-container .yui-push-button .first-child,.yui-skin-sam .yui-toolbar-container .yui-color-button .first-child,.yui-skin-sam .yui-toolbar-container .yui-menu-b
 utton .first-child{border-color:#808080;border-style:solid;border-width:0 1px;margin:0 -1px;display:block;position:relative;}.yui-skin-sam .yui-toolbar-container .yui-push-button-disabled .first-child,.yui-skin-sam .yui-toolbar-container .yui-color-button-disabled .first-child,.yui-skin-sam .yui-toolbar-container .yui-menu-button-disabled .first-child{border-color:#ccc;}.yui-skin-sam .yui-toolbar-container .yui-push-button-disabled a,.yui-skin-sam .yui-toolbar-container .yui-color-button-disabled a,.yui-skin-sam .yui-toolbar-container .yui-menu-button-disabled a{color:#A6A6A6;cursor:default;}.yui-skin-sam .yui-toolbar-container .yui-push-button-disabled,.yui-skin-sam .yui-toolbar-container .yui-color-button-disabled,.yui-skin-sam .yui-toolbar-container .yui-menu-button-disabled{border-color:#ccc;}.yui-skin-sam .yui-toolbar-container .yui-button .first-child{*left:0;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-fontname{width:135px;}.yui-skin-sam .yui-toolbar-container .
 yui-toolbar-heading{width:92px;}.yui-skin-sam .yui-toolbar-container .yui-button-hover{background:url(sprite.png) repeat-x 0 -1300px;border-color:#808080;}.yui-skin-sam .yui-toolbar-container .yui-button-selected{background:url(sprite.png) repeat-x 0 -1700px;border-color:#808080;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-nogrouplabels h3{display:none;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-nogrouplabels .yui-toolbar-group{margin-top:.75em;}.yui-skin-sam .yui-toolbar-container .yui-push-button span.yui-toolbar-icon,.yui-skin-sam .yui-toolbar-container .yui-color-button span.yui-toolbar-icon,.yui-skin-sam .yui-toolbar-container .yui-menu-button span.yui-toolbar-icon{display:block;position:absolute;top:2px;height:18px;width:18px;overflow:hidden;background:url(editor-sprite.gif) no-repeat 30px 30px;}.yui-skin-sam .yui-toolbar-container .yui-button-selected span.yui-toolbar-icon,.yui-skin-sam .yui-toolbar-container .yui-button-hover span.yui-toolbar-icon{backgr
 ound-image:url(editor-sprite-active.gif);}.yui-skin-sam .yui-toolbar-container .visible .yuimenuitemlabel{cursor:pointer;color:#000;*position:relative;}.yui-skin-sam .yui-toolbar-container .yui-button-menu{background-color:#fff;}.yui-skin-sam .yui-toolbar-container .yui-button-menu .yui-menu-body-scrolled{position:relative;}.yui-skin-sam div.yuimenu li.selected{background-color:#B3D4FF;}.yui-skin-sam div.yuimenu li.selected a.selected{color:#000;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-bold span.yui-toolbar-icon{background-position:0 0;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-strikethrough span.yui-toolbar-icon{background-position:0 -108px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-italic span.yui-toolbar-icon{background-position:0 -36px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-undo span.yui-toolbar-icon{background-position:0 -1326px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-redo span.yui-tool
 bar-icon{background-position:0 -1355px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-underline span.yui-toolbar-icon{background-position:0 -72px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-subscript span.yui-toolbar-icon{background-position:0 -180px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-superscript span.yui-toolbar-icon{background-position:0 -144px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-forecolor span.yui-toolbar-icon{background-position:0 -216px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-backcolor span.yui-toolbar-icon{background-position:0 -288px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-justifyleft span.yui-toolbar-icon{background-position:0 -324px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-justifycenter span.yui-toolbar-icon{background-position:0 -360px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-justifyright span.yui-toolbar-icon{b
 ackground-position:0 -396px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-justifyfull span.yui-toolbar-icon{background-position:0 -432px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-indent span.yui-toolbar-icon{background-position:0 -720px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-outdent span.yui-toolbar-icon{background-position:0 -684px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-createlink span.yui-toolbar-icon{background-position:0 -792px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-insertimage span.yui-toolbar-icon{background-position:1px -756px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-left span.yui-toolbar-icon{background-position:0 -972px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-right span.yui-toolbar-icon{background-position:0 -936px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-inline span.yui-toolbar-icon{background-position:0 -900px;lef
 t:5px;}
+.yui-skin-sam .yui-toolbar-container .yui-toolbar-block span.yui-toolbar-icon{background-position:0 -864px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-bordercolor span.yui-toolbar-icon{background-position:0 -252px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-removeformat span.yui-toolbar-icon{background-position:0 -1080px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-hiddenelements span.yui-toolbar-icon{background-position:0 -1044px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-insertunorderedlist span.yui-toolbar-icon{background-position:0 -468px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-insertorderedlist span.yui-toolbar-icon{background-position:0 -504px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton,.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton .first-child{width:35px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton .first-child a{padding-left:2
 px;text-align:left;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton span.yui-toolbar-icon{display:none;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a.up,.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a.down{right:2px;background:url(editor-sprite.gif) no-repeat 0 -1222px;overflow:hidden;height:6px;width:7px;min-height:0;padding:0;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a.up{top:2px;background-position:0 -1222px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a.down{bottom:2px;background-position:0 -1187px;}.yui-skin-sam .yui-toolbar-container select{height:22px;border:1px solid #808080;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-select .first-child a{padding-left:5px;text-align:left;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-select span.yui-toolbar-icon{background:url(editor-sprite.gif) no-repeat 0 -1144px;overflow:hidden;right:-2px;top:0;height:20px;}.yui-skin-sam .yui-editor-panel
  .yui-color-button-menu .bd{background-color:transparent;border:none;width:135px;}.yui-skin-sam .yui-color-button-menu .yui-toolbar-colors{border:1px solid #808080;}.yui-skin-sam .yui-editor-panel{padding:0;margin:0;border:none;background-color:transparent;overflow:visible;position:absolute;}.yui-skin-sam .yui-editor-panel .hd{margin:10px 0 0;padding:0;border:none;}.yui-skin-sam .yui-editor-panel .hd h3{color:#000;border:1px solid #808080;background:url(sprite.png) repeat-x 0 -200px;width:99%;position:relative;margin:0;padding:3px 0 0 0;font-size:93%;text-indent:5px;height:20px;}.yui-skin-sam .yui-editor-panel .bd{background-color:#F2F2F2;border-left:1px solid #808080;border-right:1px solid #808080;width:99%;margin:0;padding:0;overflow:visible;}.yui-skin-sam .yui-editor-panel ul{list-style-type:none;margin:0;padding:0;}.yui-skin-sam .yui-editor-panel ul li{margin:0;padding:0;}.yui-skin-sam .yui-editor-panel .yui-toolbar-container .yui-toolbar-subcont{padding:0;border:none;ma
 rgin-top:.35em;}.yui-skin-sam .yui-editor-panel .yui-toolbar-bordersize,.yui-skin-sam .yui-editor-panel .yui-toolbar-bordertype{width:50px;}.yui-skin-sam .yui-editor-panel label{display:block;float:none;padding:4px 0;margin-bottom:7px;}.yui-skin-sam .yui-editor-panel label strong{font-weight:normal;font-size:93%;text-align:right;padding-top:2px;}.yui-skin-sam .yui-editor-panel label input{width:75%;}.yui-skin-sam .yui-editor-panel .createlink_target,.yui-skin-sam .yui-editor-panel .insertimage_target{width:auto;margin-right:5px;}.yui-skin-sam .yui-editor-panel .removeLink{width:98%;}.yui-skin-sam .yui-editor-panel label input.warning{background-color:#FFEE69;}.yui-skin-sam .yui-editor-panel .yui-toolbar-group h3{color:#000;float:left;font-weight:normal;font-size:93%;margin:5px 0 0 0;padding:0 3px 0 0;text-align:right;}.yui-skin-sam .yui-editor-panel .height-width h3{margin:3px 0 0 10px;}.yui-skin-sam .yui-editor-panel .height-width{margin:3px 0 0 35px;*margin-left:14px;width
 :42%;*width:44%;}.yui-skin-sam .yui-editor-panel .yui-toolbar-group-border{width:190px;}.yui-skin-sam .yui-editor-panel .no-button .yui-toolbar-group-border{width:210px;}.yui-skin-sam .yui-editor-panel .yui-toolbar-group-padding{width:203px;_width:198px;}.yui-skin-sam .yui-editor-panel .no-button .yui-toolbar-group-padding{width:172px;}.yui-skin-sam .yui-editor-panel .yui-toolbar-group-padding h3{margin-left:25px;*margin-left:12px;}.yui-skin-sam .yui-editor-panel .yui-toolbar-group-textflow{width:182px;}.yui-skin-sam .yui-editor-panel .hd{background:none;}.yui-skin-sam .yui-editor-panel .ft{background-color:#F2F2F2;border:1px solid #808080;border-top:none;padding:0;margin:0 0 2px 0;}.yui-skin-sam .yui-editor-panel .hd span.close{background:url(sprite.png) no-repeat 0 -300px;cursor:pointer;display:block;height:16px;overflow:hidden;position:absolute;right:5px;text-indent:500px;top:2px;width:26px;}.yui-skin-sam .yui-editor-panel .ft span.tip{background-color:#EDF5FF;border-top:
 1px solid #808080;font-size:85%;}.yui-skin-sam .yui-editor-panel .ft span.tip strong{display:block;float:left;margin:0 2px 8px 0;}.yui-skin-sam .yui-editor-panel .ft span.tip span.icon{background:url(editor-sprite.gif) no-repeat 0 -1260px;display:block;height:20px;left:2px;position:absolute;top:8px;width:20px;}.yui-skin-sam .yui-editor-panel .ft span.tip span.icon-info{background-position:2px -1260px;}.yui-skin-sam .yui-editor-panel .ft span.tip span.icon-warn{background-position:2px -1296px;}.yui-skin-sam .yui-editor-panel .hd span.knob{position:absolute;height:10px;width:28px;top:-10px;left:25px;text-indent:9999px;overflow:hidden;background:url(editor-knob.gif) no-repeat 0 0;}.yui-skin-sam .yui-editor-panel .yui-toolbar-container{float:left;width:100%;background-image:none;border:none;}.yui-skin-sam .yui-editor-panel .yui-toolbar-container .bd{background-color:#fff;}.yui-editor-blankimage{background-image:url(blankimage.png);}.yui-skin-sam .yui-editor-container .yui-resize
 -handle-br{height:11px;width:11px;background-position:-20px -60px;background-color:transparent;}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamheader_backgroundpng"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/header_background.png (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/header_background.png                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/header_background.png        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,5 @@
</span><ins>+\x89PNG
+
++IHDR#\xDA\xF7\xE3tEXtSoftwareAdobe ImageReadyq\xC9e&lt;@IDATx\xDA|\x8AI
+\xC00 ]\xF9\xFF7\xBF\xD6kcBé¡‚\xA1\xD1#&quot;0\xB3FU\xF9~\xDC\xFD\xC9LDDCD\xA8\xAA\xDE\xC6\xF3        ÞŽ\xC7/\x95\xC4W\x89\xFF\xBCz\x83IEND\xAEB`\x82
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamhue_bgpng"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/hue_bg.png (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/hue_bg.png                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/hue_bg.png        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,8 @@
</span><ins>+\x89PNG
+
++IHDR\xB7S\x9F^gAMA\xD6\xD8\xD4OX2tEXtSoftwareAdobe ImageReadyq\xC9e&lt;
+PLTE\xFDC\xFF!\xFD#\xFD.\xFF\xFD5\xFD0\xFF\xF6!,\xFF\xF63G\xFD\xF6\xF69\xFB\xEE\xF6G]\xFD'\xFDl\xFD\xF6@|\xFD+\xFF\xFDd\xFD\xFD\xF9\xA6\xC4\xFE9\xFF\x84\xFD\xF7g\xF7o\xF6\xFE\x96\xFD,\xFF,#Z\xFD3\xFF\xCF\xF7\x93\xF6\\xFF\xD8\xFEO\xFF\xF7?\xF8\xCD\xF8\xB9\xF6,\xF7P\xB1\xFE,\xFFAU\xFF\xE2\xFE\xEF\xFF6\xFF\xF9+\xFF0\xFD\xF9\xB0\xF7b\xFC\xFA+\xFF\x8D\xFD\xF9\xEC-\xFFX-\xFFP\xF6W*\x9D\xFD\xF9\x9B\x89\xFF\x81\xFF\x92\xFF/\xFF\x8B\xF9\xB9t\xFD\xAC\xFF.\xFFz\xBE\xFF-\xBC\xFD0\xFF\x9E\xDB\xFF\xD2\xFF\xF9\xF80\xD1\xFD1\xFF\xB13\xFF\xC5&amp;v\xFD\xFA\xCE\xFA\xD9\xF7x\xFB\xE4\xA8\xFE&quot;I\xFD(\x89\xFD-\xFFh2\xFF1\xFF\xA8\xF6 7\xFD\xF6+\xFF2\xFF\xBB .\xFD!?\xFD\xF6%&gt;\xFF+\xFD2\xDB\xFE\xF7\x81\xF8\xAF,\xFF&amp;0\xFF\x943\xE6\xFE$d\xFD,\xFF:\xF8\x87,\xFFH\xEC\xFE6\xFC\xFE'\x80\xFD\xF8~)\x93\xFD\xF7k\xF8\xD7q\xFF\xF8\x924\xFF\xD9\xFA\xC4\xF7u\xF6\xA3\xFF\xF7\xA6\xCE\xFE5\xFF\xE3y\xFF
 /\xC6\xFD\xF6\xFD\xF6^\xF6&amp;+\xFF 5\xFF\xEE\x9F\xFD\xF7\x8A %\xFD\xF7Y,\xB1\xFDc\xFF\xF7G-\xFF`j\xFF\x9A\xFF/\xFF\x82\xF6O\xF8\xC4N\xFD\xE5\xFF%m\xFD\xF7\x9C&quot;R\xFD:\xFDU\xFDA\xFD6\xFF\xF9\xE1+\xA7\xFD4\xF1\xFE\xC8\xFF\xBB\xFE\xF66.\xFFp\xF9\xFFI\xFF\xB5\xFF,\xFF2\xF6-\xF6\x88\x88\x88\xBB\xE2%\xA4\xDCIDATxÚ¤\xD6W;@\xE1+R\xCAHC\xA8PD*Ñ\x8C\x8A4\xA4\xA5\xA2-*4\x85\xF6\x92$ZT\xC2\xEC\\x8F\xAB\xEF\xDD\xF9'01I`b\\xC8Z!\xAB\x85|&quot;d\xA8\x90Ï„\xCCr\x8E\x90\xF3\x84\x8Cr\xBE\x90o\x85\xCC\xB2S\xC8x!\x84\xAC\xB2A\xC8B&amp; \xF9Q\xC8\xFBB6
+\x99.\xE4;!\xD7yK\xC8oBnò€‰B^r\x83\x90\xAB\x85| \xE4R!\x87\x85\xCC\xF2\xB8\x90\xDDB.2W\xC8eB\xC6Y&quot;d\x94\x90\x8B\x84\ \xE4!\xDF .\xE4W!? 9K\xC8!\xCF )d\x88\x90\xC1B\xCE2 \xFF\x9BO\x85\,d\xAC\x90=B\xD6 Y#\xE4!O\xF9IÈ•B6        9(\xE4a!\xAF Y)\xE4M! \x84\xFC.d\xAF\x90{\x85|,d\xB9\x90\x84\xBC,\xE4!\xAF        \xB9Q\xC8\xE7B&gt;\xB2C\xC8$!        Y'\xE4A!O        \xB9O\xC8KB\xEEr@\xC8R!        Y%\xE4!\xF3\x84\xDC.\xE4!\xD7        \xD9,\xE4_!WyQ\xC8.!\xB7
+\xB9P\xC8\xD3Bf &amp;\xE4 !g yR\xC8!!\xE3\x84&lt;'d\x90\x90\x84Lr\xBD\x90\xAB\x84|%d\x9F\x90mB&gt;r\x87\x90EB\xEE\xB2_\xC8{B\xEErT\xC8=B\xFE\xB2L\xC8\xFDB~2K\xC8\xDFBn2B\xC8cBòˆ·\x85,r\x93\x90K\x84,\xB2]\xC8!oyG\xC8V!7 \xF9RȵB\xBE2M\xC8!Ç„&lt;+\xE4]!S\x84\x9C+Sr:9\xC9?|\xE2\xE9t\xF6,\xFE{IEND\xAEB`\x82
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamimagecroppercss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/imagecropper.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/imagecropper.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/imagecropper.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+.yui-crop{position:relative;}.yui-crop .yui-crop-mask{position:absolute;top:0;left:0;height:100%;width:100%;}.yui-crop .yui-resize{position:absolute;top:10px;left:10px;border:0;}.yui-crop .yui-crop-resize-mask{position:absolute;top:0;left:0;height:100%;width:100%;background-position:-10px -10px;overflow:hidden;}.yui-skin-sam .yui-crop .yui-crop-mask{background-color:#000;opacity:.5;filter:alpha(opacity=50);}.yui-skin-sam .yui-crop .yui-resize{border:1px dashed #fff;}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamlayoutcss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/layout.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/layout.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/layout.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+.yui-layout-loading{visibility:hidden;}body.yui-layout{overflow:hidden;position:relative;padding:0;margin:0;}.yui-layout-doc{position:relative;overflow:hidden;padding:0;margin:0;}.yui-layout-unit{height:50px;width:50px;padding:0;margin:0;float:none;z-index:0;}.yui-layout-unit-top{position:absolute;top:0;left:0;width:100%;}.yui-layout-unit-left{position:absolute;top:0;left:0;}.yui-layout-unit-right{position:absolute;top:0;right:0;}.yui-layout-unit-bottom{position:absolute;bottom:0;left:0;width:100%;}.yui-layout-unit-center{position:absolute;top:0;left:0;width:100%;}.yui-layout div.yui-layout-hd{position:absolute;top:0;left:0;zoom:1;width:100%;}.yui-layout div.yui-layout-bd{position:absolute;top:0;left:0;zoom:1;width:100%;}.yui-layout .yui-layout-noscroll div.yui-layout-bd{overflow:hidden;}.yui-layout .yui-layout-scroll div.yui-layout-bd{overflow:auto;}.yui-layout div.yui-layout-ft{position:absolute;bottom:0;left:0;width:100%;zoom:1;}.yui-layout .yui-layout-unit div.yui-layout
 -hd h2{text-align:left;}.yui-layout .yui-layout-unit div.yui-layout-hd .collapse{cursor:pointer;height:13px;position:absolute;right:2px;top:2px;width:17px;font-size:0;}.yui-layout .yui-layout-unit div.yui-layout-hd .close{cursor:pointer;height:13px;position:absolute;right:2px;top:2px;width:17px;font-size:0;}.yui-layout .yui-layout-unit div.yui-layout-hd .collapse-close{right:25px;}.yui-layout .yui-layout-clip{position:absolute;height:20px;background-color:#c0c0c0;display:none;}.yui-layout .yui-layout-clip .collapse{cursor:pointer;height:13px;position:absolute;right:2px;top:2px;width:17px;font-size:0;}.yui-layout .yui-layout-wrap{height:100%;width:100%;position:absolute;left:0;}.yui-skin-sam .yui-layout .yui-resize-proxy{border:none;font-size:0;margin:0;padding:0;}.yui-skin-sam .yui-layout .yui-resize-resizing .yui-resize-handle{display:none;zoom:1;}.yui-skin-sam .yui-layout .yui-resize-proxy div{position:absolute;border:1px solid #808080;background-color:#EDF5FF;}.yui-skin-s
 am .yui-layout .yui-resize .yui-resize-handle-active{zoom:1;}.yui-skin-sam .yui-layout .yui-resize-proxy .yui-layout-handle-l{width:5px;height:100%;top:0;left:0;zoom:1;}.yui-skin-sam .yui-layout .yui-resize-proxy .yui-layout-handle-r{width:5px;top:0;right:0;height:100%;position:absolute;zoom:1;}.yui-skin-sam .yui-layout .yui-resize-proxy .yui-layout-handle-b{width:100%;bottom:0;left:0;height:5px;}.yui-skin-sam .yui-layout .yui-resize-proxy .yui-layout-handle-t{width:100%;top:0;left:0;height:5px;}.yui-skin-sam .yui-layout .yui-layout-unit-left div.yui-layout-hd .collapse{background:transparent url(layout_sprite.png) no-repeat -20px -160px;border:1px solid #808080;}.yui-skin-sam .yui-layout .yui-layout-clip-left .collapse{background:transparent url(layout_sprite.png) no-repeat -20px -140px;border:1px solid #808080;}.yui-skin-sam .yui-layout .yui-layout-unit-right div.yui-layout-hd .collapse{background:transparent url(layout_sprite.png) no-repeat -20px -200px;border:1px solid #
 808080;}.yui-skin-sam .yui-layout .yui-layout-clip-right .collapse{background:transparent url(layout_sprite.png) no-repeat -20px -120px;border:1px solid #808080;}.yui-skin-sam .yui-layout .yui-layout-unit-top div.yui-layout-hd .collapse{background:transparent url(layout_sprite.png) no-repeat -20px -220px;border:1px solid #808080;}.yui-skin-sam .yui-layout .yui-layout-clip-top .collapse{background:transparent url(layout_sprite.png) no-repeat -20px -240px;border:1px solid #808080;}.yui-skin-sam .yui-layout .yui-layout-unit-bottom div.yui-layout-hd .collapse{background:transparent url(layout_sprite.png) no-repeat -20px -260px;border:1px solid #808080;}.yui-skin-sam .yui-layout .yui-layout-clip-bottom .collapse{background:transparent url(layout_sprite.png) no-repeat -20px -180px;border:1px solid #808080;}.yui-skin-sam .yui-layout .yui-layout-unit div.yui-layout-hd .close{background:transparent url(layout_sprite.png) no-repeat -20px -100px;border:1px solid #808080;}.yui-skin-sam 
 .yui-layout .yui-layout-hd{background:url(sprite.png) repeat-x 0 -1400px;border:1px solid #808080;}.yui-skin-sam .yui-layout{background-color:#EDF5FF;}.yui-skin-sam .yui-layout .yui-layout-unit div.yui-layout-hd h2{font-weight:bold;color:#fff;padding:3px;margin:0;}.yui-skin-sam .yui-layout .yui-layout-unit div.yui-layout-bd{border:1px solid #808080;border-bottom:none;border-top:none;*border-bottom-width:0;*border-top-width:0;background-color:#f2f2f2;text-align:left;}.yui-skin-sam .yui-layout .yui-layout-unit div.yui-layout-bd-noft{border-bottom:1px solid #808080;}.yui-skin-sam .yui-layout .yui-layout-unit div.yui-layout-bd-nohd{border-top:1px solid #808080;}.yui-skin-sam .yui-layout .yui-layout-clip{position:absolute;height:20px;background-color:#EDF5FF;display:none;border:1px solid #808080;}.yui-skin-sam .yui-layout div.yui-layout-ft{border:1px solid #808080;border-top:none;*border-top-width:0;background-color:#f2f2f2;}.yui-skin-sam .yui-layout-unit .yui-resize-handle{backg
 round-color:transparent;zoom:1;}.yui-skin-sam .yui-layout-unit .yui-resize-handle-r{right:0;top:0;background-image:none;zoom:1;}.yui-skin-sam .yui-layout-unit .yui-resize-handle-l{left:0;top:0;background-image:none;zoom:1;}.yui-skin-sam .yui-layout-unit .yui-resize-handle-b{right:0;bottom:0;background-image:none;}.yui-skin-sam .yui-layout-unit .yui-resize-handle-t{right:0;top:0;background-image:none;}.yui-skin-sam .yui-layout-unit .yui-resize-handle-r .yui-layout-resize-knob,.yui-skin-sam .yui-layout-unit .yui-resize-handle-l .yui-layout-resize-knob{position:absolute;height:16px;width:6px;top:45%;left:0;display:block;background:transparent url(layout_sprite.png) no-repeat 0 -5px;}.yui-skin-sam .yui-layout-unit .yui-resize-handle-t .yui-layout-resize-knob,.yui-skin-sam .yui-layout-unit .yui-resize-handle-b .yui-layout-resize-knob{position:absolute;height:6px;width:16px;left:45%;background:transparent url(layout_sprite.png) no-repeat -20px 0;zoom:1;}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamlayout_spritepng"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/layout_sprite.png (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/layout_sprite.png                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/layout_sprite.png        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,13 @@
</span><ins>+\x89PNG
+
++IHDR+\x85\xCF\xD3gAMA\xD6\xD8\xD4OX2tEXtSoftwareAdobe ImageReadyq\xC9e&lt;oPLTE\xFF\xFF\xFF\xFE\xFE\xFE\xE7\xE7\xE8\xE2\xE2\xE3\xEB\xECì––\x96\xF0\xF1\xF1\xF4\xF4\xF5\xF9\xF9\xFA\xFD\xFD\xFD\xF7\xF7\xF7\xFB\xFB\xFB\x83\x83\x83\x92\x94\x97\xF2\xF2\xF2\xF6\xF6\x{1BEFBE}\x94\x94\x95\xF3\xF3\xF3\xF5\xF5\x{155555}\xF0\xF0\xF0\xEC\xEC\xED\xE9\xE9ê””\x94\xB7\xB7\xB7\xB5\xB5\xB5\xAB\xAB\xAB\xE8\xE9\xE9\xD9\xD9\xD9\xE4\xE5妧\xA7\xA8\xA8\xA8\xED\xED\xED\xE5\xE5\xE6\xFF\xFF\xFF\xC1\xA35\xF0%tRNS\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF?\xCFBOgIDATx\xDAbPQQa`! LA0\x84\x83\x9Bb%\xACDDL13C\xCCdS\xBC\xE2(Jx\xB1(agGV\xC2\xC9IP        #JaJH\xF13!X\x86*\xF7+\x82ÍŠA!Y\xD1\xD5s*q2\x80Lf\x85(\xD9\xC5\xD9\xB2&quot;\xB2&lt;H\xB2\x9Cxey0dÙ±\xE8 ~\x907\xF8A\xA8\x8C_ \xE2\xC8\xEEWae@\xB0Q\xC4U\xB0\x8B\x83%JH\xD0\xCBv1\x84\xCD.\xAE,ÎŽE
 +'\xAF\x88'\x94\xCD X\xF5\x8A\xF3b\xD5 \x82z\xD9%\xC8\xD7\xCBÎŽU/\xBBzy\xD0\xF4B+,Õ\xA3 \x96\xE9\x903 &amp;\x9B3^\xB0\xA5L&lt;jX\xD1s(~\xF58\xD9 8\xCCÄ¡\x9E\x95\x814wb        +H\x98\xF3\xF0p\xC2\xD8\xEC&lt;&lt;\xEC*H\xE1OP/'\x92^v\xF5\x82\x92        \xDC^v\xD2\xF4\x82\x926&quot;+\x93\xE8fN\xF2\xFDK\x89\xBD\xC8zEHÔ‹G\xEC\x84\x95\x88\xBDh-\xA3
+A +\xFC\x82J^\xD0;oz\xFFg&lt;\x9B\xC7rB\x9C\xE5\x82X#\xFC\xFA\xBB|3Gl\xC7bÝtS\xF4FY\xCE\xFB\xD4\xFD\x9E\xCC.\xC6\xFFe\x9A!'\xBE\xED\xCC*\xE4d\xED\xE9\x97\xE8\x91\xEE\xDCN\xC6\xC6\xEE\xABk\xADMt\xD1\xC1\xE0R\xF6Þ—P\xE8~-\xA8\xA8\xD0!\xA3\x91Ñ‹\xC8\xC8P-\x92\x81Q\xB4$\xACd\xC9X%\xB2I\x8E\xC8&amp;9&quot;\x9B\xA4\xB6\xB12\x87\x8F\x84\xCC\xD0#g\x96\xDC\xD9E\x96gÜ‘)\x94\x90$\xE4 \x96\xC8x\xDC\xD8\xF6Ô–\xB4\xAF\xB7\xFC
+\xC0l\xAC  A4\xC5,1\xDA&quot;\xE4`+Ń\xFF\xFF\x8D6\xB1(q'5\x82\xB8.=\xED\xA1\xF4u\x96\x99)\xCA\xD6}\xEA\xDBiz\xA4\xCE2i{8\xA0\xF7\xFE\xC3\xF6\xF9\xBD5\xBF\xBD\xAE\xDBmz\xB4\xEE\xD8\xE6\x83\xDF\xFE\xDD-\xCC0\xBD*\xE1U        n\xA3\xCEV\xF9sme3\xD5Wg{&amp;Ü¢\xCA;[/b\xE6];\xFB-\xF6\x92\xAE \xF9)\xB7\xDE\xD3&lt;\xA9꿘+\xB3\xF0V\xE7\x8E\xF3\xA4Z]\xDA\xDFh\xED\xE5\xD5\xFD6\xCB\xFC\x8A\x8D!{\xC4\xC6\xE7\xB0\xB1Cl\x9C\xF1t\xD9hOI\xB7O\xEAÖŸ\xE96\xE3!\xDDX\x9B-\xD3        \xB6,\x9B`˲        \xB6,\x9B\x93\x91&lt;Z\xF5\x9B}\xD0/#t\x8B\xD8N\x91H\xB2+\xD6u\xDDB׬[:\xCAf\xDDFk\xF5o\xB1uQ&lt;I\xB6\xE0v\xBAI}\xB6\xFAd\xBA\xB3Ö›\xBCj\xDD\xDAl\xA8\xB3{\xF6Û¡U7G\xD1)\xE8v\xA0\xB3mq\x82pz\xE1\xCC\xC6z\x86\xDAj\xA1\xD0\xFF\xFFoצw\xDA&amp;vR\xE8\x9BEÄ—A\x82Of\xCC\xBDzj\xE6uzA\xAB\xD5l/P\xED \xDA\xD8E\x9D\xC1X\xC5\xD5\xF1'\xE8\xA8Z\xA5\xA5\xEADU\xAB ^\xAB\xD0*6\xACu׳_\xAEO\xC6y\xF0\xC2x\xD11Do\xAE\x8A\x9Bz\xC3;\xC3Y\xE0\x8C\xF3\xE6\xCEz=\x94\xA5\x8D\x87T:'\xC3O\xE11\x99
 \x9EÕ…\xDBt\xF5\xA5&amp;Ë°\x94v\xEC\xEFH\xB7\x9BVÓ­aHi\x8D\x94\xD3dI\xBB\xF1xA[K\xF9kw~&lt;^\xD0V\\xDAÕ°\xA7\xB3\x9C,h\xBF\xEE냹I\xEF\x8Ar\xB3V\xC8aܬr7ky\xC7\xDC\x85[\x9E\xDF&gt;\xC4oL\x8D\xF1a~cj\x8C\xF4[\xC0W\xB8a\xDC&amp;nC\xB9\x83s\xAB\xBFM\xDCV\xB8\xC19
+\xE1f\x8C\xEFQnCG\xC4^F\xB8\xA9\xF3ω\x9F\xC2-\xC3o!)1n\xF0\xF7m渧~ IY\xB8ep\xFBv\xBDøI\xA2u-Âg\x83\xAB}GG,'\xFF\xABp\x83\xB8IFm\xD8\\xB3Ï ~\xEB\xF6}\xFB\xCB\xEA\xC2+\xF7\xDBU\xF9M&lt;d\xC4C\xB7\xE0Mp]\xE2z\xFF1~\xFBIS\x94\x99\xC3%\xE6IEND\xAEB`\x82
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamloadinggif"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/loading.gif (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/loading.gif                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/loading.gif        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,27 @@
</span><ins>+GIF89a\xF7\xDC\xFA\xFA\xFA\xF9\xF9\xF9\xF7\xF7\xF7\xF6\xF6\xF6\xF8\xF8\xF8\xF5\xF5\xF5\xEF\xEF\xEF\xF2\xF2\xF2\xF3\xF3\xF3\xF0\xF0\xF0\xE8\xE8\xE8\xF1\xF1\xF1\xD1\xD1\xD1\xF4\xF4\xF4\xD3\xD3\xD3\xEC\xEC\xEC\xEB\xEB\xEB\xD9\xD9\xD9\xEE\xEE\xEE\xDF\xDF\xDF\xE2\xE2\xE2\xCE\xCE\xCE\xD7\xD7\xD7...---\xD2\xD2\xD2\xDE\xDE\xDE\xDA\xDA\xDA\xE1\xE1\xE1~~~\xA2\xA2\xA2___vvvoooVVVTTT^^^\x8C\x8C\x8C///&lt;&lt;&lt;PPP333\xE0\xE0\xE0&quot;&quot;&quot;   \xD6\xD6\xD6\xE7\xE7\xE7\xCA\xCA\xCA\xDC\xDC\xDC\xE9\xE9\xE9\xD5\xD5Õœ\x9C\x9C\x97\x97\x97uuu\x8A\x8A\x8A\xCB\xCB˃\x83\x83\xAE\xAE\xAE\xA4\xA4\xA4\xC9\xC9\xC9+++\xAD\xAD\xADKKK,,,666aaammmSSS444;;;\xD8\xD8\xD8\x88\x88\x88777\xB6\xB6\xB6\xB4\xB4\xB4\x98\x98\x98\xC5\xC5\xC5xxxYYY\xB8\xB8\xB8sss\xAA\xAA\xAA(((\xDB\xDBÛ¬\xAC\xAC\x9F\x9F\x9F\xA9\xA9\xA9###\x94\x94\x94\xB1\xB1\xB1yyy\xCD\xCDÍ“\x93\x93\x87\x87\x87!!!hhhRRR\xE5\xE5å¹¹\xB9fffOOO]]]\x9B\x9B\x9B\xB3\xB3\xB3ttt\xA7\xA7\xA7888***)))CCCJJJ\xEA\xEA\xEA111iii\xAB
 \xAB\xAB555\xB7\xB7\xB7NNN\xC8\xC8\xC8999\xBC\xBC\xBC\\\ZZZ\xED\xED\xEDeee\xD4\xD4\xD4wwwqqq\x92\x92\x92GGG\xE6\xE6\xE6\xC7\xC7Ç•\x95\x95\x8E\x8E\x8Eggg\x8F\x8F\x8F\xB5\xB5\xB5@@@222\x81\x81\x81\x8B\x8B\x8B\xA8\xA8\xA8\x84\x84\x84===\x86\x86\x86EEE\x80\x80\x80kkkWWWppp\xC6\xC6\xC6%%%UUUHHH\xCF\xCFÏ\x9D\x9D\xBF\xBF\xBF\xE4\xE4ä‘‘\x91[[[\xE3\xE3ã»»\xBB\x9E\x9E\x9E\xDD\xDDݲ\xB2\xB2|||\xA3\xA3\xA3:::$$$&amp;&amp;&amp;\xC0\xC0\xC0\x82\x82\x82\xD0\xD0\xD0zzz\xBA\xBA\xBA\xB0\xB0\xB0\x96\x96\x96\xCC\xCC\xCCjjj'''\x8D\x8D\x8D}}}&gt;&gt;&gt;lll\xAF\xAF\xAF\x9A\x9A\x9A\xC4\xC4\xC4LLL\xA0\xA0\xA0\xBE\xBE\xBEBBB\x90\x90\x90bbbQQQ{{{MMMrrr\xC3\xC3\xC3AAA\xC1\xC1\xC1\xA5\xA5\xA5\xC2\xC2\xC2000\xFB\xFB\xFB\xFC\xFC\xFC\xFD\xFD\xFD\xFE\xFE\xFE\xFF\xFF\xFF\xFF\xFF\xFF!\xFF NETSCAPE2.0!\xF9        \xDC,\xF9\xB9        H\xB0\xE0\xC0m$\xA8M[B\x85 \xB3]Æ-
 B\x87^#@\xDB\xC3mr\xD3F@\xC0\xB61\xB2\xEC\xB0p@[\xB6l.G\xD8\xC6J#WÚˆ`\xB1+[Ü°8\x85' \x9F4,i\xEAl\xA0\xD9TJr\xC2\xC28\\xCC\xF9 \xC0\xB6&gt;Lz\xB0M\xC05\x83\x8E\x95Ú³-\x80\xB6&amp;f+\x80@\xC0+\xB4\x9D\x92\x88\xED\x9A E?:)X`\xA0\xC16\x89\xD7h\xBB\xB6\xEDS3V\x88\xE26\xD0!\x92\xA7&amp;%\xDA\xCC\x84t%\xE9\xF2td\x80W\x86@\xB8#\xEC\x9A0@8\xB8\xC6+$B2\xCBR`\xA8\xB2J\x84\xAF\xD9j?,\xC0@Í&amp;\xAF\xD0&amp;\xFC\xE3×:\xFF\xB8\xB09\xF5\xEA\xD6Eb\xAF!\xF9        \xDC,\xFB\xB9        \xB8\xAD\xE0\xC0\x83\xB7i+\xB8+\xA1\xC3l×®-4è›\xB6`\x9B\xD8\xD0\xE15Ù´ac\xA8m\xE1Am\xB4\xC9a@\x85Ç“'
+Ć\xAD\x93\x88%a\xB4\xAC \xA2!fCl\xD9\xF4j\xA5ì©)&gt;Jp\x88\xC9m\x80\x806j%Ø–\xED\xC0\x877J  \x80\xED
+ \xB0\xAD\x82\x8AFkr\xB8\xB6펊4, @\x80\x89$        \x9B&quot;\x84\xAC\x90H
+H@\xA0`\x89:(\xB3\xBDptÎ…m
+, \xEADm\xD4È…hB\xB6m l&lt;2\xB0-\xC3m3\xB9\xE3dKM&amp;@e\xC3\xC6\xED4 zZ\xB4h\x83\xA9\x87O\xB0p\xE5\x87\xB3&lt;](J\xE0\x99+\xDCX18\xC9\xEA\x99c\xCFNq`@!\xF9        \xDC,\xF6\xB9        \xC8m\x9BA\x82n˦\xED`Â\xDA\xB8\xD6p\xDBCnÚ®@1\x9BC\x82\xDA&lt;f\xBBf\xB0\xA4E\x85 \xFA\x81\x85\xD4\x93\xB7        \xC8V\xC1Ñ‘.P\x98\xE9\xF3\x9A\x80m\xE8\\xF3\xE1\x8A&quot; \xB65Ķ0\xD6
+
+.\xF8\xF0F\xD6\xA5g\xC5Q2a \xC5Hcp\x8D\xE2\xC6VPy\x80\xA06D\x92\xEC\xE2 @Û¨P\xD6H\xC4È– \x82&lt;q\x98\x9D\x99\xF6[q
+\xC8T|-\x8B
+Un+bK\xE3ƃ\xA6
+^$\x88\x80`[\x80\x92dF\xB1E\x89\xA8M9\xB6P\xB0dBZTY\xB5\xC6\xC15'M^\xCB\xE3\x8BË°h#h\xD2\xE05l\x87#4\xA9-$\xF2\x8B\xAD+6\x87\xFD#\xF4\x92!\xF9        \xDC,\xF5\xB9        H\xB0\xA0\xC1\x83ܶ!$\xA8-\x9B6\x85\xB7a \x80@\xB6mf+\x80\xEDF&lt;L\xB8M[\x80fä¹¢!@É‹\xDCb\xEC\xA0`C\x89 )nh\xD8v\xF1#\x93.%v\xB8Ë„B9&lt;b \xB0\x8E\x84)v\xB01\x87\x8E\x8C7C\xF1%\xC2\x97\x85R        \xE9\x81u\xDB,#'\xB0=0\xC0q5;\x94b+\x93\xA1ƶkL\xB8Vl\x97\x92HDa[B\xA18\x82D&quot;\xC670\xE0\xE0p\xF7\x80        \xAB\xEA \xC0\x86[\x841Zƈ\xC0&quot;\x80\x94        w(A g&quot;$\x80\xB1I\x8C\xD98܉\x80ol\xDAb\xD5\xC6y\x9B\xB2~\x8D\xC0\xB5\xE0\xB1.\x98q\xBA\xF5\x82!\xF9        \xDC,\xEE\xB9        H\xB0\xA0\xC1\x83\xDC\xC6p\x9B\xB6\x87\xDA2\xD46Q@        \xB8\x96\xAD\xA1\xB6
+ .(\xA0\x80 \xB6m\\xA3\xC8\xC9;\xB20Q!b\xC36nCL\x82\x89 @\x84\xE8#c6\x96D,!\x81C\x81\xB6:B\xDC\xC0\xC8\xD2\xC1KX&lt;(\xF0T\x94 ,\xB71\xC1\xC0c\xDB5l3\xD5\xC9mÙšdð´­€\x81'Ù´m\x98\x8D\x81&gt; \xB0X\xD0\xC1\x91\xAF:
+Qi\x816\x8F\xA2,Y\xC35\xAC\x95(I\xD0X80D\xA7p'R\xA4O\x93\xA9\x8C$\xA3\xDA!\xB6\x93X\xCC0ã‚…+\xD8:2\xCC\x80\x80k
+Ȧ+'E\x84\xB5e#\xBEM\xA1\xF3\xE7\xD0!\xF9        \xDC,\xF6\xB9        \xC8m\xDB6\x82        \\x98P\xE1B\x83+&gt;|`P[Â…Ù¶\xC9\xC1\x92i@\x80l\xB7+\xA0\xC0\xA3\xA3&quot;\xB8p\xC0\xBC\xF4@s\xC1f\x9Bl&gt;\xC1\x93BQ\x96&quot;\x91\x90P\x88\xD1 6&quot;&gt;\xB8\xCCØ–i\xC36#`d\xBB\xA6m ;$
+l# g\xDBX\xAD\xCA\+\x80\xF3\xC2L&quot; (\x90\xAD\x86 *\xD9&lt;n\xBB\xD0&amp;\x8A\x8Fls\xE2\x82\xD66\xC0(A\xC2ʶQ\xB6)\xF8\x93\xC1\x816\xDAXTk\x9B\x97\x9E|\xF1\xE5\xA3\xC5m\xD8`p\xABÔ¥!\xE8\xBC\xD8VU`\xDCm\xB1RbË‹\x8C]\xE3\xACc\x90\xBD\xB9        f p\xA0\x81\x873\xFC\xE2\xB5l\xB8#\xB2\xACzP:\xCB\xEA!\xF9\xDC,\xFA\xB9        H\xB0\xA0\xC1\x83Û¶\x98\xB0aB\x82\xB7iÛ–\xAD&quot;6l j\x9BH\xF1ZCfÓ†m\xA2[M\xD4\xE40\xA0\xC6\x85ЦaÄ‘ (+A#c$\xB7\xB6QSe'g$\x84\xF8\xB4+c\xD9&lt;\xE0\x9A\xDB6H\x84\xA6\xC4\xC8\x80\x9BG)\x80L\xD8\xE0+\xB6!\xC0M[\xB6Wvpl#0\xA0A\x80m\xB1\xC0\x900\x9B\x8C \xE60p`Û‰eh\xE3\xD6 \xB64 \xB0Í€3=\xB6]\xE36@\x8Fg\x94T5\x85\xA0Y\x97\x8A!\xADFk!\xC8!#ܨؠ\xE3\xC6C\xCCp\x9A\x83!\x85 'r\x93X@J/R\xA4x\xEBP É†%#&gt;.=&quot;D\xE9 \xA9gßž= ;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamloggercss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/logger.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/logger.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/logger.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+.yui-skin-sam .yui-log{padding:1em;width:31em;background-color:#AAA;color:#000;border:1px solid black;font-family:monospace;font-size:77%;text-align:left;z-index:9000}.yui-skin-sam .yui-log-container{position:absolute;top:1em;right:1em}.yui-skin-sam .yui-log input{margin:0;padding:0;font-family:arial;font-size:100%;font-weight:normal}.yui-skin-sam .yui-log .yui-log-btns{position:relative;float:right;bottom:.25em}.yui-skin-sam .yui-log .yui-log-hd{margin-top:1em;padding:.5em;background-color:#575757}.yui-skin-sam .yui-log .yui-log-hd h4{margin:0;padding:0;font-size:108%;font-weight:bold;color:#FFF}.yui-skin-sam .yui-log .yui-log-bd{width:100%;height:20em;background-color:#FFF;border:1px solid gray;overflow:auto}.yui-skin-sam .yui-log p{margin:1px;padding:.1em}.yui-skin-sam .yui-log pre{margin:0;padding:0}.yui-skin-sam .yui-log pre.yui-log-verbose{white-space:pre-wrap;white-space:-moz-pre-wrap!important;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}.yui-sk
 in-sam .yui-log .yui-log-ft{margin-top:.5em}.yui-skin-sam .yui-log .yui-log-ft .yui-log-sourcefilters{width:100%;border-top:1px solid #575757;margin-top:.75em;padding-top:.75em}.yui-skin-sam .yui-log .yui-log-filtergrp{margin-right:.5em}.yui-skin-sam .yui-log .info{background-color:#a7cc25}.yui-skin-sam .yui-log .warn{background-color:#f58516}.yui-skin-sam .yui-log .error{background-color:#e32f0b}.yui-skin-sam .yui-log .time{background-color:#a6c9d7}.yui-skin-sam .yui-log .window{background-color:#f2e886}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssammenubuttonarrowdisabledpng"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menu-button-arrow-disabled.png (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menu-button-arrow-disabled.png                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menu-button-arrow-disabled.png        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,4 @@
</span><ins>+\x89PNG
+
++IHDR\xB0jO\xDEgAMA\xD6\xD8\xD4OX2tEXtSoftwareAdobe ImageReadyq\xC9e&lt;PLTE\xFF\xFF\xFFs\xE7tRNS\xFF\xE5\xB70JIDATx\xDAb`\x80F``D\xE5Q\xF8 Fd&gt;#@\x80\xB21\xF7\xE9p\xBBIEND\xAEB`\x82
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssammenubuttonarrowpng"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menu-button-arrow.png (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menu-button-arrow.png                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menu-button-arrow.png        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,4 @@
</span><ins>+\x89PNG
+
++IHDR\xB0jO\xDEgAMA\xD6\xD8\xD4OX2tEXtSoftwareAdobe ImageReadyq\xC9e&lt;PLTE\xFF\xFF\xFF\xA5ÙŸ\xDDtRNS\xFF\xE5\xB70JIDATx\xDAb`\x80F``D\xE5Q\xF8 Fd&gt;#@\x80\xB21\xF7\xE9p\xBBIEND\xAEB`\x82
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssammenucss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menu.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menu.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menu.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+.yuimenu{top:-999em;left:-999em;}.yuimenubar{position:static;}.yuimenu .yuimenu,.yuimenubar .yuimenu{position:absolute;}.yuimenubar li,.yuimenu li{list-style-type:none;}.yuimenubar ul,.yuimenu ul,.yuimenubar li,.yuimenu li,.yuimenu h6,.yuimenubar h6{margin:0;padding:0;}.yuimenuitemlabel,.yuimenubaritemlabel{text-align:left;white-space:nowrap;}.yuimenubar ul{*zoom:1;}.yuimenubar .yuimenu ul{*zoom:normal;}.yuimenubar&gt;.bd&gt;ul:after{content:&quot;.&quot;;display:block;clear:both;visibility:hidden;height:0;line-height:0;}.yuimenubaritem{float:left;}.yuimenubaritemlabel,.yuimenuitemlabel{display:block;}.yuimenuitemlabel .helptext{font-style:normal;display:block;margin:-1em 0 0 10em;}.yui-menu-shadow{position:absolute;visibility:hidden;z-index:-1;}.yui-menu-shadow-visible{top:2px;right:-3px;left:-3px;bottom:-3px;visibility:visible;}.hide-scrollbars *{overflow:hidden;}.hide-scrollbars select{display:none;}.yuimenu.show-scrollbars,.yuimenubar.show-scrollbars{overflow:visible;}.y
 uimenu.hide-scrollbars .yui-menu-shadow,.yuimenubar.hide-scrollbars .yui-menu-shadow{overflow:hidden;}.yuimenu.show-scrollbars .yui-menu-shadow,.yuimenubar.show-scrollbars .yui-menu-shadow{overflow:auto;}.yui-overlay.yui-force-redraw{margin-bottom:1px;}.yui-skin-sam .yuimenubar{font-size:93%;line-height:2;*line-height:1.9;border:solid 1px #808080;background:url(sprite.png) repeat-x 0 0;}.yui-skin-sam .yuimenubarnav .yuimenubaritem{border-right:solid 1px #ccc;}.yui-skin-sam .yuimenubaritemlabel{padding:0 10px;color:#000;text-decoration:none;cursor:default;border-style:solid;border-color:#808080;border-width:1px 0;*position:relative;margin:-1px 0;}.yui-skin-sam .yuimenubaritemlabel:visited{color:#000;}.yui-skin-sam .yuimenubarnav .yuimenubaritemlabel{padding-right:20px;*display:inline-block;}.yui-skin-sam .yuimenubarnav .yuimenubaritemlabel-hassubmenu{background:url(menubaritem_submenuindicator.png) right center no-repeat;}.yui-skin-sam .yuimenubaritem-selected{background:url(
 sprite.png) repeat-x 0 -1700px;}.yui-skin-sam .yuimenubaritemlabel-selected{border-color:#7D98B8;}.yui-skin-sam .yuimenubarnav .yuimenubaritemlabel-selected{border-left-width:1px;margin-left:-1px;*left:-1px;}.yui-skin-sam .yuimenubaritemlabel-disabled,.yui-skin-sam .yuimenubaritemlabel-disabled:visited{cursor:default;color:#A6A6A6;}.yui-skin-sam .yuimenubarnav .yuimenubaritemlabel-hassubmenu-disabled{background-image:url(menubaritem_submenuindicator_disabled.png);}.yui-skin-sam .yuimenu{font-size:93%;line-height:1.5;*line-height:1.45;}.yui-skin-sam .yuimenubar .yuimenu,.yui-skin-sam .yuimenu .yuimenu{font-size:100%;}.yui-skin-sam .yuimenu .bd{*zoom:1;_zoom:normal;border:solid 1px #808080;background-color:#fff;}.yui-skin-sam .yuimenu .yuimenu .bd{*zoom:normal;}.yui-skin-sam .yuimenu ul{padding:3px 0;border-width:1px 0 0 0;border-color:#ccc;border-style:solid;}.yui-skin-sam .yuimenu ul.first-of-type{border-width:0;}.yui-skin-sam .yuimenu h6{font-weight:bold;border-style:solid;
 border-color:#ccc;border-width:1px 0 0 0;color:#a4a4a4;padding:3px 10px 0 10px;}.yui-skin-sam .yuimenu ul.hastitle,.yui-skin-sam .yuimenu h6.first-of-type{border-width:0;}.yui-skin-sam .yuimenu .yui-menu-body-scrolled{border-color:#ccc #808080;overflow:hidden;}.yui-skin-sam .yuimenu .topscrollbar,.yui-skin-sam .yuimenu .bottomscrollbar{height:16px;border:solid 1px #808080;background:#fff url(sprite.png) no-repeat 0 0;}.yui-skin-sam .yuimenu .topscrollbar{border-bottom-width:0;background-position:center -950px;}.yui-skin-sam .yuimenu .topscrollbar_disabled{background-position:center -975px;}.yui-skin-sam .yuimenu .bottomscrollbar{border-top-width:0;background-position:center -850px;}.yui-skin-sam .yuimenu .bottomscrollbar_disabled{background-position:center -875px;}.yui-skin-sam .yuimenuitem{_border-bottom:solid 1px #fff;}.yui-skin-sam .yuimenuitemlabel{padding:0 20px;color:#000;text-decoration:none;cursor:default;}.yui-skin-sam .yuimenuitemlabel:visited{color:#000;}.yui-skin
 -sam .yuimenuitemlabel .helptext{margin-top:-1.5em;*margin-top:-1.45em;}.yui-skin-sam .yuimenuitem-hassubmenu{background-image:url(menuitem_submenuindicator.png);background-position:right center;background-repeat:no-repeat;}.yui-skin-sam .yuimenuitem-checked{background-image:url(menuitem_checkbox.png);background-position:left center;background-repeat:no-repeat;}.yui-skin-sam .yui-menu-shadow-visible{background-color:#000;opacity:.12;filter:alpha(opacity=12);}.yui-skin-sam .yuimenuitem-selected{background-color:#B3D4FF;}.yui-skin-sam .yuimenuitemlabel-disabled,.yui-skin-sam .yuimenuitemlabel-disabled:visited{cursor:default;color:#A6A6A6;}.yui-skin-sam .yuimenuitem-hassubmenu-disabled{background-image:url(menuitem_submenuindicator_disabled.png);}.yui-skin-sam .yuimenuitem-checked-disabled{background-image:url(menuitem_checkbox_disabled.png);}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssammenubaritem_submenuindicatorpng"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menubaritem_submenuindicator.png (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menubaritem_submenuindicator.png                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menubaritem_submenuindicator.png        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,31 @@
</span><ins>+\x89PNG
+
++IHDR\xB0jO\xDE        pHYs  \x9A\x9C
+OiCCPPhotoshop ICC profilexÚSgTS\xE9=\xF7\xDE\xF4BK\x88\x80\x94KoR RB\x8B\x80\x91&amp;*!        J\x88!\xA1\xD9Q\xC1EEÈ \x88\x8E\x8E\x80\x8CQ, \x8A
+\xD8\xE4!\xA2\x8E\x83\xA3\x88\x8A\xCA\xFB\xE1{\xA3kÖ¼\xF7\xE6\xCD\xFE\xB5\xD7&gt;\xE7\xAC\xF3\x9D\xB3\xCF\xC0 \x96H3Q5\x80 \xA9B\xE0\x83\xC7\xC4\xC6\xE1\xE4.@\x81
+$p\xB3d!s\xFD#\xF8~&lt;&lt;+&quot;\xC0\xBEx\xD3 \xC0M\x9B\xC00\x87\xFF\xEAB\x99\\x80\x84\xC0t\x918K\x80@z\x8EB\xA6@F\x80\x9D\x98&amp;S\xA0`\xCBcb\xE3P-`'\xE6\xD3\x80\x9D\xF8\x99{[\x94!\xA0\x91 e\x88Dh;\xAC\xCFV\x8AEX0fK\xC49\xD8-0IWfH\xB0\xB7\xC0\xCE \xB2 0Q\x88\x85){`\xC8##x\x84\x99F\xF2W&lt;\xF1+\xAE\xE7*x\x99\xB2&lt;\xB9$9E\x81[-qWW.(\xCEI+6aa\x9A@.\xC2y\x992\x814\xE0\xF3\xCC\xA0\x91\xE0\x83\xF3\xFDx\xCE\xAE\xCE\xCE6\x8E\xB6_-\xEA\xBF\xFF&quot;bb\xE3\xFE\xE5Ï«p@\xE1t~\xD1\xFE,/\xB3\x80;\x80m\xFE\xA2%\xEEh^ \xA0u\xF7\x8Bf\xB2@\xB5\xA0\xE9\xDAW\xF3p\xF8~&lt;&lt;E\xA1\x90\xB9\xD9\xD9\xE5\xE4\xE4\xD8J\xC4B[a\xCAW}\xFEg\xC2_\xC0W\xFDl\xF9~&lt;\xFC\xF7\xF5\xE0\xBE\xE2$\x812]\x81G\xF8\xE0\xC2\xCC\xF4L\xA5Ï’        \x84b\xDC\xE6\x8FG\xFC\xB7 \xFF\xFC\xD3&quot;\xC4Ib\xB9X*\xE3Qq\x8ED\x9A\x8C\xF32\xA5&quot;\x89B\x92)\xC5%\xD2\xFFd\xE2\xDF,\xFB&gt;\xDF5\xB0j&gt;{\x91-\xA8]c\xF6K'Xt\xC0\xE2\xF7\xF2\xBBo\
 xC1\xD4(\x80h\x83\xE1\xCFw\xFF\xEF?\xFDG\xA0%\x80fI\x92q^D$.Tʳ?\xC7D\xA0\x81*\xB0A\xF4\xC1,\xC0\xC1\xDC\xC1 \xFC`6\x84B$\xC4\xC2BB
+d\x80r`)\xAC\x82B(\x86Í°*`/\xD4@4\xC0Qh\x86\x93p.\xC2U\xB8=p\xFAa\x9E\xC1(\xBC\x81        A\xC8a!Úˆb\x8AX#\x8E\x99\x85\xF8!\xC1H\x8B$ ÉˆQ&quot;K\x915H1R\x8AT UH\xF2=r9\x87\F\xBA\x91;\xC82\x82\xFC\x86\xBCG1\x94\x81\xB2Q=\xD4 \xB5C\xB9\xA87\x84F\xA2 \xD0dt1\x9A\x8F\xA0\x9B\xD0r\xB4=\x8C6\xA1\xE7ЫhÚ&gt;C\xC70\xC0\xE83\xC4l0.\xC6\xC3B\xB18,        \x93c˱&quot;\xAC \xAB\xC6\xB0V\xAC\xBB\x89\xF5cϱw\x81E\xC0        6wB aAHXLXN\xD8H\xA8 $4\xDA        7        \x84Q\xC2'&quot;\x93\xA8K\xB4&amp;\xBA\xF9\xC4b21\x87XH,#\xD6\x8F/{\x88C\xC47$\x89C2'\xB9\x90I\xB1\xA4T\xD2\xD2F\xD2nR#\xE9,\xA9\x9B4H#\x93\xC9\xDAdk\xB29\x94, +È…\xE4\x9D\xE4\xC3\xE43\xE4\xE4!\xF2[
+\x9Db@q\xA4\xF8S\xE2(R\xCAjJ\xE5\xE54\xE5e\x982AU\xA3\x9ARݨ\xA1T5\x8FZB\xAD\xA1\xB6R\xAFQ\x87\xA84u\x9A9̓IK\xA5\xAD\xA2\x95\xD3hh\xF7i\xAF\xE8t\xBAÝ•N\x97\xD0W\xD2\xCB\xE9G\xE8\x97\xE8\xF4w +\x86\x83Ljg(\x9Bgw\xAF\x98L\xA6Ó‹\xC7T071\xEB\x98\xE7\x99\x99oUX*\xB6*|\x91\xCA
+\x95J\x95&amp;\x95*/T\xA9\xAA\xA6\xAAÞª U\xF3U\xCBT\x8F\xA9^S}\xAEFU3S\xE3\xA9        Ô–\xABU\xAA\x9DP\xEBSSg\xA9;\xA8\x87\xAAg\xA8oT?\xA4~Y\xFD\x89Y\xC3L\xC3OC\xA4Q\xA0\xB1_\xE3\xBC\xC6  c\xB3x,!k+\xAB\x86u\x815\xC4&amp;\xB1\xCD\xD9|v*\xBB\x98\xFD\xBB\x8B=\xAA\xA9\xA19C3J3W\xB3R\xF3\x94f?\xE3\x98q\xF8\x9CtN        \xE7(\xA7\x97\xF3~\x8A\xDE\xEF)\xE2)\xA64L\xB91e\k\xAA\x96\x97\x96X\xABH\xABQ\xABG\xEB\xBD6\xAE\x{D9DD}\xA6\xBDE\xBBY\xFB\x81A\xC7J'\'Gg\x8F\xCE\x9D\xE7S\xD9Sݧ
+\xA7M=:\xF5\xAE.\xAAk\xA5\xA1\xBBDw\xBFn\xA7\xBE^\x80\x9ELo\xA7\xDEy\xBD\xE7\xFA}/\xFDT\xFDm\xFA\xA7\xF5G X\xB3 $\xDB \xCE&lt;\xC55qo&lt;/\xC7\xDB\xF1QC]\xC3@C\xA5a\x95a\x97ᄑ\xB9\xD1&lt;\xA3\xD5F\x8DF\x8Ci\xC6\\xE3$\xE3m\xC6mƣ&amp;&amp;!&amp;KM\xEAM\xEE\x9ARM\xB9\xA6)\xA6;L;L\xC7\xCD\xCC͢\xCD֙5\x9B=1\xD72\xE7\x9B\xE7\x9Bכ߷`ZxZ,\xB6\xA8\xB6\xB8eI\xB2\xE4Z\xA6Yn\x85Z9Y\xA5XUZ]\xB3F\xAD\x9D\xAD%ֻ\xAD\xBB\xA7\xA7\xB9N\x93N\xAB\x9E\xD6gð\xF1\xB6ɶ\xA9\xB7\xB0\xE5\xD8ۮ\xB6m\xB6}agbg\xB7Ů\xC3\x93}\xBA}\x8D\xFD=+\x87\xD9\xABZ~s\xB4r:V:ޚΜ\xEE?}\xC5\xF4\x96\xE9/gX\xCF\xCF\xD83\xE3\xB6\xCB)\xC4i\x9DS\x9B\xD3Ggg\xB9s\x83󈋉K\x82\xCB.\x97&gt;.\x9B\xC6\xDDȽ\xE4Jt\xF5q]\xE1z\xD2\x{15D6F3}\x9B\xC2\xED\xA8ۯ\xEE6\xEEi\xEE\x87ܟ\xCC4\x9F)\x9EY3s\xD0\xC3\xC8C\xE0Q\xE5\xD1? \x9F\x950k߬~OCO\x81g\xB5\xE7#/c/\x91W\xADװ\xB7\xA5w\xAA\xF7a\xEF&gt;\xF6&gt;r\x9F\xE3&gt;\xE3&lt;7\xDE2\xDEY_\xCC7\xC0\xB7ȷ\xCBO\xC3o\x9E_\x85\xDFC#\xFFd\xFFz\xFF\xD1\xA7\
 x80%g\x89\x81A\x81[\xFB\xF8z|!\xBF\x8E?:\xDBe\xF6\xB2\xD9\xEDA\x8C\xA0\xB9AA\x8F\x82\xAD\x82\xE5\xC1\xAD!h\xC8ì­!\xF7\xE7\x98Α\xCEi\x85P~\xE8\xD6\xD0a\xE6a\x8B\xC3~ '\x85\x87\x85W\x86?\x8Ep\x88X\xD11\x975w\xD1\xDCCs\xDFD\xFAD\x96DÞ›g1O9\xAF-J5*&gt;\xAA.j&lt;\xDA7\xBA4\xBA?\xC6.fY\xCC\xD5X\x9DXIlK9.*\xAE6nl\xBE\xDF\xFC\xED\xF3\x87\xE2\x9D\xE2 \xE3{\x98/\xC8]py\xA1\xCE\xC2\xF4\x85\xA7\xA9.,:\x96@L\x88N8\x94\xF0A*\xA8\x8C%\xF2w%\x8E
+y\xC2\xC2g&quot;/\xD16ш\xD8C\*N\xF2H*Mz\x92쑼5y$\xC53\xA5,幄'\xA9\x90\xBCL+LÝ›:\x9E\x9Av m2=:\xBD1\x83\x92\x91\x90qB\xAA!M\x93\xB6g\xEAg\xE6fvˬe\x85\xB2\xFE\xC5n\x8B\xB7/\x95\xC9k\xB3\x90\xACY-
+\xB6B\xA6\xE8TZ(\xD7*\xB2geWf\xBF͉\xCA9\x96\xAB\x9E+\xCD\xED̳\xCAÛ7\x9C\xEF\x9F\xFF\xED\xC2á’¶\xA5\x86KW-X潬j9\xB2&lt;qy\xDB
+\xE3+\x86V\xAC&lt;\xB8\x8A\xB6*m\xD5O\xAB\xEDW\x97\xAE~\xBD&amp;zMk\x81^\xC1Ê‚\xC1\xB5k\xEB U
+\xE5\x85}\xEB\xDC\xD7\xED]OX/Yßµa\xFA\x86\x9D&gt;\x89\x8A\xAE\xDB\x97\xD8(\xDCx\xE5\x87oÊ¿\x99Ü”\xB4\xA9\xABĹd\xCFf\xD2f\xE9\xE6\xDE-\x9E[\x96\xAA\x97\xE6\x97n+\xD9Ú´+\xDFV\xB4\xED\xF5\xF6E\xDB/\x97\xCD(Û»\x83\xB6C\xB9\xA3\xBF&lt;\xB8\xBCe\xA7\xC9\xCE\xCD;?T\xA4T\xF4T\xFAT6\xEE\xD2ݵa\xD7\xF8n\xD1\xEE{\xBC\xF64\xEC\xD5\xDB[\xBC\xF7\xFD&gt;ɾ\xDBUUM\xD5f\xD5e\xFBI\xFB\xB3\xF7?\xAE\x89\xAA\xE9\xF8\x96\xFBm]\xADNmq\xED\xC7\xD2\xFD#\xB6×¹\xD4\xD5\xD2=TR\x8F\xD6+\xEBG\xC7\xBE\xFE\x9D\xEFw-+6+U\x8D\x9C\xC6\xE2#pDy\xE4\xE9\xF7        \xDF\xF7+:\xDAv\x8C{\xAC\xE1\xD3vg/jB\x9A\xF2\x9AF\x9BS\x9A\xFB[b[\xBAO\xCC&gt;\xD1\xD6\xEA\xDEz\xFCG\xDB\x9C4&lt;YyJ\xF3T\xC9i\xDA\xE9\x82Ó“g\xF2ÏŒ\x9D\x95\x9D}~.\xF9\xDC`Û¢\xB6{\xE7c\xCE\xDFjo\xEF\xBAt\xE1\xD2E\xFF\x8B\xE7;\xBC;\xCE\\xF2\xB8t\xF2\xB2\xDB\xE5W\xB8W\x9A\xAF:_m\xEAt\xEA&lt;\xFE\x93\xD3OÇ»\x9C\xBB\x9A\xAE\xB9\k\xB9\xEEz\xBD\xB5{f\xF7\xE9\x9E7\xCE\xDD\xF4\xBDy\xF1\xFF\xD6Õž9=ݽ\xF3zo\xF7\xC5\xF7\xF5\xDF\xDD~r
 '\xFD\xCEË»\xD9w'î­¼O\xBC_\xF4@\xEDA\xD9C݇\xD5?[\xFE\xDC\xD8\xEF\xDCj\xC0w\xA0\xF3\xD1\xDCG\xF7\x85\x83\xCF\xFE\x91\xF5\x8FC\x8F\x99\x8Fˆ+\x86\xEB\x9E8&gt;99\xE2?r\xFD\xE9\xFC\xA7C\xCFd\xCF&amp;\x9E\xFE\xA2\xFEË®/~\xF8\xD5\xEB\xD7\xCEјѡ\x97ò—“¿m|\xA5\xFD\xEA\xC0\xEB\xAF\xDB\xC6\xC2\xC6\xBE\xC9x31^\xF4V\xFB\xED\xC1w\xDCw\xEF\xA3\xDFO\xE4| (\xFFh\xF9\xB1\xF5SЧ\xFB\x93\x93\x93\xFF\x98\xF3\xFCc3-\xDBgAMA\xB1\x8E|\xFBQ\x93 cHRMz%\x80\x83\xF9\xFF\x80\xE9u0\xEA`:\x98o\x92_\xC5FPLTE\xFF\xFF\xFF                        
+
+
+ +++   !!!&quot;&quot;&quot;###$$$%%%&amp;&amp;&amp;'''((()))***+++,,,---...///000111222333444555666777888999:::;;;&lt;&lt;&lt;===&gt;&gt;&gt;???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~\x80\x80\x80\x81\x81\x81\x82\x82\x82\x83\x83\x83\x84\x84\x84\x85\x85\x85\x86\x86\x86\x87\x87\x87\x88\x88\x88\x89\x89\x89\x8A\x8A\x8A\x8B\x8B\x8B\x8C\x8C\x8C\x8D\x8D\x8D\x8E\x8E\x8E\x8F\x8F\x8F\x90\x90\x90\x91\x91\x91\x92\x92\x92\x93\x93\x93\x94\x94\x94\x95\x95\x95\x96\x96\x96\x97\x97\x97\x98\x98\x98\x99\x99\x99\x9A\x9A\x9A\x9B\x9B\x9B\x9C\x9C\x9C\x9D\x9D\x9D\x9E\x9E\x9E\x9F\x9F\x9F\xA0\xA0\xA0\xA1\xA1\xA1\xA2\xA2\xA2\xA3\xA3\xA3\xA4\xA4\xA4\xA5\xA5\xA5\xA6\xA6\xA6\xA7\xA7\xA7\xA8\xA8\xA8\xA9\xA9\xA9\xAA\xAA\xAA\xAB\xAB\xAB\xAC\xAC\xAC\xAD\xAD\xAD\xAE\xAE\xAE\xAF\xAF\xAF\xB0\xB0\xB0\x
 B1\xB1\xB1\xB2\xB2\xB2\xB3\xB3\xB3\xB4\xB4\xB4\xB5\xB5\xB5\xB6\xB6\xB6\xB7\xB7\xB7\xB8\xB8\xB8\xB9\xB9\xB9\xBA\xBA\xBA\xBB\xBB\xBB\xBC\xBC\xBC\xBD\xBD\xBD\xBE\xBE\xBE\xBF\xBF\xBF\xC0\xC0\xC0\xC1\xC1\xC1\xC2\xC2\xC2\xC3\xC3\xC3\xC4\xC4\xC4\xC5\xC5\xC5\xC6\xC6\xC6\xC7\xC7\xC7\xC8\xC8\xC8\xC9\xC9\xC9\xCA\xCA\xCA\xCB\xCB\xCB\xCC\xCC\xCC\xCD\xCD\xCD\xCE\xCE\xCE\xCF\xCF\xCF\xD0\xD0\xD0\xD1\xD1\xD1\xD2\xD2\xD2\xD3\xD3\xD3\xD4\xD4\xD4\xD5\xD5\xD5\xD6\xD6\xD6\xD7\xD7\xD7\xD8\xD8\xD8\xD9\xD9\xD9\xDA\xDA\xDA\xDB\xDB\xDB\xDC\xDC\xDC\xDD\xDD\xDD\xDE\xDE\xDE\xDF\xDF\xDF\xE0\xE0\xE0\xE1\xE1\xE1\xE2\xE2\xE2\xE3\xE3\xE3\xE4\xE4\xE4\xE5\xE5\xE5\xE6\xE6\xE6\xE7\xE7\xE7\xE8\xE8\xE8\xE9\xE9\xE9\xEA\xEA\xEA\xEB\xEB\xEB\xEC\xEC\xEC\xED\xED\xED\xEE\xEE\xEE\xEF\xEF\xEF\xF0\xF0\xF0\xF1\xF1\xF1\xF2\xF2\xF2\xF3\xF3\xF3\xF4\xF4\xF4\xF5\xF5\xF5\xF6\xF6\xF6\xF7\xF7\xF7\xF8\xF8\xF8\xF9\xF9\xF9\xFA\xFA\xFA\xFB\xFB\xFB\xFC\xFC\xFC\xFD\xFD\xFD\xFE\xFE\xFE\xFF\xFF\xFF\xF9$\xB9\xDCtRNS\xFF\xE5\xB70J#IDA
 Tx\xDAb`\x80F``D\xE53202\xA2\xF0\xA0\xFF\xFF\xB21^6\xE9tIEND\xAEB`\x82
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssammenubaritem_submenuindicator_disabledpng"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menubaritem_submenuindicator_disabled.png (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menubaritem_submenuindicator_disabled.png                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menubaritem_submenuindicator_disabled.png        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,31 @@
</span><ins>+\x89PNG
+
++IHDR\xB0jO\xDE        pHYs  \x9A\x9C
+OiCCPPhotoshop ICC profilexÚSgTS\xE9=\xF7\xDE\xF4BK\x88\x80\x94KoR RB\x8B\x80\x91&amp;*!        J\x88!\xA1\xD9Q\xC1EEÈ \x88\x8E\x8E\x80\x8CQ, \x8A
+\xD8\xE4!\xA2\x8E\x83\xA3\x88\x8A\xCA\xFB\xE1{\xA3kÖ¼\xF7\xE6\xCD\xFE\xB5\xD7&gt;\xE7\xAC\xF3\x9D\xB3\xCF\xC0 \x96H3Q5\x80 \xA9B\xE0\x83\xC7\xC4\xC6\xE1\xE4.@\x81
+$p\xB3d!s\xFD#\xF8~&lt;&lt;+&quot;\xC0\xBEx\xD3 \xC0M\x9B\xC00\x87\xFF\xEAB\x99\\x80\x84\xC0t\x918K\x80@z\x8EB\xA6@F\x80\x9D\x98&amp;S\xA0`\xCBcb\xE3P-`'\xE6\xD3\x80\x9D\xF8\x99{[\x94!\xA0\x91 e\x88Dh;\xAC\xCFV\x8AEX0fK\xC49\xD8-0IWfH\xB0\xB7\xC0\xCE \xB2 0Q\x88\x85){`\xC8##x\x84\x99F\xF2W&lt;\xF1+\xAE\xE7*x\x99\xB2&lt;\xB9$9E\x81[-qWW.(\xCEI+6aa\x9A@.\xC2y\x992\x814\xE0\xF3\xCC\xA0\x91\xE0\x83\xF3\xFDx\xCE\xAE\xCE\xCE6\x8E\xB6_-\xEA\xBF\xFF&quot;bb\xE3\xFE\xE5Ï«p@\xE1t~\xD1\xFE,/\xB3\x80;\x80m\xFE\xA2%\xEEh^ \xA0u\xF7\x8Bf\xB2@\xB5\xA0\xE9\xDAW\xF3p\xF8~&lt;&lt;E\xA1\x90\xB9\xD9\xD9\xE5\xE4\xE4\xD8J\xC4B[a\xCAW}\xFEg\xC2_\xC0W\xFDl\xF9~&lt;\xFC\xF7\xF5\xE0\xBE\xE2$\x812]\x81G\xF8\xE0\xC2\xCC\xF4L\xA5Ï’        \x84b\xDC\xE6\x8FG\xFC\xB7 \xFF\xFC\xD3&quot;\xC4Ib\xB9X*\xE3Qq\x8ED\x9A\x8C\xF32\xA5&quot;\x89B\x92)\xC5%\xD2\xFFd\xE2\xDF,\xFB&gt;\xDF5\xB0j&gt;{\x91-\xA8]c\xF6K'Xt\xC0\xE2\xF7\xF2\xBBo\
 xC1\xD4(\x80h\x83\xE1\xCFw\xFF\xEF?\xFDG\xA0%\x80fI\x92q^D$.Tʳ?\xC7D\xA0\x81*\xB0A\xF4\xC1,\xC0\xC1\xDC\xC1 \xFC`6\x84B$\xC4\xC2BB
+d\x80r`)\xAC\x82B(\x86Í°*`/\xD4@4\xC0Qh\x86\x93p.\xC2U\xB8=p\xFAa\x9E\xC1(\xBC\x81        A\xC8a!Úˆb\x8AX#\x8E\x99\x85\xF8!\xC1H\x8B$ ÉˆQ&quot;K\x915H1R\x8AT UH\xF2=r9\x87\F\xBA\x91;\xC82\x82\xFC\x86\xBCG1\x94\x81\xB2Q=\xD4 \xB5C\xB9\xA87\x84F\xA2 \xD0dt1\x9A\x8F\xA0\x9B\xD0r\xB4=\x8C6\xA1\xE7ЫhÚ&gt;C\xC70\xC0\xE83\xC4l0.\xC6\xC3B\xB18,        \x93c˱&quot;\xAC \xAB\xC6\xB0V\xAC\xBB\x89\xF5cϱw\x81E\xC0        6wB aAHXLXN\xD8H\xA8 $4\xDA        7        \x84Q\xC2'&quot;\x93\xA8K\xB4&amp;\xBA\xF9\xC4b21\x87XH,#\xD6\x8F/{\x88C\xC47$\x89C2'\xB9\x90I\xB1\xA4T\xD2\xD2F\xD2nR#\xE9,\xA9\x9B4H#\x93\xC9\xDAdk\xB29\x94, +È…\xE4\x9D\xE4\xC3\xE43\xE4\xE4!\xF2[
+\x9Db@q\xA4\xF8S\xE2(R\xCAjJ\xE5\xE54\xE5e\x982AU\xA3\x9ARݨ\xA1T5\x8FZB\xAD\xA1\xB6R\xAFQ\x87\xA84u\x9A9̓IK\xA5\xAD\xA2\x95\xD3hh\xF7i\xAF\xE8t\xBAÝ•N\x97\xD0W\xD2\xCB\xE9G\xE8\x97\xE8\xF4w +\x86\x83Ljg(\x9Bgw\xAF\x98L\xA6Ó‹\xC7T071\xEB\x98\xE7\x99\x99oUX*\xB6*|\x91\xCA
+\x95J\x95&amp;\x95*/T\xA9\xAA\xA6\xAAÞª U\xF3U\xCBT\x8F\xA9^S}\xAEFU3S\xE3\xA9        Ô–\xABU\xAA\x9DP\xEBSSg\xA9;\xA8\x87\xAAg\xA8oT?\xA4~Y\xFD\x89Y\xC3L\xC3OC\xA4Q\xA0\xB1_\xE3\xBC\xC6  c\xB3x,!k+\xAB\x86u\x815\xC4&amp;\xB1\xCD\xD9|v*\xBB\x98\xFD\xBB\x8B=\xAA\xA9\xA19C3J3W\xB3R\xF3\x94f?\xE3\x98q\xF8\x9CtN        \xE7(\xA7\x97\xF3~\x8A\xDE\xEF)\xE2)\xA64L\xB91e\k\xAA\x96\x97\x96X\xABH\xABQ\xABG\xEB\xBD6\xAE\x{D9DD}\xA6\xBDE\xBBY\xFB\x81A\xC7J'\'Gg\x8F\xCE\x9D\xE7S\xD9Sݧ
+\xA7M=:\xF5\xAE.\xAAk\xA5\xA1\xBBDw\xBFn\xA7\xBE^\x80\x9ELo\xA7\xDEy\xBD\xE7\xFA}/\xFDT\xFDm\xFA\xA7\xF5G X\xB3 $\xDB \xCE&lt;\xC55qo&lt;/\xC7\xDB\xF1QC]\xC3@C\xA5a\x95a\x97ᄑ\xB9\xD1&lt;\xA3\xD5F\x8DF\x8Ci\xC6\\xE3$\xE3m\xC6mƣ&amp;&amp;!&amp;KM\xEAM\xEE\x9ARM\xB9\xA6)\xA6;L;L\xC7\xCD\xCC͢\xCD֙5\x9B=1\xD72\xE7\x9B\xE7\x9Bכ߷`ZxZ,\xB6\xA8\xB6\xB8eI\xB2\xE4Z\xA6Yn\x85Z9Y\xA5XUZ]\xB3F\xAD\x9D\xAD%ֻ\xAD\xBB\xA7\xA7\xB9N\x93N\xAB\x9E\xD6gð\xF1\xB6ɶ\xA9\xB7\xB0\xE5\xD8ۮ\xB6m\xB6}agbg\xB7Ů\xC3\x93}\xBA}\x8D\xFD=+\x87\xD9\xABZ~s\xB4r:V:ޚΜ\xEE?}\xC5\xF4\x96\xE9/gX\xCF\xCF\xD83\xE3\xB6\xCB)\xC4i\x9DS\x9B\xD3Ggg\xB9s\x83󈋉K\x82\xCB.\x97&gt;.\x9B\xC6\xDDȽ\xE4Jt\xF5q]\xE1z\xD2\x{15D6F3}\x9B\xC2\xED\xA8ۯ\xEE6\xEEi\xEE\x87ܟ\xCC4\x9F)\x9EY3s\xD0\xC3\xC8C\xE0Q\xE5\xD1? \x9F\x950k߬~OCO\x81g\xB5\xE7#/c/\x91W\xADװ\xB7\xA5w\xAA\xF7a\xEF&gt;\xF6&gt;r\x9F\xE3&gt;\xE3&lt;7\xDE2\xDEY_\xCC7\xC0\xB7ȷ\xCBO\xC3o\x9E_\x85\xDFC#\xFFd\xFFz\xFF\xD1\xA7\
 x80%g\x89\x81A\x81[\xFB\xF8z|!\xBF\x8E?:\xDBe\xF6\xB2\xD9\xEDA\x8C\xA0\xB9AA\x8F\x82\xAD\x82\xE5\xC1\xAD!h\xC8ì­!\xF7\xE7\x98Α\xCEi\x85P~\xE8\xD6\xD0a\xE6a\x8B\xC3~ '\x85\x87\x85W\x86?\x8Ep\x88X\xD11\x975w\xD1\xDCCs\xDFD\xFAD\x96DÞ›g1O9\xAF-J5*&gt;\xAA.j&lt;\xDA7\xBA4\xBA?\xC6.fY\xCC\xD5X\x9DXIlK9.*\xAE6nl\xBE\xDF\xFC\xED\xF3\x87\xE2\x9D\xE2 \xE3{\x98/\xC8]py\xA1\xCE\xC2\xF4\x85\xA7\xA9.,:\x96@L\x88N8\x94\xF0A*\xA8\x8C%\xF2w%\x8E
+y\xC2\xC2g&quot;/\xD16ш\xD8C\*N\xF2H*Mz\x92쑼5y$\xC53\xA5,幄'\xA9\x90\xBCL+LÝ›:\x9E\x9Av m2=:\xBD1\x83\x92\x91\x90qB\xAA!M\x93\xB6g\xEAg\xE6fvˬe\x85\xB2\xFE\xC5n\x8B\xB7/\x95\xC9k\xB3\x90\xACY-
+\xB6B\xA6\xE8TZ(\xD7*\xB2geWf\xBF͉\xCA9\x96\xAB\x9E+\xCD\xED̳\xCAÛ7\x9C\xEF\x9F\xFF\xED\xC2á’¶\xA5\x86KW-X潬j9\xB2&lt;qy\xDB
+\xE3+\x86V\xAC&lt;\xB8\x8A\xB6*m\xD5O\xAB\xEDW\x97\xAE~\xBD&amp;zMk\x81^\xC1Ê‚\xC1\xB5k\xEB U
+\xE5\x85}\xEB\xDC\xD7\xED]OX/Yßµa\xFA\x86\x9D&gt;\x89\x8A\xAE\xDB\x97\xD8(\xDCx\xE5\x87oÊ¿\x99Ü”\xB4\xA9\xABĹd\xCFf\xD2f\xE9\xE6\xDE-\x9E[\x96\xAA\x97\xE6\x97n+\xD9Ú´+\xDFV\xB4\xED\xF5\xF6E\xDB/\x97\xCD(Û»\x83\xB6C\xB9\xA3\xBF&lt;\xB8\xBCe\xA7\xC9\xCE\xCD;?T\xA4T\xF4T\xFAT6\xEE\xD2ݵa\xD7\xF8n\xD1\xEE{\xBC\xF64\xEC\xD5\xDB[\xBC\xF7\xFD&gt;ɾ\xDBUUM\xD5f\xD5e\xFBI\xFB\xB3\xF7?\xAE\x89\xAA\xE9\xF8\x96\xFBm]\xADNmq\xED\xC7\xD2\xFD#\xB6×¹\xD4\xD5\xD2=TR\x8F\xD6+\xEBG\xC7\xBE\xFE\x9D\xEFw-+6+U\x8D\x9C\xC6\xE2#pDy\xE4\xE9\xF7        \xDF\xF7+:\xDAv\x8C{\xAC\xE1\xD3vg/jB\x9A\xF2\x9AF\x9BS\x9A\xFB[b[\xBAO\xCC&gt;\xD1\xD6\xEA\xDEz\xFCG\xDB\x9C4&lt;YyJ\xF3T\xC9i\xDA\xE9\x82Ó“g\xF2ÏŒ\x9D\x95\x9D}~.\xF9\xDC`Û¢\xB6{\xE7c\xCE\xDFjo\xEF\xBAt\xE1\xD2E\xFF\x8B\xE7;\xBC;\xCE\\xF2\xB8t\xF2\xB2\xDB\xE5W\xB8W\x9A\xAF:_m\xEAt\xEA&lt;\xFE\x93\xD3OÇ»\x9C\xBB\x9A\xAE\xB9\k\xB9\xEEz\xBD\xB5{f\xF7\xE9\x9E7\xCE\xDD\xF4\xBDy\xF1\xFF\xD6Õž9=ݽ\xF3zo\xF7\xC5\xF7\xF5\xDF\xDD~r
 '\xFD\xCEË»\xD9w'î­¼O\xBC_\xF4@\xEDA\xD9C݇\xD5?[\xFE\xDC\xD8\xEF\xDCj\xC0w\xA0\xF3\xD1\xDCG\xF7\x85\x83\xCF\xFE\x91\xF5\x8FC\x8F\x99\x8Fˆ+\x86\xEB\x9E8&gt;99\xE2?r\xFD\xE9\xFC\xA7C\xCFd\xCF&amp;\x9E\xFE\xA2\xFEË®/~\xF8\xD5\xEB\xD7\xCEјѡ\x97ò—“¿m|\xA5\xFD\xEA\xC0\xEB\xAF\xDB\xC6\xC2\xC6\xBE\xC9x31^\xF4V\xFB\xED\xC1w\xDCw\xEF\xA3\xDFO\xE4| (\xFFh\xF9\xB1\xF5SЧ\xFB\x93\x93\x93\xFF\x98\xF3\xFCc3-\xDBgAMA\xB1\x8E|\xFBQ\x93 cHRMz%\x80\x83\xF9\xFF\x80\xE9u0\xEA`:\x98o\x92_\xC5FPLTE\xFF\xFF\xFF                        
+
+
+ +++   !!!&quot;&quot;&quot;###$$$%%%&amp;&amp;&amp;'''((()))***+++,,,---...///000111222333444555666777888999:::;;;&lt;&lt;&lt;===&gt;&gt;&gt;???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~\x80\x80\x80\x81\x81\x81\x82\x82\x82\x83\x83\x83\x84\x84\x84\x85\x85\x85\x86\x86\x86\x87\x87\x87\x88\x88\x88\x89\x89\x89\x8A\x8A\x8A\x8B\x8B\x8B\x8C\x8C\x8C\x8D\x8D\x8D\x8E\x8E\x8E\x8F\x8F\x8F\x90\x90\x90\x91\x91\x91\x92\x92\x92\x93\x93\x93\x94\x94\x94\x95\x95\x95\x96\x96\x96\x97\x97\x97\x98\x98\x98\x99\x99\x99\x9A\x9A\x9A\x9B\x9B\x9B\x9C\x9C\x9C\x9D\x9D\x9D\x9E\x9E\x9E\x9F\x9F\x9F\xA0\xA0\xA0\xA1\xA1\xA1\xA2\xA2\xA2\xA3\xA3\xA3\xA4\xA4\xA4\xA5\xA5\xA5\xA6\xA6\xA6\xA7\xA7\xA7\xA8\xA8\xA8\xA9\xA9\xA9\xAA\xAA\xAA\xAB\xAB\xAB\xAC\xAC\xAC\xAD\xAD\xAD\xAE\xAE\xAE\xAF\xAF\xAF\xB0\xB0\xB0\x
 B1\xB1\xB1\xB2\xB2\xB2\xB3\xB3\xB3\xB4\xB4\xB4\xB5\xB5\xB5\xB6\xB6\xB6\xB7\xB7\xB7\xB8\xB8\xB8\xB9\xB9\xB9\xBA\xBA\xBA\xBB\xBB\xBB\xBC\xBC\xBC\xBD\xBD\xBD\xBE\xBE\xBE\xBF\xBF\xBF\xC0\xC0\xC0\xC1\xC1\xC1\xC2\xC2\xC2\xC3\xC3\xC3\xC4\xC4\xC4\xC5\xC5\xC5\xC6\xC6\xC6\xC7\xC7\xC7\xC8\xC8\xC8\xC9\xC9\xC9\xCA\xCA\xCA\xCB\xCB\xCB\xCC\xCC\xCC\xCD\xCD\xCD\xCE\xCE\xCE\xCF\xCF\xCF\xD0\xD0\xD0\xD1\xD1\xD1\xD2\xD2\xD2\xD3\xD3\xD3\xD4\xD4\xD4\xD5\xD5\xD5\xD6\xD6\xD6\xD7\xD7\xD7\xD8\xD8\xD8\xD9\xD9\xD9\xDA\xDA\xDA\xDB\xDB\xDB\xDC\xDC\xDC\xDD\xDD\xDD\xDE\xDE\xDE\xDF\xDF\xDF\xE0\xE0\xE0\xE1\xE1\xE1\xE2\xE2\xE2\xE3\xE3\xE3\xE4\xE4\xE4\xE5\xE5\xE5\xE6\xE6\xE6\xE7\xE7\xE7\xE8\xE8\xE8\xE9\xE9\xE9\xEA\xEA\xEA\xEB\xEB\xEB\xEC\xEC\xEC\xED\xED\xED\xEE\xEE\xEE\xEF\xEF\xEF\xF0\xF0\xF0\xF1\xF1\xF1\xF2\xF2\xF2\xF3\xF3\xF3\xF4\xF4\xF4\xF5\xF5\xF5\xF6\xF6\xF6\xF7\xF7\xF7\xF8\xF8\xF8\xF9\xF9\xF9\xFA\xFA\xFA\xFB\xFB\xFB\xFC\xFC\xFC\xFD\xFD\xFD\xFE\xFE\xFE\xFF\xFF\xFFy\x80tRNS\xFF\xE5\xB70J#IDATx\xDA
 b`\x80F``D\xE53202\xA2\xF0\xA0\xFF\xFF\xB21^6\xE9tIEND\xAEB`\x82
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssammenuitem_checkboxpng"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menuitem_checkbox.png (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menuitem_checkbox.png                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menuitem_checkbox.png        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,31 @@
</span><ins>+\x89PNG
+
++IHDR\xE0[\xE7        pHYs  \x9A\x9C
+OiCCPPhotoshop ICC profilexÚSgTS\xE9=\xF7\xDE\xF4BK\x88\x80\x94KoR RB\x8B\x80\x91&amp;*!        J\x88!\xA1\xD9Q\xC1EEÈ \x88\x8E\x8E\x80\x8CQ, \x8A
+\xD8\xE4!\xA2\x8E\x83\xA3\x88\x8A\xCA\xFB\xE1{\xA3kÖ¼\xF7\xE6\xCD\xFE\xB5\xD7&gt;\xE7\xAC\xF3\x9D\xB3\xCF\xC0 \x96H3Q5\x80 \xA9B\xE0\x83\xC7\xC4\xC6\xE1\xE4.@\x81
+$p\xB3d!s\xFD#\xF8~&lt;&lt;+&quot;\xC0\xBEx\xD3 \xC0M\x9B\xC00\x87\xFF\xEAB\x99\\x80\x84\xC0t\x918K\x80@z\x8EB\xA6@F\x80\x9D\x98&amp;S\xA0`\xCBcb\xE3P-`'\xE6\xD3\x80\x9D\xF8\x99{[\x94!\xA0\x91 e\x88Dh;\xAC\xCFV\x8AEX0fK\xC49\xD8-0IWfH\xB0\xB7\xC0\xCE \xB2 0Q\x88\x85){`\xC8##x\x84\x99F\xF2W&lt;\xF1+\xAE\xE7*x\x99\xB2&lt;\xB9$9E\x81[-qWW.(\xCEI+6aa\x9A@.\xC2y\x992\x814\xE0\xF3\xCC\xA0\x91\xE0\x83\xF3\xFDx\xCE\xAE\xCE\xCE6\x8E\xB6_-\xEA\xBF\xFF&quot;bb\xE3\xFE\xE5Ï«p@\xE1t~\xD1\xFE,/\xB3\x80;\x80m\xFE\xA2%\xEEh^ \xA0u\xF7\x8Bf\xB2@\xB5\xA0\xE9\xDAW\xF3p\xF8~&lt;&lt;E\xA1\x90\xB9\xD9\xD9\xE5\xE4\xE4\xD8J\xC4B[a\xCAW}\xFEg\xC2_\xC0W\xFDl\xF9~&lt;\xFC\xF7\xF5\xE0\xBE\xE2$\x812]\x81G\xF8\xE0\xC2\xCC\xF4L\xA5Ï’        \x84b\xDC\xE6\x8FG\xFC\xB7 \xFF\xFC\xD3&quot;\xC4Ib\xB9X*\xE3Qq\x8ED\x9A\x8C\xF32\xA5&quot;\x89B\x92)\xC5%\xD2\xFFd\xE2\xDF,\xFB&gt;\xDF5\xB0j&gt;{\x91-\xA8]c\xF6K'Xt\xC0\xE2\xF7\xF2\xBBo\
 xC1\xD4(\x80h\x83\xE1\xCFw\xFF\xEF?\xFDG\xA0%\x80fI\x92q^D$.Tʳ?\xC7D\xA0\x81*\xB0A\xF4\xC1,\xC0\xC1\xDC\xC1 \xFC`6\x84B$\xC4\xC2BB
+d\x80r`)\xAC\x82B(\x86Í°*`/\xD4@4\xC0Qh\x86\x93p.\xC2U\xB8=p\xFAa\x9E\xC1(\xBC\x81        A\xC8a!Úˆb\x8AX#\x8E\x99\x85\xF8!\xC1H\x8B$ ÉˆQ&quot;K\x915H1R\x8AT UH\xF2=r9\x87\F\xBA\x91;\xC82\x82\xFC\x86\xBCG1\x94\x81\xB2Q=\xD4 \xB5C\xB9\xA87\x84F\xA2 \xD0dt1\x9A\x8F\xA0\x9B\xD0r\xB4=\x8C6\xA1\xE7ЫhÚ&gt;C\xC70\xC0\xE83\xC4l0.\xC6\xC3B\xB18,        \x93c˱&quot;\xAC \xAB\xC6\xB0V\xAC\xBB\x89\xF5cϱw\x81E\xC0        6wB aAHXLXN\xD8H\xA8 $4\xDA        7        \x84Q\xC2'&quot;\x93\xA8K\xB4&amp;\xBA\xF9\xC4b21\x87XH,#\xD6\x8F/{\x88C\xC47$\x89C2'\xB9\x90I\xB1\xA4T\xD2\xD2F\xD2nR#\xE9,\xA9\x9B4H#\x93\xC9\xDAdk\xB29\x94, +È…\xE4\x9D\xE4\xC3\xE43\xE4\xE4!\xF2[
+\x9Db@q\xA4\xF8S\xE2(R\xCAjJ\xE5\xE54\xE5e\x982AU\xA3\x9ARݨ\xA1T5\x8FZB\xAD\xA1\xB6R\xAFQ\x87\xA84u\x9A9̓IK\xA5\xAD\xA2\x95\xD3hh\xF7i\xAF\xE8t\xBAÝ•N\x97\xD0W\xD2\xCB\xE9G\xE8\x97\xE8\xF4w +\x86\x83Ljg(\x9Bgw\xAF\x98L\xA6Ó‹\xC7T071\xEB\x98\xE7\x99\x99oUX*\xB6*|\x91\xCA
+\x95J\x95&amp;\x95*/T\xA9\xAA\xA6\xAAÞª U\xF3U\xCBT\x8F\xA9^S}\xAEFU3S\xE3\xA9        Ô–\xABU\xAA\x9DP\xEBSSg\xA9;\xA8\x87\xAAg\xA8oT?\xA4~Y\xFD\x89Y\xC3L\xC3OC\xA4Q\xA0\xB1_\xE3\xBC\xC6  c\xB3x,!k+\xAB\x86u\x815\xC4&amp;\xB1\xCD\xD9|v*\xBB\x98\xFD\xBB\x8B=\xAA\xA9\xA19C3J3W\xB3R\xF3\x94f?\xE3\x98q\xF8\x9CtN        \xE7(\xA7\x97\xF3~\x8A\xDE\xEF)\xE2)\xA64L\xB91e\k\xAA\x96\x97\x96X\xABH\xABQ\xABG\xEB\xBD6\xAE\x{D9DD}\xA6\xBDE\xBBY\xFB\x81A\xC7J'\'Gg\x8F\xCE\x9D\xE7S\xD9Sݧ
+\xA7M=:\xF5\xAE.\xAAk\xA5\xA1\xBBDw\xBFn\xA7\xBE^\x80\x9ELo\xA7\xDEy\xBD\xE7\xFA}/\xFDT\xFDm\xFA\xA7\xF5G X\xB3 $\xDB \xCE&lt;\xC55qo&lt;/\xC7\xDB\xF1QC]\xC3@C\xA5a\x95a\x97ᄑ\xB9\xD1&lt;\xA3\xD5F\x8DF\x8Ci\xC6\\xE3$\xE3m\xC6mƣ&amp;&amp;!&amp;KM\xEAM\xEE\x9ARM\xB9\xA6)\xA6;L;L\xC7\xCD\xCC͢\xCD֙5\x9B=1\xD72\xE7\x9B\xE7\x9Bכ߷`ZxZ,\xB6\xA8\xB6\xB8eI\xB2\xE4Z\xA6Yn\x85Z9Y\xA5XUZ]\xB3F\xAD\x9D\xAD%ֻ\xAD\xBB\xA7\xA7\xB9N\x93N\xAB\x9E\xD6gð\xF1\xB6ɶ\xA9\xB7\xB0\xE5\xD8ۮ\xB6m\xB6}agbg\xB7Ů\xC3\x93}\xBA}\x8D\xFD=+\x87\xD9\xABZ~s\xB4r:V:ޚΜ\xEE?}\xC5\xF4\x96\xE9/gX\xCF\xCF\xD83\xE3\xB6\xCB)\xC4i\x9DS\x9B\xD3Ggg\xB9s\x83󈋉K\x82\xCB.\x97&gt;.\x9B\xC6\xDDȽ\xE4Jt\xF5q]\xE1z\xD2\x{15D6F3}\x9B\xC2\xED\xA8ۯ\xEE6\xEEi\xEE\x87ܟ\xCC4\x9F)\x9EY3s\xD0\xC3\xC8C\xE0Q\xE5\xD1? \x9F\x950k߬~OCO\x81g\xB5\xE7#/c/\x91W\xADװ\xB7\xA5w\xAA\xF7a\xEF&gt;\xF6&gt;r\x9F\xE3&gt;\xE3&lt;7\xDE2\xDEY_\xCC7\xC0\xB7ȷ\xCBO\xC3o\x9E_\x85\xDFC#\xFFd\xFFz\xFF\xD1\xA7\
 x80%g\x89\x81A\x81[\xFB\xF8z|!\xBF\x8E?:\xDBe\xF6\xB2\xD9\xEDA\x8C\xA0\xB9AA\x8F\x82\xAD\x82\xE5\xC1\xAD!h\xC8ì­!\xF7\xE7\x98Α\xCEi\x85P~\xE8\xD6\xD0a\xE6a\x8B\xC3~ '\x85\x87\x85W\x86?\x8Ep\x88X\xD11\x975w\xD1\xDCCs\xDFD\xFAD\x96DÞ›g1O9\xAF-J5*&gt;\xAA.j&lt;\xDA7\xBA4\xBA?\xC6.fY\xCC\xD5X\x9DXIlK9.*\xAE6nl\xBE\xDF\xFC\xED\xF3\x87\xE2\x9D\xE2 \xE3{\x98/\xC8]py\xA1\xCE\xC2\xF4\x85\xA7\xA9.,:\x96@L\x88N8\x94\xF0A*\xA8\x8C%\xF2w%\x8E
+y\xC2\xC2g&quot;/\xD16ш\xD8C\*N\xF2H*Mz\x92쑼5y$\xC53\xA5,幄'\xA9\x90\xBCL+LÝ›:\x9E\x9Av m2=:\xBD1\x83\x92\x91\x90qB\xAA!M\x93\xB6g\xEAg\xE6fvˬe\x85\xB2\xFE\xC5n\x8B\xB7/\x95\xC9k\xB3\x90\xACY-
+\xB6B\xA6\xE8TZ(\xD7*\xB2geWf\xBF͉\xCA9\x96\xAB\x9E+\xCD\xED̳\xCAÛ7\x9C\xEF\x9F\xFF\xED\xC2á’¶\xA5\x86KW-X潬j9\xB2&lt;qy\xDB
+\xE3+\x86V\xAC&lt;\xB8\x8A\xB6*m\xD5O\xAB\xEDW\x97\xAE~\xBD&amp;zMk\x81^\xC1Ê‚\xC1\xB5k\xEB U
+\xE5\x85}\xEB\xDC\xD7\xED]OX/Yßµa\xFA\x86\x9D&gt;\x89\x8A\xAE\xDB\x97\xD8(\xDCx\xE5\x87oÊ¿\x99Ü”\xB4\xA9\xABĹd\xCFf\xD2f\xE9\xE6\xDE-\x9E[\x96\xAA\x97\xE6\x97n+\xD9Ú´+\xDFV\xB4\xED\xF5\xF6E\xDB/\x97\xCD(Û»\x83\xB6C\xB9\xA3\xBF&lt;\xB8\xBCe\xA7\xC9\xCE\xCD;?T\xA4T\xF4T\xFAT6\xEE\xD2ݵa\xD7\xF8n\xD1\xEE{\xBC\xF64\xEC\xD5\xDB[\xBC\xF7\xFD&gt;ɾ\xDBUUM\xD5f\xD5e\xFBI\xFB\xB3\xF7?\xAE\x89\xAA\xE9\xF8\x96\xFBm]\xADNmq\xED\xC7\xD2\xFD#\xB6×¹\xD4\xD5\xD2=TR\x8F\xD6+\xEBG\xC7\xBE\xFE\x9D\xEFw-+6+U\x8D\x9C\xC6\xE2#pDy\xE4\xE9\xF7        \xDF\xF7+:\xDAv\x8C{\xAC\xE1\xD3vg/jB\x9A\xF2\x9AF\x9BS\x9A\xFB[b[\xBAO\xCC&gt;\xD1\xD6\xEA\xDEz\xFCG\xDB\x9C4&lt;YyJ\xF3T\xC9i\xDA\xE9\x82Ó“g\xF2ÏŒ\x9D\x95\x9D}~.\xF9\xDC`Û¢\xB6{\xE7c\xCE\xDFjo\xEF\xBAt\xE1\xD2E\xFF\x8B\xE7;\xBC;\xCE\\xF2\xB8t\xF2\xB2\xDB\xE5W\xB8W\x9A\xAF:_m\xEAt\xEA&lt;\xFE\x93\xD3OÇ»\x9C\xBB\x9A\xAE\xB9\k\xB9\xEEz\xBD\xB5{f\xF7\xE9\x9E7\xCE\xDD\xF4\xBDy\xF1\xFF\xD6Õž9=ݽ\xF3zo\xF7\xC5\xF7\xF5\xDF\xDD~r
 '\xFD\xCEË»\xD9w'î­¼O\xBC_\xF4@\xEDA\xD9C݇\xD5?[\xFE\xDC\xD8\xEF\xDCj\xC0w\xA0\xF3\xD1\xDCG\xF7\x85\x83\xCF\xFE\x91\xF5\x8FC\x8F\x99\x8Fˆ+\x86\xEB\x9E8&gt;99\xE2?r\xFD\xE9\xFC\xA7C\xCFd\xCF&amp;\x9E\xFE\xA2\xFEË®/~\xF8\xD5\xEB\xD7\xCEјѡ\x97ò—“¿m|\xA5\xFD\xEA\xC0\xEB\xAF\xDB\xC6\xC2\xC6\xBE\xC9x31^\xF4V\xFB\xED\xC1w\xDCw\xEF\xA3\xDFO\xE4| (\xFFh\xF9\xB1\xF5SЧ\xFB\x93\x93\x93\xFF\x98\xF3\xFCc3-\xDBgAMA\xB1\x8E|\xFBQ\x93 cHRMz%\x80\x83\xF9\xFF\x80\xE9u0\xEA`:\x98o\x92_\xC5FPLTE\xFF\xFF\xFF                        
+
+
+ +++   !!!&quot;&quot;&quot;###$$$%%%&amp;&amp;&amp;'''((()))***+++,,,---...///000111222333444555666777888999:::;;;&lt;&lt;&lt;===&gt;&gt;&gt;???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~\x80\x80\x80\x81\x81\x81\x82\x82\x82\x83\x83\x83\x84\x84\x84\x85\x85\x85\x86\x86\x86\x87\x87\x87\x88\x88\x88\x89\x89\x89\x8A\x8A\x8A\x8B\x8B\x8B\x8C\x8C\x8C\x8D\x8D\x8D\x8E\x8E\x8E\x8F\x8F\x8F\x90\x90\x90\x91\x91\x91\x92\x92\x92\x93\x93\x93\x94\x94\x94\x95\x95\x95\x96\x96\x96\x97\x97\x97\x98\x98\x98\x99\x99\x99\x9A\x9A\x9A\x9B\x9B\x9B\x9C\x9C\x9C\x9D\x9D\x9D\x9E\x9E\x9E\x9F\x9F\x9F\xA0\xA0\xA0\xA1\xA1\xA1\xA2\xA2\xA2\xA3\xA3\xA3\xA4\xA4\xA4\xA5\xA5\xA5\xA6\xA6\xA6\xA7\xA7\xA7\xA8\xA8\xA8\xA9\xA9\xA9\xAA\xAA\xAA\xAB\xAB\xAB\xAC\xAC\xAC\xAD\xAD\xAD\xAE\xAE\xAE\xAF\xAF\xAF\xB0\xB0\xB0\x
 B1\xB1\xB1\xB2\xB2\xB2\xB3\xB3\xB3\xB4\xB4\xB4\xB5\xB5\xB5\xB6\xB6\xB6\xB7\xB7\xB7\xB8\xB8\xB8\xB9\xB9\xB9\xBA\xBA\xBA\xBB\xBB\xBB\xBC\xBC\xBC\xBD\xBD\xBD\xBE\xBE\xBE\xBF\xBF\xBF\xC0\xC0\xC0\xC1\xC1\xC1\xC2\xC2\xC2\xC3\xC3\xC3\xC4\xC4\xC4\xC5\xC5\xC5\xC6\xC6\xC6\xC7\xC7\xC7\xC8\xC8\xC8\xC9\xC9\xC9\xCA\xCA\xCA\xCB\xCB\xCB\xCC\xCC\xCC\xCD\xCD\xCD\xCE\xCE\xCE\xCF\xCF\xCF\xD0\xD0\xD0\xD1\xD1\xD1\xD2\xD2\xD2\xD3\xD3\xD3\xD4\xD4\xD4\xD5\xD5\xD5\xD6\xD6\xD6\xD7\xD7\xD7\xD8\xD8\xD8\xD9\xD9\xD9\xDA\xDA\xDA\xDB\xDB\xDB\xDC\xDC\xDC\xDD\xDD\xDD\xDE\xDE\xDE\xDF\xDF\xDF\xE0\xE0\xE0\xE1\xE1\xE1\xE2\xE2\xE2\xE3\xE3\xE3\xE4\xE4\xE4\xE5\xE5\xE5\xE6\xE6\xE6\xE7\xE7\xE7\xE8\xE8\xE8\xE9\xE9\xE9\xEA\xEA\xEA\xEB\xEB\xEB\xEC\xEC\xEC\xED\xED\xED\xEE\xEE\xEE\xEF\xEF\xEF\xF0\xF0\xF0\xF1\xF1\xF1\xF2\xF2\xF2\xF3\xF3\xF3\xF4\xF4\xF4\xF5\xF5\xF5\xF6\xF6\xF6\xF7\xF7\xF7\xF8\xF8\xF8\xF9\xF9\xF9\xFA\xFA\xFA\xFB\xFB\xFB\xFC\xFC\xFC\xFD\xFD\xFD\xFE\xFE\xFE\xFF\xFF\xFF\xF9$\xB9\xDCtRNS\xFF\xE5\xB70J*IDA
 Tx\xDA\\xCC1\xC0 \xC1\xD9\xFF:\x88\xB8ɶ\xAE\xF0\xF0Ø¢\xD1D\xC3\xE8\xF7ÞŽ?U\xDFTU\xA0\xB8\xE8IEND\xAEB`\x82
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssammenuitem_checkbox_disabledpng"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menuitem_checkbox_disabled.png (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menuitem_checkbox_disabled.png                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menuitem_checkbox_disabled.png        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,31 @@
</span><ins>+\x89PNG
+
++IHDR\xE0[\xE7        pHYs  \x9A\x9C
+OiCCPPhotoshop ICC profilexÚSgTS\xE9=\xF7\xDE\xF4BK\x88\x80\x94KoR RB\x8B\x80\x91&amp;*!        J\x88!\xA1\xD9Q\xC1EEÈ \x88\x8E\x8E\x80\x8CQ, \x8A
+\xD8\xE4!\xA2\x8E\x83\xA3\x88\x8A\xCA\xFB\xE1{\xA3kÖ¼\xF7\xE6\xCD\xFE\xB5\xD7&gt;\xE7\xAC\xF3\x9D\xB3\xCF\xC0 \x96H3Q5\x80 \xA9B\xE0\x83\xC7\xC4\xC6\xE1\xE4.@\x81
+$p\xB3d!s\xFD#\xF8~&lt;&lt;+&quot;\xC0\xBEx\xD3 \xC0M\x9B\xC00\x87\xFF\xEAB\x99\\x80\x84\xC0t\x918K\x80@z\x8EB\xA6@F\x80\x9D\x98&amp;S\xA0`\xCBcb\xE3P-`'\xE6\xD3\x80\x9D\xF8\x99{[\x94!\xA0\x91 e\x88Dh;\xAC\xCFV\x8AEX0fK\xC49\xD8-0IWfH\xB0\xB7\xC0\xCE \xB2 0Q\x88\x85){`\xC8##x\x84\x99F\xF2W&lt;\xF1+\xAE\xE7*x\x99\xB2&lt;\xB9$9E\x81[-qWW.(\xCEI+6aa\x9A@.\xC2y\x992\x814\xE0\xF3\xCC\xA0\x91\xE0\x83\xF3\xFDx\xCE\xAE\xCE\xCE6\x8E\xB6_-\xEA\xBF\xFF&quot;bb\xE3\xFE\xE5Ï«p@\xE1t~\xD1\xFE,/\xB3\x80;\x80m\xFE\xA2%\xEEh^ \xA0u\xF7\x8Bf\xB2@\xB5\xA0\xE9\xDAW\xF3p\xF8~&lt;&lt;E\xA1\x90\xB9\xD9\xD9\xE5\xE4\xE4\xD8J\xC4B[a\xCAW}\xFEg\xC2_\xC0W\xFDl\xF9~&lt;\xFC\xF7\xF5\xE0\xBE\xE2$\x812]\x81G\xF8\xE0\xC2\xCC\xF4L\xA5Ï’        \x84b\xDC\xE6\x8FG\xFC\xB7 \xFF\xFC\xD3&quot;\xC4Ib\xB9X*\xE3Qq\x8ED\x9A\x8C\xF32\xA5&quot;\x89B\x92)\xC5%\xD2\xFFd\xE2\xDF,\xFB&gt;\xDF5\xB0j&gt;{\x91-\xA8]c\xF6K'Xt\xC0\xE2\xF7\xF2\xBBo\
 xC1\xD4(\x80h\x83\xE1\xCFw\xFF\xEF?\xFDG\xA0%\x80fI\x92q^D$.Tʳ?\xC7D\xA0\x81*\xB0A\xF4\xC1,\xC0\xC1\xDC\xC1 \xFC`6\x84B$\xC4\xC2BB
+d\x80r`)\xAC\x82B(\x86Í°*`/\xD4@4\xC0Qh\x86\x93p.\xC2U\xB8=p\xFAa\x9E\xC1(\xBC\x81        A\xC8a!Úˆb\x8AX#\x8E\x99\x85\xF8!\xC1H\x8B$ ÉˆQ&quot;K\x915H1R\x8AT UH\xF2=r9\x87\F\xBA\x91;\xC82\x82\xFC\x86\xBCG1\x94\x81\xB2Q=\xD4 \xB5C\xB9\xA87\x84F\xA2 \xD0dt1\x9A\x8F\xA0\x9B\xD0r\xB4=\x8C6\xA1\xE7ЫhÚ&gt;C\xC70\xC0\xE83\xC4l0.\xC6\xC3B\xB18,        \x93c˱&quot;\xAC \xAB\xC6\xB0V\xAC\xBB\x89\xF5cϱw\x81E\xC0        6wB aAHXLXN\xD8H\xA8 $4\xDA        7        \x84Q\xC2'&quot;\x93\xA8K\xB4&amp;\xBA\xF9\xC4b21\x87XH,#\xD6\x8F/{\x88C\xC47$\x89C2'\xB9\x90I\xB1\xA4T\xD2\xD2F\xD2nR#\xE9,\xA9\x9B4H#\x93\xC9\xDAdk\xB29\x94, +È…\xE4\x9D\xE4\xC3\xE43\xE4\xE4!\xF2[
+\x9Db@q\xA4\xF8S\xE2(R\xCAjJ\xE5\xE54\xE5e\x982AU\xA3\x9ARݨ\xA1T5\x8FZB\xAD\xA1\xB6R\xAFQ\x87\xA84u\x9A9̓IK\xA5\xAD\xA2\x95\xD3hh\xF7i\xAF\xE8t\xBAÝ•N\x97\xD0W\xD2\xCB\xE9G\xE8\x97\xE8\xF4w +\x86\x83Ljg(\x9Bgw\xAF\x98L\xA6Ó‹\xC7T071\xEB\x98\xE7\x99\x99oUX*\xB6*|\x91\xCA
+\x95J\x95&amp;\x95*/T\xA9\xAA\xA6\xAAÞª U\xF3U\xCBT\x8F\xA9^S}\xAEFU3S\xE3\xA9        Ô–\xABU\xAA\x9DP\xEBSSg\xA9;\xA8\x87\xAAg\xA8oT?\xA4~Y\xFD\x89Y\xC3L\xC3OC\xA4Q\xA0\xB1_\xE3\xBC\xC6  c\xB3x,!k+\xAB\x86u\x815\xC4&amp;\xB1\xCD\xD9|v*\xBB\x98\xFD\xBB\x8B=\xAA\xA9\xA19C3J3W\xB3R\xF3\x94f?\xE3\x98q\xF8\x9CtN        \xE7(\xA7\x97\xF3~\x8A\xDE\xEF)\xE2)\xA64L\xB91e\k\xAA\x96\x97\x96X\xABH\xABQ\xABG\xEB\xBD6\xAE\x{D9DD}\xA6\xBDE\xBBY\xFB\x81A\xC7J'\'Gg\x8F\xCE\x9D\xE7S\xD9Sݧ
+\xA7M=:\xF5\xAE.\xAAk\xA5\xA1\xBBDw\xBFn\xA7\xBE^\x80\x9ELo\xA7\xDEy\xBD\xE7\xFA}/\xFDT\xFDm\xFA\xA7\xF5G X\xB3 $\xDB \xCE&lt;\xC55qo&lt;/\xC7\xDB\xF1QC]\xC3@C\xA5a\x95a\x97ᄑ\xB9\xD1&lt;\xA3\xD5F\x8DF\x8Ci\xC6\\xE3$\xE3m\xC6mƣ&amp;&amp;!&amp;KM\xEAM\xEE\x9ARM\xB9\xA6)\xA6;L;L\xC7\xCD\xCC͢\xCD֙5\x9B=1\xD72\xE7\x9B\xE7\x9Bכ߷`ZxZ,\xB6\xA8\xB6\xB8eI\xB2\xE4Z\xA6Yn\x85Z9Y\xA5XUZ]\xB3F\xAD\x9D\xAD%ֻ\xAD\xBB\xA7\xA7\xB9N\x93N\xAB\x9E\xD6gð\xF1\xB6ɶ\xA9\xB7\xB0\xE5\xD8ۮ\xB6m\xB6}agbg\xB7Ů\xC3\x93}\xBA}\x8D\xFD=+\x87\xD9\xABZ~s\xB4r:V:ޚΜ\xEE?}\xC5\xF4\x96\xE9/gX\xCF\xCF\xD83\xE3\xB6\xCB)\xC4i\x9DS\x9B\xD3Ggg\xB9s\x83󈋉K\x82\xCB.\x97&gt;.\x9B\xC6\xDDȽ\xE4Jt\xF5q]\xE1z\xD2\x{15D6F3}\x9B\xC2\xED\xA8ۯ\xEE6\xEEi\xEE\x87ܟ\xCC4\x9F)\x9EY3s\xD0\xC3\xC8C\xE0Q\xE5\xD1? \x9F\x950k߬~OCO\x81g\xB5\xE7#/c/\x91W\xADװ\xB7\xA5w\xAA\xF7a\xEF&gt;\xF6&gt;r\x9F\xE3&gt;\xE3&lt;7\xDE2\xDEY_\xCC7\xC0\xB7ȷ\xCBO\xC3o\x9E_\x85\xDFC#\xFFd\xFFz\xFF\xD1\xA7\
 x80%g\x89\x81A\x81[\xFB\xF8z|!\xBF\x8E?:\xDBe\xF6\xB2\xD9\xEDA\x8C\xA0\xB9AA\x8F\x82\xAD\x82\xE5\xC1\xAD!h\xC8ì­!\xF7\xE7\x98Α\xCEi\x85P~\xE8\xD6\xD0a\xE6a\x8B\xC3~ '\x85\x87\x85W\x86?\x8Ep\x88X\xD11\x975w\xD1\xDCCs\xDFD\xFAD\x96DÞ›g1O9\xAF-J5*&gt;\xAA.j&lt;\xDA7\xBA4\xBA?\xC6.fY\xCC\xD5X\x9DXIlK9.*\xAE6nl\xBE\xDF\xFC\xED\xF3\x87\xE2\x9D\xE2 \xE3{\x98/\xC8]py\xA1\xCE\xC2\xF4\x85\xA7\xA9.,:\x96@L\x88N8\x94\xF0A*\xA8\x8C%\xF2w%\x8E
+y\xC2\xC2g&quot;/\xD16ш\xD8C\*N\xF2H*Mz\x92쑼5y$\xC53\xA5,幄'\xA9\x90\xBCL+LÝ›:\x9E\x9Av m2=:\xBD1\x83\x92\x91\x90qB\xAA!M\x93\xB6g\xEAg\xE6fvˬe\x85\xB2\xFE\xC5n\x8B\xB7/\x95\xC9k\xB3\x90\xACY-
+\xB6B\xA6\xE8TZ(\xD7*\xB2geWf\xBF͉\xCA9\x96\xAB\x9E+\xCD\xED̳\xCAÛ7\x9C\xEF\x9F\xFF\xED\xC2á’¶\xA5\x86KW-X潬j9\xB2&lt;qy\xDB
+\xE3+\x86V\xAC&lt;\xB8\x8A\xB6*m\xD5O\xAB\xEDW\x97\xAE~\xBD&amp;zMk\x81^\xC1Ê‚\xC1\xB5k\xEB U
+\xE5\x85}\xEB\xDC\xD7\xED]OX/Yßµa\xFA\x86\x9D&gt;\x89\x8A\xAE\xDB\x97\xD8(\xDCx\xE5\x87oÊ¿\x99Ü”\xB4\xA9\xABĹd\xCFf\xD2f\xE9\xE6\xDE-\x9E[\x96\xAA\x97\xE6\x97n+\xD9Ú´+\xDFV\xB4\xED\xF5\xF6E\xDB/\x97\xCD(Û»\x83\xB6C\xB9\xA3\xBF&lt;\xB8\xBCe\xA7\xC9\xCE\xCD;?T\xA4T\xF4T\xFAT6\xEE\xD2ݵa\xD7\xF8n\xD1\xEE{\xBC\xF64\xEC\xD5\xDB[\xBC\xF7\xFD&gt;ɾ\xDBUUM\xD5f\xD5e\xFBI\xFB\xB3\xF7?\xAE\x89\xAA\xE9\xF8\x96\xFBm]\xADNmq\xED\xC7\xD2\xFD#\xB6×¹\xD4\xD5\xD2=TR\x8F\xD6+\xEBG\xC7\xBE\xFE\x9D\xEFw-+6+U\x8D\x9C\xC6\xE2#pDy\xE4\xE9\xF7        \xDF\xF7+:\xDAv\x8C{\xAC\xE1\xD3vg/jB\x9A\xF2\x9AF\x9BS\x9A\xFB[b[\xBAO\xCC&gt;\xD1\xD6\xEA\xDEz\xFCG\xDB\x9C4&lt;YyJ\xF3T\xC9i\xDA\xE9\x82Ó“g\xF2ÏŒ\x9D\x95\x9D}~.\xF9\xDC`Û¢\xB6{\xE7c\xCE\xDFjo\xEF\xBAt\xE1\xD2E\xFF\x8B\xE7;\xBC;\xCE\\xF2\xB8t\xF2\xB2\xDB\xE5W\xB8W\x9A\xAF:_m\xEAt\xEA&lt;\xFE\x93\xD3OÇ»\x9C\xBB\x9A\xAE\xB9\k\xB9\xEEz\xBD\xB5{f\xF7\xE9\x9E7\xCE\xDD\xF4\xBDy\xF1\xFF\xD6Õž9=ݽ\xF3zo\xF7\xC5\xF7\xF5\xDF\xDD~r
 '\xFD\xCEË»\xD9w'î­¼O\xBC_\xF4@\xEDA\xD9C݇\xD5?[\xFE\xDC\xD8\xEF\xDCj\xC0w\xA0\xF3\xD1\xDCG\xF7\x85\x83\xCF\xFE\x91\xF5\x8FC\x8F\x99\x8Fˆ+\x86\xEB\x9E8&gt;99\xE2?r\xFD\xE9\xFC\xA7C\xCFd\xCF&amp;\x9E\xFE\xA2\xFEË®/~\xF8\xD5\xEB\xD7\xCEјѡ\x97ò—“¿m|\xA5\xFD\xEA\xC0\xEB\xAF\xDB\xC6\xC2\xC6\xBE\xC9x31^\xF4V\xFB\xED\xC1w\xDCw\xEF\xA3\xDFO\xE4| (\xFFh\xF9\xB1\xF5SЧ\xFB\x93\x93\x93\xFF\x98\xF3\xFCc3-\xDBgAMA\xB1\x8E|\xFBQ\x93 cHRMz%\x80\x83\xF9\xFF\x80\xE9u0\xEA`:\x98o\x92_\xC5FPLTE\xFF\xFF\xFF                        
+
+
+ +++   !!!&quot;&quot;&quot;###$$$%%%&amp;&amp;&amp;'''((()))***+++,,,---...///000111222333444555666777888999:::;;;&lt;&lt;&lt;===&gt;&gt;&gt;???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~\x80\x80\x80\x81\x81\x81\x82\x82\x82\x83\x83\x83\x84\x84\x84\x85\x85\x85\x86\x86\x86\x87\x87\x87\x88\x88\x88\x89\x89\x89\x8A\x8A\x8A\x8B\x8B\x8B\x8C\x8C\x8C\x8D\x8D\x8D\x8E\x8E\x8E\x8F\x8F\x8F\x90\x90\x90\x91\x91\x91\x92\x92\x92\x93\x93\x93\x94\x94\x94\x95\x95\x95\x96\x96\x96\x97\x97\x97\x98\x98\x98\x99\x99\x99\x9A\x9A\x9A\x9B\x9B\x9B\x9C\x9C\x9C\x9D\x9D\x9D\x9E\x9E\x9E\x9F\x9F\x9F\xA0\xA0\xA0\xA1\xA1\xA1\xA2\xA2\xA2\xA3\xA3\xA3\xA4\xA4\xA4\xA5\xA5\xA5\xA6\xA6\xA6\xA7\xA7\xA7\xA8\xA8\xA8\xA9\xA9\xA9\xAA\xAA\xAA\xAB\xAB\xAB\xAC\xAC\xAC\xAD\xAD\xAD\xAE\xAE\xAE\xAF\xAF\xAF\xB0\xB0\xB0\x
 B1\xB1\xB1\xB2\xB2\xB2\xB3\xB3\xB3\xB4\xB4\xB4\xB5\xB5\xB5\xB6\xB6\xB6\xB7\xB7\xB7\xB8\xB8\xB8\xB9\xB9\xB9\xBA\xBA\xBA\xBB\xBB\xBB\xBC\xBC\xBC\xBD\xBD\xBD\xBE\xBE\xBE\xBF\xBF\xBF\xC0\xC0\xC0\xC1\xC1\xC1\xC2\xC2\xC2\xC3\xC3\xC3\xC4\xC4\xC4\xC5\xC5\xC5\xC6\xC6\xC6\xC7\xC7\xC7\xC8\xC8\xC8\xC9\xC9\xC9\xCA\xCA\xCA\xCB\xCB\xCB\xCC\xCC\xCC\xCD\xCD\xCD\xCE\xCE\xCE\xCF\xCF\xCF\xD0\xD0\xD0\xD1\xD1\xD1\xD2\xD2\xD2\xD3\xD3\xD3\xD4\xD4\xD4\xD5\xD5\xD5\xD6\xD6\xD6\xD7\xD7\xD7\xD8\xD8\xD8\xD9\xD9\xD9\xDA\xDA\xDA\xDB\xDB\xDB\xDC\xDC\xDC\xDD\xDD\xDD\xDE\xDE\xDE\xDF\xDF\xDF\xE0\xE0\xE0\xE1\xE1\xE1\xE2\xE2\xE2\xE3\xE3\xE3\xE4\xE4\xE4\xE5\xE5\xE5\xE6\xE6\xE6\xE7\xE7\xE7\xE8\xE8\xE8\xE9\xE9\xE9\xEA\xEA\xEA\xEB\xEB\xEB\xEC\xEC\xEC\xED\xED\xED\xEE\xEE\xEE\xEF\xEF\xEF\xF0\xF0\xF0\xF1\xF1\xF1\xF2\xF2\xF2\xF3\xF3\xF3\xF4\xF4\xF4\xF5\xF5\xF5\xF6\xF6\xF6\xF7\xF7\xF7\xF8\xF8\xF8\xF9\xF9\xF9\xFA\xFA\xFA\xFB\xFB\xFB\xFC\xFC\xFC\xFD\xFD\xFD\xFE\xFE\xFE\xFF\xFF\xFFy\x80tRNS\xFF\xE5\xB70J*IDATx\xDA
 \\xCC1\xC0 \xC1\xD9\xFF:\x88\xB8ɶ\xAE\xF0\xF0Ø¢\xD1D\xC3\xE8\xF7ÞŽ?U\xDFTU\xA0\xB8\xE8IEND\xAEB`\x82
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssammenuitem_submenuindicatorpng"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menuitem_submenuindicator.png (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menuitem_submenuindicator.png                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menuitem_submenuindicator.png        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,32 @@
</span><ins>+\x89PNG
+
++IHDR  l\        pHYs  \x9A\x9C
+OiCCPPhotoshop ICC profilexÚSgTS\xE9=\xF7\xDE\xF4BK\x88\x80\x94KoR RB\x8B\x80\x91&amp;*!        J\x88!\xA1\xD9Q\xC1EEÈ \x88\x8E\x8E\x80\x8CQ, \x8A
+\xD8\xE4!\xA2\x8E\x83\xA3\x88\x8A\xCA\xFB\xE1{\xA3kÖ¼\xF7\xE6\xCD\xFE\xB5\xD7&gt;\xE7\xAC\xF3\x9D\xB3\xCF\xC0 \x96H3Q5\x80 \xA9B\xE0\x83\xC7\xC4\xC6\xE1\xE4.@\x81
+$p\xB3d!s\xFD#\xF8~&lt;&lt;+&quot;\xC0\xBEx\xD3 \xC0M\x9B\xC00\x87\xFF\xEAB\x99\\x80\x84\xC0t\x918K\x80@z\x8EB\xA6@F\x80\x9D\x98&amp;S\xA0`\xCBcb\xE3P-`'\xE6\xD3\x80\x9D\xF8\x99{[\x94!\xA0\x91 e\x88Dh;\xAC\xCFV\x8AEX0fK\xC49\xD8-0IWfH\xB0\xB7\xC0\xCE \xB2 0Q\x88\x85){`\xC8##x\x84\x99F\xF2W&lt;\xF1+\xAE\xE7*x\x99\xB2&lt;\xB9$9E\x81[-qWW.(\xCEI+6aa\x9A@.\xC2y\x992\x814\xE0\xF3\xCC\xA0\x91\xE0\x83\xF3\xFDx\xCE\xAE\xCE\xCE6\x8E\xB6_-\xEA\xBF\xFF&quot;bb\xE3\xFE\xE5Ï«p@\xE1t~\xD1\xFE,/\xB3\x80;\x80m\xFE\xA2%\xEEh^ \xA0u\xF7\x8Bf\xB2@\xB5\xA0\xE9\xDAW\xF3p\xF8~&lt;&lt;E\xA1\x90\xB9\xD9\xD9\xE5\xE4\xE4\xD8J\xC4B[a\xCAW}\xFEg\xC2_\xC0W\xFDl\xF9~&lt;\xFC\xF7\xF5\xE0\xBE\xE2$\x812]\x81G\xF8\xE0\xC2\xCC\xF4L\xA5Ï’        \x84b\xDC\xE6\x8FG\xFC\xB7 \xFF\xFC\xD3&quot;\xC4Ib\xB9X*\xE3Qq\x8ED\x9A\x8C\xF32\xA5&quot;\x89B\x92)\xC5%\xD2\xFFd\xE2\xDF,\xFB&gt;\xDF5\xB0j&gt;{\x91-\xA8]c\xF6K'Xt\xC0\xE2\xF7\xF2\xBBo\
 xC1\xD4(\x80h\x83\xE1\xCFw\xFF\xEF?\xFDG\xA0%\x80fI\x92q^D$.Tʳ?\xC7D\xA0\x81*\xB0A\xF4\xC1,\xC0\xC1\xDC\xC1 \xFC`6\x84B$\xC4\xC2BB
+d\x80r`)\xAC\x82B(\x86Í°*`/\xD4@4\xC0Qh\x86\x93p.\xC2U\xB8=p\xFAa\x9E\xC1(\xBC\x81        A\xC8a!Úˆb\x8AX#\x8E\x99\x85\xF8!\xC1H\x8B$ ÉˆQ&quot;K\x915H1R\x8AT UH\xF2=r9\x87\F\xBA\x91;\xC82\x82\xFC\x86\xBCG1\x94\x81\xB2Q=\xD4 \xB5C\xB9\xA87\x84F\xA2 \xD0dt1\x9A\x8F\xA0\x9B\xD0r\xB4=\x8C6\xA1\xE7ЫhÚ&gt;C\xC70\xC0\xE83\xC4l0.\xC6\xC3B\xB18,        \x93c˱&quot;\xAC \xAB\xC6\xB0V\xAC\xBB\x89\xF5cϱw\x81E\xC0        6wB aAHXLXN\xD8H\xA8 $4\xDA        7        \x84Q\xC2'&quot;\x93\xA8K\xB4&amp;\xBA\xF9\xC4b21\x87XH,#\xD6\x8F/{\x88C\xC47$\x89C2'\xB9\x90I\xB1\xA4T\xD2\xD2F\xD2nR#\xE9,\xA9\x9B4H#\x93\xC9\xDAdk\xB29\x94, +È…\xE4\x9D\xE4\xC3\xE43\xE4\xE4!\xF2[
+\x9Db@q\xA4\xF8S\xE2(R\xCAjJ\xE5\xE54\xE5e\x982AU\xA3\x9ARݨ\xA1T5\x8FZB\xAD\xA1\xB6R\xAFQ\x87\xA84u\x9A9̓IK\xA5\xAD\xA2\x95\xD3hh\xF7i\xAF\xE8t\xBAÝ•N\x97\xD0W\xD2\xCB\xE9G\xE8\x97\xE8\xF4w +\x86\x83Ljg(\x9Bgw\xAF\x98L\xA6Ó‹\xC7T071\xEB\x98\xE7\x99\x99oUX*\xB6*|\x91\xCA
+\x95J\x95&amp;\x95*/T\xA9\xAA\xA6\xAAÞª U\xF3U\xCBT\x8F\xA9^S}\xAEFU3S\xE3\xA9        Ô–\xABU\xAA\x9DP\xEBSSg\xA9;\xA8\x87\xAAg\xA8oT?\xA4~Y\xFD\x89Y\xC3L\xC3OC\xA4Q\xA0\xB1_\xE3\xBC\xC6  c\xB3x,!k+\xAB\x86u\x815\xC4&amp;\xB1\xCD\xD9|v*\xBB\x98\xFD\xBB\x8B=\xAA\xA9\xA19C3J3W\xB3R\xF3\x94f?\xE3\x98q\xF8\x9CtN        \xE7(\xA7\x97\xF3~\x8A\xDE\xEF)\xE2)\xA64L\xB91e\k\xAA\x96\x97\x96X\xABH\xABQ\xABG\xEB\xBD6\xAE\x{D9DD}\xA6\xBDE\xBBY\xFB\x81A\xC7J'\'Gg\x8F\xCE\x9D\xE7S\xD9Sݧ
+\xA7M=:\xF5\xAE.\xAAk\xA5\xA1\xBBDw\xBFn\xA7\xBE^\x80\x9ELo\xA7\xDEy\xBD\xE7\xFA}/\xFDT\xFDm\xFA\xA7\xF5G X\xB3 $\xDB \xCE&lt;\xC55qo&lt;/\xC7\xDB\xF1QC]\xC3@C\xA5a\x95a\x97ᄑ\xB9\xD1&lt;\xA3\xD5F\x8DF\x8Ci\xC6\\xE3$\xE3m\xC6mƣ&amp;&amp;!&amp;KM\xEAM\xEE\x9ARM\xB9\xA6)\xA6;L;L\xC7\xCD\xCC͢\xCD֙5\x9B=1\xD72\xE7\x9B\xE7\x9Bכ߷`ZxZ,\xB6\xA8\xB6\xB8eI\xB2\xE4Z\xA6Yn\x85Z9Y\xA5XUZ]\xB3F\xAD\x9D\xAD%ֻ\xAD\xBB\xA7\xA7\xB9N\x93N\xAB\x9E\xD6gð\xF1\xB6ɶ\xA9\xB7\xB0\xE5\xD8ۮ\xB6m\xB6}agbg\xB7Ů\xC3\x93}\xBA}\x8D\xFD=+\x87\xD9\xABZ~s\xB4r:V:ޚΜ\xEE?}\xC5\xF4\x96\xE9/gX\xCF\xCF\xD83\xE3\xB6\xCB)\xC4i\x9DS\x9B\xD3Ggg\xB9s\x83󈋉K\x82\xCB.\x97&gt;.\x9B\xC6\xDDȽ\xE4Jt\xF5q]\xE1z\xD2\x{15D6F3}\x9B\xC2\xED\xA8ۯ\xEE6\xEEi\xEE\x87ܟ\xCC4\x9F)\x9EY3s\xD0\xC3\xC8C\xE0Q\xE5\xD1? \x9F\x950k߬~OCO\x81g\xB5\xE7#/c/\x91W\xADװ\xB7\xA5w\xAA\xF7a\xEF&gt;\xF6&gt;r\x9F\xE3&gt;\xE3&lt;7\xDE2\xDEY_\xCC7\xC0\xB7ȷ\xCBO\xC3o\x9E_\x85\xDFC#\xFFd\xFFz\xFF\xD1\xA7\
 x80%g\x89\x81A\x81[\xFB\xF8z|!\xBF\x8E?:\xDBe\xF6\xB2\xD9\xEDA\x8C\xA0\xB9AA\x8F\x82\xAD\x82\xE5\xC1\xAD!h\xC8ì­!\xF7\xE7\x98Α\xCEi\x85P~\xE8\xD6\xD0a\xE6a\x8B\xC3~ '\x85\x87\x85W\x86?\x8Ep\x88X\xD11\x975w\xD1\xDCCs\xDFD\xFAD\x96DÞ›g1O9\xAF-J5*&gt;\xAA.j&lt;\xDA7\xBA4\xBA?\xC6.fY\xCC\xD5X\x9DXIlK9.*\xAE6nl\xBE\xDF\xFC\xED\xF3\x87\xE2\x9D\xE2 \xE3{\x98/\xC8]py\xA1\xCE\xC2\xF4\x85\xA7\xA9.,:\x96@L\x88N8\x94\xF0A*\xA8\x8C%\xF2w%\x8E
+y\xC2\xC2g&quot;/\xD16ш\xD8C\*N\xF2H*Mz\x92쑼5y$\xC53\xA5,幄'\xA9\x90\xBCL+LÝ›:\x9E\x9Av m2=:\xBD1\x83\x92\x91\x90qB\xAA!M\x93\xB6g\xEAg\xE6fvˬe\x85\xB2\xFE\xC5n\x8B\xB7/\x95\xC9k\xB3\x90\xACY-
+\xB6B\xA6\xE8TZ(\xD7*\xB2geWf\xBF͉\xCA9\x96\xAB\x9E+\xCD\xED̳\xCAÛ7\x9C\xEF\x9F\xFF\xED\xC2á’¶\xA5\x86KW-X潬j9\xB2&lt;qy\xDB
+\xE3+\x86V\xAC&lt;\xB8\x8A\xB6*m\xD5O\xAB\xEDW\x97\xAE~\xBD&amp;zMk\x81^\xC1Ê‚\xC1\xB5k\xEB U
+\xE5\x85}\xEB\xDC\xD7\xED]OX/Yßµa\xFA\x86\x9D&gt;\x89\x8A\xAE\xDB\x97\xD8(\xDCx\xE5\x87oÊ¿\x99Ü”\xB4\xA9\xABĹd\xCFf\xD2f\xE9\xE6\xDE-\x9E[\x96\xAA\x97\xE6\x97n+\xD9Ú´+\xDFV\xB4\xED\xF5\xF6E\xDB/\x97\xCD(Û»\x83\xB6C\xB9\xA3\xBF&lt;\xB8\xBCe\xA7\xC9\xCE\xCD;?T\xA4T\xF4T\xFAT6\xEE\xD2ݵa\xD7\xF8n\xD1\xEE{\xBC\xF64\xEC\xD5\xDB[\xBC\xF7\xFD&gt;ɾ\xDBUUM\xD5f\xD5e\xFBI\xFB\xB3\xF7?\xAE\x89\xAA\xE9\xF8\x96\xFBm]\xADNmq\xED\xC7\xD2\xFD#\xB6×¹\xD4\xD5\xD2=TR\x8F\xD6+\xEBG\xC7\xBE\xFE\x9D\xEFw-+6+U\x8D\x9C\xC6\xE2#pDy\xE4\xE9\xF7        \xDF\xF7+:\xDAv\x8C{\xAC\xE1\xD3vg/jB\x9A\xF2\x9AF\x9BS\x9A\xFB[b[\xBAO\xCC&gt;\xD1\xD6\xEA\xDEz\xFCG\xDB\x9C4&lt;YyJ\xF3T\xC9i\xDA\xE9\x82Ó“g\xF2ÏŒ\x9D\x95\x9D}~.\xF9\xDC`Û¢\xB6{\xE7c\xCE\xDFjo\xEF\xBAt\xE1\xD2E\xFF\x8B\xE7;\xBC;\xCE\\xF2\xB8t\xF2\xB2\xDB\xE5W\xB8W\x9A\xAF:_m\xEAt\xEA&lt;\xFE\x93\xD3OÇ»\x9C\xBB\x9A\xAE\xB9\k\xB9\xEEz\xBD\xB5{f\xF7\xE9\x9E7\xCE\xDD\xF4\xBDy\xF1\xFF\xD6Õž9=ݽ\xF3zo\xF7\xC5\xF7\xF5\xDF\xDD~r
 '\xFD\xCEË»\xD9w'î­¼O\xBC_\xF4@\xEDA\xD9C݇\xD5?[\xFE\xDC\xD8\xEF\xDCj\xC0w\xA0\xF3\xD1\xDCG\xF7\x85\x83\xCF\xFE\x91\xF5\x8FC\x8F\x99\x8Fˆ+\x86\xEB\x9E8&gt;99\xE2?r\xFD\xE9\xFC\xA7C\xCFd\xCF&amp;\x9E\xFE\xA2\xFEË®/~\xF8\xD5\xEB\xD7\xCEјѡ\x97ò—“¿m|\xA5\xFD\xEA\xC0\xEB\xAF\xDB\xC6\xC2\xC6\xBE\xC9x31^\xF4V\xFB\xED\xC1w\xDCw\xEF\xA3\xDFO\xE4| (\xFFh\xF9\xB1\xF5SЧ\xFB\x93\x93\x93\xFF\x98\xF3\xFCc3-\xDBgAMA\xB1\x8E|\xFBQ\x93 cHRMz%\x80\x83\xF9\xFF\x80\xE9u0\xEA`:\x98o\x92_\xC5FPLTE\xFF\xFF\xFF                        
+
+
+ +++   !!!&quot;&quot;&quot;###$$$%%%&amp;&amp;&amp;'''((()))***+++,,,---...///000111222333444555666777888999:::;;;&lt;&lt;&lt;===&gt;&gt;&gt;???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~\x80\x80\x80\x81\x81\x81\x82\x82\x82\x83\x83\x83\x84\x84\x84\x85\x85\x85\x86\x86\x86\x87\x87\x87\x88\x88\x88\x89\x89\x89\x8A\x8A\x8A\x8B\x8B\x8B\x8C\x8C\x8C\x8D\x8D\x8D\x8E\x8E\x8E\x8F\x8F\x8F\x90\x90\x90\x91\x91\x91\x92\x92\x92\x93\x93\x93\x94\x94\x94\x95\x95\x95\x96\x96\x96\x97\x97\x97\x98\x98\x98\x99\x99\x99\x9A\x9A\x9A\x9B\x9B\x9B\x9C\x9C\x9C\x9D\x9D\x9D\x9E\x9E\x9E\x9F\x9F\x9F\xA0\xA0\xA0\xA1\xA1\xA1\xA2\xA2\xA2\xA3\xA3\xA3\xA4\xA4\xA4\xA5\xA5\xA5\xA6\xA6\xA6\xA7\xA7\xA7\xA8\xA8\xA8\xA9\xA9\xA9\xAA\xAA\xAA\xAB\xAB\xAB\xAC\xAC\xAC\xAD\xAD\xAD\xAE\xAE\xAE\xAF\xAF\xAF\xB0\xB0\xB0\x
 B1\xB1\xB1\xB2\xB2\xB2\xB3\xB3\xB3\xB4\xB4\xB4\xB5\xB5\xB5\xB6\xB6\xB6\xB7\xB7\xB7\xB8\xB8\xB8\xB9\xB9\xB9\xBA\xBA\xBA\xBB\xBB\xBB\xBC\xBC\xBC\xBD\xBD\xBD\xBE\xBE\xBE\xBF\xBF\xBF\xC0\xC0\xC0\xC1\xC1\xC1\xC2\xC2\xC2\xC3\xC3\xC3\xC4\xC4\xC4\xC5\xC5\xC5\xC6\xC6\xC6\xC7\xC7\xC7\xC8\xC8\xC8\xC9\xC9\xC9\xCA\xCA\xCA\xCB\xCB\xCB\xCC\xCC\xCC\xCD\xCD\xCD\xCE\xCE\xCE\xCF\xCF\xCF\xD0\xD0\xD0\xD1\xD1\xD1\xD2\xD2\xD2\xD3\xD3\xD3\xD4\xD4\xD4\xD5\xD5\xD5\xD6\xD6\xD6\xD7\xD7\xD7\xD8\xD8\xD8\xD9\xD9\xD9\xDA\xDA\xDA\xDB\xDB\xDB\xDC\xDC\xDC\xDD\xDD\xDD\xDE\xDE\xDE\xDF\xDF\xDF\xE0\xE0\xE0\xE1\xE1\xE1\xE2\xE2\xE2\xE3\xE3\xE3\xE4\xE4\xE4\xE5\xE5\xE5\xE6\xE6\xE6\xE7\xE7\xE7\xE8\xE8\xE8\xE9\xE9\xE9\xEA\xEA\xEA\xEB\xEB\xEB\xEC\xEC\xEC\xED\xED\xED\xEE\xEE\xEE\xEF\xEF\xEF\xF0\xF0\xF0\xF1\xF1\xF1\xF2\xF2\xF2\xF3\xF3\xF3\xF4\xF4\xF4\xF5\xF5\xF5\xF6\xF6\xF6\xF7\xF7\xF7\xF8\xF8\xF8\xF9\xF9\xF9\xFA\xFA\xFA\xFB\xFB\xFB\xFC\xFC\xFC\xFD\xFD\xFD\xFE\xFE\xFE\xFF\xFF\xFF\xF9$\xB9\xDCtRNS\xFF\xE5\xB70J&quo
 t;IDATx\xDAb``D
+\x87\x97 \xB2$\xD3\xFF\xFF 'E2\xA5)IEND\xAEB`\x82
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssammenuitem_submenuindicator_disabledpng"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menuitem_submenuindicator_disabled.png (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menuitem_submenuindicator_disabled.png                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/menuitem_submenuindicator_disabled.png        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,32 @@
</span><ins>+\x89PNG
+
++IHDR  l\        pHYs  \x9A\x9C
+OiCCPPhotoshop ICC profilexÚSgTS\xE9=\xF7\xDE\xF4BK\x88\x80\x94KoR RB\x8B\x80\x91&amp;*!        J\x88!\xA1\xD9Q\xC1EEÈ \x88\x8E\x8E\x80\x8CQ, \x8A
+\xD8\xE4!\xA2\x8E\x83\xA3\x88\x8A\xCA\xFB\xE1{\xA3kÖ¼\xF7\xE6\xCD\xFE\xB5\xD7&gt;\xE7\xAC\xF3\x9D\xB3\xCF\xC0 \x96H3Q5\x80 \xA9B\xE0\x83\xC7\xC4\xC6\xE1\xE4.@\x81
+$p\xB3d!s\xFD#\xF8~&lt;&lt;+&quot;\xC0\xBEx\xD3 \xC0M\x9B\xC00\x87\xFF\xEAB\x99\\x80\x84\xC0t\x918K\x80@z\x8EB\xA6@F\x80\x9D\x98&amp;S\xA0`\xCBcb\xE3P-`'\xE6\xD3\x80\x9D\xF8\x99{[\x94!\xA0\x91 e\x88Dh;\xAC\xCFV\x8AEX0fK\xC49\xD8-0IWfH\xB0\xB7\xC0\xCE \xB2 0Q\x88\x85){`\xC8##x\x84\x99F\xF2W&lt;\xF1+\xAE\xE7*x\x99\xB2&lt;\xB9$9E\x81[-qWW.(\xCEI+6aa\x9A@.\xC2y\x992\x814\xE0\xF3\xCC\xA0\x91\xE0\x83\xF3\xFDx\xCE\xAE\xCE\xCE6\x8E\xB6_-\xEA\xBF\xFF&quot;bb\xE3\xFE\xE5Ï«p@\xE1t~\xD1\xFE,/\xB3\x80;\x80m\xFE\xA2%\xEEh^ \xA0u\xF7\x8Bf\xB2@\xB5\xA0\xE9\xDAW\xF3p\xF8~&lt;&lt;E\xA1\x90\xB9\xD9\xD9\xE5\xE4\xE4\xD8J\xC4B[a\xCAW}\xFEg\xC2_\xC0W\xFDl\xF9~&lt;\xFC\xF7\xF5\xE0\xBE\xE2$\x812]\x81G\xF8\xE0\xC2\xCC\xF4L\xA5Ï’        \x84b\xDC\xE6\x8FG\xFC\xB7 \xFF\xFC\xD3&quot;\xC4Ib\xB9X*\xE3Qq\x8ED\x9A\x8C\xF32\xA5&quot;\x89B\x92)\xC5%\xD2\xFFd\xE2\xDF,\xFB&gt;\xDF5\xB0j&gt;{\x91-\xA8]c\xF6K'Xt\xC0\xE2\xF7\xF2\xBBo\
 xC1\xD4(\x80h\x83\xE1\xCFw\xFF\xEF?\xFDG\xA0%\x80fI\x92q^D$.Tʳ?\xC7D\xA0\x81*\xB0A\xF4\xC1,\xC0\xC1\xDC\xC1 \xFC`6\x84B$\xC4\xC2BB
+d\x80r`)\xAC\x82B(\x86Í°*`/\xD4@4\xC0Qh\x86\x93p.\xC2U\xB8=p\xFAa\x9E\xC1(\xBC\x81        A\xC8a!Úˆb\x8AX#\x8E\x99\x85\xF8!\xC1H\x8B$ ÉˆQ&quot;K\x915H1R\x8AT UH\xF2=r9\x87\F\xBA\x91;\xC82\x82\xFC\x86\xBCG1\x94\x81\xB2Q=\xD4 \xB5C\xB9\xA87\x84F\xA2 \xD0dt1\x9A\x8F\xA0\x9B\xD0r\xB4=\x8C6\xA1\xE7ЫhÚ&gt;C\xC70\xC0\xE83\xC4l0.\xC6\xC3B\xB18,        \x93c˱&quot;\xAC \xAB\xC6\xB0V\xAC\xBB\x89\xF5cϱw\x81E\xC0        6wB aAHXLXN\xD8H\xA8 $4\xDA        7        \x84Q\xC2'&quot;\x93\xA8K\xB4&amp;\xBA\xF9\xC4b21\x87XH,#\xD6\x8F/{\x88C\xC47$\x89C2'\xB9\x90I\xB1\xA4T\xD2\xD2F\xD2nR#\xE9,\xA9\x9B4H#\x93\xC9\xDAdk\xB29\x94, +È…\xE4\x9D\xE4\xC3\xE43\xE4\xE4!\xF2[
+\x9Db@q\xA4\xF8S\xE2(R\xCAjJ\xE5\xE54\xE5e\x982AU\xA3\x9ARݨ\xA1T5\x8FZB\xAD\xA1\xB6R\xAFQ\x87\xA84u\x9A9̓IK\xA5\xAD\xA2\x95\xD3hh\xF7i\xAF\xE8t\xBAÝ•N\x97\xD0W\xD2\xCB\xE9G\xE8\x97\xE8\xF4w +\x86\x83Ljg(\x9Bgw\xAF\x98L\xA6Ó‹\xC7T071\xEB\x98\xE7\x99\x99oUX*\xB6*|\x91\xCA
+\x95J\x95&amp;\x95*/T\xA9\xAA\xA6\xAAÞª U\xF3U\xCBT\x8F\xA9^S}\xAEFU3S\xE3\xA9        Ô–\xABU\xAA\x9DP\xEBSSg\xA9;\xA8\x87\xAAg\xA8oT?\xA4~Y\xFD\x89Y\xC3L\xC3OC\xA4Q\xA0\xB1_\xE3\xBC\xC6  c\xB3x,!k+\xAB\x86u\x815\xC4&amp;\xB1\xCD\xD9|v*\xBB\x98\xFD\xBB\x8B=\xAA\xA9\xA19C3J3W\xB3R\xF3\x94f?\xE3\x98q\xF8\x9CtN        \xE7(\xA7\x97\xF3~\x8A\xDE\xEF)\xE2)\xA64L\xB91e\k\xAA\x96\x97\x96X\xABH\xABQ\xABG\xEB\xBD6\xAE\x{D9DD}\xA6\xBDE\xBBY\xFB\x81A\xC7J'\'Gg\x8F\xCE\x9D\xE7S\xD9Sݧ
+\xA7M=:\xF5\xAE.\xAAk\xA5\xA1\xBBDw\xBFn\xA7\xBE^\x80\x9ELo\xA7\xDEy\xBD\xE7\xFA}/\xFDT\xFDm\xFA\xA7\xF5G X\xB3 $\xDB \xCE&lt;\xC55qo&lt;/\xC7\xDB\xF1QC]\xC3@C\xA5a\x95a\x97ᄑ\xB9\xD1&lt;\xA3\xD5F\x8DF\x8Ci\xC6\\xE3$\xE3m\xC6mƣ&amp;&amp;!&amp;KM\xEAM\xEE\x9ARM\xB9\xA6)\xA6;L;L\xC7\xCD\xCC͢\xCD֙5\x9B=1\xD72\xE7\x9B\xE7\x9Bכ߷`ZxZ,\xB6\xA8\xB6\xB8eI\xB2\xE4Z\xA6Yn\x85Z9Y\xA5XUZ]\xB3F\xAD\x9D\xAD%ֻ\xAD\xBB\xA7\xA7\xB9N\x93N\xAB\x9E\xD6gð\xF1\xB6ɶ\xA9\xB7\xB0\xE5\xD8ۮ\xB6m\xB6}agbg\xB7Ů\xC3\x93}\xBA}\x8D\xFD=+\x87\xD9\xABZ~s\xB4r:V:ޚΜ\xEE?}\xC5\xF4\x96\xE9/gX\xCF\xCF\xD83\xE3\xB6\xCB)\xC4i\x9DS\x9B\xD3Ggg\xB9s\x83󈋉K\x82\xCB.\x97&gt;.\x9B\xC6\xDDȽ\xE4Jt\xF5q]\xE1z\xD2\x{15D6F3}\x9B\xC2\xED\xA8ۯ\xEE6\xEEi\xEE\x87ܟ\xCC4\x9F)\x9EY3s\xD0\xC3\xC8C\xE0Q\xE5\xD1? \x9F\x950k߬~OCO\x81g\xB5\xE7#/c/\x91W\xADװ\xB7\xA5w\xAA\xF7a\xEF&gt;\xF6&gt;r\x9F\xE3&gt;\xE3&lt;7\xDE2\xDEY_\xCC7\xC0\xB7ȷ\xCBO\xC3o\x9E_\x85\xDFC#\xFFd\xFFz\xFF\xD1\xA7\
 x80%g\x89\x81A\x81[\xFB\xF8z|!\xBF\x8E?:\xDBe\xF6\xB2\xD9\xEDA\x8C\xA0\xB9AA\x8F\x82\xAD\x82\xE5\xC1\xAD!h\xC8ì­!\xF7\xE7\x98Α\xCEi\x85P~\xE8\xD6\xD0a\xE6a\x8B\xC3~ '\x85\x87\x85W\x86?\x8Ep\x88X\xD11\x975w\xD1\xDCCs\xDFD\xFAD\x96DÞ›g1O9\xAF-J5*&gt;\xAA.j&lt;\xDA7\xBA4\xBA?\xC6.fY\xCC\xD5X\x9DXIlK9.*\xAE6nl\xBE\xDF\xFC\xED\xF3\x87\xE2\x9D\xE2 \xE3{\x98/\xC8]py\xA1\xCE\xC2\xF4\x85\xA7\xA9.,:\x96@L\x88N8\x94\xF0A*\xA8\x8C%\xF2w%\x8E
+y\xC2\xC2g&quot;/\xD16ш\xD8C\*N\xF2H*Mz\x92쑼5y$\xC53\xA5,幄'\xA9\x90\xBCL+LÝ›:\x9E\x9Av m2=:\xBD1\x83\x92\x91\x90qB\xAA!M\x93\xB6g\xEAg\xE6fvˬe\x85\xB2\xFE\xC5n\x8B\xB7/\x95\xC9k\xB3\x90\xACY-
+\xB6B\xA6\xE8TZ(\xD7*\xB2geWf\xBF͉\xCA9\x96\xAB\x9E+\xCD\xED̳\xCAÛ7\x9C\xEF\x9F\xFF\xED\xC2á’¶\xA5\x86KW-X潬j9\xB2&lt;qy\xDB
+\xE3+\x86V\xAC&lt;\xB8\x8A\xB6*m\xD5O\xAB\xEDW\x97\xAE~\xBD&amp;zMk\x81^\xC1Ê‚\xC1\xB5k\xEB U
+\xE5\x85}\xEB\xDC\xD7\xED]OX/Yßµa\xFA\x86\x9D&gt;\x89\x8A\xAE\xDB\x97\xD8(\xDCx\xE5\x87oÊ¿\x99Ü”\xB4\xA9\xABĹd\xCFf\xD2f\xE9\xE6\xDE-\x9E[\x96\xAA\x97\xE6\x97n+\xD9Ú´+\xDFV\xB4\xED\xF5\xF6E\xDB/\x97\xCD(Û»\x83\xB6C\xB9\xA3\xBF&lt;\xB8\xBCe\xA7\xC9\xCE\xCD;?T\xA4T\xF4T\xFAT6\xEE\xD2ݵa\xD7\xF8n\xD1\xEE{\xBC\xF64\xEC\xD5\xDB[\xBC\xF7\xFD&gt;ɾ\xDBUUM\xD5f\xD5e\xFBI\xFB\xB3\xF7?\xAE\x89\xAA\xE9\xF8\x96\xFBm]\xADNmq\xED\xC7\xD2\xFD#\xB6×¹\xD4\xD5\xD2=TR\x8F\xD6+\xEBG\xC7\xBE\xFE\x9D\xEFw-+6+U\x8D\x9C\xC6\xE2#pDy\xE4\xE9\xF7        \xDF\xF7+:\xDAv\x8C{\xAC\xE1\xD3vg/jB\x9A\xF2\x9AF\x9BS\x9A\xFB[b[\xBAO\xCC&gt;\xD1\xD6\xEA\xDEz\xFCG\xDB\x9C4&lt;YyJ\xF3T\xC9i\xDA\xE9\x82Ó“g\xF2ÏŒ\x9D\x95\x9D}~.\xF9\xDC`Û¢\xB6{\xE7c\xCE\xDFjo\xEF\xBAt\xE1\xD2E\xFF\x8B\xE7;\xBC;\xCE\\xF2\xB8t\xF2\xB2\xDB\xE5W\xB8W\x9A\xAF:_m\xEAt\xEA&lt;\xFE\x93\xD3OÇ»\x9C\xBB\x9A\xAE\xB9\k\xB9\xEEz\xBD\xB5{f\xF7\xE9\x9E7\xCE\xDD\xF4\xBDy\xF1\xFF\xD6Õž9=ݽ\xF3zo\xF7\xC5\xF7\xF5\xDF\xDD~r
 '\xFD\xCEË»\xD9w'î­¼O\xBC_\xF4@\xEDA\xD9C݇\xD5?[\xFE\xDC\xD8\xEF\xDCj\xC0w\xA0\xF3\xD1\xDCG\xF7\x85\x83\xCF\xFE\x91\xF5\x8FC\x8F\x99\x8Fˆ+\x86\xEB\x9E8&gt;99\xE2?r\xFD\xE9\xFC\xA7C\xCFd\xCF&amp;\x9E\xFE\xA2\xFEË®/~\xF8\xD5\xEB\xD7\xCEјѡ\x97ò—“¿m|\xA5\xFD\xEA\xC0\xEB\xAF\xDB\xC6\xC2\xC6\xBE\xC9x31^\xF4V\xFB\xED\xC1w\xDCw\xEF\xA3\xDFO\xE4| (\xFFh\xF9\xB1\xF5SЧ\xFB\x93\x93\x93\xFF\x98\xF3\xFCc3-\xDBgAMA\xB1\x8E|\xFBQ\x93 cHRMz%\x80\x83\xF9\xFF\x80\xE9u0\xEA`:\x98o\x92_\xC5FPLTE\xFF\xFF\xFF                        
+
+
+ +++   !!!&quot;&quot;&quot;###$$$%%%&amp;&amp;&amp;'''((()))***+++,,,---...///000111222333444555666777888999:::;;;&lt;&lt;&lt;===&gt;&gt;&gt;???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~\x80\x80\x80\x81\x81\x81\x82\x82\x82\x83\x83\x83\x84\x84\x84\x85\x85\x85\x86\x86\x86\x87\x87\x87\x88\x88\x88\x89\x89\x89\x8A\x8A\x8A\x8B\x8B\x8B\x8C\x8C\x8C\x8D\x8D\x8D\x8E\x8E\x8E\x8F\x8F\x8F\x90\x90\x90\x91\x91\x91\x92\x92\x92\x93\x93\x93\x94\x94\x94\x95\x95\x95\x96\x96\x96\x97\x97\x97\x98\x98\x98\x99\x99\x99\x9A\x9A\x9A\x9B\x9B\x9B\x9C\x9C\x9C\x9D\x9D\x9D\x9E\x9E\x9E\x9F\x9F\x9F\xA0\xA0\xA0\xA1\xA1\xA1\xA2\xA2\xA2\xA3\xA3\xA3\xA4\xA4\xA4\xA5\xA5\xA5\xA6\xA6\xA6\xA7\xA7\xA7\xA8\xA8\xA8\xA9\xA9\xA9\xAA\xAA\xAA\xAB\xAB\xAB\xAC\xAC\xAC\xAD\xAD\xAD\xAE\xAE\xAE\xAF\xAF\xAF\xB0\xB0\xB0\x
 B1\xB1\xB1\xB2\xB2\xB2\xB3\xB3\xB3\xB4\xB4\xB4\xB5\xB5\xB5\xB6\xB6\xB6\xB7\xB7\xB7\xB8\xB8\xB8\xB9\xB9\xB9\xBA\xBA\xBA\xBB\xBB\xBB\xBC\xBC\xBC\xBD\xBD\xBD\xBE\xBE\xBE\xBF\xBF\xBF\xC0\xC0\xC0\xC1\xC1\xC1\xC2\xC2\xC2\xC3\xC3\xC3\xC4\xC4\xC4\xC5\xC5\xC5\xC6\xC6\xC6\xC7\xC7\xC7\xC8\xC8\xC8\xC9\xC9\xC9\xCA\xCA\xCA\xCB\xCB\xCB\xCC\xCC\xCC\xCD\xCD\xCD\xCE\xCE\xCE\xCF\xCF\xCF\xD0\xD0\xD0\xD1\xD1\xD1\xD2\xD2\xD2\xD3\xD3\xD3\xD4\xD4\xD4\xD5\xD5\xD5\xD6\xD6\xD6\xD7\xD7\xD7\xD8\xD8\xD8\xD9\xD9\xD9\xDA\xDA\xDA\xDB\xDB\xDB\xDC\xDC\xDC\xDD\xDD\xDD\xDE\xDE\xDE\xDF\xDF\xDF\xE0\xE0\xE0\xE1\xE1\xE1\xE2\xE2\xE2\xE3\xE3\xE3\xE4\xE4\xE4\xE5\xE5\xE5\xE6\xE6\xE6\xE7\xE7\xE7\xE8\xE8\xE8\xE9\xE9\xE9\xEA\xEA\xEA\xEB\xEB\xEB\xEC\xEC\xEC\xED\xED\xED\xEE\xEE\xEE\xEF\xEF\xEF\xF0\xF0\xF0\xF1\xF1\xF1\xF2\xF2\xF2\xF3\xF3\xF3\xF4\xF4\xF4\xF5\xF5\xF5\xF6\xF6\xF6\xF7\xF7\xF7\xF8\xF8\xF8\xF9\xF9\xF9\xFA\xFA\xFA\xFB\xFB\xFB\xFC\xFC\xFC\xFD\xFD\xFD\xFE\xFE\xFE\xFF\xFF\xFFy\x80tRNS\xFF\xE5\xB70J&quot;IDAT
 x\xDAb``D
+\x87\x97 \xB2$\xD3\xFF\xFF 'E2\xA5)IEND\xAEB`\x82
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssampaginatorcss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/paginator.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/paginator.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/paginator.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+.yui-skin-sam .yui-pg-container{display:block;margin:6px 0;white-space:nowrap}.yui-skin-sam .yui-pg-first,.yui-skin-sam .yui-pg-previous,.yui-skin-sam .yui-pg-next,.yui-skin-sam .yui-pg-last,.yui-skin-sam .yui-pg-current,.yui-skin-sam .yui-pg-pages,.yui-skin-sam .yui-pg-page{display:inline-block;font-family:arial,helvetica,clean,sans-serif;padding:3px 6px;zoom:1}.yui-skin-sam .yui-pg-pages{padding:0}.yui-skin-sam .yui-pg-current{padding:3px 0}.yui-skin-sam a.yui-pg-first:link,.yui-skin-sam a.yui-pg-first:visited,.yui-skin-sam a.yui-pg-first:active,.yui-skin-sam a.yui-pg-first:hover,.yui-skin-sam a.yui-pg-previous:link,.yui-skin-sam a.yui-pg-previous:visited,.yui-skin-sam a.yui-pg-previous:active,.yui-skin-sam a.yui-pg-previous:hover,.yui-skin-sam a.yui-pg-next:link,.yui-skin-sam a.yui-pg-next:visited,.yui-skin-sam a.yui-pg-next:active,.yui-skin-sam a.yui-pg-next:hover,.yui-skin-sam a.yui-pg-last:link,.yui-skin-sam a.yui-pg-last:visited,.yui-skin-sam a.yui-pg-last:active,.yui
 -skin-sam a.yui-pg-last:hover,.yui-skin-sam a.yui-pg-page:link,.yui-skin-sam a.yui-pg-page:visited,.yui-skin-sam a.yui-pg-page:active,.yui-skin-sam a.yui-pg-page:hover{color:#06c;text-decoration:underline;outline:0}.yui-skin-sam span.yui-pg-first,.yui-skin-sam span.yui-pg-previous,.yui-skin-sam span.yui-pg-next,.yui-skin-sam span.yui-pg-last{color:#a6a6a6}.yui-skin-sam .yui-pg-page{background-color:#fff;border:1px solid #cbcbcb;padding:2px 6px;text-decoration:none}.yui-skin-sam .yui-pg-current-page{background-color:transparent;border:0;font-weight:bold;padding:3px 6px}.yui-skin-sam .yui-pg-page{margin-left:1px;margin-right:1px}.yui-skin-sam .yui-pg-first,.yui-skin-sam .yui-pg-previous{padding-left:0}.yui-skin-sam .yui-pg-next,.yui-skin-sam .yui-pg-last{padding-right:0}.yui-skin-sam .yui-pg-current,.yui-skin-sam .yui-pg-rpp-options{margin-left:1em;margin-right:1em}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssampicker_maskpng"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/picker_mask.png (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/picker_mask.png                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/picker_mask.png        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,102 @@
</span><ins>+\x89PNG
+
++IHDR\xB6\xB6t\xF0wgAMA\xD6\xD8\xD4OX2tEXtSoftwareAdobe ImageReadyq\xC9e&lt;/ IDATx\xDA\xEC]Û–\xE38rL\xE8\xEC?\xEF\xB3ϼ\xCC~\xA0\xE7&lt;\xB6g\x8Fg=\x97\xEE.1]\x94*\x91\x88\xBC\xA4\xAA\xAAÇ¥s\xAA%\x91 \xA5\xC1\xC8\xC8P~\xFC\xF1G\xA6\xCF\xC7\xE7\xE3/\xF6\xF8\xDB\xFA\xCF\xDF\xFF\xFE\xF7\xF5\xA9\x9C\x8D?o\xDF\xFA\xB7 \xEC[\x82\xD7\xDE6\xF4m\x9By\x9Dy\xFF^Û¼\x{1F3BFD}m\xD9k\xE3\xBD\xC5\xC8\xFE$~\xE9\xFF\xF8_&gt;\xFB\xF6\xE7\xE3\xAF\xF8\xF8\xF6\xE7\xE3ØŸ\x8F\xCF\xC7w\xA5\xB1\x99?\xE3\xC77\xF8
+\xF8\xA3h\xDB\xEB\xF7B\xED\xBC\xF7\xF0\xF5\xF6\xFF\xF3\xDA\xF8\xBC\xFDlﶉ\xCF@\xAFo\xED\xC5\xEB\xFDy\xFD[\x96\xA5l\xCF\xF5=-\xD7\xE5\xF6\xFC\xF2\xF2rk\xBB&gt;\xF9\xF2\x85\xFE\xFC\xF3O\xFA׿\xFEE\xFF\xF5\x9F\xFFE?\xFD\xFBO\xB7}?\xFC\xDB\xFB\xFDÃ?|\x9F\xC0N|\xDF\xF4w^g\xDEË‹\xB5\xE33;V\xD4\xDEÚ¯\xB6K@\xF8?u\xC0Û»m\xF5\xF53V\xB0J\xF0V`\xEF\xCB\xE3\xF5+h\xCB+̯\xD7\xEB\xF5\xE2\xF5\xF9Û·o\xF4\xF5\xEB\xD7\xDB\xF9VP\xFF\xF1\xC7\xF4\xDB\xFF\xFEF\xFF\xFC\xE7?\xE9\xE7\xFF\xF8\x99~\xFA\xE9\xA7O)\xF2\xF9\xF8\x94&quot;\x89\x89K\xE2Yo\xE3\x93&gt;\xFBÌ»\x89)E\xE3wm\x9Bj\x89\xB4]|N}\xCD\xFA;\xA3\xD7\xEAY\xB2p\xD1\xA3a\xE9\x85\xC6~e\xE0&quot;\xA4\xC7Cr\xBC\xFE\xBD2sY\xBA\xB2\xF5\xFAW\xD9\xFA\xEB\x97;c\xAF\xE4\xB7\xDF~\xBBÉ_\xFE\xFB\xFA\xF9\xE7\x9For\xE4\xC3Û¸&quot;\xD0N\x81\xF4d\xD0z\x91'&lt;\xF2\xBD)%\x92\xADv\xF2u\xB3+=o\xA0d        \xD6\xF5\xB5\xBFn\xDB\xED\xBAY\xBB\xB9\x82z\xF2\xFA\xFC
+\xE0\xA2A\xFD\xF2\x{D869}\xD7\xC7M\x86\xBC\xFB\xD7\xFF\xF9\x95~\xF9å—›YA\xFEn\xC0\xE7
+p'\\x96\xCB\xFE\x99\xCF\xB8d:
+\xD2\xECb\xA3\xCF7X\xB7X`\xAE\xE7S\xBA\xB8\xD0
+\xCC\xA0e\xFB\x8Ab\xE9\xBDM\xF0\xC6جٸ\x9E_[\xEA\xE9\xF5ov\xF5
+\xE8\xCA\xD6Ø¿\xFF\xFE\xFBM_\xFF\xFA\xEB\xAF7@\xAF\xAFW\xB0\x97\xB7\xB6\xFEq\xDFÄ‘C\xC0'|NJNh@z\xE7EA3\xB4\xF7\xBCf+xCV&lt;\x9E\x994C)1\xA4ÔÛܨ\xAF+\xD87w\xA3hP߀\xFD\xE5\xEC]\x82l\xC0^\xC1{c\xEC\xDF\xEF\x8C]\xFF\xD6\xED5\xB0|*\xB03\x9F\xE6,\xC0\xD0gf\xFF\x96c\xE01\xE7\x80Q&quot;OmcK\xFBjV\xD721\xF3\xAC\xEBk\xAE \xCC\xC0z\xEB\x80m&lt;K\x8B\xAE\xD9V[3\xF4\xE6|p\x95\xEB\xF7\xBA\xFB\xE5\xBA\xB8TPK\xB6\xBE1\xF6)\xB2\xB2\xF6\xFA\xBCn[\xF7U+\xF0i\xC0\x966\xD0\xC1\x9C
+\x80\xEC\xD9}&lt;h\x9B\xB9C\xDF% )a\xDE\x84t(\x8FC\xCC@\xAFH        \xD1\x9B\xAD\xD7\xF5\x99%\xB3 )\x81dGqX\xBB2\xF4j\xF5\xBD\xBEg\xA1\xAB1\xB0\xFFl5\xF6\xFAz\xFD\xAB\x8Cn\xFB\xD3\xEE\xFB||\xDA}϶\xCA\x96&amp;r\x92É„+\xB2\xC1F\xD8\xDE \xF62\xE7)J&gt; \xADÌ–Õ¦\x8E\xEF\xBCef\xB6\xAC:\xCD\xD8Z~h-\xBD\xB12\xA3$\x8B\x94&quot;R~TÆ–I\x97\xDB\xFBo\xF7\xF7R[\xEF#\xD0׫\xCDW\xE5\xC8\xFA\xA8\xAF׿u\xFF\xDAv\xCDN&gt; \xD8\xF5\x82\xF3\x89\x80e\xCDH\xF0\x8B\x9E\xE4A\x9A\xDA        \xFC\xBC\x80\xD2\xD3\xCC\xB4
+\x88\xAC\x8D^?\x9B\x8E\xB6êˆ~.\xDA\xF1\x90\xB2c\xD5\xC8\xE4Z~ `\xAF\xD2Cz\xD5د2\x83W\xA0\xAE\xDF\xE9\xEE/_\x9D\xBD&gt;v\xF9\xB1\xB9&amp;\xEBq\x9BT:\xD8C\xC3\xEEI2\x89\xC3)g\xA4e9\xD1\xF1PÈŽ+Wk\xFB\x81&quot;\xDB[\xBB\xAC3+\x90k&amp;\xAE\x8E\x85v:\x8A(\xBE\x93\xB7gh\xE9\xAD\xC0^]YzvuG4\xB0W\xBB羚\xBF~[\xBFH\xD9Y{\xFB\xAB\xC0\xAE\xBC\x9E\xC3\xB6\xB5\xF3Y,\xAD\xA5AfF\x85;|W/;ÇŽd\xA0\xC0\xB1\x83\xBD\xEEX\xC6A\xA6b\xD9\xCBv\x8E0o\xF3\x99\xAFp\xB6\x82\xC4+\xB4hÏ‹\xF4z\xFEmÇ­\xCD-\xF0\xDB\xF5\xF5\xB0;\xC8_\xEE\xC0^\xBF\xDFƨ\xEB\xFE\xF5x^\x81\xB9&gt;oAc\xF3\xBCZy\xAF\x80]Y{m\xC7K\x97\xD7g~+y\xCB&lt;\xF2\x9F\xFCy{\xBFn\xFF\xF6\xED~&lt;\xC2\xCF0c!h\xC5^3\xF2\x80&quot;I.\x9C\x91\xD2m\xC8\xEAd[^\x94\xD5R\xD3 F\xE7-\x8A\x89\xCBC-t~s1\xE4#\xAD\xE5\x859\xD2\xCB\xFB\xB3ff!=\xF4\xF6][\xDF\xE4\xC7\xD23\xAD`.\x95U\xB5+RW\xE8\xEB\xC6\x91}\xFB\xEBo/+\xDB/\xCB\xD5\xC4\xC0\x8C\x99\x92\x8A\xE1F@=\xE2MO\x87\xF2#\x94\x9Aݻӳn\xC7\xEC\xE9h\x
 A9Û­\x84\x89jk\x82W\xE9ä½­r E&lt;`7\xEF\x921\x8B0\xAE\xEC+\xFD\xEA
+l        \xEA\xDB\xF3]3\x97
+\xE8\xFA\xB7\xB2re\xFE\xF5\xA1\xF5y+X\xCF\xF6,\xA8Gm\x8FA\xA0\xC7\xC9        '\xC0\xED.\xB2\xDB,\x98;+\xE2\xC0\xBA\x9D
+M\x8FZy\xD2E\xBB2\xA8\x85I\xB0%\xD7\x91\xA2\xFDj        \xEC\xFAz\x93&quot;\xB7v\xB0_Z[\xFFUpk`Ëš$\x9E.E&amp;\xB2~Y. P\xBD\x84K+E\xB8\xEBQZ\xDBrh\xA3%\x87\xCE\xFA!\x87\x83AV\xB0\xA8\xD7l\xB8\xDA\xC2cY\xB7!\xD9Y\x82Ù‘es7\xA4\xB5W\xB5K\xCAlÜ¥rCVP\x8B\xF7E\xDB5+YÔ\x9F\x99\xC7{VW˨\xFFDP7\xEC\x9F\xAAuvu\xBB[\xDEi\x81\xDD\xD1\xCFÈ„X\xD8rA\x94\x9E.\xC8å\xC0\x93\xE4
+\xBCX[_\xFB,\xE3hln1v-tb\x99F\x97@^\xCF+\xF5\xB3dv+\xEC]\x86,|X\x8A\x94\x94\x876\xEALz&lt;h\xF8=9\x96-\x80y#Vf\x94\xD1緀\xAE\xCE\xEF\x82Xie\x9D\x841\xACR\xE2KW\xF0J\x80\x86f\xD1z֫\xAB!\xB4\xB4,rҌ]^\xCDBsK7\xDBj\xDA}=\xB6\xBA&quot;$
+\xA8Z\xB6&gt;\xA8\xB1Û\x80:\xC3\xD2\xCA6\xCF\xE3\xCAe\xEFi\xBD \xB59\xD2Éž\x9B\xA1\xF6\xE9
+J\x9C\xA44\xB5'E\x8C Q\xB2t\xC7\xCE\xD8\xEB\xAFY\xC1[e\xCA2
+0?\xD8[H\x91\xDC/\xFB{\xEE.y#\x8F\xAD\x99\xC9\xF4\xC0\x9D\xF1\xB1GÆŒ\xC7]$a9\xECJ\x8E&gt;\xF6*\xA6&amp;&amp;&lt;\x9A\x84\x8D$\x8A\xDEG\x86\xBC(F\xF6f\xF5~ѦzÒ‹\x96\x9B\xFF\\xBD\xED\xFD\xB8M?\xB9O\x82v=n\xBB\xBE7\x93Z\x8F\x8DG\xCDK\xE3c_Dm\xF5\xEEYW=]\x81\xB9\xF9\xD2\xD4\xEB\xEBE  \xB8\xAC \xBE\x8F×»\x8F]߯,_\xCBX\xD7×›\xCD\xC7\xF5\xEF\xE5\xDB\xCB\xFD\xF9\xDEn\xF7\xB1\xB7\xCF\xE5\xFAyl\x88\xEC\xB35v\xDC        xNk'%\x89\xB8\x99\xDFO\x98\xA8FÃ&amp;\xD0\xD1Ê&quot;\x96\xCC`\xC3Ò“\x89\x94\x80ͺvZ9\xAE\xD9\xEA\xB0w)R\xD9W\xEAo!A*c\xB3\xF4\xB1\xA5\xFC\x90#cn\xCF×e\x8Bf\xE2+\xB4E\xB2\xBB %c\xCBk\xE3Y}g\xBB )0~K\x9A \xC0\xC9\xB73\x80\xFD\x96D\xB1\xAC\xBC\xCE\xD5,\xBB\x8C\x81R\xC2\xF1\xA3\xD1vSrh-\xDD\xD8x\xCB\xDEX\xE8\xE3\xCEÞ“Dy\xD6\xCD&gt;+\xF2\x9A\x97[\x83~\x93!MZ\xB5\xB5\x89#\x95\x85\xF5\\xF08h\x86d\x82\xD07\xB5\xE5[[        \x978\x96\xB3\xC1\xAAV\x82\xD3p@
+\xB0\xF7t\xB0\xC8\xDAÆ“Uw #\xAD=\xC9\xD2|\xC7)\x97Ͷ\x93z\x9Be[\xA9\x9F+;+\xC0\xEF\xF6\xA0\xDE&amp;\xB7H=\xAD\x83I=D\xCC{/\x81\xAD\xEA[`/|X_G\xD5v\x96\xEE\xB6\\x91\x84\xF4\xB046J\x8A\xA0\xDEv}\xFE\xBBNN\x88\xB6^\\xEE_40UpX\x8F\xBDT\xED-X]\xEAgKW\x97\xD6\xEDBF\x94ʨ\xB5PD\xD8y\xBB\xC6\xDE\xEA=\x96+Ø—\xAAm\xAB\xB6\xAE\xBAz\xAF\xB9\xDE\xF5瀞w\x8D}\xEB\xA5Ö‡\x9D\xBD\xFF\xAD\x9AzuMd+I}]\xEF,5a\xB3\xB95\xF3;+C\xBC\x9C\xDFb\xE9HK\xA3\xA9\x90{\xB6E\xCC\xB0\xB5\xB9+1/p&gt;P\x9D\xD4Ó–\xC6F\x8C-Cn\xDA        É¡\x921Ejp)E\xD36L]A\xAA$\xC8\xC3\xB9v\x8C\xDE\xC8\x8B\x91\xBF~\xF9\xCA\xD2Γ\xAE\xA8` qu\xB0\xA3}\xD9ç€,i\x82FO?\xEB\x83$\x88\xE7G\xC3c\x83\x8FH\xB8+Xx\xCCÕ½h@/\xD2\xDE\xFBv\xC3\xDAc\xE4cäµ£\xBCs\xEB$+\x80\xAF\x8D\xEE\xAD\x8C\xAC\xC1+@\\xB4\x9D\xA7-=\xAD\xADC\xBB\xEF \xB0K\x94\xBBq\xB2\x83\xA9,\x83\xA3\xF3x\xD5t!\xF8\x86\x96@o\xE4\x8Efr(\xF2$\xC0u5^\xF0)_\x9A\xB7\xB9&gt;\x8F\xDAH\xC0\xB0N\x9Bo\xF5\xD5ݶ
+&lt;\xCD\xC2&quot;\xB8+\xCA\xF9\xE8\x82ʺ\x81\xB7\xEE\xAB\xC0\x97\xA0\x95\x8C\xB2\xF7\xDB\xF0\xB13\xFA\xDA\xB5\x97\xAD\xF4\x98Zk\xEDHcs\x92\x8D\xEBvT\xA8\x8F&amp;\xBAJ\x81[\xA3W\xCCmF\xC19zZ\xFAØ‹\x98\xFE\xA0}\x97Õ—\x96Z\xFC\xB2\xBD\xEF\xBC뺽n\xDB\xE4\xC1\xB2Vn\xBBi\xEC\xBA]zÖ›\x83!\xB7\xD5ΰs\xA9\xF5Ø›f\xA6\xFA\\xFDh\xA1\xB9\xEB\xBEÝ«\xBEnZ}뜻W^Ý–\xED\x8Ck\xEC\xA32dp{v$7\xD2\xCDY)R\x8C\xE2$\xF6t\xB6\xA3\xA7\xF56\xB3\x8Df`%1XYw\xACG\xB4\xC8{\x9B\x85u\xBA\x9C\x85\xA5\xD71sm#Jd\xF3ÉŒ\xA3\xB0\xE5\x{194E90}\xC5`\xE4\xE6RZl\x9D\xA3Hk\xEF\xFE}qv1\xA3\xB3\xDD\xCCcb\!\x8F\xC8 \x8Be\x9Dj8ȾX\xAD\xC0NgUP\x87\x8A\xFC\x9B\xBA+\x83\xC1 \xF0\x9FMg#p?4\xA37.\xC8\xE6h,uF&amp;\xE1p,\xA2\x83\\x84..l\x8B`\xEF\xDD\xA9\xAE\x88        \xB3H\xA6ÞžKu;6'd\xA9J\xB0\xB9|\xDEY\xFAUZ,u\xD8X\xDD/Y\xFAv\x8E\x97k\xC3Ø›\x9B&quot;X\xFB\xDA16\xB7\xEA9\x8Cm\xD4m\xF0\xC0vk2\x98\x8C\xBBÑܨ\xD7\xE0 \xF8\xF3{\xE8\xBDQ\xA4\xD4y\xD1R\xABÚºJ+]\xB0Ô¹$Rw#o\xDArEd6R\xEAcU\xCAZ$K+\xFF\xBAgs\xA5
 \xD3u\x9D\xC9l\xB2\xB0\x8B\xCE(\xC2g\xF6\xB0\xF7\x80\xCD!`ON\xAAv /Ì‚0\xB0&lt;\xBA\xA0W\xC1&quot;)\xEB\xFD&amp;@\xA3`|i;\x80
+\x91\xFC`\x9D\x94AYHH
+\xE0\xC9s46\x9F\xE84f\xE6Q\x81\xBB\xA8\xE0V\xE7\xE9)&quot;{\xCF\xC6\x96&quot;\xA3\xAC \xC1j\xB0\xB7\xD6\xCEÅ#Zv\x92Vr\xBC\xE7 xdU\xB4\x84\x92,\xFA\xFD\x9Ehid7\xEF/\xB5\x80I\xBD/R~È‚\xA8*3D`\xB8\x88,\xA2 0;\xD9!\xB6\xB5\xC1\xE2u\xAFÞ«\xC7\xEFD\x8F\xAB\xFCh\xA6/\xBB\xEER\x83\xA5LY\xD9Z\x8B\xA2:\xB0\x91#2xdn\x932\xD3        \x9AA\xC6vm\xBFL\xDBD\x87@\xCC\xED9%\xAE\xEC0\x82BV\x86\xF9\xDE\xBBRd\xB7\xE9t\xA0(.j\xF7~\xF7\xAB\xDBV\xFD\xEF\x8F\xA2}Sk-\x9E2⥕&amp;BVX\x81bW\xC2\xDAYw\xDC\xFA\xD0\xD2f\xF4\x922Q= '\xB5\x{148D08}\xAA\xF2,\x97\x83\x8Dk+8D2&quot;\xCB\xD8C\xEBy:H\xB1\xB5N\xA9\x93c\x{DB69}\xEEE\x8B]\x95^M\xBDW\xBBN38u\xF9i&lt;jv\xAE\xFB+SÓ­\xED\x83\xCDÛ’H\xB5_tJ]\xECga\xFB݃ɯ\xDF\xCA\xFD\x92\xADe\x80\xA8\x83E\xC0\xD2C\x8C\xEDf 2s\xA4\x8D3\xE5\xA6s{\x99B\x9A`h02\xB0\xF5;\xC3vu\xB6Sa\xEB!m\xDE\x92\x88\xB1U&amp;QÛ‚R\xDB2\x98\xE9\xA9y\xBD\xEB\xEEk\x88\x92*\xD5J\xF0\xEC\\xB6Z\x9D\xA2?y\xBC~\xD4af\xC3        \x9A\x99\xC01QÏ‘\x99\xEE\xC0\xD5\xDDJs\x
 90h\xD1Z\x9A\x8D\xE4\x8B5\x83:\x98\xDAVI\xD6`\x94\xEC\xBC옉\x99j\xE3        \xAD\xCDh=\xC1\xBC;++\xC6^$\x9B#\xBD\xBD1l\xC3\xCE*A\xB3\xAC\xB5\xD2\xD4L\xAD4\x92\xB9\xFBÊšYP\xD5\xE8g\xEF\xAF!\x9B\xB6\xF0I3uNc?A_O=
+-\xFDl+ \xAF#\xA8\xFA莡A9j\xC7\xEAÛŽ\xF5?Z\xEB5 \x8Bk-n\xD4S30\xA0\x9DF\x90\xDDg\xB1\xEB΢\xCBC\xC7k\xA6\xAEm \xAD\x9F\xB5o\xCE/\xDA\xEB5X\x8C\xB0\x96\x88˦;\xEBE#=&lt;b\xD7EYC\xE4z P\xA3R\xD2\xACHZÈŽ\xA0\x81\xA8\x9C\xD2C9\x92u\xAD\xE5.tI*\xDD}\x91S\x90        +\xBE3\xB6J\xA9_@&quot;F2\xF9
+\xB8\x9B\xE6]\xA9\xBBk
+1\xB7\x9C[Djl\x99\x84\xEA\x9D\xE5\xEFZ\x9D5\xB3\xD7\xDF]\xC80Ҍ];\x92L\xC8n\xC8q\xC6ζ
+\x9A\xBC$\x89\xC7\xDC#ll\x81\x9Dpz1\xC4Ø¢\xFD\x83\xC5+\xE8`i\xE7N_\xEB'U\xC0Ô±`é½%#W\x9F\xADV\xA0\xEE \xA1\xC6\xD6\xDFo\xBF#,\xB6\x86VUz\xE5h\xEE\xE4\xB0\xC6\xCE\x83\x99\xDBF\xE4X;P\x9A\xC9Oj=JF\xFB\xD3\xDB08äŠS\xDC\xD4M\xD3+\xFDR\xAD\x87\x9D\xBB\xF9\xA9-\x966\xFC\xEA\xC7\xF6k\xB7\xBDqE4s \xA6n4\xB6vB\xE4\xFE\xE8O\xB1\xB6\xEC&lt; \x90\x86\xB1\x9F\xA2\xB1g\xDB+\xFCw,=\xA7\xDB\xECn0\xB5xL\xD5Q\xA0B\x8C;\x83u\x9C\xA2%]\xAD\xB1\x9B\xC0\xB3aT\xE38\xA1\x83!\xF3KUYC\xF8\xBAsE\xFE\xF3&gt;\xFCK\xE9eR\xEC\xDF1r\xF5\xC0=\xE7C9T\xCD\xF5D\x99\xC7\xC3e\xAB#vÞ€\x96δ7A\x8Dl9\xC4\xC2JO+,\xD1\xC6J\xB6\xB0X)z\xD4\xFAb &amp;O\x84\xAC8\xC4ະ\xA9\xBE\x96\xAC\x9Ea\xE9F\x87_M^jQ\xB2\xB3\xCE&lt;\xD66BGwZe \x97:tK\xB5\xDD\xF7!Ö®\xFE\xBAN\xB7\xA8\xB8a\xE2\xD3;;O\xDE;{m\xB3\xAB\xC6#Ac-u\xE1\x8E\xADU\xC8\xC4A\xF0\xD8\xA3\xBC\xE8\xAEC\xA8i\xC3\xD8\xD2\xDDJ\xDFJߺsI,\x96\xF6\x98Ùš\xC0A+\xDCe45\x8B\xABN\xDCt\xEA\xDA\xD5\xE2[׺\xCE+r\xBF.O\xD2\xD8aJK{I\x
 C0\xC2\xA4Iƾ\xB3|\xE9\xB2q2\x92,\x90\x8Ds\x92N\xB2\xE8rT\xE5\x94\\xE4$9\x82q1!΢\xB3\x88u[\x96\xA5\xEB\xF1BC\xEB\xC1\x8B\xA8Ù™Z╵&quot;Ò¯\xAE\x9Dg\x9B=\xAA\x91LZzi\xF7c\xEBXT\xA2Ø™\xF8\x91m\xD4n\xC74\xF6@\x90\x98\x9D.aÄ«6\xB3\x89\xDA        Î±\x8F         \x80\xEC\xEAgjg;-\xA8\x88\x8B\xCA\xC0a#\xCB\xD8m\xC7ꊼ\x90\xB1K7\xC7#V\x96m\x81 \xD3 5\xD3\xFE\xB4&gt;?\xF0\xAD\x9B\xE3\xB6\xF4\xC0\xBAk?[c\xA7LskE\xAC u^m\xCB`\xE5S\xC4\xDEPz(]]\xEDS\xA3/\x86om\xAD,@Þº\x8A\xB2\xBA&quot;\x80\xA5Q\xB6QxÕ’\x95;\xFF:\xA1\xB1/Õ¯\xAE\x8E\x86\xAC\xF9\x90\x8E\x89de]\x82jA4ci\xEC#\xC0\x8E\xD8:o\xBD\xBBÄ v\xC5np/t\x89XI\xA8%\xDB2\xC1&quot;\x81U\xBB\x90i@\xDBwm\x8A\x9D\x99Rî­¿+pu\x9B\xA1\xB4\xFBT\xA2\xE6\x91n\xD9\xDB\xEC@v\x91\x84ÙŸ\xA5\xD5'\xB7;r\x84Ô¨\x99\xF3\xEC\xBEI\xB6N\xA7H\x93\x81\xA2=v\x91\xF1vó\xB6\\xB7O-E`\xA3Uo\xA5\xCA\xD9rK\xEA\x9DXk\x8F\xD7&quot;\xD1&quot;Ú¡4&lt;\x94(\xDE6\xCF\xD2C\xBD\xD6Ï©DË\xF5\xE8c\xA3\xD9I9\xD0\xD70\x8C\xD8\xD7\xC9 v
 \xED\xD7\x8B\xFC,\xEE}g\xE4EYæ\xFEÙ¸8!c[r2\xA5\xD8Zo\x97\xA5f\xEC}\xF5%3$c[,\xADG\xA4o\xB3\xA3\xEA\x9F.\x92m% W6w\xB4w \xC8c5k\xEB}\xB5\xBAPHy\xDEc\xCBt;\xDDV\xB3z\x80p\xA8{\x84}YC\xEF\xB5\6\xE3\x8EV?\xA3@\xD1c\xE5\xCE!AN\x86\xD2Æ\xCB\xE1\xF8\xD5 \xAA\xFB\xC8\xA4+\x81\xAEÝEe\xD1\xA2e\xF3\x89Q\xB8\xCFW\xAD\xC1\x8C\x9C)K\xAA&quot;jI.R\x88\xEC\xA2vPÖ»\xC4d\xE5\xF1\xED\x8A\xC8`ZI\xB2F\xC9 j\xEFH\x8AG\xA6P\xB0;\xD3HF\x91\x8C\xC1\xBB\xD6bE\x8C\+\xDD\xC6\xE8 \xE4i\x99aÈŽ\xA6\xFEC]`\x98UÔ’fß¾%\x8D\x80\xF3 +\xF3`K\x96\xA8N\xFB\xB0\xEF\xC49\xC1dN\x8D`d        \xD5V \x87\xA4\xAD\x99A3(\xDAENLaÊœ\xECE\x88L\x96\xA5f\x90\x8D$#\x90dk\xEE]D\xC9\xC4\xE2Fำ\x{1FAFEC}\x8Cy\x9FzA\xBB)\xBD4QA&quot;bi(ZRD\x8B\xFB8Ç—k#\x94c&quot;\xE5        ë ±\x9ES\x8E\x8C\x91\xD7W\x94\x9A\xB1sw\x8C}\xD8\xDEbC\xAD6gs\xB2I`u~\xAB\xB6Ú\xE2\xCCu&lt;\xFBZ 7\xCAS\x87\x8B,&lt;Ow+\x87\xE3\xF8ʘ&quot;gwB\xF2C\xB8\xDDv`\xEDu\xF2D ؽ\x{DEC3}\xB74r\xC2\xD2\xD8|Z7K\xB0\xF0
 _\xC4z\xF17\xD0
+6G\xC9V \xEA\x81M\xCC\xDA(\x9C\xB2\xFAt;\xE0rX\xA3e,\xD9+\xD25\xE5\x87fw}'Ð¥\xAA\xE8=\x90&quot;\xAE \xA2e\x92'\xF2\xAE!\xE5\x83:\x8E\x80\x83\xD29*Z\x86 rW\xA5\xD8wÍž\x8F\xC9~\xDA\xEFÕ¥\xF9\xE56j\x9ArK\xE2f\x931\xA6\xB9F\x8Cm\x9F\xD7[]\x8B\x9Dz\x90\f\x8FO\x84\xF5!\xB2\xD5z \x866I\xC5\xC2&gt;\x8B\xAFl\x8C\xDB\xEDc\xE41t\xF7^\xBB&quot;Z\x96H&amp;\xD7EPhÚ…\xFDyy\xA4\xBC\xB5\xB4@\xCC[_ky\xF1h{\xEAE\xD8\xE6Q)\x81W\x9D\x93&quot;z\xE2\xF7h\xE8\xD6à°\x90Q\xB9ifkp\xB4\xE6\xE4\x87,\x9EcI\xF6\x921\xC8\xE1\x90\xCE\xC86}Y/E\xDA\xEA&gt;Å”\xFCP\x96!9)m\xFD\xEB\xC2rDM\xA7\xA1\xF56\xA4\xAF\xFBc\xE1\!Ñœ!\xAC-?\xD8\x93,I\xB6NKÌš\xF1Ѽ\xD4\xD0\xC10\x82K\xCB\xF9\xB0&lt;p+\xA0d\xB0&gt; \xB5\xFA\xD6}\x97L\xA8&amp;\x84A&amp;\x92-\xF7\xC9\xE4\x8E\xE8Q:\x96\x8C\xA9\xE5\xA7JV\xA0\xCF,\x96#J+\xDA\xFF\xB7pC&quot;        |\xFA\xBC&quot;'\x8C\x8E\x89櫆\xC03R\xE7\xD13\x81Zi\xD8^(\x81\xD1\xE8 \xA4GW\xA2        ÂŒ&lt;\x91\xB6\x99\x{1B72D1}h!U\xC1G\xC8\xFD\xD0̬dI\xC3\xCC2\xD
 1\xD29% \xB3\xAE\xF6\xD3RC&gt;#F\x97\xC9Ù®eg\xEA\xBBJ+U0\xC5@\x8EÌ»&quot;\x89U\x87\xA6F`\xCE\xCE        bTzi\xDDM\xA3\xF2C\x9DÊŠ\xD0\xD7Kw&lt;1v\x96\xD9BR\x80\xEE
+\x97D\x91S\xA7Õ\xAE&amp;\xA5\x99\xA1\x96F\xF2\xA3\xD3Ó›\xD6E\xD2BW\xD7wx '5\xB7M\xBCܦP[*&amp;\xB9\xF1t`\x8F\x8Cz\xD12\xC5sD\xB2\x99D\xF6\x80o1\xBDQ\xBDg1\xB2\x96\xE4Ñ»\xDB4;Ck\xCF\xD8f\xD9`t\xE4\xA8\xF0\xA9󚯽hY{\x96\xEEF \x97\xE0\x96Û€i\xC0 ,\xBD&lt;\xB0g4v:\x8B\xE8\xBC\xCFl\xF6\x9C%[\xC2lb6㈒BJ\xBE\xC0\xE2(\xB3\xDD\xD2u,2\xAC&gt;\xB7\xEEZg\xE7@\xB1\x93}\xA7×\x8B\xB3\xA1Þ³\xE9\xA2=\xFEa}\xCC\xFDÒ‚\x87&quot;xc{i\xF6\x96\xF6\\x90ЫN\xB0\xB1\xDB\xC8k\x92 \x8FmLdd#Q\xE6\xD1j\x87\xEA\xAA]Æ–\x85M\xC0!$A\xB6\x816\xA8f:\xA3\xB1\xE9&gt;3\x92&amp;\xA4\xAA+A\xB5\xD8Ï‘&quot;\xC6\xF4 f\x85_0&quot;\xAC\xFB\xC8fybjiK\xA2Óšul\xA7G\x97\x8B\xAAC\xAF\xCAO\xEB\xEA\xC5IÉ‹&quot;jB\xA0\x8FC\x90K\x80\x8A        s\x9A\xE0\xC9 \x9D\xA5v\xF9\xA1m&lt;urD\x96x\x9F\xAA\xB1G\x8B\x9D\x90\xF6\x8E\x86}\x85ωj&gt;2&amp;\xAF!c|#
+!\x83EAM\xFD\x8A\xC5\xCE*P$\xA3\xD6\xD9chs?\xB0\xE1\x8APu&gt;\xE4q\x96\xE3ѱ\xBBr\xC4\xD0\xF4ݘE\xEE\xC71*mN\xF0\xB8\xA3\x9B\xECub&quot;\xDDlJ
+GND\xB2c\xE6\xB9\xF3\xAB5\xEBMMjL&quot;\xB9ÑŒ\xD61:\xA1\xCFE\x81\xA8Ǩ5\xB51\xF6\x92\x8CT:O\xBCX\xA9\xEA\xCCoi\xDCm\xBB:\x8DmM\xC9[\xE3\xAF\xF0\xB4ê¾\x89$\xBD\x82\xA5\x88\xA5\xC5\xE8\x98\xDB+]\xD9ge        \xF4\xF8n4\x8D#Qxݤ\x9AQ\xB9'\xCAN꤅\x96H\x9E6v]\x87\xB1\xF7c${\xD7ad\xA0J\xAES\xE4\xE7v\xEEX\xDCsEt6x\xDA\xC8+\xB1\x8A\x9D\xA6\xA5Hz\xD5t\xA9j\xC0Ò†}8\xAA\xA1\xA3iP\x87 \xABS4\xA0o\xFDg\xB7| (\x80\xB6\xA0%O\x8C9\xF2,\xAF{\xF7\xA5믓\x98r
+K\x92È™\xADP*\xC9\xAD\xB9\xC1\x9D\x92AB\xC60h3\xAE\xB1\xD9;\x95l        JQ\xDD\xFAÆ‹\x8Cz媚}        \x80\x96\x8D\xE9\x81%\x98\xD1(wr\xC5`\x83su\xC0u@\xBE\xD5M\xF3\xB2\xDDJ$\xB3C\x96\xD6Ao\xB3\xF4\xB3k1j\xAF/\xAA6\x88UP\xD82sk\x85z\xB5\xD7V9\xA7\xB1Ê’0{h\xB0\xB7uL4\xC1\xA4\xB7\xEA@78\xC1\x9ArA\xCC9\x82\xBClÒGxÖ°\x9D\xBA\x90È«5\xB4\x9A1\x8A \x9F\x9A\x{2667EB9}\xFF&lt;\x8D\x8FÚ¶\xB1\x83\xA1\x89\xAD;\xF6\xAE{}-\xA18Z\x92zZ\xAD\xE7V\x83\xF5Ñ–+\xE2\xC8k\xB1#\xC4\xCC\xDE\xF0#80XP\x83U \xB9\x82\xF6\xC8 \xCA [\xBCaQ\x86?+\xB5w\xA0\xB1M\xC6Öº\xBA\xB5)+\xC0刕\x95!Ok\xAB\x8A\xBC:J\xBA&quot;\xA0&lt;uo\x8B\x9C\x8B\xB1ÃG\xA5HTË‘\xB1\xF2\xC8^x\xD4\xBB\xA8e\x82\xB4\xDAȘ\x9B\xC1\x82\x98\xACR\xA5Y,\xB0\x9B\xE3\xB8_#\xDDw\xA3\x85R\x84TÂ¥\xFF[X[\x8B\xF0\xB5%Ot*2IJ        \xBCisQ$\x95[p%Gy \xDC=\xD8        V&amp;gA$U\x8A\xCC\xF6X@\xE6\xFC\xEAm&amp;\x94v\xAF\x95\x9D\xD9\xB65\x84,3:\xF4\xAD%\xE3j\xE0ﯗf*\xE3%\xF1\xBA2j\x8A\xA9u\xA0\xA84\xE6س\xC7m\xDB\xB9%\x88\x999\xAB\x
 B1\xBB/L\xC6$ d\x86\x86Y\x93H\xA2\x89\xDA-Í'\xA4l\xA77#$U4pY\xADG\xEE.\xB0u1\xD3ݱ\B`#p\x86e5\x9DB'Kd\x9C'x&gt;\xE9txMR2\xA8\xD12\xA4\xAE;
+m6/\xBB\x9F*Akd&amp;\xA3\xE0\xF1\xD1~2\xA5:&amp;{s\xBC\xFCF\xE8\xAC\xCC\xF0\x8E\xB7\xECA\xC4\xE8h,\xA4i\xD9\xC30\xB8W\xDE\xFA\xB4\2&amp;u\xEF\xEED*\xE9S\xB6\xA0\x8CјC+6\x91EA#
+v\xB3\xC1]s.'\xF6{\xB4[\xE8\xE8\xE3\x8CZ\x91\xF4\x94 \xC0\x9Bv\xEC\x80&amp;S{2\L\xC8\xDE2\xCB\xC5`\xADs\xA3\x84\xD5dqk\x9B\xB3\xEF\xA2F\xCDt\x8C\xEC\xBD'&amp;\x8B\xA5=\xAE\xA5\x8B;^\xD8\xD9bdi*=NÈ“Fr\xC4
+\x96|&gt;\+\x92I\xBA\xB8@\xB6,&gt;C\x92\x98\xDBvb\xE0x\xB2\xA6\xC0t\x80\xA9\xD3\xD0\xC3 \xB6\xE7|\xD8\xEF\x97\xE6=\xA9        t\xF5[\xA3A\xB7&amp;\xD8E{E\x83\xBEq7:\xE0.\xE8P\xA6\xB9B\xE4ω\xCD\xCFd\xECL&amp;\x91+\x8B/4\x93\xF4\xEE\xD6 \x98\xB5%#xt]\x92\xCC\xFB p\x93\xC0\xF6\xCF\xC11p\xA3\xB75\x83+_4h\x81\xD6\xEE:\x89j{\xB7T\xBES\x9A\xC5:\xDBM\x9B?\xD8Y\xBA\xDA\xD4\xE6\xC1\xEC\xA9\xA0-\x8FÛ“%H\x8A4\xC7X5#@O`kBv\x9Fpx\xD8;+\xF0q-J3\xEEK\x83U2.\xB2\x94Ú·\xD6ReiEy\xBB\xCFN\xAB\x92+S?m\x94zzDzz\xF2{\xDE&gt;2R\xEC&amp;\xA0\xA9\x9F\xAA \x8D\xE6@\x8B5\x91rE\x88\xFA        t\xDC\xB0t\x9F\xFE\x84\xAA\xF3\x9CQ&amp;\xAC\x86\x981H\xE1ww,\xF5;\xB3\xB9\xBE\xBA\xA2PK4X\xEA\xEF\xB8n\xBCzU{\xEC\xEC\xC0Ó«\xFE{z\xF0\x98I\x9B{\x95}\xA2\xD71\xF5\xCB@\xBB:\xE8\xE7\x8C\xC6F\x80`\x8B\xE53\xB2$f&lt;:\xCF\xE2K\xDBÉ„\xFC $9|\x89B\x84\x921\x8E~f\xE4\xD2TfÖ•y\x8D\x9CY+\xCE\xD5V\xDE\xE2\xE8\xEF@\x8A\x94Ó¤H\xB4R+S\xD8\xF5\xBC\xC9\xD1\xD8\xBA\xA3a\xC8a_\x8F\xE1\xD0&quot;3
 R\x84\xBD\xB4&lt;\xC8\xFA\x85RdM\x8B \xC0\xA2\x94:I\x81\xBCo/\x90lî –\xB1\xDCZ\x8E\xD8\xE5\xE2\x9D\xA06?\xD8\xC00\xED\x9D\xF1\xBC-\xAF\x99\xF0\xB2ÑGm16\xB2\xFB,GD\xDF)@\xFB!}=\*/\xFE\xA2\xD2Û–\xFB\xB1\xA7\xE7\xB5\xF7\xAD\x9D5\xE4\x80X\xC1\xA3d\xF0Lu]\xDDK\xB2\xB5\xEC\xEA\xFA:Ó™n+{V\xF0\x98\x9CxrHWk\x9DO:bl\x93\xA5\xA3\xC2'4\xFA\xC5sR\xB2\x8B\xE9R\xB4\xC1\xA1Y#b\x8F\xC0!!϶S\xAC\xDCyÑ–\xD1&gt;6r:lr\xCB\xC8:\xC0惮\xE7\xB2H#%\xAE\x83F\xF3u\xC0ê”f i\x81b\x91Ĉ\\x90C\x8BrN÷&amp;\xA5W\xD9\xC8Jvz[\x83\x81\x9D_\xD3Ù‚G\x8F3\x99\xA3bD᪳/+E `\xA3\x8C\x9D\xD2\xCB\xD2 /F\xD8\xD7\xD5t\x90\xBD@iJ\x8AXM \xCC\xF8\x91\x93b$v\xD8J\xA3g#l\xA7\x8F\xAE\x9DK\x89\xF6k0\xC3\xED\x9E\x82\x8A\xC0P\xBA]ß°\xF8\xD2T+ZC\xF6R\xFB\xE4cΓ\xEE\xB7\xEC\xA4\xC8\xC1        )S\xFB\xB2L\x9E`\xEE\xA0\x83\xF2c\x98\xB1\xAD\xD2\xFC\x9A\x95$\x8A\xA5ɲ+\xBD \xD9\xD6ba\xA4\xBD\xEB6%KH\xEBh )\xB2,hiw\xB5\xDD,k\xBF-\xB0\xB5$\x874\xB6S \xCA\xD4!,逘\x80?\xA9V\xF9!\xD9a\xD
 5n\xB8\xE7R#0\x82J\xC7&amp;I\xDA\xF7\xC8\xC4E\x8CP=\xF0\xF2@\xEA\xFC݀ݤ\xCA#W$
+.=\x80O=\xC3Ø\x8D\xC16\xB2\x92)\x96n\x8E\x98[\x89\xCA:%V \xA8,&gt;\xE2xE\xA8\xBD\xB5\x85gZg]\x8D\xAD2\x8D\xDBa\xAF\xAF\xAF c\x9B\xBF\xB03i\xF4!Û« t\xC0\xAA/\xA6\\xB2\xD7\x80Ì«\xECXv&amp;b{\xE9\x8F {`w=h\xCC \xC6Y\x9A\x80F \xB6t5\x92-&quot;\xB5\xDC\xD4W;u\xD6\xEF \xEC\xCC\xE0#x\xCCL\xB9@FI+\xAC\x8BF@uΛ\xB8\x8C\x87ع\xA9A6&amp;\xC0\x9C\xAA\xB4\x8D\xB6YI\x90\xAC\xF1,@\x8A\xEC&gt;\x94\x80Q\xE7p\x81 L
+$IÆ€=2S\xAA!7R\x8B\xE6\xB8OcLm\xD5hCou$\xC7\xFF6:w\x83\x88\xBF\xBB)R\x86=y\xCF\xE8xVn\x86\xDDZä´1{\x93\xE9\xE27\x87fj\xB2hV\xD9SjE\x923\xAD\xC2\xE1b\x86\xBE\xE6 \x98\x93`GR\xC4\xD5݆_MN\xAD\x88)e\xB2:\xDB
+S\xBE\xB7\xB1\xADd\x83?]\xA8\xA5\xFDjRc-\xFD\x8C4:n\xE9c\xCDШLU3\xB43 \xEC\x{D908}\xA7\xB3\x83\xF1\x91L\xBEY,\xD9\xB7\xDDI0p\xA4\x91!Hp\xBD\xF4yd\xD9\xF1pz\xDE\xCA&quot;\x90\xAA\xF1\x98\xA0k+\xB5h\xC5\xDC\xCDx\xD0\xEC8F+\xF9ҵ+ݣ\xC0נ1\xF4\xB75\xA1\xA5\xCBʑ!c\xD6'ctj\xAB\xC1\xC7\xC0
+tY\xBBM\xFE&gt;\xC4\xE6z\x93V9\xAD\xD6\xCF\xC8\xFA\xA3vl\x8B\xDD1-6\x9B\xEB\xE0$\x828\xD0Óˆ\xB9\xE1q\xFC ÆŽ\x86\x91E\xF5Ï£cu%\xDF\xE36\xC4\xC0\xA6G\xB9'\xFB\x85S\x9Fy {\xC4]kNÕ“\xEC\xBA\6i\xBB\x8F쉇\xF65\xC9q\x8Et92\x83\x93R\xE3y\xC1\xA3Qg\x9B\xD9i\xD2\xF2\xC5b\xF3\xB6h\x8B\xCD%\xF7,\x8F\xDCrO\xF6\x8B\xC1\x84\x92 V@i\xCDU\xE2:)\xE0w\x94\xBA\xD9A\x94g\g=\x98Mm\xB6\x9D3\x87\x91Ñ€\xF0\xAC\xC01\xC5\xD8H7\x9D!\x9C\xE7\xDA,\x9C`\x92\xFC\xA9Ѭ\xA1a\xE6Ä”\x96\xDEF\x9EzsngJ\x83(m&gt;R4\xE5\xB1x$\xB22#\x93A^{\xFE\xCDA\xC3.) zZ:b\xFAa`\x87\xCE;\xAB\x84+\xF8Û¡,q\xB2\x98\xC5        $\xCD\xD3~nƨ8\xA0L؃\xDBs\xA0\x97;i\x81\xDA\xE9\x92R\xD4        Pf\xD1\xF2\xA2\xF5\xF1\xC9@\xFAÕ†\x8BR\x83\xC8`\xA9]gtv\xB8 \xB5+\xE5zm\x91\xAC\x81,}:\x99G\xE8\xC1qÙ‘ k\xBD\xBCJ\xAC%*\xACz\\xDBc\xEB\xED\x9D\xFE^\xE0\xB5C\xA3a\xD0uΰr4\xD9\xE4Y\xC0N;#\xD6\xDC\xD7h\x9E?b\xCB.\xB4\xE6\xBCv\x939        \xF6n\xBF\x9B\xB2\xC4c\xD8.\xC5ne!\xA3\xEDƈzδ[\xEFb\xB0-\xF2\x95-\xC6v\xAA\
 xF3ʶh\xCC{YE5\xBE\x8DJG\xE7!\x83\xB9Ç\x9D\x9C\x84r\xB6M\x94\xCC!C\xEFr|8\xFF\xB5'C\xF4\x8F,\xA6\x87\xEB\xF6G\xD3\xEB\x8BeM\x9F\x86\xDAQ_\xFBNV\xBBu\xE7A\z\x9F\x87@&amp;_[\xFB\xAD\x80\xD5Q\xBFep(~^:\x8B\xB1S3\xB0:s\x8DXk3f$HzE(O\xB8[\xAE-\xA7A@*6\xBD\x97\xA6ftw\x86\xB5-G\xFAXkb˾\xB5\x86\xA6.M\xE1\xB8+t\xDAؘ-.\xAD\xE1Ì\xEDY}5\xB7;%Eᤕ\x90\x93\xFB(!KP\x90\x97\xD2\xE3j\xC2s.?G+3\xE8&lt; \xCDe;&lt;-\x9F\xED6w#\xD9\xD5\xE3\xBA  wr\xCB\xBD\xB2\xB0\x9Bd\xC9LI\xE6&lt;9\xA9\xF4\xE8\xF8\xA72v\x94VG\xBD\x9C\xC8R\xE6\xEC'T\xB2\xAA\xAD9$G\xD0-\xDCI\xE2X\xE5\xAA&lt;[\xDEi\xE9h\xFB\xC0~\xB6\x80|g禸\xAB\xED\x8B\xBB\x86}\xF7\xFBX,\xED\xDDx29#^\xB7\xA4\x9F\xD0Ø…\xBCR\xD3\xC0        I\xCF\xB1\xB7\xBB\x8C\x9Cw\xA4\x8B\xA7E\xC9\xD3\xD0Vz^kjj\xD3xVЕ\xF9\xBCp\x9DG\xAB3\xD6Ò-\xEF]\x90|Bd73Óˆv\x9E\xD1Ù¹uy\x9C\xB1Y9J\xF2\x94`4\x8D\xC5\xDEE'\xC8Y\x99׿\xE0fVVOG\xAC\x9C\xF1\xBA;wGN\x86\xE3t(\x8E\xF6?~;&amp;\xE0\x84\xC0\xF6+\xE32A66Ø»\xD3Ǩ\x82\xCF\xD3\xD9r\
 x85\xAC~\xD8Q\x89j
+\xF8V\xC0Ùœ[\x80\x98쥥\xD9\xD0\xD9Y\xB3\x95r캽\x8E\xFD\xB5$]\x9D\xEDH#\xB6\x8E\xB7\x8E\xC9\x98\xEC\x89\x9B\xA5L`\xF6\xC0\x8E|A΋q\xEEwv|CWc\x89\xC0\xEE:\xEB\xE6\x85\xE065x\xE4\xA8F1\xF1\x92\xB1#\x93\xCCm\x86\xC3\xE1jn\xC7u*\xC6d?l8Qn\xF2\xC4\xD2Ø¢\xC3\xEF\xB7 \xAB;\xA7\x9D{\xF0\xA0\xCF\xFB\xD8\x81=5\xB3\x94~\x8BE\x9C\xCEp\xAF\xE38\xED\xC3m\x96\xF3\xE2\xB81Pbe\xF7\xA0j\x8F_8\xF5\xBB\x8E\xE8\xE3cs\xA5\xBEMTئ\xE9\x97[\xB1V2'\xDB\xF1\xAC\xBF\x8B\xB12`|km\xC94 \x8F\xB26;k\xDDL\xB2\xB1\xCB\xCE\x8E+\xB8&quot;%\xB0\xF7\xDEG\x8Atn'kI,\xC0\xB9A\xA77\x99òœ½Ž\xE0\x81\jv8\x97qG\x80\xAD#Gvg\xEE\xEF4\x98=MN\xB2\xC5\xD5Æ–\xC6v\xEEf-H\x90\xED|.\xB05\x80\x96\xBE&amp;\xD9$\xA5\xE5}\x9Fr/@uA\xDBV\xB1\\xB32\xFA\x84\xB4q\xB5\xB4\xF5\xFF{\xFCWl\xCF9#E\x92r\x85-i\x94\xD5\xD7F]\xF9\xB8ÆŽ\xC4Qf\xAE\xF5\xC5F\xF5\xB9\xD7\x8C\x8BÅ‘\xD4)඲m^0\x9AfPO+;\xFF71\xFEܽ\x8Am\xE6\xFB\xCE\xEA\xE0\xA3LJ\x9B+\xF9FD\x8F\xB5\x93\xF5Ý®\xA3b-\xC71
+\xDA$\xD8\xC9I˧\xAB\xFD\xDA\xEFÝ”\xCB:+s\x9E\xF0A\xED\xDC?\xFBA&quot;\x81\xA1\\xA6 \x92L\x83s\x92\xAD\xD3\xFA:!S\xA6\xA4Hv\x89\xC8ÚÔˆ;5\xB3\x87\xCE\xF932\xC6
+!\x93e\xCA\xF8yI\x8A3\xEF;\x9D\xCB\xF1\xEF \xBCm/\xE9Å \xE2\xD0\xD2ß¡4\xD1^P\xAA\x9Ay?n\xF7e|\xE5\x91ÄŽ#5B\x90\xB5&amp;3vaÄŒQu\xE2q&amp;u:\xD1\xC8{\xB4l        uF\xB8\xA4\xFD\x9D\xCDvß݇\xE9+6 &lt;U\x83 Þ¤\xDD\xE7e&gt;\xA3\x92VNcN\xD30\xF2$\x95\xD2\xCFZ\xA2X\x8C\xED\x95\xA0;eb\xB4 \x94 A\xCAÜ’(V\xBA\x9ClV\xA7(p&lt;O\x8A È‘0\xA0\x8C\xD2\xF0        I9\x94eJ\xD9Wm\xF6\xBBe\xD0O\xBE\xD3!&quot;\xE0F+CPg\\x8D`\xA2~\x8AF\xBA$\xA5G\xA6\x95\x8C)C\x9E#E&quot;GS1\x8C\xA0Q'p\xEA\xC0Ý‹\xEE\xDDlV_ \xA8Î!\xFBQV\xC24\xC7\xAEG\xD6Õ°FÔœ\xFD8TM\x92\xB1G\x81\xEE&amp;q\x888`\xEA\xE8\xF6\x96\xABhF\x8C+20~\xA3\xF41^ %\xA3\xD01{\xB0\xC7an\x80\xA2\x8E\xE4e        3\xD7+~\x963l\xEC\xB4y@ \xADf\xCCul@OR\xA4\xC1\xBD\xED\xCCÊ“\xE2\x80*\x9D\xECA\x8E\xC7,\xD03ËŽÌ´\xA5\xBAn&quot;\xEA\xD8\xEC^\x83L*&lt;C\xA1\xEC\xC8\xD9\xF2̳\xC1\xABw\xBC\xFE1\xA6\x97\x9C\xA9#\xC9Jλ(\xC3\xA1\xC3\xE6\xF8\xD8\xC7\xF7        \xB5oRÛ§\x8B\xAC\xAB1[L\x9D\x8F\xBE\xA3\xC7\xF4\xA6\xE0\x97m\xEE        \x8EÖž\x95'S\xEE\xC
 9\xC3\xCFÊŒL\x9C\xDD\xD6\xFF\xBF8\x83@V\xFF\x86\xF6dÇ„_\x9DOv4Kk&amp;\xA8\x94\xED\xCAc\x8D\xEE\xB4&amp;\x9D꤉\xA3LF{w)\xE4\xEF:@\xBBQ\xB8D`\xB5Û’\xD5\xC7h\xDBz\xD2뉚y\xB0\xB0\xE9`OJ\xCB\xC2;\xC2\xDA\xAB+\xC8l\xEB\xDCT\xB9\x9E\xF2ͳ@\x8F\xB6y\xFA}4\x90k\xB6-Sò¼¸nEV{nG\xF4\xD9gH\x9F\xF3\xA4Hr\xD2\xF7 \xB83k\xD7Hf\xB6&amp;\xA8A\xF5#\x8B\x9Fr\xCB\xF6X{\xA8\xA3\xE1yPF;d\x8A\xBD\x83\xC4 \x91S\x86:$&quot;\xA6MÈ’\xE706\xE1qh\xA1\x89$H\x96\xC53s\xAA$B\x94$B\x92\xE7,\xA0='\x81\xE4
+al\x8BU$\xA8Ø›+.g\xD887J}\x82\xB1\xC0\x87\xD6`\xD2
+\xF4
+\xA9,V\xE7\xF7\xF5\xB5        \xA4\xFE\xB3\xA2s\xD8\xFAzD3c\xFD\x9C\xC9Ζ\x91\xFF&quot;3\xE7\xA0LGQ\xD70m\xE9%\xD2\xEB\xA3 &gt;\xCC\xD8`{\xA1\xEC\xBC\x81\xA4Yo\xE2\xE71\xFF\xD1D\xD0\xE8\xF9fA\x88f\xAD휨d0\xF0f\xE7#Z\xFA\xDD\x{DF91} 2\xA1\xB5G\xB4\xB7kz,s\xE4u2\xED\x9Ffr\xB7#\xFA        \x96\xA6\xAD3Ý°\xFD\x96\xF9\xDDFA=j\xE1+t\x923\xBB\xC5k\xC9\x91)\xCD&gt; If\xCD pÝ‹\x9C8o\xEA\x9C\xDD,QL\x9C\xFDnI\x9D|\xC6\xFF7dܨ\xA6#\x939\xFC\xB0\x8CM\xF6\xD8E\xA3ÝŽ\xC1H{G::\xBCp        =^\x81\xD0\\xB4\xF2\xA8C\xB6\xD8L!F\x99\xE9%\xBC\x8Em\xC6'\x83\x8C=\xF4\xBB$]\xA2\x81tx\xF8&lt;(g\xCE\xD1Øž\xC1\x80\xE7\xA8\xCDS\x87\x81hF\x8F\xCF\x99H\xAF\x9B)a\xA7\xCDÈ‹\xF0\xF8Y\xDD&lt;\xCAij\xB2U~\x85rs\x96\x8C2\xF6\xC7$\xE5uL:$V0\xE8\\xD0ami25\x93\xD7n4\xD8Mˬ\xE4\xFF\x8B&lt;\xA7d\x86\x89\x8D\xC98y\xE8)\xCDG;\x90\xE1*b\xB8r\xC3`sT\x93G\xAB\x98\xCDvW
+\xF9\xECLt\x92L\xEC\xD4\xD3.ÅŒf\x9E\x91$\xB3\x9Ewt\xC8\xD83\xAC\xED\xE9rrF\xBA'.\x92gft\xE2\x88\xE44`8w[IJM\xC8'\xF8\xBB&amp;\xE9 V\xEC2\xB55\x8Dr\x86\xBD\xF6\xF5T\x87Rd\xA8\x83:;bJ\xB8RB\xD6
+\x8C\xA4̈\x95\xE81\xF1\xA1 uL#\xE7\x89,\xB7D„\x9E\xE1vlMG\xEF$\x87\\x91\xD8\xCF씓$t_cm$\xC0\x9C`\xF7\xF4E\x99i^\x8EX\xA0CqÄ\xCE}\x97\x85#i!\xA6e\xE8:Ë’(\xAA\xFB\xF9\x8C=\x91\xC49\xB1\xD3o\xB9\x80u\x83t7\xA4sq4P}\xEB\xF7G\xA7j\xEB\xF0Y \x8F\xDE\xF7!\xD9\xF3t`O\xB0y\xF6\xA3^x\xB7\x8D\x93`&gt;\xC0}$\xFB\x9B~\xE4g\x82z\xC6\xCA;[\x82\xF0        Rd\xCA9\xB1d\x83\xD1\xE1Ͷ\xA6\xD6\xE0\xC3 \xA35\xFF\x8D\xD1\xF7\x89\xF8b4\xC0\xA6\xC9\xFFgx\x9C\xB5Ý«\xCA;\xC1\xBDy\x8E\x99\xF5\xBB\xAD\xC1l\xA0\x9A\xF3\xAC\x86?T3\x80B\x8B\x98\xCEh\xE0# ?#\xB9\xF2\x96\x93\xB1\x93\xD2\xC1emp\xF1S\x8C\x8Ez\x84\xD1 Gn\xCFa'N\x92Hk\xFD+È®\xF4m\x8A\x91\xCBaF\x8E\x9C\x98\xBF\xDC\xB6\x88;\xBA\xC0\xF5\xB7\xF1\xC7z\x8C\x9E\xD4\xE3Y\xE6C\xB6c+2\xE5p'e\xDEA-\xBD\x9D3]7\xC5\xE0gj\xEE;ct8F&amp;\x8B?!\xD0,\xD8\xFB \x87d\x89JjM\xFCiq\x90ysmgj\xAD\xF3\xDA9[\xF5q\xD8\xF5\xFF\xD5-—\xB7\xEE&lt;\xF0N{âž”1~\x95\xA2\x97\xE1\xEC&lt;G@\x9FÚ¡\xE3k\x95ሔ\x9Aq7'c8 \x8Cb\xBF\xB
 3\x92f\xE2w&gt;`Ñ…\xACM\xEE\x98\xC9\xC4&amp;\xF3\xBA\xCCH\x94f\xADI\xA0\x8C0Y\xBAS{myà·±\xB6\xEB\x94{\xE2wT\xBFM\xCB+I\xDDLt \xE12\xDA\xFEv\xC4\xDD8[\x8Fg-D@\xD7e\xB2S b\x84\xE1\xB3Û³ \:\xA2\xD4Ͳ\xAD7\x95\xD89S)\x9C/KN6+B\xF0d\x8D\xD9\xB1\xD6\x87&amp;\xBC\xA8_\xBC&lt;\xBE\xE22+\xE6\xC6YH\xB6\xE7\xB4\x87\xEFDG=\xE5\xB3\xE6\xA9\xEB\xBDT`\xA7\xC1}4\xF93![\x8E\xEA\xF9))t\xD6\xF6$\xDB\xCE2\xF1\xF09\xCF\xD4\xC4\xCFB\xE6\xF9\xD8\xC3:;        .\xEFb\x8E\xB4\xF1\xF6[\xA0\x98\xC6\xEC\xC5\xB7@\xE7:my\xE3\xDF)\xA3\xA7)\xC1\xE64\xEA\x91N0v\xB3\xB2\xD5\xE8\xC3\xE8\x9D\x9E:\x9A:\x9C\xA6/\xFE 0f\xD8xp\x83`\x9B\xEE\xCEJ\x9C&lt;\x93\xA5\x80\xCD#,\x9C$b\xF93~Ô¡\xF9\xEC8\xD63}\xFB΀z\x86\xDDC\x8D}@o\xCFH\x99{\xA9s\x94u\x87\xF7T\xA9\xF0\xEC\xE9Íž&lt;\x9E\xEC\xA7\xA0w\x913:B·\xF24\x98ÇZ\x9Eƾo\xF5\xF8\xDB \xF0
+Ï¡{TÊ \x8C\x9B\xE5tf\xD8\xF9\xECv\xA7=\xDBf̃혎\x9E\xF3\xA8\x948\xDAyF\x81m\x80;m\xB0\xCFh\xF5{\xB6\xEC        ,&gt;\xF2\xB3\x81~ȧ\x80yRϸS\x80&gt;zG6\x9E\xEAl\x98\xC4g\x98\xA4Sd\x81;\xDEi\xA0\x8F\x80\xFD\x90\xCB\x98\x9F\xE8\x8F S2&gt;\xF6Y\xCC{P3\xA0e-z2{=\xBD\xAB!iÿ\xC7H\xE7\xCB\xFF\x8E\xE3\xE9\xF2\xA3L?+E\xCE\xD0\xDCGY\xF6\xACN2\xD3QF\x98\xF6\xA0f:\xE5\xACT\xA0 \xE5\xD8
+Ô‡\x99\xFE(\xB0\xCFb\xEF3A~\xE8\xB3`o\xB4\x9FxW9\xC4gy6x&lt;\x9B\xA53\xF7\x803\x80Mg\x9D\xC3\xF8\xF2GA&gt;Ë°ÓŒ\xCB\xE7\x82\xF7 &amp;&gt;\xC4g\x81yk\x896\xFA\xA0\xA6\xBFÚ£\xD0\xE7\xE3\xED~+\xC1؇kb\xCF`\xD6gI\x843u\xEF$/\x99\xC9+\xCF`e\xE3&lt;\xB9\xEB{\x86\xE49~'\xE03\x81\xCDO\xE0A\xFE,\xB0        \xDC\xE6:\xD1\xDC\xF9\xC1\xC6\xEF
+ⷖ5\xA7i\xEC\xF2g\x81\xF20\xB0\xCE\xEC'~\xE6\x9B\xE8\xA3\xF7\xD0\xE8o\xEC'\xB3딄*O\xE4SAt\xB6Dz&amp;\x88g$\xD6\xF7
+\xEC'\xB0+\xBF\xEB\xF7\xFB\xFE:ȱXj\xA8\\xE1\x94O\xFC~\x81}\xFA\x85\xE4\x8F\xF9\xFA \xB6\xFD\x9D\xCAhWy\x8F\x8Bq\xF9\xBC\xFE\xFF_\xE5        ]\xE5\xE3\xFC_&gt; cu\xEF\xF8C\xF6\x8E\x8Fwy\xEE\xEF\xF4\xB6\xF2\x83\xBFK)\xF2]q\xC7[ߊ\xCA\xFD_\xF3;\xFF/\xA8\xE5=1\xF3Ù•?\xC45\x9E\xFB\xDE\xFB\x87\x{51C7CF}\xBF\xD4\xE3\xFFZF×­}DTIEND\xAEB`\x82
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamprofilerviewercss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/profilerviewer.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/profilerviewer.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/profilerviewer.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+.yui-skin-sam .yui-pv{background-color:#4a4a4a;font-family:arial;position:relative;width:99%;z-index:1000;margin-bottom:1em;overflow:hidden;}.yui-skin-sam .yui-pv .hd{background:url(header_background.png) repeat-x;min-height:30px;overflow:hidden;zoom:1;padding:2px 0;}.yui-skin-sam .yui-pv .hd h4{padding:8px 10px;margin:0;font:bold 14px arial;color:#fff;}.yui-skin-sam .yui-pv .hd a{background:#3f6bc3;font:bold 11px arial;color:#fff;padding:4px;margin:3px 10px 0 0;border:1px solid #3f567d;cursor:pointer;display:block;float:right;}.yui-skin-sam .yui-pv .hd span{display:none;}.yui-skin-sam .yui-pv .hd span.yui-pv-busy{height:18px;width:18px;background:url(wait.gif) no-repeat;overflow:hidden;display:block;float:right;margin:4px 10px 0 0;}.yui-skin-sam .yui-pv .hd:after,.yui-pv .bd:after,.yui-skin-sam .yui-pv-chartlegend dl:after{content:'.';visibility:hidden;clear:left;height:0;display:block;}.yui-skin-sam .yui-pv .bd{position:relative;zoom:1;overflow-x:auto;overflow-y:hidden;}.y
 ui-skin-sam .yui-pv .yui-pv-table{padding:0 10px;margin:5px 0 10px 0;}.yui-skin-sam .yui-pv .yui-pv-table .yui-dt-bd td{color:#eeee5c;font:12px arial;}.yui-skin-sam .yui-pv .yui-pv-table tr.yui-dt-odd{background:#929292;}.yui-skin-sam .yui-pv .yui-pv-table tr.yui-dt-even{background:#58637a;}.yui-skin-sam .yui-pv .yui-pv-table tr.yui-dt-even td.yui-dt-asc,.yui-skin-sam .yui-pv .yui-pv-table tr.yui-dt-even td.yui-dt-desc{background:#384970;}.yui-skin-sam .yui-pv .yui-pv-table tr.yui-dt-odd td.yui-dt-asc,.yui-skin-sam .yui-pv .yui-pv-table tr.yui-dt-odd td.yui-dt-desc{background:#6F6E6E;}.yui-skin-sam .yui-pv .yui-pv-table .yui-dt-hd th{background-image:none;background:#2E2D2D;}.yui-skin-sam .yui-pv th.yui-dt-asc .yui-dt-liner{background:transparent url(asc.gif) no-repeat scroll right center;}.yui-skin-sam .yui-pv th.yui-dt-desc .yui-dt-liner{background:transparent url(desc.gif) no-repeat scroll right center;}.yui-skin-sam .yui-pv .yui-pv-table .yui-dt-hd th a{color:#fff;font:b
 old 12px arial;}.yui-skin-sam .yui-pv .yui-pv-table .yui-dt-hd th.yui-dt-asc,.yui-skin-sam .yui-pv .yui-pv-table .yui-dt-hd th.yui-dt-desc{background:#333;}.yui-skin-sam .yui-pv-chartcontainer{padding:0 10px;}.yui-skin-sam .yui-pv-chart{height:250px;clear:right;margin:5px 0 0 0;color:#fff;}.yui-skin-sam .yui-pv-chartlegend div{float:right;margin:0 0 0 10px;_width:250px;}.yui-skin-sam .yui-pv-chartlegend dl{border:1px solid #999;padding:.2em 0 .2em .5em;zoom:1;margin:5px 0;}.yui-skin-sam .yui-pv-chartlegend dt{float:left;display:block;height:.7em;width:.7em;padding:0;}.yui-skin-sam .yui-pv-chartlegend dd{float:left;display:block;color:#fff;margin:0 1em 0 .5em;padding:0;font:11px arial;}.yui-skin-sam .yui-pv-minimized{height:35px;}.yui-skin-sam .yui-pv-minimized .bd{top:-3000px;}.yui-skin-sam .yui-pv-minimized .hd a.yui-pv-refresh{display:none;}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamprogressbarcss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/progressbar.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/progressbar.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/progressbar.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+.yui-pb-bar,.yui-pb-mask{width:100%;height:100%}.yui-pb{position:relative;top:0;left:0;width:200px;height:20px;padding:0;border:0;margin:0;text-align:left}.yui-pb-mask{position:absolute;top:0;left:0;z-index:2}.yui-pb-mask div{width:50%;height:50%;background-repeat:no-repeat;padding:0;position:absolute}.yui-pb-tl{background-position:top left}.yui-pb-tr{background-position:top right;left:50%}.yui-pb-bl{background-position:bottom left;top:50%}.yui-pb-br{background-position:bottom right;left:50%;top:50%}.yui-pb-bar{margin:0;position:absolute;left:0;top:0;z-index:1}.yui-pb-ltr .yui-pb-bar{_position:static}.yui-pb-rtl .yui-pb-bar{background-position:right}.yui-pb-btt .yui-pb-bar{background-position:left bottom}.yui-pb-bar{background-color:blue}.yui-pb{border:thin solid #808080}.yui-skin-sam .yui-pb{background-color:transparent;border:solid #808080;border-width:1px 0}.yui-skin-sam .yui-pb-rtl,.yui-skin-sam .yui-pb-ltr{background-image:url(back-h.png);background-repeat:repeat-x}.yui
 -skin-sam .yui-pb-ttb,.yui-skin-sam .yui-pb-btt{background-image:url(back-v.png);background-repeat:repeat-y}.yui-skin-sam .yui-pb-bar{background-color:transparent}.yui-skin-sam .yui-pb-ltr .yui-pb-bar,.yui-skin-sam .yui-pb-rtl .yui-pb-bar{background-image:url(bar-h.png);background-repeat:repeat-x}.yui-skin-sam .yui-pb-ttb .yui-pb-bar,.yui-skin-sam .yui-pb-btt .yui-pb-bar{background-image:url(bar-v.png);background-repeat:repeat-y}.yui-skin-sam .yui-pb-mask{border:solid #808080;border-width:0 1px;margin:0 -1px}.yui-skin-sam .yui-pb-caption{color:#000;text-align:center;margin:0 auto}.yui-skin-sam .yui-pb-range{color:#a6a6a6}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamresizecss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/resize.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/resize.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/resize.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+.yui-resize{position:relative;zoom:1;z-index:0;}.yui-resize-wrap{zoom:1;}.yui-draggable{cursor:move;}.yui-resize .yui-resize-handle{position:absolute;z-index:1;font-size:0;margin:0;padding:0;zoom:1;height:1px;width:1px;}.yui-resize .yui-resize-handle-br{height:5px;width:5px;bottom:0;right:0;cursor:se-resize;z-index:2;zoom:1;}.yui-resize .yui-resize-handle-bl{height:5px;width:5px;bottom:0;left:0;cursor:sw-resize;z-index:2;zoom:1;}.yui-resize .yui-resize-handle-tl{height:5px;width:5px;top:0;left:0;cursor:nw-resize;z-index:2;zoom:1;}.yui-resize .yui-resize-handle-tr{height:5px;width:5px;top:0;right:0;cursor:ne-resize;z-index:2;zoom:1;}.yui-resize .yui-resize-handle-r{width:5px;height:100%;top:0;right:0;cursor:e-resize;zoom:1;}.yui-resize .yui-resize-handle-l{height:100%;width:5px;top:0;left:0;cursor:w-resize;zoom:1;}.yui-resize .yui-resize-handle-b{width:100%;height:5px;bottom:0;right:0;cursor:s-resize;zoom:1;}.yui-resize .yui-resize-handle-t{width:100%;height:5px;top:0;right:0
 ;cursor:n-resize;zoom:1;}.yui-resize-proxy{position:absolute;border:1px dashed #000;visibility:hidden;z-index:1000;}.yui-resize-hover .yui-resize-handle,.yui-resize-hidden .yui-resize-handle{opacity:0;filter:alpha(opacity=0);}.yui-resize-ghost{opacity:.5;filter:alpha(opacity=50);}.yui-resize-knob .yui-resize-handle{height:6px;width:6px;}.yui-resize-knob .yui-resize-handle-tr{right:-3px;top:-3px;}.yui-resize-knob .yui-resize-handle-tl{left:-3px;top:-3px;}.yui-resize-knob .yui-resize-handle-bl{left:-3px;bottom:-3px;}.yui-resize-knob .yui-resize-handle-br{right:-3px;bottom:-3px;}.yui-resize-knob .yui-resize-handle-t{left:45%;top:-3px;}.yui-resize-knob .yui-resize-handle-r{right:-3px;top:45%;}.yui-resize-knob .yui-resize-handle-l{left:-3px;top:45%;}.yui-resize-knob .yui-resize-handle-b{left:45%;bottom:-3px;}.yui-resize-status{position:absolute;top:-999px;left:-999px;padding:2px;font-size:80%;display:none;zoom:1;z-index:9999;}.yui-resize-status strong,.yui-resize-status em{font-w
 eight:normal;font-style:normal;padding:1px;zoom:1;}.yui-skin-sam .yui-resize .yui-resize-handle{background-color:#F2F2F2;zoom:1;}.yui-skin-sam .yui-resize .yui-resize-handle-active{background-color:#7D98B8;zoom:1;}.yui-skin-sam .yui-resize .yui-resize-handle-l,.yui-skin-sam .yui-resize .yui-resize-handle-r,.yui-skin-sam .yui-resize .yui-resize-handle-l-active,.yui-skin-sam .yui-resize .yui-resize-handle-r-active{height:100%;zoom:1;}.yui-skin-sam .yui-resize-knob .yui-resize-handle{border:1px solid #808080;}.yui-skin-sam .yui-resize-hover .yui-resize-handle-active{opacity:1;filter:alpha(opacity=100);}.yui-skin-sam .yui-resize-proxy{border:1px dashed #426FD9;}.yui-skin-sam .yui-resize-status{border:1px solid #A6982B;border-top:1px solid #D4C237;background-color:#FFEE69;color:#000;}.yui-skin-sam .yui-resize-status strong,.yui-skin-sam .yui-resize-status em{float:left;display:block;clear:both;padding:1px;text-align:center;}.yui-skin-sam .yui-resize .yui-resize-handle-inner-r,.yu
 i-skin-sam .yui-resize .yui-resize-handle-inner-l{background:transparent url(layout_sprite.png) no-repeat 0 -5px;height:16px;width:5px;position:absolute;top:45%;}.yui-skin-sam .yui-resize .yui-resize-handle-inner-t,.yui-skin-sam .yui-resize .yui-resize-handle-inner-b{background:transparent url(layout_sprite.png) no-repeat -20px 0;height:5px;width:16px;position:absolute;left:50%;}.yui-skin-sam .yui-resize .yui-resize-handle-br{background-image:url(layout_sprite.png);background-repeat:no-repeat;background-position:-22px -62px;}.yui-skin-sam .yui-resize .yui-resize-handle-tr{background-image:url(layout_sprite.png);background-repeat:no-repeat;background-position:-22px -42px;}.yui-skin-sam .yui-resize .yui-resize-handle-tl{background-image:url(layout_sprite.png);background-repeat:no-repeat;background-position:-22px -82px;}.yui-skin-sam .yui-resize .yui-resize-handle-bl{background-image:url(layout_sprite.png);background-repeat:no-repeat;background-position:-22px -23px;}.yui-skin-s
 am .yui-resize-knob .yui-resize-handle-t,.yui-skin-sam .yui-resize-knob .yui-resize-handle-r,.yui-skin-sam .yui-resize-knob .yui-resize-handle-b,.yui-skin-sam .yui-resize-knob .yui-resize-handle-l,.yui-skin-sam .yui-resize-knob .yui-resize-handle-tl,.yui-skin-sam .yui-resize-knob .yui-resize-handle-tr,.yui-skin-sam .yui-resize-knob .yui-resize-handle-bl,.yui-skin-sam .yui-resize-knob .yui-resize-handle-br,.yui-skin-sam .yui-resize-knob .yui-resize-handle-inner-t,.yui-skin-sam .yui-resize-knob .yui-resize-handle-inner-r,.yui-skin-sam .yui-resize-knob .yui-resize-handle-inner-b,.yui-skin-sam .yui-resize-knob .yui-resize-handle-inner-l,.yui-skin-sam .yui-resize-knob .yui-resize-handle-inner-tl,.yui-skin-sam .yui-resize-knob .yui-resize-handle-inner-tr,.yui-skin-sam .yui-resize-knob .yui-resize-handle-inner-bl,.yui-skin-sam .yui-resize-knob .yui-resize-handle-inner-br{background-image:none;}.yui-skin-sam .yui-resize-knob .yui-resize-handle-l,.yui-skin-sam .yui-resize-knob .yui-r
 esize-handle-r,.yui-skin-sam .yui-resize-knob .yui-resize-handle-l-active,.yui-skin-sam .yui-resize-knob .yui-resize-handle-r-active{height:6px;width:6px;}.yui-skin-sam .yui-resize-textarea .yui-resize-handle-r{right:-8px;}.yui-skin-sam .yui-resize-textarea .yui-resize-handle-b{bottom:-8px;}.yui-skin-sam .yui-resize-textarea .yui-resize-handle-br{right:-8px;bottom:-8px;}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamsimpleeditorcss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/simpleeditor.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/simpleeditor.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/simpleeditor.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+.yui-busy{cursor:wait!important;}.yui-toolbar-container fieldset,.yui-editor-container fieldset{padding:0;margin:0;border:0;}.yui-toolbar-container legend{display:none;}.yui-skin-sam .yui-toolbar-container .yui-button button,.yui-skin-sam .yui-toolbar-container .yui-button a,.yui-skin-sam .yui-toolbar-container .yui-button a:visited{font-size:0;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-select button,.yui-skin-sam .yui-toolbar-container .yui-toolbar-select a,.yui-skin-sam .yui-toolbar-container .yui-toolbar-select a:visited,.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton button,.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a,.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a:visited{font-size:12px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a.up,.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a.down{font-size:0;line-height:0;padding:0;}.yui-toolbar-container .yui-toolbar-subcont{padding:.25em 0;zo
 om:1;}.yui-toolbar-container-collapsed .yui-toolbar-subcont{display:none;}.yui-toolbar-container .yui-toolbar-subcont:after{display:block;clear:both;visibility:hidden;content:'.';height:0;}.yui-toolbar-container span.yui-toolbar-draghandle{cursor:move;border-left:1px solid #999;border-right:1px solid #999;overflow:hidden;text-indent:77777px;width:2px;height:20px;display:block;clear:none;float:left;margin:0 0 0 .2em;}.yui-toolbar-container .yui-toolbar-titlebar.draggable{cursor:move;}.yui-toolbar-container .yui-toolbar-titlebar{position:relative;}.yui-toolbar-container .yui-toolbar-titlebar h2{font-weight:bold;letter-spacing:0;border:none;color:#000;margin:0;padding:.2em;}.yui-toolbar-container .yui-toolbar-titlebar h2 a{text-decoration:none;color:#000;cursor:default;}.yui-toolbar-container.yui-toolbar-grouped span.yui-toolbar-draghandle{height:40px;}.yui-toolbar-container .yui-toolbar-group{float:left;margin-right:.5em;zoom:1;}.yui-toolbar-container .yui-toolbar-group:after{
 display:block;clear:both;visibility:hidden;content:'.';height:0;}.yui-toolbar-container .yui-toolbar-group h3{font-size:75%;padding:0 0 0 .25em;margin:0;}.yui-toolbar-container span.yui-toolbar-separator{width:2px;padding:0;height:18px;margin:.2em 0 .2em .1em;display:none;float:left;}.yui-toolbar-container.yui-toolbar-grouped span.yui-toolbar-separator{height:45px;*height:50px;}.yui-toolbar-container.yui-toolbar-grouped .yui-toolbar-group span.yui-toolbar-separator{height:18px;display:block;}.yui-toolbar-container ul li{margin:0;padding:0;list-style-type:none;}.yui-toolbar-container .yui-toolbar-nogrouplabels h3{display:none;}.yui-toolbar-container .yui-push-button,.yui-toolbar-container .yui-color-button,.yui-toolbar-container .yui-menu-button{position:relative;cursor:pointer;}.yui-toolbar-container .yui-button .first-child,.yui-toolbar-container .yui-button .first-child a{height:100%;width:100%;overflow:hidden;font-size:0;}.yui-toolbar-container .yui-button-disabled{cursor
 :default;}.yui-toolbar-container .yui-button-disabled .yui-toolbar-icon{opacity:.5;filter:alpha(opacity=50);}.yui-toolbar-container .yui-button-disabled .up,.yui-toolbar-container .yui-button-disabled .down{opacity:.5;filter:alpha(opacity=50);}.yui-toolbar-container .yui-button a{overflow:hidden;}.yui-toolbar-container .yui-toolbar-select .first-child a{cursor:pointer;}.yui-toolbar-fontname-arial{font-family:Arial;}.yui-toolbar-fontname-arial-black{font-family:Arial Black;}.yui-toolbar-fontname-comic-sans-ms{font-family:Comic Sans MS;}.yui-toolbar-fontname-courier-new{font-family:Courier New;}.yui-toolbar-fontname-times-new-roman{font-family:Times New Roman;}.yui-toolbar-fontname-verdana{font-family:Verdana;}.yui-toolbar-fontname-impact{font-family:Impact;}.yui-toolbar-fontname-lucida-console{font-family:Lucida Console;}.yui-toolbar-fontname-tahoma{font-family:Tahoma;}.yui-toolbar-fontname-trebuchet-ms{font-family:Trebuchet MS;}.yui-toolbar-container .yui-toolbar-spinbutton{
 position:relative;}.yui-toolbar-container .yui-toolbar-spinbutton .first-child a{z-index:0;opacity:1;}.yui-toolbar-container .yui-toolbar-spinbutton a.up,.yui-toolbar-container .yui-toolbar-spinbutton a.down{position:absolute;display:block;right:0;cursor:pointer;z-index:1;padding:0;margin:0;}.yui-toolbar-container .yui-overlay{position:absolute;}.yui-toolbar-container .yui-overlay ul li{margin:0;list-style-type:none;}.yui-toolbar-container{z-index:1;}.yui-editor-container .yui-editor-editable-container{position:relative;z-index:0;width:100%;}.yui-editor-container .yui-editor-masked{background-color:#CCC;height:100%;width:100%;position:absolute;top:0;left:0;opacity:.5;filter:alpha(opacity=50);}.yui-editor-container iframe{border:0;padding:0;margin:0;zoom:1;display:block;}.yui-editor-container .yui-editor-editable{padding:0;margin:0;}.yui-editor-container .dompath{font-size:85%;}.yui-editor-panel .hd{text-align:left;position:relative;}.yui-editor-panel .hd h3{font-weight:bold;
 padding:.25em 0 .25em .25em;margin:0;}.yui-editor-panel .bd{width:100%;zoom:1;position:relative;}.yui-editor-panel .bd div.yui-editor-body-cont{padding:.25em .1em;zoom:1;}.yui-editor-panel .bd .gecko form{overflow:auto;}.yui-editor-panel .bd div.yui-editor-body-cont:after{display:block;clear:both;visibility:hidden;content:'.';height:0;}.yui-editor-panel .ft{text-align:right;width:99%;float:left;clear:both;}.yui-editor-panel .ft span.tip{display:block;position:relative;padding:.5em .5em .5em 23px;text-align:left;zoom:1;}.yui-editor-panel label{clear:both;float:left;padding:0;width:100%;text-align:left;zoom:1;}.yui-editor-panel .gecko label{overflow:auto;}.yui-editor-panel label strong{float:left;width:6em;}.yui-editor-panel .removeLink{width:80%;text-align:right;}.yui-editor-panel label input{margin-left:.25em;float:left;}.yui-editor-panel .yui-toolbar-group{margin-bottom:.75em;}.yui-editor-panel .height-width{float:left;}.yui-editor-panel .height-width span{font-style:italic
 ;display:block;float:left;overflow:visible;}.yui-editor-panel .height-width span.info{font-size:70%;margin-top:3px;float:none;}
+.yui-editor-panel .yui-toolbar-bordersize,.yui-editor-panel .yui-toolbar-bordertype{font-size:75%;}.yui-editor-panel .yui-toolbar-container span.yui-toolbar-separator{border:none;}.yui-editor-panel .yui-toolbar-bordersize span a span,.yui-editor-panel .yui-toolbar-bordertype span a span{display:block;height:8px;left:4px;position:absolute;top:3px;_top:-5px;width:24px;text-indent:52px;font-size:0;}.yui-editor-panel .yui-toolbar-bordertype span a span.yui-toolbar-bordertype-solid{border-bottom:1px solid black;}.yui-editor-panel .yui-toolbar-bordertype span a span.yui-toolbar-bordertype-dotted{border-bottom:1px dotted black;}.yui-editor-panel .yui-toolbar-bordertype span a span.yui-toolbar-bordertype-dashed{border-bottom:1px dashed black;}.yui-editor-panel .yui-toolbar-bordersize span a span.yui-toolbar-bordersize-0{*top:0;text-indent:0;font-size:75%;}.yui-editor-panel .yui-toolbar-bordersize span a span.yui-toolbar-bordersize-1{border-bottom:1px solid black;}.yui-editor-panel .
 yui-toolbar-bordersize span a span.yui-toolbar-bordersize-2{border-bottom:2px solid black;}.yui-editor-panel .yui-toolbar-bordersize span a span.yui-toolbar-bordersize-3{top:2px;*top:-5px;border-bottom:3px solid black;}.yui-editor-panel .yui-toolbar-bordersize span a span.yui-toolbar-bordersize-4{top:1px;*top:-5px;border-bottom:4px solid black;}.yui-editor-panel .yui-toolbar-bordersize span a span.yui-toolbar-bordersize-5{top:1px;*top:-5px;border-bottom:5px solid black;}.yui-toolbar-container .yui-toolbar-bordersize-menu,.yui-toolbar-container .yui-toolbar-bordertype-menu{width:95px!important;}.yui-toolbar-bordersize-menu .yuimenuitemlabel,.yui-toolbar-bordertype-menu .yuimenuitemlabel,.yui-toolbar-bordersize-menu .yuimenuitemlabel,.yui-toolbar-bordertype-menu .yuimenuitemlabel:hover{margin:0 3px 7px 17px;}.yui-toolbar-bordersize-menu .yuimenuitemlabel .checkedindicator,.yui-toolbar-bordertype-menu .yuimenuitemlabel .checkedindicator{position:absolute;left:-12px;*top:14px;*l
 eft:0;}.yui-toolbar-bordersize-menu li.yui-toolbar-bordersize-1 a{border-bottom:1px solid black;height:14px;}.yui-toolbar-bordersize-menu li.yui-toolbar-bordersize-2 a{border-bottom:2px solid black;height:14px;}.yui-toolbar-bordersize-menu li.yui-toolbar-bordersize-3 a{border-bottom:3px solid black;height:14px;}.yui-toolbar-bordersize-menu li.yui-toolbar-bordersize-4 a{border-bottom:4px solid black;height:14px;}.yui-toolbar-bordersize-menu li.yui-toolbar-bordersize-5 a{border-bottom:5px solid black;height:14px;}.yui-toolbar-bordertype-menu li.yui-toolbar-bordertype-solid a{border-bottom:1px solid black;height:14px;}.yui-toolbar-bordertype-menu li.yui-toolbar-bordertype-dashed a{border-bottom:1px dashed black;height:14px;}.yui-toolbar-bordertype-menu li.yui-toolbar-bordertype-dotted a{border-bottom:1px dotted black;height:14px;}h2.yui-editor-skipheader,h3.yui-editor-skipheader{height:0;margin:0;padding:0;border:none;width:0;overflow:hidden;position:absolute;}.yui-toolbar-colo
 rs{width:133px;zoom:1;display:none;z-index:100;overflow:hidden;}.yui-toolbar-colors:after{display:block;clear:both;visibility:hidden;content:'.';height:0;}.yui-toolbar-colors a{height:9px;width:9px;float:left;display:block;overflow:hidden;text-indent:999px;margin:0;cursor:pointer;border:1px solid #F6F7EE;}.yui-toolbar-colors a:hover{border:1px solid black;}.yui-color-button-menu{overflow:visible;background-color:transparent;}.yui-toolbar-colors span{position:relative;display:block;padding:3px;overflow:hidden;float:left;width:100%;zoom:1;}.yui-toolbar-colors span:after{display:block;clear:both;visibility:hidden;content:'.';height:0;}.yui-toolbar-colors span em{height:35px;width:30px;float:left;display:block;overflow:hidden;text-indent:999px;margin:.75px;border:1px solid black;}.yui-toolbar-colors span strong{font-weight:normal;padding-left:3px;display:block;font-size:85%;float:left;width:65%;}.yui-toolbar-group-undoredo h3,.yui-toolbar-group-insertitem h3,.yui-toolbar-group-i
 ndentlist h3{width:68px;}.yui-toolbar-group-indentlist2 h3{width:122px;}.yui-toolbar-group-alignment h3{width:130px;}.yui-skin-sam .yui-editor-container{border:1px solid #808080;}.yui-skin-sam .yui-toolbar-container{zoom:1;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-titlebar{background:url(sprite.png) repeat-x 0 -200px;position:relative;}.yui-skin-sam .yui-editor-container .draggable .yui-toolbar-titlebar{cursor:move;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-titlebar h2{color:#000;font-weight:bold;margin:0;padding:.3em 1em;font-size:100%;text-align:left;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-group h3{color:#808080;font-size:75%;margin:1em 0 0;padding-bottom:0;padding-left:.25em;text-align:left;}.yui-toolbar-container span.yui-toolbar-separator{border:none;text-indent:33px;overflow:hidden;margin:0 .25em;}.yui-skin-sam .yui-toolbar-container{background-color:#F2F2F2;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-subcont{padding:0 1em .35em;borde
 r-bottom:1px solid #808080;}.yui-skin-sam .yui-toolbar-container-collapsed .yui-toolbar-titlebar{border-bottom:1px solid #808080;}.yui-skin-sam .yui-editor-container .visible .yui-menu-shadow,.yui-skin-sam .yui-editor-panel .visible .yui-menu-shadow{display:none;}.yui-skin-sam .yui-editor-container ul{list-style-type:none;margin:0;padding:0;}.yui-skin-sam .yui-editor-container ul li{list-style-type:none;margin:0;padding:0;}.yui-skin-sam .yui-toolbar-group ul li.yui-toolbar-groupitem{float:left;}.yui-skin-sam .yui-editor-container .dompath{background-color:#F2F2F2;border-top:1px solid #808080;color:#999;text-align:left;padding:.25em;}.yui-skin-sam .yui-toolbar-container .collapse{background:url(sprite.png) no-repeat 0 -400px;}.yui-skin-sam .yui-toolbar-container .collapsed{background:url(sprite.png) no-repeat 0 -350px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-titlebar span.collapse{cursor:pointer;position:absolute;top:4px;right:2px;display:block;overflow:hidden;heigh
 t:15px;width:15px;text-indent:9999px;}
+.yui-skin-sam .yui-toolbar-container .yui-push-button,.yui-skin-sam .yui-toolbar-container .yui-color-button,.yui-skin-sam .yui-toolbar-container .yui-menu-button{background:url(sprite.png) repeat-x 0 0;position:relative;display:block;height:22px;width:30px;_font-size:0;margin:0;border-color:#808080;color:#f2f2f2;border-style:solid;border-width:1px 0;zoom:1;}.yui-skin-sam .yui-toolbar-container .yui-push-button a,.yui-skin-sam .yui-toolbar-container .yui-color-button a,.yui-skin-sam .yui-toolbar-container .yui-menu-button a{padding-left:35px;height:20px;text-decoration:none;font-size:0;line-height:2;display:block;color:#000;overflow:hidden;white-space:nowrap;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a,.yui-skin-sam .yui-toolbar-container .yui-toolbar-select a{font-size:12px;}.yui-skin-sam .yui-toolbar-container .yui-push-button .first-child,.yui-skin-sam .yui-toolbar-container .yui-color-button .first-child,.yui-skin-sam .yui-toolbar-container .yui-menu-b
 utton .first-child{border-color:#808080;border-style:solid;border-width:0 1px;margin:0 -1px;display:block;position:relative;}.yui-skin-sam .yui-toolbar-container .yui-push-button-disabled .first-child,.yui-skin-sam .yui-toolbar-container .yui-color-button-disabled .first-child,.yui-skin-sam .yui-toolbar-container .yui-menu-button-disabled .first-child{border-color:#ccc;}.yui-skin-sam .yui-toolbar-container .yui-push-button-disabled a,.yui-skin-sam .yui-toolbar-container .yui-color-button-disabled a,.yui-skin-sam .yui-toolbar-container .yui-menu-button-disabled a{color:#A6A6A6;cursor:default;}.yui-skin-sam .yui-toolbar-container .yui-push-button-disabled,.yui-skin-sam .yui-toolbar-container .yui-color-button-disabled,.yui-skin-sam .yui-toolbar-container .yui-menu-button-disabled{border-color:#ccc;}.yui-skin-sam .yui-toolbar-container .yui-button .first-child{*left:0;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-fontname{width:135px;}.yui-skin-sam .yui-toolbar-container .
 yui-toolbar-heading{width:92px;}.yui-skin-sam .yui-toolbar-container .yui-button-hover{background:url(sprite.png) repeat-x 0 -1300px;border-color:#808080;}.yui-skin-sam .yui-toolbar-container .yui-button-selected{background:url(sprite.png) repeat-x 0 -1700px;border-color:#808080;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-nogrouplabels h3{display:none;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-nogrouplabels .yui-toolbar-group{margin-top:.75em;}.yui-skin-sam .yui-toolbar-container .yui-push-button span.yui-toolbar-icon,.yui-skin-sam .yui-toolbar-container .yui-color-button span.yui-toolbar-icon,.yui-skin-sam .yui-toolbar-container .yui-menu-button span.yui-toolbar-icon{display:block;position:absolute;top:2px;height:18px;width:18px;overflow:hidden;background:url(editor-sprite.gif) no-repeat 30px 30px;}.yui-skin-sam .yui-toolbar-container .yui-button-selected span.yui-toolbar-icon,.yui-skin-sam .yui-toolbar-container .yui-button-hover span.yui-toolbar-icon{backgr
 ound-image:url(editor-sprite-active.gif);}.yui-skin-sam .yui-toolbar-container .visible .yuimenuitemlabel{cursor:pointer;color:#000;*position:relative;}.yui-skin-sam .yui-toolbar-container .yui-button-menu{background-color:#fff;}.yui-skin-sam .yui-toolbar-container .yui-button-menu .yui-menu-body-scrolled{position:relative;}.yui-skin-sam div.yuimenu li.selected{background-color:#B3D4FF;}.yui-skin-sam div.yuimenu li.selected a.selected{color:#000;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-bold span.yui-toolbar-icon{background-position:0 0;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-strikethrough span.yui-toolbar-icon{background-position:0 -108px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-italic span.yui-toolbar-icon{background-position:0 -36px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-undo span.yui-toolbar-icon{background-position:0 -1326px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-redo span.yui-tool
 bar-icon{background-position:0 -1355px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-underline span.yui-toolbar-icon{background-position:0 -72px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-subscript span.yui-toolbar-icon{background-position:0 -180px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-superscript span.yui-toolbar-icon{background-position:0 -144px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-forecolor span.yui-toolbar-icon{background-position:0 -216px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-backcolor span.yui-toolbar-icon{background-position:0 -288px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-justifyleft span.yui-toolbar-icon{background-position:0 -324px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-justifycenter span.yui-toolbar-icon{background-position:0 -360px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-justifyright span.yui-toolbar-icon{b
 ackground-position:0 -396px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-justifyfull span.yui-toolbar-icon{background-position:0 -432px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-indent span.yui-toolbar-icon{background-position:0 -720px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-outdent span.yui-toolbar-icon{background-position:0 -684px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-createlink span.yui-toolbar-icon{background-position:0 -792px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-insertimage span.yui-toolbar-icon{background-position:1px -756px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-left span.yui-toolbar-icon{background-position:0 -972px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-right span.yui-toolbar-icon{background-position:0 -936px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-inline span.yui-toolbar-icon{background-position:0 -900px;lef
 t:5px;}
+.yui-skin-sam .yui-toolbar-container .yui-toolbar-block span.yui-toolbar-icon{background-position:0 -864px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-bordercolor span.yui-toolbar-icon{background-position:0 -252px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-removeformat span.yui-toolbar-icon{background-position:0 -1080px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-hiddenelements span.yui-toolbar-icon{background-position:0 -1044px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-insertunorderedlist span.yui-toolbar-icon{background-position:0 -468px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-insertorderedlist span.yui-toolbar-icon{background-position:0 -504px;left:5px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton,.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton .first-child{width:35px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton .first-child a{padding-left:2
 px;text-align:left;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton span.yui-toolbar-icon{display:none;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a.up,.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a.down{right:2px;background:url(editor-sprite.gif) no-repeat 0 -1222px;overflow:hidden;height:6px;width:7px;min-height:0;padding:0;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a.up{top:2px;background-position:0 -1222px;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-spinbutton a.down{bottom:2px;background-position:0 -1187px;}.yui-skin-sam .yui-toolbar-container select{height:22px;border:1px solid #808080;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-select .first-child a{padding-left:5px;text-align:left;}.yui-skin-sam .yui-toolbar-container .yui-toolbar-select span.yui-toolbar-icon{background:url(editor-sprite.gif) no-repeat 0 -1144px;overflow:hidden;right:-2px;top:0;height:20px;}.yui-skin-sam .yui-editor-panel
  .yui-color-button-menu .bd{background-color:transparent;border:none;width:135px;}.yui-skin-sam .yui-color-button-menu .yui-toolbar-colors{border:1px solid #808080;}.yui-skin-sam .yui-editor-panel{padding:0;margin:0;border:none;background-color:transparent;overflow:visible;position:absolute;}.yui-skin-sam .yui-editor-panel .hd{margin:10px 0 0;padding:0;border:none;}.yui-skin-sam .yui-editor-panel .hd h3{color:#000;border:1px solid #808080;background:url(sprite.png) repeat-x 0 -200px;width:99%;position:relative;margin:0;padding:3px 0 0 0;font-size:93%;text-indent:5px;height:20px;}.yui-skin-sam .yui-editor-panel .bd{background-color:#F2F2F2;border-left:1px solid #808080;border-right:1px solid #808080;width:99%;margin:0;padding:0;overflow:visible;}.yui-skin-sam .yui-editor-panel ul{list-style-type:none;margin:0;padding:0;}.yui-skin-sam .yui-editor-panel ul li{margin:0;padding:0;}.yui-skin-sam .yui-editor-panel .yui-toolbar-container .yui-toolbar-subcont{padding:0;border:none;ma
 rgin-top:.35em;}.yui-skin-sam .yui-editor-panel .yui-toolbar-bordersize,.yui-skin-sam .yui-editor-panel .yui-toolbar-bordertype{width:50px;}.yui-skin-sam .yui-editor-panel label{display:block;float:none;padding:4px 0;margin-bottom:7px;}.yui-skin-sam .yui-editor-panel label strong{font-weight:normal;font-size:93%;text-align:right;padding-top:2px;}.yui-skin-sam .yui-editor-panel label input{width:75%;}.yui-skin-sam .yui-editor-panel .createlink_target,.yui-skin-sam .yui-editor-panel .insertimage_target{width:auto;margin-right:5px;}.yui-skin-sam .yui-editor-panel .removeLink{width:98%;}.yui-skin-sam .yui-editor-panel label input.warning{background-color:#FFEE69;}.yui-skin-sam .yui-editor-panel .yui-toolbar-group h3{color:#000;float:left;font-weight:normal;font-size:93%;margin:5px 0 0 0;padding:0 3px 0 0;text-align:right;}.yui-skin-sam .yui-editor-panel .height-width h3{margin:3px 0 0 10px;}.yui-skin-sam .yui-editor-panel .height-width{margin:3px 0 0 35px;*margin-left:14px;width
 :42%;*width:44%;}.yui-skin-sam .yui-editor-panel .yui-toolbar-group-border{width:190px;}.yui-skin-sam .yui-editor-panel .no-button .yui-toolbar-group-border{width:210px;}.yui-skin-sam .yui-editor-panel .yui-toolbar-group-padding{width:203px;_width:198px;}.yui-skin-sam .yui-editor-panel .no-button .yui-toolbar-group-padding{width:172px;}.yui-skin-sam .yui-editor-panel .yui-toolbar-group-padding h3{margin-left:25px;*margin-left:12px;}.yui-skin-sam .yui-editor-panel .yui-toolbar-group-textflow{width:182px;}.yui-skin-sam .yui-editor-panel .hd{background:none;}.yui-skin-sam .yui-editor-panel .ft{background-color:#F2F2F2;border:1px solid #808080;border-top:none;padding:0;margin:0 0 2px 0;}.yui-skin-sam .yui-editor-panel .hd span.close{background:url(sprite.png) no-repeat 0 -300px;cursor:pointer;display:block;height:16px;overflow:hidden;position:absolute;right:5px;text-indent:500px;top:2px;width:26px;}.yui-skin-sam .yui-editor-panel .ft span.tip{background-color:#EDF5FF;border-top:
 1px solid #808080;font-size:85%;}.yui-skin-sam .yui-editor-panel .ft span.tip strong{display:block;float:left;margin:0 2px 8px 0;}.yui-skin-sam .yui-editor-panel .ft span.tip span.icon{background:url(editor-sprite.gif) no-repeat 0 -1260px;display:block;height:20px;left:2px;position:absolute;top:8px;width:20px;}.yui-skin-sam .yui-editor-panel .ft span.tip span.icon-info{background-position:2px -1260px;}.yui-skin-sam .yui-editor-panel .ft span.tip span.icon-warn{background-position:2px -1296px;}.yui-skin-sam .yui-editor-panel .hd span.knob{position:absolute;height:10px;width:28px;top:-10px;left:25px;text-indent:9999px;overflow:hidden;background:url(editor-knob.gif) no-repeat 0 0;}.yui-skin-sam .yui-editor-panel .yui-toolbar-container{float:left;width:100%;background-image:none;border:none;}.yui-skin-sam .yui-editor-panel .yui-toolbar-container .bd{background-color:#fff;}.yui-editor-blankimage{background-image:url(blankimage.png);}.yui-skin-sam .yui-editor-container .yui-resize
 -handle-br{height:11px;width:11px;background-position:-20px -60px;background-color:transparent;}
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamslidercss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/slider.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/slider.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/slider.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+.yui-h-slider,.yui-v-slider,.yui-region-slider{position:relative;}.yui-h-slider .yui-slider-thumb,.yui-v-slider .yui-slider-thumb,.yui-region-slider .yui-slider-thumb{position:absolute;cursor:default;}.yui-skin-sam .yui-h-slider{background:url(bg-h.gif) no-repeat 5px 0;height:28px;width:228px;}.yui-skin-sam .yui-h-slider .yui-slider-thumb{top:4px;}.yui-skin-sam .yui-v-slider{background:url(bg-v.gif) no-repeat 12px 0;height:228px;width:48px;}.yui-skin-sam .yui-region-slider{height:228px;width:228px;}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamsplitbuttonarrowactivepng"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/split-button-arrow-active.png (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/split-button-arrow-active.png                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/split-button-arrow-active.png        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,5 @@
</span><ins>+\x89PNG
+
++IHDR2bI\xABngAMA\xD6\xD8\xD4OX2tEXtSoftwareAdobe ImageReadyq\xC9e&lt;BPLTE\xE8\xF2\xFF\xBA\xD8\xFF}\x98\xB8\xE6\xF1\xFF\xC7\xDF\xFF\xD1\xE6\xFF\xCB\xE2\xFF\xDA\xE9\xFF\xBF\xDA\xFF\xE7\xF2\xFF\xC4\xDD\xFF\xE7\xF1\xFF\xD5\xE7\xFF\xD7\xE8\xFF\xCF\xE3\xFF\xE5\xF0\xFF\xDC\xEC\xFF\xE3\xF0\xFF\xE2\xEE\xFF\xE0\xED\xFF\xDF\xED\xFF\xDBR]\xFB\IDATx\xDA\xEC\xC8I\x82@\xC1\xB2AE\xC0\xED\xFF_f\xBC\xB4\xE1 \xF3\xD2 \xFB&gt;N        /        \xBB\x84}\xC29\xE11\xE15\xE1\x94pHxK\xF8Z\xB5\xD5V\xF1\xB9)\xBB4|\xEB\xAE\xEFU\xFBI\6\xE9\xC71&amp;&lt;'\xE4\xCB\xFFou@+\x82\x8F)8\xC5IEND\xAEB`\x82
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamsplitbuttonarrowdisabledpng"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/split-button-arrow-disabled.png (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/split-button-arrow-disabled.png                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/split-button-arrow-disabled.png        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,5 @@
</span><ins>+\x89PNG
+
++IHDR2bI\xABngAMA\xD6\xD8\xD4OX2tEXtSoftwareAdobe ImageReadyq\xC9e&lt;        PLTE\xCC\xCC\xCC\xFF\xFF\xFFI0\xE0\xC9tRNS\xFF\xFF\xD7\xCA+A'IDATx\xDAb``B \xA3\x83G\x80\x90T\xC0\xF9p-0&gt;\xC2 \xC6\xD1 @\x80\xA1\xCDÛ‚\xB4\x89IEND\xAEB`\x82
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamsplitbuttonarrowfocuspng"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/split-button-arrow-focus.png (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/split-button-arrow-focus.png                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/split-button-arrow-focus.png        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,5 @@
</span><ins>+\x89PNG
+
++IHDR2bI\xABngAMA\xD6\xD8\xD4OX2tEXtSoftwareAdobe ImageReadyq\xC9e&lt;        PLTE}\x98\xB8\xFF\xFF\xFFm\xCEE\xD3tRNS\xFF\xFF\xD7\xCA+A'IDATx\xDAb``B \xA3\x83G\x80\x90T\xC0\xF9p-0&gt;\xC2 \xC6\xD1 @\x80\xA1\xCDÛ‚\xB4\x89IEND\xAEB`\x82
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamsplitbuttonarrowhoverpng"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/split-button-arrow-hover.png (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/split-button-arrow-hover.png                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/split-button-arrow-hover.png        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,5 @@
</span><ins>+\x89PNG
+
++IHDR2bI\xABngAMA\xD6\xD8\xD4OX2tEXtSoftwareAdobe ImageReadyq\xC9e&lt;        PLTE}\x98\xB8\xFF\xFF\xFFm\xCEE\xD3tRNS\xFF\xFF\xD7\xCA+A'IDATx\xDAb``B \xA3\x83G\x80\x90T\xC0\xF9p-0&gt;\xC2 \xC6\xD1 @\x80\xA1\xCDÛ‚\xB4\x89IEND\xAEB`\x82
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamsplitbuttonarrowpng"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/split-button-arrow.png (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/split-button-arrow.png                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/split-button-arrow.png        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,5 @@
</span><ins>+\x89PNG
+
++IHDR2bI\xABngAMA\xD6\xD8\xD4OX2tEXtSoftwareAdobe ImageReadyq\xC9e&lt;        PLTE\x80\x80\x80\xFF\xFF\xFF&gt;\xA5\xA0\xB5tRNS\xFF\xFF\xD7\xCA+A'IDATx\xDAb``B \xA3\x83G\x80\x90T\xC0\xF9p-0&gt;\xC2 \xC6\xD1 @\x80\xA1\xCDÛ‚\xB4\x89IEND\xAEB`\x82
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamspritepng"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/sprite.png (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/sprite.png                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/sprite.png        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,39 @@
</span><ins>+\x89PNG
+
++IHDR(f\xBD\x9Dm$tEXtSoftwareAdobe ImageReadyq\xC9e&lt;PLTE\xD7\xD8\xDA\xC1\xC1\xC1\xFE\xFE\xFEmmm\xFC\xFC\xFC\xFB\xFB\xFB\xF5\xF5\xF5\xFA\xFA\xFA\xF7\xF7\xF7\xE3\xE3\xE5\xE7\xE8\xE8\xEF\xF0\xF0Bo\xD9\xE6\xF1\xFF\xDF\xE0\xE0\xEC\xEC\xEC\xE1\xE1\xE2\xF2\xF2\xF2\xF6\xF6\xF6\xE0\xE1\xE2\xF5\xF5\xF6\xEB\xEB\xEC\xE1\xE2\xE3\xE7\xF1\xFF\xF1\xF1\xF2\xE5\xF0\xFF\xF7\xF7\xF9An\xD7\xF2\xF4\xF4\xEB\xEC\xEC\xCB\xE2\xFF\xDF\xED\xFF\xE8\xEA\xEA\xE0\xED\xFF\xDC\xEC\xFF\xE2\xEE\xFF\xD1\xE6\xFF\xF9\xF9\xFA3[\xBC\xC7\xDF\xFF\xD5\xE7\xFF\xC4\xDD\xFF?jÑ…\x85\x85\xCF\xE3\xFF\xD7\xE8\xFF\xDF\xE0\xE1\xE3\xF0\xFF\xED\xEF\xEF\xFA\xFA\xFB\xE7\xF2\xFF\xDA\xE9\xFF\xDE\xDF\xE0\xE5\xE6\xE6\xF9\xF9\xF9\xE0\xE0\xE1\xE2\xE3\xE3&quot;&quot;&quot;\xE6\xE7\xE8/&gt;\xAC\xEA\xEA\xEB\xDA\xDA\xDB\xDC\xDC\xDD\xD0\xD1\xD2\xE7\xE8\xEA\xD7\xD7غ\xD8\xFF\xEC\xEC\xED\xBE\xC1\xC2\xF1\xF2\xF2\xF4\xF4\xF4\xC4\xC5\xC6\xDD\xDDß³\xB5\xB7\xE8\xE8\xEA\xF9\xFA\xFA0V\xB5.R\xB0\xF4\xF5\xF5@l\xD5\xD4\x
 D5\xD6@m\xD69aĸ\xBB\xBD\xC9\xCA\xCB\xF5\xF6\xF67_¬\xAF\xB0=g\xCE;e\xCB9c\xC8\xEC\xED\xED\xEF\xEF\xEF@k\xD4\xF0\xF0\xF1\xF0\xF0\xF0\xF0\xF1\xF1\xF1\xF1\xF1\xF2\xF2\xF4(L\xA6+N\xAB\xED\xED\xEF\xE5\xE5\xE6\xF6\xF6\xF7\xCC\xCE\xD0\xF644\xE1w\x9D\x9D\x9D\xED\x89\xF1\xD2X(1\x93\xA5\xCB\xFF\xE1z\xB1\xB1\xB1\xF9\xBC\xBC\xE8\xAB;\x96\xAA\xC3\xCA\xCE\xE9\xE7\xA4=\xEA\xC0)\xEA\xBD7\xE9\xBA%׳(\xF8 sss\xEB\xC25\xF9\xE8\xB6\xE8\xB2:n\x8A\xAC\xF5GG\x96\x96\x96\xE9\xB78\xF8\xF3\xCE&lt;\xE8\xA7\xF8$$\xF3RGK\xE6\x9C?\xD4III\xE5h\xA1s.7\x9C\xF5\xCBL\xE6\xB2\xE1\xE7\xEF\xF8a^\xE8\x92B\xE6\x9A\xE7~\xE6\xE6\xE6\xD51\xE6\xDA\xC1Ú£+$*\x91jjj\xF1\xD4F\xCC|
+\xF0\x9A4;C\x9B\xF5\x8F\x8F3C\xAC\xF1\xB3\x87Ä–\xB9\xBA\xD7\xF1\xD5g\xF4uu\xFAКDY\xB3j\xFB\xD5\xD5-+k\xF6\xE0S\xDCM\xFA\xE7\xCA\xE4\x8A׆\xF8×¾\x81\x99\xB7 $\x81\xFB\~\xCA\xE9y\xE8t%+\x87\xE8\xE8\xE8\xF7UU\xF6jj\xB4\x93H\xF4È¢\xE0YαL\x84\x87\xC1\xF7Ä€\xE2a+\xF5\xB2U~\xAC\xAD\xB1\xC4Rc\xBA\xEE\x8F)\xAD\x86&quot;$w\xF5\xE0\x8C&lt;Q\xB6\xFCqw\x9E\xA3\xD1\xE5\xCAM\xA4\xAB\xDB\xFB\xEA\xDF\xE6v.\xE1\xEE\xFF\xDF\xC9u\xFD\xEF\xE2\xEBVW\xED\x8B!\xF3\xA3;\xF0\x96,\xD6&lt; \xD9Æ‹\xF6zz\xE1twt\x93\xE4\xCEv\xEA
+ Mh\xC3ζn\xF9\xEB\xA8\xF9\xC5\xC5\xF2\xF9\xFFs\x86\xCE\xFB\xD7PϷ\x87\xF1\xA8a\xFB\xEDl\xFE\xFD\xF4\xDB\xC0M\xEA\x91a\xF6\xDA}\xA4\xA4\xA5:M\xB2\xED./Qo\xC6fff&amp;G\xA0\xE6\xE6\xE7\xDB\xDCݿ\xDA\xFF\xA5\xA8\xAB\xD8\xD8\xDA\xDC\xDD\xDF\xE8\xF2\xFF\xFF\xFF\xFF\xFF\xFF\xFFXwxtRNS\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\
 xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFFS\xF7%
++IDATx\xDA\xEC\xDCw\\xE7\xF09Gq\xD3a\x9AD8i\x9B\xB4\xE9Hm\xBA\xC6\xBBM\xF7\xDE{ï‚„l\x86m\xC0l06l\xEC\xA4 \xC6\x82k\xD7q\xBC\xE3\xEDx\xC5\xCEh\x9A\xD5\xCCf4\xDD;mS)\xEF\x9DpL\xA4Ó½\x8Fc\x90x\x9E?}\xBE\x9FW\xF7Þt\xBF{ß»\x93GxN#ç‚‘\xF3\xC0\xC8U`\xE4\xA7`\xE43`\xE4\xC3`\xE4\xC5`\xE4\x83`\xE4r0\xF2&gt;02\x8C&lt;+F\xFE\x86\x90\x90\x90\x90\x90\x90\x90\x900a !a\x82\xC3d0c/#\xE9`\xE4\xBD`\xE4c`d\xC9##\x9F#\xB3\xC1\xC8\xCF\xC0È—\xC0\xC8G\xC1ȇ\xC0\xC8\xC1\xC8\xC7\xC1\xC8W\xC1\xC8\xC1N \xC8\xD3=B\xC23\x83\xB1\x9F\x8C\x8F\xFD\xFB`d*\xB9\x8C\xB8\xC0È¥`\xE40\xF20\xF2-0\xF2M0r\xC9#\xEF#3\xC1\xE0 \xBC ~e&lt;xu%|\xF0\xEA)0\x84\x84\x84\x84\x84\x84\x84\x84\x84\xE1\x90ç…„\x84!\x98d\x9F\x98ep \xE9\xECa\x9EK\xBD\xB8\xF2\xB40\xCFHu\\xA9F\x9E*\x93:-\xD5Ôº\x8FV\xB2\xF4\xB4s\xEAÌ´R\xA3t\xD0\xB4Ex\xBD#\xBD\xF6j[\xF4\xBA\x9E}\x8DÑ–\xD1Ax\xEFá·\x90\x90\x90pbWN0\xC9\xE9Pp\xD00\xC6#\x89\xC7\xCE\xC4x\xCB\xC0;\xBF\\x84\x84\x84\x84\xA
 C\xE2\x8EI\x90 \xAB\x87!!!\xE1d\xAB\xC6i\xE09s\xCEp\xD4\x80#t\x8D_׌Ùr\xD0k)Pg\xE0\xE1e \x8C\x9EЭG\xAF+\xC6[\x86\xB3\x84\x84\x84\x84\xACÆ°\xC8sa0oL\x8E\xAE\xD0u\x81@\x8Aq\xFA8\x8B\xE1e\xC4{\xEDuż6c@HHH\x98\xA8Ѐ#        \xB9i0\xC9\x88܆f6e\xDA\xC1\x88\x9Bwd\xB8\xBB\xC2Þ²`\xF8\xBD\x8933\xDC3\xC3Þ³`\xD8\xE3\xAFQ\xEE\x9A\xF0g[0\xEC\xD6\xC4&amp;\xB7{v\xC4\xFD\x8A\xBCè¹™\xAEZ\x9C\xF6\xDEE|yXÒ•L{Ï‚\xCF\xF5\x9D\x95\xE1n
+{Ë‚\xD3&quot;\x92Õ”\xF6\x8E\xCFbA\xE4\x86&lt; \xBE \x88\xA1\xF8\xCE_
+BBBV\x89T\x99Q`\xD8\xC1\xBEË\xB1#\xA2(\xB0\xAB\xEC
+\xDB
+\xC0\xB6\xB0\xAB\xA6N\x9D\xEDv7\x80m        `W\xD8\xB6\xC0?\xDD\xB3&quot;\x8A\xDB
+ \xE2\xF0\xCF
+\x80\x90\x90\x900\xFE\xE1_K\x8DR/S\xAB\x93\xC9Õ©Zè­¶\x8E\xDCÕº6\xA54Ù‚É¥:h\x8CF\xCCZ\xACY\xC6\xEA\x98\xF5:\xACV뱚\xBB!!!!a\xDC\xC0\x9B+++ xC\xE1\xD2\xC0\xD2\xC2\xB4\xB0\xB0\xF0Ws\xE6̹\xB8PצT.\x9Dcfi\xA5,\xF8xe\xCCZ\x84\x97\xD1\xEC\xF5\xE3H\xAF\x83\xC1Bp=r$$$$$\x9C0\xC1\xAF\xC8Ì„f\xA6\xECȈ\x9C\x882 ]`\xCEDND\xCE\xCCPh\x86\xF5\xA2\x99\xE8\xB2f\xA6g\xB8\x9B4\xB3\xE9M\xE9\xA3\xFEh\xAE\xB0I\x94\xEB8 \xC0\x9FBBBV\xF1u% v\x80ml*\x80.\xEB\xE0?\xB3KWtYUtŪ\xB0\xAE\x88\xBC \xCAu\xE0\x95\x80\xB32&quot;/\xB0\xAF\xB2\xB2X\xF0'\x85\x90\x90\x900\xF1\xA0;\xA0E{g\xF7Ѷ\xCEv\xDD\xDC2\x84\x84\xE3        \xD3BZ\xB4wvm\xEBl\x971\x8D[\x86\x90\xF0\x85\x84n\xBAa膡;\xD6-ƺ\xD7\xDC{\xA6\xC10+\x86i0L\x8Bu\x8B\xB1\xEE5\xF7\xC2I\xD1q\xF4\xD4,\xC0\x87\xB8                        \xC7 \xA2'\xE2\xE8\xA9=:X\x80?p\xC6\xBAA\x9Cd[\xE7\xD7n\xBA!,pC\x9DAG\x90s\xEF!\x9C40+\x84\xC0I\xB6u~\x9D\xC14È… ҠΠ\xA3
+H\x8F\xB9\xF7LJXV\xA6\x879\xC1\xE0ueeEE\xD7\xCD\xA3\xC3S\xAE\xA8\xC6Y\xCA|\xE5\x8A\xCAÛŠjj\x94\x9C︌#\xAE\xA2\xA2AÓ™\xA2\xA2@\x9B\xE9*:\xB4\xB0\xBCM\xB1\x82\x82+\xAC\xA9\xF9K\x9Bbóµ°¢\xAD\xCDt:X^Q\xDEf\xB2\xF9+9\xE5N\xF0\xB4kp\x94\x92Sp\x8A5tt8\xAD\xF0\x82\x9CQ\xE9\xD0\xEE99\xFC\xCE&amp;6\xCC?\xB1D\xE5D\xBE\xE6/Y\xB6l\xD9\xCE%U\xD9\xF9\xCE\xD0t;\xAB\x9C\xA5\x98\xAE\xEA\xEA\xBF\xD5\xD9\xD9NRnܵ\xCBr\xC1A\xE0\x92\x9Fm/{q\xB63 Û™m\xC1Z+\xBC\xDFTU\x8F\xAD^\xDC\xE8\xABvY\x8De\xAF\xEF\xAFu\x82\xEAU\xAC^d\xD7\xFE\xDD\x9EPl\xA7\xD5\xEDÕµ w9\xAD\xC7\xDA\xDA\xDAeV\xBF.l\xCCw\xDC2J\xD6VU-vvÖ¶^Jc\xBEv\xEF\xB9\xEB\xE1\xC6Ƈ\xEF\xCAç—‹\x90\x90\x900\xEE\xE0\xF1E*\xB9ǵP\xA9\xDF-XP\\x9C\xAB\x81\xB9J\x99N'E)%r\xDB\xDBÛ—k`q\xB1\xF9WÉ\xCE\xF0x\xAE\xF9\x91\xB9uuu\xBFV\x8F\xE5r\xF5p!XW\xB7\\xE7Bp\xB9Þ\x82\xABb \xE1\xBDg\xE3F\xB0E\xAEZ\xEBe$$$$$&lt;K\xB8\xAF\xB7\xB3\xB3\xB3w\x9F\xAEmm\xBA\xA5\xCF\xD3\xDA\xE9_\xEB\xD7v\xFD\xA3\xEF\xB6\xC0m\x8F\xF3Z'\xD8:\
 xF4\x88\xC73/0Ï£\xE4v\xB8\xAFoK\x9F\xC73t\xF8\xB0\x82\x9E͇\xA2\xC3Þ¾!%\x9E8\xF9\x84        \xFD\xEB\xA3\xC3ο\xA9G&gt;\xDAÓº\xCEn\xB9\xE54\xF4\xD4G\x87\x9BGC\xBF\xEC=\xFC\xC8l\xF5\xFB\x8F9,\xE3\xA1\xDE-\xAD\xAD\xAD
+\xFAU\xEAtX\x8Fۇz\xFD\xFE\W\xEF\xB8e\xD6m\xF6\xFBO\xCE;i\xBA\x9B\x9D\xB7\xF5\xFAuǶ\xFB\xB7\xABwr\xA1\xBD\xE7\xD0\xFA\xFA\xFA\xFA\xF5\xF2\xCBEHHHw\xF0\xA1\x95;\xF5\xF0O\xB7&gt;Z\xDE]V\xB2W\xBA\xF5\x8F\xE5\xBA-(\xF9\xAD\x96&lt;Z\xFE\xF7\xEB`\xF7\x86+&amp;l\xD7\xC2E\xDD\xDD\xC3\xC3e\xC5\xEDG5\xF0Β\xB2\xB2\x81\x81\xE2\xF6~\xDD2\xF7\x96 \xB4\xF7ߤ_\x8F{W \xAC&lt;
+\xAC\xF0߬T\xB9        \x81-*\xFC\xB9&gt;\xD9R\xB2k\xF1hË“\xD0n\xD6\xD2\xC2/!!!a&lt;\xC2\xFF\x83O\xF8n0r1y)\xBE\x8C\xBC\x8C\xBC\x8C\xBC\x8C\xBC\x8C\xBC\x8C\xBC\x8C\xBC\x8C\xBC\x8C\xBC\x8C\xBC+\x8C\xBC\x8C\xBC        \x8C\xBC\x8C\xFC !!!!!!!!a8\xE4\xE9!\xE1\x99\xC1\x97\x80O\xF8*08\xFC&lt;\xF9,\xF96y+~+\x8C|\x8C|\x8C|\x8C|\x8C\xBC ?F&gt;+F~F~F\xFE\x86\x90\x90\x90\x90\x90\x90\x90\x900\xF2t\x8F\x90p\x8C`L\\xC0s\xC0\x8C\x9C\x87ç‚‘\xF3\xC0\xC8`\xE4\x95`\xE40\xE2##\x97\x80\x91ï‚‘\x83\x910\xF2        0\xF2o0\x84\x84\x84\x84\x84\x84\x84\x84\x84á§{\x84\x84\x93x \x80\x90\x900\xF1`&lt;\x8C\xED\xC1Cv\xEF#\x9F3\x9ECv?#\xDF#\xEF#\x97\x81\x91\xCB\xC1\xE0\x85\xE6 0r%y
+\x8C0 \xC30\xF6\xE1\xE9!\xA1\xAF\x83ß‘\xDF+\xDFV+ߨ+\xDF\xFA+\xDFLßž\xDF\xF0\xDFBß”\xDF\xE6?8~\xFCp\xF8q        \xB1R\xFC\x90\xF8\xB1\xF1\xF0 +BBBBBBB\xC2\xC9y\xBAGH\x98x\xD3\xFB        5iw\x99
+F\xBE F.#\xDF\x83\xCF\xC5\xC1WÅŸF~F.#O\x83!$$$$$$$$\x9C@\x90\xA7{\x84\x84\xCF\xAEin^\x83\xC0M\xCD=\xF76o`\xC7\xDD\xFBn\xEB\xD0\xC3\xDD\xCD\xBF\xF65\xEF\xD6\xC2G\xF6\xBEm9:\xB8f\xDB=\xF49\xF6G\xC1Û·\xF5\xF4\xF4\xA8\x8F\xF6m=p\xBB#\xFC\xFD\xD6{|\xBE\xC0\xB0\xCF\xE7;\xF0g'8\xDC\xDCs\xB7\xCF7\xBC_\xC1\xD7or\x80[\xEFU\xA6\xE7\x88        \xF7\xDC\xAAu\xADÈ‘M\xBBWÌ;7\xE7Ú¨\xFD\x91\x8E\xAD+T\x81\xB9f\xF6\xDCx\xC0\xBB\xD7Xh\x8C
+\xEFس\xE7z\x95k\xAD46\xDE\xC7\xEF !!!a&quot;\xC2$(AI†\xEC\x93&amp;t\xE5aЕj\xE4!P\xB9Tm\x9D\xF4F
+\xD4\xB8Ex-\xE9×£\xD75á·µ-\x84\xF7p\xFER\xB2H\xA4
+ Ï…\xC1&lt;\xBB\x83\xEB uN1\xB0\xC3\xF0h\xAF\xBD\xAEx\xA8\xF6X\xB28c\xE8\xF2z]`\x86Mg##\xA0y\xB4NI\x89&lt;dG\xC0P\x8Dy\xCE\xF9Ñ¡\xAA'â \x94è›!!!!+\x80\xB1\x83\xE8\xD1&gt;^\xC3\S\xE0U
+^\xF7\xB0\xE0/!!a\xC2\xC1g\xBD\x9Dp\xE3x\x8BIEND\xAEB`\x82
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamtabviewcss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/tabview.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/tabview.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/tabview.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,8 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+.yui-navset .yui-nav li,.yui-navset .yui-navset-top .yui-nav li,.yui-navset .yui-navset-bottom .yui-nav li{margin:0 .5em 0 0}.yui-navset-left .yui-nav li,.yui-navset-right .yui-nav li{margin:0 0 .5em}.yui-navset .yui-content .yui-hidden{border:0;height:0;width:0;padding:0;position:absolute;left:-999999px;overflow:hidden;visibility:hidden}.yui-navset .yui-navset-left .yui-nav,.yui-navset .yui-navset-right .yui-nav,.yui-navset-left .yui-nav,.yui-navset-right .yui-nav{width:6em}.yui-navset-top .yui-nav,.yui-navset-bottom .yui-nav{width:auto}.yui-navset .yui-navset-left,.yui-navset-left{padding:0 0 0 6em}.yui-navset-right{padding:0 6em 0 0}.yui-navset-top,.yui-navset-bottom{padding:auto}.yui-nav,.yui-nav li{margin:0;padding:0;list-style:none}.yui-navset li em{font-style:normal}.yui-navset{position:relative;zoom:1}.yui-navset .yui-content,.yui-navset .yui-content div{zoom:1}.yui-navset .yui-content:after{content:'';display:block;clear:both}.yui-navset .yui-nav li,.yui-navset .yui
 -navset-top .yui-nav li,.yui-navset .yui-navset-bottom .yui-nav li{display:inline-block;display:-moz-inline-stack;*display:inline;vertical-align:bottom;cursor:pointer;zoom:1}.yui-navset-left .yui-nav li,.yui-navset-right .yui-nav li{display:block}.yui-navset .yui-nav a{position:relative}.yui-navset .yui-nav li a,.yui-navset-top .yui-nav li a,.yui-navset-bottom .yui-nav li a{display:block;display:inline-block;vertical-align:bottom;zoom:1}.yui-navset-left .yui-nav li a,.yui-navset-right .yui-nav li a{display:block}.yui-navset-bottom .yui-nav li a{vertical-align:text-top}.yui-navset .yui-nav li a em,.yui-navset-top .yui-nav li a em,.yui-navset-bottom .yui-nav li a em{display:block}.yui-navset .yui-navset-left .yui-nav,.yui-navset .yui-navset-right .yui-nav,.yui-navset-left .yui-nav,.yui-navset-right .yui-nav{position:absolute;z-index:1}.yui-navset-top .yui-nav,.yui-navset-bottom .yui-nav{position:static}.yui-navset .yui-navset-left .yui-nav,.yui-navset-left .yui-nav{left:0;righ
 t:auto}.yui-navset .yui-navset-right .yui-nav,.yui-navset-right .yui-nav{right:0;left:auto}.yui-skin-sam .yui-navset .yui-nav,.yui-skin-sam .yui-navset .yui-navset-top .yui-nav{border:solid #2647a0;border-width:0 0 5px;zoom:1}.yui-skin-sam .yui-navset .yui-nav li,.yui-skin-sam .yui-navset .yui-navset-top .yui-nav li{margin:0 .16em 0 0;padding:1px 0 0;zoom:1}.yui-skin-sam .yui-navset .yui-nav .selected,.yui-skin-sam .yui-navset .yui-navset-top .yui-nav .selected{margin:0 .16em -1px 0}.yui-skin-sam .yui-navset .yui-nav a,.yui-skin-sam .yui-navset .yui-navset-top .yui-nav a{background:#d8d8d8 url(sprite.png) repeat-x;border:solid #a3a3a3;border-width:0 1px;color:#000;position:relative;text-decoration:none}.yui-skin-sam .yui-navset .yui-nav a em,.yui-skin-sam .yui-navset .yui-navset-top .yui-nav a em{border:solid #a3a3a3;border-width:1px 0 0;padding:.25em .75em;left:0;right:0;bottom:0;top:-1px;position:relative}.yui-skin-sam .yui-navset .yui-nav .selected a,.yui-skin-sam .yui-na
 vset .yui-nav .selected a:focus,.yui-skin-sam .yui-navset .yui-nav .selected a:hover{background:#2647a0 url(sprite.png) repeat-x left -1400px;color:#fff}.yui-skin-sam .yui-navset .yui-nav a:hover,.yui-skin-sam .yui-navset .yui-nav a:focus{background:#bfdaff url(sprite.png) repeat-x left -1300px;outline:0}.yui-skin-sam .yui-navset .yui-nav .selected a em{padding:.35em .75em}.yui-skin-sam .yui-navset .yui-nav .selected a,.yui-skin-sam .yui-navset .yui-nav .selected a em{border-color:#243356}.yui-skin-sam .yui-navset .yui-content{background:#edf5ff}.yui-skin-sam .yui-navset .yui-content,.yui-skin-sam .yui-navset .yui-navset-top .yui-content{border:1px solid #808080;border-top-color:#243356;padding:.25em .5em}.yui-skin-sam .yui-navset-left .yui-nav,.yui-skin-sam .yui-navset .yui-navset-left .yui-nav,.yui-skin-sam .yui-navset .yui-navset-right .yui-nav,.yui-skin-sam .yui-navset-right .yui-nav{border-width:0 5px 0 0;Xposition:absolute;top:0;bottom:0}.yui-skin-sam .yui-navset .yui-
 navset-right .yui-nav,.yui-skin-sam .yui-navset-right .yui-nav{border-width:0 0 0 5px}.yui-skin-sam .yui-navset-left .yui-nav li,.yui-skin-sam .yui-navset .yui-navset-left .yui-nav li,.yui-skin-sam .yui-navset-right .yui-nav li{margin:0 0 .16em;padding:0 0 0 1px}.yui-skin-sam .yui-navset-right .yui-nav li{padding:0 1px 0 0}.yui-skin-sam .yui-navset-left .yui-nav .selected,.yui-skin-sam .yui-navset .yui-navset-left .yui-nav .selected{margin:0 -1px .16em 0}.yui-skin-sam .yui-navset-right .yui-nav .selected{margin:0 0 .16em -1px}.yui-skin-sam .yui-navset-left .yui-nav a,.yui-skin-sam .yui-navset-right .yui-nav a{border-width:1px 0}.yui-skin-sam .yui-navset-left .yui-nav a em,.yui-skin-sam .yui-navset .yui-navset-left .yui-nav a em,.yui-skin-sam .yui-navset-right .yui-nav a em{border-width:0 0 0 1px;padding:.2em .75em;top:auto;left:-1px}.yui-skin-sam .yui-navset-right .yui-nav a em{border-width:0 1px 0 0;left:auto;right:-1px}.yui-skin-sam .yui-navset-left .yui-nav a,.yui-skin-sa
 m .yui-navset-left .yui-nav .selected a,.yui-skin-sam .yui-navset-left .yui-nav a:hover,.yui-skin-sam .yui-navset-right .yui-nav a,.yui-skin-sam .yui-navset-right .yui-nav .selected a,.yui-skin-sam .yui-navset-right .yui-nav a:hover,.yui-skin-sam .yui-navset-bottom .yui-nav a,.yui-skin-sam .yui-navset-bottom .yui-nav .selected a,.yui-skin-sam .yui-navset-bottom .yui-nav a:hover{background-image:none}.yui-skin-sam .yui-navset-left .yui-content{border:1px solid #808080;border-left-color:#243356}.yui-skin-sam .yui-navset-bottom .yui-nav,.yui-skin-sam .yui-navset .yui-navset-bottom .yui-nav{border-width:5px 0 0}.yui-skin-sam .yui-navset .yui-navset-bottom .yui-nav .selected,.yui-skin-sam .yui-navset-bottom .yui-nav .selected{margin:-1px .16em 0 0}.yui-skin-sam .yui-navset .yui-navset-bottom .yui-nav li,.yui-skin-sam .yui-navset-bottom .yui-nav li{padding:0 0 1px 0;vertical-align:top}.yui-skin-sam .yui-navset .yui-navset-bottom .yui-nav a em,.yui-skin-sam .yui-navset-bottom .yui-
 nav a em{border-width:0 0 1px;top:auto;bottom:-1px}
+.yui-skin-sam .yui-navset-bottom .yui-content,.yui-skin-sam .yui-navset .yui-navset-bottom .yui-content{border:1px solid #808080;border-bottom-color:#243356}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamtreeviewloadinggif"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/treeview-loading.gif (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/treeview-loading.gif                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/treeview-loading.gif        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,27 @@
</span><ins>+GIF89a\xF7\xDC\xFA\xFA\xFA\xF9\xF9\xF9\xF7\xF7\xF7\xF6\xF6\xF6\xF8\xF8\xF8\xF5\xF5\xF5\xEF\xEF\xEF\xF2\xF2\xF2\xF3\xF3\xF3\xF0\xF0\xF0\xE8\xE8\xE8\xF1\xF1\xF1\xD1\xD1\xD1\xF4\xF4\xF4\xD3\xD3\xD3\xEC\xEC\xEC\xEB\xEB\xEB\xD9\xD9\xD9\xEE\xEE\xEE\xDF\xDF\xDF\xE2\xE2\xE2\xCE\xCE\xCE\xD7\xD7\xD7...---\xD2\xD2\xD2\xDE\xDE\xDE\xDA\xDA\xDA\xE1\xE1\xE1~~~\xA2\xA2\xA2___vvvoooVVVTTT^^^\x8C\x8C\x8C///&lt;&lt;&lt;PPP333\xE0\xE0\xE0&quot;&quot;&quot;   \xD6\xD6\xD6\xE7\xE7\xE7\xCA\xCA\xCA\xDC\xDC\xDC\xE9\xE9\xE9\xD5\xD5Õœ\x9C\x9C\x97\x97\x97uuu\x8A\x8A\x8A\xCB\xCB˃\x83\x83\xAE\xAE\xAE\xA4\xA4\xA4\xC9\xC9\xC9+++\xAD\xAD\xADKKK,,,666aaammmSSS444;;;\xD8\xD8\xD8\x88\x88\x88777\xB6\xB6\xB6\xB4\xB4\xB4\x98\x98\x98\xC5\xC5\xC5xxxYYY\xB8\xB8\xB8sss\xAA\xAA\xAA(((\xDB\xDBÛ¬\xAC\xAC\x9F\x9F\x9F\xA9\xA9\xA9###\x94\x94\x94\xB1\xB1\xB1yyy\xCD\xCDÍ“\x93\x93\x87\x87\x87!!!hhhRRR\xE5\xE5å¹¹\xB9fffOOO]]]\x9B\x9B\x9B\xB3\xB3\xB3ttt\xA7\xA7\xA7888***)))CCCJJJ\xEA\xEA\xEA111iii\xAB
 \xAB\xAB555\xB7\xB7\xB7NNN\xC8\xC8\xC8999\xBC\xBC\xBC\\\ZZZ\xED\xED\xEDeee\xD4\xD4\xD4wwwqqq\x92\x92\x92GGG\xE6\xE6\xE6\xC7\xC7Ç•\x95\x95\x8E\x8E\x8Eggg\x8F\x8F\x8F\xB5\xB5\xB5@@@222\x81\x81\x81\x8B\x8B\x8B\xA8\xA8\xA8\x84\x84\x84===\x86\x86\x86EEE\x80\x80\x80kkkWWWppp\xC6\xC6\xC6%%%UUUHHH\xCF\xCFÏ\x9D\x9D\xBF\xBF\xBF\xE4\xE4ä‘‘\x91[[[\xE3\xE3ã»»\xBB\x9E\x9E\x9E\xDD\xDDݲ\xB2\xB2|||\xA3\xA3\xA3:::$$$&amp;&amp;&amp;\xC0\xC0\xC0\x82\x82\x82\xD0\xD0\xD0zzz\xBA\xBA\xBA\xB0\xB0\xB0\x96\x96\x96\xCC\xCC\xCCjjj'''\x8D\x8D\x8D}}}&gt;&gt;&gt;lll\xAF\xAF\xAF\x9A\x9A\x9A\xC4\xC4\xC4LLL\xA0\xA0\xA0\xBE\xBE\xBEBBB\x90\x90\x90bbbQQQ{{{MMMrrr\xC3\xC3\xC3AAA\xC1\xC1\xC1\xA5\xA5\xA5\xC2\xC2\xC2000\xFB\xFB\xFB\xFC\xFC\xFC\xFD\xFD\xFD\xFE\xFE\xFE\xFF\xFF\xFF\xFF\xFF\xFF!\xFF NETSCAPE2.0!\xF9        \xDC,\xF9\xB9        H\xB0\xE0\xC0m$\xA8M[B\x85 \xB3]Æ-
 B\x87^#@\xDB\xC3mr\xD3F@\xC0\xB61\xB2\xEC\xB0p@[\xB6l.G\xD8\xC6J#WÚˆ`\xB1+[Ü°8\x85' \x9F4,i\xEAl\xA0\xD9TJr\xC2\xC28\\xCC\xF9 \xC0\xB6&gt;Lz\xB0M\xC05\x83\x8E\x95Ú³-\x80\xB6&amp;f+\x80@\xC0+\xB4\x9D\x92\x88\xED\x9A E?:)X`\xA0\xC16\x89\xD7h\xBB\xB6\xEDS3V\x88\xE26\xD0!\x92\xA7&amp;%\xDA\xCC\x84t%\xE9\xF2td\x80W\x86@\xB8#\xEC\x9A0@8\xB8\xC6+$B2\xCBR`\xA8\xB2J\x84\xAF\xD9j?,\xC0@Í&amp;\xAF\xD0&amp;\xFC\xE3×:\xFF\xB8\xB09\xF5\xEA\xD6Eb\xAF!\xF9        \xDC,\xFB\xB9        \xB8\xAD\xE0\xC0\x83\xB7i+\xB8+\xA1\xC3l×®-4è›\xB6`\x9B\xD8\xD0\xE15Ù´ac\xA8m\xE1Am\xB4\xC9a@\x85Ç“'
+Ć\xAD\x93\x88%a\xB4\xAC \xA2!fCl\xD9\xF4j\xA5ì©)&gt;Jp\x88\xC9m\x80\x806j%Ø–\xED\xC0\x877J  \x80\xED
+ \xB0\xAD\x82\x8AFkr\xB8\xB6펊4, @\x80\x89$        \x9B&quot;\x84\xAC\x90H
+H@\xA0`\x89:(\xB3\xBDptÎ…m
+, \xEADm\xD4È…hB\xB6m l&lt;2\xB0-\xC3m3\xB9\xE3dKM&amp;@e\xC3\xC6\xED4 zZ\xB4h\x83\xA9\x87O\xB0p\xE5\x87\xB3&lt;](J\xE0\x99+\xDCX18\xC9\xEA\x99c\xCFNq`@!\xF9        \xDC,\xF6\xB9        \xC8m\x9BA\x82n˦\xED`Â\xDA\xB8\xD6p\xDBCnÚ®@1\x9BC\x82\xDA&lt;f\xBBf\xB0\xA4E\x85 \xFA\x81\x85\xD4\x93\xB7        \xC8V\xC1Ñ‘.P\x98\xE9\xF3\x9A\x80m\xE8\\xF3\xE1\x8A&quot; \xB65Ķ0\xD6
+
+.\xF8\xF0F\xD6\xA5g\xC5Q2a \xC5Hcp\x8D\xE2\xC6VPy\x80\xA06D\x92\xEC\xE2 @Û¨P\xD6H\xC4È– \x82&lt;q\x98\x9D\x99\xF6[q
+\xC8T|-\x8B
+Un+bK\xE3ƃ\xA6
+^$\x88\x80`[\x80\x92dF\xB1E\x89\xA8M9\xB6P\xB0dBZTY\xB5\xC6\xC15'M^\xCB\xE3\x8BË°h#h\xD2\xE05l\x87#4\xA9-$\xF2\x8B\xAD+6\x87\xFD#\xF4\x92!\xF9        \xDC,\xF5\xB9        H\xB0\xA0\xC1\x83ܶ!$\xA8-\x9B6\x85\xB7a \x80@\xB6mf+\x80\xEDF&lt;L\xB8M[\x80fä¹¢!@É‹\xDCb\xEC\xA0`C\x89 )nh\xD8v\xF1#\x93.%v\xB8Ë„B9&lt;b \xB0\x8E\x84)v\xB01\x87\x8E\x8C7C\xF1%\xC2\x97\x85R        \xE9\x81u\xDB,#'\xB0=0\xC0q5;\x94b+\x93\xA1ƶkL\xB8Vl\x97\x92HDa[B\xA18\x82D&quot;\xC670\xE0\xE0p\xF7\x80        \xAB\xEA \xC0\x86[\x841Zƈ\xC0&quot;\x80\x94        w(A g&quot;$\x80\xB1I\x8C\xD98܉\x80ol\xDAb\xD5\xC6y\x9B\xB2~\x8D\xC0\xB5\xE0\xB1.\x98q\xBA\xF5\x82!\xF9        \xDC,\xEE\xB9        H\xB0\xA0\xC1\x83\xDC\xC6p\x9B\xB6\x87\xDA2\xD46Q@        \xB8\x96\xAD\xA1\xB6
+ .(\xA0\x80 \xB6m\\xA3\xC8\xC9;\xB20Q!b\xC36nCL\x82\x89 @\x84\xE8#c6\x96D,!\x81C\x81\xB6:B\xDC\xC0\xC8\xD2\xC1KX&lt;(\xF0T\x94 ,\xB71\xC1\xC0c\xDB5l3\xD5\xC9mÙšdð´­€\x81'Ù´m\x98\x8D\x81&gt; \xB0X\xD0\xC1\x91\xAF:
+Qi\x816\x8F\xA2,Y\xC35\xAC\x95(I\xD0X80D\xA7p'R\xA4O\x93\xA9\x8C$\xA3\xDA!\xB6\x93X\xCC0ã‚…+\xD8:2\xCC\x80\x80k
+Ȧ+'E\x84\xB5e#\xBEM\xA1\xF3\xE7\xD0!\xF9        \xDC,\xF6\xB9        \xC8m\xDB6\x82        \\x98P\xE1B\x83+&gt;|`P[Â…Ù¶\xC9\xC1\x92i@\x80l\xB7+\xA0\xC0\xA3\xA3&quot;\xB8p\xC0\xBC\xF4@s\xC1f\x9Bl&gt;\xC1\x93BQ\x96&quot;\x91\x90P\x88\xD1 6&quot;&gt;\xB8\xCCØ–i\xC36#`d\xBB\xA6m ;$
+l# g\xDBX\xAD\xCA\+\x80\xF3\xC2L&quot; (\x90\xAD\x86 *\xD9&lt;n\xBB\xD0&amp;\x8A\x8Fls\xE2\x82\xD66\xC0(A\xC2ʶQ\xB6)\xF8\x93\xC1\x816\xDAXTk\x9B\x97\x9E|\xF1\xE5\xA3\xC5m\xD8`p\xABÔ¥!\xE8\xBC\xD8VU`\xDCm\xB1RbË‹\x8C]\xE3\xACc\x90\xBD\xB9        f p\xA0\x81\x873\xFC\xE2\xB5l\xB8#\xB2\xACzP:\xCB\xEA!\xF9\xDC,\xFA\xB9        H\xB0\xA0\xC1\x83Û¶\x98\xB0aB\x82\xB7iÛ–\xAD&quot;6l j\x9BH\xF1ZCfÓ†m\xA2[M\xD4\xE40\xA0\xC6\x85ЦaÄ‘ (+A#c$\xB7\xB6QSe'g$\x84\xF8\xB4+c\xD9&lt;\xE0\x9A\xDB6H\x84\xA6\xC4\xC8\x80\x9BG)\x80L\xD8\xE0+\xB6!\xC0M[\xB6Wvpl#0\xA0A\x80m\xB1\xC0\x900\x9B\x8C \xE60p`Û‰eh\xE3\xD6 \xB64 \xB0Í€3=\xB6]\xE36@\x8Fg\x94T5\x85\xA0Y\x97\x8A!\xADFk!\xC8!#ܨؠ\xE3\xC6C\xCCp\x9A\x83!\x85 'r\x93X@J/R\xA4x\xEBP É†%#&gt;.=&quot;D\xE9 \xA9gßž= ;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamtreeviewspritegif"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/treeview-sprite.gif (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/treeview-sprite.gif                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/treeview-sprite.gif        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,40 @@
</span><ins>+GIF89a\xB8&quot;\xF4mmmUU\xFFj\x85\xA9\x80\x80\x80\xC1\xC1\xC1\xD2\xE6\xFF\xD5\xE7\xFF\xD8\xE8\xFF\xDA\xE9\xFF\xDD\xEC\xFF\xDF\xED\xFF\xE2\xE2\xE4\xE6\xE6\xE7\xE9\xEA\xEA\xEB\xEC\xEC\xED\xEF\xEF\xE0\xED\xFF\xE3\xEE\xFF\xE4\xF0\xFF\xE6\xF1\xFF\xF0\xF1\xF1\xF2\xF2\xF4\xF5\xF5\xF5\xF6\xF6\xF7\xF7\xF9\xF9\xFA\xFA\xFA\xFB\xFB\xFB\xFF\xFF\xFF!\xF9,\xB8&quot;\xFE`'\x8Edi\x92Ä©\xAEl\x97\xB6E,\xCFqYlx\xAE\xE3yg\xBB\x8DF\xC3\xF3e\x8EGL\x83jz\xA3sJ\xC5\.PQ\xE12\xBDz\xBD\xD9N\xC1b        \x98\xCF\xE6K\xA50p\x89+4n\x83\xD8\xEF\x8F\xCA\xE3.&lt;\x81\x82\x83}\x86\x87\x88}+\x8C\x8D\x8E\x8C} \x92\x93\x94\x92ab4\x99-\x9B\x9C\x9D\x9E\x9F\xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF\xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF\xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF\xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF\xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\
 xEF\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF
+H\xB0\xA0\xC1\x83*\È°\xA1Ç#J\x9CH\xB1\xA2Å‹3j\xDCȱ\xA3Ç C\x8AI\xB2\xA4É“(\xFES\xAA\ɲ\xA5Ë—0cÊœI\xB3\xA6͉/`\xE5\1\xA0\xA7ÏŸ=K \xA0@\xB4\xA8Q\xA2mF =\xCA4\xA9\x88\xA1\x88F\xA505\xAA\xD3\xA2j\xD5:\xA1ë„«Y%\x88\x95a\xECX\xB0 \xC89S6h\x8A $\xAC5Zx\xF3\xEAU6\x81ß¿\x80\xFD\x82E\x80\xC0\xEFÇ\x93p\xC0\xC0\x81Ç#\x835@\xB9\xB2e\xCAW\xB1\xDD|\xB3\xB3\xE7Ï C\x8BM\xBA\xB4\xE9Ó¨S\xAB^ͺ\xB5\xEB×°cËžM\xBB\xB6\xEDÛ¸s\xEB\xDEÍ»\xB7\xEF\xDF\xC0\x83 N\xBC\xB8\xF1\xE3È“+_μ\xB9\xF3\xE7УK\x9FN\xBD\xBA\xF5\xEBسk\xDFν\xBB\xF7\xEF\xE0m\xEEt5\xBEUyV\xE7W\xA5W\x95\xA2\xBD\xF7\xE1\xE3ËŸO\xBF\xBE\xFD\xFB\xF8\xF3\xEB\xDFÏ¿\xBF\xFF\xFF(\xE0\x80h\xE0\x81&amp;\xFE\xA8\xE0\x82 6\xE8\xE0\x83F(\xE1\x84Vh\xE1\x85f\xA8\xE1\x86v\xE8\xE1\x87 \x86(\xE2\x88$B\xB8^*'j\x91        +6D.
+A\xC4}$q\x84L8\xD1G82qE\\xF8\x98\xC6}\x901Wj\xB0\xE1FpI\x87w\xD8aF{@\xD0\xC7\x82LI\x88\x888`\xC6!\x8A\xF8\xF0Ș+DRÉ™\x97\xAC\xC8b\x89l\xB6\xE9\xE6\x9Bp\xC6)\xE7\x9Ct\xD6i\xE7\x9Dx\xE6\xA9\xE7\x9E|\xF6\xE9矀*è „j衈&amp;\xAA袌6\xEAè£F*餔Vj\xE9\xA5Ϥx\x8A\xA6\x9Bq\xB6SM}
+\xAAQ`Q%\x95R!\xF5\xE9VfD\xE5Xf\xC9@\xACh\xA95W\xB8\x85U\GÖ…Vy\x99\x91W|-\x98\x81\xF5U\xD8c\xC8&amp;\x96X\x91E \xD9d\x97\xFEU\x9BY\xA7@a\xAA\xED\xB6\xDCv\xEB\xED\xB7\xE0\x86+\xEE\xB8\xE4\x96k\xEE\xB9覫\xEE\xBA\xEC\xB6\xEB\xEE\xBB\xF0\xC6+\xEF\xBC\xF4\xD6k\xEF\xBD\xF8\xE6\xAB\xEF\xBE\xFC\xF6\xEB\xEF\xBFtjjJ\x9B\xA89C\x8B1\xE6c@\xBC\xE8H,q;Va1\x90_\a&gt;Xp\xC1\x91d\xF4As\x8D\\x80{\xD8Q%z\xE0q\xE5 0R\x98]\x86\x99\x8F\x98y&amp;%i\\x83z\xB2\\x8AФ=\x8AÑ¢ \x8AÒ 0\xFD\x89Óž@݉ԜP\xBD\x89\xD5-`Í‚\xD6+p\xAD\x82\xD7'\x80m\x82\xD8%\x90\x8DB\xD0h\xC7b\xF6k\x8Bжj\xA7\xAD\x93ܯ\xBCm7\xDD\xE4\xE1m\x9E\xDE\xE8\xF1+tÜ€\xCFx\xDD~\xB3W8\x8A\x87\xA3r\xF7\xE0y3\xBE\xB7\xE3}C\xFE\xB7\xE0\x94.\xB9\xE1\x97#\x9E\xB9\xE2\x89oÚ¹)\xFE\x8BWÞ¸è“\xB9\xE9\x93[\x8E:\xE6\xABk\xDE:\xE7\x9B{;\xE8\x9F]{Ñ·\x9D{Ò»/\xDD{Ó¿?|\xD4\xC3O]|\xD5\xC7_\x9D|\xD6\xCBo\xDD|\xD7\xCF}\xD8Ó]}\xD9ן=\xBB\xED\xDB\xE3Þ½\xEE\xDF\xF3\xBE\xEF\xE3_\xBE\xF0\xE7\x9F\xBE\xF1\xEB#ß¾\xF2\xE
 F3\xBF\xF3\xF3C_\xBF\xF4\xF7S\x9F\xBF\xF5\xFBcß¿\xF6\xAF\x93]i\xF7?\xB6eÏ€t\xDB\x98@\xB8+\x90{\xF4^\xC17A\xF1U\x90|4_Ñ·A\xF5u\x90}t_\xE17B\xF9\x95\x90~'\xB4_
+\xF1\xB7B\xFD\xB5\x90/\xF4_ \xA8\xBA\x8EΆ\xA5\xC3\xE1\xE9t\x98\xBA\xFA0\x87?\xDCa{\xC4&quot;
+шD&lt;\xA2\x93\xC8D\xD6\xF1ЉC\x84&quot;\xA5\xB8D*6\xD1uO\xC4b\xB58E.VÑ‹W\x84\xFE\xDD 8F\x96ÑYc\xB8F\x9E1tm\x84`%8G
+\xD6Ñ‚w\xC4`5\xB8G\xF6уa E8HÒ„\x87Da&quot;U\xB8H6Ò…\x8F\x84a$e8InQ\x8D\x97dc&amp;\xDDXI2vÒŒ\x9FD\xE3&amp;\xE58J:\x96ÒŽ\xA7\xC4c*\xF5\xB8J&gt;\xB6Ò\xAFd,9KB\xD6Ò\xB7Dd.\xB9KF\xF6Ò‘\xBF\x84d0%9LJÓ’]\xC4d25\xB9LNÓ“\xCFe4E\xD9LRV\x93|/\xD0TN\x84\xF9e\x93\x84ܤ&amp;/\xAF\x89\xCA`\xEB'B\xA9D\xA5N
+\x94\xCAUE\xA9\x8A;\xE3\x95zz\xC5*\x8B\x89\x95&gt;%\x80Y\xADW\xB5\xEA\x95]\xDA\xF0\x96$ - È‹AÚ—\xC08t0\x84\x89ha$
+\xAD\xC6@\xC61\x8F1\xFE\xA8U\xAD\xCA\xE0Z\xE7 J\x99\xF9Ee\x96\x94\xA4#u&amp;9U\xB9RV\xB6Ô•/\x85eLe9SZ\xD6Ô–7\xC5eNu\xB9\xD3q\x9ET\xA5?\xB5fPM\xD9S_\x98GfR\x89\xB9Tc6\x99C-gTY:U\x97V\xA6W\x95iVi\xBAU\x9Bv\xA7_\xD5iXy:V\x9F\xA6T\xA8g%jY\x8D\xBAV\xA4\xB6U\xA9oej\\x9D:W\xA8\xA6U\xAAw\xA5j^\xAD\xBAW\xAC\xF6U\xAB\xE5j`\xBD:X\xB0V\xAC\x87%kb\xCDj\xC5Ƃѱ&amp;],[%\xEBV\xCA\xC2Õ²r\xC5,]5kWÈ¢Ô³@\xE5,4\x9F:Úº\x96V\xB4\xD2$mjM\xBBZÔŠÓµp\x9CflU\xFBZТնj\x85\xEDk\xFB\xD8\xDEF\xB7x\xAE^\x85\xCBW\xE2\xFAÕ¸\x80E\xAE`\x95KX\xE6Ö¹\x88\x85\xAEb\xFE\xA5\xCBX\xDF~Öº\xA1\xA5\xEEd\xB5[Y\xEE^Ö»\x99\xEFf\xC5\xDBY\xEC\xDEÖ¼\xB9%\xEFi\xD5\xDBZ\xF6\xF2\xF6\xB7\xE8+n|\x87;\xDF\xE2\xD6\xF7\xB8\xF7Mn~\x97\xBB\xDF\xE6\xF6\xF7\xB9\xFF\x8Dn\x80\xA7;\xE0\xEA\xC2\xF7\xC0\xD7Epv \xBC]w\xD7\xC1ß…px%&lt;^
+\x97W\xC1\xE7\xC5pz-\xBC^\xB7\xD7\xC3\xEFM\xB0\x88\xACa\xF9\x96\x98\xBE'\xB6o\x8A\xF1\xBBb\xFD\xB6\x98\xBF/\xF6o\x8C&lt;cט\xC076\xF0\x883\xBC\xE3+\xE7\xB8\xC1?~p\x90#&lt;\xE4        \xB9\xC2G\xBEp\x8FM\xBCd7Y\xC5Ofq\x94]&lt;eWY\xC6W\xA6q\x96m\xBCewY\xC7$\xFE2\x90\xC5,d2\xD9\xCCFF3\x92Õ¬\xE40\xBB\x99\xC7o\xF61\x9B;\x9Cd:\xCF\xF9\xC3u\xC6\xF3\x9DCg&amp;\xF7\xD9\xC9\x86r\xA0\xA5&lt;h*\xDAʇ\xC6r\xA2\xB5\xFE\xBCh.7\xDAË3\x9C'-\xE7H\x8F\xD9\xD2e\xC6\xF4\x995\x9DfN\xAF\xD9\xD3m\xA6\xB4\xF9\xBEi\xC2p
+\x8C\xD4Ú´\xB3\x8D6[\xD6\xF2YÔ€\xB6\x9D{f\x9D\xE7WWÖ‚\xC65\xA1umh^#\xDA׊6\xA3\x85\xEDhbC\xDAØ’\xBE\xB5\xB2\xFD\x8C\xECK7;\xD3\xCF\xDEt\xB4;=\xEDOW;\xD4ËŽu\xB6s\xBD\xED]w\xBB\xD7\xDF\xFEu\xB8\x83=\xEEa\x97\xBB\xD8\xE7&gt;v\xBA\x93\xCD\xECu;\xDB\xDDІ\xB7\xB4\xE5Mmz[\xDB\xDE\xD8n\xB7\xBE\xB5\xBDon\xF7\xDB\xDB\xFFw\xC0\xC5=pr\xDC\xDCGw\xC2Õ½pv\xF3\xFB\xE1\xFE\x868\xC0%.p\x8A\xDC\xE2\xC78\xC25\xAEp\x8E3\xDC\xE3\x8F\xB8\xC8'&gt;\xF2\x8A\x97\xFC\xE2'\xCFx\xCA7\xBE\xF2\x8E\xB7\xFC\xE3/9\xC9gnr\x9A\xA3\xDC\xE6*\xC79\xCBu\xEEr\x9E\xC3\xDC\xE72\xAF\xB9\xD0o&gt;\xFE\xF4\x9C}\xE7G\xEFy\xD2\xBE\xF4\xA0\xFD\xE9F\x87:Ò¥\xAEt\xAA3\xDD\xEAN\x8F\xBAÖ§\xBE\xF5\xAAw\xFD\xEA_\xCF:\xD7\xC7\xEEu\xB2\x83\xDD\xECb/\xBB\xDAϾ\xF6\xB4\xB3\xFD\xEDn\x8F\xFB\xBB&gt;w\x90\xD7=\xE6wzÞ›\xBEw\xAC\xF7=\xECG{\xE0\xDB&gt;x\xB8^\xEE\xF1\xA6{\xE2\xED\xBEx\xBC7^\xEF\x8F\xE7{\xE4\xFD&gt;y\xC0W^\xF0\x97'|\xE6+\xBFy\xC4\xCF[\xF1\x9Fg|\xE8?zÈ—^\xF2\xA7\xA7|\xEA-\xBFzÌ·^\xF3\xAF\xE7|\xEC=_o\xD0\xD7^
 \xF4\xB7'}\xEEM\xBF{\xD4\xF7^\xF5\xBFg}\xF0]?|\xD8_\xF6ǧ\xFD\xBDm\xBF|\xDC7_\xF7\xCF\xE7}\xF4}?}\xE0W_\xF8\xD7'~\xF6\x8D\xBF}\xE4w_\xF9\xF9v~\xF8\xA1?~é—Ÿ\xFA\xE7\xB7~\xFA\xB1\xBF~\x{DDDF}\xFB\xEF\xF7~\xFC\xC1\xAF\xEAk\xD7\xDF\xF7g\xFE\xFC\xCF\xFF\xFE\xCE\xF7\xF6\xFF\x97|\xF8}\xB8\xFEw\x80\x88\x80\xA8\x80È€\x98\x80\xB8\x80Ø€\xF8\x80x\x81\x88\x81\x98\x81\xB8\x81\x98\xE2\x82\xE4'\x82\xE6G\x82\xE8g\x82ꇂ짂\xEEÇ‚\xF0\xE7\x82\xF2\x83\xF4\xA7g\xA0&amp;\x83h\x83\x88\x83\xDACj(dj\xEEÃ*\xE4\x83)H\x83\xA5@00\xE03i\x920
+\xF30 \xE3&quot; \x83f`#\xE3&lt;U\x801^\xD0#S$3!%$\xB3pp2K\xA22R+\xF3/\x93%h\xB8%Q\x90_\x82\x8B\x803\x8C\xE0:\xB33\x96`H\xE8j\xAD\xA6[+Ô‡\xEE\x88 &amp;\x88\xB5F\x88{f\x885H\x84\xF8\xA7\x88\xFA\xA7\x83\xE8\x88\x89Ȉ!H\x89#h\x89%\x88\x89'\xA8\x89Chk\x8Dȉ+\x8A-(\x8A/H\x8A1\xFEh\x8A3艕\xA8\x8A\x97ÈŠ\x99芛\x8B\x9D\x88\x88\xF6\x87\x8A7h\x8B9\x88\x8B(\x89\xBC\xA8\x8B\x8Fè‹‘\x8C\x93(\x8B\xA1H\x8C\xA3h\x8C\xA5\x88\x8C\xA7\xA8\x8C\xA9H\x8B\x8BÈŒ\xB7\x8D\xB9(\x8D\xBB(\x8C\xBDH\x8D\xBF\x88\x8D\xC1\xA8\x8D\xC3茟È\xD7è«(\x8E\xADH\x8E\xAFh\x8E\xB1\x88\x8E\xB3\xB8[\xEAX\x8C\xEDx\x8C\xF1\xB8\x8C\xF3ØŒ\xECx\x8F\x88\x8Fo\xA4\x8F\xA1T\x8F\xD1\xE8\x8F\xD3\x90\xD5\x8E\xD6X\x90y\x90\x99\x8D        \xB9\x8D Ù\xFC([I[+\x8Eɇ\xE9\x87\xFB\x98\x8F\x99\x91Ù\x889\x88!Y\x88#y\x88%\x99\x88y\x92\xB5\x98\x92\xE9\x91-        \x91/)\x91*\xF9\x8Ci\x905É’        \x939)\x931i\x91=\x89\x91.\xB9\x93&gt;)\x94@\xA9\x93Ay\x94F\x99\x94&lt;I\x94 \xF9\x93MÉ”\xFE&quot;\xE9\x94Q        \x95$)\
 x95UI\x95&amp;i\x95Y\x89\x95(y\x93^9\x93\xDF\xF8\x95ZÙ•`9\x8EeY\x8Egy\x8Ei\x99\x8Ek\xB9\x8Ec\xB9\x92bÉ•pÙ–\xEEH\x97\xF0h9@\xC8BB\xE8Mz\xB6M\xC6\xC3j%R&quot;\xA5\xED\xA4*\x84Y\x98\xB0B@\xA8b*\xF3D\x98\xE0*fpO_\x91Of\xD1*fPs! \xA0\x99k\x91\xE0\xA0\xB6\x92Py\xD1P\x81,\x80\xD1P\x87qÍ’\x871Ñ‚QÓ²u RC\x89\x94KÉ›\xBB\xA9\x94\xBFÙ›\xC0Y\x94\xC2Y\x9C\xC1y\x9Cĉ\x9CO\xE9\x9B\xC9Ùœ\xCB9\x9C\xCFi\x9C\xCE9\x95\xCC\x9D\xCAI\x9DЉ\x9D\xD2i\x9D\xD3y\x95Õ©\x9D\xD7\xE9\x9D\xD9)\x9E\xDB        \x9Eݹ\x95\xDFI\x9E቞\xE3Éžå©ž\xE7I\x96oI\x93v)\x8F\xF5I\x8F\xF7i\xFE\x8F\xF3\x96\xF9\xF9\x8F\xFD\x90\xFF9\x90q\x99\x9E\xF2)\x97\xF4\xB9\x9Ff\xA9\xA0hÉ j\xE9\xA0l        \xA1n\x89\xA0\xFC)\xA1ui\xA1w\x89\xA1\xF6\xA9\xA1\xF8É¡\xFAI\xA1
+\xA2+*\xA2J\xA2j\xA2J\xA0\xAA\xA2s\xE9\xA1\xFE\xE9\xA2
+\xA3\xA0
+I\xA3 i\xA3)\xA35\xAA\xA37Ê£9\x8A\xA2
+\xA4*\xA4J\xA4j\xA4Ê¢        \x8A\xA4/ʤ1\xEA\xA43\xEA\xA3)\xA56\x89\xA3S
+\xA5;\x8A\xA5=\xAA\xA5?\xAA\xA4ʥW\xEA\xA5!*\xA6#J\xA6%j\xA6'\x8A\xA6)ڞ+ʦ-
+\xA6UJ\xA58\xA9\xA6AJ\xA7Cj\xA7E\x8A\xA7GZI\xA8N\xF9\x83}Y\xDDt\xA7n\xBA\xA4z\x9A\xA4\x85\xFA\xA5\x87Ú¤\x8B\xFA\xA4\x8D\xA5p:\xA7\x89:\xA6\x93Z\xA6\x95z\xA6\x97\x9A\xA6\x99\xBA\xA6\xEFY\xA0\xF1\x{198F6A5}\xA1\xFE\xBA\xA5\xA3Ú¥\x9BZ\xA7\xA7J\xA8\x9DÚ¦\xAB
+\xAA\xA9\x9A\xA7\xAF\xBA\xA7\xB1\x8A\xA8\xADj\xA8\xB3ʨ\xB7꨹
+\xA9\xA5\xA6\xBB*\xAA\xBFJ\xAA\xC1j\xAA\xB5\xAA\xA8\xC3\xEA\xAB\xC5J\xA9\xC9j\xA9ËŠ\xA9ͪ\xA9\xCFÊ©\xEA\xAAÑŠ\xAAÕª\xAA\xD3j\xAB\xD7
+\xAB\xDB*\xAB\xDDJ\xAB\xD9j\xACߊ\xAB㪫\xE5Ê«\xC7\xA7\x91:\xA0\xE9*\xA9\xE7
+\xAC\xEF*\xAC\xF1J\xAC᪬\xF5ʬ\xF7\xEA\xAC\xF9
+\xAD\xFB*\xAD\x9F\xAA\xAD\xFDj\xAD\x8B\xAD\xFF*\xAEË­\xEB\xAD         \xAEk\xAF+\x8B\xAF\xAB\xAF˯\xEB\xAF\xDCy\xB1扱𩱞ʱ\xAC\xBA\xB0\xE4
+\xB2\xE6*\xB2\xE8:\xAF\xC8J\xB2\xF0\x8A\xB2\xF2\xAA\xB2\xF4Z\xB1\xEB\xB2\xEB\xB1\xD4ʲ' \xB3k\xB3
+\x8B\xB3 +\xB3\xAB\xB3!\xEB\xB3# \xB4%K\xB3\xEAÚ«EÛ®+Ù§\xA5\xF6\xA7\xFE\xF0\x93\x97.\xB4\x97\xC7 H\x98&amp;P\xB5V{\xB5U\xDBX\xBB\xB5\xA0\xB5\{\xB5^˵\xC0]\xEB_;\xB6Yk\xB6[\x8B\xB6i\xC0\xB6oK\xB6V\xEB\xB5h \xB7m\xABV;\xB6r \xB6j[\xB5{Ë·n\xFB\xB5sÛ·\x82\xDB3&gt;SS\x8B0J\xB80\xE3\x84L\x85\xB9sL@\xB9\x80\x85k\xC11Q\xE01W\x80@ 2w\x80w\xBAPr\x86\xA4 j\xE8\x81p\xAD\xAB%3\x87\x860%v(&amp;t        &gt;\x80\x87&lt;\xA3\x87\x87K\xF0\xBB\xC0\xBC\xBF[\xA0\x848$P\xBCM\xC8;\xCA1J1\xCD+`1S\xF0\xBB0\xBD\xA31\xBF{\xDA \x9C\xFB\xBF \xBA\xE1 \xBF{\xE9kp\xBE\xE8 \xEF%\xBE\x82s\xBC1\xBE\x885\xE3\xE1{\xBB\x8C\xBE\xBA;        Ú»\xBD\xC2[\xC0%Q\xC0\x9C\xBCÆ»\xE1\xAB+\xB3+\xCC\xC0`#\xBF{\xE1\xCB\xC0\x8B\xC1Ø›\xBD\xC9\xEB\xEC\xC1\xC9;\xBE\xC1\xFB\xB9d\xE0\xBEv\xBC\xA5k\xC2\xAC2\xF4;\xBF\xBF\xF6;\xBF\xC9k\xBF\x9B\xBF\xF0\xFD\xEB\xBF\xC0 0\xC0,\xBC\xDB;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamtreeviewcss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/treeview.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/treeview.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/treeview.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+table.ygtvtable{margin-bottom:0;border:0;border-collapse:collapse}td.ygtvcell{border:0;padding:0}a.ygtvspacer{text-decoration:none;outline-style:none;display:block}.ygtvtn{width:18px;height:22px;background:url(treeview-sprite.gif) 0 -5600px no-repeat;cursor:pointer}.ygtvtm{width:18px;height:22px;cursor:pointer;background:url(treeview-sprite.gif) 0 -4000px no-repeat}.ygtvtmh,.ygtvtmhh{width:18px;height:22px;cursor:pointer;background:url(treeview-sprite.gif) 0 -4800px no-repeat}.ygtvtp{width:18px;height:22px;cursor:pointer;background:url(treeview-sprite.gif) 0 -6400px no-repeat}.ygtvtph,.ygtvtphh{width:18px;height:22px;cursor:pointer;background:url(treeview-sprite.gif) 0 -7200px no-repeat}.ygtvln{width:18px;height:22px;background:url(treeview-sprite.gif) 0 -1600px no-repeat;cursor:pointer}.ygtvlm{width:18px;height:22px;cursor:pointer;background:url(treeview-sprite.gif) 0 0 no-repeat}.ygtvlmh,.ygtvlmhh{width:18px;height:22px;cursor:pointer;background:url(treeview-sprite.gif) 0 
 -800px no-repeat}.ygtvlp{width:18px;height:22px;cursor:pointer;background:url(treeview-sprite.gif) 0 -2400px no-repeat}.ygtvlph,.ygtvlphh{width:18px;height:22px;cursor:pointer;background:url(treeview-sprite.gif) 0 -3200px no-repeat;cursor:pointer}.ygtvloading{width:18px;height:22px;background:url(treeview-loading.gif) 0 0 no-repeat}.ygtvdepthcell{width:18px;height:22px;background:url(treeview-sprite.gif) 0 -8000px no-repeat}.ygtvblankdepthcell{width:18px;height:22px}* html .ygtvchildren{height:2%}.ygtvlabel,.ygtvlabel:link,.ygtvlabel:visited,.ygtvlabel:hover{margin-left:2px;text-decoration:none;background-color:white;cursor:pointer}.ygtvcontent{cursor:default}.ygtvspacer{height:22px;width:18px}.ygtvfocus{background-color:#c0e0e0;border:0}.ygtvfocus .ygtvlabel,.ygtvfocus .ygtvlabel:link,.ygtvfocus .ygtvlabel:visited,.ygtvfocus .ygtvlabel:hover{background-color:#c0e0e0}.ygtvfocus a{outline-style:none}.ygtvok{width:18px;height:22px;background:url(treeview-sprite.gif) 0 -8800px 
 no-repeat}.ygtvok:hover{background:url(treeview-sprite.gif) 0 -8844px no-repeat}.ygtvcancel{width:18px;height:22px;background:url(treeview-sprite.gif) 0 -8822px no-repeat}.ygtvcancel:hover{background:url(treeview-sprite.gif) 0 -8866px no-repeat}.ygtv-label-editor{background-color:#f2f2f2;border:1px solid silver;position:absolute;display:none;overflow:hidden;margin:auto;z-index:9000}.ygtv-edit-TextNode{width:190px}.ygtv-edit-TextNode .ygtvcancel,.ygtv-edit-TextNode .ygtvok{border:0}.ygtv-edit-TextNode .ygtv-button-container{float:right}.ygtv-edit-TextNode .ygtv-input input{width:140px}.ygtv-edit-DateNode .ygtvcancel{border:0}.ygtv-edit-DateNode .ygtvok{display:none}.ygtv-edit-DateNode .ygtv-button-container{text-align:right;margin:auto}.ygtv-highlight .ygtv-highlight1,.ygtv-highlight .ygtv-highlight1 .ygtvlabel{background-color:blue;color:white}.ygtv-highlight .ygtv-highlight2,.ygtv-highlight .ygtv-highlight2 .ygtvlabel{background-color:silver}.ygtv-highlight .ygtv-highlight0
  .ygtvfocus .ygtvlabel,.ygtv-highlight .ygtv-highlight1 .ygtvfocus .ygtvlabel,.ygtv-highlight .ygtv-highlight2 .ygtvfocus .ygtvlabel{background-color:#c0e0e0}.ygtv-highlight .ygtvcontent{padding-right:1em}.ygtv-checkbox .ygtv-highlight0 .ygtvcontent{padding-left:1em;background:url(check0.gif) no-repeat}.ygtv-checkbox .ygtv-highlight0 .ygtvfocus.ygtvcontent,.ygtv-checkbox .ygtv-highlight1 .ygtvfocus.ygtvcontent,.ygtv-checkbox .ygtv-highlight2 .ygtvfocus.ygtvcontent{background-color:#c0e0e0}.ygtv-checkbox .ygtv-highlight1 .ygtvcontent{padding-left:1em;background:url(check1.gif) no-repeat}.ygtv-checkbox .ygtv-highlight2 .ygtvcontent{padding-left:1em;background:url(check2.gif) no-repeat}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamwaitgif"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/wait.gif (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/wait.gif                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/wait.gif        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,13 @@
</span><ins>+GIF89a\xC4yyw\xAE\xAE\xAC\xC5\xC5\xC3yyv\x94\x94\x93\x95\x95\x94\xA3\xA3\xA2\xAF\xAF\xAE\xC6\xC6ä\xA4\xA3\xBB\xBB\xB9\xA5\xA5\xA5\xB9\xB9\xB7xxv\x88\x88\x86\xD2\xD2φ\x86\x84\x96\x96\x96\xC6\xC6\xC4\xD1\xD1ΰ\xB0\xAF\x94\x94\x92\xA2\xA2\xA1\xBA\xBA\xB8\xD1\xD1χ\x87\x85\xFF\xFF\xFF!\xFF NETSCAPE2.0!\xF9,i\xA0&amp;\x8Edi\x96\xCBr\xAEI\x9B\xAC#EiFmhQt\xFC\xA1YMaX0\x8EaI8M\x95\x8AI\xA1\x80i\x8E\xD1e{Ye\xBE\xB7{\x87E \x861I$&amp;\xE0\x84\xA8#Hr\xB9I\xC0h\x83'|\x89++V\x88\x8A\x8F$\x92\x96!!\xF9,c\xA0&amp;\x8EE\x91(y\xACG:*\x8AÌ\xB6,\xE8\xA5_r\x9D\xFC        ÒŽ72+(#e\xB1\x90$\xD7(\xD1 \xAEia[xR\x82\x98\xA0\xF1JE\x95
+\xE9\xF1H9(\x8CC\xCA\xD83\xA49\xD0\xDC\xF1$||g\x8Bg$++.!!\xF9,d\xA0&amp;\x8E\x9A\xA2\x90(y\xADW:J\x92ƶ\x85&quot;8\xA21\x8Cv\xFC\x92`( \x8E\xD40u$=\xAE\xD1b\xA1\xC1X1Ñ„6qź `\x83f2\x89\x8A,\x90\x8ADP\xEB5\xA9@/\x90\xF8\x81\xC6\xE1\xD0\xFE(++\x86f\x87\x88f#.!!\xF9,c\xA0&amp;\x8E\x9A$\x91(\x89\xACH:&gt;\x8F&amp;Ì‚\xA6((\xA6cr}\xFDÒŽ7I\x93I\x8A\xC1 \xAE\x85\xA2y&gt;\xA3\x87\xECa\xC0D\xE0\x80\xA6ш\x8A\xC0$\x87#\xB5X\xA02\xF0 )AO\x90\xE2\xF2HDc\xE8P\x84f\x8Bf$.!!\xF9,d\xA0&amp;\x8E\xDA\xF3\x90(\x89\xADX:\x80ƶ\x92\x84°6M\xE2#\xA4\x81p@\xA8F#e$9\xAE\x91B\xA1\xC9X3Ñ‹\xF6rź\xB6+1\xA4H$E\xA1\xA0
+\xF0\xE9@?\x90x\x82f\xB1\xD0\xFE(        \x86        ~\x81Q\x8Ce$.!!\xF9,e\xA0&amp;\x8E\x90(i\x9A\xE9\xE88\xDA \xDA\xF3\xA0Y\x9EiM\xA3a@ I\xB7\x85$$5\x99\x90&quot;\x91\xD6H&quot;\xD1\xAE)b\x8B x        R\x81X\xA0\xA9T\xA4&quot;1i\xB1H)\xA8\x84&lt;A\xBA\xD8/$\x83Þ \xA1P4wx$\x87 h\x8Eh$\x8E-!!\xF9,c\xA0&amp;\x8E\x9A\xE3\x90(\x99\xADY:F\x91ƶ\x80x\xA1A\x90V\xD7$\x82\x90@\xA8J%\xD5h\x90 \xD7\xE8\xF1\xD0$\xAE        )f\x8B1x+Z\xAE\xC6b\x91\x8A&amp;\x85\x92\x92HP\x87\xF8\x81\x84\xA8#H\x81|@\xA3Ph\x80(y\x86\x82R\x87\x88f# .!!\xF9,d\xA0&amp;\x8EZ\x91(Y\xACE:.\x8BFÌ„\xE68h\xA2'ZUi\x99`\x86d(H\xC2!\xC9bIA $
+\xC554\x87\xEC\x81j\xB5\xBE\xEA`&lt;\xD0|\xA9\xA2F\x83\xA4P\xA4\xD4e~!a\xEE\xBD.\x91h\xF0y$ \x86h\x8Dh$\x8D.!;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiassetsskinssamyuitestcss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/yuitest.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/yuitest.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/assets/skins/sam/yuitest.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiautocompleteautocompleteminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/autocomplete/autocomplete-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/autocomplete/autocomplete-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/autocomplete/autocomplete-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+YAHOO.widget.DS_JSArray=YAHOO.util.LocalDataSource;YAHOO.widget.DS_JSFunction=YAHOO.util.FunctionDataSource;YAHOO.widget.DS_XHR=function(b,a,d){var c=new YAHOO.util.XHRDataSource(b,d);c._aDeprecatedSchema=a;return c;};YAHOO.widget.DS_ScriptNode=function(b,a,d){var c=new YAHOO.util.ScriptNodeDataSource(b,d);c._aDeprecatedSchema=a;return c;};YAHOO.widget.DS_XHR.TYPE_JSON=YAHOO.util.DataSourceBase.TYPE_JSON;YAHOO.widget.DS_XHR.TYPE_XML=YAHOO.util.DataSourceBase.TYPE_XML;YAHOO.widget.DS_XHR.TYPE_FLAT=YAHOO.util.DataSourceBase.TYPE_TEXT;YAHOO.widget.AutoComplete=function(g,b,j,c){if(g&amp;&amp;b&amp;&amp;j){if(j&amp;&amp;YAHOO.lang.isFunction(j.sendRequest)){this.dataSource=j;}else{return;}this.key=0;var d=j.responseSchema;if(j._aDeprecatedSchema){var k=j._aDeprecatedSchema;if(YAHOO.lang.isArray(k)){if((j.responseType===YAHOO.util.DataSourceBase.TYPE_JSON)||(j.responseType===YAHOO.util.DataSourceBase.TYPE_UNKNOWN)){d.resultsList=k[0];this.key=k[1];d.fields=(k.length&lt;3)?null:k.
 slice(1);}else{if(j.responseType===YAHOO.util.DataSourceBase.TYPE_XML){d.resultNode=k[0];this.key=k[1];d.fields=k.slice(1);}else{if(j.responseType===YAHOO.util.DataSourceBase.TYPE_TEXT){d.recordDelim=k[0];d.fieldDelim=k[1];}}}j.responseSchema=d;}}if(YAHOO.util.Dom.inDocument(g)){if(YAHOO.lang.isString(g)){this._sName=&quot;instance&quot;+YAHOO.widget.AutoComplete._nIndex+&quot; &quot;+g;this._elTextbox=document.getElementById(g);}else{this._sName=(g.id)?&quot;instance&quot;+YAHOO.widget.AutoComplete._nIndex+&quot; &quot;+g.id:&quot;instance&quot;+YAHOO.widget.AutoComplete._nIndex;this._elTextbox=g;}YAHOO.util.Dom.addClass(this._elTextbox,&quot;yui-ac-input&quot;);}else{return;}if(YAHOO.util.Dom.inDocument(b)){if(YAHOO.lang.isString(b)){this._elContainer=document.getElementById(b);}else{this._elContainer=b;}if(this._elContainer.style.display==&quot;none&quot;){}var e=this._elContainer.parentNode;var a=e.tagName.toLowerCase();if(a==&quot;div&quot;){YAHOO.util.Dom.addClass(e,&q
 uot;yui-ac&quot;);}else{}}else{return;}if(this.dataSource.dataType===YAHOO.util.DataSourceBase.TYPE_LOCAL){this.applyLocalFilter=true;}if(c&amp;&amp;(c.constructor==Object)){for(var i in c){if(i){this[i]=c[i];}}}this._initContainerEl();this._initProps();this._initListEl();this._initContainerHelperEls();var h=this;var f=this._elTextbox;YAHOO.util.Event.addListener(f,&quot;keyup&quot;,h._onTextboxKeyUp,h);YAHOO.util.Event.addListener(f,&quot;keydown&quot;,h._onTextboxKeyDown,h);YAHOO.util.Event.addListener(f,&quot;focus&quot;,h._onTextboxFocus,h);YAHOO.util.Event.addListener(f,&quot;blur&quot;,h._onTextboxBlur,h);YAHOO.util.Event.addListener(b,&quot;mouseover&quot;,h._onContainerMouseover,h);YAHOO.util.Event.addListener(b,&quot;mouseout&quot;,h._onContainerMouseout,h);YAHOO.util.Event.addListener(b,&quot;click&quot;,h._onContainerClick,h);YAHOO.util.Event.addListener(b,&quot;scroll&quot;,h._onContainerScroll,h);YAHOO.util.Event.addListener(b,&quot;resize&quot;,h._onContainerRe
 size,h);YAHOO.util.Event.addListener(f,&quot;keypress&quot;,h._onTextboxKeyPress,h);YAHOO.util.Event.addListener(window,&quot;unload&quot;,h._onWindowUnload,h);this.textboxFocusEvent=new YAHOO.util.CustomEvent(&quot;textboxFocus&quot;,this);this.textboxKeyEvent=new YAHOO.util.CustomEvent(&quot;textboxKey&quot;,this);this.dataRequestEvent=new YAHOO.util.CustomEvent(&quot;dataRequest&quot;,this);this.dataRequestCancelEvent=new YAHOO.util.CustomEvent(&quot;dataRequestCancel&quot;,this);this.dataReturnEvent=new YAHOO.util.CustomEvent(&quot;dataReturn&quot;,this);this.dataErrorEvent=new YAHOO.util.CustomEvent(&quot;dataError&quot;,this);this.containerPopulateEvent=new YAHOO.util.CustomEvent(&quot;containerPopulate&quot;,this);this.containerExpandEvent=new YAHOO.util.CustomEvent(&quot;containerExpand&quot;,this);this.typeAheadEvent=new YAHOO.util.CustomEvent(&quot;typeAhead&quot;,this);this.itemMouseOverEvent=new YAHOO.util.CustomEvent(&quot;itemMouseOver&quot;,this);this.itemMous
 eOutEvent=new YAHOO.util.CustomEvent(&quot;itemMouseOut&quot;,this);this.itemArrowToEvent=new YAHOO.util.CustomEvent(&quot;itemArrowTo&quot;,this);this.itemArrowFromEvent=new YAHOO.util.CustomEvent(&quot;itemArrowFrom&quot;,this);this.itemSelectEvent=new YAHOO.util.CustomEvent(&quot;itemSelect&quot;,this);this.unmatchedItemSelectEvent=new YAHOO.util.CustomEvent(&quot;unmatchedItemSelect&quot;,this);this.selectionEnforceEvent=new YAHOO.util.CustomEvent(&quot;selectionEnforce&quot;,this);this.containerCollapseEvent=new YAHOO.util.CustomEvent(&quot;containerCollapse&quot;,this);this.textboxBlurEvent=new YAHOO.util.CustomEvent(&quot;textboxBlur&quot;,this);this.textboxChangeEvent=new YAHOO.util.CustomEvent(&quot;textboxChange&quot;,this);f.setAttribute(&quot;autocomplete&quot;,&quot;off&quot;);YAHOO.widget.AutoComplete._nIndex++;}else{}};YAHOO.widget.AutoComplete.prototype.dataSource=null;YAHOO.widget.AutoComplete.prototype.applyLocalFilter=null;YAHOO.widget.AutoComplete.prototy
 pe.queryMatchCase=false;YAHOO.widget.AutoComplete.prototype.queryMatchContains=false;YAHOO.widget.AutoComplete.prototype.queryMatchSubset=false;YAHOO.widget.AutoComplete.prototype.minQueryLength=1;YAHOO.widget.AutoComplete.prototype.maxResultsDisplayed=10;YAHOO.widget.AutoComplete.prototype.queryDelay=0.2;YAHOO.widget.AutoComplete.prototype.typeAheadDelay=0.5;YAHOO.widget.AutoComplete.prototype.queryInterval=500;YAHOO.widget.AutoComplete.prototype.highlightClassName=&quot;yui-ac-highlight&quot;;YAHOO.widget.AutoComplete.prototype.prehighlightClassName=null;YAHOO.widget.AutoComplete.prototype.delimChar=null;YAHOO.widget.AutoComplete.prototype.autoHighlight=true;YAHOO.widget.AutoComplete.prototype.typeAhead=false;YAHOO.widget.AutoComplete.prototype.animHoriz=false;YAHOO.widget.AutoComplete.prototype.animVert=true;YAHOO.widget.AutoComplete.prototype.animSpeed=0.3;YAHOO.widget.AutoComplete.prototype.forceSelection=false;YAHOO.widget.AutoComplete.prototype.allowBrowserAutocomplet
 e=true;YAHOO.widget.AutoComplete.prototype.alwaysShowContainer=false;YAHOO.widget.AutoComplete.prototype.useIFrame=false;YAHOO.widget.AutoComplete.prototype.useShadow=false;YAHOO.widget.AutoComplete.prototype.suppressInputUpdate=false;YAHOO.widget.AutoComplete.prototype.resultTypeList=true;YAHOO.widget.AutoComplete.prototype.queryQuestionMark=true;YAHOO.widget.AutoComplete.prototype.autoSnapContainer=true;YAHOO.widget.AutoComplete.prototype.toString=function(){return&quot;AutoComplete &quot;+this._sName;};YAHOO.widget.AutoComplete.prototype.getInputEl=function(){return this._elTextbox;
+};YAHOO.widget.AutoComplete.prototype.getContainerEl=function(){return this._elContainer;};YAHOO.widget.AutoComplete.prototype.isFocused=function(){return this._bFocused;};YAHOO.widget.AutoComplete.prototype.isContainerOpen=function(){return this._bContainerOpen;};YAHOO.widget.AutoComplete.prototype.getListEl=function(){return this._elList;};YAHOO.widget.AutoComplete.prototype.getListItemMatch=function(a){if(a._sResultMatch){return a._sResultMatch;}else{return null;}};YAHOO.widget.AutoComplete.prototype.getListItemData=function(a){if(a._oResultData){return a._oResultData;}else{return null;}};YAHOO.widget.AutoComplete.prototype.getListItemIndex=function(a){if(YAHOO.lang.isNumber(a._nItemIndex)){return a._nItemIndex;}else{return null;}};YAHOO.widget.AutoComplete.prototype.setHeader=function(b){if(this._elHeader){var a=this._elHeader;if(b){a.innerHTML=b;a.style.display=&quot;&quot;;}else{a.innerHTML=&quot;&quot;;a.style.display=&quot;none&quot;;}}};YAHOO.widget.AutoComplete.pro
 totype.setFooter=function(b){if(this._elFooter){var a=this._elFooter;if(b){a.innerHTML=b;a.style.display=&quot;&quot;;}else{a.innerHTML=&quot;&quot;;a.style.display=&quot;none&quot;;}}};YAHOO.widget.AutoComplete.prototype.setBody=function(a){if(this._elBody){var b=this._elBody;YAHOO.util.Event.purgeElement(b,true);if(a){b.innerHTML=a;b.style.display=&quot;&quot;;}else{b.innerHTML=&quot;&quot;;b.style.display=&quot;none&quot;;}this._elList=null;}};YAHOO.widget.AutoComplete.prototype.generateRequest=function(b){var a=this.dataSource.dataType;if(a===YAHOO.util.DataSourceBase.TYPE_XHR){if(!this.dataSource.connMethodPost){b=(this.queryQuestionMark?&quot;?&quot;:&quot;&quot;)+(this.dataSource.scriptQueryParam||&quot;query&quot;)+&quot;=&quot;+b+(this.dataSource.scriptQueryAppend?(&quot;&amp;&quot;+this.dataSource.scriptQueryAppend):&quot;&quot;);}else{b=(this.dataSource.scriptQueryParam||&quot;query&quot;)+&quot;=&quot;+b+(this.dataSource.scriptQueryAppend?(&quot;&amp;&quot;+this.
 dataSource.scriptQueryAppend):&quot;&quot;);}}else{if(a===YAHOO.util.DataSourceBase.TYPE_SCRIPTNODE){b=&quot;&amp;&quot;+(this.dataSource.scriptQueryParam||&quot;query&quot;)+&quot;=&quot;+b+(this.dataSource.scriptQueryAppend?(&quot;&amp;&quot;+this.dataSource.scriptQueryAppend):&quot;&quot;);}}return b;};YAHOO.widget.AutoComplete.prototype.sendQuery=function(b){this._bFocused=true;var a=(this.delimChar)?this._elTextbox.value+b:b;this._sendQuery(a);};YAHOO.widget.AutoComplete.prototype.snapContainer=function(){var a=this._elTextbox,b=YAHOO.util.Dom.getXY(a);b[1]+=YAHOO.util.Dom.get(a).offsetHeight+2;YAHOO.util.Dom.setXY(this._elContainer,b);};YAHOO.widget.AutoComplete.prototype.expandContainer=function(){this._toggleContainer(true);};YAHOO.widget.AutoComplete.prototype.collapseContainer=function(){this._toggleContainer(false);};YAHOO.widget.AutoComplete.prototype.clearList=function(){var b=this._elList.childNodes,a=b.length-1;for(;a&gt;-1;a--){b[a].style.display=&quot;none&q
 uot;;}};YAHOO.widget.AutoComplete.prototype.getSubsetMatches=function(e){var d,c,a;for(var b=e.length;b&gt;=this.minQueryLength;b--){a=this.generateRequest(e.substr(0,b));this.dataRequestEvent.fire(this,d,a);c=this.dataSource.getCachedResponse(a);if(c){return this.filterResults.apply(this.dataSource,[e,c,c,{scope:this}]);}}return null;};YAHOO.widget.AutoComplete.prototype.preparseRawResponse=function(c,b,a){var d=((this.responseStripAfter!==&quot;&quot;)&amp;&amp;(b.indexOf))?b.indexOf(this.responseStripAfter):-1;if(d!=-1){b=b.substring(0,d);}return b;};YAHOO.widget.AutoComplete.prototype.filterResults=function(l,n,r,m){if(m&amp;&amp;m.argument&amp;&amp;YAHOO.lang.isValue(m.argument.query)){l=m.argument.query;}if(l&amp;&amp;l!==&quot;&quot;){r=YAHOO.widget.AutoComplete._cloneObject(r);var j=m.scope,q=this,c=r.results,o=[],b=j.maxResultsDisplayed,k=(q.queryMatchCase||j.queryMatchCase),a=(q.queryMatchContains||j.queryMatchContains);for(var d=0,h=c.length;d&lt;h;d++){var f=c[d]
 ;var e=null;if(YAHOO.lang.isString(f)){e=f;}else{if(YAHOO.lang.isArray(f)){e=f[0];}else{if(this.responseSchema.fields){var p=this.responseSchema.fields[0].key||this.responseSchema.fields[0];e=f[p];}else{if(this.key){e=f[this.key];}}}}if(YAHOO.lang.isString(e)){var g=(k)?e.indexOf(decodeURIComponent(l)):e.toLowerCase().indexOf(decodeURIComponent(l).toLowerCase());if((!a&amp;&amp;(g===0))||(a&amp;&amp;(g&gt;-1))){o.push(f);}}if(h&gt;b&amp;&amp;o.length===b){break;}}r.results=o;}else{}return r;};YAHOO.widget.AutoComplete.prototype.handleResponse=function(c,a,b){if((this instanceof YAHOO.widget.AutoComplete)&amp;&amp;this._sName){this._populateList(c,a,b);}};YAHOO.widget.AutoComplete.prototype.doBeforeLoadData=function(c,a,b){return true;};YAHOO.widget.AutoComplete.prototype.formatResult=function(b,d,a){var c=(a)?a:&quot;&quot;;return c;};YAHOO.widget.AutoComplete.prototype.formatEscapedResult=function(c,d,b){var a=(b)?b:&quot;&quot;;return YAHOO.lang.escapeHTML(a);};YAHOO.widge
 t.AutoComplete.prototype.doBeforeExpandContainer=function(d,a,c,b){return true;};YAHOO.widget.AutoComplete.prototype.destroy=function(){var b=this.toString();var a=this._elTextbox;var d=this._elContainer;this.textboxFocusEvent.unsubscribeAll();this.textboxKeyEvent.unsubscribeAll();this.dataRequestEvent.unsubscribeAll();this.dataReturnEvent.unsubscribeAll();this.dataErrorEvent.unsubscribeAll();this.containerPopulateEvent.unsubscribeAll();this.containerExpandEvent.unsubscribeAll();this.typeAheadEvent.unsubscribeAll();this.itemMouseOverEvent.unsubscribeAll();this.itemMouseOutEvent.unsubscribeAll();this.itemArrowToEvent.unsubscribeAll();this.itemArrowFromEvent.unsubscribeAll();this.itemSelectEvent.unsubscribeAll();this.unmatchedItemSelectEvent.unsubscribeAll();this.selectionEnforceEvent.unsubscribeAll();this.containerCollapseEvent.unsubscribeAll();this.textboxBlurEvent.unsubscribeAll();this.textboxChangeEvent.unsubscribeAll();YAHOO.util.Event.purgeElement(a,true);YAHOO.util.Even
 t.purgeElement(d,true);d.innerHTML=&quot;&quot;;for(var c in this){if(YAHOO.lang.hasOwnProperty(this,c)){this[c]=null;}}};YAHOO.widget.AutoComplete.prototype.textboxFocusEvent=null;YAHOO.widget.AutoComplete.prototype.textboxKeyEvent=null;YAHOO.widget.AutoComplete.prototype.dataRequestEvent=null;YAHOO.widget.AutoComplete.prototype.dataRequestCancelEvent=null;YAHOO.widget.AutoComplete.prototype.dataReturnEvent=null;YAHOO.widget.AutoComplete.prototype.dataErrorEvent=null;
+YAHOO.widget.AutoComplete.prototype.containerPopulateEvent=null;YAHOO.widget.AutoComplete.prototype.containerExpandEvent=null;YAHOO.widget.AutoComplete.prototype.typeAheadEvent=null;YAHOO.widget.AutoComplete.prototype.itemMouseOverEvent=null;YAHOO.widget.AutoComplete.prototype.itemMouseOutEvent=null;YAHOO.widget.AutoComplete.prototype.itemArrowToEvent=null;YAHOO.widget.AutoComplete.prototype.itemArrowFromEvent=null;YAHOO.widget.AutoComplete.prototype.itemSelectEvent=null;YAHOO.widget.AutoComplete.prototype.unmatchedItemSelectEvent=null;YAHOO.widget.AutoComplete.prototype.selectionEnforceEvent=null;YAHOO.widget.AutoComplete.prototype.containerCollapseEvent=null;YAHOO.widget.AutoComplete.prototype.textboxBlurEvent=null;YAHOO.widget.AutoComplete.prototype.textboxChangeEvent=null;YAHOO.widget.AutoComplete._nIndex=0;YAHOO.widget.AutoComplete.prototype._sName=null;YAHOO.widget.AutoComplete.prototype._elTextbox=null;YAHOO.widget.AutoComplete.prototype._elContainer=null;YAHOO.widget
 .AutoComplete.prototype._elContent=null;YAHOO.widget.AutoComplete.prototype._elHeader=null;YAHOO.widget.AutoComplete.prototype._elBody=null;YAHOO.widget.AutoComplete.prototype._elFooter=null;YAHOO.widget.AutoComplete.prototype._elShadow=null;YAHOO.widget.AutoComplete.prototype._elIFrame=null;YAHOO.widget.AutoComplete.prototype._bFocused=false;YAHOO.widget.AutoComplete.prototype._oAnim=null;YAHOO.widget.AutoComplete.prototype._bContainerOpen=false;YAHOO.widget.AutoComplete.prototype._bOverContainer=false;YAHOO.widget.AutoComplete.prototype._elList=null;YAHOO.widget.AutoComplete.prototype._nDisplayedItems=0;YAHOO.widget.AutoComplete.prototype._sCurQuery=null;YAHOO.widget.AutoComplete.prototype._sPastSelections=&quot;&quot;;YAHOO.widget.AutoComplete.prototype._sInitInputValue=null;YAHOO.widget.AutoComplete.prototype._elCurListItem=null;YAHOO.widget.AutoComplete.prototype._elCurPrehighlightItem=null;YAHOO.widget.AutoComplete.prototype._bItemSelected=false;YAHOO.widget.AutoComple
 te.prototype._nKeyCode=null;YAHOO.widget.AutoComplete.prototype._nDelayID=-1;YAHOO.widget.AutoComplete.prototype._nTypeAheadDelayID=-1;YAHOO.widget.AutoComplete.prototype._iFrameSrc=&quot;javascript:false;&quot;;YAHOO.widget.AutoComplete.prototype._queryInterval=null;YAHOO.widget.AutoComplete.prototype._sLastTextboxValue=null;YAHOO.widget.AutoComplete.prototype._initProps=function(){var b=this.minQueryLength;if(!YAHOO.lang.isNumber(b)){this.minQueryLength=1;}var e=this.maxResultsDisplayed;if(!YAHOO.lang.isNumber(e)||(e&lt;1)){this.maxResultsDisplayed=10;}var f=this.queryDelay;if(!YAHOO.lang.isNumber(f)||(f&lt;0)){this.queryDelay=0.2;}var c=this.typeAheadDelay;if(!YAHOO.lang.isNumber(c)||(c&lt;0)){this.typeAheadDelay=0.2;}var a=this.delimChar;if(YAHOO.lang.isString(a)&amp;&amp;(a.length&gt;0)){this.delimChar=[a];}else{if(!YAHOO.lang.isArray(a)){this.delimChar=null;}}var d=this.animSpeed;if((this.animHoriz||this.animVert)&amp;&amp;YAHOO.util.Anim){if(!YAHOO.lang.isNumber(d)||(
 d&lt;0)){this.animSpeed=0.3;}if(!this._oAnim){this._oAnim=new YAHOO.util.Anim(this._elContent,{},this.animSpeed);}else{this._oAnim.duration=this.animSpeed;}}if(this.forceSelection&amp;&amp;a){}};YAHOO.widget.AutoComplete.prototype._initContainerHelperEls=function(){if(this.useShadow&amp;&amp;!this._elShadow){var a=document.createElement(&quot;div&quot;);a.className=&quot;yui-ac-shadow&quot;;a.style.width=0;a.style.height=0;this._elShadow=this._elContainer.appendChild(a);}if(this.useIFrame&amp;&amp;!this._elIFrame){var b=document.createElement(&quot;iframe&quot;);b.src=this._iFrameSrc;b.frameBorder=0;b.scrolling=&quot;no&quot;;b.style.position=&quot;absolute&quot;;b.style.width=0;b.style.height=0;b.style.padding=0;b.tabIndex=-1;b.role=&quot;presentation&quot;;b.title=&quot;Presentational iframe shim&quot;;this._elIFrame=this._elContainer.appendChild(b);}};YAHOO.widget.AutoComplete.prototype._initContainerEl=function(){YAHOO.util.Dom.addClass(this._elContainer,&quot;yui-ac-con
 tainer&quot;);if(!this._elContent){var c=document.createElement(&quot;div&quot;);c.className=&quot;yui-ac-content&quot;;c.style.display=&quot;none&quot;;this._elContent=this._elContainer.appendChild(c);var b=document.createElement(&quot;div&quot;);b.className=&quot;yui-ac-hd&quot;;b.style.display=&quot;none&quot;;this._elHeader=this._elContent.appendChild(b);var d=document.createElement(&quot;div&quot;);d.className=&quot;yui-ac-bd&quot;;this._elBody=this._elContent.appendChild(d);var a=document.createElement(&quot;div&quot;);a.className=&quot;yui-ac-ft&quot;;a.style.display=&quot;none&quot;;this._elFooter=this._elContent.appendChild(a);}else{}};YAHOO.widget.AutoComplete.prototype._initListEl=function(){var c=this.maxResultsDisplayed,a=this._elList||document.createElement(&quot;ul&quot;),b;while(a.childNodes.length&lt;c){b=document.createElement(&quot;li&quot;);b.style.display=&quot;none&quot;;b._nItemIndex=a.childNodes.length;a.appendChild(b);}if(!this._elList){var d=this._e
 lBody;YAHOO.util.Event.purgeElement(d,true);d.innerHTML=&quot;&quot;;this._elList=d.appendChild(a);}this._elBody.style.display=&quot;&quot;;};YAHOO.widget.AutoComplete.prototype._focus=function(){var a=this;setTimeout(function(){try{a._elTextbox.focus();}catch(b){}},0);};YAHOO.widget.AutoComplete.prototype._enableIntervalDetection=function(){var a=this;if(!a._queryInterval&amp;&amp;a.queryInterval){a._queryInterval=setInterval(function(){a._onInterval();},a.queryInterval);}};YAHOO.widget.AutoComplete.prototype.enableIntervalDetection=YAHOO.widget.AutoComplete.prototype._enableIntervalDetection;YAHOO.widget.AutoComplete.prototype._onInterval=function(){var a=this._elTextbox.value;var b=this._sLastTextboxValue;if(a!=b){this._sLastTextboxValue=a;this._sendQuery(a);}};YAHOO.widget.AutoComplete.prototype._clearInterval=function(){if(this._queryInterval){clearInterval(this._queryInterval);this._queryInterval=null;}};YAHOO.widget.AutoComplete.prototype._isIgnoreKey=function(a){if((
 a==9)||(a==13)||(a==16)||(a==17)||(a&gt;=18&amp;&amp;a&lt;=20)||(a==27)||(a&gt;=33&amp;&amp;a&lt;=35)||(a&gt;=36&amp;&amp;a&lt;=40)||(a&gt;=44&amp;&amp;a&lt;=45)||(a==229)){return true;}return false;};YAHOO.widget.AutoComplete.prototype._sendQuery=function(d){if(this.minQueryLength&lt;0){this._toggleContainer(false);return;}if(this.delimChar){var a=this._extractQuery(d);d=a.query;this._sPastSelections=a.previous;}if((d&amp;&amp;(d.length&lt;this.minQueryLength))||(!d&amp;&amp;this.minQueryLength&gt;0)){if(this._nDelayID!=-1){clearTimeout(this._nDelayID);
+}this._toggleContainer(false);return;}d=encodeURIComponent(d);this._nDelayID=-1;if(this.dataSource.queryMatchSubset||this.queryMatchSubset){var c=this.getSubsetMatches(d);if(c){this.handleResponse(d,c,{query:d});return;}}if(this.dataSource.responseStripAfter){this.dataSource.doBeforeParseData=this.preparseRawResponse;}if(this.applyLocalFilter){this.dataSource.doBeforeCallback=this.filterResults;}var b=this.generateRequest(d);if(b!==undefined){this.dataRequestEvent.fire(this,d,b);this.dataSource.sendRequest(b,{success:this.handleResponse,failure:this.handleResponse,scope:this,argument:{query:d}});}else{this.dataRequestCancelEvent.fire(this,d);}};YAHOO.widget.AutoComplete.prototype._populateListItem=function(b,a,c){b.innerHTML=this.formatResult(a,c,b._sResultMatch);};YAHOO.widget.AutoComplete.prototype._populateList=function(n,f,c){if(this._nTypeAheadDelayID!=-1){clearTimeout(this._nTypeAheadDelayID);}n=(c&amp;&amp;c.query)?c.query:n;var h=this.doBeforeLoadData(n,f,c);if(h&amp
 ;&amp;!f.error){this.dataReturnEvent.fire(this,n,f.results);if(this._bFocused){var p=decodeURIComponent(n);this._sCurQuery=p;this._bItemSelected=false;var u=f.results,a=Math.min(u.length,this.maxResultsDisplayed),m=(this.dataSource.responseSchema.fields)?(this.dataSource.responseSchema.fields[0].key||this.dataSource.responseSchema.fields[0]):0;if(a&gt;0){if(!this._elList||(this._elList.childNodes.length&lt;a)){this._initListEl();}this._initContainerHelperEls();var l=this._elList.childNodes;for(var t=a-1;t&gt;=0;t--){var s=l[t],e=u[t];if(this.resultTypeList){var b=[];b[0]=(YAHOO.lang.isString(e))?e:e[m]||e[this.key];var o=this.dataSource.responseSchema.fields;if(YAHOO.lang.isArray(o)&amp;&amp;(o.length&gt;1)){for(var q=1,v=o.length;q&lt;v;q++){b[b.length]=e[o[q].key||o[q]];}}else{if(YAHOO.lang.isArray(e)){b=e;}else{if(YAHOO.lang.isString(e)){b=[e];}else{b[1]=e;}}}e=b;}s._sResultMatch=(YAHOO.lang.isString(e))?e:(YAHOO.lang.isArray(e))?e[0]:(e[m]||&quot;&quot;);s._oResultData=e
 ;this._populateListItem(s,e,p);s.style.display=&quot;&quot;;}if(a&lt;l.length){var g;for(var r=l.length-1;r&gt;=a;r--){g=l[r];g.style.display=&quot;none&quot;;}}this._nDisplayedItems=a;this.containerPopulateEvent.fire(this,n,u);if(this.autoHighlight){var d=this._elList.firstChild;this._toggleHighlight(d,&quot;to&quot;);this.itemArrowToEvent.fire(this,d);this._typeAhead(d,n);}else{this._toggleHighlight(this._elCurListItem,&quot;from&quot;);}h=this._doBeforeExpandContainer(this._elTextbox,this._elContainer,n,u);this._toggleContainer(h);}else{this._toggleContainer(false);}return;}}else{this.dataErrorEvent.fire(this,n,f);}};YAHOO.widget.AutoComplete.prototype._doBeforeExpandContainer=function(d,a,c,b){if(this.autoSnapContainer){this.snapContainer();}return this.doBeforeExpandContainer(d,a,c,b);};YAHOO.widget.AutoComplete.prototype._clearSelection=function(){var a=(this.delimChar)?this._extractQuery(this._elTextbox.value):{previous:&quot;&quot;,query:this._elTextbox.value};this._
 elTextbox.value=a.previous;this.selectionEnforceEvent.fire(this,a.query);};YAHOO.widget.AutoComplete.prototype._textMatchesOption=function(){var a=null;for(var b=0;b&lt;this._nDisplayedItems;b++){var c=this._elList.childNodes[b];var d=(&quot;&quot;+c._sResultMatch).toLowerCase();if(d==this._sCurQuery.toLowerCase()){a=c;break;}}return(a);};YAHOO.widget.AutoComplete.prototype._typeAhead=function(b,d){if(!this.typeAhead||(this._nKeyCode==8)){return;}var a=this,c=this._elTextbox;if(c.setSelectionRange||c.createTextRange){this._nTypeAheadDelayID=setTimeout(function(){var f=c.value.length;a._updateValue(b);var g=c.value.length;a._selectText(c,f,g);var e=c.value.substr(f,g);a._sCurQuery=b._sResultMatch;a.typeAheadEvent.fire(a,d,e);},(this.typeAheadDelay*1000));}};YAHOO.widget.AutoComplete.prototype._selectText=function(d,a,b){if(d.setSelectionRange){d.setSelectionRange(a,b);}else{if(d.createTextRange){var c=d.createTextRange();c.moveStart(&quot;character&quot;,a);c.moveEnd(&quot;ch
 aracter&quot;,b-d.value.length);c.select();}else{d.select();}}};YAHOO.widget.AutoComplete.prototype._extractQuery=function(h){var c=this.delimChar,f=-1,g,e,b=c.length-1,d;for(;b&gt;=0;b--){g=h.lastIndexOf(c[b]);if(g&gt;f){f=g;}}if(c[b]==&quot; &quot;){for(var a=c.length-1;a&gt;=0;a--){if(h[f-1]==c[a]){f--;break;}}}if(f&gt;-1){e=f+1;while(h.charAt(e)==&quot; &quot;){e+=1;}d=h.substring(0,e);h=h.substr(e);}else{d=&quot;&quot;;}return{previous:d,query:h};};YAHOO.widget.AutoComplete.prototype._toggleContainerHelpers=function(d){var e=this._elContent.offsetWidth+&quot;px&quot;;var b=this._elContent.offsetHeight+&quot;px&quot;;if(this.useIFrame&amp;&amp;this._elIFrame){var c=this._elIFrame;if(d){c.style.width=e;c.style.height=b;c.style.padding=&quot;&quot;;}else{c.style.width=0;c.style.height=0;c.style.padding=0;}}if(this.useShadow&amp;&amp;this._elShadow){var a=this._elShadow;if(d){a.style.width=e;a.style.height=b;}else{a.style.width=0;a.style.height=0;}}};YAHOO.widget.AutoComple
 te.prototype._toggleContainer=function(i){var d=this._elContainer;if(this.alwaysShowContainer&amp;&amp;this._bContainerOpen){return;}if(!i){this._toggleHighlight(this._elCurListItem,&quot;from&quot;);this._nDisplayedItems=0;this._sCurQuery=null;if(this._elContent.style.display==&quot;none&quot;){return;}}var a=this._oAnim;if(a&amp;&amp;a.getEl()&amp;&amp;(this.animHoriz||this.animVert)){if(a.isAnimated()){a.stop(true);}var g=this._elContent.cloneNode(true);d.appendChild(g);g.style.top=&quot;-9000px&quot;;g.style.width=&quot;&quot;;g.style.height=&quot;&quot;;g.style.display=&quot;&quot;;var f=g.offsetWidth;var c=g.offsetHeight;var b=(this.animHoriz)?0:f;var e=(this.animVert)?0:c;a.attributes=(i)?{width:{to:f},height:{to:c}}:{width:{to:b},height:{to:e}};if(i&amp;&amp;!this._bContainerOpen){this._elContent.style.width=b+&quot;px&quot;;this._elContent.style.height=e+&quot;px&quot;;}else{this._elContent.style.width=f+&quot;px&quot;;this._elContent.style.height=c+&quot;px&quot;;}
 d.removeChild(g);g=null;var h=this;var j=function(){a.onComplete.unsubscribeAll();if(i){h._toggleContainerHelpers(true);h._bContainerOpen=i;h.containerExpandEvent.fire(h);}else{h._elContent.style.display=&quot;none&quot;;h._bContainerOpen=i;h.containerCollapseEvent.fire(h);}};this._toggleContainerHelpers(false);this._elContent.style.display=&quot;&quot;;a.onComplete.subscribe(j);a.animate();}else{if(i){this._elContent.style.display=&quot;&quot;;this._toggleContainerHelpers(true);
+this._bContainerOpen=i;this.containerExpandEvent.fire(this);}else{this._toggleContainerHelpers(false);this._elContent.style.display=&quot;none&quot;;this._bContainerOpen=i;this.containerCollapseEvent.fire(this);}}};YAHOO.widget.AutoComplete.prototype._toggleHighlight=function(a,c){if(a){var b=this.highlightClassName;if(this._elCurListItem){YAHOO.util.Dom.removeClass(this._elCurListItem,b);this._elCurListItem=null;}if((c==&quot;to&quot;)&amp;&amp;b){YAHOO.util.Dom.addClass(a,b);this._elCurListItem=a;}}};YAHOO.widget.AutoComplete.prototype._togglePrehighlight=function(b,c){var a=this.prehighlightClassName;if(this._elCurPrehighlightItem){YAHOO.util.Dom.removeClass(this._elCurPrehighlightItem,a);}if(b==this._elCurListItem){return;}if((c==&quot;mouseover&quot;)&amp;&amp;a){YAHOO.util.Dom.addClass(b,a);this._elCurPrehighlightItem=b;}else{YAHOO.util.Dom.removeClass(b,a);}};YAHOO.widget.AutoComplete.prototype._updateValue=function(c){if(!this.suppressInputUpdate){var f=this._elTextb
 ox;var e=(this.delimChar)?(this.delimChar[0]||this.delimChar):null;var b=c._sResultMatch;var d=&quot;&quot;;if(e){d=this._sPastSelections;d+=b+e;if(e!=&quot; &quot;){d+=&quot; &quot;;}}else{d=b;}f.value=d;if(f.type==&quot;textarea&quot;){f.scrollTop=f.scrollHeight;}var a=f.value.length;this._selectText(f,a,a);this._elCurListItem=c;}};YAHOO.widget.AutoComplete.prototype._selectItem=function(a){this._bItemSelected=true;this._updateValue(a);this._sPastSelections=this._elTextbox.value;this._clearInterval();this.itemSelectEvent.fire(this,a,a._oResultData);this._toggleContainer(false);};YAHOO.widget.AutoComplete.prototype._jumpSelection=function(){if(this._elCurListItem){this._selectItem(this._elCurListItem);}else{this._toggleContainer(false);}};YAHOO.widget.AutoComplete.prototype._moveSelection=function(g){if(this._bContainerOpen){var h=this._elCurListItem,d=-1;if(h){d=h._nItemIndex;}var e=(g==40)?(d+1):(d-1);if(e&lt;-2||e&gt;=this._nDisplayedItems){return;}if(h){this._toggleHigh
 light(h,&quot;from&quot;);this.itemArrowFromEvent.fire(this,h);}if(e==-1){if(this.delimChar){this._elTextbox.value=this._sPastSelections+this._sCurQuery;}else{this._elTextbox.value=this._sCurQuery;}return;}if(e==-2){this._toggleContainer(false);return;}var f=this._elList.childNodes[e],b=this._elContent,c=YAHOO.util.Dom.getStyle(b,&quot;overflow&quot;),i=YAHOO.util.Dom.getStyle(b,&quot;overflowY&quot;),a=((c==&quot;auto&quot;)||(c==&quot;scroll&quot;)||(i==&quot;auto&quot;)||(i==&quot;scroll&quot;));if(a&amp;&amp;(e&gt;-1)&amp;&amp;(e&lt;this._nDisplayedItems)){if(g==40){if((f.offsetTop+f.offsetHeight)&gt;(b.scrollTop+b.offsetHeight)){b.scrollTop=(f.offsetTop+f.offsetHeight)-b.offsetHeight;}else{if((f.offsetTop+f.offsetHeight)&lt;b.scrollTop){b.scrollTop=f.offsetTop;}}}else{if(f.offsetTop&lt;b.scrollTop){this._elContent.scrollTop=f.offsetTop;}else{if(f.offsetTop&gt;(b.scrollTop+b.offsetHeight)){this._elContent.scrollTop=(f.offsetTop+f.offsetHeight)-b.offsetHeight;}}}}this._to
 ggleHighlight(f,&quot;to&quot;);this.itemArrowToEvent.fire(this,f);if(this.typeAhead){this._updateValue(f);this._sCurQuery=f._sResultMatch;}}};YAHOO.widget.AutoComplete.prototype._onContainerMouseover=function(a,c){var d=YAHOO.util.Event.getTarget(a);var b=d.nodeName.toLowerCase();while(d&amp;&amp;(b!=&quot;table&quot;)){switch(b){case&quot;body&quot;:return;case&quot;li&quot;:if(c.prehighlightClassName){c._togglePrehighlight(d,&quot;mouseover&quot;);}else{c._toggleHighlight(d,&quot;to&quot;);}c.itemMouseOverEvent.fire(c,d);break;case&quot;div&quot;:if(YAHOO.util.Dom.hasClass(d,&quot;yui-ac-container&quot;)){c._bOverContainer=true;return;}break;default:break;}d=d.parentNode;if(d){b=d.nodeName.toLowerCase();}}};YAHOO.widget.AutoComplete.prototype._onContainerMouseout=function(a,c){var d=YAHOO.util.Event.getTarget(a);var b=d.nodeName.toLowerCase();while(d&amp;&amp;(b!=&quot;table&quot;)){switch(b){case&quot;body&quot;:return;case&quot;li&quot;:if(c.prehighlightClassName){c._to
 gglePrehighlight(d,&quot;mouseout&quot;);}else{c._toggleHighlight(d,&quot;from&quot;);}c.itemMouseOutEvent.fire(c,d);break;case&quot;ul&quot;:c._toggleHighlight(c._elCurListItem,&quot;to&quot;);break;case&quot;div&quot;:if(YAHOO.util.Dom.hasClass(d,&quot;yui-ac-container&quot;)){c._bOverContainer=false;return;}break;default:break;}d=d.parentNode;if(d){b=d.nodeName.toLowerCase();}}};YAHOO.widget.AutoComplete.prototype._onContainerClick=function(a,c){var d=YAHOO.util.Event.getTarget(a);var b=d.nodeName.toLowerCase();while(d&amp;&amp;(b!=&quot;table&quot;)){switch(b){case&quot;body&quot;:return;case&quot;li&quot;:c._toggleHighlight(d,&quot;to&quot;);c._selectItem(d);return;default:break;}d=d.parentNode;if(d){b=d.nodeName.toLowerCase();}}};YAHOO.widget.AutoComplete.prototype._onContainerScroll=function(a,b){b._focus();};YAHOO.widget.AutoComplete.prototype._onContainerResize=function(a,b){b._toggleContainerHelpers(b._bContainerOpen);};YAHOO.widget.AutoComplete.prototype._onTextbo
 xKeyDown=function(a,b){var c=a.keyCode;if(b._nTypeAheadDelayID!=-1){clearTimeout(b._nTypeAheadDelayID);}switch(c){case 9:if(!YAHOO.env.ua.opera&amp;&amp;(navigator.userAgent.toLowerCase().indexOf(&quot;mac&quot;)==-1)||(YAHOO.env.ua.webkit&gt;420)){if(b._elCurListItem){if(b.delimChar&amp;&amp;(b._nKeyCode!=c)){if(b._bContainerOpen){YAHOO.util.Event.stopEvent(a);}}b._selectItem(b._elCurListItem);}else{b._toggleContainer(false);}}break;case 13:if(!YAHOO.env.ua.opera&amp;&amp;(navigator.userAgent.toLowerCase().indexOf(&quot;mac&quot;)==-1)||(YAHOO.env.ua.webkit&gt;420)){if(b._elCurListItem){if(b._nKeyCode!=c){if(b._bContainerOpen){YAHOO.util.Event.stopEvent(a);}}b._selectItem(b._elCurListItem);}else{b._toggleContainer(false);}}break;case 27:b._toggleContainer(false);return;case 39:b._jumpSelection();break;case 38:if(b._bContainerOpen){YAHOO.util.Event.stopEvent(a);b._moveSelection(c);}break;case 40:if(b._bContainerOpen){YAHOO.util.Event.stopEvent(a);b._moveSelection(c);}break;d
 efault:b._bItemSelected=false;b._toggleHighlight(b._elCurListItem,&quot;from&quot;);b.textboxKeyEvent.fire(b,c);break;}if(c===18){b._enableIntervalDetection();}b._nKeyCode=c;};YAHOO.widget.AutoComplete.prototype._onTextboxKeyPress=function(a,b){var c=a.keyCode;if(YAHOO.env.ua.opera||(navigator.userAgent.toLowerCase().indexOf(&quot;mac&quot;)!=-1)&amp;&amp;(YAHOO.env.ua.webkit&lt;420)){switch(c){case 9:if(b._bContainerOpen){if(b.delimChar){YAHOO.util.Event.stopEvent(a);}if(b._elCurListItem){b._selectItem(b._elCurListItem);}else{b._toggleContainer(false);}}break;case 13:if(b._bContainerOpen){YAHOO.util.Event.stopEvent(a);
+if(b._elCurListItem){b._selectItem(b._elCurListItem);}else{b._toggleContainer(false);}}break;default:break;}}else{if(c==229){b._enableIntervalDetection();}}};YAHOO.widget.AutoComplete.prototype._onTextboxKeyUp=function(a,c){var b=this.value;c._initProps();var d=a.keyCode;if(c._isIgnoreKey(d)){return;}if(c._nDelayID!=-1){clearTimeout(c._nDelayID);}c._nDelayID=setTimeout(function(){c._sendQuery(b);},(c.queryDelay*1000));};YAHOO.widget.AutoComplete.prototype._onTextboxFocus=function(a,b){if(!b._bFocused){b._elTextbox.setAttribute(&quot;autocomplete&quot;,&quot;off&quot;);b._bFocused=true;b._sInitInputValue=b._elTextbox.value;b.textboxFocusEvent.fire(b);}};YAHOO.widget.AutoComplete.prototype._onTextboxBlur=function(a,c){if(!c._bOverContainer||(c._nKeyCode==9)){if(!c._bItemSelected){var b=c._textMatchesOption();if(!c._bContainerOpen||(c._bContainerOpen&amp;&amp;(b===null))){if(c.forceSelection){c._clearSelection();}else{c.unmatchedItemSelectEvent.fire(c,c._sCurQuery);}}else{if(c.
 forceSelection){c._selectItem(b);}}}c._clearInterval();c._bFocused=false;if(c._sInitInputValue!==c._elTextbox.value){c.textboxChangeEvent.fire(c);}c.textboxBlurEvent.fire(c);c._toggleContainer(false);}else{c._focus();}};YAHOO.widget.AutoComplete.prototype._onWindowUnload=function(a,b){if(b&amp;&amp;b._elTextbox&amp;&amp;b.allowBrowserAutocomplete){b._elTextbox.setAttribute(&quot;autocomplete&quot;,&quot;on&quot;);}};YAHOO.widget.AutoComplete.prototype.doBeforeSendQuery=function(a){return this.generateRequest(a);};YAHOO.widget.AutoComplete.prototype.getListItems=function(){var c=[],b=this._elList.childNodes;for(var a=b.length-1;a&gt;=0;a--){c[a]=b[a];}return c;};YAHOO.widget.AutoComplete._cloneObject=function(d){if(!YAHOO.lang.isValue(d)){return d;}var f={};if(YAHOO.lang.isFunction(d)){f=d;}else{if(YAHOO.lang.isArray(d)){var e=[];for(var c=0,b=d.length;c&lt;b;c++){e[c]=YAHOO.widget.AutoComplete._cloneObject(d[c]);}f=e;}else{if(YAHOO.lang.isObject(d)){for(var a in d){if(YAHOO.
 lang.hasOwnProperty(d,a)){if(YAHOO.lang.isValue(d[a])&amp;&amp;YAHOO.lang.isObject(d[a])||YAHOO.lang.isArray(d[a])){f[a]=YAHOO.widget.AutoComplete._cloneObject(d[a]);}else{f[a]=d[a];}}}}else{f=d;}}}return f;};YAHOO.register(&quot;autocomplete&quot;,YAHOO.widget.AutoComplete,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuibasebasemincss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/base/base-min.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/base/base-min.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/base/base-min.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+body{margin:10px}h1{font-size:138.5%}h2{font-size:123.1%}h3{font-size:108%}h1,h2,h3{margin:1em 0}h1,h2,h3,h4,h5,h6,strong,dt{font-weight:bold}optgroup{font-weight:normal}abbr,acronym{border-bottom:1px dotted #000;cursor:help}em{font-style:italic}del{text-decoration:line-through}blockquote,ul,ol,dl{margin:1em}ol,ul,dl{margin-left:2em}ol{list-style:decimal outside}ul{list-style:disc outside}dl dd{margin-left:1em}th,td{border:1px solid #000;padding:.5em}th{font-weight:bold;text-align:center}caption{margin-bottom:.5em;text-align:center}sup{vertical-align:super}sub{vertical-align:sub}p,fieldset,table,pre{margin-bottom:1em}button,input[type=&quot;checkbox&quot;],input[type=&quot;radio&quot;],input[type=&quot;reset&quot;],input[type=&quot;submit&quot;]{padding:1px}img{-ms-interpolation-mode:bicubic}
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuibasebasecss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/base/base.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/base/base.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/base/base.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,137 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+/**
+ * YUI Base
+ * @module base
+ * @namespace yui-
+ * @requires reset, fonts
+*/
+
+body {
+        /* For breathing room between content and viewport. */
+        margin:10px;
+}
+
+h1 {
+        /* 18px via YUI Fonts CSS foundation. */
+        font-size: 138.5%;
+}
+
+h2 {
+        /* 16px via YUI Fonts CSS foundation. */
+        font-size: 123.1%;
+}
+
+h3 {
+        /* 14px via YUI Fonts CSS foundation. */
+        font-size: 108%;
+}
+
+h1,h2,h3 {
+        /* Top &amp; bottom margin based on font size. */
+        margin: 1em 0;
+}
+
+h1,h2,h3,h4,h5,h6,strong,dt {
+        /* Bringing boldness back to headers and the strong element. */
+        font-weight: bold;
+}
+optgroup {
+        font-weight:normal;
+}
+
+abbr,acronym {
+        /* Indicating to users that more info is available. */
+        border-bottom: 1px dotted #000;
+        cursor: help;
+}
+
+em {
+        /* Bringing italics back to the em element. */
+        font-style: italic;
+}
+
+del {
+        /* Striking deleted phrases. */
+        text-decoration: line-through;
+}
+
+blockquote,ul,ol,dl {
+        /* Giving blockquotes and lists room to breath. */
+        margin: 1em;
+}
+
+ol,ul,dl {
+        /* Bringing lists on to the page with breathing room. */
+        margin-left: 2em;
+}
+
+ol {
+        /* Giving OL's LIs generated numbers. */
+        list-style: decimal outside;
+}
+
+ul {
+        /* Giving UL's LIs generated disc markers. */
+        list-style: disc outside;
+}
+
+dl dd {
+        /* Giving DD default indent. */
+        margin-left: 1em;
+}
+
+th,td {
+        /* Borders and padding to make the table readable. */
+        border: 1px solid #000;
+        padding: .5em;
+}
+
+th {
+        /* Distinguishing table headers from data cells. */
+        font-weight: bold;
+        text-align: center;
+}
+
+caption {
+        /* Coordinated margin to match cell's padding. */
+        margin-bottom: .5em;
+        /* Centered so it doesn't blend in to other content. */
+        text-align: center;
+}
+
+sup {
+        /* to preserve line-height and selector appearance */
+        vertical-align: super;
+}
+
+sub {
+        /* to preserve line-height and selector appearance */
+        vertical-align: sub;
+}
+
+p,
+fieldset,
+table,
+pre {
+        /* So things don't run into each other. */
+        margin-bottom: 1em;
+}
+/* Opera requires 1px of padding to render with contemporary native chrome */
+button,
+input[type=&quot;checkbox&quot;],
+input[type=&quot;radio&quot;],
+input[type=&quot;reset&quot;],
+input[type=&quot;submit&quot;] {
+        padding:1px;
+}
+
+/* make IE scale images properly */
+/* see http://code.flickr.com/blog/2008/11/12/on-ui-quality-the-little-things-client-side-image-resizing/ */
+ img {
+    -ms-interpolation-mode:bicubic;
+}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuibuttonbuttonminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/button/button-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/button/button-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/button/button-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,11 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+(function(){var G=YAHOO.util.Dom,M=YAHOO.util.Event,I=YAHOO.lang,L=YAHOO.env.ua,B=YAHOO.widget.Overlay,J=YAHOO.widget.Menu,D={},K=null,E=null,C=null;function F(O,N,R,P){var S,Q;if(I.isString(O)&amp;&amp;I.isString(N)){if(L.ie&amp;&amp;(L.ie&lt;9)){Q='&lt;input type=&quot;'+O+'&quot; name=&quot;'+N+'&quot;';if(P){Q+=&quot; checked&quot;;}Q+=&quot;&gt;&quot;;S=document.createElement(Q);S.value=R;}else{S=document.createElement(&quot;input&quot;);S.name=N;S.type=O;S.value=R;if(P){S.checked=true;}}}return S;}function H(O,V){var N=O.nodeName.toUpperCase(),S=(this.CLASS_NAME_PREFIX+this.CSS_CLASS_NAME),T=this,U,P,Q;function W(X){if(!(X in V)){U=O.getAttributeNode(X);if(U&amp;&amp;(&quot;value&quot; in U)){V[X]=U.value;}}}function R(){W(&quot;type&quot;);if(V.type==&quot;button&quot;){V.type=&quot;push&quot;;}if(!(&quot;disabled&quot; in V)){V.disabled=O.disabled;}W(&quot;name&quot;);W(&quot;value&quot;);W(&quot;title&quot;);}switch(N){case&quot;A&quot;:V.type=&quot;link&quot;;W(&qu
 ot;href&quot;);W(&quot;target&quot;);break;case&quot;INPUT&quot;:R();if(!(&quot;checked&quot; in V)){V.checked=O.checked;}break;case&quot;BUTTON&quot;:R();P=O.parentNode.parentNode;if(G.hasClass(P,S+&quot;-checked&quot;)){V.checked=true;}if(G.hasClass(P,S+&quot;-disabled&quot;)){V.disabled=true;}O.removeAttribute(&quot;value&quot;);O.setAttribute(&quot;type&quot;,&quot;button&quot;);break;}O.removeAttribute(&quot;id&quot;);O.removeAttribute(&quot;name&quot;);if(!(&quot;tabindex&quot; in V)){V.tabindex=O.tabIndex;}if(!(&quot;label&quot; in V)){Q=N==&quot;INPUT&quot;?O.value:O.innerHTML;if(Q&amp;&amp;Q.length&gt;0){V.label=Q;}}}function A(P){var O=P.attributes,N=O.srcelement,R=N.nodeName.toUpperCase(),Q=this;if(R==this.NODE_NAME){P.element=N;P.id=N.id;G.getElementsBy(function(S){switch(S.nodeName.toUpperCase()){case&quot;BUTTON&quot;:case&quot;A&quot;:case&quot;INPUT&quot;:H.call(Q,S,O);break;}},&quot;*&quot;,N);}else{switch(R){case&quot;BUTTON&quot;:case&quot;A&quot;:case&quo
 t;INPUT&quot;:H.call(this,N,O);break;}}}YAHOO.widget.Button=function(R,O){if(!B&amp;&amp;YAHOO.widget.Overlay){B=YAHOO.widget.Overlay;}if(!J&amp;&amp;YAHOO.widget.Menu){J=YAHOO.widget.Menu;}var Q=YAHOO.widget.Button.superclass.constructor,P,N;if(arguments.length==1&amp;&amp;!I.isString(R)&amp;&amp;!R.nodeName){if(!R.id){R.id=G.generateId();}Q.call(this,(this.createButtonElement(R.type)),R);}else{P={element:null,attributes:(O||{})};if(I.isString(R)){N=G.get(R);if(N){if(!P.attributes.id){P.attributes.id=R;}P.attributes.srcelement=N;A.call(this,P);if(!P.element){P.element=this.createButtonElement(P.attributes.type);}Q.call(this,P.element,P.attributes);}}else{if(R.nodeName){if(!P.attributes.id){if(R.id){P.attributes.id=R.id;}else{P.attributes.id=G.generateId();}}P.attributes.srcelement=R;A.call(this,P);if(!P.element){P.element=this.createButtonElement(P.attributes.type);}Q.call(this,P.element,P.attributes);}}}};YAHOO.extend(YAHOO.widget.Button,YAHOO.util.Element,{_button:null,_m
 enu:null,_hiddenFields:null,_onclickAttributeValue:null,_activationKeyPressed:false,_activationButtonPressed:false,_hasKeyEventHandlers:false,_hasMouseEventHandlers:false,_nOptionRegionX:0,CLASS_NAME_PREFIX:&quot;yui-&quot;,NODE_NAME:&quot;SPAN&quot;,CHECK_ACTIVATION_KEYS:[32],ACTIVATION_KEYS:[13,32],OPTION_AREA_WIDTH:20,CSS_CLASS_NAME:&quot;button&quot;,_setType:function(N){if(N==&quot;split&quot;){this.on(&quot;option&quot;,this._onOption);}},_setLabel:function(O){this._button.innerHTML=O;var P,N=L.gecko;if(N&amp;&amp;N&lt;1.9&amp;&amp;G.inDocument(this.get(&quot;element&quot;))){P=(this.CLASS_NAME_PREFIX+this.CSS_CLASS_NAME);this.removeClass(P);I.later(0,this,this.addClass,P);}},_setTabIndex:function(N){this._button.tabIndex=N;},_setTitle:function(N){if(this.get(&quot;type&quot;)!=&quot;link&quot;){this._button.title=N;}},_setDisabled:function(N){if(this.get(&quot;type&quot;)!=&quot;link&quot;){if(N){if(this._menu){this._menu.hide();}if(this.hasFocus()){this.blur();}this.
 _button.setAttribute(&quot;disabled&quot;,&quot;disabled&quot;);this.addStateCSSClasses(&quot;disabled&quot;);this.removeStateCSSClasses(&quot;hover&quot;);this.removeStateCSSClasses(&quot;active&quot;);this.removeStateCSSClasses(&quot;focus&quot;);}else{this._button.removeAttribute(&quot;disabled&quot;);this.removeStateCSSClasses(&quot;disabled&quot;);}}},_setHref:function(N){if(this.get(&quot;type&quot;)==&quot;link&quot;){this._button.href=N;}},_setTarget:function(N){if(this.get(&quot;type&quot;)==&quot;link&quot;){this._button.setAttribute(&quot;target&quot;,N);}},_setChecked:function(N){var O=this.get(&quot;type&quot;);if(O==&quot;checkbox&quot;||O==&quot;radio&quot;){if(N){this.addStateCSSClasses(&quot;checked&quot;);}else{this.removeStateCSSClasses(&quot;checked&quot;);}}},_setMenu:function(U){var P=this.get(&quot;lazyloadmenu&quot;),R=this.get(&quot;element&quot;),N,W=false,X,O,Q;function V(){X.render(R.parentNode);this.removeListener(&quot;appendTo&quot;,V);}functio
 n T(){X.cfg.queueProperty(&quot;container&quot;,R.parentNode);this.removeListener(&quot;appendTo&quot;,T);}function S(){var Y;if(X){G.addClass(X.element,this.get(&quot;menuclassname&quot;));G.addClass(X.element,this.CLASS_NAME_PREFIX+this.get(&quot;type&quot;)+&quot;-button-menu&quot;);X.showEvent.subscribe(this._onMenuShow,null,this);X.hideEvent.subscribe(this._onMenuHide,null,this);X.renderEvent.subscribe(this._onMenuRender,null,this);if(J&amp;&amp;X instanceof J){if(P){Y=this.get(&quot;container&quot;);if(Y){X.cfg.queueProperty(&quot;container&quot;,Y);}else{this.on(&quot;appendTo&quot;,T);}}X.cfg.queueProperty(&quot;clicktohide&quot;,false);X.keyDownEvent.subscribe(this._onMenuKeyDown,this,true);X.subscribe(&quot;click&quot;,this._onMenuClick,this,true);this.on(&quot;selectedMenuItemChange&quot;,this._onSelectedMenuItemChange);Q=X.srcElement;if(Q&amp;&amp;Q.nodeName.toUpperCase()==&quot;SELECT&quot;){Q.style.display=&quot;none&quot;;Q.parentNode.removeChild(Q);}}else{if(
 B&amp;&amp;X instanceof B){if(!K){K=new YAHOO.widget.OverlayManager();}K.register(X);}}this._menu=X;if(!W&amp;&amp;!P){if(G.inDocument(R)){X.render(R.parentNode);}else{this.on(&quot;appendTo&quot;,V);}}}}if(B){if(J){N=J.prototype.CSS_CLASS_NAME;}if(U&amp;&amp;J&amp;&amp;(U instanceof J)){X=U;W=true;S.call(this);}else{if(B&amp;&amp;U&amp;&amp;(U instanceof B)){X=U;W=true;X.cfg.queueProperty(&quot;visible&quot;,false);S.call(this);}else{if(J&amp;&amp;I.isArray(U)){X=new J(G.generateId(),{lazyload:P,itemdata:U});this._menu=X;this.on(&quot;appendTo&quot;,S);}else{if(I.isString(U)){O=G.get(U);if(O){if(J&amp;&amp;G.hasClass(O,N)||O.nodeName.toUpperCase()==&quot;SELECT&quot;){X=new J(U,{lazyload:P});S.call(this);}else{if(B){X=new B(U,{visible:false});S.call(this);}}}}else{if(U&amp;&amp;U.nodeName){if(J&amp;&amp;G.hasClass(U,N)||U.nodeName.toUpperCase()==&quot;SELECT&quot;){X=new J(U,{lazyload:P});S.call(this);}else{if(B){if(!U.id){G.generateId(U);}X=new B(U,{visible:false});S.call(
 this);}}}}}}}}},_setOnClick:function(N){if(this._onclickAttributeValue&amp;&amp;(this._onclickAttributeValue!=N)){this.removeListener(&quot;click&quot;,this._onclickAttributeValue.fn);
+this._onclickAttributeValue=null;}if(!this._onclickAttributeValue&amp;&amp;I.isObject(N)&amp;&amp;I.isFunction(N.fn)){this.on(&quot;click&quot;,N.fn,N.obj,N.scope);this._onclickAttributeValue=N;}},_isActivationKey:function(N){var S=this.get(&quot;type&quot;),O=(S==&quot;checkbox&quot;||S==&quot;radio&quot;)?this.CHECK_ACTIVATION_KEYS:this.ACTIVATION_KEYS,Q=O.length,R=false,P;if(Q&gt;0){P=Q-1;do{if(N==O[P]){R=true;break;}}while(P--);}return R;},_isSplitButtonOptionKey:function(P){var O=(M.getCharCode(P)==40);var N=function(Q){M.preventDefault(Q);this.removeListener(&quot;keypress&quot;,N);};if(O){if(L.opera){this.on(&quot;keypress&quot;,N);}M.preventDefault(P);}return O;},_addListenersToForm:function(){var T=this.getForm(),S=YAHOO.widget.Button.onFormKeyPress,R,N,Q,P,O;if(T){M.on(T,&quot;reset&quot;,this._onFormReset,null,this);M.on(T,&quot;submit&quot;,this._onFormSubmit,null,this);N=this.get(&quot;srcelement&quot;);if(this.get(&quot;type&quot;)==&quot;submit&quot;||(N&amp;&
 amp;N.type==&quot;submit&quot;)){Q=M.getListeners(T,&quot;keypress&quot;);R=false;if(Q){P=Q.length;if(P&gt;0){O=P-1;do{if(Q[O].fn==S){R=true;break;}}while(O--);}}if(!R){M.on(T,&quot;keypress&quot;,S);}}}},_showMenu:function(R){if(YAHOO.widget.MenuManager){YAHOO.widget.MenuManager.hideVisible();}if(K){K.hideAll();}var N=this._menu,Q=this.get(&quot;menualignment&quot;),P=this.get(&quot;focusmenu&quot;),O;if(this._renderedMenu){N.cfg.setProperty(&quot;context&quot;,[this.get(&quot;element&quot;),Q[0],Q[1]]);N.cfg.setProperty(&quot;preventcontextoverlap&quot;,true);N.cfg.setProperty(&quot;constraintoviewport&quot;,true);}else{N.cfg.queueProperty(&quot;context&quot;,[this.get(&quot;element&quot;),Q[0],Q[1]]);N.cfg.queueProperty(&quot;preventcontextoverlap&quot;,true);N.cfg.queueProperty(&quot;constraintoviewport&quot;,true);}this.focus();if(J&amp;&amp;N&amp;&amp;(N instanceof J)){O=N.focus;N.focus=function(){};if(this._renderedMenu){N.cfg.setProperty(&quot;minscrollheight&quot;,t
 his.get(&quot;menuminscrollheight&quot;));N.cfg.setProperty(&quot;maxheight&quot;,this.get(&quot;menumaxheight&quot;));}else{N.cfg.queueProperty(&quot;minscrollheight&quot;,this.get(&quot;menuminscrollheight&quot;));N.cfg.queueProperty(&quot;maxheight&quot;,this.get(&quot;menumaxheight&quot;));}N.show();N.focus=O;N.align();if(R.type==&quot;mousedown&quot;){M.stopPropagation(R);}if(P){N.focus();}}else{if(B&amp;&amp;N&amp;&amp;(N instanceof B)){if(!this._renderedMenu){N.render(this.get(&quot;element&quot;).parentNode);}N.show();N.align();}}},_hideMenu:function(){var N=this._menu;if(N){N.hide();}},_onMouseOver:function(O){var Q=this.get(&quot;type&quot;),N,P;if(Q===&quot;split&quot;){N=this.get(&quot;element&quot;);P=(G.getX(N)+(N.offsetWidth-this.OPTION_AREA_WIDTH));this._nOptionRegionX=P;}if(!this._hasMouseEventHandlers){if(Q===&quot;split&quot;){this.on(&quot;mousemove&quot;,this._onMouseMove);}this.on(&quot;mouseout&quot;,this._onMouseOut);this._hasMouseEventHandlers=true;}
 this.addStateCSSClasses(&quot;hover&quot;);if(Q===&quot;split&quot;&amp;&amp;(M.getPageX(O)&gt;P)){this.addStateCSSClasses(&quot;hoveroption&quot;);}if(this._activationButtonPressed){this.addStateCSSClasses(&quot;active&quot;);}if(this._bOptionPressed){this.addStateCSSClasses(&quot;activeoption&quot;);}if(this._activationButtonPressed||this._bOptionPressed){M.removeListener(document,&quot;mouseup&quot;,this._onDocumentMouseUp);}},_onMouseMove:function(N){var O=this._nOptionRegionX;if(O){if(M.getPageX(N)&gt;O){this.addStateCSSClasses(&quot;hoveroption&quot;);}else{this.removeStateCSSClasses(&quot;hoveroption&quot;);}}},_onMouseOut:function(N){var O=this.get(&quot;type&quot;);this.removeStateCSSClasses(&quot;hover&quot;);if(O!=&quot;menu&quot;){this.removeStateCSSClasses(&quot;active&quot;);}if(this._activationButtonPressed||this._bOptionPressed){M.on(document,&quot;mouseup&quot;,this._onDocumentMouseUp,null,this);}if(O===&quot;split&quot;&amp;&amp;(M.getPageX(N)&gt;this._nOpt
 ionRegionX)){this.removeStateCSSClasses(&quot;hoveroption&quot;);}},_onDocumentMouseUp:function(P){this._activationButtonPressed=false;this._bOptionPressed=false;var Q=this.get(&quot;type&quot;),N,O;if(Q==&quot;menu&quot;||Q==&quot;split&quot;){N=M.getTarget(P);O=this._menu.element;if(N!=O&amp;&amp;!G.isAncestor(O,N)){this.removeStateCSSClasses((Q==&quot;menu&quot;?&quot;active&quot;:&quot;activeoption&quot;));this._hideMenu();}}M.removeListener(document,&quot;mouseup&quot;,this._onDocumentMouseUp);},_onMouseDown:function(P){var Q,O=true;function N(){this._hideMenu();this.removeListener(&quot;mouseup&quot;,N);}if((P.which||P.button)==1){if(!this.hasFocus()){I.later(0,this,this.focus);}Q=this.get(&quot;type&quot;);if(Q==&quot;split&quot;){if(M.getPageX(P)&gt;this._nOptionRegionX){this.fireEvent(&quot;option&quot;,P);O=false;}else{this.addStateCSSClasses(&quot;active&quot;);this._activationButtonPressed=true;}}else{if(Q==&quot;menu&quot;){if(this.isActive()){this._hideMenu();t
 his._activationButtonPressed=false;}else{this._showMenu(P);this._activationButtonPressed=true;}}else{this.addStateCSSClasses(&quot;active&quot;);this._activationButtonPressed=true;}}if(Q==&quot;split&quot;||Q==&quot;menu&quot;){this._hideMenuTimer=I.later(250,this,this.on,[&quot;mouseup&quot;,N]);}}return O;},_onMouseUp:function(P){this.inMouseDown=false;var Q=this.get(&quot;type&quot;),N=this._hideMenuTimer,O=true;if(N){N.cancel();}if(Q==&quot;checkbox&quot;||Q==&quot;radio&quot;){if((P.which||P.button)!=1){return;}this.set(&quot;checked&quot;,!(this.get(&quot;checked&quot;)));}this._activationButtonPressed=false;if(Q!=&quot;menu&quot;){this.removeStateCSSClasses(&quot;active&quot;);}if(Q==&quot;split&quot;&amp;&amp;M.getPageX(P)&gt;this._nOptionRegionX){O=false;}return O;},_onFocus:function(O){var N;this.addStateCSSClasses(&quot;focus&quot;);if(this._activationKeyPressed){this.addStateCSSClasses(&quot;active&quot;);}C=this;if(!this._hasKeyEventHandlers){N=this._button;M.on
 (N,&quot;blur&quot;,this._onBlur,null,this);M.on(N,&quot;keydown&quot;,this._onKeyDown,null,this);M.on(N,&quot;keyup&quot;,this._onKeyUp,null,this);this._hasKeyEventHandlers=true;}this.fireEvent(&quot;focus&quot;,O);},_onBlur:function(N){this.removeStateCSSClasses(&quot;focus&quot;);if(this.get(&quot;type&quot;)!=&quot;menu&quot;){this.removeStateCSSClasses(&quot;active&quot;);}if(this._activationKeyPressed){M.on(document,&quot;keyup&quot;,this._onDocumentKeyUp,null,this);}C=null;this.fireEvent(&quot;blur&quot;,N);},_onDocumentKeyUp:function(N){if(this._isActivationKey(M.getCharCode(N))){this._activationKeyPressed=false;M.removeListener(document,&quot;keyup&quot;,this._onDocumentKeyUp);}},_onKeyDown:function(O){var N=this._menu;if(this.get(&quot;type&quot;)==&quot;split&quot;&amp;&amp;this._isSplitButtonOptionKey(O)){this.fireEvent(&quot;option&quot;,O);}else{if(this._isActivationKey(M.getCharCode(O))){if(this.get(&quot;type&quot;)==&quot;menu&quot;){this._showMenu(O);}else{
 this._activationKeyPressed=true;this.addStateCSSClasses(&quot;active&quot;);}}}if(N&amp;&amp;N.cfg.getProperty(&quot;visible&quot;)&amp;&amp;M.getCharCode(O)==27){N.hide();this.focus();}},_onKeyUp:function(N){var O;
+if(this._isActivationKey(M.getCharCode(N))){O=this.get(&quot;type&quot;);if(O==&quot;checkbox&quot;||O==&quot;radio&quot;){this.set(&quot;checked&quot;,!(this.get(&quot;checked&quot;)));}this._activationKeyPressed=false;if(this.get(&quot;type&quot;)!=&quot;menu&quot;){this.removeStateCSSClasses(&quot;active&quot;);}}},_onClick:function(P){var R=this.get(&quot;type&quot;),Q,N,O;switch(R){case&quot;submit&quot;:if(P.returnValue!==false){this.submitForm();}break;case&quot;reset&quot;:Q=this.getForm();if(Q){Q.reset();}break;case&quot;split&quot;:if(this._nOptionRegionX&gt;0&amp;&amp;(M.getPageX(P)&gt;this._nOptionRegionX)){O=false;}else{this._hideMenu();N=this.get(&quot;srcelement&quot;);if(N&amp;&amp;N.type==&quot;submit&quot;&amp;&amp;P.returnValue!==false){this.submitForm();}}break;}return O;},_onDblClick:function(O){var N=true;if(this.get(&quot;type&quot;)==&quot;split&quot;&amp;&amp;M.getPageX(O)&gt;this._nOptionRegionX){N=false;}return N;},_onAppendTo:function(N){I.later(0
 ,this,this._addListenersToForm);},_onFormReset:function(O){var P=this.get(&quot;type&quot;),N=this._menu;if(P==&quot;checkbox&quot;||P==&quot;radio&quot;){this.resetValue(&quot;checked&quot;);}if(J&amp;&amp;N&amp;&amp;(N instanceof J)){this.resetValue(&quot;selectedMenuItem&quot;);}},_onFormSubmit:function(N){this.createHiddenFields();},_onDocumentMouseDown:function(R){var O=M.getTarget(R),Q=this.get(&quot;element&quot;),P=this._menu.element;function N(T){var V,S,U;if(!T){return true;}for(V=0,S=T.length;V&lt;S;V++){U=T[V].element;if(O==U||G.isAncestor(U,O)){return true;}if(T[V]&amp;&amp;T[V].getSubmenus){if(N(T[V].getSubmenus())){return true;}}}return false;}if(O!=Q&amp;&amp;!G.isAncestor(Q,O)&amp;&amp;O!=P&amp;&amp;!G.isAncestor(P,O)){if(this._menu&amp;&amp;this._menu.getSubmenus){if(!N(this._menu.getSubmenus())){return;}}this._hideMenu();if(L.ie&amp;&amp;(L.ie&lt;9)&amp;&amp;O.focus){O.setActive();}M.removeListener(document,&quot;mousedown&quot;,this._onDocumentMouseDown);
 }},_onOption:function(N){if(this.hasClass(this.CLASS_NAME_PREFIX+&quot;split-button-activeoption&quot;)){this._hideMenu();this._bOptionPressed=false;}else{this._showMenu(N);this._bOptionPressed=true;}},_onMenuShow:function(N){M.on(document,&quot;mousedown&quot;,this._onDocumentMouseDown,null,this);var O=(this.get(&quot;type&quot;)==&quot;split&quot;)?&quot;activeoption&quot;:&quot;active&quot;;this.addStateCSSClasses(O);},_onMenuHide:function(N){var O=(this.get(&quot;type&quot;)==&quot;split&quot;)?&quot;activeoption&quot;:&quot;active&quot;;this.removeStateCSSClasses(O);if(this.get(&quot;type&quot;)==&quot;split&quot;){this._bOptionPressed=false;}},_onMenuKeyDown:function(P,O){var N=O[0];if(M.getCharCode(N)==27){this.focus();if(this.get(&quot;type&quot;)==&quot;split&quot;){this._bOptionPressed=false;}}},_onMenuRender:function(P){var S=this.get(&quot;element&quot;),O=S.parentNode,N=this._menu,R=N.element,Q=N.srcElement,T;if(O!=R.parentNode){O.appendChild(R);}this._renderedM
 enu=true;if(Q&amp;&amp;Q.nodeName.toLowerCase()===&quot;select&quot;&amp;&amp;Q.value){T=N.getItem(Q.selectedIndex);this.set(&quot;selectedMenuItem&quot;,T,true);this._onSelectedMenuItemChange({newValue:T});}},_onMenuClick:function(O,N){var Q=N[1],P;if(Q){this.set(&quot;selectedMenuItem&quot;,Q);P=this.get(&quot;srcelement&quot;);if(P&amp;&amp;P.type==&quot;submit&quot;){this.submitForm();}this._hideMenu();}},_onSelectedMenuItemChange:function(O){var P=O.prevValue,Q=O.newValue,N=this.CLASS_NAME_PREFIX;if(P){G.removeClass(P.element,(N+&quot;button-selectedmenuitem&quot;));}if(Q){G.addClass(Q.element,(N+&quot;button-selectedmenuitem&quot;));}},_onLabelClick:function(N){this.focus();var O=this.get(&quot;type&quot;);if(O==&quot;radio&quot;||O==&quot;checkbox&quot;){this.set(&quot;checked&quot;,(!this.get(&quot;checked&quot;)));}},createButtonElement:function(N){var P=this.NODE_NAME,O=document.createElement(P);O.innerHTML=&quot;&lt;&quot;+P+' class=&quot;first-child&quot;&gt;'+(N
 ==&quot;link&quot;?&quot;&lt;a&gt;&lt;/a&gt;&quot;:'&lt;button type=&quot;button&quot;&gt;&lt;/button&gt;')+&quot;&lt;/&quot;+P+&quot;&gt;&quot;;return O;},addStateCSSClasses:function(O){var P=this.get(&quot;type&quot;),N=this.CLASS_NAME_PREFIX;if(I.isString(O)){if(O!=&quot;activeoption&quot;&amp;&amp;O!=&quot;hoveroption&quot;){this.addClass(N+this.CSS_CLASS_NAME+(&quot;-&quot;+O));}this.addClass(N+P+(&quot;-button-&quot;+O));}},removeStateCSSClasses:function(O){var P=this.get(&quot;type&quot;),N=this.CLASS_NAME_PREFIX;if(I.isString(O)){this.removeClass(N+this.CSS_CLASS_NAME+(&quot;-&quot;+O));this.removeClass(N+P+(&quot;-button-&quot;+O));}},createHiddenFields:function(){this.removeHiddenFields();var V=this.getForm(),Z,O,S,X,Y,T,U,N,R,W,P,Q=false;if(V&amp;&amp;!this.get(&quot;disabled&quot;)){O=this.get(&quot;type&quot;);S=(O==&quot;checkbox&quot;||O==&quot;radio&quot;);if((S&amp;&amp;this.get(&quot;checked&quot;))||(E==this)){Z=F((S?O:&quot;hidden&quot;),this.get(&quot;na
 me&quot;),this.get(&quot;value&quot;),this.get(&quot;checked&quot;));if(Z){if(S){Z.style.display=&quot;none&quot;;}V.appendChild(Z);}}X=this._menu;if(J&amp;&amp;X&amp;&amp;(X instanceof J)){Y=this.get(&quot;selectedMenuItem&quot;);P=X.srcElement;Q=(P&amp;&amp;P.nodeName.toUpperCase()==&quot;SELECT&quot;);if(Y){U=(Y.value===null||Y.value===&quot;&quot;)?Y.cfg.getProperty(&quot;text&quot;):Y.value;T=this.get(&quot;name&quot;);if(Q){W=P.name;}else{if(T){W=(T+&quot;_options&quot;);}}if(U&amp;&amp;W){N=F(&quot;hidden&quot;,W,U);V.appendChild(N);}}else{if(Q){N=V.appendChild(P);}}}if(Z&amp;&amp;N){this._hiddenFields=[Z,N];}else{if(!Z&amp;&amp;N){this._hiddenFields=N;}else{if(Z&amp;&amp;!N){this._hiddenFields=Z;}}}R=this._hiddenFields;}return R;},removeHiddenFields:function(){var Q=this._hiddenFields,O,P;function N(R){if(G.inDocument(R)){R.parentNode.removeChild(R);}}if(Q){if(I.isArray(Q)){O=Q.length;if(O&gt;0){P=O-1;do{N(Q[P]);}while(P--);}}else{N(Q);}this._hiddenFields=null;}},sub
 mitForm:function(){var Q=this.getForm(),P=this.get(&quot;srcelement&quot;),O=false,N;if(Q){if(this.get(&quot;type&quot;)==&quot;submit&quot;||(P&amp;&amp;P.type==&quot;submit&quot;)){E=this;}if(L.ie&amp;&amp;(L.ie&lt;9)){O=Q.fireEvent(&quot;onsubmit&quot;);}else{N=document.createEvent(&quot;HTMLEvents&quot;);N.initEvent(&quot;submit&quot;,true,true);O=Q.dispatchEvent(N);}if((L.ie||L.webkit)&amp;&amp;O){Q.submit();}}return O;},init:function(P,d){var V=d.type==&quot;link&quot;?&quot;a&quot;:&quot;button&quot;,a=d.srcelement,S=P.getElementsByTagName(V)[0],U;if(!S){U=P.getElementsByTagName(&quot;input&quot;)[0];if(U){S=document.createElement(&quot;button&quot;);S.setAttribute(&quot;type&quot;,&quot;button&quot;);U.parentNode.replaceChild(S,U);}}this._button=S;YAHOO.widget.Button.superclass.init.call(this,P,d);var T=this.get(&quot;id&quot;),Z=T+&quot;-button&quot;;S.id=Z;var X,Q;var e=function(f){return(f.htmlFor===T);};var c=function(){Q.setAttribute((L.ie?&quot;htmlFor&quot;:&q
 uot;for&quot;),Z);};if(a&amp;&amp;this.get(&quot;type&quot;)!=&quot;link&quot;){X=G.getElementsBy(e,&quot;label&quot;);if(I.isArray(X)&amp;&amp;X.length&gt;0){Q=X[0];}}D[T]=this;var b=this.CLASS_NAME_PREFIX;this.addClass(b+this.CSS_CLASS_NAME);this.addClass(b+this.get(&quot;type&quot;)+&quot;-button&quot;);M.on(this._button,&quot;focus&quot;,this._onFocus,null,this);this.on(&quot;mouseover&quot;,this._onMouseOver);this.on(&quot;mousedown&quot;,this._onMouseDown);
+this.on(&quot;mouseup&quot;,this._onMouseUp);this.on(&quot;click&quot;,this._onClick);var R=this.get(&quot;onclick&quot;);this.set(&quot;onclick&quot;,null);this.set(&quot;onclick&quot;,R);this.on(&quot;dblclick&quot;,this._onDblClick);var O;if(Q){if(this.get(&quot;replaceLabel&quot;)){this.set(&quot;label&quot;,Q.innerHTML);O=Q.parentNode;O.removeChild(Q);}else{this.on(&quot;appendTo&quot;,c);M.on(Q,&quot;click&quot;,this._onLabelClick,null,this);this._label=Q;}}this.on(&quot;appendTo&quot;,this._onAppendTo);var N=this.get(&quot;container&quot;),Y=this.get(&quot;element&quot;),W=G.inDocument(Y);if(N){if(a&amp;&amp;a!=Y){O=a.parentNode;if(O){O.removeChild(a);}}if(I.isString(N)){M.onContentReady(N,this.appendTo,N,this);}else{this.on(&quot;init&quot;,function(){I.later(0,this,this.appendTo,N);});}}else{if(!W&amp;&amp;a&amp;&amp;a!=Y){O=a.parentNode;if(O){this.fireEvent(&quot;beforeAppendTo&quot;,{type:&quot;beforeAppendTo&quot;,target:O});O.replaceChild(Y,a);this.fireEvent(&qu
 ot;appendTo&quot;,{type:&quot;appendTo&quot;,target:O});}}else{if(this.get(&quot;type&quot;)!=&quot;link&quot;&amp;&amp;W&amp;&amp;a&amp;&amp;a==Y){this._addListenersToForm();}}}this.fireEvent(&quot;init&quot;,{type:&quot;init&quot;,target:this});},initAttributes:function(O){var N=O||{};YAHOO.widget.Button.superclass.initAttributes.call(this,N);this.setAttributeConfig(&quot;type&quot;,{value:(N.type||&quot;push&quot;),validator:I.isString,writeOnce:true,method:this._setType});this.setAttributeConfig(&quot;label&quot;,{value:N.label,validator:I.isString,method:this._setLabel});this.setAttributeConfig(&quot;value&quot;,{value:N.value});this.setAttributeConfig(&quot;name&quot;,{value:N.name,validator:I.isString});this.setAttributeConfig(&quot;tabindex&quot;,{value:N.tabindex,validator:I.isNumber,method:this._setTabIndex});this.configureAttribute(&quot;title&quot;,{value:N.title,validator:I.isString,method:this._setTitle});this.setAttributeConfig(&quot;disabled&quot;,{value:(N.d
 isabled||false),validator:I.isBoolean,method:this._setDisabled});this.setAttributeConfig(&quot;href&quot;,{value:N.href,validator:I.isString,method:this._setHref});this.setAttributeConfig(&quot;target&quot;,{value:N.target,validator:I.isString,method:this._setTarget});this.setAttributeConfig(&quot;checked&quot;,{value:(N.checked||false),validator:I.isBoolean,method:this._setChecked});this.setAttributeConfig(&quot;container&quot;,{value:N.container,writeOnce:true});this.setAttributeConfig(&quot;srcelement&quot;,{value:N.srcelement,writeOnce:true});this.setAttributeConfig(&quot;menu&quot;,{value:null,method:this._setMenu,writeOnce:true});this.setAttributeConfig(&quot;lazyloadmenu&quot;,{value:(N.lazyloadmenu===false?false:true),validator:I.isBoolean,writeOnce:true});this.setAttributeConfig(&quot;menuclassname&quot;,{value:(N.menuclassname||(this.CLASS_NAME_PREFIX+&quot;button-menu&quot;)),validator:I.isString,method:this._setMenuClassName,writeOnce:true});this.setAttributeConf
 ig(&quot;menuminscrollheight&quot;,{value:(N.menuminscrollheight||90),validator:I.isNumber});this.setAttributeConfig(&quot;menumaxheight&quot;,{value:(N.menumaxheight||0),validator:I.isNumber});this.setAttributeConfig(&quot;menualignment&quot;,{value:(N.menualignment||[&quot;tl&quot;,&quot;bl&quot;]),validator:I.isArray});this.setAttributeConfig(&quot;selectedMenuItem&quot;,{value:null});this.setAttributeConfig(&quot;onclick&quot;,{value:N.onclick,method:this._setOnClick});this.setAttributeConfig(&quot;focusmenu&quot;,{value:(N.focusmenu===false?false:true),validator:I.isBoolean});this.setAttributeConfig(&quot;replaceLabel&quot;,{value:false,validator:I.isBoolean,writeOnce:true});},focus:function(){if(!this.get(&quot;disabled&quot;)){try{this._button.focus();}catch(N){}}},blur:function(){if(!this.get(&quot;disabled&quot;)){try{this._button.blur();}catch(N){}}},hasFocus:function(){return(C==this);},isActive:function(){return this.hasClass(this.CLASS_NAME_PREFIX+this.CSS_CLASS
 _NAME+&quot;-active&quot;);},getMenu:function(){return this._menu;},getForm:function(){var N=this._button,O;if(N){O=N.form;}return O;},getHiddenFields:function(){return this._hiddenFields;},destroy:function(){var P=this.get(&quot;element&quot;),N=this._menu,T=this._label,O,S;if(N){if(K&amp;&amp;K.find(N)){K.remove(N);}N.destroy();}M.purgeElement(P);M.purgeElement(this._button);M.removeListener(document,&quot;mouseup&quot;,this._onDocumentMouseUp);M.removeListener(document,&quot;keyup&quot;,this._onDocumentKeyUp);M.removeListener(document,&quot;mousedown&quot;,this._onDocumentMouseDown);if(T){M.removeListener(T,&quot;click&quot;,this._onLabelClick);O=T.parentNode;O.removeChild(T);}var Q=this.getForm();if(Q){M.removeListener(Q,&quot;reset&quot;,this._onFormReset);M.removeListener(Q,&quot;submit&quot;,this._onFormSubmit);}this.unsubscribeAll();O=P.parentNode;if(O){O.removeChild(P);}delete D[this.get(&quot;id&quot;)];var R=(this.CLASS_NAME_PREFIX+this.CSS_CLASS_NAME);S=G.getElem
 entsByClassName(R,this.NODE_NAME,Q);if(I.isArray(S)&amp;&amp;S.length===0){M.removeListener(Q,&quot;keypress&quot;,YAHOO.widget.Button.onFormKeyPress);}},fireEvent:function(O,N){var P=arguments[0];if(this.DOM_EVENTS[P]&amp;&amp;this.get(&quot;disabled&quot;)){return false;}return YAHOO.widget.Button.superclass.fireEvent.apply(this,arguments);},toString:function(){return(&quot;Button &quot;+this.get(&quot;id&quot;));}});YAHOO.widget.Button.onFormKeyPress=function(R){var P=M.getTarget(R),S=M.getCharCode(R),Q=P.nodeName&amp;&amp;P.nodeName.toUpperCase(),N=P.type,T=false,V,X,O,W;function U(a){var Z,Y;switch(a.nodeName.toUpperCase()){case&quot;INPUT&quot;:case&quot;BUTTON&quot;:if(a.type==&quot;submit&quot;&amp;&amp;!a.disabled){if(!T&amp;&amp;!O){O=a;}}break;default:Z=a.id;if(Z){V=D[Z];if(V){T=true;if(!V.get(&quot;disabled&quot;)){Y=V.get(&quot;srcelement&quot;);if(!X&amp;&amp;(V.get(&quot;type&quot;)==&quot;submit&quot;||(Y&amp;&amp;Y.type==&quot;submit&quot;))){X=V;}}}}break;}
 }if(S==13&amp;&amp;((Q==&quot;INPUT&quot;&amp;&amp;(N==&quot;text&quot;||N==&quot;password&quot;||N==&quot;checkbox&quot;||N==&quot;radio&quot;||N==&quot;file&quot;))||Q==&quot;SELECT&quot;)){G.getElementsBy(U,&quot;*&quot;,this);if(O){O.focus();}else{if(!O&amp;&amp;X){M.preventDefault(R);if(L.ie){X.get(&quot;element&quot;).fireEvent(&quot;onclick&quot;);}else{W=document.createEvent(&quot;HTMLEvents&quot;);W.initEvent(&quot;click&quot;,true,true);if(L.gecko&lt;1.9){X.fireEvent(&quot;click&quot;,W);}else{X.get(&quot;element&quot;).dispatchEvent(W);}}}}}};YAHOO.widget.Button.addHiddenFieldsToForm=function(N){var R=YAHOO.widget.Button.prototype,T=G.getElementsByClassName((R.CLASS_NAME_PREFIX+R.CSS_CLASS_NAME),&quot;*&quot;,N),Q=T.length,S,O,P;if(Q&gt;0){for(P=0;P&lt;Q;P++){O=T[P].id;if(O){S=D[O];if(S){S.createHiddenFields();}}}}};YAHOO.widget.Button.getButton=function(N){return D[N];};})();(function(){var C=YAHOO.util.Dom,B=YAHOO.util.Event,D=YAHOO.lang,A=YAHOO.widget.Button,E=
 {};YAHOO.widget.ButtonGroup=function(J,H){var I=YAHOO.widget.ButtonGroup.superclass.constructor,K,G,F;
+if(arguments.length==1&amp;&amp;!D.isString(J)&amp;&amp;!J.nodeName){if(!J.id){F=C.generateId();J.id=F;}I.call(this,(this._createGroupElement()),J);}else{if(D.isString(J)){G=C.get(J);if(G){if(G.nodeName.toUpperCase()==this.NODE_NAME){I.call(this,G,H);}}}else{K=J.nodeName.toUpperCase();if(K&amp;&amp;K==this.NODE_NAME){if(!J.id){J.id=C.generateId();}I.call(this,J,H);}}}};YAHOO.extend(YAHOO.widget.ButtonGroup,YAHOO.util.Element,{_buttons:null,NODE_NAME:&quot;DIV&quot;,CLASS_NAME_PREFIX:&quot;yui-&quot;,CSS_CLASS_NAME:&quot;buttongroup&quot;,_createGroupElement:function(){var F=document.createElement(this.NODE_NAME);return F;},_setDisabled:function(G){var H=this.getCount(),F;if(H&gt;0){F=H-1;do{this._buttons[F].set(&quot;disabled&quot;,G);}while(F--);}},_onKeyDown:function(K){var G=B.getTarget(K),I=B.getCharCode(K),H=G.parentNode.parentNode.id,J=E[H],F=-1;if(I==37||I==38){F=(J.index===0)?(this._buttons.length-1):(J.index-1);}else{if(I==39||I==40){F=(J.index===(this._buttons.leng
 th-1))?0:(J.index+1);}}if(F&gt;-1){this.check(F);this.getButton(F).focus();}},_onAppendTo:function(H){var I=this._buttons,G=I.length,F;for(F=0;F&lt;G;F++){I[F].appendTo(this.get(&quot;element&quot;));}},_onButtonCheckedChange:function(G,F){var I=G.newValue,H=this.get(&quot;checkedButton&quot;);if(I&amp;&amp;H!=F){if(H){H.set(&quot;checked&quot;,false,true);}this.set(&quot;checkedButton&quot;,F);this.set(&quot;value&quot;,F.get(&quot;value&quot;));}else{if(H&amp;&amp;!H.set(&quot;checked&quot;)){H.set(&quot;checked&quot;,true,true);}}},init:function(I,H){this._buttons=[];YAHOO.widget.ButtonGroup.superclass.init.call(this,I,H);this.addClass(this.CLASS_NAME_PREFIX+this.CSS_CLASS_NAME);var K=(YAHOO.widget.Button.prototype.CLASS_NAME_PREFIX+&quot;radio-button&quot;),J=this.getElementsByClassName(K);if(J.length&gt;0){this.addButtons(J);}function F(L){return(L.type==&quot;radio&quot;);}J=C.getElementsBy(F,&quot;input&quot;,this.get(&quot;element&quot;));if(J.length&gt;0){this.addBu
 ttons(J);}this.on(&quot;keydown&quot;,this._onKeyDown);this.on(&quot;appendTo&quot;,this._onAppendTo);var G=this.get(&quot;container&quot;);if(G){if(D.isString(G)){B.onContentReady(G,function(){this.appendTo(G);},null,this);}else{this.appendTo(G);}}},initAttributes:function(G){var F=G||{};YAHOO.widget.ButtonGroup.superclass.initAttributes.call(this,F);this.setAttributeConfig(&quot;name&quot;,{value:F.name,validator:D.isString});this.setAttributeConfig(&quot;disabled&quot;,{value:(F.disabled||false),validator:D.isBoolean,method:this._setDisabled});this.setAttributeConfig(&quot;value&quot;,{value:F.value});this.setAttributeConfig(&quot;container&quot;,{value:F.container,writeOnce:true});this.setAttributeConfig(&quot;checkedButton&quot;,{value:null});},addButton:function(J){var L,K,G,F,H,I;if(J instanceof A&amp;&amp;J.get(&quot;type&quot;)==&quot;radio&quot;){L=J;}else{if(!D.isString(J)&amp;&amp;!J.nodeName){J.type=&quot;radio&quot;;L=new A(J);}else{L=new A(J,{type:&quot;radio&
 quot;});}}if(L){F=this._buttons.length;H=L.get(&quot;name&quot;);I=this.get(&quot;name&quot;);L.index=F;this._buttons[F]=L;E[L.get(&quot;id&quot;)]=L;if(H!=I){L.set(&quot;name&quot;,I);}if(this.get(&quot;disabled&quot;)){L.set(&quot;disabled&quot;,true);}if(L.get(&quot;checked&quot;)){this.set(&quot;checkedButton&quot;,L);}K=L.get(&quot;element&quot;);G=this.get(&quot;element&quot;);if(K.parentNode!=G){G.appendChild(K);}L.on(&quot;checkedChange&quot;,this._onButtonCheckedChange,L,this);}return L;},addButtons:function(G){var H,I,J,F;if(D.isArray(G)){H=G.length;J=[];if(H&gt;0){for(F=0;F&lt;H;F++){I=this.addButton(G[F]);if(I){J[J.length]=I;}}}}return J;},removeButton:function(H){var I=this.getButton(H),G,F;if(I){this._buttons.splice(H,1);delete E[I.get(&quot;id&quot;)];I.removeListener(&quot;checkedChange&quot;,this._onButtonCheckedChange);I.destroy();G=this._buttons.length;if(G&gt;0){F=this._buttons.length-1;do{this._buttons[F].index=F;}while(F--);}}},getButton:function(F){ret
 urn this._buttons[F];},getButtons:function(){return this._buttons;},getCount:function(){return this._buttons.length;},focus:function(H){var I,G,F;if(D.isNumber(H)){I=this._buttons[H];if(I){I.focus();}}else{G=this.getCount();for(F=0;F&lt;G;F++){I=this._buttons[F];if(!I.get(&quot;disabled&quot;)){I.focus();break;}}}},check:function(F){var G=this.getButton(F);if(G){G.set(&quot;checked&quot;,true);}},destroy:function(){var I=this._buttons.length,H=this.get(&quot;element&quot;),F=H.parentNode,G;if(I&gt;0){G=this._buttons.length-1;do{this._buttons[G].destroy();}while(G--);}B.purgeElement(H);F.removeChild(H);},toString:function(){return(&quot;ButtonGroup &quot;+this.get(&quot;id&quot;));}});})();YAHOO.register(&quot;button&quot;,YAHOO.widget.Button,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuicalendarcalendarminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/calendar/calendar-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/calendar/calendar-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/calendar/calendar-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,18 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+(function(){YAHOO.util.Config=function(d){if(d){this.init(d);}};var b=YAHOO.lang,c=YAHOO.util.CustomEvent,a=YAHOO.util.Config;a.CONFIG_CHANGED_EVENT=&quot;configChanged&quot;;a.BOOLEAN_TYPE=&quot;boolean&quot;;a.prototype={owner:null,queueInProgress:false,config:null,initialConfig:null,eventQueue:null,configChangedEvent:null,init:function(d){this.owner=d;this.configChangedEvent=this.createEvent(a.CONFIG_CHANGED_EVENT);this.configChangedEvent.signature=c.LIST;this.queueInProgress=false;this.config={};this.initialConfig={};this.eventQueue=[];},checkBoolean:function(d){return(typeof d==a.BOOLEAN_TYPE);},checkNumber:function(d){return(!isNaN(d));},fireEvent:function(d,f){var e=this.config[d];if(e&amp;&amp;e.event){e.event.fire(f);}},addProperty:function(e,d){e=e.toLowerCase();this.config[e]=d;d.event=this.createEvent(e,{scope:this.owner});d.event.signature=c.LIST;d.key=e;if(d.handler){d.event.subscribe(d.handler,this.owner);}this.setProperty(e,d.value,true);if(!d.suppressEvent){
 this.queueProperty(e,d.value);}},getConfig:function(){var d={},f=this.config,g,e;for(g in f){if(b.hasOwnProperty(f,g)){e=f[g];if(e&amp;&amp;e.event){d[g]=e.value;}}}return d;},getProperty:function(d){var e=this.config[d.toLowerCase()];if(e&amp;&amp;e.event){return e.value;}else{return undefined;}},resetProperty:function(d){d=d.toLowerCase();var e=this.config[d];if(e&amp;&amp;e.event){if(d in this.initialConfig){this.setProperty(d,this.initialConfig[d]);return true;}}else{return false;}},setProperty:function(e,g,d){var f;e=e.toLowerCase();if(this.queueInProgress&amp;&amp;!d){this.queueProperty(e,g);return true;}else{f=this.config[e];if(f&amp;&amp;f.event){if(f.validator&amp;&amp;!f.validator(g)){return false;}else{f.value=g;if(!d){this.fireEvent(e,g);this.configChangedEvent.fire([e,g]);}return true;}}else{return false;}}},queueProperty:function(v,r){v=v.toLowerCase();var u=this.config[v],l=false,k,g,h,j,p,t,f,n,o,d,m,w,e;if(u&amp;&amp;u.event){if(!b.isUndefined(r)&amp;&amp;u.
 validator&amp;&amp;!u.validator(r)){return false;}else{if(!b.isUndefined(r)){u.value=r;}else{r=u.value;}l=false;k=this.eventQueue.length;for(m=0;m&lt;k;m++){g=this.eventQueue[m];if(g){h=g[0];j=g[1];if(h==v){this.eventQueue[m]=null;this.eventQueue.push([v,(!b.isUndefined(r)?r:j)]);l=true;break;}}}if(!l&amp;&amp;!b.isUndefined(r)){this.eventQueue.push([v,r]);}}if(u.supercedes){p=u.supercedes.length;for(w=0;w&lt;p;w++){t=u.supercedes[w];f=this.eventQueue.length;for(e=0;e&lt;f;e++){n=this.eventQueue[e];if(n){o=n[0];d=n[1];if(o==t.toLowerCase()){this.eventQueue.push([o,d]);this.eventQueue[e]=null;break;}}}}}return true;}else{return false;}},refireEvent:function(d){d=d.toLowerCase();var e=this.config[d];if(e&amp;&amp;e.event&amp;&amp;!b.isUndefined(e.value)){if(this.queueInProgress){this.queueProperty(d);}else{this.fireEvent(d,e.value);}}},applyConfig:function(d,g){var f,e;if(g){e={};for(f in d){if(b.hasOwnProperty(d,f)){e[f.toLowerCase()]=d[f];}}this.initialConfig=e;}for(f in d){
 if(b.hasOwnProperty(d,f)){this.queueProperty(f,d[f]);}}},refresh:function(){var d;for(d in this.config){if(b.hasOwnProperty(this.config,d)){this.refireEvent(d);}}},fireQueue:function(){var e,h,d,g,f;this.queueInProgress=true;for(e=0;e&lt;this.eventQueue.length;e++){h=this.eventQueue[e];if(h){d=h[0];g=h[1];f=this.config[d];f.value=g;this.eventQueue[e]=null;this.fireEvent(d,g);}}this.queueInProgress=false;this.eventQueue=[];},subscribeToConfigEvent:function(d,e,g,h){var f=this.config[d.toLowerCase()];if(f&amp;&amp;f.event){if(!a.alreadySubscribed(f.event,e,g)){f.event.subscribe(e,g,h);}return true;}else{return false;}},unsubscribeFromConfigEvent:function(d,e,g){var f=this.config[d.toLowerCase()];if(f&amp;&amp;f.event){return f.event.unsubscribe(e,g);}else{return false;}},toString:function(){var d=&quot;Config&quot;;if(this.owner){d+=&quot; [&quot;+this.owner.toString()+&quot;]&quot;;}return d;},outputEventQueue:function(){var d=&quot;&quot;,g,e,f=this.eventQueue.length;for(e=0
 ;e&lt;f;e++){g=this.eventQueue[e];if(g){d+=g[0]+&quot;=&quot;+g[1]+&quot;, &quot;;}}return d;},destroy:function(){var e=this.config,d,f;for(d in e){if(b.hasOwnProperty(e,d)){f=e[d];f.event.unsubscribeAll();f.event=null;}}this.configChangedEvent.unsubscribeAll();this.configChangedEvent=null;this.owner=null;this.config=null;this.initialConfig=null;this.eventQueue=null;}};a.alreadySubscribed=function(e,h,j){var f=e.subscribers.length,d,g;if(f&gt;0){g=f-1;do{d=e.subscribers[g];if(d&amp;&amp;d.obj==j&amp;&amp;d.fn==h){return true;}}while(g--);}return false;};YAHOO.lang.augmentProto(a,YAHOO.util.EventProvider);}());YAHOO.widget.DateMath={DAY:&quot;D&quot;,WEEK:&quot;W&quot;,YEAR:&quot;Y&quot;,MONTH:&quot;M&quot;,ONE_DAY_MS:1000*60*60*24,WEEK_ONE_JAN_DATE:1,add:function(a,e,c){var g=new Date(a.getTime());switch(e){case this.MONTH:var f=a.getMonth()+c;var b=0;if(f&lt;0){while(f&lt;0){f+=12;b-=1;}}else{if(f&gt;11){while(f&gt;11){f-=12;b+=1;}}}g.setMonth(f);g.setFullYear(a.getFullYear
 ()+b);break;case this.DAY:this._addDays(g,c);break;case this.YEAR:g.setFullYear(a.getFullYear()+c);break;case this.WEEK:this._addDays(g,(c*7));break;}return g;},_addDays:function(e,c){if(YAHOO.env.ua.webkit&amp;&amp;YAHOO.env.ua.webkit&lt;420){if(c&lt;0){for(var b=-128;c&lt;b;c-=b){e.setDate(e.getDate()+b);}}else{for(var a=96;c&gt;a;c-=a){e.setDate(e.getDate()+a);}}}e.setDate(e.getDate()+c);},subtract:function(a,c,b){return this.add(a,c,(b*-1));},before:function(c,b){var a=b.getTime();if(c.getTime()&lt;a){return true;}else{return false;}},after:function(c,b){var a=b.getTime();if(c.getTime()&gt;a){return true;}else{return false;}},between:function(b,a,c){if(this.after(b,a)&amp;&amp;this.before(b,c)){return true;}else{return false;}},getJan1:function(a){return this.getDate(a,0,1);},getDayOffset:function(b,d){var c=this.getJan1(d);var a=Math.ceil((b.getTime()-c.getTime())/this.ONE_DAY_MS);return a;},getWeekNumber:function(d,b,g){b=b||0;g=g||this.WEEK_ONE_JAN_DATE;var h=this.cle
 arTime(d),l,m;if(h.getDay()===b){l=h;}else{l=this.getFirstDayOfWeek(h,b);}var i=l.getFullYear();m=new Date(l.getTime()+6*this.ONE_DAY_MS);var f;if(i!==m.getFullYear()&amp;&amp;m.getDate()&gt;=g){f=1;}else{var e=this.clearTime(this.getDate(i,0,g)),a=this.getFirstDayOfWeek(e,b);var j=Math.round((h.getTime()-a.getTime())/this.ONE_DAY_MS);var k=j%7;var c=(j-k)/7;f=c+1;}return f;},getFirstDayOfWeek:function(d,a){a=a||0;
+var b=d.getDay(),c=(b-a+7)%7;return this.subtract(d,this.DAY,c);},isYearOverlapWeek:function(a){var c=false;var b=this.add(a,this.DAY,6);if(b.getFullYear()!=a.getFullYear()){c=true;}return c;},isMonthOverlapWeek:function(a){var c=false;var b=this.add(a,this.DAY,6);if(b.getMonth()!=a.getMonth()){c=true;}return c;},findMonthStart:function(a){var b=this.getDate(a.getFullYear(),a.getMonth(),1);return b;},findMonthEnd:function(b){var d=this.findMonthStart(b);var c=this.add(d,this.MONTH,1);var a=this.subtract(c,this.DAY,1);return a;},clearTime:function(a){a.setHours(12,0,0,0);return a;},getDate:function(e,a,c){var b=null;if(YAHOO.lang.isUndefined(c)){c=1;}if(e&gt;=100){b=new Date(e,a,c);}else{b=new Date();b.setFullYear(e);b.setMonth(a);b.setDate(c);b.setHours(0,0,0,0);}return b;}};(function(){var c=YAHOO.util.Dom,a=YAHOO.util.Event,e=YAHOO.lang,d=YAHOO.widget.DateMath;function f(i,g,h){this.init.apply(this,arguments);}f.IMG_ROOT=null;f.DATE=&quot;D&quot;;f.MONTH_DAY=&quot;MD&quot;
 ;f.WEEKDAY=&quot;WD&quot;;f.RANGE=&quot;R&quot;;f.MONTH=&quot;M&quot;;f.DISPLAY_DAYS=42;f.STOP_RENDER=&quot;S&quot;;f.SHORT=&quot;short&quot;;f.LONG=&quot;long&quot;;f.MEDIUM=&quot;medium&quot;;f.ONE_CHAR=&quot;1char&quot;;f.DEFAULT_CONFIG={YEAR_OFFSET:{key:&quot;year_offset&quot;,value:0,supercedes:[&quot;pagedate&quot;,&quot;selected&quot;,&quot;mindate&quot;,&quot;maxdate&quot;]},TODAY:{key:&quot;today&quot;,value:new Date(),supercedes:[&quot;pagedate&quot;]},PAGEDATE:{key:&quot;pagedate&quot;,value:null},SELECTED:{key:&quot;selected&quot;,value:[]},TITLE:{key:&quot;title&quot;,value:&quot;&quot;},CLOSE:{key:&quot;close&quot;,value:false},IFRAME:{key:&quot;iframe&quot;,value:(YAHOO.env.ua.ie&amp;&amp;YAHOO.env.ua.ie&lt;=6)?true:false},MINDATE:{key:&quot;mindate&quot;,value:null},MAXDATE:{key:&quot;maxdate&quot;,value:null},MULTI_SELECT:{key:&quot;multi_select&quot;,value:false},OOM_SELECT:{key:&quot;oom_select&quot;,value:false},START_WEEKDAY:{key:&quot;start_weekday&quot
 ;,value:0},SHOW_WEEKDAYS:{key:&quot;show_weekdays&quot;,value:true},SHOW_WEEK_HEADER:{key:&quot;show_week_header&quot;,value:false},SHOW_WEEK_FOOTER:{key:&quot;show_week_footer&quot;,value:false},HIDE_BLANK_WEEKS:{key:&quot;hide_blank_weeks&quot;,value:false},NAV_ARROW_LEFT:{key:&quot;nav_arrow_left&quot;,value:null},NAV_ARROW_RIGHT:{key:&quot;nav_arrow_right&quot;,value:null},MONTHS_SHORT:{key:&quot;months_short&quot;,value:[&quot;Jan&quot;,&quot;Feb&quot;,&quot;Mar&quot;,&quot;Apr&quot;,&quot;May&quot;,&quot;Jun&quot;,&quot;Jul&quot;,&quot;Aug&quot;,&quot;Sep&quot;,&quot;Oct&quot;,&quot;Nov&quot;,&quot;Dec&quot;]},MONTHS_LONG:{key:&quot;months_long&quot;,value:[&quot;January&quot;,&quot;February&quot;,&quot;March&quot;,&quot;April&quot;,&quot;May&quot;,&quot;June&quot;,&quot;July&quot;,&quot;August&quot;,&quot;September&quot;,&quot;October&quot;,&quot;November&quot;,&quot;December&quot;]},WEEKDAYS_1CHAR:{key:&quot;weekdays_1char&quot;,value:[&quot;S&quot;,&quot;M&quot;,&qu
 ot;T&quot;,&quot;W&quot;,&quot;T&quot;,&quot;F&quot;,&quot;S&quot;]},WEEKDAYS_SHORT:{key:&quot;weekdays_short&quot;,value:[&quot;Su&quot;,&quot;Mo&quot;,&quot;Tu&quot;,&quot;We&quot;,&quot;Th&quot;,&quot;Fr&quot;,&quot;Sa&quot;]},WEEKDAYS_MEDIUM:{key:&quot;weekdays_medium&quot;,value:[&quot;Sun&quot;,&quot;Mon&quot;,&quot;Tue&quot;,&quot;Wed&quot;,&quot;Thu&quot;,&quot;Fri&quot;,&quot;Sat&quot;]},WEEKDAYS_LONG:{key:&quot;weekdays_long&quot;,value:[&quot;Sunday&quot;,&quot;Monday&quot;,&quot;Tuesday&quot;,&quot;Wednesday&quot;,&quot;Thursday&quot;,&quot;Friday&quot;,&quot;Saturday&quot;]},LOCALE_MONTHS:{key:&quot;locale_months&quot;,value:&quot;long&quot;},LOCALE_WEEKDAYS:{key:&quot;locale_weekdays&quot;,value:&quot;short&quot;},DATE_DELIMITER:{key:&quot;date_delimiter&quot;,value:&quot;,&quot;},DATE_FIELD_DELIMITER:{key:&quot;date_field_delimiter&quot;,value:&quot;/&quot;},DATE_RANGE_DELIMITER:{key:&quot;date_range_delimiter&quot;,value:&quot;-&quot;},MY_MONTH_POSITION:{key:
 &quot;my_month_position&quot;,value:1},MY_YEAR_POSITION:{key:&quot;my_year_position&quot;,value:2},MD_MONTH_POSITION:{key:&quot;md_month_position&quot;,value:1},MD_DAY_POSITION:{key:&quot;md_day_position&quot;,value:2},MDY_MONTH_POSITION:{key:&quot;mdy_month_position&quot;,value:1},MDY_DAY_POSITION:{key:&quot;mdy_day_position&quot;,value:2},MDY_YEAR_POSITION:{key:&quot;mdy_year_position&quot;,value:3},MY_LABEL_MONTH_POSITION:{key:&quot;my_label_month_position&quot;,value:1},MY_LABEL_YEAR_POSITION:{key:&quot;my_label_year_position&quot;,value:2},MY_LABEL_MONTH_SUFFIX:{key:&quot;my_label_month_suffix&quot;,value:&quot; &quot;},MY_LABEL_YEAR_SUFFIX:{key:&quot;my_label_year_suffix&quot;,value:&quot;&quot;},NAV:{key:&quot;navigator&quot;,value:null},STRINGS:{key:&quot;strings&quot;,value:{previousMonth:&quot;Previous Month&quot;,nextMonth:&quot;Next Month&quot;,close:&quot;Close&quot;},supercedes:[&quot;close&quot;,&quot;title&quot;]}};f._DEFAULT_CONFIG=f.DEFAULT_CONFIG;var b=f.D
 EFAULT_CONFIG;f._EVENT_TYPES={BEFORE_SELECT:&quot;beforeSelect&quot;,SELECT:&quot;select&quot;,BEFORE_DESELECT:&quot;beforeDeselect&quot;,DESELECT:&quot;deselect&quot;,CHANGE_PAGE:&quot;changePage&quot;,BEFORE_RENDER:&quot;beforeRender&quot;,RENDER:&quot;render&quot;,BEFORE_DESTROY:&quot;beforeDestroy&quot;,DESTROY:&quot;destroy&quot;,RESET:&quot;reset&quot;,CLEAR:&quot;clear&quot;,BEFORE_HIDE:&quot;beforeHide&quot;,HIDE:&quot;hide&quot;,BEFORE_SHOW:&quot;beforeShow&quot;,SHOW:&quot;show&quot;,BEFORE_HIDE_NAV:&quot;beforeHideNav&quot;,HIDE_NAV:&quot;hideNav&quot;,BEFORE_SHOW_NAV:&quot;beforeShowNav&quot;,SHOW_NAV:&quot;showNav&quot;,BEFORE_RENDER_NAV:&quot;beforeRenderNav&quot;,RENDER_NAV:&quot;renderNav&quot;};f.STYLES={CSS_ROW_HEADER:&quot;calrowhead&quot;,CSS_ROW_FOOTER:&quot;calrowfoot&quot;,CSS_CELL:&quot;calcell&quot;,CSS_CELL_SELECTOR:&quot;selector&quot;,CSS_CELL_SELECTED:&quot;selected&quot;,CSS_CELL_SELECTABLE:&quot;selectable&quot;,CSS_CELL_RESTRICTED:&quot;restri
 cted&quot;,CSS_CELL_TODAY:&quot;today&quot;,CSS_CELL_OOM:&quot;oom&quot;,CSS_CELL_OOB:&quot;previous&quot;,CSS_HEADER:&quot;calheader&quot;,CSS_HEADER_TEXT:&quot;calhead&quot;,CSS_BODY:&quot;calbody&quot;,CSS_WEEKDAY_CELL:&quot;calweekdaycell&quot;,CSS_WEEKDAY_ROW:&quot;calweekdayrow&quot;,CSS_FOOTER:&quot;calfoot&quot;,CSS_CALENDAR:&quot;yui-calendar&quot;,CSS_SINGLE:&quot;single&quot;,CSS_CONTAINER:&quot;yui-calcontainer&quot;,CSS_NAV_LEFT:&quot;calnavleft&quot;,CSS_NAV_RIGHT:&quot;calnavright&quot;,CSS_NAV:&quot;calnav&quot;,CSS_CLOSE:&quot;calclose&quot;,CSS_CELL_TOP:&quot;calcelltop&quot;,CSS_CELL_LEFT:&quot;calcellleft&quot;,CSS_CELL_RIGHT:&quot;calcellright&quot;,CSS_CELL_BOTTOM:&quot;calcellbottom&quot;,CSS_CELL_HOVER:&quot;calcellhover&quot;,CSS_CELL_HIGHLIGHT1:&quot;highlight1&quot;,CSS_CELL_HIGHLIGHT2:&quot;highlight2&quot;,CSS_CELL_HIGHLIGHT3:&quot;highlight3&quot;,CSS_CELL_HIGHLIGHT4:&quot;highlight4&quot;,CSS_WITH_TITLE:&quot;withtitle&quot;,CSS_FIXED_SIZE:&quo
 t;fixedsize&quot;,CSS_LINK_CLOSE:&quot;link-close&quot;};f._STYLES=f.STYLES;f.prototype={Config:null,parent:null,index:-1,cells:null,cellDates:null,id:null,containerId:null,oDomContainer:null,today:null,renderStack:null,_renderStack:null,oNavigator:null,_selectedDates:null,domEventMap:null,_parseArgs:function(h){var g={id:null,container:null,config:null};if(h&amp;&amp;h.length&amp;&amp;h.length&gt;0){switch(h.length){case 1:g.id=null;g.container=h[0];g.config=null;break;case 2:if(e.isObject(h[1])&amp;&amp;!h[1].tagName&amp;&amp;!(h[1] instanceof String)){g.id=null;g.container=h[0];g.config=h[1];}else{g.id=h[0];g.container=h[1];g.config=null;}break;default:g.id=h[0];g.container=h[1];g.config=h[2];break;}}else{}return g;},init:function(j,h,i){var g=this._parseArgs(arguments);j=g.id;h=g.container;i=g.config;this.oDomContainer=c.get(h);this._oDoc=this.oDomContainer.ownerDocument;if(!this.oDomContainer.id){this.oDomContainer.id=c.generateId();
+}if(!j){j=this.oDomContainer.id+&quot;_t&quot;;}this.id=j;this.containerId=this.oDomContainer.id;this.initEvents();this.cfg=new YAHOO.util.Config(this);this.Options={};this.Locale={};this.initStyles();c.addClass(this.oDomContainer,this.Style.CSS_CONTAINER);c.addClass(this.oDomContainer,this.Style.CSS_SINGLE);this.cellDates=[];this.cells=[];this.renderStack=[];this._renderStack=[];this.setupConfig();if(i){this.cfg.applyConfig(i,true);}this.cfg.fireQueue();this.today=this.cfg.getProperty(&quot;today&quot;);},configIframe:function(i,h,j){var g=h[0];if(!this.parent){if(c.inDocument(this.oDomContainer)){if(g){var k=c.getStyle(this.oDomContainer,&quot;position&quot;);if(k==&quot;absolute&quot;||k==&quot;relative&quot;){if(!c.inDocument(this.iframe)){this.iframe=document.createElement(&quot;iframe&quot;);this.iframe.src=&quot;javascript:false;&quot;;c.setStyle(this.iframe,&quot;opacity&quot;,&quot;0&quot;);if(YAHOO.env.ua.ie&amp;&amp;YAHOO.env.ua.ie&lt;=6){c.addClass(this.iframe,th
 is.Style.CSS_FIXED_SIZE);}this.oDomContainer.insertBefore(this.iframe,this.oDomContainer.firstChild);}}}else{if(this.iframe){if(this.iframe.parentNode){this.iframe.parentNode.removeChild(this.iframe);}this.iframe=null;}}}}},configTitle:function(h,g,i){var k=g[0];if(k){this.createTitleBar(k);}else{var j=this.cfg.getProperty(b.CLOSE.key);if(!j){this.removeTitleBar();}else{this.createTitleBar(&quot;&amp;#160;&quot;);}}},configClose:function(h,g,i){var k=g[0],j=this.cfg.getProperty(b.TITLE.key);if(k){if(!j){this.createTitleBar(&quot;&amp;#160;&quot;);}this.createCloseButton();}else{this.removeCloseButton();if(!j){this.removeTitleBar();}}},initEvents:function(){var g=f._EVENT_TYPES,i=YAHOO.util.CustomEvent,h=this;h.beforeSelectEvent=new i(g.BEFORE_SELECT);h.selectEvent=new i(g.SELECT);h.beforeDeselectEvent=new i(g.BEFORE_DESELECT);h.deselectEvent=new i(g.DESELECT);h.changePageEvent=new i(g.CHANGE_PAGE);h.beforeRenderEvent=new i(g.BEFORE_RENDER);h.renderEvent=new i(g.RENDER);h.bef
 oreDestroyEvent=new i(g.BEFORE_DESTROY);h.destroyEvent=new i(g.DESTROY);h.resetEvent=new i(g.RESET);h.clearEvent=new i(g.CLEAR);h.beforeShowEvent=new i(g.BEFORE_SHOW);h.showEvent=new i(g.SHOW);h.beforeHideEvent=new i(g.BEFORE_HIDE);h.hideEvent=new i(g.HIDE);h.beforeShowNavEvent=new i(g.BEFORE_SHOW_NAV);h.showNavEvent=new i(g.SHOW_NAV);h.beforeHideNavEvent=new i(g.BEFORE_HIDE_NAV);h.hideNavEvent=new i(g.HIDE_NAV);h.beforeRenderNavEvent=new i(g.BEFORE_RENDER_NAV);h.renderNavEvent=new i(g.RENDER_NAV);h.beforeSelectEvent.subscribe(h.onBeforeSelect,this,true);h.selectEvent.subscribe(h.onSelect,this,true);h.beforeDeselectEvent.subscribe(h.onBeforeDeselect,this,true);h.deselectEvent.subscribe(h.onDeselect,this,true);h.changePageEvent.subscribe(h.onChangePage,this,true);h.renderEvent.subscribe(h.onRender,this,true);h.resetEvent.subscribe(h.onReset,this,true);h.clearEvent.subscribe(h.onClear,this,true);},doPreviousMonthNav:function(h,g){a.preventDefault(h);setTimeout(function(){g.pre
 viousMonth();var j=c.getElementsByClassName(g.Style.CSS_NAV_LEFT,&quot;a&quot;,g.oDomContainer);if(j&amp;&amp;j[0]){try{j[0].focus();}catch(i){}}},0);},doNextMonthNav:function(h,g){a.preventDefault(h);setTimeout(function(){g.nextMonth();var j=c.getElementsByClassName(g.Style.CSS_NAV_RIGHT,&quot;a&quot;,g.oDomContainer);if(j&amp;&amp;j[0]){try{j[0].focus();}catch(i){}}},0);},doSelectCell:function(m,g){var r,o,i,l;var n=a.getTarget(m),h=n.tagName.toLowerCase(),k=false;while(h!=&quot;td&quot;&amp;&amp;!c.hasClass(n,g.Style.CSS_CELL_SELECTABLE)){if(!k&amp;&amp;h==&quot;a&quot;&amp;&amp;c.hasClass(n,g.Style.CSS_CELL_SELECTOR)){k=true;}n=n.parentNode;h=n.tagName.toLowerCase();if(n==this.oDomContainer||h==&quot;html&quot;){return;}}if(k){a.preventDefault(m);}r=n;if(c.hasClass(r,g.Style.CSS_CELL_SELECTABLE)){l=g.getIndexFromId(r.id);if(l&gt;-1){o=g.cellDates[l];if(o){i=d.getDate(o[0],o[1]-1,o[2]);var q;if(g.Options.MULTI_SELECT){q=r.getElementsByTagName(&quot;a&quot;)[0];if(q){q.blu
 r();}var j=g.cellDates[l];var p=g._indexOfSelectedFieldArray(j);if(p&gt;-1){g.deselectCell(l);}else{g.selectCell(l);}}else{q=r.getElementsByTagName(&quot;a&quot;)[0];if(q){q.blur();}g.selectCell(l);}}}}},doCellMouseOver:function(i,h){var g;if(i){g=a.getTarget(i);}else{g=this;}while(g.tagName&amp;&amp;g.tagName.toLowerCase()!=&quot;td&quot;){g=g.parentNode;if(!g.tagName||g.tagName.toLowerCase()==&quot;html&quot;){return;}}if(c.hasClass(g,h.Style.CSS_CELL_SELECTABLE)){c.addClass(g,h.Style.CSS_CELL_HOVER);}},doCellMouseOut:function(i,h){var g;if(i){g=a.getTarget(i);}else{g=this;}while(g.tagName&amp;&amp;g.tagName.toLowerCase()!=&quot;td&quot;){g=g.parentNode;if(!g.tagName||g.tagName.toLowerCase()==&quot;html&quot;){return;}}if(c.hasClass(g,h.Style.CSS_CELL_SELECTABLE)){c.removeClass(g,h.Style.CSS_CELL_HOVER);}},setupConfig:function(){var g=this.cfg;g.addProperty(b.TODAY.key,{value:new Date(b.TODAY.value.getTime()),supercedes:b.TODAY.supercedes,handler:this.configToday,suppressE
 vent:true});g.addProperty(b.PAGEDATE.key,{value:b.PAGEDATE.value||new Date(b.TODAY.value.getTime()),handler:this.configPageDate});g.addProperty(b.SELECTED.key,{value:b.SELECTED.value.concat(),handler:this.configSelected});g.addProperty(b.TITLE.key,{value:b.TITLE.value,handler:this.configTitle});g.addProperty(b.CLOSE.key,{value:b.CLOSE.value,handler:this.configClose});g.addProperty(b.IFRAME.key,{value:b.IFRAME.value,handler:this.configIframe,validator:g.checkBoolean});g.addProperty(b.MINDATE.key,{value:b.MINDATE.value,handler:this.configMinDate});g.addProperty(b.MAXDATE.key,{value:b.MAXDATE.value,handler:this.configMaxDate});g.addProperty(b.MULTI_SELECT.key,{value:b.MULTI_SELECT.value,handler:this.configOptions,validator:g.checkBoolean});g.addProperty(b.OOM_SELECT.key,{value:b.OOM_SELECT.value,handler:this.configOptions,validator:g.checkBoolean});g.addProperty(b.START_WEEKDAY.key,{value:b.START_WEEKDAY.value,handler:this.configOptions,validator:g.checkNumber});g.addProperty(b
 .SHOW_WEEKDAYS.key,{value:b.SHOW_WEEKDAYS.value,handler:this.configOptions,validator:g.checkBoolean});g.addProperty(b.SHOW_WEEK_HEADER.key,{value:b.SHOW_WEEK_HEADER.value,handler:this.configOptions,validator:g.checkBoolean});g.addProperty(b.SHOW_WEEK_FOOTER.key,{value:b.SHOW_WEEK_FOOTER.value,handler:this.configOptions,validator:g.checkBoolean});g.addProperty(b.HIDE_BLANK_WEEKS.key,{value:b.HIDE_BLANK_WEEKS.value,handler:this.configOptions,validator:g.checkBoolean});
+g.addProperty(b.NAV_ARROW_LEFT.key,{value:b.NAV_ARROW_LEFT.value,handler:this.configOptions});g.addProperty(b.NAV_ARROW_RIGHT.key,{value:b.NAV_ARROW_RIGHT.value,handler:this.configOptions});g.addProperty(b.MONTHS_SHORT.key,{value:b.MONTHS_SHORT.value,handler:this.configLocale});g.addProperty(b.MONTHS_LONG.key,{value:b.MONTHS_LONG.value,handler:this.configLocale});g.addProperty(b.WEEKDAYS_1CHAR.key,{value:b.WEEKDAYS_1CHAR.value,handler:this.configLocale});g.addProperty(b.WEEKDAYS_SHORT.key,{value:b.WEEKDAYS_SHORT.value,handler:this.configLocale});g.addProperty(b.WEEKDAYS_MEDIUM.key,{value:b.WEEKDAYS_MEDIUM.value,handler:this.configLocale});g.addProperty(b.WEEKDAYS_LONG.key,{value:b.WEEKDAYS_LONG.value,handler:this.configLocale});var h=function(){g.refireEvent(b.LOCALE_MONTHS.key);g.refireEvent(b.LOCALE_WEEKDAYS.key);};g.subscribeToConfigEvent(b.START_WEEKDAY.key,h,this,true);g.subscribeToConfigEvent(b.MONTHS_SHORT.key,h,this,true);g.subscribeToConfigEvent(b.MONTHS_LONG.key,h,
 this,true);g.subscribeToConfigEvent(b.WEEKDAYS_1CHAR.key,h,this,true);g.subscribeToConfigEvent(b.WEEKDAYS_SHORT.key,h,this,true);g.subscribeToConfigEvent(b.WEEKDAYS_MEDIUM.key,h,this,true);g.subscribeToConfigEvent(b.WEEKDAYS_LONG.key,h,this,true);g.addProperty(b.LOCALE_MONTHS.key,{value:b.LOCALE_MONTHS.value,handler:this.configLocaleValues});g.addProperty(b.LOCALE_WEEKDAYS.key,{value:b.LOCALE_WEEKDAYS.value,handler:this.configLocaleValues});g.addProperty(b.YEAR_OFFSET.key,{value:b.YEAR_OFFSET.value,supercedes:b.YEAR_OFFSET.supercedes,handler:this.configLocale});g.addProperty(b.DATE_DELIMITER.key,{value:b.DATE_DELIMITER.value,handler:this.configLocale});g.addProperty(b.DATE_FIELD_DELIMITER.key,{value:b.DATE_FIELD_DELIMITER.value,handler:this.configLocale});g.addProperty(b.DATE_RANGE_DELIMITER.key,{value:b.DATE_RANGE_DELIMITER.value,handler:this.configLocale});g.addProperty(b.MY_MONTH_POSITION.key,{value:b.MY_MONTH_POSITION.value,handler:this.configLocale,validator:g.checkNumb
 er});g.addProperty(b.MY_YEAR_POSITION.key,{value:b.MY_YEAR_POSITION.value,handler:this.configLocale,validator:g.checkNumber});g.addProperty(b.MD_MONTH_POSITION.key,{value:b.MD_MONTH_POSITION.value,handler:this.configLocale,validator:g.checkNumber});g.addProperty(b.MD_DAY_POSITION.key,{value:b.MD_DAY_POSITION.value,handler:this.configLocale,validator:g.checkNumber});g.addProperty(b.MDY_MONTH_POSITION.key,{value:b.MDY_MONTH_POSITION.value,handler:this.configLocale,validator:g.checkNumber});g.addProperty(b.MDY_DAY_POSITION.key,{value:b.MDY_DAY_POSITION.value,handler:this.configLocale,validator:g.checkNumber});g.addProperty(b.MDY_YEAR_POSITION.key,{value:b.MDY_YEAR_POSITION.value,handler:this.configLocale,validator:g.checkNumber});g.addProperty(b.MY_LABEL_MONTH_POSITION.key,{value:b.MY_LABEL_MONTH_POSITION.value,handler:this.configLocale,validator:g.checkNumber});g.addProperty(b.MY_LABEL_YEAR_POSITION.key,{value:b.MY_LABEL_YEAR_POSITION.value,handler:this.configLocale,validator:
 g.checkNumber});g.addProperty(b.MY_LABEL_MONTH_SUFFIX.key,{value:b.MY_LABEL_MONTH_SUFFIX.value,handler:this.configLocale});g.addProperty(b.MY_LABEL_YEAR_SUFFIX.key,{value:b.MY_LABEL_YEAR_SUFFIX.value,handler:this.configLocale});g.addProperty(b.NAV.key,{value:b.NAV.value,handler:this.configNavigator});g.addProperty(b.STRINGS.key,{value:b.STRINGS.value,handler:this.configStrings,validator:function(i){return e.isObject(i);},supercedes:b.STRINGS.supercedes});},configStrings:function(h,g,i){var j=e.merge(b.STRINGS.value,g[0]);this.cfg.setProperty(b.STRINGS.key,j,true);},configPageDate:function(h,g,i){this.cfg.setProperty(b.PAGEDATE.key,this._parsePageDate(g[0]),true);},configMinDate:function(h,g,i){var j=g[0];if(e.isString(j)){j=this._parseDate(j);this.cfg.setProperty(b.MINDATE.key,d.getDate(j[0],(j[1]-1),j[2]));}},configMaxDate:function(h,g,i){var j=g[0];if(e.isString(j)){j=this._parseDate(j);this.cfg.setProperty(b.MAXDATE.key,d.getDate(j[0],(j[1]-1),j[2]));}},configToday:functi
 on(i,h,j){var k=h[0];if(e.isString(k)){k=this._parseDate(k);}var g=d.clearTime(k);if(!this.cfg.initialConfig[b.PAGEDATE.key]){this.cfg.setProperty(b.PAGEDATE.key,g);}this.today=g;this.cfg.setProperty(b.TODAY.key,g,true);},configSelected:function(i,g,k){var h=g[0],j=b.SELECTED.key;if(h){if(e.isString(h)){this.cfg.setProperty(j,this._parseDates(h),true);}}if(!this._selectedDates){this._selectedDates=this.cfg.getProperty(j);}},configOptions:function(h,g,i){this.Options[h.toUpperCase()]=g[0];},configLocale:function(h,g,i){this.Locale[h.toUpperCase()]=g[0];this.cfg.refireEvent(b.LOCALE_MONTHS.key);this.cfg.refireEvent(b.LOCALE_WEEKDAYS.key);},configLocaleValues:function(j,i,k){j=j.toLowerCase();var m=i[0],h=this.cfg,n=this.Locale;switch(j){case b.LOCALE_MONTHS.key:switch(m){case f.SHORT:n.LOCALE_MONTHS=h.getProperty(b.MONTHS_SHORT.key).concat();break;case f.LONG:n.LOCALE_MONTHS=h.getProperty(b.MONTHS_LONG.key).concat();break;}break;case b.LOCALE_WEEKDAYS.key:switch(m){case f.ONE_
 CHAR:n.LOCALE_WEEKDAYS=h.getProperty(b.WEEKDAYS_1CHAR.key).concat();break;case f.SHORT:n.LOCALE_WEEKDAYS=h.getProperty(b.WEEKDAYS_SHORT.key).concat();break;case f.MEDIUM:n.LOCALE_WEEKDAYS=h.getProperty(b.WEEKDAYS_MEDIUM.key).concat();break;case f.LONG:n.LOCALE_WEEKDAYS=h.getProperty(b.WEEKDAYS_LONG.key).concat();break;}var l=h.getProperty(b.START_WEEKDAY.key);if(l&gt;0){for(var g=0;g&lt;l;++g){n.LOCALE_WEEKDAYS.push(n.LOCALE_WEEKDAYS.shift());}}break;}},configNavigator:function(h,g,i){var j=g[0];if(YAHOO.widget.CalendarNavigator&amp;&amp;(j===true||e.isObject(j))){if(!this.oNavigator){this.oNavigator=new YAHOO.widget.CalendarNavigator(this);this.beforeRenderEvent.subscribe(function(){if(!this.pages){this.oNavigator.erase();}},this,true);}}else{if(this.oNavigator){this.oNavigator.destroy();this.oNavigator=null;}}},initStyles:function(){var g=f.STYLES;this.Style={CSS_ROW_HEADER:g.CSS_ROW_HEADER,CSS_ROW_FOOTER:g.CSS_ROW_FOOTER,CSS_CELL:g.CSS_CELL,CSS_CELL_SELECTOR:g.CSS_CELL_SE
 LECTOR,CSS_CELL_SELECTED:g.CSS_CELL_SELECTED,CSS_CELL_SELECTABLE:g.CSS_CELL_SELECTABLE,CSS_CELL_RESTRICTED:g.CSS_CELL_RESTRICTED,CSS_CELL_TODAY:g.CSS_CELL_TODAY,CSS_CELL_OOM:g.CSS_CELL_OOM,CSS_CELL_OOB:g.CSS_CELL_OOB,CSS_HEADER:g.CSS_HEADER,CSS_HEADER_TEXT:g.CSS_HEADER_TEXT,CSS_BODY:g.CSS_BODY,CSS_WEEKDAY_CELL:g.CSS_WEEKDAY_CELL,CSS_WEEKDAY_ROW:g.CSS_WEEKDAY_ROW,CSS_FOOTER:g.CSS_FOOTER,CSS_CALENDAR:g.CSS_CALENDAR,CSS_SINGLE:g.CSS_SINGLE,CSS_CONTAINER:g.CSS_CONTAINER,CSS_NAV_LEFT:g.CSS_NAV_LEFT,CSS_NAV_RIGHT:g.CSS_NAV_RIGHT,CSS_NAV:g.CSS_NAV,CSS_CLOSE:g.CSS_CLOSE,CSS_CELL_TOP:g.CSS_CELL_TOP,CSS_CELL_LEFT:g.CSS_CELL_LEFT,CSS_CELL_RIGHT:g.CSS_CELL_RIGHT,CSS_CELL_BOTTOM:g.CSS_CELL_BOTTOM,CSS_CELL_HOVER:g.CSS_CELL_HOVER,CSS_CELL_HIGHLIGHT1:g.CSS_CELL_HIGHLIGHT1,CSS_CELL_HIGHLIGHT2:g.CSS_CELL_HIGHLIGHT2,CSS_CELL_HIGHLIGHT3:g.CSS_CELL_HIGHLIGHT3,CSS_CELL_HIGHLIGHT4:g.CSS_CELL_HIGHLIGHT4,CSS_WITH_TITLE:g.CSS_WITH_TITLE,CSS_FIXED_SIZE:g.CSS_FIXED_SIZE,CSS_LINK_CLOSE:g.CSS_LINK_CLOSE}
 ;
+},buildMonthLabel:function(){return this._buildMonthLabel(this.cfg.getProperty(b.PAGEDATE.key));},_buildMonthLabel:function(g){var i=this.Locale.LOCALE_MONTHS[g.getMonth()]+this.Locale.MY_LABEL_MONTH_SUFFIX,h=(g.getFullYear()+this.Locale.YEAR_OFFSET)+this.Locale.MY_LABEL_YEAR_SUFFIX;if(this.Locale.MY_LABEL_MONTH_POSITION==2||this.Locale.MY_LABEL_YEAR_POSITION==1){return h+i;}else{return i+h;}},buildDayLabel:function(g){return g.getDate();},createTitleBar:function(g){var h=c.getElementsByClassName(YAHOO.widget.CalendarGroup.CSS_2UPTITLE,&quot;div&quot;,this.oDomContainer)[0]||document.createElement(&quot;div&quot;);h.className=YAHOO.widget.CalendarGroup.CSS_2UPTITLE;h.innerHTML=g;this.oDomContainer.insertBefore(h,this.oDomContainer.firstChild);c.addClass(this.oDomContainer,this.Style.CSS_WITH_TITLE);return h;},removeTitleBar:function(){var g=c.getElementsByClassName(YAHOO.widget.CalendarGroup.CSS_2UPTITLE,&quot;div&quot;,this.oDomContainer)[0]||null;if(g){a.purgeElement(g);th
 is.oDomContainer.removeChild(g);}c.removeClass(this.oDomContainer,this.Style.CSS_WITH_TITLE);},createCloseButton:function(){var k=YAHOO.widget.CalendarGroup.CSS_2UPCLOSE,j=this.Style.CSS_LINK_CLOSE,m=&quot;us/my/bn/x_d.gif&quot;,l=c.getElementsByClassName(j,&quot;a&quot;,this.oDomContainer)[0],g=this.cfg.getProperty(b.STRINGS.key),h=(g&amp;&amp;g.close)?g.close:&quot;&quot;;if(!l){l=document.createElement(&quot;a&quot;);a.addListener(l,&quot;click&quot;,function(o,n){n.hide();a.preventDefault(o);},this);}l.href=&quot;#&quot;;l.className=j;if(f.IMG_ROOT!==null){var i=c.getElementsByClassName(k,&quot;img&quot;,l)[0]||document.createElement(&quot;img&quot;);i.src=f.IMG_ROOT+m;i.className=k;l.appendChild(i);}else{l.innerHTML='&lt;span class=&quot;'+k+&quot; &quot;+this.Style.CSS_CLOSE+'&quot;&gt;'+h+&quot;&lt;/span&gt;&quot;;}this.oDomContainer.appendChild(l);return l;},removeCloseButton:function(){var g=c.getElementsByClassName(this.Style.CSS_LINK_CLOSE,&quot;a&quot;,this.oDomC
 ontainer)[0]||null;if(g){a.purgeElement(g);this.oDomContainer.removeChild(g);}},renderHeader:function(q){var p=7,o=&quot;us/tr/callt.gif&quot;,g=&quot;us/tr/calrt.gif&quot;,n=this.cfg,k=n.getProperty(b.PAGEDATE.key),l=n.getProperty(b.STRINGS.key),v=(l&amp;&amp;l.previousMonth)?l.previousMonth:&quot;&quot;,h=(l&amp;&amp;l.nextMonth)?l.nextMonth:&quot;&quot;,m;if(n.getProperty(b.SHOW_WEEK_HEADER.key)){p+=1;}if(n.getProperty(b.SHOW_WEEK_FOOTER.key)){p+=1;}q[q.length]=&quot;&lt;thead&gt;&quot;;q[q.length]=&quot;&lt;tr&gt;&quot;;q[q.length]='&lt;th colspan=&quot;'+p+'&quot; class=&quot;'+this.Style.CSS_HEADER_TEXT+'&quot;&gt;';q[q.length]='&lt;div class=&quot;'+this.Style.CSS_HEADER+'&quot;&gt;';var x,u=false;if(this.parent){if(this.index===0){x=true;}if(this.index==(this.parent.cfg.getProperty(&quot;pages&quot;)-1)){u=true;}}else{x=true;u=true;}if(x){m=this._buildMonthLabel(d.subtract(k,d.MONTH,1));var r=n.getProperty(b.NAV_ARROW_LEFT.key);if(r===null&amp;&amp;f.IMG_ROOT!==null)
 {r=f.IMG_ROOT+o;}var i=(r===null)?&quot;&quot;:' style=&quot;background-image:url('+r+')&quot;';q[q.length]='&lt;a class=&quot;'+this.Style.CSS_NAV_LEFT+'&quot;'+i+' href=&quot;#&quot;&gt;'+v+&quot; (&quot;+m+&quot;)&quot;+&quot;&lt;/a&gt;&quot;;}var w=this.buildMonthLabel();var s=this.parent||this;if(s.cfg.getProperty(&quot;navigator&quot;)){w='&lt;a class=&quot;'+this.Style.CSS_NAV+'&quot; href=&quot;#&quot;&gt;'+w+&quot;&lt;/a&gt;&quot;;}q[q.length]=w;if(u){m=this._buildMonthLabel(d.add(k,d.MONTH,1));var t=n.getProperty(b.NAV_ARROW_RIGHT.key);if(t===null&amp;&amp;f.IMG_ROOT!==null){t=f.IMG_ROOT+g;}var j=(t===null)?&quot;&quot;:' style=&quot;background-image:url('+t+')&quot;';q[q.length]='&lt;a class=&quot;'+this.Style.CSS_NAV_RIGHT+'&quot;'+j+' href=&quot;#&quot;&gt;'+h+&quot; (&quot;+m+&quot;)&quot;+&quot;&lt;/a&gt;&quot;;}q[q.length]=&quot;&lt;/div&gt;\n&lt;/th&gt;\n&lt;/tr&gt;&quot;;if(n.getProperty(b.SHOW_WEEKDAYS.key)){q=this.buildWeekdays(q);}q[q.length]=&quot;&lt;/
 thead&gt;&quot;;return q;},buildWeekdays:function(h){h[h.length]='&lt;tr class=&quot;'+this.Style.CSS_WEEKDAY_ROW+'&quot;&gt;';if(this.cfg.getProperty(b.SHOW_WEEK_HEADER.key)){h[h.length]=&quot;&lt;th&gt;&amp;#160;&lt;/th&gt;&quot;;}for(var g=0;g&lt;this.Locale.LOCALE_WEEKDAYS.length;++g){h[h.length]='&lt;th class=&quot;'+this.Style.CSS_WEEKDAY_CELL+'&quot;&gt;'+this.Locale.LOCALE_WEEKDAYS[g]+&quot;&lt;/th&gt;&quot;;}if(this.cfg.getProperty(b.SHOW_WEEK_FOOTER.key)){h[h.length]=&quot;&lt;th&gt;&amp;#160;&lt;/th&gt;&quot;;}h[h.length]=&quot;&lt;/tr&gt;&quot;;return h;},renderBody:function(T,Q){var ao=this.cfg.getProperty(b.START_WEEKDAY.key);this.preMonthDays=T.getDay();if(ao&gt;0){this.preMonthDays-=ao;}if(this.preMonthDays&lt;0){this.preMonthDays+=7;}this.monthDays=d.findMonthEnd(T).getDate();this.postMonthDays=f.DISPLAY_DAYS-this.preMonthDays-this.monthDays;T=d.subtract(T,d.DAY,this.preMonthDays);var F,q,o=&quot;w&quot;,L=&quot;_cell&quot;,J=&quot;wd&quot;,Z=&quot;d&quot;,v
 ,X,af=this.today,u=this.cfg,ae,D=af.getFullYear(),Y=af.getMonth(),k=af.getDate(),ad=u.getProperty(b.PAGEDATE.key),j=u.getProperty(b.HIDE_BLANK_WEEKS.key),P=u.getProperty(b.SHOW_WEEK_FOOTER.key),I=u.getProperty(b.SHOW_WEEK_HEADER.key),O=u.getProperty(b.OOM_SELECT.key),B=u.getProperty(b.MINDATE.key),H=u.getProperty(b.MAXDATE.key),A=this.Locale.YEAR_OFFSET;if(B){B=d.clearTime(B);}if(H){H=d.clearTime(H);}Q[Q.length]='&lt;tbody class=&quot;m'+(ad.getMonth()+1)+&quot; &quot;+this.Style.CSS_BODY+'&quot;&gt;';var am=0,w=document.createElement(&quot;div&quot;),R=document.createElement(&quot;td&quot;);w.appendChild(R);var ac=this.parent||this;for(var ah=0;ah&lt;6;ah++){F=d.getWeekNumber(T,ao);q=o+F;if(ah!==0&amp;&amp;j===true&amp;&amp;T.getMonth()!=ad.getMonth()){break;}else{Q[Q.length]='&lt;tr class=&quot;'+q+'&quot;&gt;';if(I){Q=this.renderRowHeader(F,Q);}for(var an=0;an&lt;7;an++){v=[];this.clearElement(R);R.className=this.Style.CSS_CELL;R.id=this.id+L+am;if(T.getDate()==k&amp;&amp
 ;T.getMonth()==Y&amp;&amp;T.getFullYear()==D){v[v.length]=ac.renderCellStyleToday;}var G=[T.getFullYear(),T.getMonth()+1,T.getDate()];this.cellDates[this.cellDates.length]=G;ae=T.getMonth()!=ad.getMonth();if(ae&amp;&amp;!O){v[v.length]=ac.renderCellNotThisMonth;}else{c.addClass(R,J+T.getDay());c.addClass(R,Z+T.getDate());var S=this.renderStack.concat();for(var ag=0,al=S.length;ag&lt;al;++ag){X=null;var aa=S[ag],ap=aa[0],h,K,n;switch(ap){case f.DATE:h=aa[1][1];K=aa[1][2];n=aa[1][0];if(T.getMonth()+1==h&amp;&amp;T.getDate()==K&amp;&amp;T.getFullYear()==n){X=aa[2];this.renderStack.splice(ag,1);}break;case f.MONTH_DAY:h=aa[1][0];K=aa[1][1];if(T.getMonth()+1==h&amp;&amp;T.getDate()==K){X=aa[2];this.renderStack.splice(ag,1);}break;case f.RANGE:var N=aa[1][0],M=aa[1][1],U=N[1],z=N[2],E=N[0],ak=d.getDate(E,U-1,z),m=M[1],W=M[2],g=M[0],aj=d.getDate(g,m-1,W);if(T.getTime()&gt;=ak.getTime()&amp;&amp;T.getTime()&lt;=aj.getTime()){X=aa[2];if(T.getTime()==aj.getTime()){this.renderStack.spl
 ice(ag,1);
+}}break;case f.WEEKDAY:var y=aa[1][0];if(T.getDay()+1==y){X=aa[2];}break;case f.MONTH:h=aa[1][0];if(T.getMonth()+1==h){X=aa[2];}break;}if(X){v[v.length]=X;}}}if(this._indexOfSelectedFieldArray(G)&gt;-1){v[v.length]=ac.renderCellStyleSelected;}if(ae){v[v.length]=ac.styleCellNotThisMonth;}if((B&amp;&amp;(T.getTime()&lt;B.getTime()))||(H&amp;&amp;(T.getTime()&gt;H.getTime()))){v[v.length]=ac.renderOutOfBoundsDate;}else{v[v.length]=ac.styleCellDefault;v[v.length]=ac.renderCellDefault;}for(var ab=0;ab&lt;v.length;++ab){if(v[ab].call(ac,T,R)==f.STOP_RENDER){break;}}T.setTime(T.getTime()+d.ONE_DAY_MS);T=d.clearTime(T);if(am&gt;=0&amp;&amp;am&lt;=6){c.addClass(R,this.Style.CSS_CELL_TOP);}if((am%7)===0){c.addClass(R,this.Style.CSS_CELL_LEFT);}if(((am+1)%7)===0){c.addClass(R,this.Style.CSS_CELL_RIGHT);}var V=this.postMonthDays;if(j&amp;&amp;V&gt;=7){var C=Math.floor(V/7);for(var ai=0;ai&lt;C;++ai){V-=7;}}if(am&gt;=((this.preMonthDays+V+this.monthDays)-7)){c.addClass(R,this.Style.CSS_C
 ELL_BOTTOM);}Q[Q.length]=w.innerHTML;am++;}if(P){Q=this.renderRowFooter(F,Q);}Q[Q.length]=&quot;&lt;/tr&gt;&quot;;}}Q[Q.length]=&quot;&lt;/tbody&gt;&quot;;return Q;},renderFooter:function(g){return g;},render:function(){this.beforeRenderEvent.fire();var i=d.findMonthStart(this.cfg.getProperty(b.PAGEDATE.key));this.resetRenderers();this.cellDates.length=0;a.purgeElement(this.oDomContainer,true);var g=[],h;g[g.length]='&lt;table cellSpacing=&quot;0&quot; class=&quot;'+this.Style.CSS_CALENDAR+&quot; y&quot;+(i.getFullYear()+this.Locale.YEAR_OFFSET)+'&quot; id=&quot;'+this.id+'&quot;&gt;';g=this.renderHeader(g);g=this.renderBody(i,g);g=this.renderFooter(g);g[g.length]=&quot;&lt;/table&gt;&quot;;this.oDomContainer.innerHTML=g.join(&quot;\n&quot;);this.applyListeners();h=((this._oDoc)&amp;&amp;this._oDoc.getElementById(this.id))||(this.id);this.cells=c.getElementsByClassName(this.Style.CSS_CELL,&quot;td&quot;,h);this.cfg.refireEvent(b.TITLE.key);this.cfg.refireEvent(b.CLOSE.key);t
 his.cfg.refireEvent(b.IFRAME.key);this.renderEvent.fire();},applyListeners:function(){var q=this.oDomContainer,h=this.parent||this,m=&quot;a&quot;,t=&quot;click&quot;;var n=c.getElementsByClassName(this.Style.CSS_NAV_LEFT,m,q),j=c.getElementsByClassName(this.Style.CSS_NAV_RIGHT,m,q);if(n&amp;&amp;n.length&gt;0){this.linkLeft=n[0];a.addListener(this.linkLeft,t,this.doPreviousMonthNav,h,true);}if(j&amp;&amp;j.length&gt;0){this.linkRight=j[0];a.addListener(this.linkRight,t,this.doNextMonthNav,h,true);}if(h.cfg.getProperty(&quot;navigator&quot;)!==null){this.applyNavListeners();}if(this.domEventMap){var k,g;for(var s in this.domEventMap){if(e.hasOwnProperty(this.domEventMap,s)){var o=this.domEventMap[s];if(!(o instanceof Array)){o=[o];}for(var l=0;l&lt;o.length;l++){var r=o[l];g=c.getElementsByClassName(s,r.tag,this.oDomContainer);for(var p=0;p&lt;g.length;p++){k=g[p];a.addListener(k,r.event,r.handler,r.scope,r.correct);}}}}}a.addListener(this.oDomContainer,&quot;click&quot;,thi
 s.doSelectCell,this);a.addListener(this.oDomContainer,&quot;mouseover&quot;,this.doCellMouseOver,this);a.addListener(this.oDomContainer,&quot;mouseout&quot;,this.doCellMouseOut,this);},applyNavListeners:function(){var h=this.parent||this,i=this,g=c.getElementsByClassName(this.Style.CSS_NAV,&quot;a&quot;,this.oDomContainer);if(g.length&gt;0){a.addListener(g,&quot;click&quot;,function(n,m){var l=a.getTarget(n);if(this===l||c.isAncestor(this,l)){a.preventDefault(n);}var j=h.oNavigator;if(j){var k=i.cfg.getProperty(&quot;pagedate&quot;);j.setYear(k.getFullYear()+i.Locale.YEAR_OFFSET);j.setMonth(k.getMonth());j.show();}});}},getDateByCellId:function(h){var g=this.getDateFieldsByCellId(h);return(g)?d.getDate(g[0],g[1]-1,g[2]):null;},getDateFieldsByCellId:function(g){g=this.getIndexFromId(g);return(g&gt;-1)?this.cellDates[g]:null;},getCellIndex:function(j){var h=-1;if(j){var g=j.getMonth(),p=j.getFullYear(),o=j.getDate(),l=this.cellDates;for(var k=0;k&lt;l.length;++k){var n=l[k];if
 (n[0]===p&amp;&amp;n[1]===g+1&amp;&amp;n[2]===o){h=k;break;}}}return h;},getIndexFromId:function(i){var h=-1,g=i.lastIndexOf(&quot;_cell&quot;);if(g&gt;-1){h=parseInt(i.substring(g+5),10);}return h;},renderOutOfBoundsDate:function(h,g){c.addClass(g,this.Style.CSS_CELL_OOB);g.innerHTML=h.getDate();return f.STOP_RENDER;},renderRowHeader:function(h,g){g[g.length]='&lt;th class=&quot;'+this.Style.CSS_ROW_HEADER+'&quot;&gt;'+h+&quot;&lt;/th&gt;&quot;;return g;},renderRowFooter:function(h,g){g[g.length]='&lt;th class=&quot;'+this.Style.CSS_ROW_FOOTER+'&quot;&gt;'+h+&quot;&lt;/th&gt;&quot;;return g;},renderCellDefault:function(h,g){g.innerHTML='&lt;a href=&quot;#&quot; class=&quot;'+this.Style.CSS_CELL_SELECTOR+'&quot;&gt;'+this.buildDayLabel(h)+&quot;&lt;/a&gt;&quot;;},styleCellDefault:function(h,g){c.addClass(g,this.Style.CSS_CELL_SELECTABLE);},renderCellStyleHighlight1:function(h,g){c.addClass(g,this.Style.CSS_CELL_HIGHLIGHT1);},renderCellStyleHighlight2:function(h,g){c.addClass
 (g,this.Style.CSS_CELL_HIGHLIGHT2);},renderCellStyleHighlight3:function(h,g){c.addClass(g,this.Style.CSS_CELL_HIGHLIGHT3);},renderCellStyleHighlight4:function(h,g){c.addClass(g,this.Style.CSS_CELL_HIGHLIGHT4);},renderCellStyleToday:function(h,g){c.addClass(g,this.Style.CSS_CELL_TODAY);},renderCellStyleSelected:function(h,g){c.addClass(g,this.Style.CSS_CELL_SELECTED);},renderCellNotThisMonth:function(h,g){this.styleCellNotThisMonth(h,g);g.innerHTML=h.getDate();return f.STOP_RENDER;},styleCellNotThisMonth:function(h,g){YAHOO.util.Dom.addClass(g,this.Style.CSS_CELL_OOM);},renderBodyCellRestricted:function(h,g){c.addClass(g,this.Style.CSS_CELL);c.addClass(g,this.Style.CSS_CELL_RESTRICTED);g.innerHTML=h.getDate();return f.STOP_RENDER;},addMonths:function(i){var h=b.PAGEDATE.key,j=this.cfg.getProperty(h),g=d.add(j,d.MONTH,i);this.cfg.setProperty(h,g);this.resetRenderers();this.changePageEvent.fire(j,g);},subtractMonths:function(g){this.addMonths(-1*g);},addYears:function(i){var h=
 b.PAGEDATE.key,j=this.cfg.getProperty(h),g=d.add(j,d.YEAR,i);this.cfg.setProperty(h,g);this.resetRenderers();this.changePageEvent.fire(j,g);},subtractYears:function(g){this.addYears(-1*g);},nextMonth:function(){this.addMonths(1);},previousMonth:function(){this.addMonths(-1);},nextYear:function(){this.addYears(1);},previousYear:function(){this.addYears(-1);},reset:function(){this.cfg.resetProperty(b.SELECTED.key);this.cfg.resetProperty(b.PAGEDATE.key);this.resetEvent.fire();},clear:function(){this.cfg.setProperty(b.SELECTED.key,[]);
+this.cfg.setProperty(b.PAGEDATE.key,new Date(this.today.getTime()));this.clearEvent.fire();},select:function(i){var l=this._toFieldArray(i),h=[],k=[],m=b.SELECTED.key;for(var g=0;g&lt;l.length;++g){var j=l[g];if(!this.isDateOOB(this._toDate(j))){if(h.length===0){this.beforeSelectEvent.fire();k=this.cfg.getProperty(m);}h.push(j);if(this._indexOfSelectedFieldArray(j)==-1){k[k.length]=j;}}}if(h.length&gt;0){if(this.parent){this.parent.cfg.setProperty(m,k);}else{this.cfg.setProperty(m,k);}this.selectEvent.fire(h);}return this.getSelectedDates();},selectCell:function(j){var h=this.cells[j],n=this.cellDates[j],m=this._toDate(n),i=c.hasClass(h,this.Style.CSS_CELL_SELECTABLE);if(i){this.beforeSelectEvent.fire();var l=b.SELECTED.key;var k=this.cfg.getProperty(l);var g=n.concat();if(this._indexOfSelectedFieldArray(g)==-1){k[k.length]=g;}if(this.parent){this.parent.cfg.setProperty(l,k);}else{this.cfg.setProperty(l,k);}this.renderCellStyleSelected(m,h);this.selectEvent.fire([g]);this.do
 CellMouseOut.call(h,null,this);}return this.getSelectedDates();},deselect:function(k){var g=this._toFieldArray(k),j=[],m=[],n=b.SELECTED.key;for(var h=0;h&lt;g.length;++h){var l=g[h];if(!this.isDateOOB(this._toDate(l))){if(j.length===0){this.beforeDeselectEvent.fire();m=this.cfg.getProperty(n);}j.push(l);var i=this._indexOfSelectedFieldArray(l);if(i!=-1){m.splice(i,1);}}}if(j.length&gt;0){if(this.parent){this.parent.cfg.setProperty(n,m);}else{this.cfg.setProperty(n,m);}this.deselectEvent.fire(j);}return this.getSelectedDates();},deselectCell:function(k){var h=this.cells[k],n=this.cellDates[k],i=this._indexOfSelectedFieldArray(n);var j=c.hasClass(h,this.Style.CSS_CELL_SELECTABLE);if(j){this.beforeDeselectEvent.fire();var l=this.cfg.getProperty(b.SELECTED.key),m=this._toDate(n),g=n.concat();if(i&gt;-1){if((this.cfg.getProperty(b.PAGEDATE.key).getMonth()==m.getMonth()&amp;&amp;this.cfg.getProperty(b.PAGEDATE.key).getFullYear()==m.getFullYear())||this.cfg.getProperty(b.OOM_SELEC
 T.key)){c.removeClass(h,this.Style.CSS_CELL_SELECTED);}l.splice(i,1);}if(this.parent){this.parent.cfg.setProperty(b.SELECTED.key,l);}else{this.cfg.setProperty(b.SELECTED.key,l);}this.deselectEvent.fire([g]);}return this.getSelectedDates();},deselectAll:function(){this.beforeDeselectEvent.fire();var j=b.SELECTED.key,g=this.cfg.getProperty(j),h=g.length,i=g.concat();if(this.parent){this.parent.cfg.setProperty(j,[]);}else{this.cfg.setProperty(j,[]);}if(h&gt;0){this.deselectEvent.fire(i);}return this.getSelectedDates();},_toFieldArray:function(h){var g=[];if(h instanceof Date){g=[[h.getFullYear(),h.getMonth()+1,h.getDate()]];}else{if(e.isString(h)){g=this._parseDates(h);}else{if(e.isArray(h)){for(var j=0;j&lt;h.length;++j){var k=h[j];g[g.length]=[k.getFullYear(),k.getMonth()+1,k.getDate()];}}}}return g;},toDate:function(g){return this._toDate(g);},_toDate:function(g){if(g instanceof Date){return g;}else{return d.getDate(g[0],g[1]-1,g[2]);}},_fieldArraysAreEqual:function(i,h){var
  g=false;if(i[0]==h[0]&amp;&amp;i[1]==h[1]&amp;&amp;i[2]==h[2]){g=true;}return g;},_indexOfSelectedFieldArray:function(k){var j=-1,g=this.cfg.getProperty(b.SELECTED.key);for(var i=0;i&lt;g.length;++i){var h=g[i];if(k[0]==h[0]&amp;&amp;k[1]==h[1]&amp;&amp;k[2]==h[2]){j=i;break;}}return j;},isDateOOM:function(g){return(g.getMonth()!=this.cfg.getProperty(b.PAGEDATE.key).getMonth());},isDateOOB:function(i){var j=this.cfg.getProperty(b.MINDATE.key),k=this.cfg.getProperty(b.MAXDATE.key),h=d;if(j){j=h.clearTime(j);}if(k){k=h.clearTime(k);}var g=new Date(i.getTime());g=h.clearTime(g);return((j&amp;&amp;g.getTime()&lt;j.getTime())||(k&amp;&amp;g.getTime()&gt;k.getTime()));},_parsePageDate:function(g){var j;if(g){if(g instanceof Date){j=d.findMonthStart(g);}else{var k,i,h;h=g.split(this.cfg.getProperty(b.DATE_FIELD_DELIMITER.key));k=parseInt(h[this.cfg.getProperty(b.MY_MONTH_POSITION.key)-1],10)-1;i=parseInt(h[this.cfg.getProperty(b.MY_YEAR_POSITION.key)-1],10)-this.Locale.YEAR_OFFSET
 ;j=d.getDate(i,k,1);}}else{j=d.getDate(this.today.getFullYear(),this.today.getMonth(),1);}return j;},onBeforeSelect:function(){if(this.cfg.getProperty(b.MULTI_SELECT.key)===false){if(this.parent){this.parent.callChildFunction(&quot;clearAllBodyCellStyles&quot;,this.Style.CSS_CELL_SELECTED);this.parent.deselectAll();}else{this.clearAllBodyCellStyles(this.Style.CSS_CELL_SELECTED);this.deselectAll();}}},onSelect:function(g){},onBeforeDeselect:function(){},onDeselect:function(g){},onChangePage:function(){this.render();},onRender:function(){},onReset:function(){this.render();},onClear:function(){this.render();},validate:function(){return true;},_parseDate:function(j){var k=j.split(this.Locale.DATE_FIELD_DELIMITER),g;if(k.length==2){g=[k[this.Locale.MD_MONTH_POSITION-1],k[this.Locale.MD_DAY_POSITION-1]];g.type=f.MONTH_DAY;}else{g=[k[this.Locale.MDY_YEAR_POSITION-1]-this.Locale.YEAR_OFFSET,k[this.Locale.MDY_MONTH_POSITION-1],k[this.Locale.MDY_DAY_POSITION-1]];g.type=f.DATE;}for(var
  h=0;h&lt;g.length;h++){g[h]=parseInt(g[h],10);}return g;},_parseDates:function(h){var o=[],n=h.split(this.Locale.DATE_DELIMITER);for(var m=0;m&lt;n.length;++m){var l=n[m];if(l.indexOf(this.Locale.DATE_RANGE_DELIMITER)!=-1){var g=l.split(this.Locale.DATE_RANGE_DELIMITER),k=this._parseDate(g[0]),p=this._parseDate(g[1]),j=this._parseRange(k,p);o=o.concat(j);}else{var i=this._parseDate(l);o.push(i);}}return o;},_parseRange:function(g,k){var h=d.add(d.getDate(g[0],g[1]-1,g[2]),d.DAY,1),j=d.getDate(k[0],k[1]-1,k[2]),i=[];i.push(g);while(h.getTime()&lt;=j.getTime()){i.push([h.getFullYear(),h.getMonth()+1,h.getDate()]);h=d.add(h,d.DAY,1);}return i;},resetRenderers:function(){this.renderStack=this._renderStack.concat();},removeRenderers:function(){this._renderStack=[];this.renderStack=[];},clearElement:function(g){g.innerHTML=&quot;&amp;#160;&quot;;g.className=&quot;&quot;;},addRenderer:function(g,h){var k=this._parseDates(g);for(var j=0;j&lt;k.length;++j){var l=k[j];if(l.length==2)
 {if(l[0] instanceof Array){this._addRenderer(f.RANGE,l,h);}else{this._addRenderer(f.MONTH_DAY,l,h);}}else{if(l.length==3){this._addRenderer(f.DATE,l,h);}}}},_addRenderer:function(h,i,g){var j=[h,i,g];
+this.renderStack.unshift(j);this._renderStack=this.renderStack.concat();},addMonthRenderer:function(h,g){this._addRenderer(f.MONTH,[h],g);},addWeekdayRenderer:function(h,g){this._addRenderer(f.WEEKDAY,[h],g);},clearAllBodyCellStyles:function(g){for(var h=0;h&lt;this.cells.length;++h){c.removeClass(this.cells[h],g);}},setMonth:function(i){var g=b.PAGEDATE.key,h=this.cfg.getProperty(g);h.setMonth(parseInt(i,10));this.cfg.setProperty(g,h);},setYear:function(h){var g=b.PAGEDATE.key,i=this.cfg.getProperty(g);i.setFullYear(parseInt(h,10)-this.Locale.YEAR_OFFSET);this.cfg.setProperty(g,i);},getSelectedDates:function(){var i=[],h=this.cfg.getProperty(b.SELECTED.key);for(var k=0;k&lt;h.length;++k){var j=h[k];var g=d.getDate(j[0],j[1]-1,j[2]);i.push(g);}i.sort(function(m,l){return m-l;});return i;},hide:function(){if(this.beforeHideEvent.fire()){this.oDomContainer.style.display=&quot;none&quot;;this.hideEvent.fire();}},show:function(){if(this.beforeShowEvent.fire()){this.oDomContainer
 .style.display=&quot;block&quot;;this.showEvent.fire();}},browser:(function(){var g=navigator.userAgent.toLowerCase();if(g.indexOf(&quot;opera&quot;)!=-1){return&quot;opera&quot;;}else{if(g.indexOf(&quot;msie 7&quot;)!=-1){return&quot;ie7&quot;;}else{if(g.indexOf(&quot;msie&quot;)!=-1){return&quot;ie&quot;;}else{if(g.indexOf(&quot;safari&quot;)!=-1){return&quot;safari&quot;;}else{if(g.indexOf(&quot;gecko&quot;)!=-1){return&quot;gecko&quot;;}else{return false;}}}}}})(),toString:function(){return&quot;Calendar &quot;+this.id;},destroy:function(){if(this.beforeDestroyEvent.fire()){var g=this;if(g.navigator){g.navigator.destroy();}if(g.cfg){g.cfg.destroy();}a.purgeElement(g.oDomContainer,true);c.removeClass(g.oDomContainer,g.Style.CSS_WITH_TITLE);c.removeClass(g.oDomContainer,g.Style.CSS_CONTAINER);c.removeClass(g.oDomContainer,g.Style.CSS_SINGLE);g.oDomContainer.innerHTML=&quot;&quot;;g.oDomContainer=null;g.cells=null;this.destroyEvent.fire();}}};YAHOO.widget.Calendar=f;YAHOO.w
 idget.Calendar_Core=YAHOO.widget.Calendar;YAHOO.widget.Cal_Core=YAHOO.widget.Calendar;})();(function(){var d=YAHOO.util.Dom,f=YAHOO.widget.DateMath,a=YAHOO.util.Event,e=YAHOO.lang,g=YAHOO.widget.Calendar;function b(j,h,i){if(arguments.length&gt;0){this.init.apply(this,arguments);}}b.DEFAULT_CONFIG=b._DEFAULT_CONFIG=g.DEFAULT_CONFIG;b.DEFAULT_CONFIG.PAGES={key:&quot;pages&quot;,value:2};var c=b.DEFAULT_CONFIG;b.prototype={init:function(k,i,j){var h=this._parseArgs(arguments);k=h.id;i=h.container;j=h.config;this.oDomContainer=d.get(i);if(!this.oDomContainer.id){this.oDomContainer.id=d.generateId();}if(!k){k=this.oDomContainer.id+&quot;_t&quot;;}this.id=k;this.containerId=this.oDomContainer.id;this.initEvents();this.initStyles();this.pages=[];d.addClass(this.oDomContainer,b.CSS_CONTAINER);d.addClass(this.oDomContainer,b.CSS_MULTI_UP);this.cfg=new YAHOO.util.Config(this);this.Options={};this.Locale={};this.setupConfig();if(j){this.cfg.applyConfig(j,true);}this.cfg.fireQueue();},
 setupConfig:function(){var h=this.cfg;h.addProperty(c.PAGES.key,{value:c.PAGES.value,validator:h.checkNumber,handler:this.configPages});h.addProperty(c.YEAR_OFFSET.key,{value:c.YEAR_OFFSET.value,handler:this.delegateConfig,supercedes:c.YEAR_OFFSET.supercedes,suppressEvent:true});h.addProperty(c.TODAY.key,{value:new Date(c.TODAY.value.getTime()),supercedes:c.TODAY.supercedes,handler:this.configToday,suppressEvent:false});h.addProperty(c.PAGEDATE.key,{value:c.PAGEDATE.value||new Date(c.TODAY.value.getTime()),handler:this.configPageDate});h.addProperty(c.SELECTED.key,{value:[],handler:this.configSelected});h.addProperty(c.TITLE.key,{value:c.TITLE.value,handler:this.configTitle});h.addProperty(c.CLOSE.key,{value:c.CLOSE.value,handler:this.configClose});h.addProperty(c.IFRAME.key,{value:c.IFRAME.value,handler:this.configIframe,validator:h.checkBoolean});h.addProperty(c.MINDATE.key,{value:c.MINDATE.value,handler:this.delegateConfig});h.addProperty(c.MAXDATE.key,{value:c.MAXDATE.va
 lue,handler:this.delegateConfig});h.addProperty(c.MULTI_SELECT.key,{value:c.MULTI_SELECT.value,handler:this.delegateConfig,validator:h.checkBoolean});h.addProperty(c.OOM_SELECT.key,{value:c.OOM_SELECT.value,handler:this.delegateConfig,validator:h.checkBoolean});h.addProperty(c.START_WEEKDAY.key,{value:c.START_WEEKDAY.value,handler:this.delegateConfig,validator:h.checkNumber});h.addProperty(c.SHOW_WEEKDAYS.key,{value:c.SHOW_WEEKDAYS.value,handler:this.delegateConfig,validator:h.checkBoolean});h.addProperty(c.SHOW_WEEK_HEADER.key,{value:c.SHOW_WEEK_HEADER.value,handler:this.delegateConfig,validator:h.checkBoolean});h.addProperty(c.SHOW_WEEK_FOOTER.key,{value:c.SHOW_WEEK_FOOTER.value,handler:this.delegateConfig,validator:h.checkBoolean});h.addProperty(c.HIDE_BLANK_WEEKS.key,{value:c.HIDE_BLANK_WEEKS.value,handler:this.delegateConfig,validator:h.checkBoolean});h.addProperty(c.NAV_ARROW_LEFT.key,{value:c.NAV_ARROW_LEFT.value,handler:this.delegateConfig});h.addProperty(c.NAV_ARROW
 _RIGHT.key,{value:c.NAV_ARROW_RIGHT.value,handler:this.delegateConfig});h.addProperty(c.MONTHS_SHORT.key,{value:c.MONTHS_SHORT.value,handler:this.delegateConfig});h.addProperty(c.MONTHS_LONG.key,{value:c.MONTHS_LONG.value,handler:this.delegateConfig});h.addProperty(c.WEEKDAYS_1CHAR.key,{value:c.WEEKDAYS_1CHAR.value,handler:this.delegateConfig});h.addProperty(c.WEEKDAYS_SHORT.key,{value:c.WEEKDAYS_SHORT.value,handler:this.delegateConfig});h.addProperty(c.WEEKDAYS_MEDIUM.key,{value:c.WEEKDAYS_MEDIUM.value,handler:this.delegateConfig});h.addProperty(c.WEEKDAYS_LONG.key,{value:c.WEEKDAYS_LONG.value,handler:this.delegateConfig});h.addProperty(c.LOCALE_MONTHS.key,{value:c.LOCALE_MONTHS.value,handler:this.delegateConfig});h.addProperty(c.LOCALE_WEEKDAYS.key,{value:c.LOCALE_WEEKDAYS.value,handler:this.delegateConfig});h.addProperty(c.DATE_DELIMITER.key,{value:c.DATE_DELIMITER.value,handler:this.delegateConfig});h.addProperty(c.DATE_FIELD_DELIMITER.key,{value:c.DATE_FIELD_DELIMITER.v
 alue,handler:this.delegateConfig});h.addProperty(c.DATE_RANGE_DELIMITER.key,{value:c.DATE_RANGE_DELIMITER.value,handler:this.delegateConfig});h.addProperty(c.MY_MONTH_POSITION.key,{value:c.MY_MONTH_POSITION.value,handler:this.delegateConfig,validator:h.checkNumber});
+h.addProperty(c.MY_YEAR_POSITION.key,{value:c.MY_YEAR_POSITION.value,handler:this.delegateConfig,validator:h.checkNumber});h.addProperty(c.MD_MONTH_POSITION.key,{value:c.MD_MONTH_POSITION.value,handler:this.delegateConfig,validator:h.checkNumber});h.addProperty(c.MD_DAY_POSITION.key,{value:c.MD_DAY_POSITION.value,handler:this.delegateConfig,validator:h.checkNumber});h.addProperty(c.MDY_MONTH_POSITION.key,{value:c.MDY_MONTH_POSITION.value,handler:this.delegateConfig,validator:h.checkNumber});h.addProperty(c.MDY_DAY_POSITION.key,{value:c.MDY_DAY_POSITION.value,handler:this.delegateConfig,validator:h.checkNumber});h.addProperty(c.MDY_YEAR_POSITION.key,{value:c.MDY_YEAR_POSITION.value,handler:this.delegateConfig,validator:h.checkNumber});h.addProperty(c.MY_LABEL_MONTH_POSITION.key,{value:c.MY_LABEL_MONTH_POSITION.value,handler:this.delegateConfig,validator:h.checkNumber});h.addProperty(c.MY_LABEL_YEAR_POSITION.key,{value:c.MY_LABEL_YEAR_POSITION.value,handler:this.delegateConfig
 ,validator:h.checkNumber});h.addProperty(c.MY_LABEL_MONTH_SUFFIX.key,{value:c.MY_LABEL_MONTH_SUFFIX.value,handler:this.delegateConfig});h.addProperty(c.MY_LABEL_YEAR_SUFFIX.key,{value:c.MY_LABEL_YEAR_SUFFIX.value,handler:this.delegateConfig});h.addProperty(c.NAV.key,{value:c.NAV.value,handler:this.configNavigator});h.addProperty(c.STRINGS.key,{value:c.STRINGS.value,handler:this.configStrings,validator:function(i){return e.isObject(i);},supercedes:c.STRINGS.supercedes});},initEvents:function(){var j=this,l=&quot;Event&quot;,m=YAHOO.util.CustomEvent;var i=function(o,s,n){for(var r=0;r&lt;j.pages.length;++r){var q=j.pages[r];q[this.type+l].subscribe(o,s,n);}};var h=function(n,r){for(var q=0;q&lt;j.pages.length;++q){var o=j.pages[q];o[this.type+l].unsubscribe(n,r);}};var k=g._EVENT_TYPES;j.beforeSelectEvent=new m(k.BEFORE_SELECT);j.beforeSelectEvent.subscribe=i;j.beforeSelectEvent.unsubscribe=h;j.selectEvent=new m(k.SELECT);j.selectEvent.subscribe=i;j.selectEvent.unsubscribe=h;j
 .beforeDeselectEvent=new m(k.BEFORE_DESELECT);j.beforeDeselectEvent.subscribe=i;j.beforeDeselectEvent.unsubscribe=h;j.deselectEvent=new m(k.DESELECT);j.deselectEvent.subscribe=i;j.deselectEvent.unsubscribe=h;j.changePageEvent=new m(k.CHANGE_PAGE);j.changePageEvent.subscribe=i;j.changePageEvent.unsubscribe=h;j.beforeRenderEvent=new m(k.BEFORE_RENDER);j.beforeRenderEvent.subscribe=i;j.beforeRenderEvent.unsubscribe=h;j.renderEvent=new m(k.RENDER);j.renderEvent.subscribe=i;j.renderEvent.unsubscribe=h;j.resetEvent=new m(k.RESET);j.resetEvent.subscribe=i;j.resetEvent.unsubscribe=h;j.clearEvent=new m(k.CLEAR);j.clearEvent.subscribe=i;j.clearEvent.unsubscribe=h;j.beforeShowEvent=new m(k.BEFORE_SHOW);j.showEvent=new m(k.SHOW);j.beforeHideEvent=new m(k.BEFORE_HIDE);j.hideEvent=new m(k.HIDE);j.beforeShowNavEvent=new m(k.BEFORE_SHOW_NAV);j.showNavEvent=new m(k.SHOW_NAV);j.beforeHideNavEvent=new m(k.BEFORE_HIDE_NAV);j.hideNavEvent=new m(k.HIDE_NAV);j.beforeRenderNavEvent=new m(k.BEFORE_R
 ENDER_NAV);j.renderNavEvent=new m(k.RENDER_NAV);j.beforeDestroyEvent=new m(k.BEFORE_DESTROY);j.destroyEvent=new m(k.DESTROY);},configPages:function(u,s,n){var l=s[0],j=c.PAGEDATE.key,x=&quot;_&quot;,m,o=null,t=&quot;groupcal&quot;,w=&quot;first-of-type&quot;,k=&quot;last-of-type&quot;;for(var i=0;i&lt;l;++i){var v=this.id+x+i,r=this.containerId+x+i,q=this.cfg.getConfig();q.close=false;q.title=false;q.navigator=null;if(i&gt;0){m=new Date(o);this._setMonthOnDate(m,m.getMonth()+i);q.pageDate=m;}var h=this.constructChild(v,r,q);d.removeClass(h.oDomContainer,this.Style.CSS_SINGLE);d.addClass(h.oDomContainer,t);if(i===0){o=h.cfg.getProperty(j);d.addClass(h.oDomContainer,w);}if(i==(l-1)){d.addClass(h.oDomContainer,k);}h.parent=this;h.index=i;this.pages[this.pages.length]=h;}},configPageDate:function(o,n,l){var j=n[0],m;var k=c.PAGEDATE.key;for(var i=0;i&lt;this.pages.length;++i){var h=this.pages[i];if(i===0){m=h._parsePageDate(j);h.cfg.setProperty(k,m);}else{var q=new Date(m);this.
 _setMonthOnDate(q,q.getMonth()+i);h.cfg.setProperty(k,q);}}},configSelected:function(j,h,l){var k=c.SELECTED.key;this.delegateConfig(j,h,l);var i=(this.pages.length&gt;0)?this.pages[0].cfg.getProperty(k):[];this.cfg.setProperty(k,i,true);},delegateConfig:function(i,h,l){var m=h[0];var k;for(var j=0;j&lt;this.pages.length;j++){k=this.pages[j];k.cfg.setProperty(i,m);}},setChildFunction:function(k,i){var h=this.cfg.getProperty(c.PAGES.key);for(var j=0;j&lt;h;++j){this.pages[j][k]=i;}},callChildFunction:function(m,i){var h=this.cfg.getProperty(c.PAGES.key);for(var l=0;l&lt;h;++l){var k=this.pages[l];if(k[m]){var j=k[m];j.call(k,i);}}},constructChild:function(k,i,j){var h=document.getElementById(i);if(!h){h=document.createElement(&quot;div&quot;);h.id=i;this.oDomContainer.appendChild(h);}return new g(k,i,j);},setMonth:function(l){l=parseInt(l,10);var m;var i=c.PAGEDATE.key;for(var k=0;k&lt;this.pages.length;++k){var j=this.pages[k];var h=j.cfg.getProperty(i);if(k===0){m=h.getFull
 Year();}else{h.setFullYear(m);}this._setMonthOnDate(h,l+k);j.cfg.setProperty(i,h);}},setYear:function(j){var i=c.PAGEDATE.key;j=parseInt(j,10);for(var l=0;l&lt;this.pages.length;++l){var k=this.pages[l];var h=k.cfg.getProperty(i);if((h.getMonth()+1)==1&amp;&amp;l&gt;0){j+=1;}k.setYear(j);}},render:function(){this.renderHeader();for(var i=0;i&lt;this.pages.length;++i){var h=this.pages[i];h.render();}this.renderFooter();},select:function(h){for(var j=0;j&lt;this.pages.length;++j){var i=this.pages[j];i.select(h);}return this.getSelectedDates();},selectCell:function(h){for(var j=0;j&lt;this.pages.length;++j){var i=this.pages[j];i.selectCell(h);}return this.getSelectedDates();},deselect:function(h){for(var j=0;j&lt;this.pages.length;++j){var i=this.pages[j];i.deselect(h);}return this.getSelectedDates();},deselectAll:function(){for(var i=0;i&lt;this.pages.length;++i){var h=this.pages[i];h.deselectAll();}return this.getSelectedDates();},deselectCell:function(h){for(var j=0;j&lt;thi
 s.pages.length;++j){var i=this.pages[j];i.deselectCell(h);}return this.getSelectedDates();},reset:function(){for(var i=0;i&lt;this.pages.length;++i){var h=this.pages[i];h.reset();}},clear:function(){for(var i=0;
+i&lt;this.pages.length;++i){var h=this.pages[i];h.clear();}this.cfg.setProperty(c.SELECTED.key,[]);this.cfg.setProperty(c.PAGEDATE.key,new Date(this.pages[0].today.getTime()));this.render();},nextMonth:function(){for(var i=0;i&lt;this.pages.length;++i){var h=this.pages[i];h.nextMonth();}},previousMonth:function(){for(var i=this.pages.length-1;i&gt;=0;--i){var h=this.pages[i];h.previousMonth();}},nextYear:function(){for(var i=0;i&lt;this.pages.length;++i){var h=this.pages[i];h.nextYear();}},previousYear:function(){for(var i=0;i&lt;this.pages.length;++i){var h=this.pages[i];h.previousYear();}},getSelectedDates:function(){var j=[];var i=this.cfg.getProperty(c.SELECTED.key);for(var l=0;l&lt;i.length;++l){var k=i[l];var h=f.getDate(k[0],k[1]-1,k[2]);j.push(h);}j.sort(function(n,m){return n-m;});return j;},addRenderer:function(h,i){for(var k=0;k&lt;this.pages.length;++k){var j=this.pages[k];j.addRenderer(h,i);}},addMonthRenderer:function(k,h){for(var j=0;j&lt;this.pages.length;++j
 ){var i=this.pages[j];i.addMonthRenderer(k,h);}},addWeekdayRenderer:function(i,h){for(var k=0;k&lt;this.pages.length;++k){var j=this.pages[k];j.addWeekdayRenderer(i,h);}},removeRenderers:function(){this.callChildFunction(&quot;removeRenderers&quot;);},renderHeader:function(){},renderFooter:function(){},addMonths:function(h){this.callChildFunction(&quot;addMonths&quot;,h);},subtractMonths:function(h){this.callChildFunction(&quot;subtractMonths&quot;,h);},addYears:function(h){this.callChildFunction(&quot;addYears&quot;,h);},subtractYears:function(h){this.callChildFunction(&quot;subtractYears&quot;,h);},getCalendarPage:function(l){var o=null;if(l){var p=l.getFullYear(),k=l.getMonth();var j=this.pages;for(var n=0;n&lt;j.length;++n){var h=j[n].cfg.getProperty(&quot;pagedate&quot;);if(h.getFullYear()===p&amp;&amp;h.getMonth()===k){o=j[n];break;}}}return o;},_setMonthOnDate:function(i,j){if(YAHOO.env.ua.webkit&amp;&amp;YAHOO.env.ua.webkit&lt;420&amp;&amp;(j&lt;0||j&gt;11)){var h=f.
 add(i,f.MONTH,j-i.getMonth());i.setTime(h.getTime());}else{i.setMonth(j);}},_fixWidth:function(){var h=0;for(var j=0;j&lt;this.pages.length;++j){var i=this.pages[j];h+=i.oDomContainer.offsetWidth;}if(h&gt;0){this.oDomContainer.style.width=h+&quot;px&quot;;}},toString:function(){return&quot;CalendarGroup &quot;+this.id;},destroy:function(){if(this.beforeDestroyEvent.fire()){var k=this;if(k.navigator){k.navigator.destroy();}if(k.cfg){k.cfg.destroy();}a.purgeElement(k.oDomContainer,true);d.removeClass(k.oDomContainer,b.CSS_CONTAINER);d.removeClass(k.oDomContainer,b.CSS_MULTI_UP);for(var j=0,h=k.pages.length;j&lt;h;j++){k.pages[j].destroy();k.pages[j]=null;}k.oDomContainer.innerHTML=&quot;&quot;;k.oDomContainer=null;this.destroyEvent.fire();}}};b.CSS_CONTAINER=&quot;yui-calcontainer&quot;;b.CSS_MULTI_UP=&quot;multi&quot;;b.CSS_2UPTITLE=&quot;title&quot;;b.CSS_2UPCLOSE=&quot;close-icon&quot;;YAHOO.lang.augmentProto(b,g,&quot;buildDayLabel&quot;,&quot;buildMonthLabel&quot;,&quot;r
 enderOutOfBoundsDate&quot;,&quot;renderRowHeader&quot;,&quot;renderRowFooter&quot;,&quot;renderCellDefault&quot;,&quot;styleCellDefault&quot;,&quot;renderCellStyleHighlight1&quot;,&quot;renderCellStyleHighlight2&quot;,&quot;renderCellStyleHighlight3&quot;,&quot;renderCellStyleHighlight4&quot;,&quot;renderCellStyleToday&quot;,&quot;renderCellStyleSelected&quot;,&quot;renderCellNotThisMonth&quot;,&quot;styleCellNotThisMonth&quot;,&quot;renderBodyCellRestricted&quot;,&quot;initStyles&quot;,&quot;configTitle&quot;,&quot;configClose&quot;,&quot;configIframe&quot;,&quot;configStrings&quot;,&quot;configToday&quot;,&quot;configNavigator&quot;,&quot;createTitleBar&quot;,&quot;createCloseButton&quot;,&quot;removeTitleBar&quot;,&quot;removeCloseButton&quot;,&quot;hide&quot;,&quot;show&quot;,&quot;toDate&quot;,&quot;_toDate&quot;,&quot;_parseArgs&quot;,&quot;browser&quot;);YAHOO.widget.CalGrp=b;YAHOO.widget.CalendarGroup=b;YAHOO.widget.Calendar2up=function(j,h,i){this.init(j,h,i);};YAHO
 O.extend(YAHOO.widget.Calendar2up,b);YAHOO.widget.Cal2up=YAHOO.widget.Calendar2up;})();YAHOO.widget.CalendarNavigator=function(a){this.init(a);};(function(){var a=YAHOO.widget.CalendarNavigator;a.CLASSES={NAV:&quot;yui-cal-nav&quot;,NAV_VISIBLE:&quot;yui-cal-nav-visible&quot;,MASK:&quot;yui-cal-nav-mask&quot;,YEAR:&quot;yui-cal-nav-y&quot;,MONTH:&quot;yui-cal-nav-m&quot;,BUTTONS:&quot;yui-cal-nav-b&quot;,BUTTON:&quot;yui-cal-nav-btn&quot;,ERROR:&quot;yui-cal-nav-e&quot;,YEAR_CTRL:&quot;yui-cal-nav-yc&quot;,MONTH_CTRL:&quot;yui-cal-nav-mc&quot;,INVALID:&quot;yui-invalid&quot;,DEFAULT:&quot;yui-default&quot;};a.DEFAULT_CONFIG={strings:{month:&quot;Month&quot;,year:&quot;Year&quot;,submit:&quot;Okay&quot;,cancel:&quot;Cancel&quot;,invalidYear:&quot;Year needs to be a number&quot;},monthFormat:YAHOO.widget.Calendar.LONG,initialFocus:&quot;year&quot;};a._DEFAULT_CFG=a.DEFAULT_CONFIG;a.ID_SUFFIX=&quot;_nav&quot;;a.MONTH_SUFFIX=&quot;_month&quot;;a.YEAR_SUFFIX=&quot;_year&quot;;a.E
 RROR_SUFFIX=&quot;_error&quot;;a.CANCEL_SUFFIX=&quot;_cancel&quot;;a.SUBMIT_SUFFIX=&quot;_submit&quot;;a.YR_MAX_DIGITS=4;a.YR_MINOR_INC=1;a.YR_MAJOR_INC=10;a.UPDATE_DELAY=50;a.YR_PATTERN=/^\d+$/;a.TRIM=/^\s*(.*?)\s*$/;})();YAHOO.widget.CalendarNavigator.prototype={id:null,cal:null,navEl:null,maskEl:null,yearEl:null,monthEl:null,errorEl:null,submitEl:null,cancelEl:null,firstCtrl:null,lastCtrl:null,_doc:null,_year:null,_month:0,__rendered:false,init:function(a){var c=a.oDomContainer;this.cal=a;this.id=c.id+YAHOO.widget.CalendarNavigator.ID_SUFFIX;this._doc=c.ownerDocument;var b=YAHOO.env.ua.ie;this.__isIEQuirks=(b&amp;&amp;((b&lt;=6)||(this._doc.compatMode==&quot;BackCompat&quot;)));},show:function(){var a=YAHOO.widget.CalendarNavigator.CLASSES;if(this.cal.beforeShowNavEvent.fire()){if(!this.__rendered){this.render();}this.clearErrors();this._updateMonthUI();this._updateYearUI();this._show(this.navEl,true);this.setInitialFocus();this.showMask();YAHOO.util.Dom.addClass(this.cal
 .oDomContainer,a.NAV_VISIBLE);this.cal.showNavEvent.fire();}},hide:function(){var a=YAHOO.widget.CalendarNavigator.CLASSES;if(this.cal.beforeHideNavEvent.fire()){this._show(this.navEl,false);this.hideMask();YAHOO.util.Dom.removeClass(this.cal.oDomContainer,a.NAV_VISIBLE);this.cal.hideNavEvent.fire();}},showMask:function(){this._show(this.maskEl,true);if(this.__isIEQuirks){this._syncMask();}},hideMask:function(){this._show(this.maskEl,false);},getMonth:function(){return this._month;},getYear:function(){return this._year;},setMonth:function(a){if(a&gt;=0&amp;&amp;a&lt;12){this._month=a;}this._updateMonthUI();},setYear:function(b){var a=YAHOO.widget.CalendarNavigator.YR_PATTERN;if(YAHOO.lang.isNumber(b)&amp;&amp;a.test(b+&quot;&quot;)){this._year=b;}this._updateYearUI();},render:function(){this.cal.beforeRenderNavEvent.fire();if(!this.__rendered){this.createNav();this.createMask();this.applyListeners();
+this.__rendered=true;}this.cal.renderNavEvent.fire();},createNav:function(){var b=YAHOO.widget.CalendarNavigator;var c=this._doc;var e=c.createElement(&quot;div&quot;);e.className=b.CLASSES.NAV;var a=this.renderNavContents([]);e.innerHTML=a.join(&quot;&quot;);this.cal.oDomContainer.appendChild(e);this.navEl=e;this.yearEl=c.getElementById(this.id+b.YEAR_SUFFIX);this.monthEl=c.getElementById(this.id+b.MONTH_SUFFIX);this.errorEl=c.getElementById(this.id+b.ERROR_SUFFIX);this.submitEl=c.getElementById(this.id+b.SUBMIT_SUFFIX);this.cancelEl=c.getElementById(this.id+b.CANCEL_SUFFIX);if(YAHOO.env.ua.gecko&amp;&amp;this.yearEl&amp;&amp;this.yearEl.type==&quot;text&quot;){this.yearEl.setAttribute(&quot;autocomplete&quot;,&quot;off&quot;);}this._setFirstLastElements();},createMask:function(){var b=YAHOO.widget.CalendarNavigator.CLASSES;var a=this._doc.createElement(&quot;div&quot;);a.className=b.MASK;this.cal.oDomContainer.appendChild(a);this.maskEl=a;},_syncMask:function(){var b=this.
 cal.oDomContainer;if(b&amp;&amp;this.maskEl){var a=YAHOO.util.Dom.getRegion(b);YAHOO.util.Dom.setStyle(this.maskEl,&quot;width&quot;,a.right-a.left+&quot;px&quot;);YAHOO.util.Dom.setStyle(this.maskEl,&quot;height&quot;,a.bottom-a.top+&quot;px&quot;);}},renderNavContents:function(a){var c=YAHOO.widget.CalendarNavigator,d=c.CLASSES,b=a;b[b.length]='&lt;div class=&quot;'+d.MONTH+'&quot;&gt;';this.renderMonth(b);b[b.length]=&quot;&lt;/div&gt;&quot;;b[b.length]='&lt;div class=&quot;'+d.YEAR+'&quot;&gt;';this.renderYear(b);b[b.length]=&quot;&lt;/div&gt;&quot;;b[b.length]='&lt;div class=&quot;'+d.BUTTONS+'&quot;&gt;';this.renderButtons(b);b[b.length]=&quot;&lt;/div&gt;&quot;;b[b.length]='&lt;div class=&quot;'+d.ERROR+'&quot; id=&quot;'+this.id+c.ERROR_SUFFIX+'&quot;&gt;&lt;/div&gt;';return b;},renderMonth:function(c){var f=YAHOO.widget.CalendarNavigator,g=f.CLASSES;var j=this.id+f.MONTH_SUFFIX,e=this.__getCfg(&quot;monthFormat&quot;),a=this.cal.cfg.getProperty((e==YAHOO.widget.Cale
 ndar.SHORT)?&quot;MONTHS_SHORT&quot;:&quot;MONTHS_LONG&quot;),d=c;if(a&amp;&amp;a.length&gt;0){d[d.length]='&lt;label for=&quot;'+j+'&quot;&gt;';d[d.length]=this.__getCfg(&quot;month&quot;,true);d[d.length]=&quot;&lt;/label&gt;&quot;;d[d.length]='&lt;select name=&quot;'+j+'&quot; id=&quot;'+j+'&quot; class=&quot;'+g.MONTH_CTRL+'&quot;&gt;';for(var b=0;b&lt;a.length;b++){d[d.length]='&lt;option value=&quot;'+b+'&quot;&gt;';d[d.length]=a[b];d[d.length]=&quot;&lt;/option&gt;&quot;;}d[d.length]=&quot;&lt;/select&gt;&quot;;}return d;},renderYear:function(b){var d=YAHOO.widget.CalendarNavigator,e=d.CLASSES;var f=this.id+d.YEAR_SUFFIX,a=d.YR_MAX_DIGITS,c=b;c[c.length]='&lt;label for=&quot;'+f+'&quot;&gt;';c[c.length]=this.__getCfg(&quot;year&quot;,true);c[c.length]=&quot;&lt;/label&gt;&quot;;c[c.length]='&lt;input type=&quot;text&quot; name=&quot;'+f+'&quot; id=&quot;'+f+'&quot; class=&quot;'+e.YEAR_CTRL+'&quot; maxlength=&quot;'+a+'&quot;/&gt;';return c;},renderButtons:function(a)
 {var c=YAHOO.widget.CalendarNavigator.CLASSES;var b=a;b[b.length]='&lt;span class=&quot;'+c.BUTTON+&quot; &quot;+c.DEFAULT+'&quot;&gt;';b[b.length]='&lt;button type=&quot;button&quot; id=&quot;'+this.id+&quot;_submit&quot;+'&quot;&gt;';b[b.length]=this.__getCfg(&quot;submit&quot;,true);b[b.length]=&quot;&lt;/button&gt;&quot;;b[b.length]=&quot;&lt;/span&gt;&quot;;b[b.length]='&lt;span class=&quot;'+c.BUTTON+'&quot;&gt;';b[b.length]='&lt;button type=&quot;button&quot; id=&quot;'+this.id+&quot;_cancel&quot;+'&quot;&gt;';b[b.length]=this.__getCfg(&quot;cancel&quot;,true);b[b.length]=&quot;&lt;/button&gt;&quot;;b[b.length]=&quot;&lt;/span&gt;&quot;;return b;},applyListeners:function(){var b=YAHOO.util.Event;function a(){if(this.validate()){this.setYear(this._getYearFromUI());}}function c(){this.setMonth(this._getMonthFromUI());}b.on(this.submitEl,&quot;click&quot;,this.submit,this,true);b.on(this.cancelEl,&quot;click&quot;,this.cancel,this,true);b.on(this.yearEl,&quot;blur&quot;,
 a,this,true);b.on(this.monthEl,&quot;change&quot;,c,this,true);if(this.__isIEQuirks){YAHOO.util.Event.on(this.cal.oDomContainer,&quot;resize&quot;,this._syncMask,this,true);}this.applyKeyListeners();},purgeListeners:function(){var a=YAHOO.util.Event;a.removeListener(this.submitEl,&quot;click&quot;,this.submit);a.removeListener(this.cancelEl,&quot;click&quot;,this.cancel);a.removeListener(this.yearEl,&quot;blur&quot;);a.removeListener(this.monthEl,&quot;change&quot;);if(this.__isIEQuirks){a.removeListener(this.cal.oDomContainer,&quot;resize&quot;,this._syncMask);}this.purgeKeyListeners();},applyKeyListeners:function(){var d=YAHOO.util.Event,a=YAHOO.env.ua;var c=(a.ie||a.webkit)?&quot;keydown&quot;:&quot;keypress&quot;;var b=(a.ie||a.opera||a.webkit)?&quot;keydown&quot;:&quot;keypress&quot;;d.on(this.yearEl,&quot;keypress&quot;,this._handleEnterKey,this,true);d.on(this.yearEl,c,this._handleDirectionKeys,this,true);d.on(this.lastCtrl,b,this._handleTabKey,this,true);d.on(this.fi
 rstCtrl,b,this._handleShiftTabKey,this,true);},purgeKeyListeners:function(){var d=YAHOO.util.Event,a=YAHOO.env.ua;var c=(a.ie||a.webkit)?&quot;keydown&quot;:&quot;keypress&quot;;var b=(a.ie||a.opera||a.webkit)?&quot;keydown&quot;:&quot;keypress&quot;;d.removeListener(this.yearEl,&quot;keypress&quot;,this._handleEnterKey);d.removeListener(this.yearEl,c,this._handleDirectionKeys);d.removeListener(this.lastCtrl,b,this._handleTabKey);d.removeListener(this.firstCtrl,b,this._handleShiftTabKey);},submit:function(){if(this.validate()){this.hide();this.setMonth(this._getMonthFromUI());this.setYear(this._getYearFromUI());var b=this.cal;var a=YAHOO.widget.CalendarNavigator.UPDATE_DELAY;if(a&gt;0){var c=this;window.setTimeout(function(){c._update(b);},a);}else{this._update(b);}}},_update:function(b){var a=YAHOO.widget.DateMath.getDate(this.getYear()-b.cfg.getProperty(&quot;YEAR_OFFSET&quot;),this.getMonth(),1);b.cfg.setProperty(&quot;pagedate&quot;,a);b.render();},cancel:function(){this
 .hide();},validate:function(){if(this._getYearFromUI()!==null){this.clearErrors();return true;}else{this.setYearError();this.setError(this.__getCfg(&quot;invalidYear&quot;,true));return false;}},setError:function(a){if(this.errorEl){this.errorEl.innerHTML=a;this._show(this.errorEl,true);}},clearError:function(){if(this.errorEl){this.errorEl.innerHTML=&quot;&quot;;this._show(this.errorEl,false);}},setYearError:function(){YAHOO.util.Dom.addClass(this.yearEl,YAHOO.widget.CalendarNavigator.CLASSES.INVALID);},clearYearError:function(){YAHOO.util.Dom.removeClass(this.yearEl,YAHOO.widget.CalendarNavigator.CLASSES.INVALID);},clearErrors:function(){this.clearError();this.clearYearError();},setInitialFocus:function(){var a=this.submitEl,c=this.__getCfg(&quot;initialFocus&quot;);if(c&amp;&amp;c.toLowerCase){c=c.toLowerCase();if(c==&quot;year&quot;){a=this.yearEl;try{this.yearEl.select();}catch(b){}}else{if(c==&quot;month&quot;){a=this.monthEl;}}}if(a&amp;&amp;YAHOO.lang.isFunction(a.fo
 cus)){try{a.focus();}catch(d){}}},erase:function(){if(this.__rendered){this.purgeListeners();
+this.yearEl=null;this.monthEl=null;this.errorEl=null;this.submitEl=null;this.cancelEl=null;this.firstCtrl=null;this.lastCtrl=null;if(this.navEl){this.navEl.innerHTML=&quot;&quot;;}var b=this.navEl.parentNode;if(b){b.removeChild(this.navEl);}this.navEl=null;var a=this.maskEl.parentNode;if(a){a.removeChild(this.maskEl);}this.maskEl=null;this.__rendered=false;}},destroy:function(){this.erase();this._doc=null;this.cal=null;this.id=null;},_show:function(b,a){if(b){YAHOO.util.Dom.setStyle(b,&quot;display&quot;,(a)?&quot;block&quot;:&quot;none&quot;);}},_getMonthFromUI:function(){if(this.monthEl){return this.monthEl.selectedIndex;}else{return 0;}},_getYearFromUI:function(){var b=YAHOO.widget.CalendarNavigator;var a=null;if(this.yearEl){var c=this.yearEl.value;c=c.replace(b.TRIM,&quot;$1&quot;);if(b.YR_PATTERN.test(c)){a=parseInt(c,10);}}return a;},_updateYearUI:function(){if(this.yearEl&amp;&amp;this._year!==null){this.yearEl.value=this._year;}},_updateMonthUI:function(){if(this.mo
 nthEl){this.monthEl.selectedIndex=this._month;}},_setFirstLastElements:function(){this.firstCtrl=this.monthEl;this.lastCtrl=this.cancelEl;if(this.__isMac){if(YAHOO.env.ua.webkit&amp;&amp;YAHOO.env.ua.webkit&lt;420){this.firstCtrl=this.monthEl;this.lastCtrl=this.yearEl;}if(YAHOO.env.ua.gecko){this.firstCtrl=this.yearEl;this.lastCtrl=this.yearEl;}}},_handleEnterKey:function(b){var a=YAHOO.util.KeyListener.KEY;if(YAHOO.util.Event.getCharCode(b)==a.ENTER){YAHOO.util.Event.preventDefault(b);this.submit();}},_handleDirectionKeys:function(h){var g=YAHOO.util.Event,a=YAHOO.util.KeyListener.KEY,d=YAHOO.widget.CalendarNavigator;var f=(this.yearEl.value)?parseInt(this.yearEl.value,10):null;if(isFinite(f)){var b=false;switch(g.getCharCode(h)){case a.UP:this.yearEl.value=f+d.YR_MINOR_INC;b=true;break;case a.DOWN:this.yearEl.value=Math.max(f-d.YR_MINOR_INC,0);b=true;break;case a.PAGE_UP:this.yearEl.value=f+d.YR_MAJOR_INC;b=true;break;case a.PAGE_DOWN:this.yearEl.value=Math.max(f-d.YR_MAJO
 R_INC,0);b=true;break;default:break;}if(b){g.preventDefault(h);try{this.yearEl.select();}catch(c){}}}},_handleTabKey:function(d){var c=YAHOO.util.Event,a=YAHOO.util.KeyListener.KEY;if(c.getCharCode(d)==a.TAB&amp;&amp;!d.shiftKey){try{c.preventDefault(d);this.firstCtrl.focus();}catch(b){}}},_handleShiftTabKey:function(d){var c=YAHOO.util.Event,a=YAHOO.util.KeyListener.KEY;if(d.shiftKey&amp;&amp;c.getCharCode(d)==a.TAB){try{c.preventDefault(d);this.lastCtrl.focus();}catch(b){}}},__getCfg:function(d,b){var c=YAHOO.widget.CalendarNavigator.DEFAULT_CONFIG;var a=this.cal.cfg.getProperty(&quot;navigator&quot;);if(b){return(a!==true&amp;&amp;a.strings&amp;&amp;a.strings[d])?a.strings[d]:c.strings[d];}else{return(a!==true&amp;&amp;a[d])?a[d]:c[d];}},__isMac:(navigator.userAgent.toLowerCase().indexOf(&quot;macintosh&quot;)!=-1)};YAHOO.register(&quot;calendar&quot;,YAHOO.widget.Calendar,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuicalendarjs"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/js/yui/calendar.js (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/calendar.js        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/js/yui/calendar.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,16 +0,0 @@
</span><del>-/*
-Copyright (c) 2007, Yahoo! Inc. All rights reserved.
-Code licensed under the BSD License:
-http://developer.yahoo.net/yui/license.txt
-version: 2.3.1
-*/
-(function(){YAHOO.util.Config=function(D){if(D){this.init(D);}if(!D){}};var B=YAHOO.lang,C=YAHOO.util.CustomEvent,A=YAHOO.util.Config;A.CONFIG_CHANGED_EVENT=&quot;configChanged&quot;;A.BOOLEAN_TYPE=&quot;boolean&quot;;A.prototype={owner:null,queueInProgress:false,config:null,initialConfig:null,eventQueue:null,configChangedEvent:null,init:function(D){this.owner=D;this.configChangedEvent=this.createEvent(A.CONFIG_CHANGED_EVENT);this.configChangedEvent.signature=C.LIST;this.queueInProgress=false;this.config={};this.initialConfig={};this.eventQueue=[];},checkBoolean:function(D){return(typeof D==A.BOOLEAN_TYPE);},checkNumber:function(D){return(!isNaN(D));},fireEvent:function(D,F){var E=this.config[D];if(E&amp;&amp;E.event){E.event.fire(F);}},addProperty:function(E,D){E=E.toLowerCase();this.config[E]=D;D.event=this.createEvent(E,{scope:this.owner});D.event.signature=C.LIST;D.key=E;if(D.handler){D.event.subscribe(D.handler,this.owner);}this.setProperty(E,D.value,true);if(!D.suppres
 sEvent){this.queueProperty(E,D.value);}},getConfig:function(){var D={},F,E;for(F in this.config){E=this.config[F];if(E&amp;&amp;E.event){D[F]=E.value;}}return D;},getProperty:function(D){var E=this.config[D.toLowerCase()];if(E&amp;&amp;E.event){return E.value;}else{return undefined;}},resetProperty:function(D){D=D.toLowerCase();var E=this.config[D];if(E&amp;&amp;E.event){if(this.initialConfig[D]&amp;&amp;!B.isUndefined(this.initialConfig[D])){this.setProperty(D,this.initialConfig[D]);return true;}}else{return false;}},setProperty:function(E,G,D){var F;E=E.toLowerCase();if(this.queueInProgress&amp;&amp;!D){this.queueProperty(E,G);return true;}else{F=this.config[E];if(F&amp;&amp;F.event){if(F.validator&amp;&amp;!F.validator(G)){return false;}else{F.value=G;if(!D){this.fireEvent(E,G);this.configChangedEvent.fire([E,G]);}return true;}}else{return false;}}},queueProperty:function(S,P){S=S.toLowerCase();var R=this.config[S],K=false,J,G,H,I,O,Q,F,M,N,D,L,T,E;if(R&amp;&amp;R.event){
 if(!B.isUndefined(P)&amp;&amp;R.validator&amp;&amp;!R.validator(P)){return false;}else{if(!B.isUndefined(P)){R.value=P;}else{P=R.value;}K=false;J=this.eventQueue.length;for(L=0;L&lt;J;L++){G=this.eventQueue[L];if(G){H=G[0];I=G[1];if(H==S){this.eventQueue[L]=null;this.eventQueue.push([S,(!B.isUndefined(P)?P:I)]);K=true;break;}}}if(!K&amp;&amp;!B.isUndefined(P)){this.eventQueue.push([S,P]);}}if(R.supercedes){O=R.supercedes.length;for(T=0;T&lt;O;T++){Q=R.supercedes[T];F=this.eventQueue.length;for(E=0;E&lt;F;E++){M=this.eventQueue[E];if(M){N=M[0];D=M[1];if(N==Q.toLowerCase()){this.eventQueue.push([N,D]);this.eventQueue[E]=null;break;}}}}}return true;}else{return false;}},refireEvent:function(D){D=D.toLowerCase();var E=this.config[D];if(E&amp;&amp;E.event&amp;&amp;!B.isUndefined(E.value)){if(this.queueInProgress){this.queueProperty(D);}else{this.fireEvent(D,E.value);}}},applyConfig:function(E,H){var G,D,F;if(H){F={};for(G in E){if(B.hasOwnProperty(E,G)){F[G.toLowerCase()]=E[G];}}
 this.initialConfig=F;}for(G in E){if(B.hasOwnProperty(E,G)){this.queueProperty(G,E[G]);}}},refresh:function(){var D;for(D in this.config){this.refireEvent(D);}},fireQueue:function(){var E,H,D,G,F;this.queueInProgress=true;for(E=0;E&lt;this.eventQueue.length;E++){H=this.eventQueue[E];if(H){D=H[0];G=H[1];F=this.config[D];F.value=G;this.fireEvent(D,G);}}this.queueInProgress=false;this.eventQueue=[];},subscribeToConfigEvent:function(E,F,H,D){var G=this.config[E.toLowerCase()];if(G&amp;&amp;G.event){if(!A.alreadySubscribed(G.event,F,H)){G.event.subscribe(F,H,D);}return true;}else{return false;}},unsubscribeFromConfigEvent:function(D,E,G){var F=this.config[D.toLowerCase()];if(F&amp;&amp;F.event){return F.event.unsubscribe(E,G);}else{return false;}},toString:function(){var D=&quot;Config&quot;;if(this.owner){D+=&quot; [&quot;+this.owner.toString()+&quot;]&quot;;}return D;},outputEventQueue:function(){var D=&quot;&quot;,G,E,F=this.eventQueue.length;for(E=0;E&lt;F;E++){G=this.eventQu
 eue[E];if(G){D+=G[0]+&quot;=&quot;+G[1]+&quot;, &quot;;}}return D;},destroy:function(){var E=this.config,D,F;for(D in E){if(B.hasOwnProperty(E,D)){F=E[D];F.event.unsubscribeAll();F.event=null;}}this.configChangedEvent.unsubscribeAll();this.configChangedEvent=null;this.owner=null;this.config=null;this.initialConfig=null;this.eventQueue=null;}};A.alreadySubscribed=function(E,H,I){var F=E.subscribers.length,D,G;if(F&gt;0){G=F-1;do{D=E.subscribers[G];if(D&amp;&amp;D.obj==I&amp;&amp;D.fn==H){return true;}}while(G--);}return false;};YAHOO.lang.augmentProto(A,YAHOO.util.EventProvider);}());YAHOO.widget.DateMath={DAY:&quot;D&quot;,WEEK:&quot;W&quot;,YEAR:&quot;Y&quot;,MONTH:&quot;M&quot;,ONE_DAY_MS:1000*60*60*24,add:function(A,D,C){var F=new Date(A.getTime());switch(D){case this.MONTH:var E=A.getMonth()+C;var B=0;if(E&lt;0){while(E&lt;0){E+=12;B-=1;}}else{if(E&gt;11){while(E&gt;11){E-=12;B+=1;}}}F.setMonth(E);F.setFullYear(A.getFullYear()+B);break;case this.DAY:F.setDate(A.getDate()
 +C);break;case this.YEAR:F.setFullYear(A.getFullYear()+C);break;case this.WEEK:F.setDate(A.getDate()+(C*7));break;}return F;},subtract:function(A,C,B){return this.add(A,C,(B*-1));},before:function(C,B){var A=B.getTime();if(C.getTime()&lt;A){return true;}else{return false;}},after:function(C,B){var A=B.getTime();if(C.getTime()&gt;A){return true;}else{return false;}},between:function(B,A,C){if(this.after(B,A)&amp;&amp;this.before(B,C)){return true;}else{return false;}},getJan1:function(A){return new Date(A,0,1);},getDayOffset:function(B,D){var C=this.getJan1(D);var A=Math.ceil((B.getTime()-C.getTime())/this.ONE_DAY_MS);return A;},getWeekNumber:function(C,F){C=this.clearTime(C);var E=new Date(C.getTime()+(4*this.ONE_DAY_MS)-((C.getDay())*this.ONE_DAY_MS));var B=new Date(E.getFullYear(),0,1);var A=((E.getTime()-B.getTime())/this.ONE_DAY_MS)-1;var D=Math.ceil((A)/7);return D;},isYearOverlapWeek:function(A){var C=false;var B=this.add(A,this.DAY,6);if(B.getFullYear()!=A.getFullYear
 ()){C=true;}return C;},isMonthOverlapWeek:function(A){var C=false;var B=this.add(A,this.DAY,6);if(B.getMonth()!=A.getMonth()){C=true;}return C;},findMonthStart:function(A){var B=new Date(A.getFullYear(),A.getMonth(),1);return B;},findMonthEnd:function(B){var D=this.findMonthStart(B);var C=this.add(D,this.MONTH,1);var A=this.subtract(C,this.DAY,1);return A;},clearTime:function(A){A.setHours(12,0,0,0);
-return A;}};YAHOO.widget.Calendar=function(C,A,B){this.init(C,A,B);};YAHOO.widget.Calendar.IMG_ROOT=null;YAHOO.widget.Calendar.DATE=&quot;D&quot;;YAHOO.widget.Calendar.MONTH_DAY=&quot;MD&quot;;YAHOO.widget.Calendar.WEEKDAY=&quot;WD&quot;;YAHOO.widget.Calendar.RANGE=&quot;R&quot;;YAHOO.widget.Calendar.MONTH=&quot;M&quot;;YAHOO.widget.Calendar.DISPLAY_DAYS=42;YAHOO.widget.Calendar.STOP_RENDER=&quot;S&quot;;YAHOO.widget.Calendar.SHORT=&quot;short&quot;;YAHOO.widget.Calendar.LONG=&quot;long&quot;;YAHOO.widget.Calendar.MEDIUM=&quot;medium&quot;;YAHOO.widget.Calendar.ONE_CHAR=&quot;1char&quot;;YAHOO.widget.Calendar._DEFAULT_CONFIG={PAGEDATE:{key:&quot;pagedate&quot;,value:null},SELECTED:{key:&quot;selected&quot;,value:null},TITLE:{key:&quot;title&quot;,value:&quot;&quot;},CLOSE:{key:&quot;close&quot;,value:false},IFRAME:{key:&quot;iframe&quot;,value:(YAHOO.env.ua.ie&amp;&amp;YAHOO.env.ua.ie&lt;=6)?true:false},MINDATE:{key:&quot;mindate&quot;,value:null},MAXDATE:{key:&quot;maxdate&
 quot;,value:null},MULTI_SELECT:{key:&quot;multi_select&quot;,value:false},START_WEEKDAY:{key:&quot;start_weekday&quot;,value:0},SHOW_WEEKDAYS:{key:&quot;show_weekdays&quot;,value:true},SHOW_WEEK_HEADER:{key:&quot;show_week_header&quot;,value:false},SHOW_WEEK_FOOTER:{key:&quot;show_week_footer&quot;,value:false},HIDE_BLANK_WEEKS:{key:&quot;hide_blank_weeks&quot;,value:false},NAV_ARROW_LEFT:{key:&quot;nav_arrow_left&quot;,value:null},NAV_ARROW_RIGHT:{key:&quot;nav_arrow_right&quot;,value:null},MONTHS_SHORT:{key:&quot;months_short&quot;,value:[&quot;Jan&quot;,&quot;Feb&quot;,&quot;Mar&quot;,&quot;Apr&quot;,&quot;May&quot;,&quot;Jun&quot;,&quot;Jul&quot;,&quot;Aug&quot;,&quot;Sep&quot;,&quot;Oct&quot;,&quot;Nov&quot;,&quot;Dec&quot;]},MONTHS_LONG:{key:&quot;months_long&quot;,value:[&quot;January&quot;,&quot;February&quot;,&quot;March&quot;,&quot;April&quot;,&quot;May&quot;,&quot;June&quot;,&quot;July&quot;,&quot;August&quot;,&quot;September&quot;,&quot;October&quot;,&quot;Novemb
 er&quot;,&quot;December&quot;]},WEEKDAYS_1CHAR:{key:&quot;weekdays_1char&quot;,value:[&quot;S&quot;,&quot;M&quot;,&quot;T&quot;,&quot;W&quot;,&quot;T&quot;,&quot;F&quot;,&quot;S&quot;]},WEEKDAYS_SHORT:{key:&quot;weekdays_short&quot;,value:[&quot;Su&quot;,&quot;Mo&quot;,&quot;Tu&quot;,&quot;We&quot;,&quot;Th&quot;,&quot;Fr&quot;,&quot;Sa&quot;]},WEEKDAYS_MEDIUM:{key:&quot;weekdays_medium&quot;,value:[&quot;Sun&quot;,&quot;Mon&quot;,&quot;Tue&quot;,&quot;Wed&quot;,&quot;Thu&quot;,&quot;Fri&quot;,&quot;Sat&quot;]},WEEKDAYS_LONG:{key:&quot;weekdays_long&quot;,value:[&quot;Sunday&quot;,&quot;Monday&quot;,&quot;Tuesday&quot;,&quot;Wednesday&quot;,&quot;Thursday&quot;,&quot;Friday&quot;,&quot;Saturday&quot;]},LOCALE_MONTHS:{key:&quot;locale_months&quot;,value:&quot;long&quot;},LOCALE_WEEKDAYS:{key:&quot;locale_weekdays&quot;,value:&quot;short&quot;},DATE_DELIMITER:{key:&quot;date_delimiter&quot;,value:&quot;,&quot;},DATE_FIELD_DELIMITER:{key:&quot;date_field_delimiter&quot;,value:&
 quot;/&quot;},DATE_RANGE_DELIMITER:{key:&quot;date_range_delimiter&quot;,value:&quot;-&quot;},MY_MONTH_POSITION:{key:&quot;my_month_position&quot;,value:1},MY_YEAR_POSITION:{key:&quot;my_year_position&quot;,value:2},MD_MONTH_POSITION:{key:&quot;md_month_position&quot;,value:1},MD_DAY_POSITION:{key:&quot;md_day_position&quot;,value:2},MDY_MONTH_POSITION:{key:&quot;mdy_month_position&quot;,value:1},MDY_DAY_POSITION:{key:&quot;mdy_day_position&quot;,value:2},MDY_YEAR_POSITION:{key:&quot;mdy_year_position&quot;,value:3},MY_LABEL_MONTH_POSITION:{key:&quot;my_label_month_position&quot;,value:1},MY_LABEL_YEAR_POSITION:{key:&quot;my_label_year_position&quot;,value:2},MY_LABEL_MONTH_SUFFIX:{key:&quot;my_label_month_suffix&quot;,value:&quot; &quot;},MY_LABEL_YEAR_SUFFIX:{key:&quot;my_label_year_suffix&quot;,value:&quot;&quot;}};YAHOO.widget.Calendar._EVENT_TYPES={BEFORE_SELECT:&quot;beforeSelect&quot;,SELECT:&quot;select&quot;,BEFORE_DESELECT:&quot;beforeDeselect&quot;,DESELECT:&quot;
 deselect&quot;,CHANGE_PAGE:&quot;changePage&quot;,BEFORE_RENDER:&quot;beforeRender&quot;,RENDER:&quot;render&quot;,RESET:&quot;reset&quot;,CLEAR:&quot;clear&quot;};YAHOO.widget.Calendar._STYLES={CSS_ROW_HEADER:&quot;calrowhead&quot;,CSS_ROW_FOOTER:&quot;calrowfoot&quot;,CSS_CELL:&quot;calcell&quot;,CSS_CELL_SELECTOR:&quot;selector&quot;,CSS_CELL_SELECTED:&quot;selected&quot;,CSS_CELL_SELECTABLE:&quot;selectable&quot;,CSS_CELL_RESTRICTED:&quot;restricted&quot;,CSS_CELL_TODAY:&quot;today&quot;,CSS_CELL_OOM:&quot;oom&quot;,CSS_CELL_OOB:&quot;previous&quot;,CSS_HEADER:&quot;calheader&quot;,CSS_HEADER_TEXT:&quot;calhead&quot;,CSS_BODY:&quot;calbody&quot;,CSS_WEEKDAY_CELL:&quot;calweekdaycell&quot;,CSS_WEEKDAY_ROW:&quot;calweekdayrow&quot;,CSS_FOOTER:&quot;calfoot&quot;,CSS_CALENDAR:&quot;yui-calendar&quot;,CSS_SINGLE:&quot;single&quot;,CSS_CONTAINER:&quot;yui-calcontainer&quot;,CSS_NAV_LEFT:&quot;calnavleft&quot;,CSS_NAV_RIGHT:&quot;calnavright&quot;,CSS_CLOSE:&quot;calclose&quot
 ;,CSS_CELL_TOP:&quot;calcelltop&quot;,CSS_CELL_LEFT:&quot;calcellleft&quot;,CSS_CELL_RIGHT:&quot;calcellright&quot;,CSS_CELL_BOTTOM:&quot;calcellbottom&quot;,CSS_CELL_HOVER:&quot;calcellhover&quot;,CSS_CELL_HIGHLIGHT1:&quot;highlight1&quot;,CSS_CELL_HIGHLIGHT2:&quot;highlight2&quot;,CSS_CELL_HIGHLIGHT3:&quot;highlight3&quot;,CSS_CELL_HIGHLIGHT4:&quot;highlight4&quot;};YAHOO.widget.Calendar.prototype={Config:null,parent:null,index:-1,cells:null,cellDates:null,id:null,oDomContainer:null,today:null,renderStack:null,_renderStack:null,_selectedDates:null,domEventMap:null};YAHOO.widget.Calendar.prototype.init=function(C,A,B){this.initEvents();this.today=new Date();YAHOO.widget.DateMath.clearTime(this.today);this.id=C;this.oDomContainer=document.getElementById(A);this.cfg=new YAHOO.util.Config(this);this.Options={};this.Locale={};this.initStyles();YAHOO.util.Dom.addClass(this.oDomContainer,this.Style.CSS_CONTAINER);YAHOO.util.Dom.addClass(this.oDomContainer,this.Style.CSS_SINGLE);t
 his.cellDates=[];this.cells=[];this.renderStack=[];this._renderStack=[];this.setupConfig();if(B){this.cfg.applyConfig(B,true);}this.cfg.fireQueue();};YAHOO.widget.Calendar.prototype.configIframe=function(C,B,D){var A=B[0];if(!this.parent){if(YAHOO.util.Dom.inDocument(this.oDomContainer)){if(A){var E=YAHOO.util.Dom.getStyle(this.oDomContainer,&quot;position&quot;);if(E==&quot;absolute&quot;||E==&quot;relative&quot;){if(!YAHOO.util.Dom.inDocument(this.iframe)){this.iframe=document.createElement(&quot;iframe&quot;);this.iframe.src=&quot;javascript:false;&quot;;YAHOO.util.Dom.setStyle(this.iframe,&quot;opacity&quot;,&quot;0&quot;);if(YAHOO.env.ua.ie&amp;&amp;YAHOO.env.ua.ie&lt;=6){YAHOO.util.Dom.addClass(this.iframe,&quot;fixedsize&quot;);}this.oDomContainer.insertBefore(this.iframe,this.oDomContainer.firstChild);}}}else{if(this.iframe){if(this.iframe.parentNode){this.iframe.parentNode.removeChild(this.iframe);}this.iframe=null;}}}}};YAHOO.widget.Calendar.prototype.configTitle=f
 unction(B,A,C){var E=A[0],F;if(E){this.createTitleBar(E);}else{var D=this.cfg.getProperty(YAHOO.widget.Calendar._DEFAULT_CONFIG.CLOSE.key);if(!D){this.removeTitleBar();}else{this.createTitleBar(&quot;&amp;#160;&quot;);}}};YAHOO.widget.Calendar.prototype.configClose=function(B,A,C){var E=A[0],D=this.cfg.getProperty(YAHOO.widget.Calendar._DEFAULT_CONFIG.TITLE.key);if(E){if(!D){this.createTitleBar(&quot;&amp;#160;&quot;);}this.createCloseButton();}else{this.removeCloseButton();if(!D){this.removeTitleBar();}}};YAHOO.widget.Calendar.prototype.initEvents=function(){var A=YAHOO.widget.Calendar._EVENT_TYPES;this.beforeSelectEvent=new YAHOO.util.CustomEvent(A.BEFORE_SELECT);this.selectEvent=new YAHOO.util.CustomEvent(A.SELECT);
-this.beforeDeselectEvent=new YAHOO.util.CustomEvent(A.BEFORE_DESELECT);this.deselectEvent=new YAHOO.util.CustomEvent(A.DESELECT);this.changePageEvent=new YAHOO.util.CustomEvent(A.CHANGE_PAGE);this.beforeRenderEvent=new YAHOO.util.CustomEvent(A.BEFORE_RENDER);this.renderEvent=new YAHOO.util.CustomEvent(A.RENDER);this.resetEvent=new YAHOO.util.CustomEvent(A.RESET);this.clearEvent=new YAHOO.util.CustomEvent(A.CLEAR);this.beforeSelectEvent.subscribe(this.onBeforeSelect,this,true);this.selectEvent.subscribe(this.onSelect,this,true);this.beforeDeselectEvent.subscribe(this.onBeforeDeselect,this,true);this.deselectEvent.subscribe(this.onDeselect,this,true);this.changePageEvent.subscribe(this.onChangePage,this,true);this.renderEvent.subscribe(this.onRender,this,true);this.resetEvent.subscribe(this.onReset,this,true);this.clearEvent.subscribe(this.onClear,this,true);};YAHOO.widget.Calendar.prototype.doSelectCell=function(G,A){var L,F,I,C;var H=YAHOO.util.Event.getTarget(G);var B=H.tag
 Name.toLowerCase();var E=false;while(B!=&quot;td&quot;&amp;&amp;!YAHOO.util.Dom.hasClass(H,A.Style.CSS_CELL_SELECTABLE)){if(!E&amp;&amp;B==&quot;a&quot;&amp;&amp;YAHOO.util.Dom.hasClass(H,A.Style.CSS_CELL_SELECTOR)){E=true;}H=H.parentNode;B=H.tagName.toLowerCase();if(B==&quot;html&quot;){return ;}}if(E){YAHOO.util.Event.preventDefault(G);}L=H;if(YAHOO.util.Dom.hasClass(L,A.Style.CSS_CELL_SELECTABLE)){F=L.id.split(&quot;cell&quot;)[1];I=A.cellDates[F];C=new Date(I[0],I[1]-1,I[2]);var K;if(A.Options.MULTI_SELECT){K=L.getElementsByTagName(&quot;a&quot;)[0];if(K){K.blur();}var D=A.cellDates[F];var J=A._indexOfSelectedFieldArray(D);if(J&gt;-1){A.deselectCell(F);}else{A.selectCell(F);}}else{K=L.getElementsByTagName(&quot;a&quot;)[0];if(K){K.blur();}A.selectCell(F);}}};YAHOO.widget.Calendar.prototype.doCellMouseOver=function(C,B){var A;if(C){A=YAHOO.util.Event.getTarget(C);}else{A=this;}while(A.tagName.toLowerCase()!=&quot;td&quot;){A=A.parentNode;if(A.tagName.toLowerCase()==&quot;
 html&quot;){return ;}}if(YAHOO.util.Dom.hasClass(A,B.Style.CSS_CELL_SELECTABLE)){YAHOO.util.Dom.addClass(A,B.Style.CSS_CELL_HOVER);}};YAHOO.widget.Calendar.prototype.doCellMouseOut=function(C,B){var A;if(C){A=YAHOO.util.Event.getTarget(C);}else{A=this;}while(A.tagName.toLowerCase()!=&quot;td&quot;){A=A.parentNode;if(A.tagName.toLowerCase()==&quot;html&quot;){return ;}}if(YAHOO.util.Dom.hasClass(A,B.Style.CSS_CELL_SELECTABLE)){YAHOO.util.Dom.removeClass(A,B.Style.CSS_CELL_HOVER);}};YAHOO.widget.Calendar.prototype.setupConfig=function(){var A=YAHOO.widget.Calendar._DEFAULT_CONFIG;this.cfg.addProperty(A.PAGEDATE.key,{value:new Date(),handler:this.configPageDate});this.cfg.addProperty(A.SELECTED.key,{value:[],handler:this.configSelected});this.cfg.addProperty(A.TITLE.key,{value:A.TITLE.value,handler:this.configTitle});this.cfg.addProperty(A.CLOSE.key,{value:A.CLOSE.value,handler:this.configClose});this.cfg.addProperty(A.IFRAME.key,{value:A.IFRAME.value,handler:this.configIframe,
 validator:this.cfg.checkBoolean});this.cfg.addProperty(A.MINDATE.key,{value:A.MINDATE.value,handler:this.configMinDate});this.cfg.addProperty(A.MAXDATE.key,{value:A.MAXDATE.value,handler:this.configMaxDate});this.cfg.addProperty(A.MULTI_SELECT.key,{value:A.MULTI_SELECT.value,handler:this.configOptions,validator:this.cfg.checkBoolean});this.cfg.addProperty(A.START_WEEKDAY.key,{value:A.START_WEEKDAY.value,handler:this.configOptions,validator:this.cfg.checkNumber});this.cfg.addProperty(A.SHOW_WEEKDAYS.key,{value:A.SHOW_WEEKDAYS.value,handler:this.configOptions,validator:this.cfg.checkBoolean});this.cfg.addProperty(A.SHOW_WEEK_HEADER.key,{value:A.SHOW_WEEK_HEADER.value,handler:this.configOptions,validator:this.cfg.checkBoolean});this.cfg.addProperty(A.SHOW_WEEK_FOOTER.key,{value:A.SHOW_WEEK_FOOTER.value,handler:this.configOptions,validator:this.cfg.checkBoolean});this.cfg.addProperty(A.HIDE_BLANK_WEEKS.key,{value:A.HIDE_BLANK_WEEKS.value,handler:this.configOptions,validator:this
 .cfg.checkBoolean});this.cfg.addProperty(A.NAV_ARROW_LEFT.key,{value:A.NAV_ARROW_LEFT.value,handler:this.configOptions});this.cfg.addProperty(A.NAV_ARROW_RIGHT.key,{value:A.NAV_ARROW_RIGHT.value,handler:this.configOptions});this.cfg.addProperty(A.MONTHS_SHORT.key,{value:A.MONTHS_SHORT.value,handler:this.configLocale});this.cfg.addProperty(A.MONTHS_LONG.key,{value:A.MONTHS_LONG.value,handler:this.configLocale});this.cfg.addProperty(A.WEEKDAYS_1CHAR.key,{value:A.WEEKDAYS_1CHAR.value,handler:this.configLocale});this.cfg.addProperty(A.WEEKDAYS_SHORT.key,{value:A.WEEKDAYS_SHORT.value,handler:this.configLocale});this.cfg.addProperty(A.WEEKDAYS_MEDIUM.key,{value:A.WEEKDAYS_MEDIUM.value,handler:this.configLocale});this.cfg.addProperty(A.WEEKDAYS_LONG.key,{value:A.WEEKDAYS_LONG.value,handler:this.configLocale});var B=function(){this.cfg.refireEvent(A.LOCALE_MONTHS.key);this.cfg.refireEvent(A.LOCALE_WEEKDAYS.key);};this.cfg.subscribeToConfigEvent(A.START_WEEKDAY.key,B,this,true);this.
 cfg.subscribeToConfigEvent(A.MONTHS_SHORT.key,B,this,true);this.cfg.subscribeToConfigEvent(A.MONTHS_LONG.key,B,this,true);this.cfg.subscribeToConfigEvent(A.WEEKDAYS_1CHAR.key,B,this,true);this.cfg.subscribeToConfigEvent(A.WEEKDAYS_SHORT.key,B,this,true);this.cfg.subscribeToConfigEvent(A.WEEKDAYS_MEDIUM.key,B,this,true);this.cfg.subscribeToConfigEvent(A.WEEKDAYS_LONG.key,B,this,true);this.cfg.addProperty(A.LOCALE_MONTHS.key,{value:A.LOCALE_MONTHS.value,handler:this.configLocaleValues});this.cfg.addProperty(A.LOCALE_WEEKDAYS.key,{value:A.LOCALE_WEEKDAYS.value,handler:this.configLocaleValues});this.cfg.addProperty(A.DATE_DELIMITER.key,{value:A.DATE_DELIMITER.value,handler:this.configLocale});this.cfg.addProperty(A.DATE_FIELD_DELIMITER.key,{value:A.DATE_FIELD_DELIMITER.value,handler:this.configLocale});this.cfg.addProperty(A.DATE_RANGE_DELIMITER.key,{value:A.DATE_RANGE_DELIMITER.value,handler:this.configLocale});this.cfg.addProperty(A.MY_MONTH_POSITION.key,{value:A.MY_MONTH_POSI
 TION.value,handler:this.configLocale,validator:this.cfg.checkNumber});this.cfg.addProperty(A.MY_YEAR_POSITION.key,{value:A.MY_YEAR_POSITION.value,handler:this.configLocale,validator:this.cfg.checkNumber});
-this.cfg.addProperty(A.MD_MONTH_POSITION.key,{value:A.MD_MONTH_POSITION.value,handler:this.configLocale,validator:this.cfg.checkNumber});this.cfg.addProperty(A.MD_DAY_POSITION.key,{value:A.MD_DAY_POSITION.value,handler:this.configLocale,validator:this.cfg.checkNumber});this.cfg.addProperty(A.MDY_MONTH_POSITION.key,{value:A.MDY_MONTH_POSITION.value,handler:this.configLocale,validator:this.cfg.checkNumber});this.cfg.addProperty(A.MDY_DAY_POSITION.key,{value:A.MDY_DAY_POSITION.value,handler:this.configLocale,validator:this.cfg.checkNumber});this.cfg.addProperty(A.MDY_YEAR_POSITION.key,{value:A.MDY_YEAR_POSITION.value,handler:this.configLocale,validator:this.cfg.checkNumber});this.cfg.addProperty(A.MY_LABEL_MONTH_POSITION.key,{value:A.MY_LABEL_MONTH_POSITION.value,handler:this.configLocale,validator:this.cfg.checkNumber});this.cfg.addProperty(A.MY_LABEL_YEAR_POSITION.key,{value:A.MY_LABEL_YEAR_POSITION.value,handler:this.configLocale,validator:this.cfg.checkNumber});this.cfg.add
 Property(A.MY_LABEL_MONTH_SUFFIX.key,{value:A.MY_LABEL_MONTH_SUFFIX.value,handler:this.configLocale});this.cfg.addProperty(A.MY_LABEL_YEAR_SUFFIX.key,{value:A.MY_LABEL_YEAR_SUFFIX.value,handler:this.configLocale});};YAHOO.widget.Calendar.prototype.configPageDate=function(B,A,C){this.cfg.setProperty(YAHOO.widget.Calendar._DEFAULT_CONFIG.PAGEDATE.key,this._parsePageDate(A[0]),true);};YAHOO.widget.Calendar.prototype.configMinDate=function(B,A,C){var D=A[0];if(YAHOO.lang.isString(D)){D=this._parseDate(D);this.cfg.setProperty(YAHOO.widget.Calendar._DEFAULT_CONFIG.MINDATE.key,new Date(D[0],(D[1]-1),D[2]));}};YAHOO.widget.Calendar.prototype.configMaxDate=function(B,A,C){var D=A[0];if(YAHOO.lang.isString(D)){D=this._parseDate(D);this.cfg.setProperty(YAHOO.widget.Calendar._DEFAULT_CONFIG.MAXDATE.key,new Date(D[0],(D[1]-1),D[2]));}};YAHOO.widget.Calendar.prototype.configSelected=function(C,A,E){var B=A[0];var D=YAHOO.widget.Calendar._DEFAULT_CONFIG.SELECTED.key;if(B){if(YAHOO.lang.isS
 tring(B)){this.cfg.setProperty(D,this._parseDates(B),true);}}if(!this._selectedDates){this._selectedDates=this.cfg.getProperty(D);}};YAHOO.widget.Calendar.prototype.configOptions=function(B,A,C){this.Options[B.toUpperCase()]=A[0];};YAHOO.widget.Calendar.prototype.configLocale=function(C,B,D){var A=YAHOO.widget.Calendar._DEFAULT_CONFIG;this.Locale[C.toUpperCase()]=B[0];this.cfg.refireEvent(A.LOCALE_MONTHS.key);this.cfg.refireEvent(A.LOCALE_WEEKDAYS.key);};YAHOO.widget.Calendar.prototype.configLocaleValues=function(D,C,E){var B=YAHOO.widget.Calendar._DEFAULT_CONFIG;D=D.toLowerCase();var G=C[0];switch(D){case B.LOCALE_MONTHS.key:switch(G){case YAHOO.widget.Calendar.SHORT:this.Locale.LOCALE_MONTHS=this.cfg.getProperty(B.MONTHS_SHORT.key).concat();break;case YAHOO.widget.Calendar.LONG:this.Locale.LOCALE_MONTHS=this.cfg.getProperty(B.MONTHS_LONG.key).concat();break;}break;case B.LOCALE_WEEKDAYS.key:switch(G){case YAHOO.widget.Calendar.ONE_CHAR:this.Locale.LOCALE_WEEKDAYS=this.cfg.
 getProperty(B.WEEKDAYS_1CHAR.key).concat();break;case YAHOO.widget.Calendar.SHORT:this.Locale.LOCALE_WEEKDAYS=this.cfg.getProperty(B.WEEKDAYS_SHORT.key).concat();break;case YAHOO.widget.Calendar.MEDIUM:this.Locale.LOCALE_WEEKDAYS=this.cfg.getProperty(B.WEEKDAYS_MEDIUM.key).concat();break;case YAHOO.widget.Calendar.LONG:this.Locale.LOCALE_WEEKDAYS=this.cfg.getProperty(B.WEEKDAYS_LONG.key).concat();break;}var F=this.cfg.getProperty(B.START_WEEKDAY.key);if(F&gt;0){for(var A=0;A&lt;F;++A){this.Locale.LOCALE_WEEKDAYS.push(this.Locale.LOCALE_WEEKDAYS.shift());}}break;}};YAHOO.widget.Calendar.prototype.initStyles=function(){var A=YAHOO.widget.Calendar._STYLES;this.Style={CSS_ROW_HEADER:A.CSS_ROW_HEADER,CSS_ROW_FOOTER:A.CSS_ROW_FOOTER,CSS_CELL:A.CSS_CELL,CSS_CELL_SELECTOR:A.CSS_CELL_SELECTOR,CSS_CELL_SELECTED:A.CSS_CELL_SELECTED,CSS_CELL_SELECTABLE:A.CSS_CELL_SELECTABLE,CSS_CELL_RESTRICTED:A.CSS_CELL_RESTRICTED,CSS_CELL_TODAY:A.CSS_CELL_TODAY,CSS_CELL_OOM:A.CSS_CELL_OOM,CSS_CELL_OOB
 :A.CSS_CELL_OOB,CSS_HEADER:A.CSS_HEADER,CSS_HEADER_TEXT:A.CSS_HEADER_TEXT,CSS_BODY:A.CSS_BODY,CSS_WEEKDAY_CELL:A.CSS_WEEKDAY_CELL,CSS_WEEKDAY_ROW:A.CSS_WEEKDAY_ROW,CSS_FOOTER:A.CSS_FOOTER,CSS_CALENDAR:A.CSS_CALENDAR,CSS_SINGLE:A.CSS_SINGLE,CSS_CONTAINER:A.CSS_CONTAINER,CSS_NAV_LEFT:A.CSS_NAV_LEFT,CSS_NAV_RIGHT:A.CSS_NAV_RIGHT,CSS_CLOSE:A.CSS_CLOSE,CSS_CELL_TOP:A.CSS_CELL_TOP,CSS_CELL_LEFT:A.CSS_CELL_LEFT,CSS_CELL_RIGHT:A.CSS_CELL_RIGHT,CSS_CELL_BOTTOM:A.CSS_CELL_BOTTOM,CSS_CELL_HOVER:A.CSS_CELL_HOVER,CSS_CELL_HIGHLIGHT1:A.CSS_CELL_HIGHLIGHT1,CSS_CELL_HIGHLIGHT2:A.CSS_CELL_HIGHLIGHT2,CSS_CELL_HIGHLIGHT3:A.CSS_CELL_HIGHLIGHT3,CSS_CELL_HIGHLIGHT4:A.CSS_CELL_HIGHLIGHT4};};YAHOO.widget.Calendar.prototype.buildMonthLabel=function(){var A=this.cfg.getProperty(YAHOO.widget.Calendar._DEFAULT_CONFIG.PAGEDATE.key);var C=this.Locale.LOCALE_MONTHS[A.getMonth()]+this.Locale.MY_LABEL_MONTH_SUFFIX;var B=A.getFullYear()+this.Locale.MY_LABEL_YEAR_SUFFIX;if(this.Locale.MY_LABEL_MONTH_POSITION=
 =2||this.Locale.MY_LABEL_YEAR_POSITION==1){return B+C;}else{return C+B;}};YAHOO.widget.Calendar.prototype.buildDayLabel=function(A){return A.getDate();};YAHOO.widget.Calendar.prototype.createTitleBar=function(A){var B=YAHOO.util.Dom.getElementsByClassName(YAHOO.widget.CalendarGroup.CSS_2UPTITLE,&quot;div&quot;,this.oDomContainer)[0]||document.createElement(&quot;div&quot;);B.className=YAHOO.widget.CalendarGroup.CSS_2UPTITLE;B.innerHTML=A;this.oDomContainer.insertBefore(B,this.oDomContainer.firstChild);YAHOO.util.Dom.addClass(this.oDomContainer,&quot;withtitle&quot;);return B;};YAHOO.widget.Calendar.prototype.removeTitleBar=function(){var A=YAHOO.util.Dom.getElementsByClassName(YAHOO.widget.CalendarGroup.CSS_2UPTITLE,&quot;div&quot;,this.oDomContainer)[0]||null;if(A){YAHOO.util.Event.purgeElement(A);this.oDomContainer.removeChild(A);}YAHOO.util.Dom.removeClass(this.oDomContainer,&quot;withtitle&quot;);};YAHOO.widget.Calendar.prototype.createCloseButton=function(){var D=YAHOO.
 util.Dom,A=YAHOO.util.Event,C=YAHOO.widget.CalendarGroup.CSS_2UPCLOSE,F=&quot;us/my/bn/x_d.gif&quot;;var E=D.getElementsByClassName(&quot;link-close&quot;,&quot;a&quot;,this.oDomContainer)[0];
-if(!E){E=document.createElement(&quot;a&quot;);A.addListener(E,&quot;click&quot;,function(H,G){G.hide();A.preventDefault(H);},this);}E.href=&quot;#&quot;;E.className=&quot;link-close&quot;;if(YAHOO.widget.Calendar.IMG_ROOT!==null){var B=D.getElementsByClassName(C,&quot;img&quot;,E)[0]||document.createElement(&quot;img&quot;);B.src=YAHOO.widget.Calendar.IMG_ROOT+F;B.className=C;E.appendChild(B);}else{E.innerHTML=&quot;&lt;span class=\&quot;&quot;+C+&quot; &quot;+this.Style.CSS_CLOSE+&quot;\&quot;&gt;&lt;/span&gt;&quot;;}this.oDomContainer.appendChild(E);return E;};YAHOO.widget.Calendar.prototype.removeCloseButton=function(){var A=YAHOO.util.Dom.getElementsByClassName(&quot;link-close&quot;,&quot;a&quot;,this.oDomContainer)[0]||null;if(A){YAHOO.util.Event.purgeElement(A);this.oDomContainer.removeChild(A);}};YAHOO.widget.Calendar.prototype.renderHeader=function(E){var H=7;var F=&quot;us/tr/callt.gif&quot;;var G=&quot;us/tr/calrt.gif&quot;;var L=YAHOO.widget.Calendar._DEFAULT_CO
 NFIG;if(this.cfg.getProperty(L.SHOW_WEEK_HEADER.key)){H+=1;}if(this.cfg.getProperty(L.SHOW_WEEK_FOOTER.key)){H+=1;}E[E.length]=&quot;&lt;thead&gt;&quot;;E[E.length]=&quot;&lt;tr&gt;&quot;;E[E.length]=&quot;&lt;th colspan=\&quot;&quot;+H+&quot;\&quot; class=\&quot;&quot;+this.Style.CSS_HEADER_TEXT+&quot;\&quot;&gt;&quot;;E[E.length]=&quot;&lt;div class=\&quot;&quot;+this.Style.CSS_HEADER+&quot;\&quot;&gt;&quot;;var J,K=false;if(this.parent){if(this.index===0){J=true;}if(this.index==(this.parent.cfg.getProperty(&quot;pages&quot;)-1)){K=true;}}else{J=true;K=true;}var B=this.parent||this;if(J){var A=this.cfg.getProperty(L.NAV_ARROW_LEFT.key);if(A===null&amp;&amp;YAHOO.widget.Calendar.IMG_ROOT!==null){A=YAHOO.widget.Calendar.IMG_ROOT+F;}var C=(A===null)?&quot;&quot;:&quot; style=\&quot;background-image:url(&quot;+A+&quot;)\&quot;&quot;;E[E.length]=&quot;&lt;a class=\&quot;&quot;+this.Style.CSS_NAV_LEFT+&quot;\&quot;&quot;+C+&quot; &gt;&amp;#160;&lt;/a&gt;&quot;;}E[E.length]=this.
 buildMonthLabel();if(K){var D=this.cfg.getProperty(L.NAV_ARROW_RIGHT.key);if(D===null&amp;&amp;YAHOO.widget.Calendar.IMG_ROOT!==null){D=YAHOO.widget.Calendar.IMG_ROOT+G;}var I=(D===null)?&quot;&quot;:&quot; style=\&quot;background-image:url(&quot;+D+&quot;)\&quot;&quot;;E[E.length]=&quot;&lt;a class=\&quot;&quot;+this.Style.CSS_NAV_RIGHT+&quot;\&quot;&quot;+I+&quot; &gt;&amp;#160;&lt;/a&gt;&quot;;}E[E.length]=&quot;&lt;/div&gt;\n&lt;/th&gt;\n&lt;/tr&gt;&quot;;if(this.cfg.getProperty(L.SHOW_WEEKDAYS.key)){E=this.buildWeekdays(E);}E[E.length]=&quot;&lt;/thead&gt;&quot;;return E;};YAHOO.widget.Calendar.prototype.buildWeekdays=function(C){var A=YAHOO.widget.Calendar._DEFAULT_CONFIG;C[C.length]=&quot;&lt;tr class=\&quot;&quot;+this.Style.CSS_WEEKDAY_ROW+&quot;\&quot;&gt;&quot;;if(this.cfg.getProperty(A.SHOW_WEEK_HEADER.key)){C[C.length]=&quot;&lt;th&gt;&amp;#160;&lt;/th&gt;&quot;;}for(var B=0;B&lt;this.Locale.LOCALE_WEEKDAYS.length;++B){C[C.length]=&quot;&lt;th class=\&quot;calwe
 ekdaycell\&quot;&gt;&quot;+this.Locale.LOCALE_WEEKDAYS[B]+&quot;&lt;/th&gt;&quot;;}if(this.cfg.getProperty(A.SHOW_WEEK_FOOTER.key)){C[C.length]=&quot;&lt;th&gt;&amp;#160;&lt;/th&gt;&quot;;}C[C.length]=&quot;&lt;/tr&gt;&quot;;return C;};YAHOO.widget.Calendar.prototype.renderBody=function(c,a){var m=YAHOO.widget.Calendar._DEFAULT_CONFIG;var AC=this.cfg.getProperty(m.START_WEEKDAY.key);this.preMonthDays=c.getDay();if(AC&gt;0){this.preMonthDays-=AC;}if(this.preMonthDays&lt;0){this.preMonthDays+=7;}this.monthDays=YAHOO.widget.DateMath.findMonthEnd(c).getDate();this.postMonthDays=YAHOO.widget.Calendar.DISPLAY_DAYS-this.preMonthDays-this.monthDays;c=YAHOO.widget.DateMath.subtract(c,YAHOO.widget.DateMath.DAY,this.preMonthDays);var Q,H;var G=&quot;w&quot;;var W=&quot;_cell&quot;;var U=&quot;wd&quot;;var k=&quot;d&quot;;var I;var h;var O=this.today.getFullYear();var j=this.today.getMonth();var D=this.today.getDate();var q=this.cfg.getProperty(m.PAGEDATE.key);var C=this.cfg.getProperty
 (m.HIDE_BLANK_WEEKS.key);var Z=this.cfg.getProperty(m.SHOW_WEEK_FOOTER.key);var T=this.cfg.getProperty(m.SHOW_WEEK_HEADER.key);var M=this.cfg.getProperty(m.MINDATE.key);var S=this.cfg.getProperty(m.MAXDATE.key);if(M){M=YAHOO.widget.DateMath.clearTime(M);}if(S){S=YAHOO.widget.DateMath.clearTime(S);}a[a.length]=&quot;&lt;tbody class=\&quot;m&quot;+(q.getMonth()+1)+&quot; &quot;+this.Style.CSS_BODY+&quot;\&quot;&gt;&quot;;var AA=0;var J=document.createElement(&quot;div&quot;);var b=document.createElement(&quot;td&quot;);J.appendChild(b);var z=new Date(q.getFullYear(),0,1);var o=this.parent||this;for(var u=0;u&lt;6;u++){Q=YAHOO.widget.DateMath.getWeekNumber(c,q.getFullYear(),AC);H=G+Q;if(u!==0&amp;&amp;C===true&amp;&amp;c.getMonth()!=q.getMonth()){break;}else{a[a.length]=&quot;&lt;tr class=\&quot;&quot;+H+&quot;\&quot;&gt;&quot;;if(T){a=this.renderRowHeader(Q,a);}for(var AB=0;AB&lt;7;AB++){I=[];h=null;this.clearElement(b);b.className=this.Style.CSS_CELL;b.id=this.id+W+AA;if(c.ge
 tDate()==D&amp;&amp;c.getMonth()==j&amp;&amp;c.getFullYear()==O){I[I.length]=o.renderCellStyleToday;}var R=[c.getFullYear(),c.getMonth()+1,c.getDate()];this.cellDates[this.cellDates.length]=R;if(c.getMonth()!=q.getMonth()){I[I.length]=o.renderCellNotThisMonth;}else{YAHOO.util.Dom.addClass(b,U+c.getDay());YAHOO.util.Dom.addClass(b,k+c.getDate());for(var t=0;t&lt;this.renderStack.length;++t){var l=this.renderStack[t];var AD=l[0];var B;var V;var F;switch(AD){case YAHOO.widget.Calendar.DATE:B=l[1][1];V=l[1][2];F=l[1][0];if(c.getMonth()+1==B&amp;&amp;c.getDate()==V&amp;&amp;c.getFullYear()==F){h=l[2];this.renderStack.splice(t,1);}break;case YAHOO.widget.Calendar.MONTH_DAY:B=l[1][0];V=l[1][1];if(c.getMonth()+1==B&amp;&amp;c.getDate()==V){h=l[2];this.renderStack.splice(t,1);}break;case YAHOO.widget.Calendar.RANGE:var Y=l[1][0];var X=l[1][1];var e=Y[1];var L=Y[2];var P=Y[0];var y=new Date(P,e-1,L);var E=X[1];var g=X[2];var A=X[0];var w=new Date(A,E-1,g);if(c.getTime()&gt;=y.getTime(
 )&amp;&amp;c.getTime()&lt;=w.getTime()){h=l[2];if(c.getTime()==w.getTime()){this.renderStack.splice(t,1);}}break;case YAHOO.widget.Calendar.WEEKDAY:var K=l[1][0];if(c.getDay()+1==K){h=l[2];}break;case YAHOO.widget.Calendar.MONTH:B=l[1][0];if(c.getMonth()+1==B){h=l[2];}break;}if(h){I[I.length]=h;}}}if(this._indexOfSelectedFieldArray(R)&gt;-1){I[I.length]=o.renderCellStyleSelected;}if((M&amp;&amp;(c.getTime()&lt;M.getTime()))||(S&amp;&amp;(c.getTime()&gt;S.getTime()))){I[I.length]=o.renderOutOfBoundsDate;}else{I[I.length]=o.styleCellDefault;I[I.length]=o.renderCellDefault;}for(var n=0;n&lt;I.length;++n){if(I[n].call(o,c,b)==YAHOO.widget.Calendar.STOP_RENDER){break;}}c.setTime(c.getTime()+YAHOO.widget.DateMath.ONE_DAY_MS);if(AA&gt;=0&amp;&amp;AA&lt;=6){YAHOO.util.Dom.addClass(b,this.Style.CSS_CELL_TOP);}if((AA%7)===0){YAHOO.util.Dom.addClass(b,this.Style.CSS_CELL_LEFT);}if(((AA+1)%7)===0){YAHOO.util.Dom.addClass(b,this.Style.CSS_CELL_RIGHT);}var f=this.postMonthDays;if(C&amp;&a
 mp;f&gt;=7){var N=Math.floor(f/7);for(var v=0;
-v&lt;N;++v){f-=7;}}if(AA&gt;=((this.preMonthDays+f+this.monthDays)-7)){YAHOO.util.Dom.addClass(b,this.Style.CSS_CELL_BOTTOM);}a[a.length]=J.innerHTML;AA++;}if(Z){a=this.renderRowFooter(Q,a);}a[a.length]=&quot;&lt;/tr&gt;&quot;;}}a[a.length]=&quot;&lt;/tbody&gt;&quot;;return a;};YAHOO.widget.Calendar.prototype.renderFooter=function(A){return A;};YAHOO.widget.Calendar.prototype.render=function(){this.beforeRenderEvent.fire();var A=YAHOO.widget.Calendar._DEFAULT_CONFIG;var C=YAHOO.widget.DateMath.findMonthStart(this.cfg.getProperty(A.PAGEDATE.key));this.resetRenderers();this.cellDates.length=0;YAHOO.util.Event.purgeElement(this.oDomContainer,true);var B=[];B[B.length]=&quot;&lt;table cellSpacing=\&quot;0\&quot; class=\&quot;&quot;+this.Style.CSS_CALENDAR+&quot; y&quot;+C.getFullYear()+&quot;\&quot; id=\&quot;&quot;+this.id+&quot;\&quot;&gt;&quot;;B=this.renderHeader(B);B=this.renderBody(C,B);B=this.renderFooter(B);B[B.length]=&quot;&lt;/table&gt;&quot;;this.oDomContainer.innerH
 TML=B.join(&quot;\n&quot;);this.applyListeners();this.cells=this.oDomContainer.getElementsByTagName(&quot;td&quot;);this.cfg.refireEvent(A.TITLE.key);this.cfg.refireEvent(A.CLOSE.key);this.cfg.refireEvent(A.IFRAME.key);this.renderEvent.fire();};YAHOO.widget.Calendar.prototype.applyListeners=function(){var K=this.oDomContainer;var B=this.parent||this;var G=&quot;a&quot;;var D=&quot;mousedown&quot;;var H=YAHOO.util.Dom.getElementsByClassName(this.Style.CSS_NAV_LEFT,G,K);var C=YAHOO.util.Dom.getElementsByClassName(this.Style.CSS_NAV_RIGHT,G,K);if(H&amp;&amp;H.length&gt;0){this.linkLeft=H[0];YAHOO.util.Event.addListener(this.linkLeft,D,B.previousMonth,B,true);}if(C&amp;&amp;C.length&gt;0){this.linkRight=C[0];YAHOO.util.Event.addListener(this.linkRight,D,B.nextMonth,B,true);}if(this.domEventMap){var E,A;for(var M in this.domEventMap){if(YAHOO.lang.hasOwnProperty(this.domEventMap,M)){var I=this.domEventMap[M];if(!(I instanceof Array)){I=[I];}for(var F=0;F&lt;I.length;F++){var L=I[
 F];A=YAHOO.util.Dom.getElementsByClassName(M,L.tag,this.oDomContainer);for(var J=0;J&lt;A.length;J++){E=A[J];YAHOO.util.Event.addListener(E,L.event,L.handler,L.scope,L.correct);}}}}}YAHOO.util.Event.addListener(this.oDomContainer,&quot;click&quot;,this.doSelectCell,this);YAHOO.util.Event.addListener(this.oDomContainer,&quot;mouseover&quot;,this.doCellMouseOver,this);YAHOO.util.Event.addListener(this.oDomContainer,&quot;mouseout&quot;,this.doCellMouseOut,this);};YAHOO.widget.Calendar.prototype.getDateByCellId=function(B){var A=this.getDateFieldsByCellId(B);return new Date(A[0],A[1]-1,A[2]);};YAHOO.widget.Calendar.prototype.getDateFieldsByCellId=function(A){A=A.toLowerCase().split(&quot;_cell&quot;)[1];A=parseInt(A,10);return this.cellDates[A];};YAHOO.widget.Calendar.prototype.renderOutOfBoundsDate=function(B,A){YAHOO.util.Dom.addClass(A,this.Style.CSS_CELL_OOB);A.innerHTML=B.getDate();return YAHOO.widget.Calendar.STOP_RENDER;};YAHOO.widget.Calendar.prototype.renderRowHeader=f
 unction(B,A){A[A.length]=&quot;&lt;th class=\&quot;calrowhead\&quot;&gt;&quot;+B+&quot;&lt;/th&gt;&quot;;return A;};YAHOO.widget.Calendar.prototype.renderRowFooter=function(B,A){A[A.length]=&quot;&lt;th class=\&quot;calrowfoot\&quot;&gt;&quot;+B+&quot;&lt;/th&gt;&quot;;return A;};YAHOO.widget.Calendar.prototype.renderCellDefault=function(B,A){A.innerHTML=&quot;&lt;a href=\&quot;#\&quot; class=\&quot;&quot;+this.Style.CSS_CELL_SELECTOR+&quot;\&quot;&gt;&quot;+this.buildDayLabel(B)+&quot;&lt;/a&gt;&quot;;};YAHOO.widget.Calendar.prototype.styleCellDefault=function(B,A){YAHOO.util.Dom.addClass(A,this.Style.CSS_CELL_SELECTABLE);};YAHOO.widget.Calendar.prototype.renderCellStyleHighlight1=function(B,A){YAHOO.util.Dom.addClass(A,this.Style.CSS_CELL_HIGHLIGHT1);};YAHOO.widget.Calendar.prototype.renderCellStyleHighlight2=function(B,A){YAHOO.util.Dom.addClass(A,this.Style.CSS_CELL_HIGHLIGHT2);};YAHOO.widget.Calendar.prototype.renderCellStyleHighlight3=function(B,A){YAHOO.util.Dom.addCl
 ass(A,this.Style.CSS_CELL_HIGHLIGHT3);};YAHOO.widget.Calendar.prototype.renderCellStyleHighlight4=function(B,A){YAHOO.util.Dom.addClass(A,this.Style.CSS_CELL_HIGHLIGHT4);};YAHOO.widget.Calendar.prototype.renderCellStyleToday=function(B,A){YAHOO.util.Dom.addClass(A,this.Style.CSS_CELL_TODAY);};YAHOO.widget.Calendar.prototype.renderCellStyleSelected=function(B,A){YAHOO.util.Dom.addClass(A,this.Style.CSS_CELL_SELECTED);};YAHOO.widget.Calendar.prototype.renderCellNotThisMonth=function(B,A){YAHOO.util.Dom.addClass(A,this.Style.CSS_CELL_OOM);A.innerHTML=B.getDate();return YAHOO.widget.Calendar.STOP_RENDER;};YAHOO.widget.Calendar.prototype.renderBodyCellRestricted=function(B,A){YAHOO.util.Dom.addClass(A,this.Style.CSS_CELL);YAHOO.util.Dom.addClass(A,this.Style.CSS_CELL_RESTRICTED);A.innerHTML=B.getDate();return YAHOO.widget.Calendar.STOP_RENDER;};YAHOO.widget.Calendar.prototype.addMonths=function(B){var A=YAHOO.widget.Calendar._DEFAULT_CONFIG.PAGEDATE.key;this.cfg.setProperty(A,YAH
 OO.widget.DateMath.add(this.cfg.getProperty(A),YAHOO.widget.DateMath.MONTH,B));this.resetRenderers();this.changePageEvent.fire();};YAHOO.widget.Calendar.prototype.subtractMonths=function(B){var A=YAHOO.widget.Calendar._DEFAULT_CONFIG.PAGEDATE.key;this.cfg.setProperty(A,YAHOO.widget.DateMath.subtract(this.cfg.getProperty(A),YAHOO.widget.DateMath.MONTH,B));this.resetRenderers();this.changePageEvent.fire();};YAHOO.widget.Calendar.prototype.addYears=function(B){var A=YAHOO.widget.Calendar._DEFAULT_CONFIG.PAGEDATE.key;this.cfg.setProperty(A,YAHOO.widget.DateMath.add(this.cfg.getProperty(A),YAHOO.widget.DateMath.YEAR,B));this.resetRenderers();this.changePageEvent.fire();};YAHOO.widget.Calendar.prototype.subtractYears=function(B){var A=YAHOO.widget.Calendar._DEFAULT_CONFIG.PAGEDATE.key;this.cfg.setProperty(A,YAHOO.widget.DateMath.subtract(this.cfg.getProperty(A),YAHOO.widget.DateMath.YEAR,B));this.resetRenderers();this.changePageEvent.fire();};YAHOO.widget.Calendar.prototype.nextMo
 nth=function(){this.addMonths(1);};YAHOO.widget.Calendar.prototype.previousMonth=function(){this.subtractMonths(1);};YAHOO.widget.Calendar.prototype.nextYear=function(){this.addYears(1);};YAHOO.widget.Calendar.prototype.previousYear=function(){this.subtractYears(1);};YAHOO.widget.Calendar.prototype.reset=function(){var A=YAHOO.widget.Calendar._DEFAULT_CONFIG;this.cfg.resetProperty(A.SELECTED.key);this.cfg.resetProperty(A.PAGEDATE.key);this.resetEvent.fire();
-};YAHOO.widget.Calendar.prototype.clear=function(){var A=YAHOO.widget.Calendar._DEFAULT_CONFIG;this.cfg.setProperty(A.SELECTED.key,[]);this.cfg.setProperty(A.PAGEDATE.key,new Date(this.today.getTime()));this.clearEvent.fire();};YAHOO.widget.Calendar.prototype.select=function(C){var F=this._toFieldArray(C);var B=[];var E=[];var G=YAHOO.widget.Calendar._DEFAULT_CONFIG.SELECTED.key;for(var A=0;A&lt;F.length;++A){var D=F[A];if(!this.isDateOOB(this._toDate(D))){if(B.length===0){this.beforeSelectEvent.fire();E=this.cfg.getProperty(G);}B.push(D);if(this._indexOfSelectedFieldArray(D)==-1){E[E.length]=D;}}}if(B.length&gt;0){if(this.parent){this.parent.cfg.setProperty(G,E);}else{this.cfg.setProperty(G,E);}this.selectEvent.fire(B);}return this.getSelectedDates();};YAHOO.widget.Calendar.prototype.selectCell=function(D){var B=this.cells[D];var H=this.cellDates[D];var G=this._toDate(H);var C=YAHOO.util.Dom.hasClass(B,this.Style.CSS_CELL_SELECTABLE);if(C){this.beforeSelectEvent.fire();var 
 F=YAHOO.widget.Calendar._DEFAULT_CONFIG.SELECTED.key;var E=this.cfg.getProperty(F);var A=H.concat();if(this._indexOfSelectedFieldArray(A)==-1){E[E.length]=A;}if(this.parent){this.parent.cfg.setProperty(F,E);}else{this.cfg.setProperty(F,E);}this.renderCellStyleSelected(G,B);this.selectEvent.fire([A]);this.doCellMouseOut.call(B,null,this);}return this.getSelectedDates();};YAHOO.widget.Calendar.prototype.deselect=function(E){var A=this._toFieldArray(E);var D=[];var G=[];var H=YAHOO.widget.Calendar._DEFAULT_CONFIG.SELECTED.key;for(var B=0;B&lt;A.length;++B){var F=A[B];if(!this.isDateOOB(this._toDate(F))){if(D.length===0){this.beforeDeselectEvent.fire();G=this.cfg.getProperty(H);}D.push(F);var C=this._indexOfSelectedFieldArray(F);if(C!=-1){G.splice(C,1);}}}if(D.length&gt;0){if(this.parent){this.parent.cfg.setProperty(H,G);}else{this.cfg.setProperty(H,G);}this.deselectEvent.fire(D);}return this.getSelectedDates();};YAHOO.widget.Calendar.prototype.deselectCell=function(E){var H=thi
 s.cells[E];var B=this.cellDates[E];var F=this._indexOfSelectedFieldArray(B);var G=YAHOO.util.Dom.hasClass(H,this.Style.CSS_CELL_SELECTABLE);if(G){this.beforeDeselectEvent.fire();var I=YAHOO.widget.Calendar._DEFAULT_CONFIG;var D=this.cfg.getProperty(I.SELECTED.key);var C=this._toDate(B);var A=B.concat();if(F&gt;-1){if(this.cfg.getProperty(I.PAGEDATE.key).getMonth()==C.getMonth()&amp;&amp;this.cfg.getProperty(I.PAGEDATE.key).getFullYear()==C.getFullYear()){YAHOO.util.Dom.removeClass(H,this.Style.CSS_CELL_SELECTED);}D.splice(F,1);}if(this.parent){this.parent.cfg.setProperty(I.SELECTED.key,D);}else{this.cfg.setProperty(I.SELECTED.key,D);}this.deselectEvent.fire(A);}return this.getSelectedDates();};YAHOO.widget.Calendar.prototype.deselectAll=function(){this.beforeDeselectEvent.fire();var D=YAHOO.widget.Calendar._DEFAULT_CONFIG.SELECTED.key;var A=this.cfg.getProperty(D);var B=A.length;var C=A.concat();if(this.parent){this.parent.cfg.setProperty(D,[]);}else{this.cfg.setProperty(D,[
 ]);}if(B&gt;0){this.deselectEvent.fire(C);}return this.getSelectedDates();};YAHOO.widget.Calendar.prototype._toFieldArray=function(B){var A=[];if(B instanceof Date){A=[[B.getFullYear(),B.getMonth()+1,B.getDate()]];}else{if(YAHOO.lang.isString(B)){A=this._parseDates(B);}else{if(YAHOO.lang.isArray(B)){for(var C=0;C&lt;B.length;++C){var D=B[C];A[A.length]=[D.getFullYear(),D.getMonth()+1,D.getDate()];}}}}return A;};YAHOO.widget.Calendar.prototype._toDate=function(A){if(A instanceof Date){return A;}else{return new Date(A[0],A[1]-1,A[2]);}};YAHOO.widget.Calendar.prototype._fieldArraysAreEqual=function(C,B){var A=false;if(C[0]==B[0]&amp;&amp;C[1]==B[1]&amp;&amp;C[2]==B[2]){A=true;}return A;};YAHOO.widget.Calendar.prototype._indexOfSelectedFieldArray=function(E){var D=-1;var A=this.cfg.getProperty(YAHOO.widget.Calendar._DEFAULT_CONFIG.SELECTED.key);for(var C=0;C&lt;A.length;++C){var B=A[C];if(E[0]==B[0]&amp;&amp;E[1]==B[1]&amp;&amp;E[2]==B[2]){D=C;break;}}return D;};YAHOO.widget.Cal
 endar.prototype.isDateOOM=function(A){return(A.getMonth()!=this.cfg.getProperty(YAHOO.widget.Calendar._DEFAULT_CONFIG.PAGEDATE.key).getMonth());};YAHOO.widget.Calendar.prototype.isDateOOB=function(D){var A=YAHOO.widget.Calendar._DEFAULT_CONFIG;var E=this.cfg.getProperty(A.MINDATE.key);var F=this.cfg.getProperty(A.MAXDATE.key);var C=YAHOO.widget.DateMath;if(E){E=C.clearTime(E);}if(F){F=C.clearTime(F);}var B=new Date(D.getTime());B=C.clearTime(B);return((E&amp;&amp;B.getTime()&lt;E.getTime())||(F&amp;&amp;B.getTime()&gt;F.getTime()));};YAHOO.widget.Calendar.prototype._parsePageDate=function(B){var E;var A=YAHOO.widget.Calendar._DEFAULT_CONFIG;if(B){if(B instanceof Date){E=YAHOO.widget.DateMath.findMonthStart(B);}else{var F,D,C;C=B.split(this.cfg.getProperty(A.DATE_FIELD_DELIMITER.key));F=parseInt(C[this.cfg.getProperty(A.MY_MONTH_POSITION.key)-1],10)-1;D=parseInt(C[this.cfg.getProperty(A.MY_YEAR_POSITION.key)-1],10);E=new Date(D,F,1);}}else{E=new Date(this.today.getFullYear(),
 this.today.getMonth(),1);}return E;};YAHOO.widget.Calendar.prototype.onBeforeSelect=function(){if(this.cfg.getProperty(YAHOO.widget.Calendar._DEFAULT_CONFIG.MULTI_SELECT.key)===false){if(this.parent){this.parent.callChildFunction(&quot;clearAllBodyCellStyles&quot;,this.Style.CSS_CELL_SELECTED);this.parent.deselectAll();}else{this.clearAllBodyCellStyles(this.Style.CSS_CELL_SELECTED);this.deselectAll();}}};YAHOO.widget.Calendar.prototype.onSelect=function(A){};YAHOO.widget.Calendar.prototype.onBeforeDeselect=function(){};YAHOO.widget.Calendar.prototype.onDeselect=function(A){};YAHOO.widget.Calendar.prototype.onChangePage=function(){this.render();};YAHOO.widget.Calendar.prototype.onRender=function(){};YAHOO.widget.Calendar.prototype.onReset=function(){this.render();};YAHOO.widget.Calendar.prototype.onClear=function(){this.render();};YAHOO.widget.Calendar.prototype.validate=function(){return true;};YAHOO.widget.Calendar.prototype._parseDate=function(C){var D=C.split(this.Locale.
 DATE_FIELD_DELIMITER);var A;if(D.length==2){A=[D[this.Locale.MD_MONTH_POSITION-1],D[this.Locale.MD_DAY_POSITION-1]];A.type=YAHOO.widget.Calendar.MONTH_DAY;}else{A=[D[this.Locale.MDY_YEAR_POSITION-1],D[this.Locale.MDY_MONTH_POSITION-1],D[this.Locale.MDY_DAY_POSITION-1]];
-A.type=YAHOO.widget.Calendar.DATE;}for(var B=0;B&lt;A.length;B++){A[B]=parseInt(A[B],10);}return A;};YAHOO.widget.Calendar.prototype._parseDates=function(B){var I=[];var H=B.split(this.Locale.DATE_DELIMITER);for(var G=0;G&lt;H.length;++G){var F=H[G];if(F.indexOf(this.Locale.DATE_RANGE_DELIMITER)!=-1){var A=F.split(this.Locale.DATE_RANGE_DELIMITER);var E=this._parseDate(A[0]);var J=this._parseDate(A[1]);var D=this._parseRange(E,J);I=I.concat(D);}else{var C=this._parseDate(F);I.push(C);}}return I;};YAHOO.widget.Calendar.prototype._parseRange=function(A,F){var E=new Date(A[0],A[1]-1,A[2]);var B=YAHOO.widget.DateMath.add(new Date(A[0],A[1]-1,A[2]),YAHOO.widget.DateMath.DAY,1);var D=new Date(F[0],F[1]-1,F[2]);var C=[];C.push(A);while(B.getTime()&lt;=D.getTime()){C.push([B.getFullYear(),B.getMonth()+1,B.getDate()]);B=YAHOO.widget.DateMath.add(B,YAHOO.widget.DateMath.DAY,1);}return C;};YAHOO.widget.Calendar.prototype.resetRenderers=function(){this.renderStack=this._renderStack.conc
 at();};YAHOO.widget.Calendar.prototype.clearElement=function(A){A.innerHTML=&quot;&amp;#160;&quot;;A.className=&quot;&quot;;};YAHOO.widget.Calendar.prototype.addRenderer=function(A,B){var D=this._parseDates(A);for(var C=0;C&lt;D.length;++C){var E=D[C];if(E.length==2){if(E[0] instanceof Array){this._addRenderer(YAHOO.widget.Calendar.RANGE,E,B);}else{this._addRenderer(YAHOO.widget.Calendar.MONTH_DAY,E,B);}}else{if(E.length==3){this._addRenderer(YAHOO.widget.Calendar.DATE,E,B);}}}};YAHOO.widget.Calendar.prototype._addRenderer=function(B,C,A){var D=[B,C,A];this.renderStack.unshift(D);this._renderStack=this.renderStack.concat();};YAHOO.widget.Calendar.prototype.addMonthRenderer=function(B,A){this._addRenderer(YAHOO.widget.Calendar.MONTH,[B],A);};YAHOO.widget.Calendar.prototype.addWeekdayRenderer=function(B,A){this._addRenderer(YAHOO.widget.Calendar.WEEKDAY,[B],A);};YAHOO.widget.Calendar.prototype.clearAllBodyCellStyles=function(A){for(var B=0;B&lt;this.cells.length;++B){YAHOO.uti
 l.Dom.removeClass(this.cells[B],A);}};YAHOO.widget.Calendar.prototype.setMonth=function(C){var A=YAHOO.widget.Calendar._DEFAULT_CONFIG.PAGEDATE.key;var B=this.cfg.getProperty(A);B.setMonth(parseInt(C,10));this.cfg.setProperty(A,B);};YAHOO.widget.Calendar.prototype.setYear=function(B){var A=YAHOO.widget.Calendar._DEFAULT_CONFIG.PAGEDATE.key;var C=this.cfg.getProperty(A);C.setFullYear(parseInt(B,10));this.cfg.setProperty(A,C);};YAHOO.widget.Calendar.prototype.getSelectedDates=function(){var C=[];var B=this.cfg.getProperty(YAHOO.widget.Calendar._DEFAULT_CONFIG.SELECTED.key);for(var E=0;E&lt;B.length;++E){var D=B[E];var A=new Date(D[0],D[1]-1,D[2]);C.push(A);}C.sort(function(G,F){return G-F;});return C;};YAHOO.widget.Calendar.prototype.hide=function(){this.oDomContainer.style.display=&quot;none&quot;;};YAHOO.widget.Calendar.prototype.show=function(){this.oDomContainer.style.display=&quot;block&quot;;};YAHOO.widget.Calendar.prototype.browser=function(){var A=navigator.userAgent.t
 oLowerCase();if(A.indexOf(&quot;opera&quot;)!=-1){return&quot;opera&quot;;}else{if(A.indexOf(&quot;msie 7&quot;)!=-1){return&quot;ie7&quot;;}else{if(A.indexOf(&quot;msie&quot;)!=-1){return&quot;ie&quot;;}else{if(A.indexOf(&quot;safari&quot;)!=-1){return&quot;safari&quot;;}else{if(A.indexOf(&quot;gecko&quot;)!=-1){return&quot;gecko&quot;;}else{return false;}}}}}}();YAHOO.widget.Calendar.prototype.toString=function(){return&quot;Calendar &quot;+this.id;};YAHOO.widget.Calendar_Core=YAHOO.widget.Calendar;YAHOO.widget.Cal_Core=YAHOO.widget.Calendar;YAHOO.widget.CalendarGroup=function(C,A,B){if(arguments.length&gt;0){this.init(C,A,B);}};YAHOO.widget.CalendarGroup.prototype.init=function(C,A,B){this.initEvents();this.initStyles();this.pages=[];this.id=C;this.containerId=A;this.oDomContainer=document.getElementById(A);YAHOO.util.Dom.addClass(this.oDomContainer,YAHOO.widget.CalendarGroup.CSS_CONTAINER);YAHOO.util.Dom.addClass(this.oDomContainer,YAHOO.widget.CalendarGroup.CSS_MULTI_UP
 );this.cfg=new YAHOO.util.Config(this);this.Options={};this.Locale={};this.setupConfig();if(B){this.cfg.applyConfig(B,true);}this.cfg.fireQueue();if(YAHOO.env.ua.opera){this.renderEvent.subscribe(this._fixWidth,this,true);}};YAHOO.widget.CalendarGroup.prototype.setupConfig=function(){var A=YAHOO.widget.CalendarGroup._DEFAULT_CONFIG;this.cfg.addProperty(A.PAGES.key,{value:A.PAGES.value,validator:this.cfg.checkNumber,handler:this.configPages});this.cfg.addProperty(A.PAGEDATE.key,{value:new Date(),handler:this.configPageDate});this.cfg.addProperty(A.SELECTED.key,{value:[],handler:this.configSelected});this.cfg.addProperty(A.TITLE.key,{value:A.TITLE.value,handler:this.configTitle});this.cfg.addProperty(A.CLOSE.key,{value:A.CLOSE.value,handler:this.configClose});this.cfg.addProperty(A.IFRAME.key,{value:A.IFRAME.value,handler:this.configIframe,validator:this.cfg.checkBoolean});this.cfg.addProperty(A.MINDATE.key,{value:A.MINDATE.value,handler:this.delegateConfig});this.cfg.addPrope
 rty(A.MAXDATE.key,{value:A.MAXDATE.value,handler:this.delegateConfig});this.cfg.addProperty(A.MULTI_SELECT.key,{value:A.MULTI_SELECT.value,handler:this.delegateConfig,validator:this.cfg.checkBoolean});this.cfg.addProperty(A.START_WEEKDAY.key,{value:A.START_WEEKDAY.value,handler:this.delegateConfig,validator:this.cfg.checkNumber});this.cfg.addProperty(A.SHOW_WEEKDAYS.key,{value:A.SHOW_WEEKDAYS.value,handler:this.delegateConfig,validator:this.cfg.checkBoolean});this.cfg.addProperty(A.SHOW_WEEK_HEADER.key,{value:A.SHOW_WEEK_HEADER.value,handler:this.delegateConfig,validator:this.cfg.checkBoolean});this.cfg.addProperty(A.SHOW_WEEK_FOOTER.key,{value:A.SHOW_WEEK_FOOTER.value,handler:this.delegateConfig,validator:this.cfg.checkBoolean});this.cfg.addProperty(A.HIDE_BLANK_WEEKS.key,{value:A.HIDE_BLANK_WEEKS.value,handler:this.delegateConfig,validator:this.cfg.checkBoolean});this.cfg.addProperty(A.NAV_ARROW_LEFT.key,{value:A.NAV_ARROW_LEFT.value,handler:this.delegateConfig});this.cfg.
 addProperty(A.NAV_ARROW_RIGHT.key,{value:A.NAV_ARROW_RIGHT.value,handler:this.delegateConfig});this.cfg.addProperty(A.MONTHS_SHORT.key,{value:A.MONTHS_SHORT.value,handler:this.delegateConfig});this.cfg.addProperty(A.MONTHS_LONG.key,{value:A.MONTHS_LONG.value,handler:this.delegateConfig});
-this.cfg.addProperty(A.WEEKDAYS_1CHAR.key,{value:A.WEEKDAYS_1CHAR.value,handler:this.delegateConfig});this.cfg.addProperty(A.WEEKDAYS_SHORT.key,{value:A.WEEKDAYS_SHORT.value,handler:this.delegateConfig});this.cfg.addProperty(A.WEEKDAYS_MEDIUM.key,{value:A.WEEKDAYS_MEDIUM.value,handler:this.delegateConfig});this.cfg.addProperty(A.WEEKDAYS_LONG.key,{value:A.WEEKDAYS_LONG.value,handler:this.delegateConfig});this.cfg.addProperty(A.LOCALE_MONTHS.key,{value:A.LOCALE_MONTHS.value,handler:this.delegateConfig});this.cfg.addProperty(A.LOCALE_WEEKDAYS.key,{value:A.LOCALE_WEEKDAYS.value,handler:this.delegateConfig});this.cfg.addProperty(A.DATE_DELIMITER.key,{value:A.DATE_DELIMITER.value,handler:this.delegateConfig});this.cfg.addProperty(A.DATE_FIELD_DELIMITER.key,{value:A.DATE_FIELD_DELIMITER.value,handler:this.delegateConfig});this.cfg.addProperty(A.DATE_RANGE_DELIMITER.key,{value:A.DATE_RANGE_DELIMITER.value,handler:this.delegateConfig});this.cfg.addProperty(A.MY_MONTH_POSITION.key,{v
 alue:A.MY_MONTH_POSITION.value,handler:this.delegateConfig,validator:this.cfg.checkNumber});this.cfg.addProperty(A.MY_YEAR_POSITION.key,{value:A.MY_YEAR_POSITION.value,handler:this.delegateConfig,validator:this.cfg.checkNumber});this.cfg.addProperty(A.MD_MONTH_POSITION.key,{value:A.MD_MONTH_POSITION.value,handler:this.delegateConfig,validator:this.cfg.checkNumber});this.cfg.addProperty(A.MD_DAY_POSITION.key,{value:A.MD_DAY_POSITION.value,handler:this.delegateConfig,validator:this.cfg.checkNumber});this.cfg.addProperty(A.MDY_MONTH_POSITION.key,{value:A.MDY_MONTH_POSITION.value,handler:this.delegateConfig,validator:this.cfg.checkNumber});this.cfg.addProperty(A.MDY_DAY_POSITION.key,{value:A.MDY_DAY_POSITION.value,handler:this.delegateConfig,validator:this.cfg.checkNumber});this.cfg.addProperty(A.MDY_YEAR_POSITION.key,{value:A.MDY_YEAR_POSITION.value,handler:this.delegateConfig,validator:this.cfg.checkNumber});this.cfg.addProperty(A.MY_LABEL_MONTH_POSITION.key,{value:A.MY_LABEL_
 MONTH_POSITION.value,handler:this.delegateConfig,validator:this.cfg.checkNumber});this.cfg.addProperty(A.MY_LABEL_YEAR_POSITION.key,{value:A.MY_LABEL_YEAR_POSITION.value,handler:this.delegateConfig,validator:this.cfg.checkNumber});this.cfg.addProperty(A.MY_LABEL_MONTH_SUFFIX.key,{value:A.MY_LABEL_MONTH_SUFFIX.value,handler:this.delegateConfig});this.cfg.addProperty(A.MY_LABEL_YEAR_SUFFIX.key,{value:A.MY_LABEL_YEAR_SUFFIX.value,handler:this.delegateConfig});};YAHOO.widget.CalendarGroup.prototype.initEvents=function(){var C=this;var E=&quot;Event&quot;;var B=function(G,J,F){for(var I=0;I&lt;C.pages.length;++I){var H=C.pages[I];H[this.type+E].subscribe(G,J,F);}};var A=function(F,I){for(var H=0;H&lt;C.pages.length;++H){var G=C.pages[H];G[this.type+E].unsubscribe(F,I);}};var D=YAHOO.widget.Calendar._EVENT_TYPES;this.beforeSelectEvent=new YAHOO.util.CustomEvent(D.BEFORE_SELECT);this.beforeSelectEvent.subscribe=B;this.beforeSelectEvent.unsubscribe=A;this.selectEvent=new YAHOO.util.
 CustomEvent(D.SELECT);this.selectEvent.subscribe=B;this.selectEvent.unsubscribe=A;this.beforeDeselectEvent=new YAHOO.util.CustomEvent(D.BEFORE_DESELECT);this.beforeDeselectEvent.subscribe=B;this.beforeDeselectEvent.unsubscribe=A;this.deselectEvent=new YAHOO.util.CustomEvent(D.DESELECT);this.deselectEvent.subscribe=B;this.deselectEvent.unsubscribe=A;this.changePageEvent=new YAHOO.util.CustomEvent(D.CHANGE_PAGE);this.changePageEvent.subscribe=B;this.changePageEvent.unsubscribe=A;this.beforeRenderEvent=new YAHOO.util.CustomEvent(D.BEFORE_RENDER);this.beforeRenderEvent.subscribe=B;this.beforeRenderEvent.unsubscribe=A;this.renderEvent=new YAHOO.util.CustomEvent(D.RENDER);this.renderEvent.subscribe=B;this.renderEvent.unsubscribe=A;this.resetEvent=new YAHOO.util.CustomEvent(D.RESET);this.resetEvent.subscribe=B;this.resetEvent.unsubscribe=A;this.clearEvent=new YAHOO.util.CustomEvent(D.CLEAR);this.clearEvent.subscribe=B;this.clearEvent.unsubscribe=A;};YAHOO.widget.CalendarGroup.proto
 type.configPages=function(K,J,G){var E=J[0];var C=YAHOO.widget.CalendarGroup._DEFAULT_CONFIG.PAGEDATE.key;var O=&quot;_&quot;;var L=&quot;groupcal&quot;;var N=&quot;first-of-type&quot;;var D=&quot;last-of-type&quot;;for(var B=0;B&lt;E;++B){var M=this.id+O+B;var I=this.containerId+O+B;var H=this.cfg.getConfig();H.close=false;H.title=false;var A=this.constructChild(M,I,H);var F=A.cfg.getProperty(C);this._setMonthOnDate(F,F.getMonth()+B);A.cfg.setProperty(C,F);YAHOO.util.Dom.removeClass(A.oDomContainer,this.Style.CSS_SINGLE);YAHOO.util.Dom.addClass(A.oDomContainer,L);if(B===0){YAHOO.util.Dom.addClass(A.oDomContainer,N);}if(B==(E-1)){YAHOO.util.Dom.addClass(A.oDomContainer,D);}A.parent=this;A.index=B;this.pages[this.pages.length]=A;}};YAHOO.widget.CalendarGroup.prototype.configPageDate=function(H,G,E){var C=G[0];var F;var D=YAHOO.widget.CalendarGroup._DEFAULT_CONFIG.PAGEDATE.key;for(var B=0;B&lt;this.pages.length;++B){var A=this.pages[B];if(B===0){F=A._parsePageDate(C);A.cfg.set
 Property(D,F);}else{var I=new Date(F);this._setMonthOnDate(I,I.getMonth()+B);A.cfg.setProperty(D,I);}}};YAHOO.widget.CalendarGroup.prototype.configSelected=function(C,A,E){var D=YAHOO.widget.CalendarGroup._DEFAULT_CONFIG.SELECTED.key;this.delegateConfig(C,A,E);var B=(this.pages.length&gt;0)?this.pages[0].cfg.getProperty(D):[];this.cfg.setProperty(D,B,true);};YAHOO.widget.CalendarGroup.prototype.delegateConfig=function(B,A,E){var F=A[0];var D;for(var C=0;C&lt;this.pages.length;C++){D=this.pages[C];D.cfg.setProperty(B,F);}};YAHOO.widget.CalendarGroup.prototype.setChildFunction=function(D,B){var A=this.cfg.getProperty(YAHOO.widget.CalendarGroup._DEFAULT_CONFIG.PAGES.key);for(var C=0;C&lt;A;++C){this.pages[C][D]=B;}};YAHOO.widget.CalendarGroup.prototype.callChildFunction=function(F,B){var A=this.cfg.getProperty(YAHOO.widget.CalendarGroup._DEFAULT_CONFIG.PAGES.key);for(var E=0;E&lt;A;++E){var D=this.pages[E];if(D[F]){var C=D[F];C.call(D,B);}}};YAHOO.widget.CalendarGroup.prototype
 .constructChild=function(D,B,C){var A=document.getElementById(B);if(!A){A=document.createElement(&quot;div&quot;);A.id=B;this.oDomContainer.appendChild(A);
-}return new YAHOO.widget.Calendar(D,B,C);};YAHOO.widget.CalendarGroup.prototype.setMonth=function(E){E=parseInt(E,10);var F;var B=YAHOO.widget.CalendarGroup._DEFAULT_CONFIG.PAGEDATE.key;for(var D=0;D&lt;this.pages.length;++D){var C=this.pages[D];var A=C.cfg.getProperty(B);if(D===0){F=A.getFullYear();}else{A.setYear(F);}this._setMonthOnDate(A,E+D);C.cfg.setProperty(B,A);}};YAHOO.widget.CalendarGroup.prototype.setYear=function(C){var B=YAHOO.widget.CalendarGroup._DEFAULT_CONFIG.PAGEDATE.key;C=parseInt(C,10);for(var E=0;E&lt;this.pages.length;++E){var D=this.pages[E];var A=D.cfg.getProperty(B);if((A.getMonth()+1)==1&amp;&amp;E&gt;0){C+=1;}D.setYear(C);}};YAHOO.widget.CalendarGroup.prototype.render=function(){this.renderHeader();for(var B=0;B&lt;this.pages.length;++B){var A=this.pages[B];A.render();}this.renderFooter();};YAHOO.widget.CalendarGroup.prototype.select=function(A){for(var C=0;C&lt;this.pages.length;++C){var B=this.pages[C];B.select(A);}return this.getSelectedDates();
 };YAHOO.widget.CalendarGroup.prototype.selectCell=function(A){for(var C=0;C&lt;this.pages.length;++C){var B=this.pages[C];B.selectCell(A);}return this.getSelectedDates();};YAHOO.widget.CalendarGroup.prototype.deselect=function(A){for(var C=0;C&lt;this.pages.length;++C){var B=this.pages[C];B.deselect(A);}return this.getSelectedDates();};YAHOO.widget.CalendarGroup.prototype.deselectAll=function(){for(var B=0;B&lt;this.pages.length;++B){var A=this.pages[B];A.deselectAll();}return this.getSelectedDates();};YAHOO.widget.CalendarGroup.prototype.deselectCell=function(A){for(var C=0;C&lt;this.pages.length;++C){var B=this.pages[C];B.deselectCell(A);}return this.getSelectedDates();};YAHOO.widget.CalendarGroup.prototype.reset=function(){for(var B=0;B&lt;this.pages.length;++B){var A=this.pages[B];A.reset();}};YAHOO.widget.CalendarGroup.prototype.clear=function(){for(var B=0;B&lt;this.pages.length;++B){var A=this.pages[B];A.clear();}};YAHOO.widget.CalendarGroup.prototype.nextMonth=functi
 on(){for(var B=0;B&lt;this.pages.length;++B){var A=this.pages[B];A.nextMonth();}};YAHOO.widget.CalendarGroup.prototype.previousMonth=function(){for(var B=this.pages.length-1;B&gt;=0;--B){var A=this.pages[B];A.previousMonth();}};YAHOO.widget.CalendarGroup.prototype.nextYear=function(){for(var B=0;B&lt;this.pages.length;++B){var A=this.pages[B];A.nextYear();}};YAHOO.widget.CalendarGroup.prototype.previousYear=function(){for(var B=0;B&lt;this.pages.length;++B){var A=this.pages[B];A.previousYear();}};YAHOO.widget.CalendarGroup.prototype.getSelectedDates=function(){var C=[];var B=this.cfg.getProperty(YAHOO.widget.CalendarGroup._DEFAULT_CONFIG.SELECTED.key);for(var E=0;E&lt;B.length;++E){var D=B[E];var A=new Date(D[0],D[1]-1,D[2]);C.push(A);}C.sort(function(G,F){return G-F;});return C;};YAHOO.widget.CalendarGroup.prototype.addRenderer=function(A,B){for(var D=0;D&lt;this.pages.length;++D){var C=this.pages[D];C.addRenderer(A,B);}};YAHOO.widget.CalendarGroup.prototype.addMonthRendere
 r=function(D,A){for(var C=0;C&lt;this.pages.length;++C){var B=this.pages[C];B.addMonthRenderer(D,A);}};YAHOO.widget.CalendarGroup.prototype.addWeekdayRenderer=function(B,A){for(var D=0;D&lt;this.pages.length;++D){var C=this.pages[D];C.addWeekdayRenderer(B,A);}};YAHOO.widget.CalendarGroup.prototype.renderHeader=function(){};YAHOO.widget.CalendarGroup.prototype.renderFooter=function(){};YAHOO.widget.CalendarGroup.prototype.addMonths=function(A){this.callChildFunction(&quot;addMonths&quot;,A);};YAHOO.widget.CalendarGroup.prototype.subtractMonths=function(A){this.callChildFunction(&quot;subtractMonths&quot;,A);};YAHOO.widget.CalendarGroup.prototype.addYears=function(A){this.callChildFunction(&quot;addYears&quot;,A);};YAHOO.widget.CalendarGroup.prototype.subtractYears=function(A){this.callChildFunction(&quot;subtractYears&quot;,A);};YAHOO.widget.CalendarGroup.prototype.show=function(){this.oDomContainer.style.display=&quot;block&quot;;if(YAHOO.env.ua.opera){this._fixWidth();}};YA
 HOO.widget.CalendarGroup.prototype._setMonthOnDate=function(C,D){if(YAHOO.env.ua.webkit&amp;&amp;YAHOO.env.ua.webkit&lt;420&amp;&amp;(D&lt;0||D&gt;11)){var B=YAHOO.widget.DateMath;var A=B.add(C,B.MONTH,D-C.getMonth());C.setTime(A.getTime());}else{C.setMonth(D);}};YAHOO.widget.CalendarGroup.prototype._fixWidth=function(){var B=this.oDomContainer.offsetWidth;var A=0;for(var D=0;D&lt;this.pages.length;++D){var C=this.pages[D];A+=C.oDomContainer.offsetWidth;}if(A&gt;0){this.oDomContainer.style.width=A+&quot;px&quot;;}};YAHOO.widget.CalendarGroup.CSS_CONTAINER=&quot;yui-calcontainer&quot;;YAHOO.widget.CalendarGroup.CSS_MULTI_UP=&quot;multi&quot;;YAHOO.widget.CalendarGroup.CSS_2UPTITLE=&quot;title&quot;;YAHOO.widget.CalendarGroup.CSS_2UPCLOSE=&quot;close-icon&quot;;YAHOO.lang.augmentProto(YAHOO.widget.CalendarGroup,YAHOO.widget.Calendar,&quot;buildDayLabel&quot;,&quot;buildMonthLabel&quot;,&quot;renderOutOfBoundsDate&quot;,&quot;renderRowHeader&quot;,&quot;renderRowFooter&quot;,&q
 uot;renderCellDefault&quot;,&quot;styleCellDefault&quot;,&quot;renderCellStyleHighlight1&quot;,&quot;renderCellStyleHighlight2&quot;,&quot;renderCellStyleHighlight3&quot;,&quot;renderCellStyleHighlight4&quot;,&quot;renderCellStyleToday&quot;,&quot;renderCellStyleSelected&quot;,&quot;renderCellNotThisMonth&quot;,&quot;renderBodyCellRestricted&quot;,&quot;initStyles&quot;,&quot;configTitle&quot;,&quot;configClose&quot;,&quot;configIframe&quot;,&quot;createTitleBar&quot;,&quot;createCloseButton&quot;,&quot;removeTitleBar&quot;,&quot;removeCloseButton&quot;,&quot;hide&quot;,&quot;browser&quot;);YAHOO.widget.CalendarGroup._DEFAULT_CONFIG=YAHOO.widget.Calendar._DEFAULT_CONFIG;YAHOO.widget.CalendarGroup._DEFAULT_CONFIG.PAGES={key:&quot;pages&quot;,value:2};YAHOO.widget.CalendarGroup.prototype.toString=function(){return&quot;CalendarGroup &quot;+this.id;};YAHOO.widget.CalGrp=YAHOO.widget.CalendarGroup;YAHOO.widget.Calendar2up=function(C,A,B){this.init(C,A,B);};YAHOO.extend(YAHOO.wid
 get.Calendar2up,YAHOO.widget.CalendarGroup);YAHOO.widget.Cal2up=YAHOO.widget.Calendar2up;YAHOO.register(&quot;calendar&quot;,YAHOO.widget.Calendar,{version:&quot;2.3.1&quot;,build:&quot;541&quot;});
</del><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuicarouselcarouselminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/carousel/carousel-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/carousel/carousel-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/carousel/carousel-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+(function(){var Q=&quot;Carousel&quot;;YAHOO.widget.Carousel=function(u,t){YAHOO.widget.Carousel.superclass.constructor.call(this,u,t);};var V=YAHOO.widget.Carousel,g=YAHOO.util.Dom,e=YAHOO.util.Event,r=YAHOO.lang,U={},a=true,F=&quot;afterScroll&quot;,i=&quot;allItemsRemoved&quot;,d=&quot;beforeHide&quot;,K=&quot;beforePageChange&quot;,k=&quot;beforeScroll&quot;,Z=&quot;beforeShow&quot;,B=&quot;blur&quot;,Y=&quot;focus&quot;,c=&quot;hide&quot;,T=&quot;itemAdded&quot;,q=&quot;itemRemoved&quot;,R=&quot;itemReplaced&quot;,C=&quot;itemSelected&quot;,M=&quot;loadItems&quot;,J=&quot;navigationStateChange&quot;,j=&quot;pageChange&quot;,I=&quot;render&quot;,W=&quot;show&quot;,b=&quot;startAutoPlay&quot;,s=&quot;stopAutoPlay&quot;,L=&quot;uiUpdate&quot;;function H(t,u){var v;for(v in u){if(u.hasOwnProperty(v)){g.setStyle(t,v,u[v]);}}}function X(u,t){var v=document.createElement(u);t=t||{};if(t.className){g.addClass(v,t.className);}if(t.styles){H(v,t.styles);}if(t.parent){t.parent.app
 endChild(v);}if(t.id){v.setAttribute(&quot;id&quot;,t.id);}if(t.content){if(t.content.nodeName){v.appendChild(t.content);}else{v.innerHTML=t.content;}}return v;}function f(v,u,t){var x;if(!v){return 0;}function w(AA,z){var AB;if(z==&quot;marginRight&quot;&amp;&amp;(YAHOO.env.ua.webkit||(YAHOO.env.ua.ie&amp;&amp;YAHOO.env.ua.ie&gt;=9))){AB=parseInt(g.getStyle(AA,&quot;marginLeft&quot;),10);}else{AB=parseInt(g.getStyle(AA,z),10);}return r.isNumber(AB)?AB:0;}function y(AA,z){var AB;if(z==&quot;marginRight&quot;&amp;&amp;YAHOO.env.ua.webkit){AB=parseFloat(g.getStyle(AA,&quot;marginLeft&quot;));}else{AB=parseFloat(g.getStyle(AA,z));}return r.isNumber(AB)?AB:0;}if(typeof t==&quot;undefined&quot;){t=&quot;int&quot;;}switch(u){case&quot;height&quot;:x=v.offsetHeight;if(x&gt;0){x+=w(v,&quot;marginTop&quot;)+w(v,&quot;marginBottom&quot;);}else{x=y(v,&quot;height&quot;)+w(v,&quot;marginTop&quot;)+w(v,&quot;marginBottom&quot;)+w(v,&quot;borderTopWidth&quot;)+w(v,&quot;borderBottomWidth&
 quot;)+w(v,&quot;paddingTop&quot;)+w(v,&quot;paddingBottom&quot;);}break;case&quot;width&quot;:x=v.offsetWidth;if(x&gt;0){x+=w(v,&quot;marginLeft&quot;)+w(v,&quot;marginRight&quot;);}else{x=y(v,&quot;width&quot;)+w(v,&quot;marginLeft&quot;)+w(v,&quot;marginRight&quot;)+w(v,&quot;borderLeftWidth&quot;)+w(v,&quot;borderRightWidth&quot;)+w(v,&quot;paddingLeft&quot;)+w(v,&quot;paddingRight&quot;);}break;default:if(t==&quot;int&quot;){x=w(v,u);}else{if(t==&quot;float&quot;){x=y(v,u);}else{x=g.getStyle(v,u);}}break;}return x;}function P(x){var w=this,y,v,u=0,t=false;if(w._itemAttrCache[x]){return w._itemAttrCache[x];}if(w._itemsTable.numItems===0){return 0;}v=w._findClosestSibling(-1);if(r.isUndefined(v)){return 0;}y=g.get(v.id);if(typeof x==&quot;undefined&quot;){t=w.get(&quot;isVertical&quot;);}else{t=x==&quot;height&quot;;}if(t){u=f(y,&quot;height&quot;);}else{u=f(y,&quot;width&quot;);}if(u){w._itemAttrCache[x]=u;}return u;}function O(){var u=this,v,t;v=u.get(&quot;isVertical&q
 uot;);t=P.call(u,v?&quot;height&quot;:&quot;width&quot;);return(t*u.get(&quot;revealAmount&quot;)/100);}function o(AC){var AI=this,AA=AI._cols,AG=AI._rows,y,z,AD,AE,x,w,AB,t,v,AF,AH={},u=AI._itemsTable;AD=AI.get(&quot;isVertical&quot;);z=P.call(AI,AD?&quot;height&quot;:&quot;width&quot;);v=O.call(AI);if(AG){y=this.getPageForItem(AC);if(AD){x=Math.floor(AC/AA);AF=x;AB=AF*z;AH.top=(AB+v)+&quot;px&quot;;z=P.call(AI,&quot;width&quot;);AE=AC%AA;AF=AE;t=AF*z;AH.left=t+&quot;px&quot;;}else{AE=AC%AA;w=(y-1)*AA;AF=AE+w;t=AF*z;AH.left=(t+v)+&quot;px&quot;;z=P.call(AI,&quot;height&quot;);x=Math.floor(AC/AA);w=(y-1)*AG;AF=x-w;AB=AF*z;AH.top=AB+&quot;px&quot;;}}else{if(AD){AH.left=0;AH.top=((AC*z)+v)+&quot;px&quot;;}else{AH.top=0;AH.left=((AC*z)+v)+&quot;px&quot;;}}return AH;}function D(u){var t=this.get(&quot;numVisible&quot;);return Math.floor(u/t)*t;}function l(x){var w=this,v=0,u=0,t=w.get(&quot;isVertical&quot;)?&quot;height&quot;:&quot;width&quot;;v=P.call(w,t);u=v*x;return u;}func
 tion h(t,u){u.scrollPageBackward();e.preventDefault(t);}function m(t,u){u.scrollPageForward();e.preventDefault(t);}function p(x,u){var AA=this,AC=AA.CLASSES,t,z=AA._firstItem,y=AA.get(&quot;numItems&quot;),AB=AA.get(&quot;numVisible&quot;),w=u,v=z+AB-1;if(w&gt;=0&amp;&amp;w&lt;y){if(!r.isUndefined(AA._itemsTable.items[w])){t=g.get(AA._itemsTable.items[w].id);if(t){g.removeClass(t,AC.SELECTED_ITEM);}}}if(r.isNumber(x)){x=parseInt(x,10);x=r.isNumber(x)?x:0;}else{x=z;}if(r.isUndefined(AA._itemsTable.items[x])){x=D.call(AA,x);AA.scrollTo(x);}if(!r.isUndefined(AA._itemsTable.items[x])){t=g.get(AA._itemsTable.items[x].id);if(t){g.addClass(t,AC.SELECTED_ITEM);}}if(x&lt;z||x&gt;v){x=D.call(AA,x);AA.scrollTo(x);}}function G(u){var v=this,t=v.get(&quot;navigation&quot;);if(r.isUndefined(t)){return;}if(r.isUndefined(u)){if(!r.isUndefined(t.prev)&amp;&amp;r.isArray(t.prev)&amp;&amp;!r.isUndefined(t.prev[0])){g.setStyle(t.prev[0],&quot;visibility&quot;,&quot;visible&quot;);}if(!r.isUndef
 ined(t.next)&amp;&amp;r.isArray(t.next)&amp;&amp;!r.isUndefined(t.next[0])){g.setStyle(t.next[0],&quot;visibility&quot;,&quot;visible&quot;);}if(!r.isUndefined(v._pages)&amp;&amp;!r.isUndefined(v._pages.el)){g.setStyle(v._pages.el,&quot;visibility&quot;,&quot;visible&quot;);}}else{if(!r.isUndefined(t.prev)&amp;&amp;r.isArray(t.prev)&amp;&amp;!r.isUndefined(t.prev[0])){g.setStyle(t.prev[0],&quot;visibility&quot;,&quot;hidden&quot;);}if(!r.isUndefined(t.next)&amp;&amp;r.isArray(t.next)&amp;&amp;!r.isUndefined(t.next[0])){g.setStyle(t.next[0],&quot;visibility&quot;,&quot;hidden&quot;);}if(!r.isUndefined(v._pages)&amp;&amp;!r.isUndefined(v._pages.el)){g.setStyle(v._pages.el,&quot;visibility&quot;,&quot;hidden&quot;);}}}function n(){var v=false,y=this,u=y.CLASSES,x,t,w;if(!y._hasRendered){return;}t=y.get(&quot;navigation&quot;);w=y._firstItem+y.get(&quot;numVisible&quot;);if(t.prev){if(y.get(&quot;numItems&quot;)===0||y._firstItem===0){if(y.get(&quot;numItems&quot;)===0||!y.get(&
 quot;isCircular&quot;)){e.removeListener(t.prev,&quot;click&quot;,h);g.addClass(t.prev,u.FIRST_NAV_DISABLED);for(x=0;x&lt;y._navBtns.prev.length;x++){y._navBtns.prev[x].setAttribute(&quot;disabled&quot;,&quot;true&quot;);}y._prevEnabled=false;}else{v=!y._prevEnabled;}}else{v=!y._prevEnabled;}if(v){e.on(t.prev,&quot;click&quot;,h,y);g.removeClass(t.prev,u.FIRST_NAV_DISABLED);for(x=0;x&lt;y._navBtns.prev.length;x++){y._navBtns.prev[x].removeAttribute(&quot;disabled&quot;);}y._prevEnabled=true;}}v=false;if(t.next){if(w&gt;=y.get(&quot;numItems&quot;)){if(!y.get(&quot;isCircular&quot;)){e.removeListener(t.next,&quot;click&quot;,m);g.addClass(t.next,u.DISABLED);for(x=0;x&lt;y._navBtns.next.length;x++){y._navBtns.next[x].setAttribute(&quot;disabled&quot;,&quot;true&quot;);}y._nextEnabled=false;}else{v=!y._nextEnabled;}}else{v=!y._nextEnabled;}if(v){e.on(t.next,&quot;click&quot;,m,y);g.removeClass(t.next,u.DISABLED);for(x=0;x&lt;y._navBtns.next.length;x++){y._navBtns.next[x].remove
 Attribute(&quot;disabled&quot;);}y._nextEnabled=true;}}y.fireEvent(J,{next:y._nextEnabled,prev:y._prevEnabled});}function S(v){var w=this,t,u;if(!w._hasRendered){return;}u=w.get(&quot;numVisible&quot;);if(!r.isNumber(v)){v=Math.floor(w.get(&quot;selectedItem&quot;)/u);}t=Math.ceil(w.get(&quot;numItems&quot;)/u);w._pages.num=t;
+w._pages.cur=v;if(t&gt;w.CONFIG.MAX_PAGER_BUTTONS){w._updatePagerMenu();}else{w._updatePagerButtons();}}function N(t,u){switch(u){case&quot;height&quot;:return f(t,&quot;marginTop&quot;)+f(t,&quot;marginBottom&quot;)+f(t,&quot;paddingTop&quot;)+f(t,&quot;paddingBottom&quot;)+f(t,&quot;borderTopWidth&quot;)+f(t,&quot;borderBottomWidth&quot;);case&quot;width&quot;:return f(t,&quot;marginLeft&quot;)+f(t,&quot;marginRight&quot;)+f(t,&quot;paddingLeft&quot;)+f(t,&quot;paddingRight&quot;)+f(t,&quot;borderLeftWidth&quot;)+f(t,&quot;borderRightWidth&quot;);default:break;}return f(t,u);}function A(u){var t=this;if(!r.isObject(u)){return;}switch(u.ev){case T:t._syncUiForItemAdd(u);break;case q:t._syncUiForItemRemove(u);break;case R:t._syncUiForItemReplace(u);break;case M:t._syncUiForLazyLoading(u);break;}t.fireEvent(L);}function E(w,u){var y=this,x=y.get(&quot;currentPage&quot;),v,t=y.get(&quot;numVisible&quot;);v=parseInt(y._firstItem/t,10);if(v!=x){y.setAttributeConfig(&quot;current
 Page&quot;,{value:v});y.fireEvent(j,v);}if(y.get(&quot;selectOnScroll&quot;)){if(y.get(&quot;selectedItem&quot;)!=y._selectedItem){y.set(&quot;selectedItem&quot;,y._selectedItem);}}clearTimeout(y._autoPlayTimer);delete y._autoPlayTimer;if(y.isAutoPlayOn()){y.startAutoPlay();}y.fireEvent(F,{first:y._firstItem,last:u},y);}V.getById=function(t){return U[t]?U[t].object:false;};YAHOO.extend(V,YAHOO.util.Element,{_rows:null,_cols:null,_animObj:null,_carouselEl:null,_clipEl:null,_firstItem:0,_hasFocus:false,_hasRendered:false,_isAnimationInProgress:false,_isAutoPlayInProgress:false,_itemsTable:null,_navBtns:null,_navEl:null,_nextEnabled:true,_pages:null,_pagination:null,_prevEnabled:true,_recomputeSize:true,_itemAttrCache:null,CLASSES:{BUTTON:&quot;yui-carousel-button&quot;,CAROUSEL:&quot;yui-carousel&quot;,CAROUSEL_EL:&quot;yui-carousel-element&quot;,CONTAINER:&quot;yui-carousel-container&quot;,CONTENT:&quot;yui-carousel-content&quot;,DISABLED:&quot;yui-carousel-button-disabled&qu
 ot;,FIRST_NAV:&quot; yui-carousel-first-button&quot;,FIRST_NAV_DISABLED:&quot;yui-carousel-first-button-disabled&quot;,FIRST_PAGE:&quot;yui-carousel-nav-first-page&quot;,FOCUSSED_BUTTON:&quot;yui-carousel-button-focus&quot;,HORIZONTAL:&quot;yui-carousel-horizontal&quot;,ITEM_LOADING:&quot;yui-carousel-item-loading&quot;,MIN_WIDTH:&quot;yui-carousel-min-width&quot;,NAVIGATION:&quot;yui-carousel-nav&quot;,NEXT_NAV:&quot; yui-carousel-next-button&quot;,NEXT_PAGE:&quot;yui-carousel-next&quot;,NAV_CONTAINER:&quot;yui-carousel-buttons&quot;,PAGER_ITEM:&quot;yui-carousel-pager-item&quot;,PAGINATION:&quot;yui-carousel-pagination&quot;,PAGE_FOCUS:&quot;yui-carousel-nav-page-focus&quot;,PREV_PAGE:&quot;yui-carousel-prev&quot;,ITEM:&quot;yui-carousel-item&quot;,SELECTED_ITEM:&quot;yui-carousel-item-selected&quot;,SELECTED_NAV:&quot;yui-carousel-nav-page-selected&quot;,VERTICAL:&quot;yui-carousel-vertical&quot;,MULTI_ROW:&quot;yui-carousel-multi-row&quot;,ROW:&quot;yui-carousel-row&quot
 ;,VERTICAL_CONTAINER:&quot;yui-carousel-vertical-container&quot;,VISIBLE:&quot;yui-carousel-visible&quot;},CONFIG:{FIRST_VISIBLE:0,HORZ_MIN_WIDTH:180,MAX_PAGER_BUTTONS:5,VERT_MIN_WIDTH:115,NUM_VISIBLE:3},STRINGS:{ITEM_LOADING_CONTENT:&quot;Loading&quot;,NEXT_BUTTON_TEXT:&quot;Next Page&quot;,PAGER_PREFIX_TEXT:&quot;Go to page &quot;,PREVIOUS_BUTTON_TEXT:&quot;Previous Page&quot;},addItem:function(AA,u){var z=this,w,v,t,AB=0,y,x=z.get(&quot;numItems&quot;);if(!AA){return false;}if(r.isString(AA)||AA.nodeName){v=AA.nodeName?AA.innerHTML:AA;}else{if(r.isObject(AA)){v=AA.content;}else{return false;}}w=z.CLASSES.ITEM+(AA.className?&quot; &quot;+AA.className:&quot;&quot;);t=AA.id?AA.id:g.generateId();if(r.isUndefined(u)){z._itemsTable.items.push({item:v,className:w,id:t});y=z._itemsTable.items.length-1;}else{if(u&lt;0||u&gt;x){return false;}if(!z._itemsTable.items[u]){z._itemsTable.items[u]=undefined;AB=1;}z._itemsTable.items.splice(u,AB,{item:v,className:w,id:t});}z._itemsTable.n
 umItems++;if(x&lt;z._itemsTable.items.length){z.set(&quot;numItems&quot;,z._itemsTable.items.length);}z.fireEvent(T,{pos:u,ev:T,newPos:y});return true;},addItems:function(t){var u,w,v=true;if(!r.isArray(t)){return false;}a=false;for(u=0,w=t.length;u&lt;w;u++){if(this.addItem(t[u][0],t[u][1])===false){v=false;}}a=true;this._syncUiItems();return v;},blur:function(){this._carouselEl.blur();this.fireEvent(B);},clearItems:function(){var t=this,u=t.get(&quot;numItems&quot;);while(u&gt;0){if(!t.removeItem(0)){}if(t._itemsTable.numItems===0){t.set(&quot;numItems&quot;,0);break;}u--;}t.fireEvent(i);},focus:function(){var AC=this,x,y,z,w,AB,AD,u,v,t;if(!AC._hasRendered){return;}if(AC.isAnimating()){return;}t=AC.get(&quot;selectedItem&quot;);AD=AC.get(&quot;numVisible&quot;);u=AC.get(&quot;selectOnScroll&quot;);v=(t&gt;=0)?AC.getItem(t):null;x=AC.get(&quot;firstVisible&quot;);AB=x+AD-1;z=(t&lt;x||t&gt;AB);y=(v&amp;&amp;v.id)?g.get(v.id):null;w=AC._itemsTable;if(!u&amp;&amp;z){y=(w&amp;
 &amp;w.items&amp;&amp;w.items[x])?g.get(w.items[x].id):null;}if(y){try{y.focus();}catch(AA){}}AC.fireEvent(Y);},hide:function(){var t=this;if(t.fireEvent(d)!==false){t.removeClass(t.CLASSES.VISIBLE);G.call(t,false);t.fireEvent(c);}},init:function(w,u){var x=this,t=w,y=false,v;if(!w){return;}x._hasRendered=false;x._navBtns={prev:[],next:[]};x._pages={el:null,num:0,cur:0};x._pagination={};x._itemAttrCache={};x._itemsTable={loading:{},numItems:0,items:[],size:0};if(r.isString(w)){w=g.get(w);}else{if(!w.nodeName){return;}}V.superclass.init.call(x,w,u);v=x.get(&quot;selectedItem&quot;);if(v&gt;0){x.set(&quot;firstVisible&quot;,D.call(x,v));}if(w){if(!w.id){w.setAttribute(&quot;id&quot;,g.generateId());}y=x._parseCarousel(w);if(!y){x._createCarousel(t);}}else{w=x._createCarousel(t);}t=w.id;x.initEvents();if(y){x._parseCarouselItems();}if(v&gt;0){p.call(x,v,0);}if(!u||typeof u.isVertical==&quot;undefined&quot;){x.set(&quot;isVertical&quot;,false);}x._parseCarouselNavigation(w);x._n
 avEl=x._setupCarouselNavigation();U[t]={object:x};x._loadItems(Math.min(x.get(&quot;firstVisible&quot;)+x.get(&quot;numVisible&quot;),x.get(&quot;numItems&quot;))-1);},initAttributes:function(t){var u=this;t=t||{};V.superclass.initAttributes.call(u,t);u.setAttributeConfig(&quot;carouselEl&quot;,{validator:r.isString,value:t.carouselEl||&quot;OL&quot;});u.setAttributeConfig(&quot;carouselItemEl&quot;,{validator:r.isString,value:t.carouselItemEl||&quot;LI&quot;});u.setAttributeConfig(&quot;currentPage&quot;,{readOnly:true,value:0});u.setAttributeConfig(&quot;firstVisible&quot;,{method:u._setFirstVisible,validator:u._validateFirstVisible,value:t.firstVisible||u.CONFIG.FIRST_VISIBLE});u.setAttributeConfig(&quot;selectOnScroll&quot;,{validator:r.isBoolean,value:t.selectOnScroll||true});u.setAttributeConfig(&quot;numVisible&quot;,{setter:u._numVisibleSetter,method:u._setNumVisible,validator:u._validateNumVisible,value:t.numVisible||u.CONFIG.NUM_VISIBLE});
+u.setAttributeConfig(&quot;numItems&quot;,{method:u._setNumItems,validator:u._validateNumItems,value:u._itemsTable.numItems});u.setAttributeConfig(&quot;scrollIncrement&quot;,{validator:u._validateScrollIncrement,value:t.scrollIncrement||1});u.setAttributeConfig(&quot;selectedItem&quot;,{setter:u._selectedItemSetter,method:u._setSelectedItem,validator:r.isNumber,value:-1});u.setAttributeConfig(&quot;revealAmount&quot;,{method:u._setRevealAmount,validator:u._validateRevealAmount,value:t.revealAmount||0});u.setAttributeConfig(&quot;isCircular&quot;,{validator:r.isBoolean,value:t.isCircular||false});u.setAttributeConfig(&quot;isVertical&quot;,{method:u._setOrientation,validator:r.isBoolean,value:t.isVertical||false});u.setAttributeConfig(&quot;navigation&quot;,{method:u._setNavigation,validator:u._validateNavigation,value:t.navigation||{prev:null,next:null,page:null}});u.setAttributeConfig(&quot;animation&quot;,{validator:u._validateAnimation,value:t.animation||{speed:0,effect:
 null}});u.setAttributeConfig(&quot;autoPlay&quot;,{validator:r.isNumber,value:t.autoPlay||0});u.setAttributeConfig(&quot;autoPlayInterval&quot;,{validator:r.isNumber,value:t.autoPlayInterval||0});u.setAttributeConfig(&quot;numPages&quot;,{readOnly:true,getter:u._getNumPages});u.setAttributeConfig(&quot;lastVisible&quot;,{readOnly:true,getter:u._getLastVisible});},initEvents:function(){var v=this,u=v.CLASSES,t;v.on(&quot;keydown&quot;,v._keyboardEventHandler);v.on(F,n);v.on(T,A);v.on(q,A);v.on(R,A);v.on(C,v._focusHandler);v.on(M,A);v.on(i,function(w){v.scrollTo(0);n.call(v);S.call(v);});v.on(j,S,v);v.on(I,function(w){if(v.get(&quot;selectedItem&quot;)===null||v.get(&quot;selectedItem&quot;)&lt;=0){v.set(&quot;selectedItem&quot;,v.get(&quot;firstVisible&quot;));}n.call(v,w);S.call(v,w);v._setClipContainerSize();v.show();});v.on(&quot;selectedItemChange&quot;,function(w){p.call(v,w.newValue,w.prevValue);if(w.newValue&gt;=0){v._updateTabIndex(v.getElementForItem(w.newValue));}v.
 fireEvent(C,w.newValue);});v.on(L,function(w){n.call(v,w);S.call(v,w);});v.on(&quot;firstVisibleChange&quot;,function(w){if(!v.get(&quot;selectOnScroll&quot;)){if(w.newValue&gt;=0){v._updateTabIndex(v.getElementForItem(w.newValue));}}});v.on(&quot;click&quot;,function(w){if(v.isAutoPlayOn()){v.stopAutoPlay();}v._itemClickHandler(w);v._pagerClickHandler(w);});e.onFocus(v.get(&quot;element&quot;),function(w,y){var x=e.getTarget(w);if(x&amp;&amp;x.nodeName.toUpperCase()==&quot;A&quot;&amp;&amp;g.getAncestorByClassName(x,u.NAVIGATION)){if(t){g.removeClass(t,u.PAGE_FOCUS);}t=x.parentNode;g.addClass(t,u.PAGE_FOCUS);}else{if(t){g.removeClass(t,u.PAGE_FOCUS);}}y._hasFocus=true;y._updateNavButtons(e.getTarget(w),true);},v);e.onBlur(v.get(&quot;element&quot;),function(w,x){x._hasFocus=false;x._updateNavButtons(e.getTarget(w),false);},v);},isAnimating:function(){return this._isAnimationInProgress;},isAutoPlayOn:function(){return this._isAutoPlayInProgress;},getElementForItem:function(t
 ){var u=this;if(t&lt;0||t&gt;=u.get(&quot;numItems&quot;)){return null;}if(u._itemsTable.items[t]){return g.get(u._itemsTable.items[t].id);}return null;},getElementForItems:function(){var v=this,u=[],t;for(t=0;t&lt;v._itemsTable.numItems;t++){u.push(v.getElementForItem(t));}return u;},getItem:function(t){var u=this;if(t&lt;0||t&gt;=u.get(&quot;numItems&quot;)){return null;}if(u._itemsTable.items.length&gt;t){if(!r.isUndefined(u._itemsTable.items[t])){return u._itemsTable.items[t];}}return null;},getItems:function(){return this._itemsTable.items;},getLoadingItems:function(){return this._itemsTable.loading;},getRows:function(){return this._rows;},getCols:function(){return this._cols;},getItemPositionById:function(y){var w=this,x=w.get(&quot;numItems&quot;),u=0,t=w._itemsTable.items,v;while(u&lt;x){v=t[u]||{};if(v.id==y){return u;}u++;}return -1;},getVisibleItems:function(){var v=this,t=v.get(&quot;firstVisible&quot;),w=t+v.get(&quot;numVisible&quot;),u=[];while(t&lt;w){u.push(
 v.getElementForItem(t));t++;}return u;},removeItem:function(v){var x=this,t=x._itemsTable,w,u=x.get(&quot;numItems&quot;);if(v&lt;0||v&gt;=u){return false;}w=t.items.splice(v,1);if(w&amp;&amp;w.length==1){if(t.numItems){t.numItems--;}x.set(&quot;numItems&quot;,u-1);x.fireEvent(q,{item:w[0],pos:v,ev:q});return true;}return false;},replaceItem:function(AB,w){var AA=this,y,x,v,z=AA.get(&quot;numItems&quot;),u,t=AB;if(!AB){return false;}if(r.isString(AB)||AB.nodeName){x=AB.nodeName?AB.innerHTML:AB;}else{if(r.isObject(AB)){x=AB.content;}else{return false;}}if(r.isUndefined(w)){return false;}else{if(w&lt;0||w&gt;=z){return false;}u=AA._itemsTable.items[w];if(!u){u=AA._itemsTable.loading[w];AA._itemsTable.items[w]=undefined;}v=u.id||g.generateId();AA._itemsTable.items.splice(w,1,{item:x,className:AA.CLASSES.ITEM+(AB.className?&quot; &quot;+AB.className:&quot;&quot;),id:v});t=AA._itemsTable.items[w];}AA.fireEvent(R,{newItem:t,oldItem:u,pos:w,ev:R});return true;},replaceItems:functio
 n(t){var u,w,v=true;if(!r.isArray(t)){return false;}a=false;for(u=0,w=t.length;u&lt;w;u++){if(this.replaceItem(t[u][0],t[u][1])===false){v=false;}}a=true;this._syncUiItems();return v;},render:function(u){var w=this,t=w.CLASSES,v=w._rows;w.addClass(t.CAROUSEL);if(!w._clipEl){w._clipEl=w._createCarouselClip();w._clipEl.appendChild(w._carouselEl);}if(u){w.appendChild(w._clipEl);w.appendTo(u);}else{if(!g.inDocument(w.get(&quot;element&quot;))){return false;}w.appendChild(w._clipEl);}if(v){g.addClass(w._clipEl,t.MULTI_ROW);}if(w.get(&quot;isVertical&quot;)){w.addClass(t.VERTICAL);}else{w.addClass(t.HORIZONTAL);}if(w.get(&quot;numItems&quot;)&lt;1){return false;}w._refreshUi();return true;},scrollBackward:function(){var t=this;t.scrollTo(t._firstItem-t.get(&quot;scrollIncrement&quot;));},scrollForward:function(){var t=this;t.scrollTo(t._firstItem+t.get(&quot;scrollIncrement&quot;));},scrollPageBackward:function(){var v=this,w=v.get(&quot;isVertical&quot;),u=v._cols,x=v.get(&quot;f
 irstVisible&quot;),t=x-v.get(&quot;numVisible&quot;);if(t&lt;0){if(u){t=x-u;}}v.scrollTo(t);},scrollPageForward:function(){var u=this,t=u._firstItem+u.get(&quot;numVisible&quot;);if(t&gt;u.get(&quot;numItems&quot;)){t=0;}if(u.get(&quot;selectOnScroll&quot;)){u._selectedItem=u._getSelectedItem(t);}u.scrollTo(t);},scrollTo:function(AK,AH){var AG=this,v,AI,AA,AC,AL,AM,AN,AD,AB,w,AF,t,x,u,y,AE,z,AO,AJ=AG._itemsTable;if(AJ.numItems===0||AK==AG._firstItem||AG.isAnimating()){return;}AI=AG.get(&quot;animation&quot;);AA=AG.get(&quot;isCircular&quot;);AC=AG.get(&quot;isVertical&quot;);AB=AG._cols;w=AG._rows;AN=AG._firstItem;AF=AG.get(&quot;numItems&quot;);
+t=AG.get(&quot;numVisible&quot;);u=AG.get(&quot;currentPage&quot;);AO=function(){if(AG.isAutoPlayOn()){AG.stopAutoPlay();}};if(AK&lt;0){if(AA){if(AF%t!==0){AK=AF+(AF%t)-t-1;}else{AK=AF+AK;}}else{AO.call(AG);return;}}else{if(AF&gt;0&amp;&amp;AK&gt;AF-1){if(AG.get(&quot;isCircular&quot;)){AK=AF-AK;}else{AO.call(AG);return;}}}if(isNaN(AK)){return;}AM=(AG._firstItem&gt;AK)?&quot;backward&quot;:&quot;forward&quot;;AE=AN+t;AE=(AE&gt;AF-1)?AF-1:AE;y=AG.fireEvent(k,{dir:AM,first:AN,last:AE});if(y===false){return;}AG.fireEvent(K,{page:u});AD=AK+t-1;AG._loadItems(AD&gt;AF-1?AF-1:AD);AL=0-AK;if(w){if(AC){AL=parseInt(AL/AB,10);}else{AL=parseInt(AL/w,10);}}AG._firstItem=AK;AG.set(&quot;firstVisible&quot;,AK);if(!AH&amp;&amp;AG.get(&quot;selectOnScroll&quot;)){AG._selectedItem=AK;}AE=AK+t;AE=(AE&gt;AF-1)?AF-1:AE;x=l.call(AG,AL);v=AI.speed&gt;0;if(v){AG._animateAndSetCarouselOffset(x,AK,AE,AH);}else{AG._setCarouselOffset(x);E.call(AG,AK,AE);}},getPageForItem:function(t){return Math.ceil((t
 +1)/parseInt(this.get(&quot;numVisible&quot;),10));},getFirstVisibleOnPage:function(t){return(t-1)*this.get(&quot;numVisible&quot;);},selectPreviousItem:function(){var v=this,u=0,t=v.get(&quot;selectedItem&quot;);if(t==v._firstItem){u=t-v.get(&quot;numVisible&quot;);v._selectedItem=v._getSelectedItem(t-1);v.scrollTo(u,true);}else{u=v.get(&quot;selectedItem&quot;)-v.get(&quot;scrollIncrement&quot;);v.set(&quot;selectedItem&quot;,v._getSelectedItem(u));}},selectNextItem:function(){var u=this,t=0;t=u.get(&quot;selectedItem&quot;)+u.get(&quot;scrollIncrement&quot;);u.set(&quot;selectedItem&quot;,u._getSelectedItem(t));},show:function(){var u=this,t=u.CLASSES;if(u.fireEvent(Z)!==false){u.addClass(t.VISIBLE);G.call(u);u.fireEvent(W);}},startAutoPlay:function(){var t=this,u;if(r.isUndefined(t._autoPlayTimer)){u=t.get(&quot;autoPlayInterval&quot;);if(u&lt;=0){return;}t._isAutoPlayInProgress=true;t.fireEvent(b);t._autoPlayTimer=setTimeout(function(){t._autoScroll();},u);}},stopAutoPl
 ay:function(){var t=this;if(!r.isUndefined(t._autoPlayTimer)){clearTimeout(t._autoPlayTimer);delete t._autoPlayTimer;t._isAutoPlayInProgress=false;t.fireEvent(s);}},updatePagination:function(){var AB=this,z=AB._pagination;if(!z.el){return false;}var y=AB.get(&quot;numItems&quot;),AC=AB.get(&quot;numVisible&quot;),w=AB.get(&quot;firstVisible&quot;)+1,x=AB.get(&quot;currentPage&quot;)+1,t=AB.get(&quot;numPages&quot;),v={&quot;numVisible&quot;:AC,&quot;numPages&quot;:t,&quot;numItems&quot;:y,&quot;selectedItem&quot;:AB.get(&quot;selectedItem&quot;)+1,&quot;currentPage&quot;:x,&quot;firstVisible&quot;:w,&quot;lastVisible&quot;:AB.get(&quot;lastVisible&quot;)+1},u=z.callback||{},AA=u.scope&amp;&amp;u.obj?u.obj:AB;z.el.innerHTML=r.isFunction(u.fn)?u.fn.apply(AA,[z.template,v]):YAHOO.lang.substitute(z.template,v);},registerPagination:function(u,w,t){var v=this;v._pagination.template=u;v._pagination.callback=t||{};if(!v._pagination.el){v._pagination.el=X(&quot;DIV&quot;,{className:v
 .CLASSES.PAGINATION});if(w==&quot;before&quot;){v._navEl.insertBefore(v._pagination.el,v._navEl.firstChild);}else{v._navEl.appendChild(v._pagination.el);}v.on(&quot;itemSelected&quot;,v.updatePagination);v.on(&quot;pageChange&quot;,v.updatePagination);}v.updatePagination();},toString:function(){return Q+(this.get?&quot; (#&quot;+this.get(&quot;id&quot;)+&quot;)&quot;:&quot;&quot;);},_animateAndSetCarouselOffset:function(y,w,u){var x=this,v=x.get(&quot;animation&quot;),t=null;if(x.get(&quot;isVertical&quot;)){t=new YAHOO.util.Motion(x._carouselEl,{top:{to:y}},v.speed,v.effect);}else{t=new YAHOO.util.Motion(x._carouselEl,{left:{to:y}},v.speed,v.effect);}x._isAnimationInProgress=true;t.onComplete.subscribe(x._animationCompleteHandler,{scope:x,item:w,last:u});t.animate();},_animationCompleteHandler:function(t,u,v){v.scope._isAnimationInProgress=false;E.call(v.scope,v.item,v.last);},_autoScroll:function(){var u=this,v=u._firstItem,t;if(v&gt;=u.get(&quot;numItems&quot;)-1){if(u.ge
 t(&quot;isCircular&quot;)){t=0;}else{u.stopAutoPlay();}}else{t=v+u.get(&quot;numVisible&quot;);}u._selectedItem=u._getSelectedItem(t);u.scrollTo.call(u,t);},_createCarousel:function(u){var w=this,t=w.CLASSES,v=g.get(u);if(!v){v=X(&quot;DIV&quot;,{className:t.CAROUSEL,id:u});}if(!w._carouselEl){w._carouselEl=X(w.get(&quot;carouselEl&quot;),{className:t.CAROUSEL_EL});}return v;},_createCarouselClip:function(){return X(&quot;DIV&quot;,{className:this.CLASSES.CONTENT});},_createCarouselItem:function(v){var t,u=this;return X(u.get(&quot;carouselItemEl&quot;),{className:v.className,styles:{},content:v.content,id:v.id});},_getValidIndex:function(v){var y=this,t=y.get(&quot;isCircular&quot;),w=y.get(&quot;numItems&quot;),x=y.get(&quot;numVisible&quot;),u=w-1;if(v&lt;0){v=t?Math.ceil(w/x)*x+v:0;}else{if(v&gt;u){v=t?0:u;}}return v;},_getSelectedItem:function(x){var w=this,t=w.get(&quot;isCircular&quot;),v=w.get(&quot;numItems&quot;),u=v-1;if(x&lt;0){if(t){x=v+x;}else{x=w.get(&quot;sel
 ectedItem&quot;);}}else{if(x&gt;u){if(t){x=x-v;}else{x=w.get(&quot;selectedItem&quot;);}}}return x;},_focusHandler:function(){var t=this;if(t._hasFocus){t.focus();}},_itemClickHandler:function(x){var AA=this,y=AA.get(&quot;carouselItemEl&quot;),u=AA.get(&quot;element&quot;),v,w,z=e.getTarget(x),t=z.tagName.toUpperCase();if(t===&quot;INPUT&quot;||t===&quot;SELECT&quot;||t===&quot;TEXTAREA&quot;){return;}while(z&amp;&amp;z!=u&amp;&amp;z.id!=AA._carouselEl){v=z.nodeName;if(v.toUpperCase()==y){break;}z=z.parentNode;}if((w=AA.getItemPositionById(z.id))&gt;=0){AA.set(&quot;selectedItem&quot;,AA._getSelectedItem(w));AA.focus();}},_keyboardEventHandler:function(v){var x=this,u=e.getCharCode(v),w=e.getTarget(v),t=false;if(x.isAnimating()||w.tagName.toUpperCase()===&quot;SELECT&quot;){return;}switch(u){case 37:case 38:x.selectPreviousItem();t=true;break;case 39:case 40:x.selectNextItem();t=true;break;case 33:x.scrollPageBackward();t=true;break;case 34:x.scrollPageForward();t=true;brea
 k;}if(t){if(x.isAutoPlayOn()){x.stopAutoPlay();}e.preventDefault(v);}},_loadItems:function(v){var y=this,u=y.get(&quot;numItems&quot;),w=y.get(&quot;numVisible&quot;),x=y.get(&quot;revealAmount&quot;),z=y._itemsTable.items.length,t=y.get(&quot;lastVisible&quot;);if(z&gt;v&amp;&amp;v+1&gt;=w){z=v%w||v==t?v-v%w:v-w+1;}if(x&amp;&amp;v&lt;u-1){v++;}if(v&gt;=z&amp;&amp;(!y.getItem(z)||!y.getItem(v))){y.fireEvent(M,{ev:M,first:z,last:v,num:v-z+1});}},_pagerChangeHandler:function(u){var x=this,w=e.getTarget(u),v=w.value,t;if(v){t=x.getFirstVisibleOnPage(v);x._selectedItem=t;x.scrollTo(t);x.focus();}},_pagerClickHandler:function(z){var AB=this,v=AB.CLASSES,w=e.getTarget(z),u=w.nodeName.toUpperCase(),t,y,x,AA;if(g.hasClass(w,v.PAGER_ITEM)||g.hasClass(w.parentNode,v.PAGER_ITEM)){if(u==&quot;EM&quot;){w=w.parentNode;}t=w.href;y=t.lastIndexOf(&quot;#&quot;);x=parseInt(t.substring(y+1),10);
+if(x!=-1){AA=AB.getFirstVisibleOnPage(x);AB._selectedItem=AA;AB.scrollTo(AA);AB.focus();}e.preventDefault(z);}},_parseCarousel:function(v){var y=this,z,t,u,x,w;t=y.CLASSES;u=y.get(&quot;carouselEl&quot;);x=false;for(z=v.firstChild;z;z=z.nextSibling){if(z.nodeType==1){w=z.nodeName;if(w.toUpperCase()==u){y._carouselEl=z;g.addClass(y._carouselEl,y.CLASSES.CAROUSEL_EL);x=true;}}}return x;},_parseCarouselItems:function(){var AA=this,AC=AA.CLASSES,x=0,AB,t,v,w,u,y=AA.get(&quot;firstVisible&quot;),z=AA._carouselEl;AB=AA._rows;v=AA.get(&quot;carouselItemEl&quot;);for(t=z.firstChild;t;t=t.nextSibling){if(t.nodeType==1){u=t.nodeName;if(u.toUpperCase()==v){if(t.id){w=t.id;}else{w=g.generateId();t.setAttribute(&quot;id&quot;,w);g.addClass(t,AA.CLASSES.ITEM);}AA.addItem(t,y);y++;}}}},_parseCarouselNavigation:function(z){var AA=this,y,AB=AA.CLASSES,u,x,w,t,v=false;t=g.getElementsByClassName(AB.PREV_PAGE,&quot;*&quot;,z);if(t.length&gt;0){for(x in t){if(t.hasOwnProperty(x)){u=t[x];if(u.nod
 eName==&quot;INPUT&quot;||u.nodeName==&quot;BUTTON&quot;||u.nodeName==&quot;A&quot;){AA._navBtns.prev.push(u);}else{w=u.getElementsByTagName(&quot;INPUT&quot;);if(r.isArray(w)&amp;&amp;w.length&gt;0){AA._navBtns.prev.push(w[0]);}else{w=u.getElementsByTagName(&quot;BUTTON&quot;);if(r.isArray(w)&amp;&amp;w.length&gt;0){AA._navBtns.prev.push(w[0]);}}}}}y={prev:t};}t=g.getElementsByClassName(AB.NEXT_PAGE,&quot;*&quot;,z);if(t.length&gt;0){for(x in t){if(t.hasOwnProperty(x)){u=t[x];if(u.nodeName==&quot;INPUT&quot;||u.nodeName==&quot;BUTTON&quot;||u.nodeName==&quot;A&quot;){AA._navBtns.next.push(u);}else{w=u.getElementsByTagName(&quot;INPUT&quot;);if(r.isArray(w)&amp;&amp;w.length&gt;0){AA._navBtns.next.push(w[0]);}else{w=u.getElementsByTagName(&quot;BUTTON&quot;);if(r.isArray(w)&amp;&amp;w.length&gt;0){AA._navBtns.next.push(w[0]);}}}}}if(y){y.next=t;}else{y={next:t};}}if(y){AA.set(&quot;navigation&quot;,y);v=true;}return v;},_refreshUi:function(){var x=this,y=x.get(&quot;isVertic
 al&quot;),AA=x.get(&quot;firstVisible&quot;),u,v,z,t,w;if(x._itemsTable.numItems&lt;1){return;}w=P.call(x,y?&quot;height&quot;:&quot;width&quot;);v=x._itemsTable.items[AA].id;w=y?f(v,&quot;width&quot;):f(v,&quot;height&quot;);g.setStyle(x._carouselEl,y?&quot;width&quot;:&quot;height&quot;,w+&quot;px&quot;);x._hasRendered=true;x.fireEvent(I);},_setCarouselOffset:function(v){var t=this,u;u=t.get(&quot;isVertical&quot;)?&quot;top&quot;:&quot;left&quot;;g.setStyle(t._carouselEl,u,v+&quot;px&quot;);},_setupCarouselNavigation:function(){var y=this,w,u,t,AA,x,z,v;t=y.CLASSES;x=g.getElementsByClassName(t.NAVIGATION,&quot;DIV&quot;,y.get(&quot;element&quot;));if(x.length===0){x=X(&quot;DIV&quot;,{className:t.NAVIGATION});y.insertBefore(x,g.getFirstChild(y.get(&quot;element&quot;)));}else{x=x[0];}y._pages.el=X(&quot;UL&quot;);x.appendChild(y._pages.el);AA=y.get(&quot;navigation&quot;);if(r.isString(AA.prev)||r.isArray(AA.prev)){if(r.isString(AA.prev)){AA.prev=[AA.prev];}for(w in AA.pr
 ev){if(AA.prev.hasOwnProperty(w)){y._navBtns.prev.push(g.get(AA.prev[w]));}}}else{v=X(&quot;SPAN&quot;,{className:t.BUTTON+t.FIRST_NAV});g.setStyle(v,&quot;visibility&quot;,&quot;visible&quot;);w=g.generateId();v.innerHTML='&lt;button type=&quot;button&quot; '+'id=&quot;'+w+'&quot; name=&quot;'+y.STRINGS.PREVIOUS_BUTTON_TEXT+'&quot;&gt;'+y.STRINGS.PREVIOUS_BUTTON_TEXT+&quot;&lt;/button&gt;&quot;;x.appendChild(v);w=g.get(w);y._navBtns.prev=[w];u={prev:[v]};}if(r.isString(AA.next)||r.isArray(AA.next)){if(r.isString(AA.next)){AA.next=[AA.next];}for(w in AA.next){if(AA.next.hasOwnProperty(w)){y._navBtns.next.push(g.get(AA.next[w]));}}}else{z=X(&quot;SPAN&quot;,{className:t.BUTTON+t.NEXT_NAV});g.setStyle(z,&quot;visibility&quot;,&quot;visible&quot;);w=g.generateId();z.innerHTML='&lt;button type=&quot;button&quot; '+'id=&quot;'+w+'&quot; name=&quot;'+y.STRINGS.NEXT_BUTTON_TEXT+'&quot;&gt;'+y.STRINGS.NEXT_BUTTON_TEXT+&quot;&lt;/button&gt;&quot;;x.appendChild(z);w=g.get(w);y._navBtn
 s.next=[w];if(u){u.next=[z];}else{u={next:[z]};}}if(u){y.set(&quot;navigation&quot;,u);}return x;},_setClipContainerSize:function(t,v){var AB=this,z=AB.get(&quot;isVertical&quot;),AD=AB._rows,x=AB._cols,AA=AB.get(&quot;revealAmount&quot;),u=P.call(AB,&quot;height&quot;),w=P.call(AB,&quot;width&quot;),AC,y;AB._recomputeSize=(AC===0);if(AB._recomputeSize){AB._hasRendered=false;return;}t=t||AB._clipEl;if(AD){AC=u*AD;y=w*x;}else{v=v||AB.get(&quot;numVisible&quot;);if(z){AC=u*v;}else{y=w*v;}}AA=O.call(AB);if(z){AC+=(AA*2);}else{y+=(AA*2);}if(z){AC+=N(AB._carouselEl,&quot;height&quot;);g.setStyle(t,&quot;height&quot;,AC+&quot;px&quot;);if(x){y+=N(AB._carouselEl,&quot;width&quot;);g.setStyle(t,&quot;width&quot;,y+(0)+&quot;px&quot;);}}else{y+=N(AB._carouselEl,&quot;width&quot;);g.setStyle(t,&quot;width&quot;,y+&quot;px&quot;);if(AD){AC+=N(AB._carouselEl,&quot;height&quot;);g.setStyle(t,&quot;height&quot;,AC+&quot;px&quot;);}}if(t){AB._setContainerSize(t);}},_setContainerSize:functi
 on(u,v){var y=this,t=y.CONFIG,AB=y.CLASSES,x,AA,w,z;x=y.get(&quot;isVertical&quot;);AA=y._rows;w=y._cols;u=u||y._clipEl;v=v||(x?&quot;height&quot;:&quot;width&quot;);z=parseFloat(g.getStyle(u,v),10);z=r.isNumber(z)?z:0;if(x){z+=N(y._carouselEl,&quot;height&quot;)+f(y._navEl,&quot;height&quot;);}else{z+=N(y._carouselEl,&quot;width&quot;);}if(!x){if(z&lt;t.HORZ_MIN_WIDTH){z=t.HORZ_MIN_WIDTH;y.addClass(AB.MIN_WIDTH);}}y.setStyle(v,z+&quot;px&quot;);if(x){z=P.call(y,&quot;width&quot;);if(w){z=z*w;}g.setStyle(y._carouselEl,&quot;width&quot;,z+&quot;px&quot;);if(z&lt;t.VERT_MIN_WIDTH){z=t.VERT_MIN_WIDTH;y.addClass(AB.MIN_WIDTH);}y.setStyle(&quot;width&quot;,z+&quot;px&quot;);}else{z=P.call(y,&quot;height&quot;);if(AA){z=z*AA;}g.setStyle(y._carouselEl,&quot;height&quot;,z+&quot;px&quot;);}},_setFirstVisible:function(u){var t=this;if(u&gt;=0&amp;&amp;u&lt;t.get(&quot;numItems&quot;)){t.scrollTo(u);}else{u=t.get(&quot;firstVisible&quot;);}return u;},_setNavigation:function(t){var u=t
 his;if(t.prev){e.on(t.prev,&quot;click&quot;,h,u);}if(t.next){e.on(t.next,&quot;click&quot;,m,u);}},_setNumVisible:function(u){var t=this;t._setClipContainerSize(t._clipEl,u);},_numVisibleSetter:function(v){var u=this,t=v;if(r.isArray(v)){u._cols=v[0];u._rows=v[1];t=v[0]*v[1];}return t;},_selectedItemSetter:function(u){var t=this;return(u&lt;t.get(&quot;numItems&quot;))?u:0;},_setNumItems:function(v){var u=this,t=u._itemsTable.numItems;if(r.isArray(u._itemsTable.items)){if(u._itemsTable.items.length!=t){t=u._itemsTable.items.length;u._itemsTable.numItems=t;}}if(v&lt;t){while(t&gt;v){u.removeItem(t-1);t--;}}return v;},_setOrientation:function(v){var u=this,t=u.CLASSES;if(v){u.replaceClass(t.HORIZONTAL,t.VERTICAL);}else{u.replaceClass(t.VERTICAL,t.HORIZONTAL);}return v;},_setRevealAmount:function(u){var t=this;if(u&gt;=0&amp;&amp;u&lt;=100){u=parseInt(u,10);u=r.isNumber(u)?u:0;t._setClipContainerSize();}else{u=t.get(&quot;revealAmount&quot;);}return u;},_setSelectedItem:functi
 on(t){this._selectedItem=t;},_getNumPages:function(){return Math.ceil(parseInt(this.get(&quot;numItems&quot;),10)/parseInt(this.get(&quot;numVisible&quot;),10));
+},_getLastVisible:function(){var t=this;return t.get(&quot;currentPage&quot;)+1==t.get(&quot;numPages&quot;)?t.get(&quot;numItems&quot;)-1:t.get(&quot;firstVisible&quot;)+t.get(&quot;numVisible&quot;)-1;},_syncUiForItemAdd:function(w){var x,AC=this,z=AC._carouselEl,t,AD,v=AC._itemsTable,u,y,AA,AB;y=r.isUndefined(w.pos)?w.newPos||v.numItems-1:w.pos;if(!u){AD=v.items[y]||{};t=AC._createCarouselItem({className:AD.className,styles:AD.styles,content:AD.item,id:AD.id,pos:y});if(r.isUndefined(w.pos)){if(!r.isUndefined(v.loading[y])){u=v.loading[y];}if(u){z.replaceChild(t,u);delete v.loading[y];}else{z.appendChild(t);}}else{if(!r.isUndefined(v.items[w.pos+1])){AA=g.get(v.items[w.pos+1].id);}if(AA){z.insertBefore(t,AA);}else{}}}else{if(r.isUndefined(w.pos)){if(!g.isAncestor(AC._carouselEl,u)){z.appendChild(u);}}else{if(!g.isAncestor(z,u)){if(!r.isUndefined(v.items[w.pos+1])){z.insertBefore(u,g.get(v.items[w.pos+1].id));}}}}if(!AC._hasRendered){AC._refreshUi();}if(AC.get(&quot;selecte
 dItem&quot;)&lt;0){AC.set(&quot;selectedItem&quot;,AC.get(&quot;firstVisible&quot;));}AC._syncUiItems();},_syncUiForItemReplace:function(z){var y=this,v=y._carouselEl,t=y._itemsTable,AA=z.pos,x=z.newItem,u=z.oldItem,w;w=y._createCarouselItem({className:x.className,styles:x.styles,content:x.item,id:u.id});if((u=g.get(u.id))){u.className=x.className;u.styles=x.styles;u.innerHTML=x.item;t.items[AA]=w;if(t.loading[AA]){t.numItems++;delete t.loading[AA];}}},_syncUiForItemRemove:function(y){var x=this,t=x._carouselEl,v,w,u,z;u=x.get(&quot;numItems&quot;);w=y.item;z=y.pos;if(w&amp;&amp;(v=g.get(w.id))){if(v&amp;&amp;g.isAncestor(t,v)){e.purgeElement(v,true);t.removeChild(v);}if(x.get(&quot;selectedItem&quot;)==z){z=z&gt;=u?u-1:z;}}else{}x._syncUiItems();},_findClosestSibling:function(y){var x=this,u=x._itemsTable,t=u.items.length,v=y,w;while(v&lt;t&amp;&amp;!w){w=u.items[++v];}return w;},_syncUiForLazyLoading:function(x){var AD=this,AA=AD._carouselEl,v=AD._itemsTable,z=v.items.leng
 th,AC=AD._findClosestSibling(x.last),AB=x.last,y=AB-AD.get(&quot;numVisible&quot;)+1,t,u;for(var w=y;w&lt;=AB;w++){if(!v.loading[w]&amp;&amp;!v.items[w]){t=AD._createCarouselItem({className:AD.CLASSES.ITEM+&quot; &quot;+AD.CLASSES.ITEM_LOADING,content:AD.STRINGS.ITEM_LOADING_CONTENT,id:g.generateId()});if(t){if(AC){AC=g.get(AC.id);if(AC){AA.insertBefore(t,AC);}else{}}else{AA.appendChild(t);}}v.loading[w]=t;}}AD._syncUiItems();},_syncUiItems:function(){if(!a){return;}var x,AB=this,z=AB.get(&quot;numItems&quot;),w,v=AB._itemsTable,y=v.items,t=v.loading,AC,AA,u=false;for(w=0;w&lt;z;w++){AC=y[w]||t[w];if(AC&amp;&amp;AC.id){AA=o.call(AB,w);AC.styles=AC.styles||{};for(x in AA){if(AC.styles[x]!==AA[x]){u=true;AC.styles[x]=AA[x];}}if(u){H(g.get(AC.id),AA);}u=false;}}},_updateNavButtons:function(x,u){var v,t=this.CLASSES,y,w=x.parentNode;if(!w){return;}y=w.parentNode;if(x.nodeName.toUpperCase()==&quot;BUTTON&quot;&amp;&amp;g.hasClass(w,t.BUTTON)){if(u){if(y){v=g.getChildren(y);if(v){
 g.removeClass(v,t.FOCUSSED_BUTTON);}}g.addClass(w,t.FOCUSSED_BUTTON);}else{g.removeClass(w,t.FOCUSSED_BUTTON);}}},_updatePagerButtons:function(){if(!a){return;}var AB=this,z=AB.CLASSES,AA=AB._pages.cur,t,y,w,AC,u=AB.get(&quot;numVisible&quot;),x=AB._pages.num,v=AB._pages.el;if(x===0||!v){return;}g.setStyle(v,&quot;visibility&quot;,&quot;hidden&quot;);while(v.firstChild){v.removeChild(v.firstChild);}for(w=0;w&lt;x;w++){t=document.createElement(&quot;LI&quot;);if(w===0){g.addClass(t,z.FIRST_PAGE);}if(w==AA){g.addClass(t,z.SELECTED_NAV);}y=&quot;&lt;a class=&quot;+z.PAGER_ITEM+' href=&quot;#'+(w+1)+'&quot; tabindex=&quot;0&quot;&gt;&lt;em&gt;'+AB.STRINGS.PAGER_PREFIX_TEXT+&quot; &quot;+(w+1)+&quot;&lt;/em&gt;&lt;/a&gt;&quot;;t.innerHTML=y;v.appendChild(t);}g.setStyle(v,&quot;visibility&quot;,&quot;visible&quot;);},_updatePagerMenu:function(){var AB=this,z=AB.CLASSES,AA=AB._pages.cur,u,x,AC,v=AB.get(&quot;numVisible&quot;),y=AB._pages.num,w=AB._pages.el,t;if(y===0||!w){return;}t
 =document.createElement(&quot;SELECT&quot;);if(!t){return;}g.setStyle(w,&quot;visibility&quot;,&quot;hidden&quot;);while(w.firstChild){w.removeChild(w.firstChild);}for(x=0;x&lt;y;x++){u=document.createElement(&quot;OPTION&quot;);u.value=x+1;u.innerHTML=AB.STRINGS.PAGER_PREFIX_TEXT+&quot; &quot;+(x+1);if(x==AA){u.setAttribute(&quot;selected&quot;,&quot;selected&quot;);}t.appendChild(u);}u=document.createElement(&quot;FORM&quot;);if(!u){}else{u.appendChild(t);w.appendChild(u);}e.addListener(t,&quot;change&quot;,AB._pagerChangeHandler,this,true);g.setStyle(w,&quot;visibility&quot;,&quot;visible&quot;);},_updateTabIndex:function(t){var u=this;if(t){if(u._focusableItemEl){u._focusableItemEl.tabIndex=-1;}u._focusableItemEl=t;t.tabIndex=0;}},_validateAnimation:function(t){var u=true;if(r.isObject(t)){if(t.speed){u=u&amp;&amp;r.isNumber(t.speed);}if(t.effect){u=u&amp;&amp;r.isFunction(t.effect);}else{if(!r.isUndefined(YAHOO.util.Easing)){t.effect=YAHOO.util.Easing.easeOut;}}}else{u=
 false;}return u;},_validateFirstVisible:function(v){var u=this,t=u.get(&quot;numItems&quot;);if(r.isNumber(v)){if(t===0&amp;&amp;v==t){return true;}else{return(v&gt;=0&amp;&amp;v&lt;t);}}return false;},_validateNavigation:function(t){var u;if(!r.isObject(t)){return false;}if(t.prev){if(!r.isArray(t.prev)){return false;}for(u in t.prev){if(t.prev.hasOwnProperty(u)){if(!r.isString(t.prev[u].nodeName)){return false;}}}}if(t.next){if(!r.isArray(t.next)){return false;}for(u in t.next){if(t.next.hasOwnProperty(u)){if(!r.isString(t.next[u].nodeName)){return false;}}}}return true;},_validateNumItems:function(t){return r.isNumber(t)&amp;&amp;(t&gt;=0);},_validateNumVisible:function(t){var u=false;if(r.isNumber(t)){u=t&gt;0&amp;&amp;t&lt;=this.get(&quot;numItems&quot;);}else{if(r.isArray(t)){if(r.isNumber(t[0])&amp;&amp;r.isNumber(t[1])){u=t[0]*t[1]&gt;0&amp;&amp;t.length==2;}}}return u;},_validateRevealAmount:function(t){var u=false;if(r.isNumber(t)){u=t&gt;=0&amp;&amp;t&lt;100;}retu
 rn u;},_validateScrollIncrement:function(t){var u=false;if(r.isNumber(t)){u=(t&gt;0&amp;&amp;t&lt;this.get(&quot;numItems&quot;));}return u;}});})();YAHOO.register(&quot;carousel&quot;,YAHOO.widget.Carousel,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});YAHOO.register(&quot;carousel&quot;,YAHOO.widget.Carousel,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuichartschartsminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/charts/charts-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/charts/charts-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/charts/charts-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,9 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+YAHOO.widget.Chart=function(d,a,j,g){this._type=d;this._dataSource=j;var f={align:&quot;&quot;,allowNetworking:&quot;&quot;,allowScriptAccess:&quot;&quot;,base:&quot;&quot;,bgcolor:&quot;&quot;,menu:&quot;&quot;,name:&quot;&quot;,quality:&quot;&quot;,salign:&quot;&quot;,scale:&quot;&quot;,tabindex:&quot;&quot;,wmode:&quot;&quot;};var b={fixedAttributes:{allowScriptAccess:&quot;always&quot;},flashVars:{allowedDomain:document.location.hostname},backgroundColor:&quot;#ffffff&quot;,host:this,version:9.045};for(var c in g){if(f.hasOwnProperty(c)){b.fixedAttributes[c]=g[c];}else{b[c]=g[c];}}this._id=b.id=b.id||YAHOO.util.Dom.generateId(null,&quot;yuigen&quot;);this._swfURL=YAHOO.widget.Chart.SWFURL;this._containerID=a;this._attributes=b;this._swfEmbed=new YAHOO.widget.SWF(a,YAHOO.widget.Chart.SWFURL,b);this._swf=this._swfEmbed.swf;this._swfEmbed.subscribe(&quot;swfReady&quot;,this._eventHandler,this,true);try{this.createEvent(&quot;contentReady&quot;);}catch(h){}this.createEvent(&
 quot;itemMouseOverEvent&quot;);this.createEvent(&quot;itemMouseOutEvent&quot;);this.createEvent(&quot;itemClickEvent&quot;);this.createEvent(&quot;itemDoubleClickEvent&quot;);this.createEvent(&quot;itemDragStartEvent&quot;);this.createEvent(&quot;itemDragEvent&quot;);this.createEvent(&quot;itemDragEndEvent&quot;);};YAHOO.extend(YAHOO.widget.Chart,YAHOO.util.AttributeProvider,{_type:null,_pollingID:null,_pollingInterval:null,_dataTipFunction:null,_legendLabelFunction:null,_seriesFunctions:null,toString:function(){return&quot;Chart &quot;+this._id;},setStyle:function(a,b){b=YAHOO.lang.JSON.stringify(b);this._swf.setStyle(a,b);},setStyles:function(a){a=YAHOO.lang.JSON.stringify(a);this._swf.setStyles(a);},setSeriesStyles:function(b){for(var a=0;a&lt;b.length;a++){b[a]=YAHOO.lang.JSON.stringify(b[a]);}this._swf.setSeriesStyles(b);},destroy:function(){if(this._dataSource!==null){if(this._pollingID!==null){this._dataSource.clearInterval(this._pollingID);this._pollingID=null;}}if(t
 his._dataTipFunction){YAHOO.widget.Chart.removeProxyFunction(this._dataTipFunction);}if(this._legendLabelFunction){YAHOO.widget.Chart.removeProxyFunction(this._legendLabelFunction);}if(this._swf){var b=YAHOO.util.Dom.get(this._containerID);b.removeChild(this._swf);}var a=this._id;for(var c in this){if(YAHOO.lang.hasOwnProperty(this,c)){this[c]=null;}}},_initAttributes:function(a){this.setAttributeConfig(&quot;altText&quot;,{method:this._setAltText,getter:this._getAltText});this.setAttributeConfig(&quot;swfURL&quot;,{getter:this._getSWFURL});this.setAttributeConfig(&quot;request&quot;,{method:this._setRequest,getter:this._getRequest});this.setAttributeConfig(&quot;dataSource&quot;,{method:this._setDataSource,getter:this._getDataSource});this.setAttributeConfig(&quot;series&quot;,{method:this._setSeriesDefs,getter:this._getSeriesDefs});this.setAttributeConfig(&quot;categoryNames&quot;,{validator:YAHOO.lang.isArray,method:this._setCategoryNames,getter:this._getCategoryNames});t
 his.setAttributeConfig(&quot;dataTipFunction&quot;,{method:this._setDataTipFunction,getter:this._getDataTipFunction});this.setAttributeConfig(&quot;legendLabelFunction&quot;,{method:this._setLegendLabelFunction,getter:this._getLegendLabelFunction});this.setAttributeConfig(&quot;polling&quot;,{method:this._setPolling,getter:this._getPolling});},_eventHandler:function(a){if(a.type==&quot;swfReady&quot;){this._swf=this._swfEmbed._swf;this._loadHandler();this.fireEvent(&quot;contentReady&quot;);}},_loadHandler:function(){if(!this._swf||!this._swf.setType){return;}this._swf.setType(this._type);if(this._attributes.style){var a=this._attributes.style;this.setStyles(a);}this._initialized=false;this._initAttributes(this._attributes);this.setAttributes(this._attributes,true);this._initialized=true;if(this._dataSource){this.set(&quot;dataSource&quot;,this._dataSource);}},refreshData:function(){if(!this._initialized){return;}if(this._dataSource!==null){if(this._pollingID!==null){this._d
 ataSource.clearInterval(this._pollingID);this._pollingID=null;}if(this._pollingInterval&gt;0){this._pollingID=this._dataSource.setInterval(this._pollingInterval,this._request,this._loadDataHandler,this);}this._dataSource.sendRequest(this._request,this._loadDataHandler,this);}},_loadDataHandler:function(d,c,m){if(this._swf){if(m){}else{var j;if(this._seriesFunctions){var k=this._seriesFunctions.length;for(j=0;j&lt;k;j++){YAHOO.widget.Chart.removeProxyFunction(this._seriesFunctions[j]);}this._seriesFunctions=null;}this._seriesFunctions=[];var g=[];var f=0;var n=null;if(this._seriesDefs!==null){f=this._seriesDefs.length;for(j=0;j&lt;f;j++){n=this._seriesDefs[j];var b={};for(var a in n){if(YAHOO.lang.hasOwnProperty(n,a)){if(a==&quot;style&quot;){if(n.style!==null){b.style=YAHOO.lang.JSON.stringify(n.style);}}else{if(a==&quot;labelFunction&quot;){if(n.labelFunction!==null){b.labelFunction=YAHOO.widget.Chart.getFunctionReference(n.labelFunction);this._seriesFunctions.push(b.labelF
 unction);}}else{if(a==&quot;dataTipFunction&quot;){if(n.dataTipFunction!==null){b.dataTipFunction=YAHOO.widget.Chart.getFunctionReference(n.dataTipFunction);this._seriesFunctions.push(b.dataTipFunction);}}else{if(a==&quot;legendLabelFunction&quot;){if(n.legendLabelFunction!==null){b.legendLabelFunction=YAHOO.widget.Chart.getFunctionReference(n.legendLabelFunction);this._seriesFunctions.push(b.legendLabelFunction);}}else{b[a]=n[a];}}}}}}g.push(b);}}if(f&gt;0){for(j=0;j&lt;f;j++){n=g[j];if(!n.type){n.type=this._type;}n.dataProvider=c.results;}}else{var h={type:this._type,dataProvider:c.results};g.push(h);}try{if(this._swf.setDataProvider){this._swf.setDataProvider(g);}}catch(l){this._swf.setDataProvider(g);}}}},_request:&quot;&quot;,_getRequest:function(){return this._request;},_setRequest:function(a){this._request=a;this.refreshData();},_dataSource:null,_getDataSource:function(){return this._dataSource;},_setDataSource:function(a){this._dataSource=a;this.refreshData();},_seri
 esDefs:null,_getSeriesDefs:function(){return this._seriesDefs;},_setSeriesDefs:function(a){this._seriesDefs=a;this.refreshData();},_getCategoryNames:function(){return this._swf.getCategoryNames();},_setCategoryNames:function(a){this._swf.setCategoryNames(a);},_setDataTipFunction:function(a){if(this._dataTipFunction){YAHOO.widget.Chart.removeProxyFunction(this._dataTipFunction);}if(a){this._dataTipFunction=a=YAHOO.widget.Chart.getFunctionReference(a);}this._swf.setDataTipFunction(a);},_setLegendLabelFunction:function(a){if(this._legendLabelFunction){YAHOO.widget.Chart.removeProxyFunction(this._legendLabelFunction);
+}if(a){this._legendLabelFunction=a=YAHOO.widget.Chart.getFunctionReference(a);}this._swf.setLegendLabelFunction(a);},_getLegendLabelFunction:function(){return this._legendLabelFunction;},_getPolling:function(){return this._pollingInterval;},_setPolling:function(a){this._pollingInterval=a;this.refreshData();},_swfEmbed:null,_swfURL:null,_containerID:null,_swf:null,_id:null,_initialized:false,_attributes:null,set:function(a,b){this._attributes[a]=b;YAHOO.widget.Chart.superclass.set.call(this,a,b);},_getSWFURL:function(){return this._swfURL;},_getAltText:function(){return this._swf.getAltText();},_setAltText:function(a){this._swf.setAltText(a);}});YAHOO.widget.Chart.proxyFunctionCount=0;YAHOO.widget.Chart.createProxyFunction=function(c,b){var b=b||null;var a=YAHOO.widget.Chart.proxyFunctionCount;YAHOO.widget.Chart[&quot;proxyFunction&quot;+a]=function(){return c.apply(b,arguments);};YAHOO.widget.Chart.proxyFunctionCount++;return&quot;YAHOO.widget.Chart.proxyFunction&quot;+a.toS
 tring();};YAHOO.widget.Chart.getFunctionReference=function(b){if(typeof b==&quot;function&quot;){b=YAHOO.widget.Chart.createProxyFunction(b);}else{if(b.func&amp;&amp;typeof b.func==&quot;function&quot;){var a=[b.func];if(b.scope&amp;&amp;typeof b.scope==&quot;object&quot;){a.push(b.scope);}b=YAHOO.widget.Chart.createProxyFunction.apply(this,a);}}return b;};YAHOO.widget.Chart.removeProxyFunction=function(a){if(!a||a.indexOf(&quot;YAHOO.widget.Chart.proxyFunction&quot;)&lt;0){return;}a=a.substr(26);YAHOO.widget.Chart[a]=null;};YAHOO.widget.Chart.SWFURL=&quot;assets/charts.swf&quot;;YAHOO.widget.PieChart=function(a,c,b){YAHOO.widget.PieChart.superclass.constructor.call(this,&quot;pie&quot;,a,c,b);};YAHOO.lang.extend(YAHOO.widget.PieChart,YAHOO.widget.Chart,{_initAttributes:function(a){YAHOO.widget.PieChart.superclass._initAttributes.call(this,a);this.setAttributeConfig(&quot;dataField&quot;,{validator:YAHOO.lang.isString,method:this._setDataField,getter:this._getDataField});thi
 s.setAttributeConfig(&quot;categoryField&quot;,{validator:YAHOO.lang.isString,method:this._setCategoryField,getter:this._getCategoryField});},_getDataField:function(){return this._swf.getDataField();},_setDataField:function(a){this._swf.setDataField(a);},_getCategoryField:function(){return this._swf.getCategoryField();},_setCategoryField:function(a){this._swf.setCategoryField(a);}});YAHOO.widget.CartesianChart=function(c,a,d,b){YAHOO.widget.CartesianChart.superclass.constructor.call(this,c,a,d,b);};YAHOO.lang.extend(YAHOO.widget.CartesianChart,YAHOO.widget.Chart,{_xAxisLabelFunctions:[],_yAxisLabelFunctions:[],destroy:function(){this._removeAxisFunctions(this._xAxisLabelFunctions);this._removeAxisFunctions(this._yAxisLabelFunctions);YAHOO.widget.CartesianChart.superclass.destroy.call(this);},_initAttributes:function(a){YAHOO.widget.CartesianChart.superclass._initAttributes.call(this,a);this.setAttributeConfig(&quot;xField&quot;,{validator:YAHOO.lang.isString,method:this._set
 XField,getter:this._getXField});this.setAttributeConfig(&quot;yField&quot;,{validator:YAHOO.lang.isString,method:this._setYField,getter:this._getYField});this.setAttributeConfig(&quot;xAxis&quot;,{method:this._setXAxis});this.setAttributeConfig(&quot;xAxes&quot;,{method:this._setXAxes});this.setAttributeConfig(&quot;yAxis&quot;,{method:this._setYAxis});this.setAttributeConfig(&quot;yAxes&quot;,{method:this._setYAxes});this.setAttributeConfig(&quot;constrainViewport&quot;,{method:this._setConstrainViewport});},_getXField:function(){return this._swf.getHorizontalField();},_setXField:function(a){this._swf.setHorizontalField(a);},_getYField:function(){return this._swf.getVerticalField();},_setYField:function(a){this._swf.setVerticalField(a);},_getClonedAxis:function(a){var b={};for(var c in a){if(c==&quot;labelFunction&quot;){if(a.labelFunction&amp;&amp;a.labelFunction!==null){b.labelFunction=YAHOO.widget.Chart.getFunctionReference(a.labelFunction);}}else{b[c]=a[c];}}return b;},
 _removeAxisFunctions:function(c){if(c&amp;&amp;c.length&gt;0){var a=c.length;for(var b=0;b&lt;a;b++){if(c[b]!==null){YAHOO.widget.Chart.removeProxyFunction(c[b]);}}c=[];}},_setXAxis:function(a){if(a.position!=&quot;bottom&quot;&amp;&amp;a.position!=&quot;top&quot;){a.position=&quot;bottom&quot;;}this._removeAxisFunctions(this._xAxisLabelFunctions);a=this._getClonedAxis(a);this._xAxisLabelFunctions.push(a.labelFunction);this._swf.setHorizontalAxis(a);},_setXAxes:function(c){this._removeAxisFunctions(this._xAxisLabelFunctions);var a=c.length;for(var b=0;b&lt;a;b++){if(c[b].position==&quot;left&quot;){c[b].position=&quot;bottom&quot;;}c[b]=this._getClonedAxis(c[b]);if(c[b].labelFunction){this._xAxisLabelFunctions.push(c[b].labelFunction);}this._swf.setHorizontalAxis(c[b]);}},_setYAxis:function(a){this._removeAxisFunctions(this._yAxisLabelFunctions);a=this._getClonedAxis(a);this._yAxisLabelFunctions.push(a.labelFunction);this._swf.setVerticalAxis(a);},_setYAxes:function(c){this.
 _removeAxisFunctions(this._yAxisLabelFunctions);var a=c.length;for(var b=0;b&lt;a;b++){c[b]=this._getClonedAxis(c[b]);if(c[b].labelFunction){this._yAxisLabelFunctions.push(c[b].labelFunction);}this._swf.setVerticalAxis(c[b]);}},_setConstrainViewport:function(a){this._swf.setConstrainViewport(a);},setSeriesStylesByIndex:function(a,b){b=YAHOO.lang.JSON.stringify(b);if(this._swf&amp;&amp;this._swf.setSeriesStylesByIndex){this._swf.setSeriesStylesByIndex(a,b);}}});YAHOO.widget.LineChart=function(a,c,b){YAHOO.widget.LineChart.superclass.constructor.call(this,&quot;line&quot;,a,c,b);};YAHOO.lang.extend(YAHOO.widget.LineChart,YAHOO.widget.CartesianChart);YAHOO.widget.ColumnChart=function(a,c,b){YAHOO.widget.ColumnChart.superclass.constructor.call(this,&quot;column&quot;,a,c,b);};YAHOO.lang.extend(YAHOO.widget.ColumnChart,YAHOO.widget.CartesianChart);YAHOO.widget.BarChart=function(a,c,b){YAHOO.widget.BarChart.superclass.constructor.call(this,&quot;bar&quot;,a,c,b);};YAHOO.lang.exten
 d(YAHOO.widget.BarChart,YAHOO.widget.CartesianChart);YAHOO.widget.StackedColumnChart=function(a,c,b){YAHOO.widget.StackedColumnChart.superclass.constructor.call(this,&quot;stackcolumn&quot;,a,c,b);};YAHOO.lang.extend(YAHOO.widget.StackedColumnChart,YAHOO.widget.CartesianChart);YAHOO.widget.StackedBarChart=function(a,c,b){YAHOO.widget.StackedBarChart.superclass.constructor.call(this,&quot;stackbar&quot;,a,c,b);
+};YAHOO.lang.extend(YAHOO.widget.StackedBarChart,YAHOO.widget.CartesianChart);YAHOO.widget.Axis=function(){};YAHOO.widget.Axis.prototype={type:null,reverse:false,labelFunction:null,labelSpacing:2,title:null};YAHOO.widget.NumericAxis=function(){YAHOO.widget.NumericAxis.superclass.constructor.call(this);};YAHOO.lang.extend(YAHOO.widget.NumericAxis,YAHOO.widget.Axis,{type:&quot;numeric&quot;,minimum:NaN,maximum:NaN,majorUnit:NaN,minorUnit:NaN,snapToUnits:true,stackingEnabled:false,alwaysShowZero:true,scale:&quot;linear&quot;,roundMajorUnit:true,calculateByLabelSize:true,position:&quot;left&quot;,adjustMaximumByMajorUnit:true,adjustMinimumByMajorUnit:true});YAHOO.widget.TimeAxis=function(){YAHOO.widget.TimeAxis.superclass.constructor.call(this);};YAHOO.lang.extend(YAHOO.widget.TimeAxis,YAHOO.widget.Axis,{type:&quot;time&quot;,minimum:null,maximum:null,majorUnit:NaN,majorTimeUnit:null,minorUnit:NaN,minorTimeUnit:null,snapToUnits:true,stackingEnabled:false,calculateByLabelSize:tru
 e});YAHOO.widget.CategoryAxis=function(){YAHOO.widget.CategoryAxis.superclass.constructor.call(this);};YAHOO.lang.extend(YAHOO.widget.CategoryAxis,YAHOO.widget.Axis,{type:&quot;category&quot;,categoryNames:null,calculateCategoryCount:false});YAHOO.widget.Series=function(){};YAHOO.widget.Series.prototype={type:null,displayName:null};YAHOO.widget.CartesianSeries=function(){YAHOO.widget.CartesianSeries.superclass.constructor.call(this);};YAHOO.lang.extend(YAHOO.widget.CartesianSeries,YAHOO.widget.Series,{xField:null,yField:null,axis:&quot;primary&quot;,showInLegend:true});YAHOO.widget.ColumnSeries=function(){YAHOO.widget.ColumnSeries.superclass.constructor.call(this);};YAHOO.lang.extend(YAHOO.widget.ColumnSeries,YAHOO.widget.CartesianSeries,{type:&quot;column&quot;});YAHOO.widget.LineSeries=function(){YAHOO.widget.LineSeries.superclass.constructor.call(this);};YAHOO.lang.extend(YAHOO.widget.LineSeries,YAHOO.widget.CartesianSeries,{type:&quot;line&quot;});YAHOO.widget.BarSeries=
 function(){YAHOO.widget.BarSeries.superclass.constructor.call(this);};YAHOO.lang.extend(YAHOO.widget.BarSeries,YAHOO.widget.CartesianSeries,{type:&quot;bar&quot;});YAHOO.widget.PieSeries=function(){YAHOO.widget.PieSeries.superclass.constructor.call(this);};YAHOO.lang.extend(YAHOO.widget.PieSeries,YAHOO.widget.Series,{type:&quot;pie&quot;,dataField:null,categoryField:null,labelFunction:null});YAHOO.widget.StackedBarSeries=function(){YAHOO.widget.StackedBarSeries.superclass.constructor.call(this);};YAHOO.lang.extend(YAHOO.widget.StackedBarSeries,YAHOO.widget.CartesianSeries,{type:&quot;stackbar&quot;});YAHOO.widget.StackedColumnSeries=function(){YAHOO.widget.StackedColumnSeries.superclass.constructor.call(this);};YAHOO.lang.extend(YAHOO.widget.StackedColumnSeries,YAHOO.widget.CartesianSeries,{type:&quot;stackcolumn&quot;});YAHOO.register(&quot;charts&quot;,YAHOO.widget.Chart,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuicolorpickercolorpickerminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/colorpicker/colorpicker-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/colorpicker/colorpicker-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/colorpicker/colorpicker-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,9 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+YAHOO.util.Color=function(){var a=&quot;0&quot;,b=YAHOO.lang.isArray,c=YAHOO.lang.isNumber;return{real2dec:function(d){return Math.min(255,Math.round(d*256));},hsv2rgb:function(l,y,w){if(b(l)){return this.hsv2rgb.call(this,l[0],l[1],l[2]);}var d,m,u,k=Math.floor((l/60)%6),n=(l/60)-k,j=w*(1-y),e=w*(1-n*y),x=w*(1-(1-n)*y),o;switch(k){case 0:d=w;m=x;u=j;break;case 1:d=e;m=w;u=j;break;case 2:d=j;m=w;u=x;break;case 3:d=j;m=e;u=w;break;case 4:d=x;m=j;u=w;break;case 5:d=w;m=j;u=e;break;}o=this.real2dec;return[o(d),o(m),o(u)];},rgb2hsv:function(d,j,k){if(b(d)){return this.rgb2hsv.apply(this,d);}d/=255;j/=255;k/=255;var i,n,e=Math.min(Math.min(d,j),k),l=Math.max(Math.max(d,j),k),m=l-e,f;switch(l){case e:i=0;break;case d:i=60*(j-k)/m;if(j&lt;k){i+=360;}break;case j:i=(60*(k-d)/m)+120;break;case k:i=(60*(d-j)/m)+240;break;}n=(l===0)?0:1-(e/l);f=[Math.round(i),n,l];return f;},rgb2hex:function(h,e,d){if(b(h)){return this.rgb2hex.apply(this,h);}var i=this.dec2hex;return i(h)+i(e)+i(d);},d
 ec2hex:function(d){d=parseInt(d,10)|0;d=(d&gt;255||d&lt;0)?0:d;return(a+d.toString(16)).slice(-2).toUpperCase();},hex2dec:function(d){return parseInt(d,16);},hex2rgb:function(d){var e=this.hex2dec;return[e(d.slice(0,2)),e(d.slice(2,4)),e(d.slice(4,6))];},websafe:function(h,e,d){if(b(h)){return this.websafe.apply(this,h);}var i=function(f){if(c(f)){f=Math.min(Math.max(0,f),255);var g,j;for(g=0;g&lt;256;g=g+51){j=g+51;if(f&gt;=g&amp;&amp;f&lt;=j){return(f-g&gt;25)?j:g;}}}return f;};return[i(h),i(e),i(d)];}};}();(function(){var k=0,g=YAHOO.util,d=YAHOO.lang,e=YAHOO.widget.Slider,c=g.Color,f=g.Dom,j=g.Event,a=d.substitute,i=&quot;yui-picker&quot;;function h(l,b){k=k+1;b=b||{};if(arguments.length===1&amp;&amp;!YAHOO.lang.isString(l)&amp;&amp;!l.nodeName){b=l;l=b.element||null;}if(!l&amp;&amp;!b.element){l=this._createHostElement(b);}h.superclass.constructor.call(this,l,b);this.initPicker();}YAHOO.extend(h,YAHOO.util.Element,{ID:{R:i+&quot;-r&quot;,R_HEX:i+&quot;-rhex&quot;,G:i+&q
 uot;-g&quot;,G_HEX:i+&quot;-ghex&quot;,B:i+&quot;-b&quot;,B_HEX:i+&quot;-bhex&quot;,H:i+&quot;-h&quot;,S:i+&quot;-s&quot;,V:i+&quot;-v&quot;,PICKER_BG:i+&quot;-bg&quot;,PICKER_THUMB:i+&quot;-thumb&quot;,HUE_BG:i+&quot;-hue-bg&quot;,HUE_THUMB:i+&quot;-hue-thumb&quot;,HEX:i+&quot;-hex&quot;,SWATCH:i+&quot;-swatch&quot;,WEBSAFE_SWATCH:i+&quot;-websafe-swatch&quot;,CONTROLS:i+&quot;-controls&quot;,RGB_CONTROLS:i+&quot;-rgb-controls&quot;,HSV_CONTROLS:i+&quot;-hsv-controls&quot;,HEX_CONTROLS:i+&quot;-hex-controls&quot;,HEX_SUMMARY:i+&quot;-hex-summary&quot;,CONTROLS_LABEL:i+&quot;-controls-label&quot;},TXT:{ILLEGAL_HEX:&quot;Illegal hex value entered&quot;,SHOW_CONTROLS:&quot;Show color details&quot;,HIDE_CONTROLS:&quot;Hide color details&quot;,CURRENT_COLOR:&quot;Currently selected color: {rgb}&quot;,CLOSEST_WEBSAFE:&quot;Closest websafe color: {rgb}. Click to select.&quot;,R:&quot;R&quot;,G:&quot;G&quot;,B:&quot;B&quot;,H:&quot;H&quot;,S:&quot;S&quot;,V:&quot;V&quot;,HEX:&quot;
 #&quot;,DEG:&quot;\u00B0&quot;,PERCENT:&quot;%&quot;},IMAGE:{PICKER_THUMB:&quot;../../build/colorpicker/assets/picker_thumb.png&quot;,HUE_THUMB:&quot;../../build/colorpicker/assets/hue_thumb.png&quot;},DEFAULT:{PICKER_SIZE:180},OPT:{HUE:&quot;hue&quot;,SATURATION:&quot;saturation&quot;,VALUE:&quot;value&quot;,RED:&quot;red&quot;,GREEN:&quot;green&quot;,BLUE:&quot;blue&quot;,HSV:&quot;hsv&quot;,RGB:&quot;rgb&quot;,WEBSAFE:&quot;websafe&quot;,HEX:&quot;hex&quot;,PICKER_SIZE:&quot;pickersize&quot;,SHOW_CONTROLS:&quot;showcontrols&quot;,SHOW_RGB_CONTROLS:&quot;showrgbcontrols&quot;,SHOW_HSV_CONTROLS:&quot;showhsvcontrols&quot;,SHOW_HEX_CONTROLS:&quot;showhexcontrols&quot;,SHOW_HEX_SUMMARY:&quot;showhexsummary&quot;,SHOW_WEBSAFE:&quot;showwebsafe&quot;,CONTAINER:&quot;container&quot;,IDS:&quot;ids&quot;,ELEMENTS:&quot;elements&quot;,TXT:&quot;txt&quot;,IMAGES:&quot;images&quot;,ANIMATE:&quot;animate&quot;},skipAnim:true,_createHostElement:function(){var b=document.createElement(&
 quot;div&quot;);if(this.CSS.BASE){b.className=this.CSS.BASE;}return b;},_updateHueSlider:function(){var b=this.get(this.OPT.PICKER_SIZE),l=this.get(this.OPT.HUE);l=b-Math.round(l/360*b);if(l===b){l=0;}this.hueSlider.setValue(l,this.skipAnim);},_updatePickerSlider:function(){var l=this.get(this.OPT.PICKER_SIZE),m=this.get(this.OPT.SATURATION),b=this.get(this.OPT.VALUE);m=Math.round(m*l/100);b=Math.round(l-(b*l/100));this.pickerSlider.setRegionValue(m,b,this.skipAnim);},_updateSliders:function(){this._updateHueSlider();this._updatePickerSlider();},setValue:function(l,b){b=(b)||false;this.set(this.OPT.RGB,l,b);this._updateSliders();},hueSlider:null,pickerSlider:null,_getH:function(){var b=this.get(this.OPT.PICKER_SIZE),l=(b-this.hueSlider.getValue())/b;l=Math.round(l*360);return(l===360)?0:l;},_getS:function(){return this.pickerSlider.getXValue()/this.get(this.OPT.PICKER_SIZE);},_getV:function(){var b=this.get(this.OPT.PICKER_SIZE);return(b-this.pickerSlider.getYValue())/b;},_u
 pdateSwatch:function(){var m=this.get(this.OPT.RGB),o=this.get(this.OPT.WEBSAFE),n=this.getElement(this.ID.SWATCH),l=m.join(&quot;,&quot;),b=this.get(this.OPT.TXT);f.setStyle(n,&quot;background-color&quot;,&quot;rgb(&quot;+l+&quot;)&quot;);n.title=a(b.CURRENT_COLOR,{&quot;rgb&quot;:&quot;#&quot;+this.get(this.OPT.HEX)});n=this.getElement(this.ID.WEBSAFE_SWATCH);l=o.join(&quot;,&quot;);f.setStyle(n,&quot;background-color&quot;,&quot;rgb(&quot;+l+&quot;)&quot;);n.title=a(b.CLOSEST_WEBSAFE,{&quot;rgb&quot;:&quot;#&quot;+c.rgb2hex(o)});},_getValuesFromSliders:function(){this.set(this.OPT.RGB,c.hsv2rgb(this._getH(),this._getS(),this._getV()));},_updateFormFields:function(){this.getElement(this.ID.H).value=this.get(this.OPT.HUE);this.getElement(this.ID.S).value=this.get(this.OPT.SATURATION);this.getElement(this.ID.V).value=this.get(this.OPT.VALUE);this.getElement(this.ID.R).value=this.get(this.OPT.RED);this.getElement(this.ID.R_HEX).innerHTML=c.dec2hex(this.get(this.OPT.RED));this
 .getElement(this.ID.G).value=this.get(this.OPT.GREEN);this.getElement(this.ID.G_HEX).innerHTML=c.dec2hex(this.get(this.OPT.GREEN));this.getElement(this.ID.B).value=this.get(this.OPT.BLUE);this.getElement(this.ID.B_HEX).innerHTML=c.dec2hex(this.get(this.OPT.BLUE));this.getElement(this.ID.HEX).value=this.get(this.OPT.HEX);},_onHueSliderChange:function(n){var l=this._getH(),b=c.hsv2rgb(l,1,1),m=&quot;rgb(&quot;+b.join(&quot;,&quot;)+&quot;)&quot;;this.set(this.OPT.HUE,l,true);f.setStyle(this.getElement(this.ID.PICKER_BG),&quot;background-color&quot;,m);if(this.hueSlider.valueChangeSource!==e.SOURCE_SET_VALUE){this._getValuesFromSliders();}this._updateFormFields();this._updateSwatch();},_onPickerSliderChange:function(m){var l=this._getS(),b=this._getV();this.set(this.OPT.SATURATION,Math.round(l*100),true);this.set(this.OPT.VALUE,Math.round(b*100),true);if(this.pickerSlider.valueChangeSource!==e.SOURCE_SET_VALUE){this._getValuesFromSliders();
+}this._updateFormFields();this._updateSwatch();},_getCommand:function(b){var l=j.getCharCode(b);if(l===38){return 3;}else{if(l===13){return 6;}else{if(l===40){return 4;}else{if(l&gt;=48&amp;&amp;l&lt;=57){return 1;}else{if(l&gt;=97&amp;&amp;l&lt;=102){return 2;}else{if(l&gt;=65&amp;&amp;l&lt;=70){return 2;}else{if(&quot;8, 9, 13, 27, 37, 39&quot;.indexOf(l)&gt;-1||b.ctrlKey||b.metaKey){return 5;}else{return 0;}}}}}}}},_useFieldValue:function(l,b,n){var m=b.value;if(n!==this.OPT.HEX){m=parseInt(m,10);}if(m!==this.get(n)){this.set(n,m);}},_rgbFieldKeypress:function(m,b,o){var n=this._getCommand(m),l=(m.shiftKey)?10:1;switch(n){case 6:this._useFieldValue.apply(this,arguments);break;case 3:this.set(o,Math.min(this.get(o)+l,255));this._updateFormFields();break;case 4:this.set(o,Math.max(this.get(o)-l,0));this._updateFormFields();break;default:}},_hexFieldKeypress:function(l,b,n){var m=this._getCommand(l);if(m===6){this._useFieldValue.apply(this,arguments);}},_hexOnly:function(l,b
 ){var m=this._getCommand(l);switch(m){case 6:case 5:case 1:break;case 2:if(b!==true){break;}default:j.stopEvent(l);return false;}},_numbersOnly:function(b){return this._hexOnly(b,true);},getElement:function(b){return this.get(this.OPT.ELEMENTS)[this.get(this.OPT.IDS)[b]];},_createElements:function(){var n,m,q,o,l,b=this.get(this.OPT.IDS),r=this.get(this.OPT.TXT),t=this.get(this.OPT.IMAGES),s=function(p,v){var w=document.createElement(p);if(v){d.augmentObject(w,v,true);}return w;},u=function(p,v){var w=d.merge({autocomplete:&quot;off&quot;,value:&quot;0&quot;,size:3,maxlength:3},v);w.name=w.id;return new s(p,w);};l=this.get(&quot;element&quot;);n=new s(&quot;div&quot;,{id:b[this.ID.PICKER_BG],className:&quot;yui-picker-bg&quot;,tabIndex:-1,hideFocus:true});m=new s(&quot;div&quot;,{id:b[this.ID.PICKER_THUMB],className:&quot;yui-picker-thumb&quot;});q=new s(&quot;img&quot;,{src:t.PICKER_THUMB});m.appendChild(q);n.appendChild(m);l.appendChild(n);n=new s(&quot;div&quot;,{id:b[thi
 s.ID.HUE_BG],className:&quot;yui-picker-hue-bg&quot;,tabIndex:-1,hideFocus:true});m=new s(&quot;div&quot;,{id:b[this.ID.HUE_THUMB],className:&quot;yui-picker-hue-thumb&quot;});q=new s(&quot;img&quot;,{src:t.HUE_THUMB});m.appendChild(q);n.appendChild(m);l.appendChild(n);n=new s(&quot;div&quot;,{id:b[this.ID.CONTROLS],className:&quot;yui-picker-controls&quot;});l.appendChild(n);l=n;n=new s(&quot;div&quot;,{className:&quot;hd&quot;});m=new s(&quot;a&quot;,{id:b[this.ID.CONTROLS_LABEL],href:&quot;#&quot;});n.appendChild(m);l.appendChild(n);n=new s(&quot;div&quot;,{className:&quot;bd&quot;});l.appendChild(n);l=n;n=new s(&quot;ul&quot;,{id:b[this.ID.RGB_CONTROLS],className:&quot;yui-picker-rgb-controls&quot;});m=new s(&quot;li&quot;);m.appendChild(document.createTextNode(r.R+&quot; &quot;));o=new u(&quot;input&quot;,{id:b[this.ID.R],className:&quot;yui-picker-r&quot;});m.appendChild(o);n.appendChild(m);m=new s(&quot;li&quot;);m.appendChild(document.createTextNode(r.G+&quot; &quot;
 ));o=new u(&quot;input&quot;,{id:b[this.ID.G],className:&quot;yui-picker-g&quot;});m.appendChild(o);n.appendChild(m);m=new s(&quot;li&quot;);m.appendChild(document.createTextNode(r.B+&quot; &quot;));o=new u(&quot;input&quot;,{id:b[this.ID.B],className:&quot;yui-picker-b&quot;});m.appendChild(o);n.appendChild(m);l.appendChild(n);n=new s(&quot;ul&quot;,{id:b[this.ID.HSV_CONTROLS],className:&quot;yui-picker-hsv-controls&quot;});m=new s(&quot;li&quot;);m.appendChild(document.createTextNode(r.H+&quot; &quot;));o=new u(&quot;input&quot;,{id:b[this.ID.H],className:&quot;yui-picker-h&quot;});m.appendChild(o);m.appendChild(document.createTextNode(&quot; &quot;+r.DEG));n.appendChild(m);m=new s(&quot;li&quot;);m.appendChild(document.createTextNode(r.S+&quot; &quot;));o=new u(&quot;input&quot;,{id:b[this.ID.S],className:&quot;yui-picker-s&quot;});m.appendChild(o);m.appendChild(document.createTextNode(&quot; &quot;+r.PERCENT));n.appendChild(m);m=new s(&quot;li&quot;);m.appendChild(docume
 nt.createTextNode(r.V+&quot; &quot;));o=new u(&quot;input&quot;,{id:b[this.ID.V],className:&quot;yui-picker-v&quot;});m.appendChild(o);m.appendChild(document.createTextNode(&quot; &quot;+r.PERCENT));n.appendChild(m);l.appendChild(n);n=new s(&quot;ul&quot;,{id:b[this.ID.HEX_SUMMARY],className:&quot;yui-picker-hex_summary&quot;});m=new s(&quot;li&quot;,{id:b[this.ID.R_HEX]});n.appendChild(m);m=new s(&quot;li&quot;,{id:b[this.ID.G_HEX]});n.appendChild(m);m=new s(&quot;li&quot;,{id:b[this.ID.B_HEX]});n.appendChild(m);l.appendChild(n);n=new s(&quot;div&quot;,{id:b[this.ID.HEX_CONTROLS],className:&quot;yui-picker-hex-controls&quot;});n.appendChild(document.createTextNode(r.HEX+&quot; &quot;));m=new u(&quot;input&quot;,{id:b[this.ID.HEX],className:&quot;yui-picker-hex&quot;,size:6,maxlength:6});n.appendChild(m);l.appendChild(n);l=this.get(&quot;element&quot;);n=new s(&quot;div&quot;,{id:b[this.ID.SWATCH],className:&quot;yui-picker-swatch&quot;});l.appendChild(n);n=new s(&quot;div&q
 uot;,{id:b[this.ID.WEBSAFE_SWATCH],className:&quot;yui-picker-websafe-swatch&quot;});l.appendChild(n);},_attachRGBHSV:function(l,b){j.on(this.getElement(l),&quot;keydown&quot;,function(n,m){m._rgbFieldKeypress(n,this,b);},this);j.on(this.getElement(l),&quot;keypress&quot;,this._numbersOnly,this,true);j.on(this.getElement(l),&quot;blur&quot;,function(n,m){m._useFieldValue(n,this,b);},this);},_updateRGB:function(){var b=[this.get(this.OPT.RED),this.get(this.OPT.GREEN),this.get(this.OPT.BLUE)];this.set(this.OPT.RGB,b);this._updateSliders();},_initElements:function(){var p=this.OPT,n=this.get(p.IDS),l=this.get(p.ELEMENTS),b,m,q;for(b in this.ID){if(d.hasOwnProperty(this.ID,b)){n[this.ID[b]]=n[b];}}m=f.get(n[this.ID.PICKER_BG]);if(!m){this._createElements();}else{}for(b in n){if(d.hasOwnProperty(n,b)){m=f.get(n[b]);q=f.generateId(m);n[b]=q;n[n[b]]=q;l[q]=m;}}},initPicker:function(){this._initSliders();this._bindUI();this.syncUI(true);},_initSliders:function(){var b=this.ID,l=this
 .get(this.OPT.PICKER_SIZE);this.hueSlider=e.getVertSlider(this.getElement(b.HUE_BG),this.getElement(b.HUE_THUMB),0,l);this.pickerSlider=e.getSliderRegion(this.getElement(b.PICKER_BG),this.getElement(b.PICKER_THUMB),0,l,0,l);this.set(this.OPT.ANIMATE,this.get(this.OPT.ANIMATE));},_bindUI:function(){var b=this.ID,l=this.OPT;this.hueSlider.subscribe(&quot;change&quot;,this._onHueSliderChange,this,true);this.pickerSlider.subscribe(&quot;change&quot;,this._onPickerSliderChange,this,true);j.on(this.getElement(b.WEBSAFE_SWATCH),&quot;click&quot;,function(m){this.setValue(this.get(l.WEBSAFE));},this,true);j.on(this.getElement(b.CONTROLS_LABEL),&quot;click&quot;,function(m){this.set(l.SHOW_CONTROLS,!this.get(l.SHOW_CONTROLS));j.preventDefault(m);},this,true);this._attachRGBHSV(b.R,l.RED);this._attachRGBHSV(b.G,l.GREEN);this._attachRGBHSV(b.B,l.BLUE);this._attachRGBHSV(b.H,l.HUE);
+this._attachRGBHSV(b.S,l.SATURATION);this._attachRGBHSV(b.V,l.VALUE);j.on(this.getElement(b.HEX),&quot;keydown&quot;,function(n,m){m._hexFieldKeypress(n,this,l.HEX);},this);j.on(this.getElement(this.ID.HEX),&quot;keypress&quot;,this._hexOnly,this,true);j.on(this.getElement(this.ID.HEX),&quot;blur&quot;,function(n,m){m._useFieldValue(n,this,l.HEX);},this);},syncUI:function(b){this.skipAnim=b;this._updateRGB();this.skipAnim=false;},_updateRGBFromHSV:function(){var l=[this.get(this.OPT.HUE),this.get(this.OPT.SATURATION)/100,this.get(this.OPT.VALUE)/100],b=c.hsv2rgb(l);this.set(this.OPT.RGB,b);this._updateSliders();},_updateHex:function(){var o=this.get(this.OPT.HEX),b=o.length,p,n,m;if(b===3){p=o.split(&quot;&quot;);for(n=0;n&lt;b;n=n+1){p[n]=p[n]+p[n];}o=p.join(&quot;&quot;);}if(o.length!==6){return false;}m=c.hex2rgb(o);this.setValue(m);},_hideShowEl:function(m,b){var l=(d.isString(m)?this.getElement(m):m);f.setStyle(l,&quot;display&quot;,(b)?&quot;&quot;:&quot;none&quot;);},
 initAttributes:function(b){b=b||{};h.superclass.initAttributes.call(this,b);this.setAttributeConfig(this.OPT.PICKER_SIZE,{value:b.size||this.DEFAULT.PICKER_SIZE});this.setAttributeConfig(this.OPT.HUE,{value:b.hue||0,validator:d.isNumber});this.setAttributeConfig(this.OPT.SATURATION,{value:b.saturation||0,validator:d.isNumber});this.setAttributeConfig(this.OPT.VALUE,{value:d.isNumber(b.value)?b.value:100,validator:d.isNumber});this.setAttributeConfig(this.OPT.RED,{value:d.isNumber(b.red)?b.red:255,validator:d.isNumber});this.setAttributeConfig(this.OPT.GREEN,{value:d.isNumber(b.green)?b.green:255,validator:d.isNumber});this.setAttributeConfig(this.OPT.BLUE,{value:d.isNumber(b.blue)?b.blue:255,validator:d.isNumber});this.setAttributeConfig(this.OPT.HEX,{value:b.hex||&quot;FFFFFF&quot;,validator:d.isString});this.setAttributeConfig(this.OPT.RGB,{value:b.rgb||[255,255,255],method:function(o){this.set(this.OPT.RED,o[0],true);this.set(this.OPT.GREEN,o[1],true);this.set(this.OPT.BL
 UE,o[2],true);var q=c.websafe(o),p=c.rgb2hex(o),n=c.rgb2hsv(o);this.set(this.OPT.WEBSAFE,q,true);this.set(this.OPT.HEX,p,true);if(n[1]){this.set(this.OPT.HUE,n[0],true);}this.set(this.OPT.SATURATION,Math.round(n[1]*100),true);this.set(this.OPT.VALUE,Math.round(n[2]*100),true);},readonly:true});this.setAttributeConfig(this.OPT.CONTAINER,{value:null,method:function(n){if(n){n.showEvent.subscribe(function(){this.pickerSlider.focus();},this,true);}}});this.setAttributeConfig(this.OPT.WEBSAFE,{value:b.websafe||[255,255,255]});var m=b.ids||d.merge({},this.ID),l;if(!b.ids&amp;&amp;k&gt;1){for(l in m){if(d.hasOwnProperty(m,l)){m[l]=m[l]+k;}}}this.setAttributeConfig(this.OPT.IDS,{value:m,writeonce:true});this.setAttributeConfig(this.OPT.TXT,{value:b.txt||this.TXT,writeonce:true});this.setAttributeConfig(this.OPT.IMAGES,{value:b.images||this.IMAGE,writeonce:true});this.setAttributeConfig(this.OPT.ELEMENTS,{value:{},readonly:true});this.setAttributeConfig(this.OPT.SHOW_CONTROLS,{value:
 d.isBoolean(b.showcontrols)?b.showcontrols:true,method:function(n){var o=f.getElementsByClassName(&quot;bd&quot;,&quot;div&quot;,this.getElement(this.ID.CONTROLS))[0];this._hideShowEl(o,n);this.getElement(this.ID.CONTROLS_LABEL).innerHTML=(n)?this.get(this.OPT.TXT).HIDE_CONTROLS:this.get(this.OPT.TXT).SHOW_CONTROLS;}});this.setAttributeConfig(this.OPT.SHOW_RGB_CONTROLS,{value:d.isBoolean(b.showrgbcontrols)?b.showrgbcontrols:true,method:function(n){this._hideShowEl(this.ID.RGB_CONTROLS,n);}});this.setAttributeConfig(this.OPT.SHOW_HSV_CONTROLS,{value:d.isBoolean(b.showhsvcontrols)?b.showhsvcontrols:false,method:function(n){this._hideShowEl(this.ID.HSV_CONTROLS,n);if(n&amp;&amp;this.get(this.OPT.SHOW_HEX_SUMMARY)){this.set(this.OPT.SHOW_HEX_SUMMARY,false);}}});this.setAttributeConfig(this.OPT.SHOW_HEX_CONTROLS,{value:d.isBoolean(b.showhexcontrols)?b.showhexcontrols:false,method:function(n){this._hideShowEl(this.ID.HEX_CONTROLS,n);}});this.setAttributeConfig(this.OPT.SHOW_WEBSAF
 E,{value:d.isBoolean(b.showwebsafe)?b.showwebsafe:true,method:function(n){this._hideShowEl(this.ID.WEBSAFE_SWATCH,n);}});this.setAttributeConfig(this.OPT.SHOW_HEX_SUMMARY,{value:d.isBoolean(b.showhexsummary)?b.showhexsummary:true,method:function(n){this._hideShowEl(this.ID.HEX_SUMMARY,n);if(n&amp;&amp;this.get(this.OPT.SHOW_HSV_CONTROLS)){this.set(this.OPT.SHOW_HSV_CONTROLS,false);}}});this.setAttributeConfig(this.OPT.ANIMATE,{value:d.isBoolean(b.animate)?b.animate:true,method:function(n){if(this.pickerSlider){this.pickerSlider.animate=n;this.hueSlider.animate=n;}}});this.on(this.OPT.HUE+&quot;Change&quot;,this._updateRGBFromHSV,this,true);this.on(this.OPT.SATURATION+&quot;Change&quot;,this._updateRGBFromHSV,this,true);this.on(this.OPT.VALUE+&quot;Change&quot;,this._updateRGBFromHSV,this,true);this.on(this.OPT.RED+&quot;Change&quot;,this._updateRGB,this,true);this.on(this.OPT.GREEN+&quot;Change&quot;,this._updateRGB,this,true);this.on(this.OPT.BLUE+&quot;Change&quot;,this._u
 pdateRGB,this,true);this.on(this.OPT.HEX+&quot;Change&quot;,this._updateHex,this,true);this._initElements();}});YAHOO.widget.ColorPicker=h;})();YAHOO.register(&quot;colorpicker&quot;,YAHOO.widget.ColorPicker,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiconnectionconnectionminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/connection/connection-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/connection/connection-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/connection/connection-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,9 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+YAHOO.util.Connect={_msxml_progid:[&quot;Microsoft.XMLHTTP&quot;,&quot;MSXML2.XMLHTTP.3.0&quot;,&quot;MSXML2.XMLHTTP&quot;],_http_headers:{},_has_http_headers:false,_use_default_post_header:true,_default_post_header:&quot;application/x-www-form-urlencoded; charset=UTF-8&quot;,_default_form_header:&quot;application/x-www-form-urlencoded&quot;,_use_default_xhr_header:true,_default_xhr_header:&quot;XMLHttpRequest&quot;,_has_default_headers:true,_isFormSubmit:false,_default_headers:{},_poll:{},_timeOut:{},_polling_interval:50,_transaction_id:0,startEvent:new YAHOO.util.CustomEvent(&quot;start&quot;),completeEvent:new YAHOO.util.CustomEvent(&quot;complete&quot;),successEvent:new YAHOO.util.CustomEvent(&quot;success&quot;),failureEvent:new YAHOO.util.CustomEvent(&quot;failure&quot;),abortEvent:new YAHOO.util.CustomEvent(&quot;abort&quot;),_customEvents:{onStart:[&quot;startEvent&quot;,&quot;start&quot;],onComplete:[&quot;completeEvent&quot;,&quot;complete&quot;],onSuccess:[&quot;s
 uccessEvent&quot;,&quot;success&quot;],onFailure:[&quot;failureEvent&quot;,&quot;failure&quot;],onUpload:[&quot;uploadEvent&quot;,&quot;upload&quot;],onAbort:[&quot;abortEvent&quot;,&quot;abort&quot;]},setProgId:function(a){this._msxml_progid.unshift(a);},setDefaultPostHeader:function(a){if(typeof a==&quot;string&quot;){this._default_post_header=a;this._use_default_post_header=true;}else{if(typeof a==&quot;boolean&quot;){this._use_default_post_header=a;}}},setDefaultXhrHeader:function(a){if(typeof a==&quot;string&quot;){this._default_xhr_header=a;}else{this._use_default_xhr_header=a;}},setPollingInterval:function(a){if(typeof a==&quot;number&quot;&amp;&amp;isFinite(a)){this._polling_interval=a;}},createXhrObject:function(g){var d,a,b;try{a=new XMLHttpRequest();d={conn:a,tId:g,xhr:true};}catch(c){for(b=0;b&lt;this._msxml_progid.length;++b){try{a=new ActiveXObject(this._msxml_progid[b]);d={conn:a,tId:g,xhr:true};break;}catch(f){}}}finally{return d;}},getConnectionObject:functi
 on(a){var c,d=this._transaction_id;try{if(!a){c=this.createXhrObject(d);}else{c={tId:d};if(a===&quot;xdr&quot;){c.conn=this._transport;c.xdr=true;}else{if(a===&quot;upload&quot;){c.upload=true;}}}if(c){this._transaction_id++;}}catch(b){}return c;},asyncRequest:function(h,d,g,a){var b=g&amp;&amp;g.argument?g.argument:null,e=this,f,c;if(this._isFileUpload){c=&quot;upload&quot;;}else{if(g&amp;&amp;g.xdr){c=&quot;xdr&quot;;}}f=this.getConnectionObject(c);if(!f){return null;}else{if(g&amp;&amp;g.customevents){this.initCustomEvents(f,g);}if(this._isFormSubmit){if(this._isFileUpload){window.setTimeout(function(){e.uploadFile(f,g,d,a);},10);return f;}if(h.toUpperCase()==&quot;GET&quot;){if(this._sFormData.length!==0){d+=((d.indexOf(&quot;?&quot;)==-1)?&quot;?&quot;:&quot;&amp;&quot;)+this._sFormData;}}else{if(h.toUpperCase()==&quot;POST&quot;){a=a?this._sFormData+&quot;&amp;&quot;+a:this._sFormData;}}}if(h.toUpperCase()==&quot;GET&quot;&amp;&amp;(g&amp;&amp;g.cache===false)){d+=((d.
 indexOf(&quot;?&quot;)==-1)?&quot;?&quot;:&quot;&amp;&quot;)+&quot;rnd=&quot;+new Date().valueOf().toString();}if(this._use_default_xhr_header){if(!this._default_headers[&quot;X-Requested-With&quot;]){this.initHeader(&quot;X-Requested-With&quot;,this._default_xhr_header,true);}}if((h.toUpperCase()===&quot;POST&quot;&amp;&amp;this._use_default_post_header)&amp;&amp;this._isFormSubmit===false){this.initHeader(&quot;Content-Type&quot;,this._default_post_header);}if(f.xdr){this.xdr(f,h,d,g,a);return f;}f.conn.open(h,d,true);if(this._has_default_headers||this._has_http_headers){this.setHeader(f);}this.handleReadyState(f,g);f.conn.send(a||&quot;&quot;);if(this._isFormSubmit===true){this.resetFormState();}this.startEvent.fire(f,b);if(f.startEvent){f.startEvent.fire(f,b);}return f;}},initCustomEvents:function(a,c){var b;for(b in c.customevents){if(this._customEvents[b][0]){a[this._customEvents[b][0]]=new YAHOO.util.CustomEvent(this._customEvents[b][1],(c.scope)?c.scope:null);a[this.
 _customEvents[b][0]].subscribe(c.customevents[b]);}}},handleReadyState:function(c,d){var b=this,a=(d&amp;&amp;d.argument)?d.argument:null;if(d&amp;&amp;d.timeout){this._timeOut[c.tId]=window.setTimeout(function(){b.abort(c,d,true);},d.timeout);}this._poll[c.tId]=window.setInterval(function(){if(c.conn&amp;&amp;c.conn.readyState===4){window.clearInterval(b._poll[c.tId]);delete b._poll[c.tId];if(d&amp;&amp;d.timeout){window.clearTimeout(b._timeOut[c.tId]);delete b._timeOut[c.tId];}b.completeEvent.fire(c,a);if(c.completeEvent){c.completeEvent.fire(c,a);}b.handleTransactionResponse(c,d);}},this._polling_interval);},handleTransactionResponse:function(b,j,d){var f,a,h=(j&amp;&amp;j.argument)?j.argument:null,c=(b.r&amp;&amp;b.r.statusText===&quot;xdr:success&quot;)?true:false,i=(b.r&amp;&amp;b.r.statusText===&quot;xdr:failure&quot;)?true:false,k=d;try{if((b.conn.status!==undefined&amp;&amp;b.conn.status!==0)||c){f=b.conn.status;}else{if(i&amp;&amp;!k){f=0;}else{f=13030;}}}catch(g){
 f=13030;}if((f&gt;=200&amp;&amp;f&lt;300)||f===1223||c){a=b.xdr?b.r:this.createResponseObject(b,h);if(j&amp;&amp;j.success){if(!j.scope){j.success(a);}else{j.success.apply(j.scope,[a]);}}this.successEvent.fire(a);if(b.successEvent){b.successEvent.fire(a);}}else{switch(f){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:a=this.createExceptionObject(b.tId,h,(d?d:false));if(j&amp;&amp;j.failure){if(!j.scope){j.failure(a);}else{j.failure.apply(j.scope,[a]);}}break;default:a=(b.xdr)?b.response:this.createResponseObject(b,h);if(j&amp;&amp;j.failure){if(!j.scope){j.failure(a);}else{j.failure.apply(j.scope,[a]);}}}this.failureEvent.fire(a);if(b.failureEvent){b.failureEvent.fire(a);}}this.releaseObject(b);a=null;},createResponseObject:function(a,h){var d={},k={},f,c,g,b;try{c=a.conn.getAllResponseHeaders();g=c.split(&quot;\n&quot;);for(f=0;f&lt;g.length;f++){b=g[f].indexOf(&quot;:&quot;);if(b!=-1){k[g[f].substring(0,b)]=YAHOO.lang.trim(g[f].substring(b+2));}}}catch(j
 ){}d.tId=a.tId;d.status=(a.conn.status==1223)?204:a.conn.status;d.statusText=(a.conn.status==1223)?&quot;No Content&quot;:a.conn.statusText;d.getResponseHeader=k;d.getAllResponseHeaders=c;d.responseText=a.conn.responseText;d.responseXML=a.conn.responseXML;if(h){d.argument=h;}return d;},createExceptionObject:function(h,d,a){var f=0,g=&quot;communication failure&quot;,c=-1,b=&quot;transaction aborted&quot;,e={};e.tId=h;if(a){e.status=c;e.statusText=b;}else{e.status=f;e.statusText=g;}if(d){e.argument=d;}return e;},initHeader:function(a,d,c){var b=(c)?this._default_headers:this._http_headers;b[a]=d;if(c){this._has_default_headers=true;}else{this._has_http_headers=true;}},setHeader:function(a){var b;if(this._has_default_headers){for(b in this._default_headers){if(YAHOO.lang.hasOwnProperty(this._default_headers,b)){a.conn.setRequestHeader(b,this._default_headers[b]);
+}}}if(this._has_http_headers){for(b in this._http_headers){if(YAHOO.lang.hasOwnProperty(this._http_headers,b)){a.conn.setRequestHeader(b,this._http_headers[b]);}}this._http_headers={};this._has_http_headers=false;}},resetDefaultHeaders:function(){this._default_headers={};this._has_default_headers=false;},abort:function(e,g,a){var d,b=(g&amp;&amp;g.argument)?g.argument:null;e=e||{};if(e.conn){if(e.xhr){if(this.isCallInProgress(e)){e.conn.abort();window.clearInterval(this._poll[e.tId]);delete this._poll[e.tId];if(a){window.clearTimeout(this._timeOut[e.tId]);delete this._timeOut[e.tId];}d=true;}}else{if(e.xdr){e.conn.abort(e.tId);d=true;}}}else{if(e.upload){var c=&quot;yuiIO&quot;+e.tId;var f=document.getElementById(c);if(f){YAHOO.util.Event.removeListener(f,&quot;load&quot;);document.body.removeChild(f);if(a){window.clearTimeout(this._timeOut[e.tId]);delete this._timeOut[e.tId];}d=true;}}else{d=false;}}if(d===true){this.abortEvent.fire(e,b);if(e.abortEvent){e.abortEvent.fire(e
 ,b);}this.handleTransactionResponse(e,g,true);}return d;},isCallInProgress:function(a){a=a||{};if(a.xhr&amp;&amp;a.conn){return a.conn.readyState!==4&amp;&amp;a.conn.readyState!==0;}else{if(a.xdr&amp;&amp;a.conn){return a.conn.isCallInProgress(a.tId);}else{if(a.upload===true){return document.getElementById(&quot;yuiIO&quot;+a.tId)?true:false;}else{return false;}}}},releaseObject:function(a){if(a&amp;&amp;a.conn){a.conn=null;a=null;}}};(function(){var g=YAHOO.util.Connect,h={};function d(i){var j='&lt;object id=&quot;YUIConnectionSwf&quot; type=&quot;application/x-shockwave-flash&quot; data=&quot;'+i+'&quot; width=&quot;0&quot; height=&quot;0&quot;&gt;'+'&lt;param name=&quot;movie&quot; value=&quot;'+i+'&quot;&gt;'+'&lt;param name=&quot;allowScriptAccess&quot; value=&quot;always&quot;&gt;'+&quot;&lt;/object&gt;&quot;,k=document.createElement(&quot;div&quot;);document.body.appendChild(k);k.innerHTML=j;}function b(l,i,j,n,k){h[parseInt(l.tId)]={&quot;o&quot;:l,&quot;c&quot;:n};
 if(k){n.method=i;n.data=k;}l.conn.send(j,n,l.tId);}function e(i){d(i);g._transport=document.getElementById(&quot;YUIConnectionSwf&quot;);}function c(){g.xdrReadyEvent.fire();}function a(j,i){if(j){g.startEvent.fire(j,i.argument);if(j.startEvent){j.startEvent.fire(j,i.argument);}}}function f(j){var k=h[j.tId].o,i=h[j.tId].c;if(j.statusText===&quot;xdr:start&quot;){a(k,i);return;}j.responseText=decodeURI(j.responseText);k.r=j;if(i.argument){k.r.argument=i.argument;}this.handleTransactionResponse(k,i,j.statusText===&quot;xdr:abort&quot;?true:false);delete h[j.tId];}g.xdr=b;g.swf=d;g.transport=e;g.xdrReadyEvent=new YAHOO.util.CustomEvent(&quot;xdrReady&quot;);g.xdrReady=c;g.handleXdrResponse=f;})();(function(){var e=YAHOO.util.Connect,g=YAHOO.util.Event,a=document.documentMode?document.documentMode:false;e._isFileUpload=false;e._formNode=null;e._sFormData=null;e._submitElementValue=null;e.uploadEvent=new YAHOO.util.CustomEvent(&quot;upload&quot;);e._hasSubmitListener=function(){
 if(g){g.addListener(document,&quot;click&quot;,function(k){var j=g.getTarget(k),i=j.nodeName.toLowerCase();if((i===&quot;input&quot;||i===&quot;button&quot;)&amp;&amp;(j.type&amp;&amp;j.type.toLowerCase()==&quot;submit&quot;)){e._submitElementValue=encodeURIComponent(j.name)+&quot;=&quot;+encodeURIComponent(j.value);}});return true;}return false;}();function h(w,r,m){var v,l,u,s,z,t=false,p=[],y=0,o,q,n,x,k;this.resetFormState();if(typeof w==&quot;string&quot;){v=(document.getElementById(w)||document.forms[w]);}else{if(typeof w==&quot;object&quot;){v=w;}else{return;}}if(r){this.createFrame(m?m:null);this._isFormSubmit=true;this._isFileUpload=true;this._formNode=v;return;}for(o=0,q=v.elements.length;o&lt;q;++o){l=v.elements[o];z=l.disabled;u=l.name;if(!z&amp;&amp;u){u=encodeURIComponent(u)+&quot;=&quot;;s=encodeURIComponent(l.value);switch(l.type){case&quot;select-one&quot;:if(l.selectedIndex&gt;-1){k=l.options[l.selectedIndex];p[y++]=u+encodeURIComponent((k.attributes.value&
 amp;&amp;k.attributes.value.specified)?k.value:k.text);}break;case&quot;select-multiple&quot;:if(l.selectedIndex&gt;-1){for(n=l.selectedIndex,x=l.options.length;n&lt;x;++n){k=l.options[n];if(k.selected){p[y++]=u+encodeURIComponent((k.attributes.value&amp;&amp;k.attributes.value.specified)?k.value:k.text);}}}break;case&quot;radio&quot;:case&quot;checkbox&quot;:if(l.checked){p[y++]=u+s;}break;case&quot;file&quot;:case undefined:case&quot;reset&quot;:case&quot;button&quot;:break;case&quot;submit&quot;:if(t===false){if(this._hasSubmitListener&amp;&amp;this._submitElementValue){p[y++]=this._submitElementValue;}t=true;}break;default:p[y++]=u+s;}}}this._isFormSubmit=true;this._sFormData=p.join(&quot;&amp;&quot;);this.initHeader(&quot;Content-Type&quot;,this._default_form_header);return this._sFormData;}function d(){this._isFormSubmit=false;this._isFileUpload=false;this._formNode=null;this._sFormData=&quot;&quot;;}function c(i){var j=&quot;yuiIO&quot;+this._transaction_id,l=(a===9)?
 true:false,k;if(YAHOO.env.ua.ie&amp;&amp;!l){k=document.createElement('&lt;iframe id=&quot;'+j+'&quot; name=&quot;'+j+'&quot; /&gt;');if(typeof i==&quot;boolean&quot;){k.src=&quot;javascript:false&quot;;}}else{k=document.createElement(&quot;iframe&quot;);k.id=j;k.name=j;}k.style.position=&quot;absolute&quot;;k.style.top=&quot;-1000px&quot;;k.style.left=&quot;-1000px&quot;;document.body.appendChild(k);}function f(j){var m=[],k=j.split(&quot;&amp;&quot;),l,n;for(l=0;l&lt;k.length;l++){n=k[l].indexOf(&quot;=&quot;);if(n!=-1){m[l]=document.createElement(&quot;input&quot;);m[l].type=&quot;hidden&quot;;m[l].name=decodeURIComponent(k[l].substring(0,n));m[l].value=decodeURIComponent(k[l].substring(n+1));this._formNode.appendChild(m[l]);}}return m;}function b(m,y,n,l){var t=&quot;yuiIO&quot;+m.tId,u=&quot;multipart/form-data&quot;,w=document.getElementById(t),p=(a&gt;=8)?true:false,z=this,v=(y&amp;&amp;y.argument)?y.argument:null,x,s,k,r,j,q;j={action:this._formNode.getAttribute(&quo
 t;action&quot;),method:this._formNode.getAttribute(&quot;method&quot;),target:this._formNode.getAttribute(&quot;target&quot;)};this._formNode.setAttribute(&quot;action&quot;,n);this._formNode.setAttribute(&quot;method&quot;,&quot;POST&quot;);this._formNode.setAttribute(&quot;target&quot;,t);if(YAHOO.env.ua.ie&amp;&amp;!p){this._formNode.setAttribute(&quot;encoding&quot;,u);}else{this._formNode.setAttribute(&quot;enctype&quot;,u);}if(l){x=this.appendPostData(l);}this._formNode.submit();this.startEvent.fire(m,v);if(m.startEvent){m.startEvent.fire(m,v);}if(y&amp;&amp;y.timeout){this._timeOut[m.tId]=window.setTimeout(function(){z.abort(m,y,true);},y.timeout);}if(x&amp;&amp;x.length&gt;0){for(s=0;s&lt;x.length;s++){this._formNode.removeChild(x[s]);}}for(k in j){if(YAHOO.lang.hasOwnProperty(j,k)){if(j[k]){this._formNode.setAttribute(k,j[k]);}else{this._formNode.removeAttribute(k);}}}this.resetFormState();
+q=function(){var i,A,B;if(y&amp;&amp;y.timeout){window.clearTimeout(z._timeOut[m.tId]);delete z._timeOut[m.tId];}z.completeEvent.fire(m,v);if(m.completeEvent){m.completeEvent.fire(m,v);}r={tId:m.tId,argument:v};try{i=w.contentWindow.document.getElementsByTagName(&quot;body&quot;)[0];A=w.contentWindow.document.getElementsByTagName(&quot;pre&quot;)[0];if(i){if(A){B=A.textContent?A.textContent:A.innerText;}else{B=i.textContent?i.textContent:i.innerText;}}r.responseText=B;r.responseXML=w.contentWindow.document.XMLDocument?w.contentWindow.document.XMLDocument:w.contentWindow.document;}catch(o){}if(y&amp;&amp;y.upload){if(!y.scope){y.upload(r);}else{y.upload.apply(y.scope,[r]);}}z.uploadEvent.fire(r);if(m.uploadEvent){m.uploadEvent.fire(r);}g.removeListener(w,&quot;load&quot;,q);setTimeout(function(){document.body.removeChild(w);z.releaseObject(m);},100);};g.addListener(w,&quot;load&quot;,q);}e.setForm=h;e.resetFormState=d;e.createFrame=c;e.appendPostData=f;e.uploadFile=b;})();YAH
 OO.register(&quot;connection&quot;,YAHOO.util.Connect,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiconnectionconnectionswf"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/connection/connection.swf (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/connection/connection.swf                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/connection/connection.swf        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,18 @@
</span><ins>+CWS        \xC9xÚW\xDDS\xD7\xBFgw\xA5\xBB+        \xCBX|D`\xC5\xD8DH'\xB6\xC1\x83\xF9\x88!`9|4\x8E\x8BÌ®V+\xA4X\xAC\xC8îŠifB\x93\xA6I;\xEDL\xDAI3Ó™\xA6\xCDS;\xD3\xE9[\xFA\xD8?\xA0/Ï´\x9D\xE9K\xA7O}\xE3v\xA6\xEF\xF4\xDC]\xD9\xD7\xD5\xC0\xDDs\xCF\xC7\xEF\x9C{ιg\xA5]&quot;\xFD\x83\x90\xE6_\xD2d\xBA\xF5!\xE4ö?!cV\xA18\xBA4=\xDFݬ\x98\xF6(\xEEn\xF5\x97gk4\x9D\xDE\xD9\xD9I\xED\MU\xAD\x8D\xF4\xD0\xC8\xC8H:3\x9CD\x8DA{\xCFt\xB4\xDDAÓ¾\xD8?\xEEL\xB6n\x95\xB7\x9CrՌ󽖯֜[\xFD\xFDuÔ‚\xFEt\xABfU\È‚\x9E6*Ʀa:vz(5\x84@}\xB4X\xB565g\\xDBÚª\x94u\x8DÃ¥w\xEDRU\xBC\xA3m\x83ÅŠf\x97\xC6\xD2+Enã”\x8A1&gt;Y\xA8\xE6\x8D\xF8l\xC5Ø_\x8DO6\xEC]mO\x85+\x81\x8E\x9F8\xA6Æ­Szu3\xBDeU 5c*&quot;\x94k|Ò„Cl\xD5\xF2\x95\xB2]2\xAC\xF1\x9A\xF9ج\xEEx.\\xAE\xA3[\x86\xE6TOk&lt;\xE3qyE37jÚ†1&gt;sÏ•=ß»1j\x9E\xA7\xB6IƇ3\x99/ \xCEK\x9F\xC9v\x9D\x83'\xD3\xE1\x8AcdJ\xF8\xFE/~\xF30 b\x85\xFD\xF8/\x8A\xFF\x8E\xF7\xF3\xF7\xFC\x95\xD7/b\xC5\xFF\xC0s\xAE\xEF\xD5\xCA\xEB5\xA7
 \Y׫\xA6i\xE8\x8B\xFC\xB1\xDDi&quot;UH\xD1\xD26\x8D!&amp;)nY&amp;}h\x92B\x937m\x98\xA4\xA4\xB4]-\xFCËŽU67\xFC\xD9\xFC{È•je\xD3\xE9z\x91\xA9m\x98Å­h\xCA4\x9C\x90GÛ¼!|3\xFC\x9A\xCB\xCEXV\xD5r7\x81\x95\xF2\xA6\xE1\x91AO\x95\xE3\xD9&gt;\x97\x9D~\x91\x8F-\xAB\xBC\x8Dy\xC3˦\xB1P\xB6\xC34,;&lt;\xE7M\x97\xED-\xCDѱhÉ—h\x85\xC2s\xEB\x97z\xB3\x8C\xCD\xEAv\xC3Û«/Ó·\xCDr\xFA_\xAAU\xD3uö_\xAAW\xD4Ê•\x9Aet\xBFH\xEF\xA6\xE5\xD0;\xD5j\xC5\xD0\xCC\xCB/\xD2*\xDBSZ\xA52gÞ·\xAA\xD6\xFF\xE3\xAF\x89cU\xF7B'\xF5+\xBD&amp;\xAFhLyE\xDB\xF3/\xA3\x99c\x9C\xA8¯\xA6[{y\xB6f\xBA\xACgMU7\xB7*\x86c\xD0z.Z\xCE\xD4U\xA9T\xB5\x82a-j[\xB4\x9EZK\xE2\xDD\xE6\xF3\x8E^\xD2\xCCBÅ°\xEFN\xDE\xCDf]ש)\xCFu\xCA=(XK\x86\xBDU5m#\xC8\xDD\xF2\xC3y\xE6s\xEB$\xEE\xCD\xC2g\xB3\xD3r\xA6ä¡“\xFDrcjt\xAD`l\xAF\xE1A\x87\xD7lK_ktM\xB3ob\xB8h\x8Dr\xB3!Jivs\xFDN\xEC:\x86ej\x95Ö™:1g⳨\xE9F\xDD\xF0@\xF2\x9A\xFE\xB8\xF3\x8E\xB3\xCB\xA2\xF6$\x95ÄšU\x{13C037}\xD4K\xB5\x8C\xF7k\x98\x9F\xC3ï„\x
 93oKY]ZXp\x85\xA4\x96&lt;\xB9\xD3pJ\xD5B\xF8Tl\x89᫽\xF5\xDA\x9E\x93\xCBW\xD38\xB0\xAE\xA5\xF3\xB5r\xC5)\x9B\x{D9CA}&gt;\xEA=q\x9A9\xED=\xBD\x89\x81\x81;V\xD4zå´’{b+}o\x9Eb\xE7\xFF\xE9:9JF\xCF\xDCt\xE9~vy%\xDC8Ü¢{6        \xA7\xABF\xAFΠ,\x9E\xB5e\xFB\x89g \x8C\xD63\xBD\x96\xC8\xC8S\xD9\xC5\xFB 3+3ݧ\x9E\x9D-a,\x92\xCBzf*\xCFe\xD7g\x96\x96\xB2K\xCD+s\x8B3K\xEB\xCF`Ú¼&amp;:\xADk\xD5Qt\xE6
+l@\xA7f\xAF`C(XZon(\x86\xA9W \xC6\xEAÒœ\xB7\x86tE\xDE        =3\xE76Ôª\x99&amp;Ng\xC9v\xB0\xD2\\xCB\xE0W̥ܛ\xE1\xD3+U\xDBh9Ó©\xE4\xB6\xFEW)\xA2\xDF\\xC1sQ\x88*Ѧh,\xDA\xD5\xD1\xE3\xEB\x89Ge\xDF\xE4\xF9\x98|'\xD6\x9B\x8AM\xC7fb\xB3\xB17c&gt;yYh\xA6\x90\x82!SsK\xB85\xD26EA\xA4 Q\xF0Q\xF0S!@\x85 BTl\xA6B\x98\xC2y*uR_7\xA5\xAFP\x88S\xDAKi\xA5)MP\xFA*\xA5\x97(\xF4S\xB8L\xE9J_\xA34I\xE9 \x85\xA5iJ3T\xBEJ\xE1u
+ר2N\x95\xDB\xCAPe\x8E\xC2]
+\xCA&lt;P\x98WÞ‚N|f)$ip\x84\xC7(,\xD1\xF6
+\xAB\xBE\xA5,\x80\xF2(\xF7@YD\x9D5
+9
+*MY\xA5\x8A
+\x8AT0\xA8\xAFH}\xD4W
+{/R\x81\x88 \x88Ý—e\xC0\xFB\xB8\xFAÝ•\xE2*\x80$\xB7|$\xE3SQZ\xF7\xB9\x86\xE12\xA9m_\xC1'\xC9\xED\xDCÎ¥\xCEyR\xE5\xA9c?\x84\xF4\x85}\xD9\xF5\xC1\x90\xE2'Æ—w3i\xE1KH\xA0\x88_\xFD&quot;il\xD2|\x88:\x8Fa+@×»D\x89\xF1(;\x814u\x91\xBB\x81Pl\x81\xA0\xF8\xFA\x90\xF1I\xE6Md\x89\xA0&amp;\xFE5\xC4.&lt;É°s\x8F&quot;\xAB\xA4Az\x8E\xB0\x98Ú“\xECW\xCFe_X'\x92\x97\xD5('\xBB\x90L\xA9\x9D\x9C\xECF\xF2\x8DlX\xE2rP        \xFCM@\xA0\xF8\x93L|_\xD6\xFD\xF1Otz\xD7I\xFCn.#.\xA3b\xEFÜ”\xFA\x8E`\xCCw\xF1n\xF9\xAC7\xD7;\xDFK\xF6{u\x89\xF5\xE5\xFA\xE6\xFB`\xBFO\xF7\xB1K        \xA2ˇ\xE9J\xF8\xB7\x84(y%/\xF7 `\xF8.nØ•\xC3\xE2\xC5\xE4\xDDX\x806\x90\xF7\xA9\x89\xE2\xAB\xDA%\x96 \x97\xCBRy\xDFa\xB1_\xBB\xCC\xD2\xE1\xF7\xF9~('\xAF$`^xTl8\xFC\xD9\xE1U\xB4\xED\xCFS=\x90\x9C`\x97\xF3\x81~\xA7J\x90p\x92\x90\xE4&lt;\xAC\xEF!Ü…\xFB\xB7X\xA6\xBE\xC2!BÂœ\xC3_\xE5@\xE7\x8E\x8FE\xE7\xF8\xF8\xF3\xE3ã¯\x8Fq\xC3.++r\xEB\xE2\xF1\xB1\xAC\xC82\xBB\xA6F\x9E&amp;\xF2Rr1A\x92\xF7\
 xF2\xFEUQ`\xD7s\xADO\xF3\xFEl\xAB\xC0n\xE4\xBA\xF3\x92\xDDA—}+\xD8h\xEE\xC2\xD3\xEC`cyK\xC6n\xA1&lt;I\xD8m̱(        \x81@\xFB\xDC'w0\xCFwr\xE1uPMe\xC3&quot;ʤ\xE7\xB2)\x94M\xE5\xDA&lt;Y\x97\xF9\x94\xB5r\xD9,\xCAfsQu0\xF8)\xBA\x87\xBC\xC9'\x99w\xFE\x929\x82\xB7\x85I6\xC1\x80\xC3MkF&amp;\xB1R0\xC9\xEE&lt;j\x99K-\xFAQÓ„TjBjÆ€\x8A\xC1Ve\xB3\x8F:&amp;|\xA5\xE4\xDD}\x93\x83$\xFC\x82)È„\x8A\xA2G\xF6\xFC\xC4%\xF3l\x9E\xBDu\xA0\xFA\x8Ai\xB5%\x9B\xD8Â\xEA/\xA9M\x9C\xBEw\xC1\xB3\xEC\xA1J\x8B\xC3jg\xBD\x8DQÊ¢\xA0\xDEF\x94e\x8E2B\x96ÙŠ9(\xAF\xD6a^\xD8\xEA3\x8E\x86\x9Cw&lt;\xCE\xBC+\xECA}SF\xF1CV$ \xEF\xAFy\xC0kG\xF0r\xC9wY\xEE \xF90\xF9\xEDUa_\xFC3[wM\x82v\x8D\xA9j\x8Fz\xFE0\x98\x86\xD6\xBF_        |\x80\xD6:\xB7\xBEOt\x84\\xC6\\xE6\xC5\x82I+\xE4\xAEo\xFBg\xAF\xC3'\xBA\x84\xD8\xC5C\xC4~\x94\g\xA5\xBC\xB4*\xEE\x8B\xD8\xEA\x8F\xD5\xC8!\xBA\x90\xD0\xC5\xE6\xD3íˆ\x8F\x90+O\x8B#\xDBl5f&gt;ÍŽ\xF6&gt;w\x8D+\x82\xBE\xAD\\xFBa\xB6\x98\x8D1%\
 x8C\xE1\x80A\xD4\xF0Ö¡H\x8DR\xE3\x81\xD4x \xDB&lt;\x90\xF4\xBC\xC3=\xE7\xF9\xA9\xD0\xE7^\xC3\xE7w\xB0\xBF\x8F\xE0`c\xE4}\x8Dp\xB5\x9B\xEC\xC3S\xD1\xF0n\xDC7\x9C\x8F\xA1\xCF\xF7\xA0\xD0'\xBC\xA5B&lt;\xA76\xF4)xI\xFDxV? \xE03\xE0yÕ½\xBC\xFE\xEA%ËŽ\xF6\xA3\xFA\xE6+\xF4D\xF5]\xF1\xD6v\x87\xFB\xF13qv\x9C\xB0\xCF\xE1y~\x82\xAE\xB8\xEB\x9Fr\xD7M\xF6\xC9 \xBA\xFE\xA2\xEE\xFA `?\xF3,#8=Ù—u\x94k        \xE9w_\xDEe?\x87~&amp;\xCD\xDC\xE8&quot;}U7\xFA
+\xD8/!\xD7u\x90\xED\xF6+n\xF1\xDE\xC0\xF65\xC7opl\xBE\xF6$\x83\xCAa\x83\xA8bF\xBD\x9DQ'2\xEAdF\xBD\x93QC\xF8\xF7\x80t\xBB\x9FRu\xB8IWY\x9C\xFC6\x9C:\xF1\xBBle\xFF\x84\xD3
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiconnectionconnection_coreminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/connection/connection_core-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/connection/connection_core-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/connection/connection_core-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,8 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+YAHOO.util.Connect={_msxml_progid:[&quot;Microsoft.XMLHTTP&quot;,&quot;MSXML2.XMLHTTP.3.0&quot;,&quot;MSXML2.XMLHTTP&quot;],_http_headers:{},_has_http_headers:false,_use_default_post_header:true,_default_post_header:&quot;application/x-www-form-urlencoded; charset=UTF-8&quot;,_default_form_header:&quot;application/x-www-form-urlencoded&quot;,_use_default_xhr_header:true,_default_xhr_header:&quot;XMLHttpRequest&quot;,_has_default_headers:true,_isFormSubmit:false,_default_headers:{},_poll:{},_timeOut:{},_polling_interval:50,_transaction_id:0,startEvent:new YAHOO.util.CustomEvent(&quot;start&quot;),completeEvent:new YAHOO.util.CustomEvent(&quot;complete&quot;),successEvent:new YAHOO.util.CustomEvent(&quot;success&quot;),failureEvent:new YAHOO.util.CustomEvent(&quot;failure&quot;),abortEvent:new YAHOO.util.CustomEvent(&quot;abort&quot;),_customEvents:{onStart:[&quot;startEvent&quot;,&quot;start&quot;],onComplete:[&quot;completeEvent&quot;,&quot;complete&quot;],onSuccess:[&quot;s
 uccessEvent&quot;,&quot;success&quot;],onFailure:[&quot;failureEvent&quot;,&quot;failure&quot;],onUpload:[&quot;uploadEvent&quot;,&quot;upload&quot;],onAbort:[&quot;abortEvent&quot;,&quot;abort&quot;]},setProgId:function(A){this._msxml_progid.unshift(A);},setDefaultPostHeader:function(A){if(typeof A==&quot;string&quot;){this._default_post_header=A;this._use_default_post_header=true;}else{if(typeof A==&quot;boolean&quot;){this._use_default_post_header=A;}}},setDefaultXhrHeader:function(A){if(typeof A==&quot;string&quot;){this._default_xhr_header=A;}else{this._use_default_xhr_header=A;}},setPollingInterval:function(A){if(typeof A==&quot;number&quot;&amp;&amp;isFinite(A)){this._polling_interval=A;}},createXhrObject:function(F){var D,A,B;try{A=new XMLHttpRequest();D={conn:A,tId:F,xhr:true};}catch(C){for(B=0;B&lt;this._msxml_progid.length;++B){try{A=new ActiveXObject(this._msxml_progid[B]);D={conn:A,tId:F,xhr:true};break;}catch(E){}}}finally{return D;}},getConnectionObject:functi
 on(A){var C,D=this._transaction_id;try{if(!A){C=this.createXhrObject(D);}else{C={tId:D};if(A===&quot;xdr&quot;){C.conn=this._transport;C.xdr=true;}else{if(A===&quot;upload&quot;){C.upload=true;}}}if(C){this._transaction_id++;}}catch(B){}return C;},asyncRequest:function(H,D,G,A){var B=G&amp;&amp;G.argument?G.argument:null,E=this,F,C;if(this._isFileUpload){C=&quot;upload&quot;;}else{if(G&amp;&amp;G.xdr){C=&quot;xdr&quot;;}}F=this.getConnectionObject(C);if(!F){return null;}else{if(G&amp;&amp;G.customevents){this.initCustomEvents(F,G);}if(this._isFormSubmit){if(this._isFileUpload){window.setTimeout(function(){E.uploadFile(F,G,D,A);},10);return F;}if(H.toUpperCase()==&quot;GET&quot;){if(this._sFormData.length!==0){D+=((D.indexOf(&quot;?&quot;)==-1)?&quot;?&quot;:&quot;&amp;&quot;)+this._sFormData;}}else{if(H.toUpperCase()==&quot;POST&quot;){A=A?this._sFormData+&quot;&amp;&quot;+A:this._sFormData;}}}if(H.toUpperCase()==&quot;GET&quot;&amp;&amp;(G&amp;&amp;G.cache===false)){D+=((D.
 indexOf(&quot;?&quot;)==-1)?&quot;?&quot;:&quot;&amp;&quot;)+&quot;rnd=&quot;+new Date().valueOf().toString();}if(this._use_default_xhr_header){if(!this._default_headers[&quot;X-Requested-With&quot;]){this.initHeader(&quot;X-Requested-With&quot;,this._default_xhr_header,true);}}if((H.toUpperCase()===&quot;POST&quot;&amp;&amp;this._use_default_post_header)&amp;&amp;this._isFormSubmit===false){this.initHeader(&quot;Content-Type&quot;,this._default_post_header);}if(F.xdr){this.xdr(F,H,D,G,A);return F;}F.conn.open(H,D,true);if(this._has_default_headers||this._has_http_headers){this.setHeader(F);}this.handleReadyState(F,G);F.conn.send(A||&quot;&quot;);if(this._isFormSubmit===true){this.resetFormState();}this.startEvent.fire(F,B);if(F.startEvent){F.startEvent.fire(F,B);}return F;}},initCustomEvents:function(A,C){var B;for(B in C.customevents){if(this._customEvents[B][0]){A[this._customEvents[B][0]]=new YAHOO.util.CustomEvent(this._customEvents[B][1],(C.scope)?C.scope:null);A[this.
 _customEvents[B][0]].subscribe(C.customevents[B]);}}},handleReadyState:function(C,D){var B=this,A=(D&amp;&amp;D.argument)?D.argument:null;if(D&amp;&amp;D.timeout){this._timeOut[C.tId]=window.setTimeout(function(){B.abort(C,D,true);},D.timeout);}this._poll[C.tId]=window.setInterval(function(){if(C.conn&amp;&amp;C.conn.readyState===4){window.clearInterval(B._poll[C.tId]);delete B._poll[C.tId];if(D&amp;&amp;D.timeout){window.clearTimeout(B._timeOut[C.tId]);delete B._timeOut[C.tId];}B.completeEvent.fire(C,A);if(C.completeEvent){C.completeEvent.fire(C,A);}B.handleTransactionResponse(C,D);}},this._polling_interval);},handleTransactionResponse:function(B,I,D){var E,A,G=(I&amp;&amp;I.argument)?I.argument:null,C=(B.r&amp;&amp;B.r.statusText===&quot;xdr:success&quot;)?true:false,H=(B.r&amp;&amp;B.r.statusText===&quot;xdr:failure&quot;)?true:false,J=D;try{if((B.conn.status!==undefined&amp;&amp;B.conn.status!==0)||C){E=B.conn.status;}else{if(H&amp;&amp;!J){E=0;}else{E=13030;}}}catch(F){
 E=13030;}if((E&gt;=200&amp;&amp;E&lt;300)||E===1223||C){A=B.xdr?B.r:this.createResponseObject(B,G);if(I&amp;&amp;I.success){if(!I.scope){I.success(A);}else{I.success.apply(I.scope,[A]);}}this.successEvent.fire(A);if(B.successEvent){B.successEvent.fire(A);}}else{switch(E){case 12002:case 12029:case 12030:case 12031:case 12152:case 13030:A=this.createExceptionObject(B.tId,G,(D?D:false));if(I&amp;&amp;I.failure){if(!I.scope){I.failure(A);}else{I.failure.apply(I.scope,[A]);}}break;default:A=(B.xdr)?B.response:this.createResponseObject(B,G);if(I&amp;&amp;I.failure){if(!I.scope){I.failure(A);}else{I.failure.apply(I.scope,[A]);}}}this.failureEvent.fire(A);if(B.failureEvent){B.failureEvent.fire(A);}}this.releaseObject(B);A=null;},createResponseObject:function(A,G){var D={},I={},E,C,F,B;try{C=A.conn.getAllResponseHeaders();F=C.split(&quot;\n&quot;);for(E=0;E&lt;F.length;E++){B=F[E].indexOf(&quot;:&quot;);if(B!=-1){I[F[E].substring(0,B)]=YAHOO.lang.trim(F[E].substring(B+2));}}}catch(H
 ){}D.tId=A.tId;D.status=(A.conn.status==1223)?204:A.conn.status;D.statusText=(A.conn.status==1223)?&quot;No Content&quot;:A.conn.statusText;D.getResponseHeader=I;D.getAllResponseHeaders=C;D.responseText=A.conn.responseText;D.responseXML=A.conn.responseXML;if(G){D.argument=G;}return D;},createExceptionObject:function(H,D,A){var F=0,G=&quot;communication failure&quot;,C=-1,B=&quot;transaction aborted&quot;,E={};E.tId=H;if(A){E.status=C;E.statusText=B;}else{E.status=F;E.statusText=G;}if(D){E.argument=D;}return E;},initHeader:function(A,D,C){var B=(C)?this._default_headers:this._http_headers;B[A]=D;if(C){this._has_default_headers=true;}else{this._has_http_headers=true;}},setHeader:function(A){var B;if(this._has_default_headers){for(B in this._default_headers){if(YAHOO.lang.hasOwnProperty(this._default_headers,B)){A.conn.setRequestHeader(B,this._default_headers[B]);
+}}}if(this._has_http_headers){for(B in this._http_headers){if(YAHOO.lang.hasOwnProperty(this._http_headers,B)){A.conn.setRequestHeader(B,this._http_headers[B]);}}this._http_headers={};this._has_http_headers=false;}},resetDefaultHeaders:function(){this._default_headers={};this._has_default_headers=false;},abort:function(E,G,A){var D,B=(G&amp;&amp;G.argument)?G.argument:null;E=E||{};if(E.conn){if(E.xhr){if(this.isCallInProgress(E)){E.conn.abort();window.clearInterval(this._poll[E.tId]);delete this._poll[E.tId];if(A){window.clearTimeout(this._timeOut[E.tId]);delete this._timeOut[E.tId];}D=true;}}else{if(E.xdr){E.conn.abort(E.tId);D=true;}}}else{if(E.upload){var C=&quot;yuiIO&quot;+E.tId;var F=document.getElementById(C);if(F){YAHOO.util.Event.removeListener(F,&quot;load&quot;);document.body.removeChild(F);if(A){window.clearTimeout(this._timeOut[E.tId]);delete this._timeOut[E.tId];}D=true;}}else{D=false;}}if(D===true){this.abortEvent.fire(E,B);if(E.abortEvent){E.abortEvent.fire(E
 ,B);}this.handleTransactionResponse(E,G,true);}return D;},isCallInProgress:function(A){A=A||{};if(A.xhr&amp;&amp;A.conn){return A.conn.readyState!==4&amp;&amp;A.conn.readyState!==0;}else{if(A.xdr&amp;&amp;A.conn){return A.conn.isCallInProgress(A.tId);}else{if(A.upload===true){return document.getElementById(&quot;yuiIO&quot;+A.tId)?true:false;}else{return false;}}}},releaseObject:function(A){if(A&amp;&amp;A.conn){A.conn=null;A=null;}}};YAHOO.register(&quot;connection_core&quot;,YAHOO.util.Connect,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuicontainercontainerminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/container/container-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/container/container-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/container/container-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,19 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+(function(){YAHOO.util.Config=function(d){if(d){this.init(d);}};var b=YAHOO.lang,c=YAHOO.util.CustomEvent,a=YAHOO.util.Config;a.CONFIG_CHANGED_EVENT=&quot;configChanged&quot;;a.BOOLEAN_TYPE=&quot;boolean&quot;;a.prototype={owner:null,queueInProgress:false,config:null,initialConfig:null,eventQueue:null,configChangedEvent:null,init:function(d){this.owner=d;this.configChangedEvent=this.createEvent(a.CONFIG_CHANGED_EVENT);this.configChangedEvent.signature=c.LIST;this.queueInProgress=false;this.config={};this.initialConfig={};this.eventQueue=[];},checkBoolean:function(d){return(typeof d==a.BOOLEAN_TYPE);},checkNumber:function(d){return(!isNaN(d));},fireEvent:function(d,f){var e=this.config[d];if(e&amp;&amp;e.event){e.event.fire(f);}},addProperty:function(e,d){e=e.toLowerCase();this.config[e]=d;d.event=this.createEvent(e,{scope:this.owner});d.event.signature=c.LIST;d.key=e;if(d.handler){d.event.subscribe(d.handler,this.owner);}this.setProperty(e,d.value,true);if(!d.suppressEvent){
 this.queueProperty(e,d.value);}},getConfig:function(){var d={},f=this.config,g,e;for(g in f){if(b.hasOwnProperty(f,g)){e=f[g];if(e&amp;&amp;e.event){d[g]=e.value;}}}return d;},getProperty:function(d){var e=this.config[d.toLowerCase()];if(e&amp;&amp;e.event){return e.value;}else{return undefined;}},resetProperty:function(d){d=d.toLowerCase();var e=this.config[d];if(e&amp;&amp;e.event){if(d in this.initialConfig){this.setProperty(d,this.initialConfig[d]);return true;}}else{return false;}},setProperty:function(e,g,d){var f;e=e.toLowerCase();if(this.queueInProgress&amp;&amp;!d){this.queueProperty(e,g);return true;}else{f=this.config[e];if(f&amp;&amp;f.event){if(f.validator&amp;&amp;!f.validator(g)){return false;}else{f.value=g;if(!d){this.fireEvent(e,g);this.configChangedEvent.fire([e,g]);}return true;}}else{return false;}}},queueProperty:function(v,r){v=v.toLowerCase();var u=this.config[v],l=false,k,g,h,j,p,t,f,n,o,d,m,w,e;if(u&amp;&amp;u.event){if(!b.isUndefined(r)&amp;&amp;u.
 validator&amp;&amp;!u.validator(r)){return false;}else{if(!b.isUndefined(r)){u.value=r;}else{r=u.value;}l=false;k=this.eventQueue.length;for(m=0;m&lt;k;m++){g=this.eventQueue[m];if(g){h=g[0];j=g[1];if(h==v){this.eventQueue[m]=null;this.eventQueue.push([v,(!b.isUndefined(r)?r:j)]);l=true;break;}}}if(!l&amp;&amp;!b.isUndefined(r)){this.eventQueue.push([v,r]);}}if(u.supercedes){p=u.supercedes.length;for(w=0;w&lt;p;w++){t=u.supercedes[w];f=this.eventQueue.length;for(e=0;e&lt;f;e++){n=this.eventQueue[e];if(n){o=n[0];d=n[1];if(o==t.toLowerCase()){this.eventQueue.push([o,d]);this.eventQueue[e]=null;break;}}}}}return true;}else{return false;}},refireEvent:function(d){d=d.toLowerCase();var e=this.config[d];if(e&amp;&amp;e.event&amp;&amp;!b.isUndefined(e.value)){if(this.queueInProgress){this.queueProperty(d);}else{this.fireEvent(d,e.value);}}},applyConfig:function(d,g){var f,e;if(g){e={};for(f in d){if(b.hasOwnProperty(d,f)){e[f.toLowerCase()]=d[f];}}this.initialConfig=e;}for(f in d){
 if(b.hasOwnProperty(d,f)){this.queueProperty(f,d[f]);}}},refresh:function(){var d;for(d in this.config){if(b.hasOwnProperty(this.config,d)){this.refireEvent(d);}}},fireQueue:function(){var e,h,d,g,f;this.queueInProgress=true;for(e=0;e&lt;this.eventQueue.length;e++){h=this.eventQueue[e];if(h){d=h[0];g=h[1];f=this.config[d];f.value=g;this.eventQueue[e]=null;this.fireEvent(d,g);}}this.queueInProgress=false;this.eventQueue=[];},subscribeToConfigEvent:function(d,e,g,h){var f=this.config[d.toLowerCase()];if(f&amp;&amp;f.event){if(!a.alreadySubscribed(f.event,e,g)){f.event.subscribe(e,g,h);}return true;}else{return false;}},unsubscribeFromConfigEvent:function(d,e,g){var f=this.config[d.toLowerCase()];if(f&amp;&amp;f.event){return f.event.unsubscribe(e,g);}else{return false;}},toString:function(){var d=&quot;Config&quot;;if(this.owner){d+=&quot; [&quot;+this.owner.toString()+&quot;]&quot;;}return d;},outputEventQueue:function(){var d=&quot;&quot;,g,e,f=this.eventQueue.length;for(e=0
 ;e&lt;f;e++){g=this.eventQueue[e];if(g){d+=g[0]+&quot;=&quot;+g[1]+&quot;, &quot;;}}return d;},destroy:function(){var e=this.config,d,f;for(d in e){if(b.hasOwnProperty(e,d)){f=e[d];f.event.unsubscribeAll();f.event=null;}}this.configChangedEvent.unsubscribeAll();this.configChangedEvent=null;this.owner=null;this.config=null;this.initialConfig=null;this.eventQueue=null;}};a.alreadySubscribed=function(e,h,j){var f=e.subscribers.length,d,g;if(f&gt;0){g=f-1;do{d=e.subscribers[g];if(d&amp;&amp;d.obj==j&amp;&amp;d.fn==h){return true;}}while(g--);}return false;};YAHOO.lang.augmentProto(a,YAHOO.util.EventProvider);}());(function(){YAHOO.widget.Module=function(r,q){if(r){this.init(r,q);}else{}};var f=YAHOO.util.Dom,d=YAHOO.util.Config,n=YAHOO.util.Event,m=YAHOO.util.CustomEvent,g=YAHOO.widget.Module,i=YAHOO.env.ua,h,p,o,e,a={&quot;BEFORE_INIT&quot;:&quot;beforeInit&quot;,&quot;INIT&quot;:&quot;init&quot;,&quot;APPEND&quot;:&quot;append&quot;,&quot;BEFORE_RENDER&quot;:&quot;beforeRender
 &quot;,&quot;RENDER&quot;:&quot;render&quot;,&quot;CHANGE_HEADER&quot;:&quot;changeHeader&quot;,&quot;CHANGE_BODY&quot;:&quot;changeBody&quot;,&quot;CHANGE_FOOTER&quot;:&quot;changeFooter&quot;,&quot;CHANGE_CONTENT&quot;:&quot;changeContent&quot;,&quot;DESTROY&quot;:&quot;destroy&quot;,&quot;BEFORE_SHOW&quot;:&quot;beforeShow&quot;,&quot;SHOW&quot;:&quot;show&quot;,&quot;BEFORE_HIDE&quot;:&quot;beforeHide&quot;,&quot;HIDE&quot;:&quot;hide&quot;},j={&quot;VISIBLE&quot;:{key:&quot;visible&quot;,value:true,validator:YAHOO.lang.isBoolean},&quot;EFFECT&quot;:{key:&quot;effect&quot;,suppressEvent:true,supercedes:[&quot;visible&quot;]},&quot;MONITOR_RESIZE&quot;:{key:&quot;monitorresize&quot;,value:true},&quot;APPEND_TO_DOCUMENT_BODY&quot;:{key:&quot;appendtodocumentbody&quot;,value:false}};g.IMG_ROOT=null;g.IMG_ROOT_SSL=null;g.CSS_MODULE=&quot;yui-module&quot;;g.CSS_HEADER=&quot;hd&quot;;g.CSS_BODY=&quot;bd&quot;;g.CSS_FOOTER=&quot;ft&quot;;g.RESIZE_MONITOR_SECURE_URL=&quot;javasc
 ript:false;&quot;;g.RESIZE_MONITOR_BUFFER=1;g.textResizeEvent=new m(&quot;textResize&quot;);g.forceDocumentRedraw=function(){var q=document.documentElement;if(q){q.className+=&quot; &quot;;q.className=YAHOO.lang.trim(q.className);}};function l(){if(!h){h=document.createElement(&quot;div&quot;);h.innerHTML=('&lt;div class=&quot;'+g.CSS_HEADER+'&quot;&gt;&lt;/div&gt;'+'&lt;div class=&quot;'+g.CSS_BODY+'&quot;&gt;&lt;/div&gt;&lt;div class=&quot;'+g.CSS_FOOTER+'&quot;&gt;&lt;/div&gt;');p=h.firstChild;o=p.nextSibling;e=o.nextSibling;}return h;}function k(){if(!p){l();}return(p.cloneNode(false));}function b(){if(!o){l();}return(o.cloneNode(false));}function c(){if(!e){l();}return(e.cloneNode(false));}g.prototype={constructor:g,element:null,header:null,body:null,footer:null,id:null,imageRoot:g.IMG_ROOT,initEvents:function(){var q=m.LIST;
+this.beforeInitEvent=this.createEvent(a.BEFORE_INIT);this.beforeInitEvent.signature=q;this.initEvent=this.createEvent(a.INIT);this.initEvent.signature=q;this.appendEvent=this.createEvent(a.APPEND);this.appendEvent.signature=q;this.beforeRenderEvent=this.createEvent(a.BEFORE_RENDER);this.beforeRenderEvent.signature=q;this.renderEvent=this.createEvent(a.RENDER);this.renderEvent.signature=q;this.changeHeaderEvent=this.createEvent(a.CHANGE_HEADER);this.changeHeaderEvent.signature=q;this.changeBodyEvent=this.createEvent(a.CHANGE_BODY);this.changeBodyEvent.signature=q;this.changeFooterEvent=this.createEvent(a.CHANGE_FOOTER);this.changeFooterEvent.signature=q;this.changeContentEvent=this.createEvent(a.CHANGE_CONTENT);this.changeContentEvent.signature=q;this.destroyEvent=this.createEvent(a.DESTROY);this.destroyEvent.signature=q;this.beforeShowEvent=this.createEvent(a.BEFORE_SHOW);this.beforeShowEvent.signature=q;this.showEvent=this.createEvent(a.SHOW);this.showEvent.signature=q;this
 .beforeHideEvent=this.createEvent(a.BEFORE_HIDE);this.beforeHideEvent.signature=q;this.hideEvent=this.createEvent(a.HIDE);this.hideEvent.signature=q;},platform:function(){var q=navigator.userAgent.toLowerCase();if(q.indexOf(&quot;windows&quot;)!=-1||q.indexOf(&quot;win32&quot;)!=-1){return&quot;windows&quot;;}else{if(q.indexOf(&quot;macintosh&quot;)!=-1){return&quot;mac&quot;;}else{return false;}}}(),browser:function(){var q=navigator.userAgent.toLowerCase();if(q.indexOf(&quot;opera&quot;)!=-1){return&quot;opera&quot;;}else{if(q.indexOf(&quot;msie 7&quot;)!=-1){return&quot;ie7&quot;;}else{if(q.indexOf(&quot;msie&quot;)!=-1){return&quot;ie&quot;;}else{if(q.indexOf(&quot;safari&quot;)!=-1){return&quot;safari&quot;;}else{if(q.indexOf(&quot;gecko&quot;)!=-1){return&quot;gecko&quot;;}else{return false;}}}}}}(),isSecure:function(){if(window.location.href.toLowerCase().indexOf(&quot;https&quot;)===0){return true;}else{return false;}}(),initDefaultConfig:function(){this.cfg.addPrope
 rty(j.VISIBLE.key,{handler:this.configVisible,value:j.VISIBLE.value,validator:j.VISIBLE.validator});this.cfg.addProperty(j.EFFECT.key,{handler:this.configEffect,suppressEvent:j.EFFECT.suppressEvent,supercedes:j.EFFECT.supercedes});this.cfg.addProperty(j.MONITOR_RESIZE.key,{handler:this.configMonitorResize,value:j.MONITOR_RESIZE.value});this.cfg.addProperty(j.APPEND_TO_DOCUMENT_BODY.key,{value:j.APPEND_TO_DOCUMENT_BODY.value});},init:function(v,u){var s,w;this.initEvents();this.beforeInitEvent.fire(g);this.cfg=new d(this);if(this.isSecure){this.imageRoot=g.IMG_ROOT_SSL;}if(typeof v==&quot;string&quot;){s=v;v=document.getElementById(v);if(!v){v=(l()).cloneNode(false);v.id=s;}}this.id=f.generateId(v);this.element=v;w=this.element.firstChild;if(w){var r=false,q=false,t=false;do{if(1==w.nodeType){if(!r&amp;&amp;f.hasClass(w,g.CSS_HEADER)){this.header=w;r=true;}else{if(!q&amp;&amp;f.hasClass(w,g.CSS_BODY)){this.body=w;q=true;}else{if(!t&amp;&amp;f.hasClass(w,g.CSS_FOOTER)){this.fo
 oter=w;t=true;}}}}}while((w=w.nextSibling));}this.initDefaultConfig();f.addClass(this.element,g.CSS_MODULE);if(u){this.cfg.applyConfig(u,true);}if(!d.alreadySubscribed(this.renderEvent,this.cfg.fireQueue,this.cfg)){this.renderEvent.subscribe(this.cfg.fireQueue,this.cfg,true);}this.initEvent.fire(g);},initResizeMonitor:function(){var r=(i.gecko&amp;&amp;this.platform==&quot;windows&quot;);if(r){var q=this;setTimeout(function(){q._initResizeMonitor();},0);}else{this._initResizeMonitor();}},_initResizeMonitor:function(){var q,s,u;function w(){g.textResizeEvent.fire();}if(!i.opera){s=f.get(&quot;_yuiResizeMonitor&quot;);var v=this._supportsCWResize();if(!s){s=document.createElement(&quot;iframe&quot;);if(this.isSecure&amp;&amp;g.RESIZE_MONITOR_SECURE_URL&amp;&amp;i.ie){s.src=g.RESIZE_MONITOR_SECURE_URL;}if(!v){u=[&quot;&lt;html&gt;&lt;head&gt;&lt;script &quot;,'type=&quot;text/javascript&quot;&gt;',&quot;window.onresize=function(){window.parent.&quot;,&quot;YAHOO.widget.Module.t
 extResizeEvent.&quot;,&quot;fire();};&lt;&quot;,&quot;/script&gt;&lt;/head&gt;&quot;,&quot;&lt;body&gt;&lt;/body&gt;&lt;/html&gt;&quot;].join(&quot;&quot;);s.src=&quot;data:text/html;charset=utf-8,&quot;+encodeURIComponent(u);}s.id=&quot;_yuiResizeMonitor&quot;;s.title=&quot;Text Resize Monitor&quot;;s.tabIndex=-1;s.setAttribute(&quot;role&quot;,&quot;presentation&quot;);s.style.position=&quot;absolute&quot;;s.style.visibility=&quot;hidden&quot;;var r=document.body,t=r.firstChild;if(t){r.insertBefore(s,t);}else{r.appendChild(s);}s.style.backgroundColor=&quot;transparent&quot;;s.style.borderWidth=&quot;0&quot;;s.style.width=&quot;2em&quot;;s.style.height=&quot;2em&quot;;s.style.left=&quot;0&quot;;s.style.top=(-1*(s.offsetHeight+g.RESIZE_MONITOR_BUFFER))+&quot;px&quot;;s.style.visibility=&quot;visible&quot;;if(i.webkit){q=s.contentWindow.document;q.open();q.close();}}if(s&amp;&amp;s.contentWindow){g.textResizeEvent.subscribe(this.onDomResize,this,true);if(!g.textResizeInitiali
 zed){if(v){if(!n.on(s.contentWindow,&quot;resize&quot;,w)){n.on(s,&quot;resize&quot;,w);}}g.textResizeInitialized=true;}this.resizeMonitor=s;}}},_supportsCWResize:function(){var q=true;if(i.gecko&amp;&amp;i.gecko&lt;=1.8){q=false;}return q;},onDomResize:function(s,r){var q=-1*(this.resizeMonitor.offsetHeight+g.RESIZE_MONITOR_BUFFER);this.resizeMonitor.style.top=q+&quot;px&quot;;this.resizeMonitor.style.left=&quot;0&quot;;},setHeader:function(r){var q=this.header||(this.header=k());if(r.nodeName){q.innerHTML=&quot;&quot;;q.appendChild(r);}else{q.innerHTML=r;}if(this._rendered){this._renderHeader();}this.changeHeaderEvent.fire(r);this.changeContentEvent.fire();},appendToHeader:function(r){var q=this.header||(this.header=k());q.appendChild(r);this.changeHeaderEvent.fire(r);this.changeContentEvent.fire();},setBody:function(r){var q=this.body||(this.body=b());if(r.nodeName){q.innerHTML=&quot;&quot;;q.appendChild(r);}else{q.innerHTML=r;}if(this._rendered){this._renderBody();}this.
 changeBodyEvent.fire(r);this.changeContentEvent.fire();},appendToBody:function(r){var q=this.body||(this.body=b());q.appendChild(r);this.changeBodyEvent.fire(r);this.changeContentEvent.fire();},setFooter:function(r){var q=this.footer||(this.footer=c());if(r.nodeName){q.innerHTML=&quot;&quot;;q.appendChild(r);}else{q.innerHTML=r;}if(this._rendered){this._renderFooter();}this.changeFooterEvent.fire(r);this.changeContentEvent.fire();},appendToFooter:function(r){var q=this.footer||(this.footer=c());q.appendChild(r);this.changeFooterEvent.fire(r);this.changeContentEvent.fire();},render:function(s,q){var t=this;function r(u){if(typeof u==&quot;string&quot;){u=document.getElementById(u);
+}if(u){t._addToParent(u,t.element);t.appendEvent.fire();}}this.beforeRenderEvent.fire();if(!q){q=this.element;}if(s){r(s);}else{if(!f.inDocument(this.element)){return false;}}this._renderHeader(q);this._renderBody(q);this._renderFooter(q);this._rendered=true;this.renderEvent.fire();return true;},_renderHeader:function(q){q=q||this.element;if(this.header&amp;&amp;!f.inDocument(this.header)){var r=q.firstChild;if(r){q.insertBefore(this.header,r);}else{q.appendChild(this.header);}}},_renderBody:function(q){q=q||this.element;if(this.body&amp;&amp;!f.inDocument(this.body)){if(this.footer&amp;&amp;f.isAncestor(q,this.footer)){q.insertBefore(this.body,this.footer);}else{q.appendChild(this.body);}}},_renderFooter:function(q){q=q||this.element;if(this.footer&amp;&amp;!f.inDocument(this.footer)){q.appendChild(this.footer);}},destroy:function(q){var r,s=!(q);if(this.element){n.purgeElement(this.element,s);r=this.element.parentNode;}if(r){r.removeChild(this.element);}this.element=null;t
 his.header=null;this.body=null;this.footer=null;g.textResizeEvent.unsubscribe(this.onDomResize,this);this.cfg.destroy();this.cfg=null;this.destroyEvent.fire();},show:function(){this.cfg.setProperty(&quot;visible&quot;,true);},hide:function(){this.cfg.setProperty(&quot;visible&quot;,false);},configVisible:function(r,q,s){var t=q[0];if(t){if(this.beforeShowEvent.fire()){f.setStyle(this.element,&quot;display&quot;,&quot;block&quot;);this.showEvent.fire();}}else{if(this.beforeHideEvent.fire()){f.setStyle(this.element,&quot;display&quot;,&quot;none&quot;);this.hideEvent.fire();}}},configEffect:function(r,q,s){this._cachedEffects=(this.cacheEffects)?this._createEffects(q[0]):null;},cacheEffects:true,_createEffects:function(t){var q=null,u,r,s;if(t){if(t instanceof Array){q=[];u=t.length;for(r=0;r&lt;u;r++){s=t[r];if(s.effect){q[q.length]=s.effect(this,s.duration);}}}else{if(t.effect){q=[t.effect(this,t.duration)];}}}return q;},configMonitorResize:function(s,r,t){var q=r[0];if(q){t
 his.initResizeMonitor();}else{g.textResizeEvent.unsubscribe(this.onDomResize,this,true);this.resizeMonitor=null;}},_addToParent:function(q,r){if(!this.cfg.getProperty(&quot;appendtodocumentbody&quot;)&amp;&amp;q===document.body&amp;&amp;q.firstChild){q.insertBefore(r,q.firstChild);}else{q.appendChild(r);}},toString:function(){return&quot;Module &quot;+this.id;}};YAHOO.lang.augmentProto(g,YAHOO.util.EventProvider);}());(function(){YAHOO.widget.Overlay=function(p,o){YAHOO.widget.Overlay.superclass.constructor.call(this,p,o);};var i=YAHOO.lang,m=YAHOO.util.CustomEvent,g=YAHOO.widget.Module,n=YAHOO.util.Event,f=YAHOO.util.Dom,d=YAHOO.util.Config,k=YAHOO.env.ua,b=YAHOO.widget.Overlay,h=&quot;subscribe&quot;,e=&quot;unsubscribe&quot;,c=&quot;contained&quot;,j,a={&quot;BEFORE_MOVE&quot;:&quot;beforeMove&quot;,&quot;MOVE&quot;:&quot;move&quot;},l={&quot;X&quot;:{key:&quot;x&quot;,validator:i.isNumber,suppressEvent:true,supercedes:[&quot;iframe&quot;]},&quot;Y&quot;:{key:&quot;y&quot
 ;,validator:i.isNumber,suppressEvent:true,supercedes:[&quot;iframe&quot;]},&quot;XY&quot;:{key:&quot;xy&quot;,suppressEvent:true,supercedes:[&quot;iframe&quot;]},&quot;CONTEXT&quot;:{key:&quot;context&quot;,suppressEvent:true,supercedes:[&quot;iframe&quot;]},&quot;FIXED_CENTER&quot;:{key:&quot;fixedcenter&quot;,value:false,supercedes:[&quot;iframe&quot;,&quot;visible&quot;]},&quot;WIDTH&quot;:{key:&quot;width&quot;,suppressEvent:true,supercedes:[&quot;context&quot;,&quot;fixedcenter&quot;,&quot;iframe&quot;]},&quot;HEIGHT&quot;:{key:&quot;height&quot;,suppressEvent:true,supercedes:[&quot;context&quot;,&quot;fixedcenter&quot;,&quot;iframe&quot;]},&quot;AUTO_FILL_HEIGHT&quot;:{key:&quot;autofillheight&quot;,supercedes:[&quot;height&quot;],value:&quot;body&quot;},&quot;ZINDEX&quot;:{key:&quot;zindex&quot;,value:null},&quot;CONSTRAIN_TO_VIEWPORT&quot;:{key:&quot;constraintoviewport&quot;,value:false,validator:i.isBoolean,supercedes:[&quot;iframe&quot;,&quot;x&quot;,&quot;y&quot;
 ,&quot;xy&quot;]},&quot;IFRAME&quot;:{key:&quot;iframe&quot;,value:(k.ie==6?true:false),validator:i.isBoolean,supercedes:[&quot;zindex&quot;]},&quot;PREVENT_CONTEXT_OVERLAP&quot;:{key:&quot;preventcontextoverlap&quot;,value:false,validator:i.isBoolean,supercedes:[&quot;constraintoviewport&quot;]}};b.IFRAME_SRC=&quot;javascript:false;&quot;;b.IFRAME_OFFSET=3;b.VIEWPORT_OFFSET=10;b.TOP_LEFT=&quot;tl&quot;;b.TOP_RIGHT=&quot;tr&quot;;b.BOTTOM_LEFT=&quot;bl&quot;;b.BOTTOM_RIGHT=&quot;br&quot;;b.PREVENT_OVERLAP_X={&quot;tltr&quot;:true,&quot;blbr&quot;:true,&quot;brbl&quot;:true,&quot;trtl&quot;:true};b.PREVENT_OVERLAP_Y={&quot;trbr&quot;:true,&quot;tlbl&quot;:true,&quot;bltl&quot;:true,&quot;brtr&quot;:true};b.CSS_OVERLAY=&quot;yui-overlay&quot;;b.CSS_HIDDEN=&quot;yui-overlay-hidden&quot;;b.CSS_IFRAME=&quot;yui-overlay-iframe&quot;;b.STD_MOD_RE=/^\s*?(body|footer|header)\s*?$/i;b.windowScrollEvent=new m(&quot;windowScroll&quot;);b.windowResizeEvent=new m(&quot;windowResize&quot;)
 ;b.windowScrollHandler=function(p){var o=n.getTarget(p);if(!o||o===window||o===window.document){if(k.ie){if(!window.scrollEnd){window.scrollEnd=-1;}clearTimeout(window.scrollEnd);window.scrollEnd=setTimeout(function(){b.windowScrollEvent.fire();},1);}else{b.windowScrollEvent.fire();}}};b.windowResizeHandler=function(o){if(k.ie){if(!window.resizeEnd){window.resizeEnd=-1;}clearTimeout(window.resizeEnd);window.resizeEnd=setTimeout(function(){b.windowResizeEvent.fire();},100);}else{b.windowResizeEvent.fire();}};b._initialized=null;if(b._initialized===null){n.on(window,&quot;scroll&quot;,b.windowScrollHandler);n.on(window,&quot;resize&quot;,b.windowResizeHandler);b._initialized=true;}b._TRIGGER_MAP={&quot;windowScroll&quot;:b.windowScrollEvent,&quot;windowResize&quot;:b.windowResizeEvent,&quot;textResize&quot;:g.textResizeEvent};YAHOO.extend(b,g,{CONTEXT_TRIGGERS:[],init:function(p,o){b.superclass.init.call(this,p);this.beforeInitEvent.fire(b);f.addClass(this.element,b.CSS_OVERLA
 Y);if(o){this.cfg.applyConfig(o,true);}if(this.platform==&quot;mac&quot;&amp;&amp;k.gecko){if(!d.alreadySubscribed(this.showEvent,this.showMacGeckoScrollbars,this)){this.showEvent.subscribe(this.showMacGeckoScrollbars,this,true);}if(!d.alreadySubscribed(this.hideEvent,this.hideMacGeckoScrollbars,this)){this.hideEvent.subscribe(this.hideMacGeckoScrollbars,this,true);}}this.initEvent.fire(b);},initEvents:function(){b.superclass.initEvents.call(this);var o=m.LIST;this.beforeMoveEvent=this.createEvent(a.BEFORE_MOVE);this.beforeMoveEvent.signature=o;this.moveEvent=this.createEvent(a.MOVE);this.moveEvent.signature=o;},initDefaultConfig:function(){b.superclass.initDefaultConfig.call(this);var o=this.cfg;o.addProperty(l.X.key,{handler:this.configX,validator:l.X.validator,suppressEvent:l.X.suppressEvent,supercedes:l.X.supercedes});o.addProperty(l.Y.key,{handler:this.configY,validator:l.Y.validator,suppressEvent:l.Y.suppressEvent,supercedes:l.Y.supercedes});
+o.addProperty(l.XY.key,{handler:this.configXY,suppressEvent:l.XY.suppressEvent,supercedes:l.XY.supercedes});o.addProperty(l.CONTEXT.key,{handler:this.configContext,suppressEvent:l.CONTEXT.suppressEvent,supercedes:l.CONTEXT.supercedes});o.addProperty(l.FIXED_CENTER.key,{handler:this.configFixedCenter,value:l.FIXED_CENTER.value,validator:l.FIXED_CENTER.validator,supercedes:l.FIXED_CENTER.supercedes});o.addProperty(l.WIDTH.key,{handler:this.configWidth,suppressEvent:l.WIDTH.suppressEvent,supercedes:l.WIDTH.supercedes});o.addProperty(l.HEIGHT.key,{handler:this.configHeight,suppressEvent:l.HEIGHT.suppressEvent,supercedes:l.HEIGHT.supercedes});o.addProperty(l.AUTO_FILL_HEIGHT.key,{handler:this.configAutoFillHeight,value:l.AUTO_FILL_HEIGHT.value,validator:this._validateAutoFill,supercedes:l.AUTO_FILL_HEIGHT.supercedes});o.addProperty(l.ZINDEX.key,{handler:this.configzIndex,value:l.ZINDEX.value});o.addProperty(l.CONSTRAIN_TO_VIEWPORT.key,{handler:this.configConstrainToViewport,value
 :l.CONSTRAIN_TO_VIEWPORT.value,validator:l.CONSTRAIN_TO_VIEWPORT.validator,supercedes:l.CONSTRAIN_TO_VIEWPORT.supercedes});o.addProperty(l.IFRAME.key,{handler:this.configIframe,value:l.IFRAME.value,validator:l.IFRAME.validator,supercedes:l.IFRAME.supercedes});o.addProperty(l.PREVENT_CONTEXT_OVERLAP.key,{value:l.PREVENT_CONTEXT_OVERLAP.value,validator:l.PREVENT_CONTEXT_OVERLAP.validator,supercedes:l.PREVENT_CONTEXT_OVERLAP.supercedes});},moveTo:function(o,p){this.cfg.setProperty(&quot;xy&quot;,[o,p]);},hideMacGeckoScrollbars:function(){f.replaceClass(this.element,&quot;show-scrollbars&quot;,&quot;hide-scrollbars&quot;);},showMacGeckoScrollbars:function(){f.replaceClass(this.element,&quot;hide-scrollbars&quot;,&quot;show-scrollbars&quot;);},_setDomVisibility:function(o){f.setStyle(this.element,&quot;visibility&quot;,(o)?&quot;visible&quot;:&quot;hidden&quot;);var p=b.CSS_HIDDEN;if(o){f.removeClass(this.element,p);}else{f.addClass(this.element,p);}},configVisible:function(x,w,t
 ){var p=w[0],B=f.getStyle(this.element,&quot;visibility&quot;),o=this._cachedEffects||this._createEffects(this.cfg.getProperty(&quot;effect&quot;)),A=(this.platform==&quot;mac&quot;&amp;&amp;k.gecko),y=d.alreadySubscribed,q,v,s,r,u,z;if(B==&quot;inherit&quot;){v=this.element.parentNode;while(v.nodeType!=9&amp;&amp;v.nodeType!=11){B=f.getStyle(v,&quot;visibility&quot;);if(B!=&quot;inherit&quot;){break;}v=v.parentNode;}if(B==&quot;inherit&quot;){B=&quot;visible&quot;;}}if(p){if(A){this.showMacGeckoScrollbars();}if(o){if(p){if(B!=&quot;visible&quot;||B===&quot;&quot;||this._fadingOut){if(this.beforeShowEvent.fire()){z=o.length;for(s=0;s&lt;z;s++){q=o[s];if(s===0&amp;&amp;!y(q.animateInCompleteEvent,this.showEvent.fire,this.showEvent)){q.animateInCompleteEvent.subscribe(this.showEvent.fire,this.showEvent,true);}q.animateIn();}}}}}else{if(B!=&quot;visible&quot;||B===&quot;&quot;){if(this.beforeShowEvent.fire()){this._setDomVisibility(true);this.cfg.refireEvent(&quot;iframe&quot;)
 ;this.showEvent.fire();}}else{this._setDomVisibility(true);}}}else{if(A){this.hideMacGeckoScrollbars();}if(o){if(B==&quot;visible&quot;||this._fadingIn){if(this.beforeHideEvent.fire()){z=o.length;for(r=0;r&lt;z;r++){u=o[r];if(r===0&amp;&amp;!y(u.animateOutCompleteEvent,this.hideEvent.fire,this.hideEvent)){u.animateOutCompleteEvent.subscribe(this.hideEvent.fire,this.hideEvent,true);}u.animateOut();}}}else{if(B===&quot;&quot;){this._setDomVisibility(false);}}}else{if(B==&quot;visible&quot;||B===&quot;&quot;){if(this.beforeHideEvent.fire()){this._setDomVisibility(false);this.hideEvent.fire();}}else{this._setDomVisibility(false);}}}},doCenterOnDOMEvent:function(){var o=this.cfg,p=o.getProperty(&quot;fixedcenter&quot;);if(o.getProperty(&quot;visible&quot;)){if(p&amp;&amp;(p!==c||this.fitsInViewport())){this.center();}}},fitsInViewport:function(){var s=b.VIEWPORT_OFFSET,q=this.element,t=q.offsetWidth,r=q.offsetHeight,o=f.getViewportWidth(),p=f.getViewportHeight();return((t+s&lt;o)
 &amp;&amp;(r+s&lt;p));},configFixedCenter:function(s,q,t){var u=q[0],p=d.alreadySubscribed,r=b.windowResizeEvent,o=b.windowScrollEvent;if(u){this.center();if(!p(this.beforeShowEvent,this.center)){this.beforeShowEvent.subscribe(this.center);}if(!p(r,this.doCenterOnDOMEvent,this)){r.subscribe(this.doCenterOnDOMEvent,this,true);}if(!p(o,this.doCenterOnDOMEvent,this)){o.subscribe(this.doCenterOnDOMEvent,this,true);}}else{this.beforeShowEvent.unsubscribe(this.center);r.unsubscribe(this.doCenterOnDOMEvent,this);o.unsubscribe(this.doCenterOnDOMEvent,this);}},configHeight:function(r,p,s){var o=p[0],q=this.element;f.setStyle(q,&quot;height&quot;,o);this.cfg.refireEvent(&quot;iframe&quot;);},configAutoFillHeight:function(t,s,p){var v=s[0],q=this.cfg,u=&quot;autofillheight&quot;,w=&quot;height&quot;,r=q.getProperty(u),o=this._autoFillOnHeightChange;q.unsubscribeFromConfigEvent(w,o);g.textResizeEvent.unsubscribe(o);this.changeContentEvent.unsubscribe(o);if(r&amp;&amp;v!==r&amp;&amp;this
 [r]){f.setStyle(this[r],w,&quot;&quot;);}if(v){v=i.trim(v.toLowerCase());q.subscribeToConfigEvent(w,o,this[v],this);g.textResizeEvent.subscribe(o,this[v],this);this.changeContentEvent.subscribe(o,this[v],this);q.setProperty(u,v,true);}},configWidth:function(r,o,s){var q=o[0],p=this.element;f.setStyle(p,&quot;width&quot;,q);this.cfg.refireEvent(&quot;iframe&quot;);},configzIndex:function(q,o,r){var s=o[0],p=this.element;if(!s){s=f.getStyle(p,&quot;zIndex&quot;);if(!s||isNaN(s)){s=0;}}if(this.iframe||this.cfg.getProperty(&quot;iframe&quot;)===true){if(s&lt;=0){s=1;}}f.setStyle(p,&quot;zIndex&quot;,s);this.cfg.setProperty(&quot;zIndex&quot;,s,true);if(this.iframe){this.stackIframe();}},configXY:function(q,p,r){var t=p[0],o=t[0],s=t[1];this.cfg.setProperty(&quot;x&quot;,o);this.cfg.setProperty(&quot;y&quot;,s);this.beforeMoveEvent.fire([o,s]);o=this.cfg.getProperty(&quot;x&quot;);s=this.cfg.getProperty(&quot;y&quot;);this.cfg.refireEvent(&quot;iframe&quot;);this.moveEvent.fire([
 o,s]);},configX:function(q,p,r){var o=p[0],s=this.cfg.getProperty(&quot;y&quot;);this.cfg.setProperty(&quot;x&quot;,o,true);this.cfg.setProperty(&quot;y&quot;,s,true);this.beforeMoveEvent.fire([o,s]);o=this.cfg.getProperty(&quot;x&quot;);s=this.cfg.getProperty(&quot;y&quot;);f.setX(this.element,o,true);this.cfg.setProperty(&quot;xy&quot;,[o,s],true);this.cfg.refireEvent(&quot;iframe&quot;);this.moveEvent.fire([o,s]);},configY:function(q,p,r){var o=this.cfg.getProperty(&quot;x&quot;),s=p[0];this.cfg.setProperty(&quot;x&quot;,o,true);this.cfg.setProperty(&quot;y&quot;,s,true);this.beforeMoveEvent.fire([o,s]);o=this.cfg.getProperty(&quot;x&quot;);s=this.cfg.getProperty(&quot;y&quot;);f.setY(this.element,s,true);
+this.cfg.setProperty(&quot;xy&quot;,[o,s],true);this.cfg.refireEvent(&quot;iframe&quot;);this.moveEvent.fire([o,s]);},showIframe:function(){var p=this.iframe,o;if(p){o=this.element.parentNode;if(o!=p.parentNode){this._addToParent(o,p);}p.style.display=&quot;block&quot;;}},hideIframe:function(){if(this.iframe){this.iframe.style.display=&quot;none&quot;;}},syncIframe:function(){var o=this.iframe,q=this.element,s=b.IFRAME_OFFSET,p=(s*2),r;if(o){o.style.width=(q.offsetWidth+p+&quot;px&quot;);o.style.height=(q.offsetHeight+p+&quot;px&quot;);r=this.cfg.getProperty(&quot;xy&quot;);if(!i.isArray(r)||(isNaN(r[0])||isNaN(r[1]))){this.syncPosition();r=this.cfg.getProperty(&quot;xy&quot;);}f.setXY(o,[(r[0]-s),(r[1]-s)]);}},stackIframe:function(){if(this.iframe){var o=f.getStyle(this.element,&quot;zIndex&quot;);if(!YAHOO.lang.isUndefined(o)&amp;&amp;!isNaN(o)){f.setStyle(this.iframe,&quot;zIndex&quot;,(o-1));}}},configIframe:function(r,q,s){var o=q[0];function t(){var v=this.iframe,w=thi
 s.element,x;if(!v){if(!j){j=document.createElement(&quot;iframe&quot;);if(this.isSecure){j.src=b.IFRAME_SRC;}if(k.ie){j.style.filter=&quot;alpha(opacity=0)&quot;;j.frameBorder=0;}else{j.style.opacity=&quot;0&quot;;}j.style.position=&quot;absolute&quot;;j.style.border=&quot;none&quot;;j.style.margin=&quot;0&quot;;j.style.padding=&quot;0&quot;;j.style.display=&quot;none&quot;;j.tabIndex=-1;j.className=b.CSS_IFRAME;}v=j.cloneNode(false);v.id=this.id+&quot;_f&quot;;x=w.parentNode;var u=x||document.body;this._addToParent(u,v);this.iframe=v;}this.showIframe();this.syncIframe();this.stackIframe();if(!this._hasIframeEventListeners){this.showEvent.subscribe(this.showIframe);this.hideEvent.subscribe(this.hideIframe);this.changeContentEvent.subscribe(this.syncIframe);this._hasIframeEventListeners=true;}}function p(){t.call(this);this.beforeShowEvent.unsubscribe(p);this._iframeDeferred=false;}if(o){if(this.cfg.getProperty(&quot;visible&quot;)){t.call(this);}else{if(!this._iframeDeferred
 ){this.beforeShowEvent.subscribe(p);this._iframeDeferred=true;}}}else{this.hideIframe();if(this._hasIframeEventListeners){this.showEvent.unsubscribe(this.showIframe);this.hideEvent.unsubscribe(this.hideIframe);this.changeContentEvent.unsubscribe(this.syncIframe);this._hasIframeEventListeners=false;}}},_primeXYFromDOM:function(){if(YAHOO.lang.isUndefined(this.cfg.getProperty(&quot;xy&quot;))){this.syncPosition();this.cfg.refireEvent(&quot;xy&quot;);this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);}},configConstrainToViewport:function(p,o,q){var r=o[0];if(r){if(!d.alreadySubscribed(this.beforeMoveEvent,this.enforceConstraints,this)){this.beforeMoveEvent.subscribe(this.enforceConstraints,this,true);}if(!d.alreadySubscribed(this.beforeShowEvent,this._primeXYFromDOM)){this.beforeShowEvent.subscribe(this._primeXYFromDOM);}}else{this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);this.beforeMoveEvent.unsubscribe(this.enforceConstraints,this);}},configContext:function(u,t,q
 ){var x=t[0],r,o,v,s,p,w=this.CONTEXT_TRIGGERS;if(x){r=x[0];o=x[1];v=x[2];s=x[3];p=x[4];if(w&amp;&amp;w.length&gt;0){s=(s||[]).concat(w);}if(r){if(typeof r==&quot;string&quot;){this.cfg.setProperty(&quot;context&quot;,[document.getElementById(r),o,v,s,p],true);}if(o&amp;&amp;v){this.align(o,v,p);}if(this._contextTriggers){this._processTriggers(this._contextTriggers,e,this._alignOnTrigger);}if(s){this._processTriggers(s,h,this._alignOnTrigger);this._contextTriggers=s;}}}},_alignOnTrigger:function(p,o){this.align();},_findTriggerCE:function(o){var p=null;if(o instanceof m){p=o;}else{if(b._TRIGGER_MAP[o]){p=b._TRIGGER_MAP[o];}}return p;},_processTriggers:function(s,v,r){var q,u;for(var p=0,o=s.length;p&lt;o;++p){q=s[p];u=this._findTriggerCE(q);if(u){u[v](r,this,true);}else{this[v](q,r);}}},align:function(p,w,s){var v=this.cfg.getProperty(&quot;context&quot;),t=this,o,q,u;function r(z,A){var y=null,x=null;switch(p){case b.TOP_LEFT:y=A;x=z;break;case b.TOP_RIGHT:y=A-q.offsetWidth
 ;x=z;break;case b.BOTTOM_LEFT:y=A;x=z-q.offsetHeight;break;case b.BOTTOM_RIGHT:y=A-q.offsetWidth;x=z-q.offsetHeight;break;}if(y!==null&amp;&amp;x!==null){if(s){y+=s[0];x+=s[1];}t.moveTo(y,x);}}if(v){o=v[0];q=this.element;t=this;if(!p){p=v[1];}if(!w){w=v[2];}if(!s&amp;&amp;v[4]){s=v[4];}if(q&amp;&amp;o){u=f.getRegion(o);switch(w){case b.TOP_LEFT:r(u.top,u.left);break;case b.TOP_RIGHT:r(u.top,u.right);break;case b.BOTTOM_LEFT:r(u.bottom,u.left);break;case b.BOTTOM_RIGHT:r(u.bottom,u.right);break;}}}},enforceConstraints:function(p,o,q){var s=o[0];var r=this.getConstrainedXY(s[0],s[1]);this.cfg.setProperty(&quot;x&quot;,r[0],true);this.cfg.setProperty(&quot;y&quot;,r[1],true);this.cfg.setProperty(&quot;xy&quot;,r,true);},_getConstrainedPos:function(y,p){var t=this.element,r=b.VIEWPORT_OFFSET,A=(y==&quot;x&quot;),z=(A)?t.offsetWidth:t.offsetHeight,s=(A)?f.getViewportWidth():f.getViewportHeight(),D=(A)?f.getDocumentScrollLeft():f.getDocumentScrollTop(),C=(A)?b.PREVENT_OVERLAP_X:b.
 PREVENT_OVERLAP_Y,o=this.cfg.getProperty(&quot;context&quot;),u=(z+r&lt;s),w=this.cfg.getProperty(&quot;preventcontextoverlap&quot;)&amp;&amp;o&amp;&amp;C[(o[1]+o[2])],v=D+r,B=D+s-z-r,q=p;if(p&lt;v||p&gt;B){if(w){q=this._preventOverlap(y,o[0],z,s,D);}else{if(u){if(p&lt;v){q=v;}else{if(p&gt;B){q=B;}}}else{q=v;}}}return q;},_preventOverlap:function(y,w,z,u,C){var A=(y==&quot;x&quot;),t=b.VIEWPORT_OFFSET,s=this,q=((A)?f.getX(w):f.getY(w))-C,o=(A)?w.offsetWidth:w.offsetHeight,p=q-t,r=(u-(q+o))-t,D=false,v=function(){var x;if((s.cfg.getProperty(y)-C)&gt;q){x=(q-z);}else{x=(q+o);}s.cfg.setProperty(y,(x+C),true);return x;},B=function(){var E=((s.cfg.getProperty(y)-C)&gt;q)?r:p,x;if(z&gt;E){if(D){v();}else{v();D=true;x=B();}}return x;};B();return this.cfg.getProperty(y);},getConstrainedX:function(o){return this._getConstrainedPos(&quot;x&quot;,o);},getConstrainedY:function(o){return this._getConstrainedPos(&quot;y&quot;,o);},getConstrainedXY:function(o,p){return[this.getConstrainedX
 (o),this.getConstrainedY(p)];},center:function(){var r=b.VIEWPORT_OFFSET,s=this.element.offsetWidth,q=this.element.offsetHeight,p=f.getViewportWidth(),t=f.getViewportHeight(),o,u;if(s&lt;p){o=(p/2)-(s/2)+f.getDocumentScrollLeft();}else{o=r+f.getDocumentScrollLeft();}if(q&lt;t){u=(t/2)-(q/2)+f.getDocumentScrollTop();}else{u=r+f.getDocumentScrollTop();}this.cfg.setProperty(&quot;xy&quot;,[parseInt(o,10),parseInt(u,10)]);this.cfg.refireEvent(&quot;iframe&quot;);if(k.webkit){this.forceContainerRedraw();}},syncPosition:function(){var o=f.getXY(this.element);
+this.cfg.setProperty(&quot;x&quot;,o[0],true);this.cfg.setProperty(&quot;y&quot;,o[1],true);this.cfg.setProperty(&quot;xy&quot;,o,true);},onDomResize:function(q,p){var o=this;b.superclass.onDomResize.call(this,q,p);setTimeout(function(){o.syncPosition();o.cfg.refireEvent(&quot;iframe&quot;);o.cfg.refireEvent(&quot;context&quot;);},0);},_getComputedHeight:(function(){if(document.defaultView&amp;&amp;document.defaultView.getComputedStyle){return function(p){var o=null;if(p.ownerDocument&amp;&amp;p.ownerDocument.defaultView){var q=p.ownerDocument.defaultView.getComputedStyle(p,&quot;&quot;);if(q){o=parseInt(q.height,10);}}return(i.isNumber(o))?o:null;};}else{return function(p){var o=null;if(p.style.pixelHeight){o=p.style.pixelHeight;}return(i.isNumber(o))?o:null;};}})(),_validateAutoFillHeight:function(o){return(!o)||(i.isString(o)&amp;&amp;b.STD_MOD_RE.test(o));},_autoFillOnHeightChange:function(r,p,q){var o=this.cfg.getProperty(&quot;height&quot;);if((o&amp;&amp;o!==&quot;aut
 o&quot;)||(o===0)){this.fillHeight(q);}},_getPreciseHeight:function(p){var o=p.offsetHeight;if(p.getBoundingClientRect){var q=p.getBoundingClientRect();o=q.bottom-q.top;}return o;},fillHeight:function(r){if(r){var p=this.innerElement||this.element,o=[this.header,this.body,this.footer],v,w=0,x=0,t=0,q=false;for(var u=0,s=o.length;u&lt;s;u++){v=o[u];if(v){if(r!==v){x+=this._getPreciseHeight(v);}else{q=true;}}}if(q){if(k.ie||k.opera){f.setStyle(r,&quot;height&quot;,0+&quot;px&quot;);}w=this._getComputedHeight(p);if(w===null){f.addClass(p,&quot;yui-override-padding&quot;);w=p.clientHeight;f.removeClass(p,&quot;yui-override-padding&quot;);}t=Math.max(w-x,0);f.setStyle(r,&quot;height&quot;,t+&quot;px&quot;);if(r.offsetHeight!=t){t=Math.max(t-(r.offsetHeight-t),0);}f.setStyle(r,&quot;height&quot;,t+&quot;px&quot;);}}},bringToTop:function(){var s=[],r=this.element;function v(z,y){var B=f.getStyle(z,&quot;zIndex&quot;),A=f.getStyle(y,&quot;zIndex&quot;),x=(!B||isNaN(B))?0:parseInt(B,
 10),w=(!A||isNaN(A))?0:parseInt(A,10);if(x&gt;w){return -1;}else{if(x&lt;w){return 1;}else{return 0;}}}function q(y){var x=f.hasClass(y,b.CSS_OVERLAY),w=YAHOO.widget.Panel;if(x&amp;&amp;!f.isAncestor(r,y)){if(w&amp;&amp;f.hasClass(y,w.CSS_PANEL)){s[s.length]=y.parentNode;}else{s[s.length]=y;}}}f.getElementsBy(q,&quot;div&quot;,document.body);s.sort(v);var o=s[0],u;if(o){u=f.getStyle(o,&quot;zIndex&quot;);if(!isNaN(u)){var t=false;if(o!=r){t=true;}else{if(s.length&gt;1){var p=f.getStyle(s[1],&quot;zIndex&quot;);if(!isNaN(p)&amp;&amp;(u==p)){t=true;}}}if(t){this.cfg.setProperty(&quot;zindex&quot;,(parseInt(u,10)+2));}}}},destroy:function(o){if(this.iframe){this.iframe.parentNode.removeChild(this.iframe);}this.iframe=null;b.windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent,this);b.windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent,this);g.textResizeEvent.unsubscribe(this._autoFillOnHeightChange);if(this._contextTriggers){this._processTriggers(this._contextTriggers,e,this
 ._alignOnTrigger);}b.superclass.destroy.call(this,o);},forceContainerRedraw:function(){var o=this;f.addClass(o.element,&quot;yui-force-redraw&quot;);setTimeout(function(){f.removeClass(o.element,&quot;yui-force-redraw&quot;);},0);},toString:function(){return&quot;Overlay &quot;+this.id;}});}());(function(){YAHOO.widget.OverlayManager=function(g){this.init(g);};var d=YAHOO.widget.Overlay,c=YAHOO.util.Event,e=YAHOO.util.Dom,b=YAHOO.util.Config,f=YAHOO.util.CustomEvent,a=YAHOO.widget.OverlayManager;a.CSS_FOCUSED=&quot;focused&quot;;a.prototype={constructor:a,overlays:null,initDefaultConfig:function(){this.cfg.addProperty(&quot;overlays&quot;,{suppressEvent:true});this.cfg.addProperty(&quot;focusevent&quot;,{value:&quot;mousedown&quot;});},init:function(i){this.cfg=new b(this);this.initDefaultConfig();if(i){this.cfg.applyConfig(i,true);}this.cfg.fireQueue();var h=null;this.getActive=function(){return h;};this.focus=function(j){var k=this.find(j);if(k){k.focus();}};this.remove=fu
 nction(k){var m=this.find(k),j;if(m){if(h==m){h=null;}var l=(m.element===null&amp;&amp;m.cfg===null)?true:false;if(!l){j=e.getStyle(m.element,&quot;zIndex&quot;);m.cfg.setProperty(&quot;zIndex&quot;,-1000,true);}this.overlays.sort(this.compareZIndexDesc);this.overlays=this.overlays.slice(0,(this.overlays.length-1));m.hideEvent.unsubscribe(m.blur);m.destroyEvent.unsubscribe(this._onOverlayDestroy,m);m.focusEvent.unsubscribe(this._onOverlayFocusHandler,m);m.blurEvent.unsubscribe(this._onOverlayBlurHandler,m);if(!l){c.removeListener(m.element,this.cfg.getProperty(&quot;focusevent&quot;),this._onOverlayElementFocus);m.cfg.setProperty(&quot;zIndex&quot;,j,true);m.cfg.setProperty(&quot;manager&quot;,null);}if(m.focusEvent._managed){m.focusEvent=null;}if(m.blurEvent._managed){m.blurEvent=null;}if(m.focus._managed){m.focus=null;}if(m.blur._managed){m.blur=null;}}};this.blurAll=function(){var k=this.overlays.length,j;if(k&gt;0){j=k-1;do{this.overlays[j].blur();}while(j--);}};this._ma
 nageBlur=function(j){var k=false;if(h==j){e.removeClass(h.element,a.CSS_FOCUSED);h=null;k=true;}return k;};this._manageFocus=function(j){var k=false;if(h!=j){if(h){h.blur();}h=j;this.bringToTop(h);e.addClass(h.element,a.CSS_FOCUSED);k=true;}return k;};var g=this.cfg.getProperty(&quot;overlays&quot;);if(!this.overlays){this.overlays=[];}if(g){this.register(g);this.overlays.sort(this.compareZIndexDesc);}},_onOverlayElementFocus:function(i){var g=c.getTarget(i),h=this.close;if(h&amp;&amp;(g==h||e.isAncestor(h,g))){this.blur();}else{this.focus();}},_onOverlayDestroy:function(h,g,i){this.remove(i);},_onOverlayFocusHandler:function(h,g,i){this._manageFocus(i);},_onOverlayBlurHandler:function(h,g,i){this._manageBlur(i);},_bindFocus:function(g){var h=this;if(!g.focusEvent){g.focusEvent=g.createEvent(&quot;focus&quot;);g.focusEvent.signature=f.LIST;g.focusEvent._managed=true;}else{g.focusEvent.subscribe(h._onOverlayFocusHandler,g,h);}if(!g.focus){c.on(g.element,h.cfg.getProperty(&quo
 t;focusevent&quot;),h._onOverlayElementFocus,null,g);g.focus=function(){if(h._manageFocus(this)){if(this.cfg.getProperty(&quot;visible&quot;)&amp;&amp;this.focusFirst){this.focusFirst();}this.focusEvent.fire();}};g.focus._managed=true;}},_bindBlur:function(g){var h=this;if(!g.blurEvent){g.blurEvent=g.createEvent(&quot;blur&quot;);g.blurEvent.signature=f.LIST;g.focusEvent._managed=true;}else{g.blurEvent.subscribe(h._onOverlayBlurHandler,g,h);}if(!g.blur){g.blur=function(){if(h._manageBlur(this)){this.blurEvent.fire();}};g.blur._managed=true;}g.hideEvent.subscribe(g.blur);
+},_bindDestroy:function(g){var h=this;g.destroyEvent.subscribe(h._onOverlayDestroy,g,h);},_syncZIndex:function(g){var h=e.getStyle(g.element,&quot;zIndex&quot;);if(!isNaN(h)){g.cfg.setProperty(&quot;zIndex&quot;,parseInt(h,10));}else{g.cfg.setProperty(&quot;zIndex&quot;,0);}},register:function(g){var k=false,h,j;if(g instanceof d){g.cfg.addProperty(&quot;manager&quot;,{value:this});this._bindFocus(g);this._bindBlur(g);this._bindDestroy(g);this._syncZIndex(g);this.overlays.push(g);this.bringToTop(g);k=true;}else{if(g instanceof Array){for(h=0,j=g.length;h&lt;j;h++){k=this.register(g[h])||k;}}}return k;},bringToTop:function(m){var i=this.find(m),l,g,j;if(i){j=this.overlays;j.sort(this.compareZIndexDesc);g=j[0];if(g){l=e.getStyle(g.element,&quot;zIndex&quot;);if(!isNaN(l)){var k=false;if(g!==i){k=true;}else{if(j.length&gt;1){var h=e.getStyle(j[1].element,&quot;zIndex&quot;);if(!isNaN(h)&amp;&amp;(l==h)){k=true;}}}if(k){i.cfg.setProperty(&quot;zindex&quot;,(parseInt(l,10)+2));}}
 j.sort(this.compareZIndexDesc);}}},find:function(g){var l=g instanceof d,j=this.overlays,p=j.length,k=null,m,h;if(l||typeof g==&quot;string&quot;){for(h=p-1;h&gt;=0;h--){m=j[h];if((l&amp;&amp;(m===g))||(m.id==g)){k=m;break;}}}return k;},compareZIndexDesc:function(j,i){var h=(j.cfg)?j.cfg.getProperty(&quot;zIndex&quot;):null,g=(i.cfg)?i.cfg.getProperty(&quot;zIndex&quot;):null;if(h===null&amp;&amp;g===null){return 0;}else{if(h===null){return 1;}else{if(g===null){return -1;}else{if(h&gt;g){return -1;}else{if(h&lt;g){return 1;}else{return 0;}}}}}},showAll:function(){var h=this.overlays,j=h.length,g;for(g=j-1;g&gt;=0;g--){h[g].show();}},hideAll:function(){var h=this.overlays,j=h.length,g;for(g=j-1;g&gt;=0;g--){h[g].hide();}},toString:function(){return&quot;OverlayManager&quot;;}};}());(function(){YAHOO.widget.Tooltip=function(p,o){YAHOO.widget.Tooltip.superclass.constructor.call(this,p,o);};var e=YAHOO.lang,n=YAHOO.util.Event,m=YAHOO.util.CustomEvent,c=YAHOO.util.Dom,j=YAHOO.wid
 get.Tooltip,h=YAHOO.env.ua,g=(h.ie&amp;&amp;(h.ie&lt;=6||document.compatMode==&quot;BackCompat&quot;)),f,i={&quot;PREVENT_OVERLAP&quot;:{key:&quot;preventoverlap&quot;,value:true,validator:e.isBoolean,supercedes:[&quot;x&quot;,&quot;y&quot;,&quot;xy&quot;]},&quot;SHOW_DELAY&quot;:{key:&quot;showdelay&quot;,value:200,validator:e.isNumber},&quot;AUTO_DISMISS_DELAY&quot;:{key:&quot;autodismissdelay&quot;,value:5000,validator:e.isNumber},&quot;HIDE_DELAY&quot;:{key:&quot;hidedelay&quot;,value:250,validator:e.isNumber},&quot;TEXT&quot;:{key:&quot;text&quot;,suppressEvent:true},&quot;CONTAINER&quot;:{key:&quot;container&quot;},&quot;DISABLED&quot;:{key:&quot;disabled&quot;,value:false,suppressEvent:true},&quot;XY_OFFSET&quot;:{key:&quot;xyoffset&quot;,value:[0,25],suppressEvent:true}},a={&quot;CONTEXT_MOUSE_OVER&quot;:&quot;contextMouseOver&quot;,&quot;CONTEXT_MOUSE_OUT&quot;:&quot;contextMouseOut&quot;,&quot;CONTEXT_TRIGGER&quot;:&quot;contextTrigger&quot;};j.CSS_TOOLTIP=&quot;yu
 i-tt&quot;;function k(q,o){var p=this.cfg,r=p.getProperty(&quot;width&quot;);if(r==o){p.setProperty(&quot;width&quot;,q);}}function d(p,o){if(&quot;_originalWidth&quot; in this){k.call(this,this._originalWidth,this._forcedWidth);}var q=document.body,u=this.cfg,t=u.getProperty(&quot;width&quot;),r,s;if((!t||t==&quot;auto&quot;)&amp;&amp;(u.getProperty(&quot;container&quot;)!=q||u.getProperty(&quot;x&quot;)&gt;=c.getViewportWidth()||u.getProperty(&quot;y&quot;)&gt;=c.getViewportHeight())){s=this.element.cloneNode(true);s.style.visibility=&quot;hidden&quot;;s.style.top=&quot;0px&quot;;s.style.left=&quot;0px&quot;;q.appendChild(s);r=(s.offsetWidth+&quot;px&quot;);q.removeChild(s);s=null;u.setProperty(&quot;width&quot;,r);u.refireEvent(&quot;xy&quot;);this._originalWidth=t||&quot;&quot;;this._forcedWidth=r;}}function b(p,o,q){this.render(q);}function l(){n.onDOMReady(b,this.cfg.getProperty(&quot;container&quot;),this);}YAHOO.extend(j,YAHOO.widget.Overlay,{init:function(p,o){j.sup
 erclass.init.call(this,p);this.beforeInitEvent.fire(j);c.addClass(this.element,j.CSS_TOOLTIP);if(o){this.cfg.applyConfig(o,true);}this.cfg.queueProperty(&quot;visible&quot;,false);this.cfg.queueProperty(&quot;constraintoviewport&quot;,true);this.setBody(&quot;&quot;);this.subscribe(&quot;changeContent&quot;,d);this.subscribe(&quot;init&quot;,l);this.subscribe(&quot;render&quot;,this.onRender);this.initEvent.fire(j);},initEvents:function(){j.superclass.initEvents.call(this);var o=m.LIST;this.contextMouseOverEvent=this.createEvent(a.CONTEXT_MOUSE_OVER);this.contextMouseOverEvent.signature=o;this.contextMouseOutEvent=this.createEvent(a.CONTEXT_MOUSE_OUT);this.contextMouseOutEvent.signature=o;this.contextTriggerEvent=this.createEvent(a.CONTEXT_TRIGGER);this.contextTriggerEvent.signature=o;},initDefaultConfig:function(){j.superclass.initDefaultConfig.call(this);this.cfg.addProperty(i.PREVENT_OVERLAP.key,{value:i.PREVENT_OVERLAP.value,validator:i.PREVENT_OVERLAP.validator,superced
 es:i.PREVENT_OVERLAP.supercedes});this.cfg.addProperty(i.SHOW_DELAY.key,{handler:this.configShowDelay,value:200,validator:i.SHOW_DELAY.validator});this.cfg.addProperty(i.AUTO_DISMISS_DELAY.key,{handler:this.configAutoDismissDelay,value:i.AUTO_DISMISS_DELAY.value,validator:i.AUTO_DISMISS_DELAY.validator});this.cfg.addProperty(i.HIDE_DELAY.key,{handler:this.configHideDelay,value:i.HIDE_DELAY.value,validator:i.HIDE_DELAY.validator});this.cfg.addProperty(i.TEXT.key,{handler:this.configText,suppressEvent:i.TEXT.suppressEvent});this.cfg.addProperty(i.CONTAINER.key,{handler:this.configContainer,value:document.body});this.cfg.addProperty(i.DISABLED.key,{handler:this.configContainer,value:i.DISABLED.value,supressEvent:i.DISABLED.suppressEvent});this.cfg.addProperty(i.XY_OFFSET.key,{value:i.XY_OFFSET.value.concat(),supressEvent:i.XY_OFFSET.suppressEvent});},configText:function(p,o,q){var r=o[0];if(r){this.setBody(r);}},configContainer:function(q,p,r){var o=p[0];if(typeof o==&quot;stri
 ng&quot;){this.cfg.setProperty(&quot;container&quot;,document.getElementById(o),true);}},_removeEventListeners:function(){var r=this._context,o,q,p;if(r){o=r.length;if(o&gt;0){p=o-1;do{q=r[p];n.removeListener(q,&quot;mouseover&quot;,this.onContextMouseOver);n.removeListener(q,&quot;mousemove&quot;,this.onContextMouseMove);n.removeListener(q,&quot;mouseout&quot;,this.onContextMouseOut);}while(p--);}}},configContext:function(t,p,u){var s=p[0],v,o,r,q;if(s){if(!(s instanceof Array)){if(typeof s==&quot;string&quot;){this.cfg.setProperty(&quot;context&quot;,[document.getElementById(s)],true);}else{this.cfg.setProperty(&quot;context&quot;,[s],true);}s=this.cfg.getProperty(&quot;context&quot;);}this._removeEventListeners();this._context=s;v=this._context;if(v){o=v.length;if(o&gt;0){q=o-1;do{r=v[q];n.on(r,&quot;mouseover&quot;,this.onContextMouseOver,this);
+n.on(r,&quot;mousemove&quot;,this.onContextMouseMove,this);n.on(r,&quot;mouseout&quot;,this.onContextMouseOut,this);}while(q--);}}}},onContextMouseMove:function(p,o){o.pageX=n.getPageX(p);o.pageY=n.getPageY(p);},onContextMouseOver:function(q,p){var o=this;if(o.title){p._tempTitle=o.title;o.title=&quot;&quot;;}if(p.fireEvent(&quot;contextMouseOver&quot;,o,q)!==false&amp;&amp;!p.cfg.getProperty(&quot;disabled&quot;)){if(p.hideProcId){clearTimeout(p.hideProcId);p.hideProcId=null;}n.on(o,&quot;mousemove&quot;,p.onContextMouseMove,p);p.showProcId=p.doShow(q,o);}},onContextMouseOut:function(q,p){var o=this;if(p._tempTitle){o.title=p._tempTitle;p._tempTitle=null;}if(p.showProcId){clearTimeout(p.showProcId);p.showProcId=null;}if(p.hideProcId){clearTimeout(p.hideProcId);p.hideProcId=null;}p.fireEvent(&quot;contextMouseOut&quot;,o,q);p.hideProcId=setTimeout(function(){p.hide();},p.cfg.getProperty(&quot;hidedelay&quot;));},doShow:function(r,o){var t=this.cfg.getProperty(&quot;xyoffset&
 quot;),p=t[0],s=t[1],q=this;if(h.opera&amp;&amp;o.tagName&amp;&amp;o.tagName.toUpperCase()==&quot;A&quot;){s+=12;}return setTimeout(function(){var u=q.cfg.getProperty(&quot;text&quot;);if(q._tempTitle&amp;&amp;(u===&quot;&quot;||YAHOO.lang.isUndefined(u)||YAHOO.lang.isNull(u))){q.setBody(q._tempTitle);}else{q.cfg.refireEvent(&quot;text&quot;);}q.moveTo(q.pageX+p,q.pageY+s);if(q.cfg.getProperty(&quot;preventoverlap&quot;)){q.preventOverlap(q.pageX,q.pageY);}n.removeListener(o,&quot;mousemove&quot;,q.onContextMouseMove);q.contextTriggerEvent.fire(o);q.show();q.hideProcId=q.doHide();},this.cfg.getProperty(&quot;showdelay&quot;));},doHide:function(){var o=this;return setTimeout(function(){o.hide();},this.cfg.getProperty(&quot;autodismissdelay&quot;));},preventOverlap:function(s,r){var o=this.element.offsetHeight,q=new YAHOO.util.Point(s,r),p=c.getRegion(this.element);p.top-=5;p.left-=5;p.right+=5;p.bottom+=5;if(p.contains(q)){this.cfg.setProperty(&quot;y&quot;,(r-o-5));}},onRend
 er:function(s,r){function t(){var w=this.element,v=this.underlay;if(v){v.style.width=(w.offsetWidth+6)+&quot;px&quot;;v.style.height=(w.offsetHeight+1)+&quot;px&quot;;}}function p(){c.addClass(this.underlay,&quot;yui-tt-shadow-visible&quot;);if(h.ie){this.forceUnderlayRedraw();}}function o(){c.removeClass(this.underlay,&quot;yui-tt-shadow-visible&quot;);}function u(){var x=this.underlay,w,v,z,y;if(!x){w=this.element;v=YAHOO.widget.Module;z=h.ie;y=this;if(!f){f=document.createElement(&quot;div&quot;);f.className=&quot;yui-tt-shadow&quot;;}x=f.cloneNode(false);w.appendChild(x);this.underlay=x;this._shadow=this.underlay;p.call(this);this.subscribe(&quot;beforeShow&quot;,p);this.subscribe(&quot;hide&quot;,o);if(g){window.setTimeout(function(){t.call(y);},0);this.cfg.subscribeToConfigEvent(&quot;width&quot;,t);this.cfg.subscribeToConfigEvent(&quot;height&quot;,t);this.subscribe(&quot;changeContent&quot;,t);v.textResizeEvent.subscribe(t,this,true);this.subscribe(&quot;destroy&quot
 ;,function(){v.textResizeEvent.unsubscribe(t,this);});}}}function q(){u.call(this);this.unsubscribe(&quot;beforeShow&quot;,q);}if(this.cfg.getProperty(&quot;visible&quot;)){u.call(this);}else{this.subscribe(&quot;beforeShow&quot;,q);}},forceUnderlayRedraw:function(){var o=this;c.addClass(o.underlay,&quot;yui-force-redraw&quot;);setTimeout(function(){c.removeClass(o.underlay,&quot;yui-force-redraw&quot;);},0);},destroy:function(){this._removeEventListeners();j.superclass.destroy.call(this);},toString:function(){return&quot;Tooltip &quot;+this.id;}});}());(function(){YAHOO.widget.Panel=function(v,u){YAHOO.widget.Panel.superclass.constructor.call(this,v,u);};var s=null;var e=YAHOO.lang,f=YAHOO.util,a=f.Dom,t=f.Event,m=f.CustomEvent,k=YAHOO.util.KeyListener,i=f.Config,h=YAHOO.widget.Overlay,o=YAHOO.widget.Panel,l=YAHOO.env.ua,p=(l.ie&amp;&amp;(l.ie&lt;=6||document.compatMode==&quot;BackCompat&quot;)),g,q,c,d={&quot;BEFORE_SHOW_MASK&quot;:&quot;beforeShowMask&quot;,&quot;BEFORE_H
 IDE_MASK&quot;:&quot;beforeHideMask&quot;,&quot;SHOW_MASK&quot;:&quot;showMask&quot;,&quot;HIDE_MASK&quot;:&quot;hideMask&quot;,&quot;DRAG&quot;:&quot;drag&quot;},n={&quot;CLOSE&quot;:{key:&quot;close&quot;,value:true,validator:e.isBoolean,supercedes:[&quot;visible&quot;]},&quot;DRAGGABLE&quot;:{key:&quot;draggable&quot;,value:(f.DD?true:false),validator:e.isBoolean,supercedes:[&quot;visible&quot;]},&quot;DRAG_ONLY&quot;:{key:&quot;dragonly&quot;,value:false,validator:e.isBoolean,supercedes:[&quot;draggable&quot;]},&quot;UNDERLAY&quot;:{key:&quot;underlay&quot;,value:&quot;shadow&quot;,supercedes:[&quot;visible&quot;]},&quot;MODAL&quot;:{key:&quot;modal&quot;,value:false,validator:e.isBoolean,supercedes:[&quot;visible&quot;,&quot;zindex&quot;]},&quot;KEY_LISTENERS&quot;:{key:&quot;keylisteners&quot;,suppressEvent:true,supercedes:[&quot;visible&quot;]},&quot;STRINGS&quot;:{key:&quot;strings&quot;,supercedes:[&quot;close&quot;],validator:e.isObject,value:{close:&quot;Close&quo
 t;}}};o.CSS_PANEL=&quot;yui-panel&quot;;o.CSS_PANEL_CONTAINER=&quot;yui-panel-container&quot;;o.FOCUSABLE=[&quot;a&quot;,&quot;button&quot;,&quot;select&quot;,&quot;textarea&quot;,&quot;input&quot;,&quot;iframe&quot;];function j(v,u){if(!this.header&amp;&amp;this.cfg.getProperty(&quot;draggable&quot;)){this.setHeader(&quot;&amp;#160;&quot;);}}function r(v,u,w){var z=w[0],x=w[1],y=this.cfg,A=y.getProperty(&quot;width&quot;);if(A==x){y.setProperty(&quot;width&quot;,z);}this.unsubscribe(&quot;hide&quot;,r,w);}function b(v,u){var y,x,w;if(p){y=this.cfg;x=y.getProperty(&quot;width&quot;);if(!x||x==&quot;auto&quot;){w=(this.element.offsetWidth+&quot;px&quot;);y.setProperty(&quot;width&quot;,w);this.subscribe(&quot;hide&quot;,r,[(x||&quot;&quot;),w]);}}}YAHOO.extend(o,h,{init:function(v,u){o.superclass.init.call(this,v);this.beforeInitEvent.fire(o);a.addClass(this.element,o.CSS_PANEL);this.buildWrapper();if(u){this.cfg.applyConfig(u,true);}this.subscribe(&quot;showMask&quot;,this._
 addFocusHandlers);this.subscribe(&quot;hideMask&quot;,this._removeFocusHandlers);this.subscribe(&quot;beforeRender&quot;,j);this.subscribe(&quot;render&quot;,function(){this.setFirstLastFocusable();this.subscribe(&quot;changeContent&quot;,this.setFirstLastFocusable);});this.subscribe(&quot;show&quot;,this._focusOnShow);this.initEvent.fire(o);},_onElementFocus:function(z){if(s===this){var y=t.getTarget(z),x=document.documentElement,v=(y!==x&amp;&amp;y!==window);if(v&amp;&amp;y!==this.element&amp;&amp;y!==this.mask&amp;&amp;!a.isAncestor(this.element,y)){try{this._focusFirstModal();}catch(w){try{if(v&amp;&amp;y!==document.body){y.blur();}}catch(u){}}}}},_focusFirstModal:function(){var u=this.firstElement;if(u){u.focus();}else{if(this._modalFocus){this._modalFocus.focus();}else{this.innerElement.focus();}}},_addFocusHandlers:function(v,u){if(!this.firstElement){if(l.webkit||l.opera){if(!this._modalFocus){this._createHiddenFocusElement();}}else{this.innerElement.tabIndex=0;}}thi
 s._setTabLoop(this.firstElement,this.lastElement);t.onFocus(document.documentElement,this._onElementFocus,this,true);s=this;},_createHiddenFocusElement:function(){var u=document.createElement(&quot;button&quot;);
+u.style.height=&quot;1px&quot;;u.style.width=&quot;1px&quot;;u.style.position=&quot;absolute&quot;;u.style.left=&quot;-10000em&quot;;u.style.opacity=0;u.tabIndex=-1;this.innerElement.appendChild(u);this._modalFocus=u;},_removeFocusHandlers:function(v,u){t.removeFocusListener(document.documentElement,this._onElementFocus,this);if(s==this){s=null;}},_focusOnShow:function(v,u,w){if(u&amp;&amp;u[1]){t.stopEvent(u[1]);}if(!this.focusFirst(v,u,w)){if(this.cfg.getProperty(&quot;modal&quot;)){this._focusFirstModal();}}},focusFirst:function(w,u,z){var v=this.firstElement,y=false;if(u&amp;&amp;u[1]){t.stopEvent(u[1]);}if(v){try{v.focus();y=true;}catch(x){}}return y;},focusLast:function(w,u,z){var v=this.lastElement,y=false;if(u&amp;&amp;u[1]){t.stopEvent(u[1]);}if(v){try{v.focus();y=true;}catch(x){}}return y;},_setTabLoop:function(u,v){this.setTabLoop(u,v);},setTabLoop:function(x,z){var v=this.preventBackTab,w=this.preventTabOut,u=this.showEvent,y=this.hideEvent;if(v){v.disable();u.un
 subscribe(v.enable,v);y.unsubscribe(v.disable,v);v=this.preventBackTab=null;}if(w){w.disable();u.unsubscribe(w.enable,w);y.unsubscribe(w.disable,w);w=this.preventTabOut=null;}if(x){this.preventBackTab=new k(x,{shift:true,keys:9},{fn:this.focusLast,scope:this,correctScope:true});v=this.preventBackTab;u.subscribe(v.enable,v,true);y.subscribe(v.disable,v,true);}if(z){this.preventTabOut=new k(z,{shift:false,keys:9},{fn:this.focusFirst,scope:this,correctScope:true});w=this.preventTabOut;u.subscribe(w.enable,w,true);y.subscribe(w.disable,w,true);}},getFocusableElements:function(v){v=v||this.innerElement;var x={},u=this;for(var w=0;w&lt;o.FOCUSABLE.length;w++){x[o.FOCUSABLE[w]]=true;}return a.getElementsBy(function(y){return u._testIfFocusable(y,x);},null,v);},_testIfFocusable:function(u,v){if(u.focus&amp;&amp;u.type!==&quot;hidden&quot;&amp;&amp;!u.disabled&amp;&amp;v[u.tagName.toLowerCase()]){return true;}return false;},setFirstLastFocusable:function(){this.firstElement=null;this
 .lastElement=null;var u=this.getFocusableElements();this.focusableElements=u;if(u.length&gt;0){this.firstElement=u[0];this.lastElement=u[u.length-1];}if(this.cfg.getProperty(&quot;modal&quot;)){this._setTabLoop(this.firstElement,this.lastElement);}},initEvents:function(){o.superclass.initEvents.call(this);var u=m.LIST;this.showMaskEvent=this.createEvent(d.SHOW_MASK);this.showMaskEvent.signature=u;this.beforeShowMaskEvent=this.createEvent(d.BEFORE_SHOW_MASK);this.beforeShowMaskEvent.signature=u;this.hideMaskEvent=this.createEvent(d.HIDE_MASK);this.hideMaskEvent.signature=u;this.beforeHideMaskEvent=this.createEvent(d.BEFORE_HIDE_MASK);this.beforeHideMaskEvent.signature=u;this.dragEvent=this.createEvent(d.DRAG);this.dragEvent.signature=u;},initDefaultConfig:function(){o.superclass.initDefaultConfig.call(this);this.cfg.addProperty(n.CLOSE.key,{handler:this.configClose,value:n.CLOSE.value,validator:n.CLOSE.validator,supercedes:n.CLOSE.supercedes});this.cfg.addProperty(n.DRAGGABLE
 .key,{handler:this.configDraggable,value:(f.DD)?true:false,validator:n.DRAGGABLE.validator,supercedes:n.DRAGGABLE.supercedes});this.cfg.addProperty(n.DRAG_ONLY.key,{value:n.DRAG_ONLY.value,validator:n.DRAG_ONLY.validator,supercedes:n.DRAG_ONLY.supercedes});this.cfg.addProperty(n.UNDERLAY.key,{handler:this.configUnderlay,value:n.UNDERLAY.value,supercedes:n.UNDERLAY.supercedes});this.cfg.addProperty(n.MODAL.key,{handler:this.configModal,value:n.MODAL.value,validator:n.MODAL.validator,supercedes:n.MODAL.supercedes});this.cfg.addProperty(n.KEY_LISTENERS.key,{handler:this.configKeyListeners,suppressEvent:n.KEY_LISTENERS.suppressEvent,supercedes:n.KEY_LISTENERS.supercedes});this.cfg.addProperty(n.STRINGS.key,{value:n.STRINGS.value,handler:this.configStrings,validator:n.STRINGS.validator,supercedes:n.STRINGS.supercedes});},configClose:function(y,v,z){var A=v[0],x=this.close,u=this.cfg.getProperty(&quot;strings&quot;),w;if(A){if(!x){if(!c){c=document.createElement(&quot;a&quot;);c.c
 lassName=&quot;container-close&quot;;c.href=&quot;#&quot;;}x=c.cloneNode(true);w=this.innerElement.firstChild;if(w){this.innerElement.insertBefore(x,w);}else{this.innerElement.appendChild(x);}x.innerHTML=(u&amp;&amp;u.close)?u.close:&quot;&amp;#160;&quot;;t.on(x,&quot;click&quot;,this._doClose,this,true);this.close=x;}else{x.style.display=&quot;block&quot;;}}else{if(x){x.style.display=&quot;none&quot;;}}},_doClose:function(u){t.preventDefault(u);this.hide();},configDraggable:function(v,u,w){var x=u[0];if(x){if(!f.DD){this.cfg.setProperty(&quot;draggable&quot;,false);return;}if(this.header){a.setStyle(this.header,&quot;cursor&quot;,&quot;move&quot;);this.registerDragDrop();}this.subscribe(&quot;beforeShow&quot;,b);}else{if(this.dd){this.dd.unreg();}if(this.header){a.setStyle(this.header,&quot;cursor&quot;,&quot;auto&quot;);}this.unsubscribe(&quot;beforeShow&quot;,b);}},configUnderlay:function(D,C,z){var B=(this.platform==&quot;mac&quot;&amp;&amp;l.gecko),E=C[0].toLowerCase(),
 v=this.underlay,w=this.element;function x(){var F=false;if(!v){if(!q){q=document.createElement(&quot;div&quot;);q.className=&quot;underlay&quot;;}v=q.cloneNode(false);this.element.appendChild(v);this.underlay=v;if(p){this.sizeUnderlay();this.cfg.subscribeToConfigEvent(&quot;width&quot;,this.sizeUnderlay);this.cfg.subscribeToConfigEvent(&quot;height&quot;,this.sizeUnderlay);this.changeContentEvent.subscribe(this.sizeUnderlay);YAHOO.widget.Module.textResizeEvent.subscribe(this.sizeUnderlay,this,true);}if(l.webkit&amp;&amp;l.webkit&lt;420){this.changeContentEvent.subscribe(this.forceUnderlayRedraw);}F=true;}}function A(){var F=x.call(this);if(!F&amp;&amp;p){this.sizeUnderlay();}this._underlayDeferred=false;this.beforeShowEvent.unsubscribe(A);}function y(){if(this._underlayDeferred){this.beforeShowEvent.unsubscribe(A);this._underlayDeferred=false;}if(v){this.cfg.unsubscribeFromConfigEvent(&quot;width&quot;,this.sizeUnderlay);this.cfg.unsubscribeFromConfigEvent(&quot;height&quot;
 ,this.sizeUnderlay);this.changeContentEvent.unsubscribe(this.sizeUnderlay);this.changeContentEvent.unsubscribe(this.forceUnderlayRedraw);YAHOO.widget.Module.textResizeEvent.unsubscribe(this.sizeUnderlay,this,true);this.element.removeChild(v);this.underlay=null;}}switch(E){case&quot;shadow&quot;:a.removeClass(w,&quot;matte&quot;);a.addClass(w,&quot;shadow&quot;);break;case&quot;matte&quot;:if(!B){y.call(this);}a.removeClass(w,&quot;shadow&quot;);a.addClass(w,&quot;matte&quot;);break;default:if(!B){y.call(this);
+}a.removeClass(w,&quot;shadow&quot;);a.removeClass(w,&quot;matte&quot;);break;}if((E==&quot;shadow&quot;)||(B&amp;&amp;!v)){if(this.cfg.getProperty(&quot;visible&quot;)){var u=x.call(this);if(!u&amp;&amp;p){this.sizeUnderlay();}}else{if(!this._underlayDeferred){this.beforeShowEvent.subscribe(A);this._underlayDeferred=true;}}}},configModal:function(v,u,x){var w=u[0];if(w){if(!this._hasModalityEventListeners){this.subscribe(&quot;beforeShow&quot;,this.buildMask);this.subscribe(&quot;beforeShow&quot;,this.bringToTop);this.subscribe(&quot;beforeShow&quot;,this.showMask);this.subscribe(&quot;hide&quot;,this.hideMask);h.windowResizeEvent.subscribe(this.sizeMask,this,true);this._hasModalityEventListeners=true;}}else{if(this._hasModalityEventListeners){if(this.cfg.getProperty(&quot;visible&quot;)){this.hideMask();this.removeMask();}this.unsubscribe(&quot;beforeShow&quot;,this.buildMask);this.unsubscribe(&quot;beforeShow&quot;,this.bringToTop);this.unsubscribe(&quot;beforeShow&quot;,
 this.showMask);this.unsubscribe(&quot;hide&quot;,this.hideMask);h.windowResizeEvent.unsubscribe(this.sizeMask,this);this._hasModalityEventListeners=false;}}},removeMask:function(){var v=this.mask,u;if(v){this.hideMask();u=v.parentNode;if(u){u.removeChild(v);}this.mask=null;}},configKeyListeners:function(x,u,A){var w=u[0],z,y,v;if(w){if(w instanceof Array){y=w.length;for(v=0;v&lt;y;v++){z=w[v];if(!i.alreadySubscribed(this.showEvent,z.enable,z)){this.showEvent.subscribe(z.enable,z,true);}if(!i.alreadySubscribed(this.hideEvent,z.disable,z)){this.hideEvent.subscribe(z.disable,z,true);this.destroyEvent.subscribe(z.disable,z,true);}}}else{if(!i.alreadySubscribed(this.showEvent,w.enable,w)){this.showEvent.subscribe(w.enable,w,true);}if(!i.alreadySubscribed(this.hideEvent,w.disable,w)){this.hideEvent.subscribe(w.disable,w,true);this.destroyEvent.subscribe(w.disable,w,true);}}}},configStrings:function(v,u,w){var x=e.merge(n.STRINGS.value,u[0]);this.cfg.setProperty(n.STRINGS.key,x,tru
 e);},configHeight:function(x,v,y){var u=v[0],w=this.innerElement;a.setStyle(w,&quot;height&quot;,u);this.cfg.refireEvent(&quot;iframe&quot;);},_autoFillOnHeightChange:function(x,v,w){o.superclass._autoFillOnHeightChange.apply(this,arguments);if(p){var u=this;setTimeout(function(){u.sizeUnderlay();},0);}},configWidth:function(x,u,y){var w=u[0],v=this.innerElement;a.setStyle(v,&quot;width&quot;,w);this.cfg.refireEvent(&quot;iframe&quot;);},configzIndex:function(v,u,x){o.superclass.configzIndex.call(this,v,u,x);if(this.mask||this.cfg.getProperty(&quot;modal&quot;)===true){var w=a.getStyle(this.element,&quot;zIndex&quot;);if(!w||isNaN(w)){w=0;}if(w===0){this.cfg.setProperty(&quot;zIndex&quot;,1);}else{this.stackMask();}}},buildWrapper:function(){var w=this.element.parentNode,u=this.element,v=document.createElement(&quot;div&quot;);v.className=o.CSS_PANEL_CONTAINER;v.id=u.id+&quot;_c&quot;;if(w){w.insertBefore(v,u);}v.appendChild(u);this.element=v;this.innerElement=u;a.setStyle(t
 his.innerElement,&quot;visibility&quot;,&quot;inherit&quot;);},sizeUnderlay:function(){var v=this.underlay,u;if(v){u=this.element;v.style.width=u.offsetWidth+&quot;px&quot;;v.style.height=u.offsetHeight+&quot;px&quot;;}},registerDragDrop:function(){var v=this;if(this.header){if(!f.DD){return;}var u=(this.cfg.getProperty(&quot;dragonly&quot;)===true);this.dd=new f.DD(this.element.id,this.id,{dragOnly:u});if(!this.header.id){this.header.id=this.id+&quot;_h&quot;;}this.dd.startDrag=function(){var x,z,w,C,B,A;if(YAHOO.env.ua.ie==6){a.addClass(v.element,&quot;drag&quot;);}if(v.cfg.getProperty(&quot;constraintoviewport&quot;)){var y=h.VIEWPORT_OFFSET;x=v.element.offsetHeight;z=v.element.offsetWidth;w=a.getViewportWidth();C=a.getViewportHeight();B=a.getDocumentScrollLeft();A=a.getDocumentScrollTop();if(x+y&lt;C){this.minY=A+y;this.maxY=A+C-x-y;}else{this.minY=A+y;this.maxY=A+y;}if(z+y&lt;w){this.minX=B+y;this.maxX=B+w-z-y;}else{this.minX=B+y;this.maxX=B+y;}this.constrainX=true;this
 .constrainY=true;}else{this.constrainX=false;this.constrainY=false;}v.dragEvent.fire(&quot;startDrag&quot;,arguments);};this.dd.onDrag=function(){v.syncPosition();v.cfg.refireEvent(&quot;iframe&quot;);if(this.platform==&quot;mac&quot;&amp;&amp;YAHOO.env.ua.gecko){this.showMacGeckoScrollbars();}v.dragEvent.fire(&quot;onDrag&quot;,arguments);};this.dd.endDrag=function(){if(YAHOO.env.ua.ie==6){a.removeClass(v.element,&quot;drag&quot;);}v.dragEvent.fire(&quot;endDrag&quot;,arguments);v.moveEvent.fire(v.cfg.getProperty(&quot;xy&quot;));};this.dd.setHandleElId(this.header.id);this.dd.addInvalidHandleType(&quot;INPUT&quot;);this.dd.addInvalidHandleType(&quot;SELECT&quot;);this.dd.addInvalidHandleType(&quot;TEXTAREA&quot;);}},buildMask:function(){var u=this.mask;if(!u){if(!g){g=document.createElement(&quot;div&quot;);g.className=&quot;mask&quot;;g.innerHTML=&quot;&amp;#160;&quot;;}u=g.cloneNode(true);u.id=this.id+&quot;_mask&quot;;document.body.insertBefore(u,document.body.firstChil
 d);this.mask=u;if(YAHOO.env.ua.gecko&amp;&amp;this.platform==&quot;mac&quot;){a.addClass(this.mask,&quot;block-scrollbars&quot;);}this.stackMask();}},hideMask:function(){if(this.cfg.getProperty(&quot;modal&quot;)&amp;&amp;this.mask&amp;&amp;this.beforeHideMaskEvent.fire()){this.mask.style.display=&quot;none&quot;;a.removeClass(document.body,&quot;masked&quot;);this.hideMaskEvent.fire();}},showMask:function(){if(this.cfg.getProperty(&quot;modal&quot;)&amp;&amp;this.mask&amp;&amp;this.beforeShowMaskEvent.fire()){a.addClass(document.body,&quot;masked&quot;);this.sizeMask();this.mask.style.display=&quot;block&quot;;this.showMaskEvent.fire();}},sizeMask:function(){if(this.mask){var v=this.mask,w=a.getViewportWidth(),u=a.getViewportHeight();if(v.offsetHeight&gt;u){v.style.height=u+&quot;px&quot;;}if(v.offsetWidth&gt;w){v.style.width=w+&quot;px&quot;;}v.style.height=a.getDocumentHeight()+&quot;px&quot;;v.style.width=a.getDocumentWidth()+&quot;px&quot;;}},stackMask:function(){if(thi
 s.mask){var u=a.getStyle(this.element,&quot;zIndex&quot;);if(!YAHOO.lang.isUndefined(u)&amp;&amp;!isNaN(u)){a.setStyle(this.mask,&quot;zIndex&quot;,u-1);}}},render:function(u){return o.superclass.render.call(this,u,this.innerElement);},_renderHeader:function(u){u=u||this.innerElement;o.superclass._renderHeader.call(this,u);},_renderBody:function(u){u=u||this.innerElement;o.superclass._renderBody.call(this,u);},_renderFooter:function(u){u=u||this.innerElement;o.superclass._renderFooter.call(this,u);},destroy:function(u){h.windowResizeEvent.unsubscribe(this.sizeMask,this);this.removeMask();if(this.close){t.purgeElement(this.close);}o.superclass.destroy.call(this,u);},forceUnderlayRedraw:function(){var v=this.underlay;a.addClass(v,&quot;yui-force-redraw&quot;);
+setTimeout(function(){a.removeClass(v,&quot;yui-force-redraw&quot;);},0);},toString:function(){return&quot;Panel &quot;+this.id;}});}());(function(){YAHOO.widget.Dialog=function(j,i){YAHOO.widget.Dialog.superclass.constructor.call(this,j,i);};var b=YAHOO.util.Event,g=YAHOO.util.CustomEvent,e=YAHOO.util.Dom,a=YAHOO.widget.Dialog,f=YAHOO.lang,h={&quot;BEFORE_SUBMIT&quot;:&quot;beforeSubmit&quot;,&quot;SUBMIT&quot;:&quot;submit&quot;,&quot;MANUAL_SUBMIT&quot;:&quot;manualSubmit&quot;,&quot;ASYNC_SUBMIT&quot;:&quot;asyncSubmit&quot;,&quot;FORM_SUBMIT&quot;:&quot;formSubmit&quot;,&quot;CANCEL&quot;:&quot;cancel&quot;},c={&quot;POST_METHOD&quot;:{key:&quot;postmethod&quot;,value:&quot;async&quot;},&quot;POST_DATA&quot;:{key:&quot;postdata&quot;,value:null},&quot;BUTTONS&quot;:{key:&quot;buttons&quot;,value:&quot;none&quot;,supercedes:[&quot;visible&quot;]},&quot;HIDEAFTERSUBMIT&quot;:{key:&quot;hideaftersubmit&quot;,value:true}};a.CSS_DIALOG=&quot;yui-dialog&quot;;function d(){var
  m=this._aButtons,k,l,j;if(f.isArray(m)){k=m.length;if(k&gt;0){j=k-1;do{l=m[j];if(YAHOO.widget.Button&amp;&amp;l instanceof YAHOO.widget.Button){l.destroy();}else{if(l.tagName.toUpperCase()==&quot;BUTTON&quot;){b.purgeElement(l);b.purgeElement(l,false);}}}while(j--);}}}YAHOO.extend(a,YAHOO.widget.Panel,{form:null,initDefaultConfig:function(){a.superclass.initDefaultConfig.call(this);this.callback={success:null,failure:null,argument:null};this.cfg.addProperty(c.POST_METHOD.key,{handler:this.configPostMethod,value:c.POST_METHOD.value,validator:function(i){if(i!=&quot;form&quot;&amp;&amp;i!=&quot;async&quot;&amp;&amp;i!=&quot;none&quot;&amp;&amp;i!=&quot;manual&quot;){return false;}else{return true;}}});this.cfg.addProperty(c.POST_DATA.key,{value:c.POST_DATA.value});this.cfg.addProperty(c.HIDEAFTERSUBMIT.key,{value:c.HIDEAFTERSUBMIT.value});this.cfg.addProperty(c.BUTTONS.key,{handler:this.configButtons,value:c.BUTTONS.value,supercedes:c.BUTTONS.supercedes});},initEvents:functio
 n(){a.superclass.initEvents.call(this);var i=g.LIST;this.beforeSubmitEvent=this.createEvent(h.BEFORE_SUBMIT);this.beforeSubmitEvent.signature=i;this.submitEvent=this.createEvent(h.SUBMIT);this.submitEvent.signature=i;this.manualSubmitEvent=this.createEvent(h.MANUAL_SUBMIT);this.manualSubmitEvent.signature=i;this.asyncSubmitEvent=this.createEvent(h.ASYNC_SUBMIT);this.asyncSubmitEvent.signature=i;this.formSubmitEvent=this.createEvent(h.FORM_SUBMIT);this.formSubmitEvent.signature=i;this.cancelEvent=this.createEvent(h.CANCEL);this.cancelEvent.signature=i;},init:function(j,i){a.superclass.init.call(this,j);this.beforeInitEvent.fire(a);e.addClass(this.element,a.CSS_DIALOG);this.cfg.setProperty(&quot;visible&quot;,false);if(i){this.cfg.applyConfig(i,true);}this.beforeHideEvent.subscribe(this.blurButtons,this,true);this.subscribe(&quot;changeBody&quot;,this.registerForm);this.initEvent.fire(a);},doSubmit:function(){var q=YAHOO.util.Connect,r=this.form,l=false,o=false,s,n,m,j;switch(
 this.cfg.getProperty(&quot;postmethod&quot;)){case&quot;async&quot;:s=r.elements;n=s.length;if(n&gt;0){m=n-1;do{if(s[m].type==&quot;file&quot;){l=true;break;}}while(m--);}if(l&amp;&amp;YAHOO.env.ua.ie&amp;&amp;this.isSecure){o=true;}j=this._getFormAttributes(r);q.setForm(r,l,o);var k=this.cfg.getProperty(&quot;postdata&quot;);var p=q.asyncRequest(j.method,j.action,this.callback,k);this.asyncSubmitEvent.fire(p);break;case&quot;form&quot;:r.submit();this.formSubmitEvent.fire();break;case&quot;none&quot;:case&quot;manual&quot;:this.manualSubmitEvent.fire();break;}},_getFormAttributes:function(k){var i={method:null,action:null};if(k){if(k.getAttributeNode){var j=k.getAttributeNode(&quot;action&quot;);var l=k.getAttributeNode(&quot;method&quot;);if(j){i.action=j.value;}if(l){i.method=l.value;}}else{i.action=k.getAttribute(&quot;action&quot;);i.method=k.getAttribute(&quot;method&quot;);}}i.method=(f.isString(i.method)?i.method:&quot;POST&quot;).toUpperCase();i.action=f.isString(i.
 action)?i.action:&quot;&quot;;return i;},registerForm:function(){var i=this.element.getElementsByTagName(&quot;form&quot;)[0];if(this.form){if(this.form==i&amp;&amp;e.isAncestor(this.element,this.form)){return;}else{b.purgeElement(this.form);this.form=null;}}if(!i){i=document.createElement(&quot;form&quot;);i.name=&quot;frm_&quot;+this.id;this.body.appendChild(i);}if(i){this.form=i;b.on(i,&quot;submit&quot;,this._submitHandler,this,true);}},_submitHandler:function(i){b.stopEvent(i);this.submit();this.form.blur();},setTabLoop:function(i,j){i=i||this.firstButton;j=j||this.lastButton;a.superclass.setTabLoop.call(this,i,j);},_setTabLoop:function(i,j){i=i||this.firstButton;j=this.lastButton||j;this.setTabLoop(i,j);},setFirstLastFocusable:function(){a.superclass.setFirstLastFocusable.call(this);var k,j,m,n=this.focusableElements;this.firstFormElement=null;this.lastFormElement=null;if(this.form&amp;&amp;n&amp;&amp;n.length&gt;0){j=n.length;for(k=0;k&lt;j;++k){m=n[k];if(this.form===
 m.form){this.firstFormElement=m;break;}}for(k=j-1;k&gt;=0;--k){m=n[k];if(this.form===m.form){this.lastFormElement=m;break;}}}},configClose:function(j,i,k){a.superclass.configClose.apply(this,arguments);},_doClose:function(i){b.preventDefault(i);this.cancel();},configButtons:function(t,s,n){var o=YAHOO.widget.Button,v=s[0],l=this.innerElement,u,q,k,r,p,j,m;d.call(this);this._aButtons=null;if(f.isArray(v)){p=document.createElement(&quot;span&quot;);p.className=&quot;button-group&quot;;r=v.length;this._aButtons=[];this.defaultHtmlButton=null;for(m=0;m&lt;r;m++){u=v[m];if(o){k=new o({label:u.text,type:u.type});k.appendTo(p);q=k.get(&quot;element&quot;);if(u.isDefault){k.addClass(&quot;default&quot;);this.defaultHtmlButton=q;}if(f.isFunction(u.handler)){k.set(&quot;onclick&quot;,{fn:u.handler,obj:this,scope:this});}else{if(f.isObject(u.handler)&amp;&amp;f.isFunction(u.handler.fn)){k.set(&quot;onclick&quot;,{fn:u.handler.fn,obj:((!f.isUndefined(u.handler.obj))?u.handler.obj:this),
 scope:(u.handler.scope||this)});}}this._aButtons[this._aButtons.length]=k;}else{q=document.createElement(&quot;button&quot;);q.setAttribute(&quot;type&quot;,&quot;button&quot;);if(u.isDefault){q.className=&quot;default&quot;;this.defaultHtmlButton=q;}q.innerHTML=u.text;if(f.isFunction(u.handler)){b.on(q,&quot;click&quot;,u.handler,this,true);}else{if(f.isObject(u.handler)&amp;&amp;f.isFunction(u.handler.fn)){b.on(q,&quot;click&quot;,u.handler.fn,((!f.isUndefined(u.handler.obj))?u.handler.obj:this),(u.handler.scope||this));}}p.appendChild(q);this._aButtons[this._aButtons.length]=q;}u.htmlButton=q;if(m===0){this.firstButton=q;}if(m==(r-1)){this.lastButton=q;}}this.setFooter(p);j=this.footer;if(e.inDocument(this.element)&amp;&amp;!e.isAncestor(l,j)){l.appendChild(j);}this.buttonSpan=p;}else{p=this.buttonSpan;
+j=this.footer;if(p&amp;&amp;j){j.removeChild(p);this.buttonSpan=null;this.firstButton=null;this.lastButton=null;this.defaultHtmlButton=null;}}this.changeContentEvent.fire();},getButtons:function(){return this._aButtons||null;},focusFirst:function(k,i,n){var j=this.firstFormElement,m=false;if(i&amp;&amp;i[1]){b.stopEvent(i[1]);if(i[0]===9&amp;&amp;this.firstElement){j=this.firstElement;}}if(j){try{j.focus();m=true;}catch(l){}}else{if(this.defaultHtmlButton){m=this.focusDefaultButton();}else{m=this.focusFirstButton();}}return m;},focusLast:function(k,i,n){var o=this.cfg.getProperty(&quot;buttons&quot;),j=this.lastFormElement,m=false;if(i&amp;&amp;i[1]){b.stopEvent(i[1]);if(i[0]===9&amp;&amp;this.lastElement){j=this.lastElement;}}if(o&amp;&amp;f.isArray(o)){m=this.focusLastButton();}else{if(j){try{j.focus();m=true;}catch(l){}}}return m;},_getButton:function(j){var i=YAHOO.widget.Button;if(i&amp;&amp;j&amp;&amp;j.nodeName&amp;&amp;j.id){j=i.getButton(j.id)||j;}return j;},focusDe
 faultButton:function(){var i=this._getButton(this.defaultHtmlButton),k=false;if(i){try{i.focus();k=true;}catch(j){}}return k;},blurButtons:function(){var o=this.cfg.getProperty(&quot;buttons&quot;),l,n,k,j;if(o&amp;&amp;f.isArray(o)){l=o.length;if(l&gt;0){j=(l-1);do{n=o[j];if(n){k=this._getButton(n.htmlButton);if(k){try{k.blur();}catch(m){}}}}while(j--);}}},focusFirstButton:function(){var m=this.cfg.getProperty(&quot;buttons&quot;),k,i,l=false;if(m&amp;&amp;f.isArray(m)){k=m[0];if(k){i=this._getButton(k.htmlButton);if(i){try{i.focus();l=true;}catch(j){}}}}return l;},focusLastButton:function(){var n=this.cfg.getProperty(&quot;buttons&quot;),j,l,i,m=false;if(n&amp;&amp;f.isArray(n)){j=n.length;if(j&gt;0){l=n[(j-1)];if(l){i=this._getButton(l.htmlButton);if(i){try{i.focus();m=true;}catch(k){}}}}}return m;},configPostMethod:function(j,i,k){this.registerForm();},validate:function(){return true;},submit:function(){if(this.validate()){if(this.beforeSubmitEvent.fire()){this.doSubmit(
 );this.submitEvent.fire();if(this.cfg.getProperty(&quot;hideaftersubmit&quot;)){this.hide();}return true;}else{return false;}}else{return false;}},cancel:function(){this.cancelEvent.fire();this.hide();},getData:function(){var A=this.form,k,t,w,m,u,r,q,j,x,l,y,B,p,C,o,z,v;function s(n){var i=n.tagName.toUpperCase();return((i==&quot;INPUT&quot;||i==&quot;TEXTAREA&quot;||i==&quot;SELECT&quot;)&amp;&amp;n.name==m);}if(A){k=A.elements;t=k.length;w={};for(z=0;z&lt;t;z++){m=k[z].name;u=e.getElementsBy(s,&quot;*&quot;,A);r=u.length;if(r&gt;0){if(r==1){u=u[0];q=u.type;j=u.tagName.toUpperCase();switch(j){case&quot;INPUT&quot;:if(q==&quot;checkbox&quot;){w[m]=u.checked;}else{if(q!=&quot;radio&quot;){w[m]=u.value;}}break;case&quot;TEXTAREA&quot;:w[m]=u.value;break;case&quot;SELECT&quot;:x=u.options;l=x.length;y=[];for(v=0;v&lt;l;v++){B=x[v];if(B.selected){o=B.attributes.value;y[y.length]=(o&amp;&amp;o.specified)?B.value:B.text;}}w[m]=y;break;}}else{q=u[0].type;switch(q){case&quot;radio&
 quot;:for(v=0;v&lt;r;v++){p=u[v];if(p.checked){w[m]=p.value;break;}}break;case&quot;checkbox&quot;:y=[];for(v=0;v&lt;r;v++){C=u[v];if(C.checked){y[y.length]=C.value;}}w[m]=y;break;}}}}}return w;},destroy:function(i){d.call(this);this._aButtons=null;var j=this.element.getElementsByTagName(&quot;form&quot;),k;if(j.length&gt;0){k=j[0];if(k){b.purgeElement(k);if(k.parentNode){k.parentNode.removeChild(k);}this.form=null;}}a.superclass.destroy.call(this,i);},toString:function(){return&quot;Dialog &quot;+this.id;}});}());(function(){YAHOO.widget.SimpleDialog=function(e,d){YAHOO.widget.SimpleDialog.superclass.constructor.call(this,e,d);};var c=YAHOO.util.Dom,b=YAHOO.widget.SimpleDialog,a={&quot;ICON&quot;:{key:&quot;icon&quot;,value:&quot;none&quot;,suppressEvent:true},&quot;TEXT&quot;:{key:&quot;text&quot;,value:&quot;&quot;,suppressEvent:true,supercedes:[&quot;icon&quot;]}};b.ICON_BLOCK=&quot;blckicon&quot;;b.ICON_ALARM=&quot;alrticon&quot;;b.ICON_HELP=&quot;hlpicon&quot;;b.ICON_I
 NFO=&quot;infoicon&quot;;b.ICON_WARN=&quot;warnicon&quot;;b.ICON_TIP=&quot;tipicon&quot;;b.ICON_CSS_CLASSNAME=&quot;yui-icon&quot;;b.CSS_SIMPLEDIALOG=&quot;yui-simple-dialog&quot;;YAHOO.extend(b,YAHOO.widget.Dialog,{initDefaultConfig:function(){b.superclass.initDefaultConfig.call(this);this.cfg.addProperty(a.ICON.key,{handler:this.configIcon,value:a.ICON.value,suppressEvent:a.ICON.suppressEvent});this.cfg.addProperty(a.TEXT.key,{handler:this.configText,value:a.TEXT.value,suppressEvent:a.TEXT.suppressEvent,supercedes:a.TEXT.supercedes});},init:function(e,d){b.superclass.init.call(this,e);this.beforeInitEvent.fire(b);c.addClass(this.element,b.CSS_SIMPLEDIALOG);this.cfg.queueProperty(&quot;postmethod&quot;,&quot;manual&quot;);if(d){this.cfg.applyConfig(d,true);}this.beforeRenderEvent.subscribe(function(){if(!this.body){this.setBody(&quot;&quot;);}},this,true);this.initEvent.fire(b);},registerForm:function(){b.superclass.registerForm.call(this);var e=this.form.ownerDocument,d=e.
 createElement(&quot;input&quot;);d.type=&quot;hidden&quot;;d.name=this.id;d.value=&quot;&quot;;this.form.appendChild(d);},configIcon:function(k,j,h){var d=j[0],e=this.body,f=b.ICON_CSS_CLASSNAME,l,i,g;if(d&amp;&amp;d!=&quot;none&quot;){l=c.getElementsByClassName(f,&quot;*&quot;,e);if(l.length===1){i=l[0];g=i.parentNode;if(g){g.removeChild(i);i=null;}}if(d.indexOf(&quot;.&quot;)==-1){i=document.createElement(&quot;span&quot;);i.className=(f+&quot; &quot;+d);i.innerHTML=&quot;&amp;#160;&quot;;}else{i=document.createElement(&quot;img&quot;);i.src=(this.imageRoot+d);i.className=f;}if(i){e.insertBefore(i,e.firstChild);}}},configText:function(e,d,f){var g=d[0];if(g){this.setBody(g);this.cfg.refireEvent(&quot;icon&quot;);}},toString:function(){return&quot;SimpleDialog &quot;+this.id;}});}());(function(){YAHOO.widget.ContainerEffect=function(e,h,g,d,f){if(!f){f=YAHOO.util.Anim;}this.overlay=e;this.attrIn=h;this.attrOut=g;this.targetElement=d||e.element;this.animClass=f;};var b=YAHOO
 .util.Dom,c=YAHOO.util.CustomEvent,a=YAHOO.widget.ContainerEffect;a.FADE=function(d,f){var g=YAHOO.util.Easing,i={attributes:{opacity:{from:0,to:1}},duration:f,method:g.easeIn},e={attributes:{opacity:{to:0}},duration:f,method:g.easeOut},h=new a(d,i,e,d.element);h.handleUnderlayStart=function(){var k=this.overlay.underlay;if(k&amp;&amp;YAHOO.env.ua.ie){var j=(k.filters&amp;&amp;k.filters.length&gt;0);if(j){b.addClass(d.element,&quot;yui-effect-fade&quot;);}}};h.handleUnderlayComplete=function(){var j=this.overlay.underlay;if(j&amp;&amp;YAHOO.env.ua.ie){b.removeClass(d.element,&quot;yui-effect-fade&quot;);}};h.handleStartAnimateIn=function(k,j,l){l.overlay._fadingIn=true;b.addClass(l.overlay.element,&quot;hide-select&quot;);if(!l.overlay.underlay){l.overlay.cfg.refireEvent(&quot;underlay&quot;);
+}l.handleUnderlayStart();l.overlay._setDomVisibility(true);b.setStyle(l.overlay.element,&quot;opacity&quot;,0);};h.handleCompleteAnimateIn=function(k,j,l){l.overlay._fadingIn=false;b.removeClass(l.overlay.element,&quot;hide-select&quot;);if(l.overlay.element.style.filter){l.overlay.element.style.filter=null;}l.handleUnderlayComplete();l.overlay.cfg.refireEvent(&quot;iframe&quot;);l.animateInCompleteEvent.fire();};h.handleStartAnimateOut=function(k,j,l){l.overlay._fadingOut=true;b.addClass(l.overlay.element,&quot;hide-select&quot;);l.handleUnderlayStart();};h.handleCompleteAnimateOut=function(k,j,l){l.overlay._fadingOut=false;b.removeClass(l.overlay.element,&quot;hide-select&quot;);if(l.overlay.element.style.filter){l.overlay.element.style.filter=null;}l.overlay._setDomVisibility(false);b.setStyle(l.overlay.element,&quot;opacity&quot;,1);l.handleUnderlayComplete();l.overlay.cfg.refireEvent(&quot;iframe&quot;);l.animateOutCompleteEvent.fire();};h.init();return h;};a.SLIDE=func
 tion(f,d){var i=YAHOO.util.Easing,l=f.cfg.getProperty(&quot;x&quot;)||b.getX(f.element),k=f.cfg.getProperty(&quot;y&quot;)||b.getY(f.element),m=b.getClientWidth(),h=f.element.offsetWidth,j={attributes:{points:{to:[l,k]}},duration:d,method:i.easeIn},e={attributes:{points:{to:[(m+25),k]}},duration:d,method:i.easeOut},g=new a(f,j,e,f.element,YAHOO.util.Motion);g.handleStartAnimateIn=function(o,n,p){p.overlay.element.style.left=((-25)-h)+&quot;px&quot;;p.overlay.element.style.top=k+&quot;px&quot;;};g.handleTweenAnimateIn=function(q,p,r){var s=b.getXY(r.overlay.element),o=s[0],n=s[1];if(b.getStyle(r.overlay.element,&quot;visibility&quot;)==&quot;hidden&quot;&amp;&amp;o&lt;l){r.overlay._setDomVisibility(true);}r.overlay.cfg.setProperty(&quot;xy&quot;,[o,n],true);r.overlay.cfg.refireEvent(&quot;iframe&quot;);};g.handleCompleteAnimateIn=function(o,n,p){p.overlay.cfg.setProperty(&quot;xy&quot;,[l,k],true);p.startX=l;p.startY=k;p.overlay.cfg.refireEvent(&quot;iframe&quot;);p.animateIn
 CompleteEvent.fire();};g.handleStartAnimateOut=function(o,n,r){var p=b.getViewportWidth(),s=b.getXY(r.overlay.element),q=s[1];r.animOut.attributes.points.to=[(p+25),q];};g.handleTweenAnimateOut=function(p,o,q){var s=b.getXY(q.overlay.element),n=s[0],r=s[1];q.overlay.cfg.setProperty(&quot;xy&quot;,[n,r],true);q.overlay.cfg.refireEvent(&quot;iframe&quot;);};g.handleCompleteAnimateOut=function(o,n,p){p.overlay._setDomVisibility(false);p.overlay.cfg.setProperty(&quot;xy&quot;,[l,k]);p.animateOutCompleteEvent.fire();};g.init();return g;};a.prototype={init:function(){this.beforeAnimateInEvent=this.createEvent(&quot;beforeAnimateIn&quot;);this.beforeAnimateInEvent.signature=c.LIST;this.beforeAnimateOutEvent=this.createEvent(&quot;beforeAnimateOut&quot;);this.beforeAnimateOutEvent.signature=c.LIST;this.animateInCompleteEvent=this.createEvent(&quot;animateInComplete&quot;);this.animateInCompleteEvent.signature=c.LIST;this.animateOutCompleteEvent=this.createEvent(&quot;animateOutCompl
 ete&quot;);this.animateOutCompleteEvent.signature=c.LIST;this.animIn=new this.animClass(this.targetElement,this.attrIn.attributes,this.attrIn.duration,this.attrIn.method);this.animIn.onStart.subscribe(this.handleStartAnimateIn,this);this.animIn.onTween.subscribe(this.handleTweenAnimateIn,this);this.animIn.onComplete.subscribe(this.handleCompleteAnimateIn,this);this.animOut=new this.animClass(this.targetElement,this.attrOut.attributes,this.attrOut.duration,this.attrOut.method);this.animOut.onStart.subscribe(this.handleStartAnimateOut,this);this.animOut.onTween.subscribe(this.handleTweenAnimateOut,this);this.animOut.onComplete.subscribe(this.handleCompleteAnimateOut,this);},animateIn:function(){this._stopAnims(this.lastFrameOnStop);this.beforeAnimateInEvent.fire();this.animIn.animate();},animateOut:function(){this._stopAnims(this.lastFrameOnStop);this.beforeAnimateOutEvent.fire();this.animOut.animate();},lastFrameOnStop:true,_stopAnims:function(d){if(this.animOut&amp;&amp;this
 .animOut.isAnimated()){this.animOut.stop(d);}if(this.animIn&amp;&amp;this.animIn.isAnimated()){this.animIn.stop(d);}},handleStartAnimateIn:function(e,d,f){},handleTweenAnimateIn:function(e,d,f){},handleCompleteAnimateIn:function(e,d,f){},handleStartAnimateOut:function(e,d,f){},handleTweenAnimateOut:function(e,d,f){},handleCompleteAnimateOut:function(e,d,f){},toString:function(){var d=&quot;ContainerEffect&quot;;if(this.overlay){d+=&quot; [&quot;+this.overlay.toString()+&quot;]&quot;;}return d;}};YAHOO.lang.augmentProto(a,YAHOO.util.EventProvider);})();YAHOO.register(&quot;container&quot;,YAHOO.widget.Module,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuicontainercontainer_coreminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/container/container_core-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/container/container_core-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/container/container_core-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,14 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+(function(){YAHOO.util.Config=function(d){if(d){this.init(d);}};var b=YAHOO.lang,c=YAHOO.util.CustomEvent,a=YAHOO.util.Config;a.CONFIG_CHANGED_EVENT=&quot;configChanged&quot;;a.BOOLEAN_TYPE=&quot;boolean&quot;;a.prototype={owner:null,queueInProgress:false,config:null,initialConfig:null,eventQueue:null,configChangedEvent:null,init:function(d){this.owner=d;this.configChangedEvent=this.createEvent(a.CONFIG_CHANGED_EVENT);this.configChangedEvent.signature=c.LIST;this.queueInProgress=false;this.config={};this.initialConfig={};this.eventQueue=[];},checkBoolean:function(d){return(typeof d==a.BOOLEAN_TYPE);},checkNumber:function(d){return(!isNaN(d));},fireEvent:function(d,f){var e=this.config[d];if(e&amp;&amp;e.event){e.event.fire(f);}},addProperty:function(e,d){e=e.toLowerCase();this.config[e]=d;d.event=this.createEvent(e,{scope:this.owner});d.event.signature=c.LIST;d.key=e;if(d.handler){d.event.subscribe(d.handler,this.owner);}this.setProperty(e,d.value,true);if(!d.suppressEvent){
 this.queueProperty(e,d.value);}},getConfig:function(){var d={},f=this.config,g,e;for(g in f){if(b.hasOwnProperty(f,g)){e=f[g];if(e&amp;&amp;e.event){d[g]=e.value;}}}return d;},getProperty:function(d){var e=this.config[d.toLowerCase()];if(e&amp;&amp;e.event){return e.value;}else{return undefined;}},resetProperty:function(d){d=d.toLowerCase();var e=this.config[d];if(e&amp;&amp;e.event){if(d in this.initialConfig){this.setProperty(d,this.initialConfig[d]);return true;}}else{return false;}},setProperty:function(e,g,d){var f;e=e.toLowerCase();if(this.queueInProgress&amp;&amp;!d){this.queueProperty(e,g);return true;}else{f=this.config[e];if(f&amp;&amp;f.event){if(f.validator&amp;&amp;!f.validator(g)){return false;}else{f.value=g;if(!d){this.fireEvent(e,g);this.configChangedEvent.fire([e,g]);}return true;}}else{return false;}}},queueProperty:function(v,r){v=v.toLowerCase();var u=this.config[v],l=false,k,g,h,j,p,t,f,n,o,d,m,w,e;if(u&amp;&amp;u.event){if(!b.isUndefined(r)&amp;&amp;u.
 validator&amp;&amp;!u.validator(r)){return false;}else{if(!b.isUndefined(r)){u.value=r;}else{r=u.value;}l=false;k=this.eventQueue.length;for(m=0;m&lt;k;m++){g=this.eventQueue[m];if(g){h=g[0];j=g[1];if(h==v){this.eventQueue[m]=null;this.eventQueue.push([v,(!b.isUndefined(r)?r:j)]);l=true;break;}}}if(!l&amp;&amp;!b.isUndefined(r)){this.eventQueue.push([v,r]);}}if(u.supercedes){p=u.supercedes.length;for(w=0;w&lt;p;w++){t=u.supercedes[w];f=this.eventQueue.length;for(e=0;e&lt;f;e++){n=this.eventQueue[e];if(n){o=n[0];d=n[1];if(o==t.toLowerCase()){this.eventQueue.push([o,d]);this.eventQueue[e]=null;break;}}}}}return true;}else{return false;}},refireEvent:function(d){d=d.toLowerCase();var e=this.config[d];if(e&amp;&amp;e.event&amp;&amp;!b.isUndefined(e.value)){if(this.queueInProgress){this.queueProperty(d);}else{this.fireEvent(d,e.value);}}},applyConfig:function(d,g){var f,e;if(g){e={};for(f in d){if(b.hasOwnProperty(d,f)){e[f.toLowerCase()]=d[f];}}this.initialConfig=e;}for(f in d){
 if(b.hasOwnProperty(d,f)){this.queueProperty(f,d[f]);}}},refresh:function(){var d;for(d in this.config){if(b.hasOwnProperty(this.config,d)){this.refireEvent(d);}}},fireQueue:function(){var e,h,d,g,f;this.queueInProgress=true;for(e=0;e&lt;this.eventQueue.length;e++){h=this.eventQueue[e];if(h){d=h[0];g=h[1];f=this.config[d];f.value=g;this.eventQueue[e]=null;this.fireEvent(d,g);}}this.queueInProgress=false;this.eventQueue=[];},subscribeToConfigEvent:function(d,e,g,h){var f=this.config[d.toLowerCase()];if(f&amp;&amp;f.event){if(!a.alreadySubscribed(f.event,e,g)){f.event.subscribe(e,g,h);}return true;}else{return false;}},unsubscribeFromConfigEvent:function(d,e,g){var f=this.config[d.toLowerCase()];if(f&amp;&amp;f.event){return f.event.unsubscribe(e,g);}else{return false;}},toString:function(){var d=&quot;Config&quot;;if(this.owner){d+=&quot; [&quot;+this.owner.toString()+&quot;]&quot;;}return d;},outputEventQueue:function(){var d=&quot;&quot;,g,e,f=this.eventQueue.length;for(e=0
 ;e&lt;f;e++){g=this.eventQueue[e];if(g){d+=g[0]+&quot;=&quot;+g[1]+&quot;, &quot;;}}return d;},destroy:function(){var e=this.config,d,f;for(d in e){if(b.hasOwnProperty(e,d)){f=e[d];f.event.unsubscribeAll();f.event=null;}}this.configChangedEvent.unsubscribeAll();this.configChangedEvent=null;this.owner=null;this.config=null;this.initialConfig=null;this.eventQueue=null;}};a.alreadySubscribed=function(e,h,j){var f=e.subscribers.length,d,g;if(f&gt;0){g=f-1;do{d=e.subscribers[g];if(d&amp;&amp;d.obj==j&amp;&amp;d.fn==h){return true;}}while(g--);}return false;};YAHOO.lang.augmentProto(a,YAHOO.util.EventProvider);}());(function(){YAHOO.widget.Module=function(r,q){if(r){this.init(r,q);}else{}};var f=YAHOO.util.Dom,d=YAHOO.util.Config,n=YAHOO.util.Event,m=YAHOO.util.CustomEvent,g=YAHOO.widget.Module,i=YAHOO.env.ua,h,p,o,e,a={&quot;BEFORE_INIT&quot;:&quot;beforeInit&quot;,&quot;INIT&quot;:&quot;init&quot;,&quot;APPEND&quot;:&quot;append&quot;,&quot;BEFORE_RENDER&quot;:&quot;beforeRender
 &quot;,&quot;RENDER&quot;:&quot;render&quot;,&quot;CHANGE_HEADER&quot;:&quot;changeHeader&quot;,&quot;CHANGE_BODY&quot;:&quot;changeBody&quot;,&quot;CHANGE_FOOTER&quot;:&quot;changeFooter&quot;,&quot;CHANGE_CONTENT&quot;:&quot;changeContent&quot;,&quot;DESTROY&quot;:&quot;destroy&quot;,&quot;BEFORE_SHOW&quot;:&quot;beforeShow&quot;,&quot;SHOW&quot;:&quot;show&quot;,&quot;BEFORE_HIDE&quot;:&quot;beforeHide&quot;,&quot;HIDE&quot;:&quot;hide&quot;},j={&quot;VISIBLE&quot;:{key:&quot;visible&quot;,value:true,validator:YAHOO.lang.isBoolean},&quot;EFFECT&quot;:{key:&quot;effect&quot;,suppressEvent:true,supercedes:[&quot;visible&quot;]},&quot;MONITOR_RESIZE&quot;:{key:&quot;monitorresize&quot;,value:true},&quot;APPEND_TO_DOCUMENT_BODY&quot;:{key:&quot;appendtodocumentbody&quot;,value:false}};g.IMG_ROOT=null;g.IMG_ROOT_SSL=null;g.CSS_MODULE=&quot;yui-module&quot;;g.CSS_HEADER=&quot;hd&quot;;g.CSS_BODY=&quot;bd&quot;;g.CSS_FOOTER=&quot;ft&quot;;g.RESIZE_MONITOR_SECURE_URL=&quot;javasc
 ript:false;&quot;;g.RESIZE_MONITOR_BUFFER=1;g.textResizeEvent=new m(&quot;textResize&quot;);g.forceDocumentRedraw=function(){var q=document.documentElement;if(q){q.className+=&quot; &quot;;q.className=YAHOO.lang.trim(q.className);}};function l(){if(!h){h=document.createElement(&quot;div&quot;);h.innerHTML=('&lt;div class=&quot;'+g.CSS_HEADER+'&quot;&gt;&lt;/div&gt;'+'&lt;div class=&quot;'+g.CSS_BODY+'&quot;&gt;&lt;/div&gt;&lt;div class=&quot;'+g.CSS_FOOTER+'&quot;&gt;&lt;/div&gt;');p=h.firstChild;o=p.nextSibling;e=o.nextSibling;}return h;}function k(){if(!p){l();}return(p.cloneNode(false));}function b(){if(!o){l();}return(o.cloneNode(false));}function c(){if(!e){l();}return(e.cloneNode(false));}g.prototype={constructor:g,element:null,header:null,body:null,footer:null,id:null,imageRoot:g.IMG_ROOT,initEvents:function(){var q=m.LIST;
+this.beforeInitEvent=this.createEvent(a.BEFORE_INIT);this.beforeInitEvent.signature=q;this.initEvent=this.createEvent(a.INIT);this.initEvent.signature=q;this.appendEvent=this.createEvent(a.APPEND);this.appendEvent.signature=q;this.beforeRenderEvent=this.createEvent(a.BEFORE_RENDER);this.beforeRenderEvent.signature=q;this.renderEvent=this.createEvent(a.RENDER);this.renderEvent.signature=q;this.changeHeaderEvent=this.createEvent(a.CHANGE_HEADER);this.changeHeaderEvent.signature=q;this.changeBodyEvent=this.createEvent(a.CHANGE_BODY);this.changeBodyEvent.signature=q;this.changeFooterEvent=this.createEvent(a.CHANGE_FOOTER);this.changeFooterEvent.signature=q;this.changeContentEvent=this.createEvent(a.CHANGE_CONTENT);this.changeContentEvent.signature=q;this.destroyEvent=this.createEvent(a.DESTROY);this.destroyEvent.signature=q;this.beforeShowEvent=this.createEvent(a.BEFORE_SHOW);this.beforeShowEvent.signature=q;this.showEvent=this.createEvent(a.SHOW);this.showEvent.signature=q;this
 .beforeHideEvent=this.createEvent(a.BEFORE_HIDE);this.beforeHideEvent.signature=q;this.hideEvent=this.createEvent(a.HIDE);this.hideEvent.signature=q;},platform:function(){var q=navigator.userAgent.toLowerCase();if(q.indexOf(&quot;windows&quot;)!=-1||q.indexOf(&quot;win32&quot;)!=-1){return&quot;windows&quot;;}else{if(q.indexOf(&quot;macintosh&quot;)!=-1){return&quot;mac&quot;;}else{return false;}}}(),browser:function(){var q=navigator.userAgent.toLowerCase();if(q.indexOf(&quot;opera&quot;)!=-1){return&quot;opera&quot;;}else{if(q.indexOf(&quot;msie 7&quot;)!=-1){return&quot;ie7&quot;;}else{if(q.indexOf(&quot;msie&quot;)!=-1){return&quot;ie&quot;;}else{if(q.indexOf(&quot;safari&quot;)!=-1){return&quot;safari&quot;;}else{if(q.indexOf(&quot;gecko&quot;)!=-1){return&quot;gecko&quot;;}else{return false;}}}}}}(),isSecure:function(){if(window.location.href.toLowerCase().indexOf(&quot;https&quot;)===0){return true;}else{return false;}}(),initDefaultConfig:function(){this.cfg.addPrope
 rty(j.VISIBLE.key,{handler:this.configVisible,value:j.VISIBLE.value,validator:j.VISIBLE.validator});this.cfg.addProperty(j.EFFECT.key,{handler:this.configEffect,suppressEvent:j.EFFECT.suppressEvent,supercedes:j.EFFECT.supercedes});this.cfg.addProperty(j.MONITOR_RESIZE.key,{handler:this.configMonitorResize,value:j.MONITOR_RESIZE.value});this.cfg.addProperty(j.APPEND_TO_DOCUMENT_BODY.key,{value:j.APPEND_TO_DOCUMENT_BODY.value});},init:function(v,u){var s,w;this.initEvents();this.beforeInitEvent.fire(g);this.cfg=new d(this);if(this.isSecure){this.imageRoot=g.IMG_ROOT_SSL;}if(typeof v==&quot;string&quot;){s=v;v=document.getElementById(v);if(!v){v=(l()).cloneNode(false);v.id=s;}}this.id=f.generateId(v);this.element=v;w=this.element.firstChild;if(w){var r=false,q=false,t=false;do{if(1==w.nodeType){if(!r&amp;&amp;f.hasClass(w,g.CSS_HEADER)){this.header=w;r=true;}else{if(!q&amp;&amp;f.hasClass(w,g.CSS_BODY)){this.body=w;q=true;}else{if(!t&amp;&amp;f.hasClass(w,g.CSS_FOOTER)){this.fo
 oter=w;t=true;}}}}}while((w=w.nextSibling));}this.initDefaultConfig();f.addClass(this.element,g.CSS_MODULE);if(u){this.cfg.applyConfig(u,true);}if(!d.alreadySubscribed(this.renderEvent,this.cfg.fireQueue,this.cfg)){this.renderEvent.subscribe(this.cfg.fireQueue,this.cfg,true);}this.initEvent.fire(g);},initResizeMonitor:function(){var r=(i.gecko&amp;&amp;this.platform==&quot;windows&quot;);if(r){var q=this;setTimeout(function(){q._initResizeMonitor();},0);}else{this._initResizeMonitor();}},_initResizeMonitor:function(){var q,s,u;function w(){g.textResizeEvent.fire();}if(!i.opera){s=f.get(&quot;_yuiResizeMonitor&quot;);var v=this._supportsCWResize();if(!s){s=document.createElement(&quot;iframe&quot;);if(this.isSecure&amp;&amp;g.RESIZE_MONITOR_SECURE_URL&amp;&amp;i.ie){s.src=g.RESIZE_MONITOR_SECURE_URL;}if(!v){u=[&quot;&lt;html&gt;&lt;head&gt;&lt;script &quot;,'type=&quot;text/javascript&quot;&gt;',&quot;window.onresize=function(){window.parent.&quot;,&quot;YAHOO.widget.Module.t
 extResizeEvent.&quot;,&quot;fire();};&lt;&quot;,&quot;/script&gt;&lt;/head&gt;&quot;,&quot;&lt;body&gt;&lt;/body&gt;&lt;/html&gt;&quot;].join(&quot;&quot;);s.src=&quot;data:text/html;charset=utf-8,&quot;+encodeURIComponent(u);}s.id=&quot;_yuiResizeMonitor&quot;;s.title=&quot;Text Resize Monitor&quot;;s.tabIndex=-1;s.setAttribute(&quot;role&quot;,&quot;presentation&quot;);s.style.position=&quot;absolute&quot;;s.style.visibility=&quot;hidden&quot;;var r=document.body,t=r.firstChild;if(t){r.insertBefore(s,t);}else{r.appendChild(s);}s.style.backgroundColor=&quot;transparent&quot;;s.style.borderWidth=&quot;0&quot;;s.style.width=&quot;2em&quot;;s.style.height=&quot;2em&quot;;s.style.left=&quot;0&quot;;s.style.top=(-1*(s.offsetHeight+g.RESIZE_MONITOR_BUFFER))+&quot;px&quot;;s.style.visibility=&quot;visible&quot;;if(i.webkit){q=s.contentWindow.document;q.open();q.close();}}if(s&amp;&amp;s.contentWindow){g.textResizeEvent.subscribe(this.onDomResize,this,true);if(!g.textResizeInitiali
 zed){if(v){if(!n.on(s.contentWindow,&quot;resize&quot;,w)){n.on(s,&quot;resize&quot;,w);}}g.textResizeInitialized=true;}this.resizeMonitor=s;}}},_supportsCWResize:function(){var q=true;if(i.gecko&amp;&amp;i.gecko&lt;=1.8){q=false;}return q;},onDomResize:function(s,r){var q=-1*(this.resizeMonitor.offsetHeight+g.RESIZE_MONITOR_BUFFER);this.resizeMonitor.style.top=q+&quot;px&quot;;this.resizeMonitor.style.left=&quot;0&quot;;},setHeader:function(r){var q=this.header||(this.header=k());if(r.nodeName){q.innerHTML=&quot;&quot;;q.appendChild(r);}else{q.innerHTML=r;}if(this._rendered){this._renderHeader();}this.changeHeaderEvent.fire(r);this.changeContentEvent.fire();},appendToHeader:function(r){var q=this.header||(this.header=k());q.appendChild(r);this.changeHeaderEvent.fire(r);this.changeContentEvent.fire();},setBody:function(r){var q=this.body||(this.body=b());if(r.nodeName){q.innerHTML=&quot;&quot;;q.appendChild(r);}else{q.innerHTML=r;}if(this._rendered){this._renderBody();}this.
 changeBodyEvent.fire(r);this.changeContentEvent.fire();},appendToBody:function(r){var q=this.body||(this.body=b());q.appendChild(r);this.changeBodyEvent.fire(r);this.changeContentEvent.fire();},setFooter:function(r){var q=this.footer||(this.footer=c());if(r.nodeName){q.innerHTML=&quot;&quot;;q.appendChild(r);}else{q.innerHTML=r;}if(this._rendered){this._renderFooter();}this.changeFooterEvent.fire(r);this.changeContentEvent.fire();},appendToFooter:function(r){var q=this.footer||(this.footer=c());q.appendChild(r);this.changeFooterEvent.fire(r);this.changeContentEvent.fire();},render:function(s,q){var t=this;function r(u){if(typeof u==&quot;string&quot;){u=document.getElementById(u);
+}if(u){t._addToParent(u,t.element);t.appendEvent.fire();}}this.beforeRenderEvent.fire();if(!q){q=this.element;}if(s){r(s);}else{if(!f.inDocument(this.element)){return false;}}this._renderHeader(q);this._renderBody(q);this._renderFooter(q);this._rendered=true;this.renderEvent.fire();return true;},_renderHeader:function(q){q=q||this.element;if(this.header&amp;&amp;!f.inDocument(this.header)){var r=q.firstChild;if(r){q.insertBefore(this.header,r);}else{q.appendChild(this.header);}}},_renderBody:function(q){q=q||this.element;if(this.body&amp;&amp;!f.inDocument(this.body)){if(this.footer&amp;&amp;f.isAncestor(q,this.footer)){q.insertBefore(this.body,this.footer);}else{q.appendChild(this.body);}}},_renderFooter:function(q){q=q||this.element;if(this.footer&amp;&amp;!f.inDocument(this.footer)){q.appendChild(this.footer);}},destroy:function(q){var r,s=!(q);if(this.element){n.purgeElement(this.element,s);r=this.element.parentNode;}if(r){r.removeChild(this.element);}this.element=null;t
 his.header=null;this.body=null;this.footer=null;g.textResizeEvent.unsubscribe(this.onDomResize,this);this.cfg.destroy();this.cfg=null;this.destroyEvent.fire();},show:function(){this.cfg.setProperty(&quot;visible&quot;,true);},hide:function(){this.cfg.setProperty(&quot;visible&quot;,false);},configVisible:function(r,q,s){var t=q[0];if(t){if(this.beforeShowEvent.fire()){f.setStyle(this.element,&quot;display&quot;,&quot;block&quot;);this.showEvent.fire();}}else{if(this.beforeHideEvent.fire()){f.setStyle(this.element,&quot;display&quot;,&quot;none&quot;);this.hideEvent.fire();}}},configEffect:function(r,q,s){this._cachedEffects=(this.cacheEffects)?this._createEffects(q[0]):null;},cacheEffects:true,_createEffects:function(t){var q=null,u,r,s;if(t){if(t instanceof Array){q=[];u=t.length;for(r=0;r&lt;u;r++){s=t[r];if(s.effect){q[q.length]=s.effect(this,s.duration);}}}else{if(t.effect){q=[t.effect(this,t.duration)];}}}return q;},configMonitorResize:function(s,r,t){var q=r[0];if(q){t
 his.initResizeMonitor();}else{g.textResizeEvent.unsubscribe(this.onDomResize,this,true);this.resizeMonitor=null;}},_addToParent:function(q,r){if(!this.cfg.getProperty(&quot;appendtodocumentbody&quot;)&amp;&amp;q===document.body&amp;&amp;q.firstChild){q.insertBefore(r,q.firstChild);}else{q.appendChild(r);}},toString:function(){return&quot;Module &quot;+this.id;}};YAHOO.lang.augmentProto(g,YAHOO.util.EventProvider);}());(function(){YAHOO.widget.Overlay=function(p,o){YAHOO.widget.Overlay.superclass.constructor.call(this,p,o);};var i=YAHOO.lang,m=YAHOO.util.CustomEvent,g=YAHOO.widget.Module,n=YAHOO.util.Event,f=YAHOO.util.Dom,d=YAHOO.util.Config,k=YAHOO.env.ua,b=YAHOO.widget.Overlay,h=&quot;subscribe&quot;,e=&quot;unsubscribe&quot;,c=&quot;contained&quot;,j,a={&quot;BEFORE_MOVE&quot;:&quot;beforeMove&quot;,&quot;MOVE&quot;:&quot;move&quot;},l={&quot;X&quot;:{key:&quot;x&quot;,validator:i.isNumber,suppressEvent:true,supercedes:[&quot;iframe&quot;]},&quot;Y&quot;:{key:&quot;y&quot
 ;,validator:i.isNumber,suppressEvent:true,supercedes:[&quot;iframe&quot;]},&quot;XY&quot;:{key:&quot;xy&quot;,suppressEvent:true,supercedes:[&quot;iframe&quot;]},&quot;CONTEXT&quot;:{key:&quot;context&quot;,suppressEvent:true,supercedes:[&quot;iframe&quot;]},&quot;FIXED_CENTER&quot;:{key:&quot;fixedcenter&quot;,value:false,supercedes:[&quot;iframe&quot;,&quot;visible&quot;]},&quot;WIDTH&quot;:{key:&quot;width&quot;,suppressEvent:true,supercedes:[&quot;context&quot;,&quot;fixedcenter&quot;,&quot;iframe&quot;]},&quot;HEIGHT&quot;:{key:&quot;height&quot;,suppressEvent:true,supercedes:[&quot;context&quot;,&quot;fixedcenter&quot;,&quot;iframe&quot;]},&quot;AUTO_FILL_HEIGHT&quot;:{key:&quot;autofillheight&quot;,supercedes:[&quot;height&quot;],value:&quot;body&quot;},&quot;ZINDEX&quot;:{key:&quot;zindex&quot;,value:null},&quot;CONSTRAIN_TO_VIEWPORT&quot;:{key:&quot;constraintoviewport&quot;,value:false,validator:i.isBoolean,supercedes:[&quot;iframe&quot;,&quot;x&quot;,&quot;y&quot;
 ,&quot;xy&quot;]},&quot;IFRAME&quot;:{key:&quot;iframe&quot;,value:(k.ie==6?true:false),validator:i.isBoolean,supercedes:[&quot;zindex&quot;]},&quot;PREVENT_CONTEXT_OVERLAP&quot;:{key:&quot;preventcontextoverlap&quot;,value:false,validator:i.isBoolean,supercedes:[&quot;constraintoviewport&quot;]}};b.IFRAME_SRC=&quot;javascript:false;&quot;;b.IFRAME_OFFSET=3;b.VIEWPORT_OFFSET=10;b.TOP_LEFT=&quot;tl&quot;;b.TOP_RIGHT=&quot;tr&quot;;b.BOTTOM_LEFT=&quot;bl&quot;;b.BOTTOM_RIGHT=&quot;br&quot;;b.PREVENT_OVERLAP_X={&quot;tltr&quot;:true,&quot;blbr&quot;:true,&quot;brbl&quot;:true,&quot;trtl&quot;:true};b.PREVENT_OVERLAP_Y={&quot;trbr&quot;:true,&quot;tlbl&quot;:true,&quot;bltl&quot;:true,&quot;brtr&quot;:true};b.CSS_OVERLAY=&quot;yui-overlay&quot;;b.CSS_HIDDEN=&quot;yui-overlay-hidden&quot;;b.CSS_IFRAME=&quot;yui-overlay-iframe&quot;;b.STD_MOD_RE=/^\s*?(body|footer|header)\s*?$/i;b.windowScrollEvent=new m(&quot;windowScroll&quot;);b.windowResizeEvent=new m(&quot;windowResize&quot;)
 ;b.windowScrollHandler=function(p){var o=n.getTarget(p);if(!o||o===window||o===window.document){if(k.ie){if(!window.scrollEnd){window.scrollEnd=-1;}clearTimeout(window.scrollEnd);window.scrollEnd=setTimeout(function(){b.windowScrollEvent.fire();},1);}else{b.windowScrollEvent.fire();}}};b.windowResizeHandler=function(o){if(k.ie){if(!window.resizeEnd){window.resizeEnd=-1;}clearTimeout(window.resizeEnd);window.resizeEnd=setTimeout(function(){b.windowResizeEvent.fire();},100);}else{b.windowResizeEvent.fire();}};b._initialized=null;if(b._initialized===null){n.on(window,&quot;scroll&quot;,b.windowScrollHandler);n.on(window,&quot;resize&quot;,b.windowResizeHandler);b._initialized=true;}b._TRIGGER_MAP={&quot;windowScroll&quot;:b.windowScrollEvent,&quot;windowResize&quot;:b.windowResizeEvent,&quot;textResize&quot;:g.textResizeEvent};YAHOO.extend(b,g,{CONTEXT_TRIGGERS:[],init:function(p,o){b.superclass.init.call(this,p);this.beforeInitEvent.fire(b);f.addClass(this.element,b.CSS_OVERLA
 Y);if(o){this.cfg.applyConfig(o,true);}if(this.platform==&quot;mac&quot;&amp;&amp;k.gecko){if(!d.alreadySubscribed(this.showEvent,this.showMacGeckoScrollbars,this)){this.showEvent.subscribe(this.showMacGeckoScrollbars,this,true);}if(!d.alreadySubscribed(this.hideEvent,this.hideMacGeckoScrollbars,this)){this.hideEvent.subscribe(this.hideMacGeckoScrollbars,this,true);}}this.initEvent.fire(b);},initEvents:function(){b.superclass.initEvents.call(this);var o=m.LIST;this.beforeMoveEvent=this.createEvent(a.BEFORE_MOVE);this.beforeMoveEvent.signature=o;this.moveEvent=this.createEvent(a.MOVE);this.moveEvent.signature=o;},initDefaultConfig:function(){b.superclass.initDefaultConfig.call(this);var o=this.cfg;o.addProperty(l.X.key,{handler:this.configX,validator:l.X.validator,suppressEvent:l.X.suppressEvent,supercedes:l.X.supercedes});o.addProperty(l.Y.key,{handler:this.configY,validator:l.Y.validator,suppressEvent:l.Y.suppressEvent,supercedes:l.Y.supercedes});
+o.addProperty(l.XY.key,{handler:this.configXY,suppressEvent:l.XY.suppressEvent,supercedes:l.XY.supercedes});o.addProperty(l.CONTEXT.key,{handler:this.configContext,suppressEvent:l.CONTEXT.suppressEvent,supercedes:l.CONTEXT.supercedes});o.addProperty(l.FIXED_CENTER.key,{handler:this.configFixedCenter,value:l.FIXED_CENTER.value,validator:l.FIXED_CENTER.validator,supercedes:l.FIXED_CENTER.supercedes});o.addProperty(l.WIDTH.key,{handler:this.configWidth,suppressEvent:l.WIDTH.suppressEvent,supercedes:l.WIDTH.supercedes});o.addProperty(l.HEIGHT.key,{handler:this.configHeight,suppressEvent:l.HEIGHT.suppressEvent,supercedes:l.HEIGHT.supercedes});o.addProperty(l.AUTO_FILL_HEIGHT.key,{handler:this.configAutoFillHeight,value:l.AUTO_FILL_HEIGHT.value,validator:this._validateAutoFill,supercedes:l.AUTO_FILL_HEIGHT.supercedes});o.addProperty(l.ZINDEX.key,{handler:this.configzIndex,value:l.ZINDEX.value});o.addProperty(l.CONSTRAIN_TO_VIEWPORT.key,{handler:this.configConstrainToViewport,value
 :l.CONSTRAIN_TO_VIEWPORT.value,validator:l.CONSTRAIN_TO_VIEWPORT.validator,supercedes:l.CONSTRAIN_TO_VIEWPORT.supercedes});o.addProperty(l.IFRAME.key,{handler:this.configIframe,value:l.IFRAME.value,validator:l.IFRAME.validator,supercedes:l.IFRAME.supercedes});o.addProperty(l.PREVENT_CONTEXT_OVERLAP.key,{value:l.PREVENT_CONTEXT_OVERLAP.value,validator:l.PREVENT_CONTEXT_OVERLAP.validator,supercedes:l.PREVENT_CONTEXT_OVERLAP.supercedes});},moveTo:function(o,p){this.cfg.setProperty(&quot;xy&quot;,[o,p]);},hideMacGeckoScrollbars:function(){f.replaceClass(this.element,&quot;show-scrollbars&quot;,&quot;hide-scrollbars&quot;);},showMacGeckoScrollbars:function(){f.replaceClass(this.element,&quot;hide-scrollbars&quot;,&quot;show-scrollbars&quot;);},_setDomVisibility:function(o){f.setStyle(this.element,&quot;visibility&quot;,(o)?&quot;visible&quot;:&quot;hidden&quot;);var p=b.CSS_HIDDEN;if(o){f.removeClass(this.element,p);}else{f.addClass(this.element,p);}},configVisible:function(x,w,t
 ){var p=w[0],B=f.getStyle(this.element,&quot;visibility&quot;),o=this._cachedEffects||this._createEffects(this.cfg.getProperty(&quot;effect&quot;)),A=(this.platform==&quot;mac&quot;&amp;&amp;k.gecko),y=d.alreadySubscribed,q,v,s,r,u,z;if(B==&quot;inherit&quot;){v=this.element.parentNode;while(v.nodeType!=9&amp;&amp;v.nodeType!=11){B=f.getStyle(v,&quot;visibility&quot;);if(B!=&quot;inherit&quot;){break;}v=v.parentNode;}if(B==&quot;inherit&quot;){B=&quot;visible&quot;;}}if(p){if(A){this.showMacGeckoScrollbars();}if(o){if(p){if(B!=&quot;visible&quot;||B===&quot;&quot;||this._fadingOut){if(this.beforeShowEvent.fire()){z=o.length;for(s=0;s&lt;z;s++){q=o[s];if(s===0&amp;&amp;!y(q.animateInCompleteEvent,this.showEvent.fire,this.showEvent)){q.animateInCompleteEvent.subscribe(this.showEvent.fire,this.showEvent,true);}q.animateIn();}}}}}else{if(B!=&quot;visible&quot;||B===&quot;&quot;){if(this.beforeShowEvent.fire()){this._setDomVisibility(true);this.cfg.refireEvent(&quot;iframe&quot;)
 ;this.showEvent.fire();}}else{this._setDomVisibility(true);}}}else{if(A){this.hideMacGeckoScrollbars();}if(o){if(B==&quot;visible&quot;||this._fadingIn){if(this.beforeHideEvent.fire()){z=o.length;for(r=0;r&lt;z;r++){u=o[r];if(r===0&amp;&amp;!y(u.animateOutCompleteEvent,this.hideEvent.fire,this.hideEvent)){u.animateOutCompleteEvent.subscribe(this.hideEvent.fire,this.hideEvent,true);}u.animateOut();}}}else{if(B===&quot;&quot;){this._setDomVisibility(false);}}}else{if(B==&quot;visible&quot;||B===&quot;&quot;){if(this.beforeHideEvent.fire()){this._setDomVisibility(false);this.hideEvent.fire();}}else{this._setDomVisibility(false);}}}},doCenterOnDOMEvent:function(){var o=this.cfg,p=o.getProperty(&quot;fixedcenter&quot;);if(o.getProperty(&quot;visible&quot;)){if(p&amp;&amp;(p!==c||this.fitsInViewport())){this.center();}}},fitsInViewport:function(){var s=b.VIEWPORT_OFFSET,q=this.element,t=q.offsetWidth,r=q.offsetHeight,o=f.getViewportWidth(),p=f.getViewportHeight();return((t+s&lt;o)
 &amp;&amp;(r+s&lt;p));},configFixedCenter:function(s,q,t){var u=q[0],p=d.alreadySubscribed,r=b.windowResizeEvent,o=b.windowScrollEvent;if(u){this.center();if(!p(this.beforeShowEvent,this.center)){this.beforeShowEvent.subscribe(this.center);}if(!p(r,this.doCenterOnDOMEvent,this)){r.subscribe(this.doCenterOnDOMEvent,this,true);}if(!p(o,this.doCenterOnDOMEvent,this)){o.subscribe(this.doCenterOnDOMEvent,this,true);}}else{this.beforeShowEvent.unsubscribe(this.center);r.unsubscribe(this.doCenterOnDOMEvent,this);o.unsubscribe(this.doCenterOnDOMEvent,this);}},configHeight:function(r,p,s){var o=p[0],q=this.element;f.setStyle(q,&quot;height&quot;,o);this.cfg.refireEvent(&quot;iframe&quot;);},configAutoFillHeight:function(t,s,p){var v=s[0],q=this.cfg,u=&quot;autofillheight&quot;,w=&quot;height&quot;,r=q.getProperty(u),o=this._autoFillOnHeightChange;q.unsubscribeFromConfigEvent(w,o);g.textResizeEvent.unsubscribe(o);this.changeContentEvent.unsubscribe(o);if(r&amp;&amp;v!==r&amp;&amp;this
 [r]){f.setStyle(this[r],w,&quot;&quot;);}if(v){v=i.trim(v.toLowerCase());q.subscribeToConfigEvent(w,o,this[v],this);g.textResizeEvent.subscribe(o,this[v],this);this.changeContentEvent.subscribe(o,this[v],this);q.setProperty(u,v,true);}},configWidth:function(r,o,s){var q=o[0],p=this.element;f.setStyle(p,&quot;width&quot;,q);this.cfg.refireEvent(&quot;iframe&quot;);},configzIndex:function(q,o,r){var s=o[0],p=this.element;if(!s){s=f.getStyle(p,&quot;zIndex&quot;);if(!s||isNaN(s)){s=0;}}if(this.iframe||this.cfg.getProperty(&quot;iframe&quot;)===true){if(s&lt;=0){s=1;}}f.setStyle(p,&quot;zIndex&quot;,s);this.cfg.setProperty(&quot;zIndex&quot;,s,true);if(this.iframe){this.stackIframe();}},configXY:function(q,p,r){var t=p[0],o=t[0],s=t[1];this.cfg.setProperty(&quot;x&quot;,o);this.cfg.setProperty(&quot;y&quot;,s);this.beforeMoveEvent.fire([o,s]);o=this.cfg.getProperty(&quot;x&quot;);s=this.cfg.getProperty(&quot;y&quot;);this.cfg.refireEvent(&quot;iframe&quot;);this.moveEvent.fire([
 o,s]);},configX:function(q,p,r){var o=p[0],s=this.cfg.getProperty(&quot;y&quot;);this.cfg.setProperty(&quot;x&quot;,o,true);this.cfg.setProperty(&quot;y&quot;,s,true);this.beforeMoveEvent.fire([o,s]);o=this.cfg.getProperty(&quot;x&quot;);s=this.cfg.getProperty(&quot;y&quot;);f.setX(this.element,o,true);this.cfg.setProperty(&quot;xy&quot;,[o,s],true);this.cfg.refireEvent(&quot;iframe&quot;);this.moveEvent.fire([o,s]);},configY:function(q,p,r){var o=this.cfg.getProperty(&quot;x&quot;),s=p[0];this.cfg.setProperty(&quot;x&quot;,o,true);this.cfg.setProperty(&quot;y&quot;,s,true);this.beforeMoveEvent.fire([o,s]);o=this.cfg.getProperty(&quot;x&quot;);s=this.cfg.getProperty(&quot;y&quot;);f.setY(this.element,s,true);
+this.cfg.setProperty(&quot;xy&quot;,[o,s],true);this.cfg.refireEvent(&quot;iframe&quot;);this.moveEvent.fire([o,s]);},showIframe:function(){var p=this.iframe,o;if(p){o=this.element.parentNode;if(o!=p.parentNode){this._addToParent(o,p);}p.style.display=&quot;block&quot;;}},hideIframe:function(){if(this.iframe){this.iframe.style.display=&quot;none&quot;;}},syncIframe:function(){var o=this.iframe,q=this.element,s=b.IFRAME_OFFSET,p=(s*2),r;if(o){o.style.width=(q.offsetWidth+p+&quot;px&quot;);o.style.height=(q.offsetHeight+p+&quot;px&quot;);r=this.cfg.getProperty(&quot;xy&quot;);if(!i.isArray(r)||(isNaN(r[0])||isNaN(r[1]))){this.syncPosition();r=this.cfg.getProperty(&quot;xy&quot;);}f.setXY(o,[(r[0]-s),(r[1]-s)]);}},stackIframe:function(){if(this.iframe){var o=f.getStyle(this.element,&quot;zIndex&quot;);if(!YAHOO.lang.isUndefined(o)&amp;&amp;!isNaN(o)){f.setStyle(this.iframe,&quot;zIndex&quot;,(o-1));}}},configIframe:function(r,q,s){var o=q[0];function t(){var v=this.iframe,w=thi
 s.element,x;if(!v){if(!j){j=document.createElement(&quot;iframe&quot;);if(this.isSecure){j.src=b.IFRAME_SRC;}if(k.ie){j.style.filter=&quot;alpha(opacity=0)&quot;;j.frameBorder=0;}else{j.style.opacity=&quot;0&quot;;}j.style.position=&quot;absolute&quot;;j.style.border=&quot;none&quot;;j.style.margin=&quot;0&quot;;j.style.padding=&quot;0&quot;;j.style.display=&quot;none&quot;;j.tabIndex=-1;j.className=b.CSS_IFRAME;}v=j.cloneNode(false);v.id=this.id+&quot;_f&quot;;x=w.parentNode;var u=x||document.body;this._addToParent(u,v);this.iframe=v;}this.showIframe();this.syncIframe();this.stackIframe();if(!this._hasIframeEventListeners){this.showEvent.subscribe(this.showIframe);this.hideEvent.subscribe(this.hideIframe);this.changeContentEvent.subscribe(this.syncIframe);this._hasIframeEventListeners=true;}}function p(){t.call(this);this.beforeShowEvent.unsubscribe(p);this._iframeDeferred=false;}if(o){if(this.cfg.getProperty(&quot;visible&quot;)){t.call(this);}else{if(!this._iframeDeferred
 ){this.beforeShowEvent.subscribe(p);this._iframeDeferred=true;}}}else{this.hideIframe();if(this._hasIframeEventListeners){this.showEvent.unsubscribe(this.showIframe);this.hideEvent.unsubscribe(this.hideIframe);this.changeContentEvent.unsubscribe(this.syncIframe);this._hasIframeEventListeners=false;}}},_primeXYFromDOM:function(){if(YAHOO.lang.isUndefined(this.cfg.getProperty(&quot;xy&quot;))){this.syncPosition();this.cfg.refireEvent(&quot;xy&quot;);this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);}},configConstrainToViewport:function(p,o,q){var r=o[0];if(r){if(!d.alreadySubscribed(this.beforeMoveEvent,this.enforceConstraints,this)){this.beforeMoveEvent.subscribe(this.enforceConstraints,this,true);}if(!d.alreadySubscribed(this.beforeShowEvent,this._primeXYFromDOM)){this.beforeShowEvent.subscribe(this._primeXYFromDOM);}}else{this.beforeShowEvent.unsubscribe(this._primeXYFromDOM);this.beforeMoveEvent.unsubscribe(this.enforceConstraints,this);}},configContext:function(u,t,q
 ){var x=t[0],r,o,v,s,p,w=this.CONTEXT_TRIGGERS;if(x){r=x[0];o=x[1];v=x[2];s=x[3];p=x[4];if(w&amp;&amp;w.length&gt;0){s=(s||[]).concat(w);}if(r){if(typeof r==&quot;string&quot;){this.cfg.setProperty(&quot;context&quot;,[document.getElementById(r),o,v,s,p],true);}if(o&amp;&amp;v){this.align(o,v,p);}if(this._contextTriggers){this._processTriggers(this._contextTriggers,e,this._alignOnTrigger);}if(s){this._processTriggers(s,h,this._alignOnTrigger);this._contextTriggers=s;}}}},_alignOnTrigger:function(p,o){this.align();},_findTriggerCE:function(o){var p=null;if(o instanceof m){p=o;}else{if(b._TRIGGER_MAP[o]){p=b._TRIGGER_MAP[o];}}return p;},_processTriggers:function(s,v,r){var q,u;for(var p=0,o=s.length;p&lt;o;++p){q=s[p];u=this._findTriggerCE(q);if(u){u[v](r,this,true);}else{this[v](q,r);}}},align:function(p,w,s){var v=this.cfg.getProperty(&quot;context&quot;),t=this,o,q,u;function r(z,A){var y=null,x=null;switch(p){case b.TOP_LEFT:y=A;x=z;break;case b.TOP_RIGHT:y=A-q.offsetWidth
 ;x=z;break;case b.BOTTOM_LEFT:y=A;x=z-q.offsetHeight;break;case b.BOTTOM_RIGHT:y=A-q.offsetWidth;x=z-q.offsetHeight;break;}if(y!==null&amp;&amp;x!==null){if(s){y+=s[0];x+=s[1];}t.moveTo(y,x);}}if(v){o=v[0];q=this.element;t=this;if(!p){p=v[1];}if(!w){w=v[2];}if(!s&amp;&amp;v[4]){s=v[4];}if(q&amp;&amp;o){u=f.getRegion(o);switch(w){case b.TOP_LEFT:r(u.top,u.left);break;case b.TOP_RIGHT:r(u.top,u.right);break;case b.BOTTOM_LEFT:r(u.bottom,u.left);break;case b.BOTTOM_RIGHT:r(u.bottom,u.right);break;}}}},enforceConstraints:function(p,o,q){var s=o[0];var r=this.getConstrainedXY(s[0],s[1]);this.cfg.setProperty(&quot;x&quot;,r[0],true);this.cfg.setProperty(&quot;y&quot;,r[1],true);this.cfg.setProperty(&quot;xy&quot;,r,true);},_getConstrainedPos:function(y,p){var t=this.element,r=b.VIEWPORT_OFFSET,A=(y==&quot;x&quot;),z=(A)?t.offsetWidth:t.offsetHeight,s=(A)?f.getViewportWidth():f.getViewportHeight(),D=(A)?f.getDocumentScrollLeft():f.getDocumentScrollTop(),C=(A)?b.PREVENT_OVERLAP_X:b.
 PREVENT_OVERLAP_Y,o=this.cfg.getProperty(&quot;context&quot;),u=(z+r&lt;s),w=this.cfg.getProperty(&quot;preventcontextoverlap&quot;)&amp;&amp;o&amp;&amp;C[(o[1]+o[2])],v=D+r,B=D+s-z-r,q=p;if(p&lt;v||p&gt;B){if(w){q=this._preventOverlap(y,o[0],z,s,D);}else{if(u){if(p&lt;v){q=v;}else{if(p&gt;B){q=B;}}}else{q=v;}}}return q;},_preventOverlap:function(y,w,z,u,C){var A=(y==&quot;x&quot;),t=b.VIEWPORT_OFFSET,s=this,q=((A)?f.getX(w):f.getY(w))-C,o=(A)?w.offsetWidth:w.offsetHeight,p=q-t,r=(u-(q+o))-t,D=false,v=function(){var x;if((s.cfg.getProperty(y)-C)&gt;q){x=(q-z);}else{x=(q+o);}s.cfg.setProperty(y,(x+C),true);return x;},B=function(){var E=((s.cfg.getProperty(y)-C)&gt;q)?r:p,x;if(z&gt;E){if(D){v();}else{v();D=true;x=B();}}return x;};B();return this.cfg.getProperty(y);},getConstrainedX:function(o){return this._getConstrainedPos(&quot;x&quot;,o);},getConstrainedY:function(o){return this._getConstrainedPos(&quot;y&quot;,o);},getConstrainedXY:function(o,p){return[this.getConstrainedX
 (o),this.getConstrainedY(p)];},center:function(){var r=b.VIEWPORT_OFFSET,s=this.element.offsetWidth,q=this.element.offsetHeight,p=f.getViewportWidth(),t=f.getViewportHeight(),o,u;if(s&lt;p){o=(p/2)-(s/2)+f.getDocumentScrollLeft();}else{o=r+f.getDocumentScrollLeft();}if(q&lt;t){u=(t/2)-(q/2)+f.getDocumentScrollTop();}else{u=r+f.getDocumentScrollTop();}this.cfg.setProperty(&quot;xy&quot;,[parseInt(o,10),parseInt(u,10)]);this.cfg.refireEvent(&quot;iframe&quot;);if(k.webkit){this.forceContainerRedraw();}},syncPosition:function(){var o=f.getXY(this.element);
+this.cfg.setProperty(&quot;x&quot;,o[0],true);this.cfg.setProperty(&quot;y&quot;,o[1],true);this.cfg.setProperty(&quot;xy&quot;,o,true);},onDomResize:function(q,p){var o=this;b.superclass.onDomResize.call(this,q,p);setTimeout(function(){o.syncPosition();o.cfg.refireEvent(&quot;iframe&quot;);o.cfg.refireEvent(&quot;context&quot;);},0);},_getComputedHeight:(function(){if(document.defaultView&amp;&amp;document.defaultView.getComputedStyle){return function(p){var o=null;if(p.ownerDocument&amp;&amp;p.ownerDocument.defaultView){var q=p.ownerDocument.defaultView.getComputedStyle(p,&quot;&quot;);if(q){o=parseInt(q.height,10);}}return(i.isNumber(o))?o:null;};}else{return function(p){var o=null;if(p.style.pixelHeight){o=p.style.pixelHeight;}return(i.isNumber(o))?o:null;};}})(),_validateAutoFillHeight:function(o){return(!o)||(i.isString(o)&amp;&amp;b.STD_MOD_RE.test(o));},_autoFillOnHeightChange:function(r,p,q){var o=this.cfg.getProperty(&quot;height&quot;);if((o&amp;&amp;o!==&quot;aut
 o&quot;)||(o===0)){this.fillHeight(q);}},_getPreciseHeight:function(p){var o=p.offsetHeight;if(p.getBoundingClientRect){var q=p.getBoundingClientRect();o=q.bottom-q.top;}return o;},fillHeight:function(r){if(r){var p=this.innerElement||this.element,o=[this.header,this.body,this.footer],v,w=0,x=0,t=0,q=false;for(var u=0,s=o.length;u&lt;s;u++){v=o[u];if(v){if(r!==v){x+=this._getPreciseHeight(v);}else{q=true;}}}if(q){if(k.ie||k.opera){f.setStyle(r,&quot;height&quot;,0+&quot;px&quot;);}w=this._getComputedHeight(p);if(w===null){f.addClass(p,&quot;yui-override-padding&quot;);w=p.clientHeight;f.removeClass(p,&quot;yui-override-padding&quot;);}t=Math.max(w-x,0);f.setStyle(r,&quot;height&quot;,t+&quot;px&quot;);if(r.offsetHeight!=t){t=Math.max(t-(r.offsetHeight-t),0);}f.setStyle(r,&quot;height&quot;,t+&quot;px&quot;);}}},bringToTop:function(){var s=[],r=this.element;function v(z,y){var B=f.getStyle(z,&quot;zIndex&quot;),A=f.getStyle(y,&quot;zIndex&quot;),x=(!B||isNaN(B))?0:parseInt(B,
 10),w=(!A||isNaN(A))?0:parseInt(A,10);if(x&gt;w){return -1;}else{if(x&lt;w){return 1;}else{return 0;}}}function q(y){var x=f.hasClass(y,b.CSS_OVERLAY),w=YAHOO.widget.Panel;if(x&amp;&amp;!f.isAncestor(r,y)){if(w&amp;&amp;f.hasClass(y,w.CSS_PANEL)){s[s.length]=y.parentNode;}else{s[s.length]=y;}}}f.getElementsBy(q,&quot;div&quot;,document.body);s.sort(v);var o=s[0],u;if(o){u=f.getStyle(o,&quot;zIndex&quot;);if(!isNaN(u)){var t=false;if(o!=r){t=true;}else{if(s.length&gt;1){var p=f.getStyle(s[1],&quot;zIndex&quot;);if(!isNaN(p)&amp;&amp;(u==p)){t=true;}}}if(t){this.cfg.setProperty(&quot;zindex&quot;,(parseInt(u,10)+2));}}}},destroy:function(o){if(this.iframe){this.iframe.parentNode.removeChild(this.iframe);}this.iframe=null;b.windowResizeEvent.unsubscribe(this.doCenterOnDOMEvent,this);b.windowScrollEvent.unsubscribe(this.doCenterOnDOMEvent,this);g.textResizeEvent.unsubscribe(this._autoFillOnHeightChange);if(this._contextTriggers){this._processTriggers(this._contextTriggers,e,this
 ._alignOnTrigger);}b.superclass.destroy.call(this,o);},forceContainerRedraw:function(){var o=this;f.addClass(o.element,&quot;yui-force-redraw&quot;);setTimeout(function(){f.removeClass(o.element,&quot;yui-force-redraw&quot;);},0);},toString:function(){return&quot;Overlay &quot;+this.id;}});}());(function(){YAHOO.widget.OverlayManager=function(g){this.init(g);};var d=YAHOO.widget.Overlay,c=YAHOO.util.Event,e=YAHOO.util.Dom,b=YAHOO.util.Config,f=YAHOO.util.CustomEvent,a=YAHOO.widget.OverlayManager;a.CSS_FOCUSED=&quot;focused&quot;;a.prototype={constructor:a,overlays:null,initDefaultConfig:function(){this.cfg.addProperty(&quot;overlays&quot;,{suppressEvent:true});this.cfg.addProperty(&quot;focusevent&quot;,{value:&quot;mousedown&quot;});},init:function(i){this.cfg=new b(this);this.initDefaultConfig();if(i){this.cfg.applyConfig(i,true);}this.cfg.fireQueue();var h=null;this.getActive=function(){return h;};this.focus=function(j){var k=this.find(j);if(k){k.focus();}};this.remove=fu
 nction(k){var m=this.find(k),j;if(m){if(h==m){h=null;}var l=(m.element===null&amp;&amp;m.cfg===null)?true:false;if(!l){j=e.getStyle(m.element,&quot;zIndex&quot;);m.cfg.setProperty(&quot;zIndex&quot;,-1000,true);}this.overlays.sort(this.compareZIndexDesc);this.overlays=this.overlays.slice(0,(this.overlays.length-1));m.hideEvent.unsubscribe(m.blur);m.destroyEvent.unsubscribe(this._onOverlayDestroy,m);m.focusEvent.unsubscribe(this._onOverlayFocusHandler,m);m.blurEvent.unsubscribe(this._onOverlayBlurHandler,m);if(!l){c.removeListener(m.element,this.cfg.getProperty(&quot;focusevent&quot;),this._onOverlayElementFocus);m.cfg.setProperty(&quot;zIndex&quot;,j,true);m.cfg.setProperty(&quot;manager&quot;,null);}if(m.focusEvent._managed){m.focusEvent=null;}if(m.blurEvent._managed){m.blurEvent=null;}if(m.focus._managed){m.focus=null;}if(m.blur._managed){m.blur=null;}}};this.blurAll=function(){var k=this.overlays.length,j;if(k&gt;0){j=k-1;do{this.overlays[j].blur();}while(j--);}};this._ma
 nageBlur=function(j){var k=false;if(h==j){e.removeClass(h.element,a.CSS_FOCUSED);h=null;k=true;}return k;};this._manageFocus=function(j){var k=false;if(h!=j){if(h){h.blur();}h=j;this.bringToTop(h);e.addClass(h.element,a.CSS_FOCUSED);k=true;}return k;};var g=this.cfg.getProperty(&quot;overlays&quot;);if(!this.overlays){this.overlays=[];}if(g){this.register(g);this.overlays.sort(this.compareZIndexDesc);}},_onOverlayElementFocus:function(i){var g=c.getTarget(i),h=this.close;if(h&amp;&amp;(g==h||e.isAncestor(h,g))){this.blur();}else{this.focus();}},_onOverlayDestroy:function(h,g,i){this.remove(i);},_onOverlayFocusHandler:function(h,g,i){this._manageFocus(i);},_onOverlayBlurHandler:function(h,g,i){this._manageBlur(i);},_bindFocus:function(g){var h=this;if(!g.focusEvent){g.focusEvent=g.createEvent(&quot;focus&quot;);g.focusEvent.signature=f.LIST;g.focusEvent._managed=true;}else{g.focusEvent.subscribe(h._onOverlayFocusHandler,g,h);}if(!g.focus){c.on(g.element,h.cfg.getProperty(&quo
 t;focusevent&quot;),h._onOverlayElementFocus,null,g);g.focus=function(){if(h._manageFocus(this)){if(this.cfg.getProperty(&quot;visible&quot;)&amp;&amp;this.focusFirst){this.focusFirst();}this.focusEvent.fire();}};g.focus._managed=true;}},_bindBlur:function(g){var h=this;if(!g.blurEvent){g.blurEvent=g.createEvent(&quot;blur&quot;);g.blurEvent.signature=f.LIST;g.focusEvent._managed=true;}else{g.blurEvent.subscribe(h._onOverlayBlurHandler,g,h);}if(!g.blur){g.blur=function(){if(h._manageBlur(this)){this.blurEvent.fire();}};g.blur._managed=true;}g.hideEvent.subscribe(g.blur);
+},_bindDestroy:function(g){var h=this;g.destroyEvent.subscribe(h._onOverlayDestroy,g,h);},_syncZIndex:function(g){var h=e.getStyle(g.element,&quot;zIndex&quot;);if(!isNaN(h)){g.cfg.setProperty(&quot;zIndex&quot;,parseInt(h,10));}else{g.cfg.setProperty(&quot;zIndex&quot;,0);}},register:function(g){var k=false,h,j;if(g instanceof d){g.cfg.addProperty(&quot;manager&quot;,{value:this});this._bindFocus(g);this._bindBlur(g);this._bindDestroy(g);this._syncZIndex(g);this.overlays.push(g);this.bringToTop(g);k=true;}else{if(g instanceof Array){for(h=0,j=g.length;h&lt;j;h++){k=this.register(g[h])||k;}}}return k;},bringToTop:function(m){var i=this.find(m),l,g,j;if(i){j=this.overlays;j.sort(this.compareZIndexDesc);g=j[0];if(g){l=e.getStyle(g.element,&quot;zIndex&quot;);if(!isNaN(l)){var k=false;if(g!==i){k=true;}else{if(j.length&gt;1){var h=e.getStyle(j[1].element,&quot;zIndex&quot;);if(!isNaN(h)&amp;&amp;(l==h)){k=true;}}}if(k){i.cfg.setProperty(&quot;zindex&quot;,(parseInt(l,10)+2));}}
 j.sort(this.compareZIndexDesc);}}},find:function(g){var l=g instanceof d,j=this.overlays,p=j.length,k=null,m,h;if(l||typeof g==&quot;string&quot;){for(h=p-1;h&gt;=0;h--){m=j[h];if((l&amp;&amp;(m===g))||(m.id==g)){k=m;break;}}}return k;},compareZIndexDesc:function(j,i){var h=(j.cfg)?j.cfg.getProperty(&quot;zIndex&quot;):null,g=(i.cfg)?i.cfg.getProperty(&quot;zIndex&quot;):null;if(h===null&amp;&amp;g===null){return 0;}else{if(h===null){return 1;}else{if(g===null){return -1;}else{if(h&gt;g){return -1;}else{if(h&lt;g){return 1;}else{return 0;}}}}}},showAll:function(){var h=this.overlays,j=h.length,g;for(g=j-1;g&gt;=0;g--){h[g].show();}},hideAll:function(){var h=this.overlays,j=h.length,g;for(g=j-1;g&gt;=0;g--){h[g].hide();}},toString:function(){return&quot;OverlayManager&quot;;}};}());(function(){YAHOO.widget.ContainerEffect=function(e,h,g,d,f){if(!f){f=YAHOO.util.Anim;}this.overlay=e;this.attrIn=h;this.attrOut=g;this.targetElement=d||e.element;this.animClass=f;};var b=YAHOO.uti
 l.Dom,c=YAHOO.util.CustomEvent,a=YAHOO.widget.ContainerEffect;a.FADE=function(d,f){var g=YAHOO.util.Easing,i={attributes:{opacity:{from:0,to:1}},duration:f,method:g.easeIn},e={attributes:{opacity:{to:0}},duration:f,method:g.easeOut},h=new a(d,i,e,d.element);h.handleUnderlayStart=function(){var k=this.overlay.underlay;if(k&amp;&amp;YAHOO.env.ua.ie){var j=(k.filters&amp;&amp;k.filters.length&gt;0);if(j){b.addClass(d.element,&quot;yui-effect-fade&quot;);}}};h.handleUnderlayComplete=function(){var j=this.overlay.underlay;if(j&amp;&amp;YAHOO.env.ua.ie){b.removeClass(d.element,&quot;yui-effect-fade&quot;);}};h.handleStartAnimateIn=function(k,j,l){l.overlay._fadingIn=true;b.addClass(l.overlay.element,&quot;hide-select&quot;);if(!l.overlay.underlay){l.overlay.cfg.refireEvent(&quot;underlay&quot;);}l.handleUnderlayStart();l.overlay._setDomVisibility(true);b.setStyle(l.overlay.element,&quot;opacity&quot;,0);};h.handleCompleteAnimateIn=function(k,j,l){l.overlay._fadingIn=false;b.remove
 Class(l.overlay.element,&quot;hide-select&quot;);if(l.overlay.element.style.filter){l.overlay.element.style.filter=null;}l.handleUnderlayComplete();l.overlay.cfg.refireEvent(&quot;iframe&quot;);l.animateInCompleteEvent.fire();};h.handleStartAnimateOut=function(k,j,l){l.overlay._fadingOut=true;b.addClass(l.overlay.element,&quot;hide-select&quot;);l.handleUnderlayStart();};h.handleCompleteAnimateOut=function(k,j,l){l.overlay._fadingOut=false;b.removeClass(l.overlay.element,&quot;hide-select&quot;);if(l.overlay.element.style.filter){l.overlay.element.style.filter=null;}l.overlay._setDomVisibility(false);b.setStyle(l.overlay.element,&quot;opacity&quot;,1);l.handleUnderlayComplete();l.overlay.cfg.refireEvent(&quot;iframe&quot;);l.animateOutCompleteEvent.fire();};h.init();return h;};a.SLIDE=function(f,d){var i=YAHOO.util.Easing,l=f.cfg.getProperty(&quot;x&quot;)||b.getX(f.element),k=f.cfg.getProperty(&quot;y&quot;)||b.getY(f.element),m=b.getClientWidth(),h=f.element.offsetWidth,j=
 {attributes:{points:{to:[l,k]}},duration:d,method:i.easeIn},e={attributes:{points:{to:[(m+25),k]}},duration:d,method:i.easeOut},g=new a(f,j,e,f.element,YAHOO.util.Motion);g.handleStartAnimateIn=function(o,n,p){p.overlay.element.style.left=((-25)-h)+&quot;px&quot;;p.overlay.element.style.top=k+&quot;px&quot;;};g.handleTweenAnimateIn=function(q,p,r){var s=b.getXY(r.overlay.element),o=s[0],n=s[1];if(b.getStyle(r.overlay.element,&quot;visibility&quot;)==&quot;hidden&quot;&amp;&amp;o&lt;l){r.overlay._setDomVisibility(true);}r.overlay.cfg.setProperty(&quot;xy&quot;,[o,n],true);r.overlay.cfg.refireEvent(&quot;iframe&quot;);};g.handleCompleteAnimateIn=function(o,n,p){p.overlay.cfg.setProperty(&quot;xy&quot;,[l,k],true);p.startX=l;p.startY=k;p.overlay.cfg.refireEvent(&quot;iframe&quot;);p.animateInCompleteEvent.fire();};g.handleStartAnimateOut=function(o,n,r){var p=b.getViewportWidth(),s=b.getXY(r.overlay.element),q=s[1];r.animOut.attributes.points.to=[(p+25),q];};g.handleTweenAnimat
 eOut=function(p,o,q){var s=b.getXY(q.overlay.element),n=s[0],r=s[1];q.overlay.cfg.setProperty(&quot;xy&quot;,[n,r],true);q.overlay.cfg.refireEvent(&quot;iframe&quot;);};g.handleCompleteAnimateOut=function(o,n,p){p.overlay._setDomVisibility(false);p.overlay.cfg.setProperty(&quot;xy&quot;,[l,k]);p.animateOutCompleteEvent.fire();};g.init();return g;};a.prototype={init:function(){this.beforeAnimateInEvent=this.createEvent(&quot;beforeAnimateIn&quot;);this.beforeAnimateInEvent.signature=c.LIST;this.beforeAnimateOutEvent=this.createEvent(&quot;beforeAnimateOut&quot;);this.beforeAnimateOutEvent.signature=c.LIST;this.animateInCompleteEvent=this.createEvent(&quot;animateInComplete&quot;);this.animateInCompleteEvent.signature=c.LIST;this.animateOutCompleteEvent=this.createEvent(&quot;animateOutComplete&quot;);this.animateOutCompleteEvent.signature=c.LIST;this.animIn=new this.animClass(this.targetElement,this.attrIn.attributes,this.attrIn.duration,this.attrIn.method);this.animIn.onStar
 t.subscribe(this.handleStartAnimateIn,this);this.animIn.onTween.subscribe(this.handleTweenAnimateIn,this);this.animIn.onComplete.subscribe(this.handleCompleteAnimateIn,this);this.animOut=new this.animClass(this.targetElement,this.attrOut.attributes,this.attrOut.duration,this.attrOut.method);this.animOut.onStart.subscribe(this.handleStartAnimateOut,this);this.animOut.onTween.subscribe(this.handleTweenAnimateOut,this);this.animOut.onComplete.subscribe(this.handleCompleteAnimateOut,this);},animateIn:function(){this._stopAnims(this.lastFrameOnStop);
+this.beforeAnimateInEvent.fire();this.animIn.animate();},animateOut:function(){this._stopAnims(this.lastFrameOnStop);this.beforeAnimateOutEvent.fire();this.animOut.animate();},lastFrameOnStop:true,_stopAnims:function(d){if(this.animOut&amp;&amp;this.animOut.isAnimated()){this.animOut.stop(d);}if(this.animIn&amp;&amp;this.animIn.isAnimated()){this.animIn.stop(d);}},handleStartAnimateIn:function(e,d,f){},handleTweenAnimateIn:function(e,d,f){},handleCompleteAnimateIn:function(e,d,f){},handleStartAnimateOut:function(e,d,f){},handleTweenAnimateOut:function(e,d,f){},handleCompleteAnimateOut:function(e,d,f){},toString:function(){var d=&quot;ContainerEffect&quot;;if(this.overlay){d+=&quot; [&quot;+this.overlay.toString()+&quot;]&quot;;}return d;}};YAHOO.lang.augmentProto(a,YAHOO.util.EventProvider);})();YAHOO.register(&quot;containercore&quot;,YAHOO.widget.Module,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuicookiecookieminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/cookie/cookie-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/cookie/cookie-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/cookie/cookie-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+YAHOO.namespace(&quot;util&quot;);YAHOO.util.Cookie={_createCookieString:function(B,D,C,A){var F=YAHOO.lang,E=encodeURIComponent(B)+&quot;=&quot;+(C?encodeURIComponent(D):D);if(F.isObject(A)){if(A.expires instanceof Date){E+=&quot;; expires=&quot;+A.expires.toUTCString();}if(F.isString(A.path)&amp;&amp;A.path!==&quot;&quot;){E+=&quot;; path=&quot;+A.path;}if(F.isString(A.domain)&amp;&amp;A.domain!==&quot;&quot;){E+=&quot;; domain=&quot;+A.domain;}if(A.secure===true){E+=&quot;; secure&quot;;}}return E;},_createCookieHashString:function(B){var D=YAHOO.lang;if(!D.isObject(B)){throw new TypeError(&quot;Cookie._createCookieHashString(): Argument must be an object.&quot;);}var C=[];for(var A in B){if(D.hasOwnProperty(B,A)&amp;&amp;!D.isFunction(B[A])&amp;&amp;!D.isUndefined(B[A])){C.push(encodeURIComponent(A)+&quot;=&quot;+encodeURIComponent(String(B[A])));}}return C.join(&quot;&amp;&quot;);},_parseCookieHash:function(E){var D=E.split(&quot;&amp;&quot;),F=null,C={};if(E.length&gt;
 0){for(var B=0,A=D.length;B&lt;A;B++){F=D[B].split(&quot;=&quot;);C[decodeURIComponent(F[0])]=decodeURIComponent(F[1]);}}return C;},_parseCookieString:function(J,A){var K={};if(YAHOO.lang.isString(J)&amp;&amp;J.length&gt;0){var B=(A===false?function(L){return L;}:decodeURIComponent);var H=J.split(/;\s/g),I=null,C=null,E=null;for(var D=0,F=H.length;D&lt;F;D++){E=H[D].match(/([^=]+)=/i);if(E instanceof Array){try{I=decodeURIComponent(E[1]);C=B(H[D].substring(E[1].length+1));}catch(G){}}else{I=decodeURIComponent(H[D]);C=&quot;&quot;;}K[I]=C;}}return K;},exists:function(A){if(!YAHOO.lang.isString(A)||A===&quot;&quot;){throw new TypeError(&quot;Cookie.exists(): Cookie name must be a non-empty string.&quot;);}var B=this._parseCookieString(document.cookie,true);return B.hasOwnProperty(A);},get:function(B,A){var E=YAHOO.lang,C;if(E.isFunction(A)){C=A;A={};}else{if(E.isObject(A)){C=A.converter;}else{A={};}}var D=this._parseCookieString(document.cookie,!A.raw);if(!E.isString(B)||B===&
 quot;&quot;){throw new TypeError(&quot;Cookie.get(): Cookie name must be a non-empty string.&quot;);}if(E.isUndefined(D[B])){return null;}if(!E.isFunction(C)){return D[B];}else{return C(D[B]);}},getSub:function(A,C,B){var E=YAHOO.lang,D=this.getSubs(A);if(D!==null){if(!E.isString(C)||C===&quot;&quot;){throw new TypeError(&quot;Cookie.getSub(): Subcookie name must be a non-empty string.&quot;);}if(E.isUndefined(D[C])){return null;}if(!E.isFunction(B)){return D[C];}else{return B(D[C]);}}else{return null;}},getSubs:function(B){var A=YAHOO.lang.isString;if(!A(B)||B===&quot;&quot;){throw new TypeError(&quot;Cookie.getSubs(): Cookie name must be a non-empty string.&quot;);}var C=this._parseCookieString(document.cookie,false);if(A(C[B])){return this._parseCookieHash(C[B]);}return null;},remove:function(B,A){if(!YAHOO.lang.isString(B)||B===&quot;&quot;){throw new TypeError(&quot;Cookie.remove(): Cookie name must be a non-empty string.&quot;);}A=YAHOO.lang.merge(A||{},{expires:new Da
 te(0)});return this.set(B,&quot;&quot;,A);},removeSub:function(B,E,A){var F=YAHOO.lang;A=A||{};if(!F.isString(B)||B===&quot;&quot;){throw new TypeError(&quot;Cookie.removeSub(): Cookie name must be a non-empty string.&quot;);}if(!F.isString(E)||E===&quot;&quot;){throw new TypeError(&quot;Cookie.removeSub(): Subcookie name must be a non-empty string.&quot;);}var D=this.getSubs(B);if(F.isObject(D)&amp;&amp;F.hasOwnProperty(D,E)){delete D[E];if(!A.removeIfEmpty){return this.setSubs(B,D,A);}else{for(var C in D){if(F.hasOwnProperty(D,C)&amp;&amp;!F.isFunction(D[C])&amp;&amp;!F.isUndefined(D[C])){return this.setSubs(B,D,A);}}return this.remove(B,A);}}else{return&quot;&quot;;}},set:function(B,C,A){var E=YAHOO.lang;A=A||{};if(!E.isString(B)){throw new TypeError(&quot;Cookie.set(): Cookie name must be a string.&quot;);}if(E.isUndefined(C)){throw new TypeError(&quot;Cookie.set(): Value cannot be undefined.&quot;);}var D=this._createCookieString(B,C,!A.raw,A);document.cookie=D;return D
 ;},setSub:function(B,D,C,A){var F=YAHOO.lang;if(!F.isString(B)||B===&quot;&quot;){throw new TypeError(&quot;Cookie.setSub(): Cookie name must be a non-empty string.&quot;);}if(!F.isString(D)||D===&quot;&quot;){throw new TypeError(&quot;Cookie.setSub(): Subcookie name must be a non-empty string.&quot;);}if(F.isUndefined(C)){throw new TypeError(&quot;Cookie.setSub(): Subcookie value cannot be undefined.&quot;);}var E=this.getSubs(B);if(!F.isObject(E)){E={};}E[D]=C;return this.setSubs(B,E,A);},setSubs:function(B,C,A){var E=YAHOO.lang;if(!E.isString(B)){throw new TypeError(&quot;Cookie.setSubs(): Cookie name must be a string.&quot;);}if(!E.isObject(C)){throw new TypeError(&quot;Cookie.setSubs(): Cookie value must be an object.&quot;);}var D=this._createCookieString(B,this._createCookieHashString(C),false,A);document.cookie=D;return D;}};YAHOO.register(&quot;cookie&quot;,YAHOO.util.Cookie,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuidatasourcedatasourceminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/datasource/datasource-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/datasource/datasource-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/datasource/datasource-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+(function(){var lang=YAHOO.lang,util=YAHOO.util,Ev=util.Event;util.DataSourceBase=function(oLiveData,oConfigs){if(oLiveData===null||oLiveData===undefined){return;}this.liveData=oLiveData;this._oQueue={interval:null,conn:null,requests:[]};this.responseSchema={};if(oConfigs&amp;&amp;(oConfigs.constructor==Object)){for(var sConfig in oConfigs){if(sConfig){this[sConfig]=oConfigs[sConfig];}}}var maxCacheEntries=this.maxCacheEntries;if(!lang.isNumber(maxCacheEntries)||(maxCacheEntries&lt;0)){maxCacheEntries=0;}this._aIntervals=[];this.createEvent(&quot;cacheRequestEvent&quot;);this.createEvent(&quot;cacheResponseEvent&quot;);this.createEvent(&quot;requestEvent&quot;);this.createEvent(&quot;responseEvent&quot;);this.createEvent(&quot;responseParseEvent&quot;);this.createEvent(&quot;responseCacheEvent&quot;);this.createEvent(&quot;dataErrorEvent&quot;);this.createEvent(&quot;cacheFlushEvent&quot;);var DS=util.DataSourceBase;this._sName=&quot;DataSource instance&quot;+DS._nIndex;DS._
 nIndex++;};var DS=util.DataSourceBase;lang.augmentObject(DS,{TYPE_UNKNOWN:-1,TYPE_JSARRAY:0,TYPE_JSFUNCTION:1,TYPE_XHR:2,TYPE_JSON:3,TYPE_XML:4,TYPE_TEXT:5,TYPE_HTMLTABLE:6,TYPE_SCRIPTNODE:7,TYPE_LOCAL:8,ERROR_DATAINVALID:&quot;Invalid data&quot;,ERROR_DATANULL:&quot;Null data&quot;,_nIndex:0,_nTransactionId:0,_cloneObject:function(o){if(!lang.isValue(o)){return o;}var copy={};if(Object.prototype.toString.apply(o)===&quot;[object RegExp]&quot;){copy=o;}else{if(lang.isFunction(o)){copy=o;}else{if(lang.isArray(o)){var array=[];for(var i=0,len=o.length;i&lt;len;i++){array[i]=DS._cloneObject(o[i]);}copy=array;}else{if(lang.isObject(o)){for(var x in o){if(lang.hasOwnProperty(o,x)){if(lang.isValue(o[x])&amp;&amp;lang.isObject(o[x])||lang.isArray(o[x])){copy[x]=DS._cloneObject(o[x]);}else{copy[x]=o[x];}}}}else{copy=o;}}}}return copy;},_getLocationValue:function(field,context){var locator=field.locator||field.key||field,xmldoc=context.ownerDocument||context,result,res,value=null;try
 {if(!lang.isUndefined(xmldoc.evaluate)){result=xmldoc.evaluate(locator,context,xmldoc.createNSResolver(!context.ownerDocument?context.documentElement:context.ownerDocument.documentElement),0,null);while(res=result.iterateNext()){value=res.textContent;}}else{xmldoc.setProperty(&quot;SelectionLanguage&quot;,&quot;XPath&quot;);result=context.selectNodes(locator)[0];value=result.value||result.text||null;}return value;}catch(e){}},issueCallback:function(callback,params,error,scope){if(lang.isFunction(callback)){callback.apply(scope,params);}else{if(lang.isObject(callback)){scope=callback.scope||scope||window;var callbackFunc=callback.success;if(error){callbackFunc=callback.failure;}if(callbackFunc){callbackFunc.apply(scope,params.concat([callback.argument]));}}}},parseString:function(oData){if(!lang.isValue(oData)){return null;}var string=oData+&quot;&quot;;if(lang.isString(string)){return string;}else{return null;}},parseNumber:function(oData){if(!lang.isValue(oData)||(oData===&
 quot;&quot;)){return null;}var number=oData*1;if(lang.isNumber(number)){return number;}else{return null;}},convertNumber:function(oData){return DS.parseNumber(oData);},parseDate:function(oData){var date=null;if(lang.isValue(oData)&amp;&amp;!(oData instanceof Date)){date=new Date(oData);}else{return oData;}if(date instanceof Date){return date;}else{return null;}},convertDate:function(oData){return DS.parseDate(oData);}});DS.Parser={string:DS.parseString,number:DS.parseNumber,date:DS.parseDate};DS.prototype={_sName:null,_aCache:null,_oQueue:null,_aIntervals:null,maxCacheEntries:0,liveData:null,dataType:DS.TYPE_UNKNOWN,responseType:DS.TYPE_UNKNOWN,responseSchema:null,useXPath:false,cloneBeforeCaching:false,toString:function(){return this._sName;},getCachedResponse:function(oRequest,oCallback,oCaller){var aCache=this._aCache;if(this.maxCacheEntries&gt;0){if(!aCache){this._aCache=[];}else{var nCacheLength=aCache.length;if(nCacheLength&gt;0){var oResponse=null;this.fireEvent(&quot
 ;cacheRequestEvent&quot;,{request:oRequest,callback:oCallback,caller:oCaller});for(var i=nCacheLength-1;i&gt;=0;i--){var oCacheElem=aCache[i];if(this.isCacheHit(oRequest,oCacheElem.request)){oResponse=oCacheElem.response;this.fireEvent(&quot;cacheResponseEvent&quot;,{request:oRequest,response:oResponse,callback:oCallback,caller:oCaller});if(i&lt;nCacheLength-1){aCache.splice(i,1);this.addToCache(oRequest,oResponse);}oResponse.cached=true;break;}}return oResponse;}}}else{if(aCache){this._aCache=null;}}return null;},isCacheHit:function(oRequest,oCachedRequest){return(oRequest===oCachedRequest);},addToCache:function(oRequest,oResponse){var aCache=this._aCache;if(!aCache){return;}while(aCache.length&gt;=this.maxCacheEntries){aCache.shift();}oResponse=(this.cloneBeforeCaching)?DS._cloneObject(oResponse):oResponse;var oCacheElem={request:oRequest,response:oResponse};aCache[aCache.length]=oCacheElem;this.fireEvent(&quot;responseCacheEvent&quot;,{request:oRequest,response:oResponse}
 );},flushCache:function(){if(this._aCache){this._aCache=[];this.fireEvent(&quot;cacheFlushEvent&quot;);}},setInterval:function(nMsec,oRequest,oCallback,oCaller){if(lang.isNumber(nMsec)&amp;&amp;(nMsec&gt;=0)){var oSelf=this;var nId=setInterval(function(){oSelf.makeConnection(oRequest,oCallback,oCaller);},nMsec);this._aIntervals.push(nId);return nId;}else{}},clearInterval:function(nId){var tracker=this._aIntervals||[];for(var i=tracker.length-1;i&gt;-1;i--){if(tracker[i]===nId){tracker.splice(i,1);clearInterval(nId);}}},clearAllIntervals:function(){var tracker=this._aIntervals||[];for(var i=tracker.length-1;i&gt;-1;i--){clearInterval(tracker[i]);}tracker=[];},sendRequest:function(oRequest,oCallback,oCaller){var oCachedResponse=this.getCachedResponse(oRequest,oCallback,oCaller);if(oCachedResponse){DS.issueCallback(oCallback,[oRequest,oCachedResponse],false,oCaller);return null;}return this.makeConnection(oRequest,oCallback,oCaller);},makeConnection:function(oRequest,oCallback,
 oCaller){var tId=DS._nTransactionId++;this.fireEvent(&quot;requestEvent&quot;,{tId:tId,request:oRequest,callback:oCallback,caller:oCaller});var oRawResponse=this.liveData;this.handleResponse(oRequest,oRawResponse,oCallback,oCaller,tId);return tId;},handleResponse:function(oRequest,oRawResponse,oCallback,oCaller,tId){this.fireEvent(&quot;responseEvent&quot;,{tId:tId,request:oRequest,response:oRawResponse,callback:oCallback,caller:oCaller});
+var xhr=(this.dataType==DS.TYPE_XHR)?true:false;var oParsedResponse=null;var oFullResponse=oRawResponse;if(this.responseType===DS.TYPE_UNKNOWN){var ctype=(oRawResponse&amp;&amp;oRawResponse.getResponseHeader)?oRawResponse.getResponseHeader[&quot;Content-Type&quot;]:null;if(ctype){if(ctype.indexOf(&quot;text/xml&quot;)&gt;-1){this.responseType=DS.TYPE_XML;}else{if(ctype.indexOf(&quot;application/json&quot;)&gt;-1){this.responseType=DS.TYPE_JSON;}else{if(ctype.indexOf(&quot;text/plain&quot;)&gt;-1){this.responseType=DS.TYPE_TEXT;}}}}else{if(YAHOO.lang.isArray(oRawResponse)){this.responseType=DS.TYPE_JSARRAY;}else{if(oRawResponse&amp;&amp;oRawResponse.nodeType&amp;&amp;(oRawResponse.nodeType===9||oRawResponse.nodeType===1||oRawResponse.nodeType===11)){this.responseType=DS.TYPE_XML;}else{if(oRawResponse&amp;&amp;oRawResponse.nodeName&amp;&amp;(oRawResponse.nodeName.toLowerCase()==&quot;table&quot;)){this.responseType=DS.TYPE_HTMLTABLE;}else{if(YAHOO.lang.isObject(oRawResponse)){
 this.responseType=DS.TYPE_JSON;}else{if(YAHOO.lang.isString(oRawResponse)){this.responseType=DS.TYPE_TEXT;}}}}}}}switch(this.responseType){case DS.TYPE_JSARRAY:if(xhr&amp;&amp;oRawResponse&amp;&amp;oRawResponse.responseText){oFullResponse=oRawResponse.responseText;}try{if(lang.isString(oFullResponse)){var parseArgs=[oFullResponse].concat(this.parseJSONArgs);if(lang.JSON){oFullResponse=lang.JSON.parse.apply(lang.JSON,parseArgs);}else{if(window.JSON&amp;&amp;JSON.parse){oFullResponse=JSON.parse.apply(JSON,parseArgs);}else{if(oFullResponse.parseJSON){oFullResponse=oFullResponse.parseJSON.apply(oFullResponse,parseArgs.slice(1));}else{while(oFullResponse.length&gt;0&amp;&amp;(oFullResponse.charAt(0)!=&quot;{&quot;)&amp;&amp;(oFullResponse.charAt(0)!=&quot;[&quot;)){oFullResponse=oFullResponse.substring(1,oFullResponse.length);}if(oFullResponse.length&gt;0){var arrayEnd=Math.max(oFullResponse.lastIndexOf(&quot;]&quot;),oFullResponse.lastIndexOf(&quot;}&quot;));oFullResponse=oFullR
 esponse.substring(0,arrayEnd+1);oFullResponse=eval(&quot;(&quot;+oFullResponse+&quot;)&quot;);}}}}}}catch(e1){}oFullResponse=this.doBeforeParseData(oRequest,oFullResponse,oCallback);oParsedResponse=this.parseArrayData(oRequest,oFullResponse);break;case DS.TYPE_JSON:if(xhr&amp;&amp;oRawResponse&amp;&amp;oRawResponse.responseText){oFullResponse=oRawResponse.responseText;}try{if(lang.isString(oFullResponse)){var parseArgs=[oFullResponse].concat(this.parseJSONArgs);if(lang.JSON){oFullResponse=lang.JSON.parse.apply(lang.JSON,parseArgs);}else{if(window.JSON&amp;&amp;JSON.parse){oFullResponse=JSON.parse.apply(JSON,parseArgs);}else{if(oFullResponse.parseJSON){oFullResponse=oFullResponse.parseJSON.apply(oFullResponse,parseArgs.slice(1));}else{while(oFullResponse.length&gt;0&amp;&amp;(oFullResponse.charAt(0)!=&quot;{&quot;)&amp;&amp;(oFullResponse.charAt(0)!=&quot;[&quot;)){oFullResponse=oFullResponse.substring(1,oFullResponse.length);}if(oFullResponse.length&gt;0){var objEnd=Math.max
 (oFullResponse.lastIndexOf(&quot;]&quot;),oFullResponse.lastIndexOf(&quot;}&quot;));oFullResponse=oFullResponse.substring(0,objEnd+1);oFullResponse=eval(&quot;(&quot;+oFullResponse+&quot;)&quot;);}}}}}}catch(e){}oFullResponse=this.doBeforeParseData(oRequest,oFullResponse,oCallback);oParsedResponse=this.parseJSONData(oRequest,oFullResponse);break;case DS.TYPE_HTMLTABLE:if(xhr&amp;&amp;oRawResponse.responseText){var el=document.createElement(&quot;div&quot;);el.innerHTML=oRawResponse.responseText;oFullResponse=el.getElementsByTagName(&quot;table&quot;)[0];}oFullResponse=this.doBeforeParseData(oRequest,oFullResponse,oCallback);oParsedResponse=this.parseHTMLTableData(oRequest,oFullResponse);break;case DS.TYPE_XML:if(xhr&amp;&amp;oRawResponse.responseXML){oFullResponse=oRawResponse.responseXML;}oFullResponse=this.doBeforeParseData(oRequest,oFullResponse,oCallback);oParsedResponse=this.parseXMLData(oRequest,oFullResponse);break;case DS.TYPE_TEXT:if(xhr&amp;&amp;lang.isString(oRawR
 esponse.responseText)){oFullResponse=oRawResponse.responseText;}oFullResponse=this.doBeforeParseData(oRequest,oFullResponse,oCallback);oParsedResponse=this.parseTextData(oRequest,oFullResponse);break;default:oFullResponse=this.doBeforeParseData(oRequest,oFullResponse,oCallback);oParsedResponse=this.parseData(oRequest,oFullResponse);break;}oParsedResponse=oParsedResponse||{};if(!oParsedResponse.results){oParsedResponse.results=[];}if(!oParsedResponse.meta){oParsedResponse.meta={};}if(!oParsedResponse.error){oParsedResponse=this.doBeforeCallback(oRequest,oFullResponse,oParsedResponse,oCallback);this.fireEvent(&quot;responseParseEvent&quot;,{request:oRequest,response:oParsedResponse,callback:oCallback,caller:oCaller});this.addToCache(oRequest,oParsedResponse);}else{oParsedResponse.error=true;this.fireEvent(&quot;dataErrorEvent&quot;,{request:oRequest,response:oRawResponse,callback:oCallback,caller:oCaller,message:DS.ERROR_DATANULL});}oParsedResponse.tId=tId;DS.issueCallback(oCa
 llback,[oRequest,oParsedResponse],oParsedResponse.error,oCaller);},doBeforeParseData:function(oRequest,oFullResponse,oCallback){return oFullResponse;},doBeforeCallback:function(oRequest,oFullResponse,oParsedResponse,oCallback){return oParsedResponse;},parseData:function(oRequest,oFullResponse){if(lang.isValue(oFullResponse)){var oParsedResponse={results:oFullResponse,meta:{}};return oParsedResponse;}return null;},parseArrayData:function(oRequest,oFullResponse){if(lang.isArray(oFullResponse)){var results=[],i,j,rec,field,data;if(lang.isArray(this.responseSchema.fields)){var fields=this.responseSchema.fields;for(i=fields.length-1;i&gt;=0;--i){if(typeof fields[i]!==&quot;object&quot;){fields[i]={key:fields[i]};}}var parsers={},p;for(i=fields.length-1;i&gt;=0;--i){p=(typeof fields[i].parser===&quot;function&quot;?fields[i].parser:DS.Parser[fields[i].parser+&quot;&quot;])||fields[i].converter;if(p){parsers[fields[i].key]=p;}}var arrType=lang.isArray(oFullResponse[0]);for(i=oFullR
 esponse.length-1;i&gt;-1;i--){var oResult={};rec=oFullResponse[i];if(typeof rec===&quot;object&quot;){for(j=fields.length-1;j&gt;-1;j--){field=fields[j];data=arrType?rec[j]:rec[field.key];if(parsers[field.key]){data=parsers[field.key].call(this,data);}if(data===undefined){data=null;}oResult[field.key]=data;}}else{if(lang.isString(rec)){for(j=fields.length-1;j&gt;-1;j--){field=fields[j];data=rec;if(parsers[field.key]){data=parsers[field.key].call(this,data);}if(data===undefined){data=null;}oResult[field.key]=data;
+}}}results[i]=oResult;}}else{results=oFullResponse;}var oParsedResponse={results:results};return oParsedResponse;}return null;},parseTextData:function(oRequest,oFullResponse){if(lang.isString(oFullResponse)){if(lang.isString(this.responseSchema.recordDelim)&amp;&amp;lang.isString(this.responseSchema.fieldDelim)){var oParsedResponse={results:[]};var recDelim=this.responseSchema.recordDelim;var fieldDelim=this.responseSchema.fieldDelim;if(oFullResponse.length&gt;0){var newLength=oFullResponse.length-recDelim.length;if(oFullResponse.substr(newLength)==recDelim){oFullResponse=oFullResponse.substr(0,newLength);}if(oFullResponse.length&gt;0){var recordsarray=oFullResponse.split(recDelim);for(var i=0,len=recordsarray.length,recIdx=0;i&lt;len;++i){var bError=false,sRecord=recordsarray[i];if(lang.isString(sRecord)&amp;&amp;(sRecord.length&gt;0)){var fielddataarray=recordsarray[i].split(fieldDelim);var oResult={};if(lang.isArray(this.responseSchema.fields)){var fields=this.responseSch
 ema.fields;for(var j=fields.length-1;j&gt;-1;j--){try{var data=fielddataarray[j];if(lang.isString(data)){if(data.charAt(0)=='&quot;'){data=data.substr(1);}if(data.charAt(data.length-1)=='&quot;'){data=data.substr(0,data.length-1);}var field=fields[j];var key=(lang.isValue(field.key))?field.key:field;if(!field.parser&amp;&amp;field.converter){field.parser=field.converter;}var parser=(typeof field.parser===&quot;function&quot;)?field.parser:DS.Parser[field.parser+&quot;&quot;];if(parser){data=parser.call(this,data);}if(data===undefined){data=null;}oResult[key]=data;}else{bError=true;}}catch(e){bError=true;}}}else{oResult=fielddataarray;}if(!bError){oParsedResponse.results[recIdx++]=oResult;}}}}}return oParsedResponse;}}return null;},parseXMLResult:function(result){var oResult={},schema=this.responseSchema;try{for(var m=schema.fields.length-1;m&gt;=0;m--){var field=schema.fields[m];var key=(lang.isValue(field.key))?field.key:field;var data=null;if(this.useXPath){data=YAHOO.util
 .DataSource._getLocationValue(field,result);}else{var xmlAttr=result.attributes.getNamedItem(key);if(xmlAttr){data=xmlAttr.value;}else{var xmlNode=result.getElementsByTagName(key);if(xmlNode&amp;&amp;xmlNode.item(0)){var item=xmlNode.item(0);data=(item)?((item.text)?item.text:(item.textContent)?item.textContent:null):null;if(!data){var datapieces=[];for(var j=0,len=item.childNodes.length;j&lt;len;j++){if(item.childNodes[j].nodeValue){datapieces[datapieces.length]=item.childNodes[j].nodeValue;}}if(datapieces.length&gt;0){data=datapieces.join(&quot;&quot;);}}}}}if(data===null){data=&quot;&quot;;}if(!field.parser&amp;&amp;field.converter){field.parser=field.converter;}var parser=(typeof field.parser===&quot;function&quot;)?field.parser:DS.Parser[field.parser+&quot;&quot;];if(parser){data=parser.call(this,data);}if(data===undefined){data=null;}oResult[key]=data;}}catch(e){}return oResult;},parseXMLData:function(oRequest,oFullResponse){var bError=false,schema=this.responseSchema,
 oParsedResponse={meta:{}},xmlList=null,metaNode=schema.metaNode,metaLocators=schema.metaFields||{},i,k,loc,v;try{if(this.useXPath){for(k in metaLocators){oParsedResponse.meta[k]=YAHOO.util.DataSource._getLocationValue(metaLocators[k],oFullResponse);}}else{metaNode=metaNode?oFullResponse.getElementsByTagName(metaNode)[0]:oFullResponse;if(metaNode){for(k in metaLocators){if(lang.hasOwnProperty(metaLocators,k)){loc=metaLocators[k];v=metaNode.getElementsByTagName(loc)[0];if(v){v=v.firstChild.nodeValue;}else{v=metaNode.attributes.getNamedItem(loc);if(v){v=v.value;}}if(lang.isValue(v)){oParsedResponse.meta[k]=v;}}}}}xmlList=(schema.resultNode)?oFullResponse.getElementsByTagName(schema.resultNode):null;}catch(e){}if(!xmlList||!lang.isArray(schema.fields)){bError=true;}else{oParsedResponse.results=[];for(i=xmlList.length-1;i&gt;=0;--i){var oResult=this.parseXMLResult(xmlList.item(i));oParsedResponse.results[i]=oResult;}}if(bError){oParsedResponse.error=true;}else{}return oParsedResp
 onse;},parseJSONData:function(oRequest,oFullResponse){var oParsedResponse={results:[],meta:{}};if(lang.isObject(oFullResponse)&amp;&amp;this.responseSchema.resultsList){var schema=this.responseSchema,fields=schema.fields,resultsList=oFullResponse,results=[],metaFields=schema.metaFields||{},fieldParsers=[],fieldPaths=[],simpleFields=[],bError=false,i,len,j,v,key,parser,path;var buildPath=function(needle){var path=null,keys=[],i=0;if(needle){needle=needle.replace(/\[(['&quot;])(.*?)\1\]/g,function(x,$1,$2){keys[i]=$2;return&quot;.@&quot;+(i++);}).replace(/\[(\d+)\]/g,function(x,$1){keys[i]=parseInt($1,10)|0;return&quot;.@&quot;+(i++);}).replace(/^\./,&quot;&quot;);if(!/[^\w\.\$@]/.test(needle)){path=needle.split(&quot;.&quot;);for(i=path.length-1;i&gt;=0;--i){if(path[i].charAt(0)===&quot;@&quot;){path[i]=keys[parseInt(path[i].substr(1),10)];}}}else{}}return path;};var walkPath=function(path,origin){var v=origin,i=0,len=path.length;for(;i&lt;len&amp;&amp;v;++i){v=v[path[i]];}re
 turn v;};path=buildPath(schema.resultsList);if(path){resultsList=walkPath(path,oFullResponse);if(resultsList===undefined){bError=true;}}else{bError=true;}if(!resultsList){resultsList=[];}if(!lang.isArray(resultsList)){resultsList=[resultsList];}if(!bError){if(schema.fields){var field;for(i=0,len=fields.length;i&lt;len;i++){field=fields[i];key=field.key||field;parser=((typeof field.parser===&quot;function&quot;)?field.parser:DS.Parser[field.parser+&quot;&quot;])||field.converter;path=buildPath(key);if(parser){fieldParsers[fieldParsers.length]={key:key,parser:parser};}if(path){if(path.length&gt;1){fieldPaths[fieldPaths.length]={key:key,path:path};}else{simpleFields[simpleFields.length]={key:key,path:path[0]};}}else{}}for(i=resultsList.length-1;i&gt;=0;--i){var r=resultsList[i],rec={};if(r){for(j=simpleFields.length-1;j&gt;=0;--j){rec[simpleFields[j].key]=(r[simpleFields[j].path]!==undefined)?r[simpleFields[j].path]:r[j];}for(j=fieldPaths.length-1;j&gt;=0;--j){rec[fieldPaths[j]
 .key]=walkPath(fieldPaths[j].path,r);}for(j=fieldParsers.length-1;j&gt;=0;--j){var p=fieldParsers[j].key;rec[p]=fieldParsers[j].parser.call(this,rec[p]);if(rec[p]===undefined){rec[p]=null;}}}results[i]=rec;}}else{results=resultsList;}for(key in metaFields){if(lang.hasOwnProperty(metaFields,key)){path=buildPath(metaFields[key]);
+if(path){v=walkPath(path,oFullResponse);oParsedResponse.meta[key]=v;}}}}else{oParsedResponse.error=true;}oParsedResponse.results=results;}else{oParsedResponse.error=true;}return oParsedResponse;},parseHTMLTableData:function(oRequest,oFullResponse){var bError=false;var elTable=oFullResponse;var fields=this.responseSchema.fields;var oParsedResponse={results:[]};if(lang.isArray(fields)){for(var i=0;i&lt;elTable.tBodies.length;i++){var elTbody=elTable.tBodies[i];for(var j=elTbody.rows.length-1;j&gt;-1;j--){var elRow=elTbody.rows[j];var oResult={};for(var k=fields.length-1;k&gt;-1;k--){var field=fields[k];var key=(lang.isValue(field.key))?field.key:field;var data=elRow.cells[k].innerHTML;if(!field.parser&amp;&amp;field.converter){field.parser=field.converter;}var parser=(typeof field.parser===&quot;function&quot;)?field.parser:DS.Parser[field.parser+&quot;&quot;];if(parser){data=parser.call(this,data);}if(data===undefined){data=null;}oResult[key]=data;}oParsedResponse.results[j]=
 oResult;}}}else{bError=true;}if(bError){oParsedResponse.error=true;}else{}return oParsedResponse;}};lang.augmentProto(DS,util.EventProvider);util.LocalDataSource=function(oLiveData,oConfigs){this.dataType=DS.TYPE_LOCAL;if(oLiveData){if(YAHOO.lang.isArray(oLiveData)){this.responseType=DS.TYPE_JSARRAY;}else{if(oLiveData.nodeType&amp;&amp;oLiveData.nodeType==9){this.responseType=DS.TYPE_XML;}else{if(oLiveData.nodeName&amp;&amp;(oLiveData.nodeName.toLowerCase()==&quot;table&quot;)){this.responseType=DS.TYPE_HTMLTABLE;oLiveData=oLiveData.cloneNode(true);}else{if(YAHOO.lang.isString(oLiveData)){this.responseType=DS.TYPE_TEXT;}else{if(YAHOO.lang.isObject(oLiveData)){this.responseType=DS.TYPE_JSON;}}}}}}else{oLiveData=[];this.responseType=DS.TYPE_JSARRAY;}util.LocalDataSource.superclass.constructor.call(this,oLiveData,oConfigs);};lang.extend(util.LocalDataSource,DS);lang.augmentObject(util.LocalDataSource,DS);util.FunctionDataSource=function(oLiveData,oConfigs){this.dataType=DS.TYPE
 _JSFUNCTION;oLiveData=oLiveData||function(){};util.FunctionDataSource.superclass.constructor.call(this,oLiveData,oConfigs);};lang.extend(util.FunctionDataSource,DS,{scope:null,makeConnection:function(oRequest,oCallback,oCaller){var tId=DS._nTransactionId++;this.fireEvent(&quot;requestEvent&quot;,{tId:tId,request:oRequest,callback:oCallback,caller:oCaller});var oRawResponse=(this.scope)?this.liveData.call(this.scope,oRequest,this,oCallback):this.liveData(oRequest,oCallback);if(this.responseType===DS.TYPE_UNKNOWN){if(YAHOO.lang.isArray(oRawResponse)){this.responseType=DS.TYPE_JSARRAY;}else{if(oRawResponse&amp;&amp;oRawResponse.nodeType&amp;&amp;oRawResponse.nodeType==9){this.responseType=DS.TYPE_XML;}else{if(oRawResponse&amp;&amp;oRawResponse.nodeName&amp;&amp;(oRawResponse.nodeName.toLowerCase()==&quot;table&quot;)){this.responseType=DS.TYPE_HTMLTABLE;}else{if(YAHOO.lang.isObject(oRawResponse)){this.responseType=DS.TYPE_JSON;}else{if(YAHOO.lang.isString(oRawResponse)){this.re
 sponseType=DS.TYPE_TEXT;}}}}}}this.handleResponse(oRequest,oRawResponse,oCallback,oCaller,tId);return tId;}});lang.augmentObject(util.FunctionDataSource,DS);util.ScriptNodeDataSource=function(oLiveData,oConfigs){this.dataType=DS.TYPE_SCRIPTNODE;oLiveData=oLiveData||&quot;&quot;;util.ScriptNodeDataSource.superclass.constructor.call(this,oLiveData,oConfigs);};lang.extend(util.ScriptNodeDataSource,DS,{getUtility:util.Get,asyncMode:&quot;allowAll&quot;,scriptCallbackParam:&quot;callback&quot;,generateRequestCallback:function(id){return&quot;&amp;&quot;+this.scriptCallbackParam+&quot;=YAHOO.util.ScriptNodeDataSource.callbacks[&quot;+id+&quot;]&quot;;},doBeforeGetScriptNode:function(sUri){return sUri;},makeConnection:function(oRequest,oCallback,oCaller){var tId=DS._nTransactionId++;this.fireEvent(&quot;requestEvent&quot;,{tId:tId,request:oRequest,callback:oCallback,caller:oCaller});if(util.ScriptNodeDataSource._nPending===0){util.ScriptNodeDataSource.callbacks=[];util.ScriptNodeDa
 taSource._nId=0;}var id=util.ScriptNodeDataSource._nId;util.ScriptNodeDataSource._nId++;var oSelf=this;util.ScriptNodeDataSource.callbacks[id]=function(oRawResponse){if((oSelf.asyncMode!==&quot;ignoreStaleResponses&quot;)||(id===util.ScriptNodeDataSource.callbacks.length-1)){if(oSelf.responseType===DS.TYPE_UNKNOWN){if(YAHOO.lang.isArray(oRawResponse)){oSelf.responseType=DS.TYPE_JSARRAY;}else{if(oRawResponse.nodeType&amp;&amp;oRawResponse.nodeType==9){oSelf.responseType=DS.TYPE_XML;}else{if(oRawResponse.nodeName&amp;&amp;(oRawResponse.nodeName.toLowerCase()==&quot;table&quot;)){oSelf.responseType=DS.TYPE_HTMLTABLE;}else{if(YAHOO.lang.isObject(oRawResponse)){oSelf.responseType=DS.TYPE_JSON;}else{if(YAHOO.lang.isString(oRawResponse)){oSelf.responseType=DS.TYPE_TEXT;}}}}}}oSelf.handleResponse(oRequest,oRawResponse,oCallback,oCaller,tId);}else{}delete util.ScriptNodeDataSource.callbacks[id];};util.ScriptNodeDataSource._nPending++;var sUri=this.liveData+oRequest+this.generateReque
 stCallback(id);sUri=this.doBeforeGetScriptNode(sUri);this.getUtility.script(sUri,{autopurge:true,onsuccess:util.ScriptNodeDataSource._bumpPendingDown,onfail:util.ScriptNodeDataSource._bumpPendingDown});return tId;}});lang.augmentObject(util.ScriptNodeDataSource,DS);lang.augmentObject(util.ScriptNodeDataSource,{_nId:0,_nPending:0,callbacks:[]});util.XHRDataSource=function(oLiveData,oConfigs){this.dataType=DS.TYPE_XHR;this.connMgr=this.connMgr||util.Connect;oLiveData=oLiveData||&quot;&quot;;util.XHRDataSource.superclass.constructor.call(this,oLiveData,oConfigs);};lang.extend(util.XHRDataSource,DS,{connMgr:null,connXhrMode:&quot;allowAll&quot;,connMethodPost:false,connTimeout:0,makeConnection:function(oRequest,oCallback,oCaller){var oRawResponse=null;var tId=DS._nTransactionId++;this.fireEvent(&quot;requestEvent&quot;,{tId:tId,request:oRequest,callback:oCallback,caller:oCaller});var oSelf=this;var oConnMgr=this.connMgr;var oQueue=this._oQueue;var _xhrSuccess=function(oResponse)
 {if(oResponse&amp;&amp;(this.connXhrMode==&quot;ignoreStaleResponses&quot;)&amp;&amp;(oResponse.tId!=oQueue.conn.tId)){return null;}else{if(!oResponse){this.fireEvent(&quot;dataErrorEvent&quot;,{request:oRequest,response:null,callback:oCallback,caller:oCaller,message:DS.ERROR_DATANULL});DS.issueCallback(oCallback,[oRequest,{error:true}],true,oCaller);return null;
+}else{if(this.responseType===DS.TYPE_UNKNOWN){var ctype=(oResponse.getResponseHeader)?oResponse.getResponseHeader[&quot;Content-Type&quot;]:null;if(ctype){if(ctype.indexOf(&quot;text/xml&quot;)&gt;-1){this.responseType=DS.TYPE_XML;}else{if(ctype.indexOf(&quot;application/json&quot;)&gt;-1){this.responseType=DS.TYPE_JSON;}else{if(ctype.indexOf(&quot;text/plain&quot;)&gt;-1){this.responseType=DS.TYPE_TEXT;}}}}}this.handleResponse(oRequest,oResponse,oCallback,oCaller,tId);}}};var _xhrFailure=function(oResponse){this.fireEvent(&quot;dataErrorEvent&quot;,{request:oRequest,response:oResponse,callback:oCallback,caller:oCaller,message:DS.ERROR_DATAINVALID});if(lang.isString(this.liveData)&amp;&amp;lang.isString(oRequest)&amp;&amp;(this.liveData.lastIndexOf(&quot;?&quot;)!==this.liveData.length-1)&amp;&amp;(oRequest.indexOf(&quot;?&quot;)!==0)){}oResponse=oResponse||{};oResponse.error=true;DS.issueCallback(oCallback,[oRequest,oResponse],true,oCaller);return null;};var _xhrCallback={s
 uccess:_xhrSuccess,failure:_xhrFailure,scope:this};if(lang.isNumber(this.connTimeout)){_xhrCallback.timeout=this.connTimeout;}if(this.connXhrMode==&quot;cancelStaleRequests&quot;){if(oQueue.conn){if(oConnMgr.abort){oConnMgr.abort(oQueue.conn);oQueue.conn=null;}else{}}}if(oConnMgr&amp;&amp;oConnMgr.asyncRequest){var sLiveData=this.liveData;var isPost=this.connMethodPost;var sMethod=(isPost)?&quot;POST&quot;:&quot;GET&quot;;var sUri=(isPost||!lang.isValue(oRequest))?sLiveData:sLiveData+oRequest;var sRequest=(isPost)?oRequest:null;if(this.connXhrMode!=&quot;queueRequests&quot;){oQueue.conn=oConnMgr.asyncRequest(sMethod,sUri,_xhrCallback,sRequest);}else{if(oQueue.conn){var allRequests=oQueue.requests;allRequests.push({request:oRequest,callback:_xhrCallback});if(!oQueue.interval){oQueue.interval=setInterval(function(){if(oConnMgr.isCallInProgress(oQueue.conn)){return;}else{if(allRequests.length&gt;0){sUri=(isPost||!lang.isValue(allRequests[0].request))?sLiveData:sLiveData+allRequ
 ests[0].request;sRequest=(isPost)?allRequests[0].request:null;oQueue.conn=oConnMgr.asyncRequest(sMethod,sUri,allRequests[0].callback,sRequest);allRequests.shift();}else{clearInterval(oQueue.interval);oQueue.interval=null;}}},50);}}else{oQueue.conn=oConnMgr.asyncRequest(sMethod,sUri,_xhrCallback,sRequest);}}}else{DS.issueCallback(oCallback,[oRequest,{error:true}],true,oCaller);}return tId;}});lang.augmentObject(util.XHRDataSource,DS);util.DataSource=function(oLiveData,oConfigs){oConfigs=oConfigs||{};var dataType=oConfigs.dataType;if(dataType){if(dataType==DS.TYPE_LOCAL){return new util.LocalDataSource(oLiveData,oConfigs);}else{if(dataType==DS.TYPE_XHR){return new util.XHRDataSource(oLiveData,oConfigs);}else{if(dataType==DS.TYPE_SCRIPTNODE){return new util.ScriptNodeDataSource(oLiveData,oConfigs);}else{if(dataType==DS.TYPE_JSFUNCTION){return new util.FunctionDataSource(oLiveData,oConfigs);}}}}}if(YAHOO.lang.isString(oLiveData)){return new util.XHRDataSource(oLiveData,oConfigs)
 ;}else{if(YAHOO.lang.isFunction(oLiveData)){return new util.FunctionDataSource(oLiveData,oConfigs);}else{return new util.LocalDataSource(oLiveData,oConfigs);}}};lang.augmentObject(util.DataSource,DS);})();YAHOO.util.Number={format:function(e,k){if(e===&quot;&quot;||e===null||!isFinite(e)){return&quot;&quot;;}e=+e;k=YAHOO.lang.merge(YAHOO.util.Number.format.defaults,(k||{}));var j=e+&quot;&quot;,l=Math.abs(e),b=k.decimalPlaces||0,r=k.thousandsSeparator,f=k.negativeFormat||(&quot;-&quot;+k.format),q,p,g,h;if(f.indexOf(&quot;#&quot;)&gt;-1){f=f.replace(/#/,k.format);}if(b&lt;0){q=l-(l%1)+&quot;&quot;;g=q.length+b;if(g&gt;0){q=Number(&quot;.&quot;+q).toFixed(g).slice(2)+new Array(q.length-g+1).join(&quot;0&quot;);}else{q=&quot;0&quot;;}}else{var a=l+&quot;&quot;;if(b&gt;0||a.indexOf(&quot;.&quot;)&gt;0){var d=Math.pow(10,b);q=Math.round(l*d)/d+&quot;&quot;;var c=q.indexOf(&quot;.&quot;),m,o;if(c&lt;0){m=b;o=(Math.pow(10,m)+&quot;&quot;).substring(1);if(b&gt;0){q=q+&quot;.&quot;+
 o;}}else{m=b-(q.length-c-1);o=(Math.pow(10,m)+&quot;&quot;).substring(1);q=q+o;}}else{q=l.toFixed(b)+&quot;&quot;;}}p=q.split(/\D/);if(l&gt;=1000){g=p[0].length%3||3;p[0]=p[0].slice(0,g)+p[0].slice(g).replace(/(\d{3})/g,r+&quot;$1&quot;);}return YAHOO.util.Number.format._applyFormat((e&lt;0?f:k.format),p.join(k.decimalSeparator),k);}};YAHOO.util.Number.format.defaults={format:&quot;{prefix}{number}{suffix}&quot;,negativeFormat:null,decimalSeparator:&quot;.&quot;,decimalPlaces:null,thousandsSeparator:&quot;&quot;};YAHOO.util.Number.format._applyFormat=function(a,b,c){return a.replace(/\{(\w+)\}/g,function(d,e){return e===&quot;number&quot;?b:e in c?c[e]:&quot;&quot;;});};(function(){var a=function(c,e,d){if(typeof d===&quot;undefined&quot;){d=10;}for(;parseInt(c,10)&lt;d&amp;&amp;d&gt;1;d/=10){c=e.toString()+c;}return c.toString();};var b={formats:{a:function(e,c){return c.a[e.getDay()];},A:function(e,c){return c.A[e.getDay()];},b:function(e,c){return c.b[e.getMonth()];},B:fu
 nction(e,c){return c.B[e.getMonth()];},C:function(c){return a(parseInt(c.getFullYear()/100,10),0);},d:[&quot;getDate&quot;,&quot;0&quot;],e:[&quot;getDate&quot;,&quot; &quot;],g:function(c){return a(parseInt(b.formats.G(c)%100,10),0);},G:function(f){var g=f.getFullYear();var e=parseInt(b.formats.V(f),10);var c=parseInt(b.formats.W(f),10);if(c&gt;e){g++;}else{if(c===0&amp;&amp;e&gt;=52){g--;}}return g;},H:[&quot;getHours&quot;,&quot;0&quot;],I:function(e){var c=e.getHours()%12;return a(c===0?12:c,0);},j:function(h){var g=new Date(&quot;&quot;+h.getFullYear()+&quot;/1/1 GMT&quot;);var e=new Date(&quot;&quot;+h.getFullYear()+&quot;/&quot;+(h.getMonth()+1)+&quot;/&quot;+h.getDate()+&quot; GMT&quot;);var c=e-g;var f=parseInt(c/60000/60/24,10)+1;return a(f,0,100);},k:[&quot;getHours&quot;,&quot; &quot;],l:function(e){var c=e.getHours()%12;return a(c===0?12:c,&quot; &quot;);},m:function(c){return a(c.getMonth()+1,0);},M:[&quot;getMinutes&quot;,&quot;0&quot;],p:function(e,c){return 
 c.p[e.getHours()&gt;=12?1:0];},P:function(e,c){return c.P[e.getHours()&gt;=12?1:0];},s:function(e,c){return parseInt(e.getTime()/1000,10);},S:[&quot;getSeconds&quot;,&quot;0&quot;],u:function(c){var e=c.getDay();return e===0?7:e;},U:function(g){var c=parseInt(b.formats.j(g),10);var f=6-g.getDay();var e=parseInt((c+f)/7,10);return a(e,0);},V:function(g){var f=parseInt(b.formats.W(g),10);var c=(new Date(&quot;&quot;+g.getFullYear()+&quot;/1/1&quot;)).getDay();var e=f+(c&gt;4||c&lt;=1?0:1);if(e===53&amp;&amp;(new Date(&quot;&quot;+g.getFullYear()+&quot;/12/31&quot;)).getDay()&lt;4){e=1;}else{if(e===0){e=b.formats.V(new Date(&quot;&quot;+(g.getFullYear()-1)+&quot;/12/31&quot;));}}return a(e,0);},w:&quot;getDay&quot;,W:function(g){var c=parseInt(b.formats.j(g),10);var f=7-b.formats.u(g);var e=parseInt((c+f)/7,10);
+return a(e,0,10);},y:function(c){return a(c.getFullYear()%100,0);},Y:&quot;getFullYear&quot;,z:function(f){var e=f.getTimezoneOffset();var c=a(parseInt(Math.abs(e/60),10),0);var g=a(Math.abs(e%60),0);return(e&gt;0?&quot;-&quot;:&quot;+&quot;)+c+g;},Z:function(c){var e=c.toString().replace(/^.*:\d\d( GMT[+-]\d+)? \(?([A-Za-z ]+)\)?\d*$/,&quot;$2&quot;).replace(/[a-z ]/g,&quot;&quot;);if(e.length&gt;4){e=b.formats.z(c);}return e;},&quot;%&quot;:function(c){return&quot;%&quot;;}},aggregates:{c:&quot;locale&quot;,D:&quot;%m/%d/%y&quot;,F:&quot;%Y-%m-%d&quot;,h:&quot;%b&quot;,n:&quot;\n&quot;,r:&quot;locale&quot;,R:&quot;%H:%M&quot;,t:&quot;\t&quot;,T:&quot;%H:%M:%S&quot;,x:&quot;locale&quot;,X:&quot;locale&quot;},format:function(g,f,d){f=f||{};if(!(g instanceof Date)){return YAHOO.lang.isValue(g)?g:&quot;&quot;;}var h=f.format||&quot;%m/%d/%Y&quot;;if(h===&quot;YYYY/MM/DD&quot;){h=&quot;%Y/%m/%d&quot;;}else{if(h===&quot;DD/MM/YYYY&quot;){h=&quot;%d/%m/%Y&quot;;}else{if(h===&quot
 ;MM/DD/YYYY&quot;){h=&quot;%m/%d/%Y&quot;;}}}d=d||&quot;en&quot;;if(!(d in YAHOO.util.DateLocale)){if(d.replace(/-[a-zA-Z]+$/,&quot;&quot;) in YAHOO.util.DateLocale){d=d.replace(/-[a-zA-Z]+$/,&quot;&quot;);}else{d=&quot;en&quot;;}}var j=YAHOO.util.DateLocale[d];var c=function(l,k){var m=b.aggregates[k];return(m===&quot;locale&quot;?j[k]:m);};var e=function(l,k){var m=b.formats[k];if(typeof m===&quot;string&quot;){return g[m]();}else{if(typeof m===&quot;function&quot;){return m.call(g,g,j);}else{if(typeof m===&quot;object&quot;&amp;&amp;typeof m[0]===&quot;string&quot;){return a(g[m[0]](),m[1]);}else{return k;}}}};while(h.match(/%[cDFhnrRtTxX]/)){h=h.replace(/%([cDFhnrRtTxX])/g,c);}var i=h.replace(/%([aAbBCdegGHIjklmMpPsSuUVwWyYzZ%])/g,e);c=e=undefined;return i;}};YAHOO.namespace(&quot;YAHOO.util&quot;);YAHOO.util.Date=b;YAHOO.util.DateLocale={a:[&quot;Sun&quot;,&quot;Mon&quot;,&quot;Tue&quot;,&quot;Wed&quot;,&quot;Thu&quot;,&quot;Fri&quot;,&quot;Sat&quot;],A:[&quot;Sunday&qu
 ot;,&quot;Monday&quot;,&quot;Tuesday&quot;,&quot;Wednesday&quot;,&quot;Thursday&quot;,&quot;Friday&quot;,&quot;Saturday&quot;],b:[&quot;Jan&quot;,&quot;Feb&quot;,&quot;Mar&quot;,&quot;Apr&quot;,&quot;May&quot;,&quot;Jun&quot;,&quot;Jul&quot;,&quot;Aug&quot;,&quot;Sep&quot;,&quot;Oct&quot;,&quot;Nov&quot;,&quot;Dec&quot;],B:[&quot;January&quot;,&quot;February&quot;,&quot;March&quot;,&quot;April&quot;,&quot;May&quot;,&quot;June&quot;,&quot;July&quot;,&quot;August&quot;,&quot;September&quot;,&quot;October&quot;,&quot;November&quot;,&quot;December&quot;],c:&quot;%a %d %b %Y %T %Z&quot;,p:[&quot;AM&quot;,&quot;PM&quot;],P:[&quot;am&quot;,&quot;pm&quot;],r:&quot;%I:%M:%S %p&quot;,x:&quot;%d/%m/%y&quot;,X:&quot;%T&quot;};YAHOO.util.DateLocale[&quot;en&quot;]=YAHOO.lang.merge(YAHOO.util.DateLocale,{});YAHOO.util.DateLocale[&quot;en-US&quot;]=YAHOO.lang.merge(YAHOO.util.DateLocale[&quot;en&quot;],{c:&quot;%a %d %b %Y %I:%M:%S %p %Z&quot;,x:&quot;%m/%d/%Y&quot;,X:&quot;%I:%M:%S %p&quo
 t;});YAHOO.util.DateLocale[&quot;en-GB&quot;]=YAHOO.lang.merge(YAHOO.util.DateLocale[&quot;en&quot;],{r:&quot;%l:%M:%S %P %Z&quot;});YAHOO.util.DateLocale[&quot;en-AU&quot;]=YAHOO.lang.merge(YAHOO.util.DateLocale[&quot;en&quot;]);})();YAHOO.register(&quot;datasource&quot;,YAHOO.util.DataSource,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuidatatabledatatableminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/datatable/datatable-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/datatable/datatable-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/datatable/datatable-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,33 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+YAHOO.util.Chain=function(){this.q=[].slice.call(arguments);this.createEvent(&quot;end&quot;);};YAHOO.util.Chain.prototype={id:0,run:function(){var g=this.q[0],d;if(!g){this.fireEvent(&quot;end&quot;);return this;}else{if(this.id){return this;}}d=g.method||g;if(typeof d===&quot;function&quot;){var f=g.scope||{},b=g.argument||[],a=g.timeout||0,e=this;if(!(b instanceof Array)){b=[b];}if(a&lt;0){this.id=a;if(g.until){for(;!g.until();){d.apply(f,b);}}else{if(g.iterations){for(;g.iterations--&gt;0;){d.apply(f,b);}}else{d.apply(f,b);}}this.q.shift();this.id=0;return this.run();}else{if(g.until){if(g.until()){this.q.shift();return this.run();}}else{if(!g.iterations||!--g.iterations){this.q.shift();}}this.id=setTimeout(function(){d.apply(f,b);if(e.id){e.id=0;e.run();}},a);}}return this;},add:function(a){this.q.push(a);return this;},pause:function(){if(this.id&gt;0){clearTimeout(this.id);}this.id=0;return this;},stop:function(){this.pause();this.q=[];return this;}};YAHOO.lang.augment
 Proto(YAHOO.util.Chain,YAHOO.util.EventProvider);(function(){var a=YAHOO.util.Event,c=YAHOO.lang,b=[],d=function(h,e,f){var g;if(!h||h===f){g=false;}else{g=YAHOO.util.Selector.test(h,e)?h:d(h.parentNode,e,f);}return g;};c.augmentObject(a,{_createDelegate:function(f,e,g,h){return function(i){var j=this,n=a.getTarget(i),l=e,p=(j.nodeType===9),q,k,o,m;if(c.isFunction(e)){q=e(n);}else{if(c.isString(e)){if(!p){o=j.id;if(!o){o=a.generateId(j);}m=(&quot;#&quot;+o+&quot; &quot;);l=(m+e).replace(/,/gi,(&quot;,&quot;+m));}if(YAHOO.util.Selector.test(n,l)){q=n;}else{if(YAHOO.util.Selector.test(n,((l.replace(/,/gi,&quot; *,&quot;))+&quot; *&quot;))){q=d(n,l,j);}}}}if(q){k=q;if(h){if(h===true){k=g;}else{k=h;}}return f.call(k,i,q,j,g);}};},delegate:function(f,j,l,g,h,i){var e=j,k,m;if(c.isString(g)&amp;&amp;!YAHOO.util.Selector){return false;}if(j==&quot;mouseenter&quot;||j==&quot;mouseleave&quot;){if(!a._createMouseDelegate){return false;}e=a._getType(j);k=a._createMouseDelegate(l,h,i);m
 =a._createDelegate(function(p,o,n){return k.call(o,p,n);},g,h,i);}else{m=a._createDelegate(l,g,h,i);}b.push([f,e,l,m]);return a.on(f,e,m);},removeDelegate:function(f,j,i){var k=j,h=false,g,e;if(j==&quot;mouseenter&quot;||j==&quot;mouseleave&quot;){k=a._getType(j);}g=a._getCacheIndex(b,f,k,i);if(g&gt;=0){e=b[g];}if(f&amp;&amp;e){h=a.removeListener(e[0],e[1],e[3]);if(h){delete b[g][2];delete b[g][3];b.splice(g,1);}}return h;}});}());(function(){var b=YAHOO.util.Event,g=YAHOO.lang,e=b.addListener,f=b.removeListener,c=b.getListeners,d=[],h={mouseenter:&quot;mouseover&quot;,mouseleave:&quot;mouseout&quot;},a=function(n,m,l){var j=b._getCacheIndex(d,n,m,l),i,k;if(j&gt;=0){i=d[j];}if(n&amp;&amp;i){k=f.call(b,i[0],m,i[3]);if(k){delete d[j][2];delete d[j][3];d.splice(j,1);}}return k;};g.augmentObject(b._specialTypes,h);g.augmentObject(b,{_createMouseDelegate:function(i,j,k){return function(q,m){var p=this,l=b.getRelatedTarget(q),o,n;if(p!=l&amp;&amp;!YAHOO.util.Dom.isAncestor(p,l)){o
 =p;if(k){if(k===true){o=j;}else{o=k;}}n=[q,j];if(m){n.splice(1,0,p,m);}return i.apply(o,n);}};},addListener:function(m,l,k,n,o){var i,j;if(h[l]){i=b._createMouseDelegate(k,n,o);i.mouseDelegate=true;d.push([m,l,k,i]);j=e.call(b,m,l,i);}else{j=e.apply(b,arguments);}return j;},removeListener:function(l,k,j){var i;if(h[k]){i=a.apply(b,arguments);}else{i=f.apply(b,arguments);}return i;},getListeners:function(p,o){var n=[],r,m=(o===&quot;mouseover&quot;||o===&quot;mouseout&quot;),q,k,j;if(o&amp;&amp;(m||h[o])){r=c.call(b,p,this._getType(o));if(r){for(k=r.length-1;k&gt;-1;k--){j=r[k];q=j.fn.mouseDelegate;if((h[o]&amp;&amp;q)||(m&amp;&amp;!q)){n.push(j);}}}}else{n=c.apply(b,arguments);}return(n&amp;&amp;n.length)?n:null;}},true);b.on=b.addListener;}());YAHOO.register(&quot;event-mouseenter&quot;,YAHOO.util.Event,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});var Y=YAHOO,Y_DOM=YAHOO.util.Dom,EMPTY_ARRAY=[],Y_UA=Y.env.ua,Y_Lang=Y.lang,Y_DOC=document,Y_DOCUMENT_ELEMENT=Y_DOC.docum
 entElement,Y_DOM_inDoc=Y_DOM.inDocument,Y_mix=Y_Lang.augmentObject,Y_guid=Y_DOM.generateId,Y_getDoc=function(a){var b=Y_DOC;if(a){b=(a.nodeType===9)?a:a.ownerDocument||a.document||Y_DOC;}return b;},Y_Array=function(g,d){var c,b,h=d||0;try{return Array.prototype.slice.call(g,h);}catch(f){b=[];c=g.length;for(;h&lt;c;h++){b.push(g[h]);}return b;}},Y_DOM_allById=function(f,a){a=a||Y_DOC;var b=[],c=[],d,e;if(a.querySelectorAll){c=a.querySelectorAll('[id=&quot;'+f+'&quot;]');}else{if(a.all){b=a.all(f);if(b){if(b.nodeName){if(b.id===f){c.push(b);b=EMPTY_ARRAY;}else{b=[b];}}if(b.length){for(d=0;e=b[d++];){if(e.id===f||(e.attributes&amp;&amp;e.attributes.id&amp;&amp;e.attributes.id.value===f)){c.push(e);}}}}}else{c=[Y_getDoc(a).getElementById(f)];}}return c;};var COMPARE_DOCUMENT_POSITION=&quot;compareDocumentPosition&quot;,OWNER_DOCUMENT=&quot;ownerDocument&quot;,Selector={_foundCache:[],useNative:true,_compare:(&quot;sourceIndex&quot; in Y_DOCUMENT_ELEMENT)?function(f,e){var d=f.so
 urceIndex,c=e.sourceIndex;if(d===c){return 0;}else{if(d&gt;c){return 1;}}return -1;}:(Y_DOCUMENT_ELEMENT[COMPARE_DOCUMENT_POSITION]?function(b,a){if(b[COMPARE_DOCUMENT_POSITION](a)&amp;4){return -1;}else{return 1;}}:function(e,d){var c,a,b;if(e&amp;&amp;d){c=e[OWNER_DOCUMENT].createRange();c.setStart(e,0);a=d[OWNER_DOCUMENT].createRange();a.setStart(d,0);b=c.compareBoundaryPoints(1,a);}return b;}),_sort:function(a){if(a){a=Y_Array(a,0,true);if(a.sort){a.sort(Selector._compare);}}return a;},_deDupe:function(a){var b=[],c,d;for(c=0;(d=a[c++]);){if(!d._found){b[b.length]=d;d._found=true;}}for(c=0;(d=b[c++]);){d._found=null;d.removeAttribute(&quot;_found&quot;);}return b;},query:function(b,j,k,a){if(typeof j==&quot;string&quot;){j=Y_DOM.get(j);if(!j){return(k)?null:[];}}else{j=j||Y_DOC;}var f=[],c=(Selector.useNative&amp;&amp;Y_DOC.querySelector&amp;&amp;!a),e=[[b,j]],g,l,d,h=(c)?Selector._nativeQuery:Selector._bruteQuery;if(b&amp;&amp;h){if(!a&amp;&amp;(!c||j.tagName)){e=Select
 or._splitQueries(b,j);}for(d=0;(g=e[d++]);){l=h(g[0],g[1],k);if(!k){l=Y_Array(l,0,true);}if(l){f=f.concat(l);}}if(e.length&gt;1){f=Selector._sort(Selector._deDupe(f));}}Y.log(&quot;query: &quot;+b+&quot; returning: &quot;+f.length,&quot;info&quot;,&quot;Selector&quot;);return(k)?(f[0]||null):f;},_splitQueries:function(c,f){var b=c.split(&quot;,&quot;),d=[],g=&quot;&quot;,e,a;if(f){if(f.tagName){f.id=f.id||Y_guid();g='[id=&quot;'+f.id+'&quot;] ';}for(e=0,a=b.length;e&lt;a;++e){c=g+b[e];d.push([c,f]);}}return d;},_nativeQuery:function(a,b,c){if(Y_UA.webkit&amp;&amp;a.indexOf(&quot;:checked&quot;)&gt;-1&amp;&amp;(Selector.pseudos&amp;&amp;Selector.pseudos.checked)){return Selector.query(a,b,c,true);
+}try{return b[&quot;querySelector&quot;+(c?&quot;&quot;:&quot;All&quot;)](a);}catch(d){return Selector.query(a,b,c,true);}},filter:function(b,a){var c=[],d,e;if(b&amp;&amp;a){for(d=0;(e=b[d++]);){if(Selector.test(e,a)){c[c.length]=e;}}}else{Y.log(&quot;invalid filter input (nodes: &quot;+b+&quot;, selector: &quot;+a+&quot;)&quot;,&quot;warn&quot;,&quot;Selector&quot;);}return c;},test:function(c,d,k){var g=false,b=d.split(&quot;,&quot;),a=false,l,o,h,n,f,e,m;if(c&amp;&amp;c.tagName){if(!k&amp;&amp;!Y_DOM_inDoc(c)){l=c.parentNode;if(l){k=l;}else{n=c[OWNER_DOCUMENT].createDocumentFragment();n.appendChild(c);k=n;a=true;}}k=k||c[OWNER_DOCUMENT];if(!c.id){c.id=Y_guid();}for(f=0;(m=b[f++]);){m+='[id=&quot;'+c.id+'&quot;]';h=Selector.query(m,k);for(e=0;o=h[e++];){if(o===c){g=true;break;}}if(g){break;}}if(a){n.removeChild(c);}}return g;}};YAHOO.util.Selector=Selector;var PARENT_NODE=&quot;parentNode&quot;,TAG_NAME=&quot;tagName&quot;,ATTRIBUTES=&quot;attributes&quot;,COMBINATOR=&quo
 t;combinator&quot;,PSEUDOS=&quot;pseudos&quot;,SelectorCSS2={_reRegExpTokens:/([\^\$\?\[\]\*\+\-\.\(\)\|\\])/,SORT_RESULTS:true,_children:function(e,a){var b=e.children,d,c=[],f,g;if(e.children&amp;&amp;a&amp;&amp;e.children.tags){c=e.children.tags(a);}else{if((!b&amp;&amp;e[TAG_NAME])||(b&amp;&amp;a)){f=b||e.childNodes;b=[];for(d=0;(g=f[d++]);){if(g.tagName){if(!a||a===g.tagName){b.push(g);}}}}}return b||[];},_re:{attr:/(\[[^\]]*\])/g,esc:/\\[:\[\]\(\)#\.\'\&gt;+~&quot;]/gi,pseudos:/(\([^\)]*\))/g},shorthand:{&quot;\\#(-?[_a-z]+[-\\w\\uE000]*)&quot;:&quot;[id=$1]&quot;,&quot;\\.(-?[_a-z]+[-\\w\\uE000]*)&quot;:&quot;[className~=$1]&quot;},operators:{&quot;&quot;:function(b,a){return !!b.getAttribute(a);},&quot;~=&quot;:&quot;(?:^|\\s+){val}(?:\\s+|$)&quot;,&quot;|=&quot;:&quot;^{val}(?:-|$)&quot;},pseudos:{&quot;first-child&quot;:function(a){return Selector._children(a[PARENT_NODE])[0]===a;}},_bruteQuery:function(f,j,l){var g=[],a=[],i=Selector._tokenize(f),e=i[i.length-1],k
 =Y_getDoc(j),c,b,h,d;if(e){b=e.id;h=e.className;d=e.tagName||&quot;*&quot;;if(j.getElementsByTagName){if(b&amp;&amp;(j.all||(j.nodeType===9||Y_DOM_inDoc(j)))){a=Y_DOM_allById(b,j);}else{if(h){a=j.getElementsByClassName(h);}else{a=j.getElementsByTagName(d);}}}else{c=j.firstChild;while(c){if(c.tagName){a.push(c);}c=c.nextSilbing||c.firstChild;}}if(a.length){g=Selector._filterNodes(a,i,l);}}return g;},_filterNodes:function(l,f,h){var r=0,q,s=f.length,k=s-1,e=[],o=l[0],v=o,t=Selector.getters,d,p,c,g,a,m,b,u;for(r=0;(v=o=l[r++]);){k=s-1;g=null;testLoop:while(v&amp;&amp;v.tagName){c=f[k];b=c.tests;q=b.length;if(q&amp;&amp;!a){while((u=b[--q])){d=u[1];if(t[u[0]]){m=t[u[0]](v,u[0]);}else{m=v[u[0]];if(m===undefined&amp;&amp;v.getAttribute){m=v.getAttribute(u[0]);}}if((d===&quot;=&quot;&amp;&amp;m!==u[2])||(typeof d!==&quot;string&quot;&amp;&amp;d.test&amp;&amp;!d.test(m))||(!d.test&amp;&amp;typeof d===&quot;function&quot;&amp;&amp;!d(v,u[0],u[2]))){if((v=v[g])){while(v&amp;&amp;(!v.t
 agName||(c.tagName&amp;&amp;c.tagName!==v.tagName))){v=v[g];}}continue testLoop;}}}k--;if(!a&amp;&amp;(p=c.combinator)){g=p.axis;v=v[g];while(v&amp;&amp;!v.tagName){v=v[g];}if(p.direct){g=null;}}else{e.push(o);if(h){return e;}break;}}}o=v=null;return e;},combinators:{&quot; &quot;:{axis:&quot;parentNode&quot;},&quot;&gt;&quot;:{axis:&quot;parentNode&quot;,direct:true},&quot;+&quot;:{axis:&quot;previousSibling&quot;,direct:true}},_parsers:[{name:ATTRIBUTES,re:/^\uE003(-?[a-z]+[\w\-]*)+([~\|\^\$\*!=]=?)?['&quot;]?([^\uE004'&quot;]*)['&quot;]?\uE004/i,fn:function(d,e){var c=d[2]||&quot;&quot;,a=Selector.operators,b=(d[3])?d[3].replace(/\\/g,&quot;&quot;):&quot;&quot;,f;if((d[1]===&quot;id&quot;&amp;&amp;c===&quot;=&quot;)||(d[1]===&quot;className&quot;&amp;&amp;Y_DOCUMENT_ELEMENT.getElementsByClassName&amp;&amp;(c===&quot;~=&quot;||c===&quot;=&quot;))){e.prefilter=d[1];d[3]=b;e[d[1]]=(d[1]===&quot;id&quot;)?d[3]:b;}if(c in a){f=a[c];if(typeof f===&quot;string&quot;){d[3]=b.repl
 ace(Selector._reRegExpTokens,&quot;\\$1&quot;);f=new RegExp(f.replace(&quot;{val}&quot;,d[3]));}d[2]=f;}if(!e.last||e.prefilter!==d[1]){return d.slice(1);}}},{name:TAG_NAME,re:/^((?:-?[_a-z]+[\w-]*)|\*)/i,fn:function(b,c){var a=b[1].toUpperCase();c.tagName=a;if(a!==&quot;*&quot;&amp;&amp;(!c.last||c.prefilter)){return[TAG_NAME,&quot;=&quot;,a];}if(!c.prefilter){c.prefilter=&quot;tagName&quot;;}}},{name:COMBINATOR,re:/^\s*([&gt;+~]|\s)\s*/,fn:function(a,b){}},{name:PSEUDOS,re:/^:([\-\w]+)(?:\uE005['&quot;]?([^\uE005]*)['&quot;]?\uE006)*/i,fn:function(a,b){var c=Selector[PSEUDOS][a[1]];if(c){if(a[2]){a[2]=a[2].replace(/\\/g,&quot;&quot;);}return[a[2],c];}else{return false;}}}],_getToken:function(a){return{tagName:null,id:null,className:null,attributes:{},combinator:null,tests:[]};},_tokenize:function(c){c=c||&quot;&quot;;c=Selector._replaceShorthand(Y_Lang.trim(c));var b=Selector._getToken(),h=c,g=[],j=false,e,f,d,a;outer:do{j=false;for(d=0;(a=Selector._parsers[d++]);){if((e=a
 .re.exec(c))){if(a.name!==COMBINATOR){b.selector=c;}c=c.replace(e[0],&quot;&quot;);if(!c.length){b.last=true;}if(Selector._attrFilters[e[1]]){e[1]=Selector._attrFilters[e[1]];}f=a.fn(e,b);if(f===false){j=false;break outer;}else{if(f){b.tests.push(f);}}if(!c.length||a.name===COMBINATOR){g.push(b);b=Selector._getToken(b);if(a.name===COMBINATOR){b.combinator=Selector.combinators[e[1]];}}j=true;}}}while(j&amp;&amp;c.length);if(!j||c.length){Y.log(&quot;query: &quot;+h+&quot; contains unsupported token in: &quot;+c,&quot;warn&quot;,&quot;Selector&quot;);g=[];}return g;},_replaceShorthand:function(b){var d=Selector.shorthand,c=b.match(Selector._re.esc),e,h,g,f,a;if(c){b=b.replace(Selector._re.esc,&quot;\uE000&quot;);}e=b.match(Selector._re.attr);h=b.match(Selector._re.pseudos);if(e){b=b.replace(Selector._re.attr,&quot;\uE001&quot;);}if(h){b=b.replace(Selector._re.pseudos,&quot;\uE002&quot;);}for(g in d){if(d.hasOwnProperty(g)){b=b.replace(new RegExp(g,&quot;gi&quot;),d[g]);}}if(e)
 {for(f=0,a=e.length;f&lt;a;++f){b=b.replace(/\uE001/,e[f]);}}if(h){for(f=0,a=h.length;f&lt;a;++f){b=b.replace(/\uE002/,h[f]);}}b=b.replace(/\[/g,&quot;\uE003&quot;);b=b.replace(/\]/g,&quot;\uE004&quot;);b=b.replace(/\(/g,&quot;\uE005&quot;);b=b.replace(/\)/g,&quot;\uE006&quot;);if(c){for(f=0,a=c.length;f&lt;a;++f){b=b.replace(&quot;\uE000&quot;,c[f]);}}return b;},_attrFilters:{&quot;class&quot;:&quot;className&quot;,&quot;for&quot;:&quot;htmlFor&quot;},getters:{href:function(b,a){return Y_DOM.getAttribute(b,a);}}};Y_mix(Selector,SelectorCSS2,true);Selector.getters.src=Selector.getters.rel=Selector.getters.href;if(Selector.useNative&amp;&amp;Y_DOC.querySelector){Selector.shorthand[&quot;\\.([^\\s\\\\(\\[:]*)&quot;]=&quot;[class~=$1]&quot;;}Selector._reNth=/^(?:([\-]?\d*)(n){1}|(odd|even)$)*([\-+]?\d*)$/;Selector._getNth=function(d,o,q,h){Selector._reNth.test(o);var m=parseInt(RegExp.$1,10),c=RegExp.$2,j=RegExp.$3,k=parseInt(RegExp.$4,10)||0,p=[],l=Selector._children(d.parentN
 ode,q),f;if(j){m=2;f=&quot;+&quot;;c=&quot;n&quot;;k=(j===&quot;odd&quot;)?1:0;}else{if(isNaN(m)){m=(c)?1:0;
+}}if(m===0){if(h){k=l.length-k+1;}if(l[k-1]===d){return true;}else{return false;}}else{if(m&lt;0){h=!!h;m=Math.abs(m);}}if(!h){for(var e=k-1,g=l.length;e&lt;g;e+=m){if(e&gt;=0&amp;&amp;l[e]===d){return true;}}}else{for(var e=l.length-k,g=l.length;e&gt;=0;e-=m){if(e&lt;g&amp;&amp;l[e]===d){return true;}}}return false;};Y_mix(Selector.pseudos,{&quot;root&quot;:function(a){return a===a.ownerDocument.documentElement;},&quot;nth-child&quot;:function(a,b){return Selector._getNth(a,b);},&quot;nth-last-child&quot;:function(a,b){return Selector._getNth(a,b,null,true);},&quot;nth-of-type&quot;:function(a,b){return Selector._getNth(a,b,a.tagName);},&quot;nth-last-of-type&quot;:function(a,b){return Selector._getNth(a,b,a.tagName,true);},&quot;last-child&quot;:function(b){var a=Selector._children(b.parentNode);return a[a.length-1]===b;},&quot;first-of-type&quot;:function(a){return Selector._children(a.parentNode,a.tagName)[0]===a;},&quot;last-of-type&quot;:function(b){var a=Selector._chi
 ldren(b.parentNode,b.tagName);return a[a.length-1]===b;},&quot;only-child&quot;:function(b){var a=Selector._children(b.parentNode);return a.length===1&amp;&amp;a[0]===b;},&quot;only-of-type&quot;:function(b){var a=Selector._children(b.parentNode,b.tagName);return a.length===1&amp;&amp;a[0]===b;},&quot;empty&quot;:function(a){return a.childNodes.length===0;},&quot;not&quot;:function(a,b){return !Selector.test(a,b);},&quot;contains&quot;:function(a,b){var c=a.innerText||a.textContent||&quot;&quot;;return c.indexOf(b)&gt;-1;},&quot;checked&quot;:function(a){return(a.checked===true||a.selected===true);},enabled:function(a){return(a.disabled!==undefined&amp;&amp;!a.disabled);},disabled:function(a){return(a.disabled);}});Y_mix(Selector.operators,{&quot;^=&quot;:&quot;^{val}&quot;,&quot;!=&quot;:function(b,a,c){return b[a]!==c;},&quot;$=&quot;:&quot;{val}$&quot;,&quot;*=&quot;:&quot;{val}&quot;});Selector.combinators[&quot;~&quot;]={axis:&quot;previousSibling&quot;};YAHOO.register(
 &quot;selector&quot;,YAHOO.util.Selector,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});var Dom=YAHOO.util.Dom;YAHOO.widget.ColumnSet=function(a){this._sId=Dom.generateId(null,&quot;yui-cs&quot;);a=YAHOO.widget.DataTable._cloneObject(a);this._init(a);YAHOO.widget.ColumnSet._nCount++;};YAHOO.widget.ColumnSet._nCount=0;YAHOO.widget.ColumnSet.prototype={_sId:null,_aDefinitions:null,tree:null,flat:null,keys:null,headers:null,_init:function(j){var k=[];var a=[];var g=[];var e=[];var c=-1;var b=function(m,s){c++;if(!k[c]){k[c]=[];}for(var o=0;o&lt;m.length;o++){var i=m[o];var q=new YAHOO.widget.Column(i);i.yuiColumnId=q._sId;a.push(q);if(s){q._oParent=s;}if(YAHOO.lang.isArray(i.children)){q.children=i.children;var r=0;var p=function(v){var w=v.children;for(var u=0;u&lt;w.length;u++){if(YAHOO.lang.isArray(w[u].children)){p(w[u]);}else{r++;}}};p(i);q._nColspan=r;var t=i.children;for(var n=0;n&lt;t.length;n++){var l=t[n];if(q.className&amp;&amp;(l.className===undefined)){l.class
 Name=q.className;}if(q.editor&amp;&amp;(l.editor===undefined)){l.editor=q.editor;}if(q.editorOptions&amp;&amp;(l.editorOptions===undefined)){l.editorOptions=q.editorOptions;}if(q.formatter&amp;&amp;(l.formatter===undefined)){l.formatter=q.formatter;}if(q.resizeable&amp;&amp;(l.resizeable===undefined)){l.resizeable=q.resizeable;}if(q.sortable&amp;&amp;(l.sortable===undefined)){l.sortable=q.sortable;}if(q.hidden){l.hidden=true;}if(q.width&amp;&amp;(l.width===undefined)){l.width=q.width;}if(q.minWidth&amp;&amp;(l.minWidth===undefined)){l.minWidth=q.minWidth;}if(q.maxAutoWidth&amp;&amp;(l.maxAutoWidth===undefined)){l.maxAutoWidth=q.maxAutoWidth;}if(q.type&amp;&amp;(l.type===undefined)){l.type=q.type;}if(q.type&amp;&amp;!q.formatter){q.formatter=q.type;}if(q.text&amp;&amp;!YAHOO.lang.isValue(q.label)){q.label=q.text;}if(q.parser){}if(q.sortOptions&amp;&amp;((q.sortOptions.ascFunction)||(q.sortOptions.descFunction))){}}if(!k[c+1]){k[c+1]=[];}b(t,q);}else{q._nKeyIndex=g.length;q._n
 Colspan=1;g.push(q);}k[c].push(q);}c--;};if(YAHOO.lang.isArray(j)){b(j);this._aDefinitions=j;}else{return null;}var f;var d=function(l){var n=1;var q;var o;var r=function(t,p){p=p||1;for(var u=0;u&lt;t.length;u++){var m=t[u];if(YAHOO.lang.isArray(m.children)){p++;r(m.children,p);p--;}else{if(p&gt;n){n=p;}}}};for(var i=0;i&lt;l.length;i++){q=l[i];r(q);for(var s=0;s&lt;q.length;s++){o=q[s];if(!YAHOO.lang.isArray(o.children)){o._nRowspan=n;}else{o._nRowspan=1;}}n=1;}};d(k);for(f=0;f&lt;k[0].length;f++){k[0][f]._nTreeIndex=f;}var h=function(l,m){e[l].push(m.getSanitizedKey());if(m._oParent){h(l,m._oParent);}};for(f=0;f&lt;g.length;f++){e[f]=[];h(f,g[f]);e[f]=e[f].reverse();}this.tree=k;this.flat=a;this.keys=g;this.headers=e;},getId:function(){return this._sId;},toString:function(){return&quot;ColumnSet instance &quot;+this._sId;},getDefinitions:function(){var a=this._aDefinitions;var b=function(e,g){for(var d=0;d&lt;e.length;d++){var f=e[d];var i=g.getColumnById(f.yuiColumnId);i
 f(i){var h=i.getDefinition();for(var c in h){if(YAHOO.lang.hasOwnProperty(h,c)){f[c]=h[c];}}}if(YAHOO.lang.isArray(f.children)){b(f.children,g);}}};b(a,this);this._aDefinitions=a;return a;},getColumnById:function(c){if(YAHOO.lang.isString(c)){var a=this.flat;for(var b=a.length-1;b&gt;-1;b--){if(a[b]._sId===c){return a[b];}}}return null;},getColumn:function(c){if(YAHOO.lang.isNumber(c)&amp;&amp;this.keys[c]){return this.keys[c];}else{if(YAHOO.lang.isString(c)){var a=this.flat;var d=[];for(var b=0;b&lt;a.length;b++){if(a[b].key===c){d.push(a[b]);}}if(d.length===1){return d[0];}else{if(d.length&gt;1){return d;}}}}return null;},getDescendants:function(d){var b=this;var c=[];var a;var e=function(f){c.push(f);if(f.children){for(a=0;a&lt;f.children.length;a++){e(b.getColumn(f.children[a].key));}}};e(d);return c;}};YAHOO.widget.Column=function(b){this._sId=Dom.generateId(null,&quot;yui-col&quot;);if(b&amp;&amp;YAHOO.lang.isObject(b)){for(var a in b){if(a){this[a]=b[a];}}}if(!YAHOO.l
 ang.isValue(this.key)){this.key=Dom.generateId(null,&quot;yui-dt-col&quot;);}if(!YAHOO.lang.isValue(this.field)){this.field=this.key;}YAHOO.widget.Column._nCount++;if(this.width&amp;&amp;!YAHOO.lang.isNumber(this.width)){this.width=null;}if(this.editor&amp;&amp;YAHOO.lang.isString(this.editor)){this.editor=new YAHOO.widget.CellEditor(this.editor,this.editorOptions);}};YAHOO.lang.augmentObject(YAHOO.widget.Column,{_nCount:0,formatCheckbox:function(b,a,c,d){YAHOO.widget.DataTable.formatCheckbox(b,a,c,d);},formatCurrency:function(b,a,c,d){YAHOO.widget.DataTable.formatCurrency(b,a,c,d);},formatDate:function(b,a,c,d){YAHOO.widget.DataTable.formatDate(b,a,c,d);
+},formatEmail:function(b,a,c,d){YAHOO.widget.DataTable.formatEmail(b,a,c,d);},formatLink:function(b,a,c,d){YAHOO.widget.DataTable.formatLink(b,a,c,d);},formatNumber:function(b,a,c,d){YAHOO.widget.DataTable.formatNumber(b,a,c,d);},formatSelect:function(b,a,c,d){YAHOO.widget.DataTable.formatDropdown(b,a,c,d);}});YAHOO.widget.Column.prototype={_sId:null,_nKeyIndex:null,_nTreeIndex:null,_nColspan:1,_nRowspan:1,_oParent:null,_elTh:null,_elThLiner:null,_elThLabel:null,_elResizer:null,_nWidth:null,_dd:null,_ddResizer:null,key:null,field:null,label:null,abbr:null,children:null,width:null,minWidth:null,maxAutoWidth:null,hidden:false,selected:false,className:null,formatter:null,currencyOptions:null,dateOptions:null,dropdownOptions:null,editor:null,resizeable:false,sortable:false,sortOptions:null,getId:function(){return this._sId;},toString:function(){return&quot;Column instance &quot;+this._sId;},getDefinition:function(){var a={};a.abbr=this.abbr;a.className=this.className;a.editor=th
 is.editor;a.editorOptions=this.editorOptions;a.field=this.field;a.formatter=this.formatter;a.hidden=this.hidden;a.key=this.key;a.label=this.label;a.minWidth=this.minWidth;a.maxAutoWidth=this.maxAutoWidth;a.resizeable=this.resizeable;a.selected=this.selected;a.sortable=this.sortable;a.sortOptions=this.sortOptions;a.width=this.width;a._calculatedWidth=this._calculatedWidth;return a;},getKey:function(){return this.key;},getField:function(){return this.field;},getSanitizedKey:function(){return this.getKey().replace(/[^\w\-]/g,&quot;&quot;);},getKeyIndex:function(){return this._nKeyIndex;},getTreeIndex:function(){return this._nTreeIndex;},getParent:function(){return this._oParent;},getColspan:function(){return this._nColspan;},getColSpan:function(){return this.getColspan();},getRowspan:function(){return this._nRowspan;},getThEl:function(){return this._elTh;},getThLinerEl:function(){return this._elThLiner;},getResizerEl:function(){return this._elResizer;},getColEl:function(){retur
 n this.getThEl();},getIndex:function(){return this.getKeyIndex();},format:function(){}};YAHOO.util.Sort={compare:function(d,c,e){if((d===null)||(typeof d==&quot;undefined&quot;)){if((c===null)||(typeof c==&quot;undefined&quot;)){return 0;}else{return 1;}}else{if((c===null)||(typeof c==&quot;undefined&quot;)){return -1;}}if(d.constructor==String){d=d.toLowerCase();}if(c.constructor==String){c=c.toLowerCase();}if(d&lt;c){return(e)?1:-1;}else{if(d&gt;c){return(e)?-1:1;}else{return 0;}}}};YAHOO.widget.ColumnDD=function(d,a,c,b){if(d&amp;&amp;a&amp;&amp;c&amp;&amp;b){this.datatable=d;this.table=d.getTableEl();this.column=a;this.headCell=c;this.pointer=b;this.newIndex=null;this.init(c);this.initFrame();this.invalidHandleTypes={};this.setPadding(10,0,(this.datatable.getTheadEl().offsetHeight+10),0);YAHOO.util.Event.on(window,&quot;resize&quot;,function(){this.initConstraints();},this,true);}else{}};if(YAHOO.util.DDProxy){YAHOO.extend(YAHOO.widget.ColumnDD,YAHOO.util.DDProxy,{initCo
 nstraints:function(){var g=YAHOO.util.Dom.getRegion(this.table),d=this.getEl(),f=YAHOO.util.Dom.getXY(d),c=parseInt(YAHOO.util.Dom.getStyle(d,&quot;width&quot;),10),a=parseInt(YAHOO.util.Dom.getStyle(d,&quot;height&quot;),10),e=((f[0]-g.left)+15),b=((g.right-f[0]-c)+15);this.setXConstraint(e,b);this.setYConstraint(10,10);},_resizeProxy:function(){YAHOO.widget.ColumnDD.superclass._resizeProxy.apply(this,arguments);var a=this.getDragEl(),b=this.getEl();YAHOO.util.Dom.setStyle(this.pointer,&quot;height&quot;,(this.table.parentNode.offsetHeight+10)+&quot;px&quot;);YAHOO.util.Dom.setStyle(this.pointer,&quot;display&quot;,&quot;block&quot;);var c=YAHOO.util.Dom.getXY(b);YAHOO.util.Dom.setXY(this.pointer,[c[0],(c[1]-5)]);YAHOO.util.Dom.setStyle(a,&quot;height&quot;,this.datatable.getContainerEl().offsetHeight+&quot;px&quot;);YAHOO.util.Dom.setStyle(a,&quot;width&quot;,(parseInt(YAHOO.util.Dom.getStyle(a,&quot;width&quot;),10)+4)+&quot;px&quot;);YAHOO.util.Dom.setXY(this.dragEl,c);}
 ,onMouseDown:function(){this.initConstraints();this.resetConstraints();},clickValidator:function(b){if(!this.column.hidden){var a=YAHOO.util.Event.getTarget(b);return(this.isValidHandleChild(a)&amp;&amp;(this.id==this.handleElId||this.DDM.handleWasClicked(a,this.id)));}},onDragOver:function(h,a){var f=this.datatable.getColumn(a);if(f){var c=f.getTreeIndex();while((c===null)&amp;&amp;f.getParent()){f=f.getParent();c=f.getTreeIndex();}if(c!==null){var b=f.getThEl();var k=c;var d=YAHOO.util.Event.getPageX(h),i=YAHOO.util.Dom.getX(b),j=i+((YAHOO.util.Dom.get(b).offsetWidth)/2),e=this.column.getTreeIndex();if(d&lt;j){YAHOO.util.Dom.setX(this.pointer,i);}else{var g=parseInt(b.offsetWidth,10);YAHOO.util.Dom.setX(this.pointer,(i+g));k++;}if(c&gt;e){k--;}if(k&lt;0){k=0;}else{if(k&gt;this.datatable.getColumnSet().tree[0].length){k=this.datatable.getColumnSet().tree[0].length;}}this.newIndex=k;}}},onDragDrop:function(){this.datatable.reorderColumn(this.column,this.newIndex);},endDrag:f
 unction(){this.newIndex=null;YAHOO.util.Dom.setStyle(this.pointer,&quot;display&quot;,&quot;none&quot;);}});}YAHOO.util.ColumnResizer=function(e,c,d,a,b){if(e&amp;&amp;c&amp;&amp;d&amp;&amp;a){this.datatable=e;this.column=c;this.headCell=d;this.headCellLiner=c.getThLinerEl();this.resizerLiner=d.firstChild;this.init(a,a,{dragOnly:true,dragElId:b.id});this.initFrame();this.resetResizerEl();this.setPadding(0,1,0,0);}else{}};if(YAHOO.util.DD){YAHOO.extend(YAHOO.util.ColumnResizer,YAHOO.util.DDProxy,{resetResizerEl:function(){var a=YAHOO.util.Dom.get(this.handleElId).style;a.left=&quot;auto&quot;;a.right=0;a.top=&quot;auto&quot;;a.bottom=0;a.height=this.headCell.offsetHeight+&quot;px&quot;;},onMouseUp:function(h){var f=this.datatable.getColumnSet().keys,b;for(var c=0,a=f.length;c&lt;a;c++){b=f[c];if(b._ddResizer){b._ddResizer.resetResizerEl();}}this.resetResizerEl();var d=this.headCellLiner;var g=d.offsetWidth-(parseInt(YAHOO.util.Dom.getStyle(d,&quot;paddingLeft&quot;),10)|0)-(p
 arseInt(YAHOO.util.Dom.getStyle(d,&quot;paddingRight&quot;),10)|0);this.datatable.fireEvent(&quot;columnResizeEvent&quot;,{column:this.column,target:this.headCell,width:g});},onMouseDown:function(a){this.startWidth=this.headCellLiner.offsetWidth;this.startX=YAHOO.util.Event.getXY(a)[0];this.nLinerPadding=(parseInt(YAHOO.util.Dom.getStyle(this.headCellLiner,&quot;paddingLeft&quot;),10)|0)+(parseInt(YAHOO.util.Dom.getStyle(this.headCellLiner,&quot;paddingRight&quot;),10)|0);
+},clickValidator:function(b){if(!this.column.hidden){var a=YAHOO.util.Event.getTarget(b);return(this.isValidHandleChild(a)&amp;&amp;(this.id==this.handleElId||this.DDM.handleWasClicked(a,this.id)));}},startDrag:function(){var e=this.datatable.getColumnSet().keys,d=this.column.getKeyIndex(),b;for(var c=0,a=e.length;c&lt;a;c++){b=e[c];if(b._ddResizer){YAHOO.util.Dom.get(b._ddResizer.handleElId).style.height=&quot;1em&quot;;}}},onDrag:function(c){var d=YAHOO.util.Event.getXY(c)[0];if(d&gt;YAHOO.util.Dom.getX(this.headCellLiner)){var a=d-this.startX;var b=this.startWidth+a-this.nLinerPadding;if(b&gt;0){this.datatable.setColumnWidth(this.column,b);}}}});}(function(){var g=YAHOO.lang,a=YAHOO.util,e=YAHOO.widget,c=a.Dom,f=a.Event,d=e.DataTable;YAHOO.widget.RecordSet=function(h){this._init(h);};var b=e.RecordSet;b._nCount=0;b.prototype={_sId:null,_init:function(h){this._sId=c.generateId(null,&quot;yui-rs&quot;);e.RecordSet._nCount++;this._records=[];this._initEvents();if(h){if(g.isA
 rray(h)){this.addRecords(h);}else{if(g.isObject(h)){this.addRecord(h);}}}},_initEvents:function(){this.createEvent(&quot;recordAddEvent&quot;);this.createEvent(&quot;recordsAddEvent&quot;);this.createEvent(&quot;recordSetEvent&quot;);this.createEvent(&quot;recordsSetEvent&quot;);this.createEvent(&quot;recordUpdateEvent&quot;);this.createEvent(&quot;recordDeleteEvent&quot;);this.createEvent(&quot;recordsDeleteEvent&quot;);this.createEvent(&quot;resetEvent&quot;);this.createEvent(&quot;recordValueUpdateEvent&quot;);},_addRecord:function(j,h){var i=new YAHOO.widget.Record(j);if(YAHOO.lang.isNumber(h)&amp;&amp;(h&gt;-1)){this._records.splice(h,0,i);}else{this._records[this._records.length]=i;}return i;},_setRecord:function(i,h){if(!g.isNumber(h)||h&lt;0){h=this._records.length;}return(this._records[h]=new e.Record(i));},_deleteRecord:function(i,h){if(!g.isNumber(h)||(h&lt;0)){h=1;}this._records.splice(i,h);},getId:function(){return this._sId;},toString:function(){return&quot;Rec
 ordSet instance &quot;+this._sId;},getLength:function(){return this._records.length;},getRecord:function(h){var j;if(h instanceof e.Record){for(j=0;j&lt;this._records.length;j++){if(this._records[j]&amp;&amp;(this._records[j]._sId===h._sId)){return h;}}}else{if(g.isNumber(h)){if((h&gt;-1)&amp;&amp;(h&lt;this.getLength())){return this._records[h];}}else{if(g.isString(h)){for(j=0;j&lt;this._records.length;j++){if(this._records[j]&amp;&amp;(this._records[j]._sId===h)){return this._records[j];}}}}}return null;},getRecords:function(i,h){if(!g.isNumber(i)){return this._records;}if(!g.isNumber(h)){return this._records.slice(i);}return this._records.slice(i,i+h);},hasRecords:function(j,h){var l=this.getRecords(j,h);for(var k=0;k&lt;h;++k){if(typeof l[k]===&quot;undefined&quot;){return false;}}return true;},getRecordIndex:function(j){if(j){for(var h=this._records.length-1;h&gt;-1;h--){if(this._records[h]&amp;&amp;j.getId()===this._records[h].getId()){return h;}}}return null;},addReco
 rd:function(j,h){if(g.isObject(j)){var i=this._addRecord(j,h);this.fireEvent(&quot;recordAddEvent&quot;,{record:i,data:j});return i;}else{return null;}},addRecords:function(m,l){if(g.isArray(m)){var p=[],j,n,h;l=g.isNumber(l)?l:this._records.length;j=l;for(n=0,h=m.length;n&lt;h;++n){if(g.isObject(m[n])){var k=this._addRecord(m[n],j++);p.push(k);}}this.fireEvent(&quot;recordsAddEvent&quot;,{records:p,data:m});return p;}else{if(g.isObject(m)){var o=this._addRecord(m);this.fireEvent(&quot;recordsAddEvent&quot;,{records:[o],data:m});return o;}else{return null;}}},setRecord:function(j,h){if(g.isObject(j)){var i=this._setRecord(j,h);this.fireEvent(&quot;recordSetEvent&quot;,{record:i,data:j});return i;}else{return null;}},setRecords:function(o,n){var r=e.Record,k=g.isArray(o)?o:[o],q=[],p=0,h=k.length,m=0;n=parseInt(n,10)|0;for(;p&lt;h;++p){if(typeof k[p]===&quot;object&quot;&amp;&amp;k[p]){q[m++]=this._records[n+p]=new r(k[p]);}}this.fireEvent(&quot;recordsSetEvent&quot;,{records
 :q,data:o});this.fireEvent(&quot;recordsSet&quot;,{records:q,data:o});if(k.length&amp;&amp;!q.length){}return q;},updateRecord:function(h,l){var j=this.getRecord(h);if(j&amp;&amp;g.isObject(l)){var k={};for(var i in j._oData){if(g.hasOwnProperty(j._oData,i)){k[i]=j._oData[i];}}j._oData=l;this.fireEvent(&quot;recordUpdateEvent&quot;,{record:j,newData:l,oldData:k});return j;}else{return null;}},updateKey:function(h,i,j){this.updateRecordValue(h,i,j);},updateRecordValue:function(h,k,n){var j=this.getRecord(h);if(j){var m=null;var l=j._oData[k];if(l&amp;&amp;g.isObject(l)){m={};for(var i in l){if(g.hasOwnProperty(l,i)){m[i]=l[i];}}}else{m=l;}j._oData[k]=n;this.fireEvent(&quot;keyUpdateEvent&quot;,{record:j,key:k,newData:n,oldData:m});this.fireEvent(&quot;recordValueUpdateEvent&quot;,{record:j,key:k,newData:n,oldData:m});}else{}},replaceRecords:function(h){this.reset();return this.addRecords(h);},sortRecords:function(h,j,i){return this._records.sort(function(l,k){return h(l,k,j,i
 );});},reverseRecords:function(){return this._records.reverse();},deleteRecord:function(h){if(g.isNumber(h)&amp;&amp;(h&gt;-1)&amp;&amp;(h&lt;this.getLength())){var i=this.getRecord(h).getData();this._deleteRecord(h);this.fireEvent(&quot;recordDeleteEvent&quot;,{data:i,index:h});return i;}else{return null;}},deleteRecords:function(k,h){if(!g.isNumber(h)){h=1;}if(g.isNumber(k)&amp;&amp;(k&gt;-1)&amp;&amp;(k&lt;this.getLength())){var m=this.getRecords(k,h);var j=[],n=[];for(var l=0;l&lt;m.length;l++){j[j.length]=m[l];n[n.length]=m[l].getData();}this._deleteRecord(k,h);this.fireEvent(&quot;recordsDeleteEvent&quot;,{data:j,deletedData:n,index:k});return j;}else{return null;}},reset:function(){this._records=[];this.fireEvent(&quot;resetEvent&quot;);}};g.augmentProto(b,a.EventProvider);YAHOO.widget.Record=function(h){this._nCount=e.Record._nCount;this._sId=c.generateId(null,&quot;yui-rec&quot;);e.Record._nCount++;this._oData={};if(g.isObject(h)){for(var i in h){if(g.hasOwnProperty
 (h,i)){this._oData[i]=h[i];}}}};YAHOO.widget.Record._nCount=0;YAHOO.widget.Record.prototype={_nCount:null,_sId:null,_oData:null,getCount:function(){return this._nCount;},getId:function(){return this._sId;},getData:function(h){if(g.isString(h)){return this._oData[h];}else{return this._oData;}},setData:function(h,i){this._oData[h]=i;}};})();(function(){var h=YAHOO.lang,a=YAHOO.util,e=YAHOO.widget,b=YAHOO.env.ua,c=a.Dom,g=a.Event,f=a.DataSourceBase;YAHOO.widget.DataTable=function(i,m,o,k){var l=e.DataTable;
+if(k&amp;&amp;k.scrollable){return new YAHOO.widget.ScrollingDataTable(i,m,o,k);}this._nIndex=l._nCount;this._sId=c.generateId(null,&quot;yui-dt&quot;);this._oChainRender=new YAHOO.util.Chain();this._oChainRender.subscribe(&quot;end&quot;,this._onRenderChainEnd,this,true);this._initConfigs(k);this._initDataSource(o);if(!this._oDataSource){return;}this._initColumnSet(m);if(!this._oColumnSet){return;}this._initRecordSet();if(!this._oRecordSet){}l.superclass.constructor.call(this,i,this.configs);var q=this._initDomElements(i);if(!q){return;}this.showTableMessage(this.get(&quot;MSG_LOADING&quot;),l.CLASS_LOADING);this._initEvents();l._nCount++;l._nCurrentCount++;var n={success:this.onDataReturnSetRows,failure:this.onDataReturnSetRows,scope:this,argument:this.getState()};var p=this.get(&quot;initialLoad&quot;);if(p===true){this._oDataSource.sendRequest(this.get(&quot;initialRequest&quot;),n);}else{if(p===false){this.showTableMessage(this.get(&quot;MSG_EMPTY&quot;),l.CLASS_EMPTY);
 }else{var j=p||{};n.argument=j.argument||{};this._oDataSource.sendRequest(j.request,n);}}};var d=e.DataTable;h.augmentObject(d,{CLASS_DATATABLE:&quot;yui-dt&quot;,CLASS_LINER:&quot;yui-dt-liner&quot;,CLASS_LABEL:&quot;yui-dt-label&quot;,CLASS_MESSAGE:&quot;yui-dt-message&quot;,CLASS_MASK:&quot;yui-dt-mask&quot;,CLASS_DATA:&quot;yui-dt-data&quot;,CLASS_COLTARGET:&quot;yui-dt-coltarget&quot;,CLASS_RESIZER:&quot;yui-dt-resizer&quot;,CLASS_RESIZERLINER:&quot;yui-dt-resizerliner&quot;,CLASS_RESIZERPROXY:&quot;yui-dt-resizerproxy&quot;,CLASS_EDITOR:&quot;yui-dt-editor&quot;,CLASS_EDITOR_SHIM:&quot;yui-dt-editor-shim&quot;,CLASS_PAGINATOR:&quot;yui-dt-paginator&quot;,CLASS_PAGE:&quot;yui-dt-page&quot;,CLASS_DEFAULT:&quot;yui-dt-default&quot;,CLASS_PREVIOUS:&quot;yui-dt-previous&quot;,CLASS_NEXT:&quot;yui-dt-next&quot;,CLASS_FIRST:&quot;yui-dt-first&quot;,CLASS_LAST:&quot;yui-dt-last&quot;,CLASS_REC:&quot;yui-dt-rec&quot;,CLASS_EVEN:&quot;yui-dt-even&quot;,CLASS_ODD:&quot;yui-dt-odd
 &quot;,CLASS_SELECTED:&quot;yui-dt-selected&quot;,CLASS_HIGHLIGHTED:&quot;yui-dt-highlighted&quot;,CLASS_HIDDEN:&quot;yui-dt-hidden&quot;,CLASS_DISABLED:&quot;yui-dt-disabled&quot;,CLASS_EMPTY:&quot;yui-dt-empty&quot;,CLASS_LOADING:&quot;yui-dt-loading&quot;,CLASS_ERROR:&quot;yui-dt-error&quot;,CLASS_EDITABLE:&quot;yui-dt-editable&quot;,CLASS_DRAGGABLE:&quot;yui-dt-draggable&quot;,CLASS_RESIZEABLE:&quot;yui-dt-resizeable&quot;,CLASS_SCROLLABLE:&quot;yui-dt-scrollable&quot;,CLASS_SORTABLE:&quot;yui-dt-sortable&quot;,CLASS_ASC:&quot;yui-dt-asc&quot;,CLASS_DESC:&quot;yui-dt-desc&quot;,CLASS_BUTTON:&quot;yui-dt-button&quot;,CLASS_CHECKBOX:&quot;yui-dt-checkbox&quot;,CLASS_DROPDOWN:&quot;yui-dt-dropdown&quot;,CLASS_RADIO:&quot;yui-dt-radio&quot;,_nCount:0,_nCurrentCount:0,_elDynStyleNode:null,_bDynStylesFallback:(b.ie)?true:false,_oDynStyles:{},_cloneObject:function(m){if(!h.isValue(m)){return m;}var p={};if(m instanceof YAHOO.widget.BaseCellEditor){p=m;}else{if(Object.prototype.
 toString.apply(m)===&quot;[object RegExp]&quot;){p=m;}else{if(h.isFunction(m)){p=m;}else{if(h.isArray(m)){var n=[];for(var l=0,k=m.length;l&lt;k;l++){n[l]=d._cloneObject(m[l]);}p=n;}else{if(h.isObject(m)){for(var j in m){if(h.hasOwnProperty(m,j)){if(h.isValue(m[j])&amp;&amp;h.isObject(m[j])||h.isArray(m[j])){p[j]=d._cloneObject(m[j]);}else{p[j]=m[j];}}}}else{p=m;}}}}}return p;},formatButton:function(i,j,k,n,m){var l=h.isValue(n)?n:&quot;Click&quot;;i.innerHTML='&lt;button type=&quot;button&quot; class=&quot;'+d.CLASS_BUTTON+'&quot;&gt;'+l+&quot;&lt;/button&gt;&quot;;},formatCheckbox:function(i,j,k,n,m){var l=n;l=(l)?' checked=&quot;checked&quot;':&quot;&quot;;i.innerHTML='&lt;input type=&quot;checkbox&quot;'+l+' class=&quot;'+d.CLASS_CHECKBOX+'&quot; /&gt;';},formatCurrency:function(j,k,l,n,m){var i=m||this;j.innerHTML=a.Number.format(n,l.currencyOptions||i.get(&quot;currencyOptions&quot;));},formatDate:function(j,l,m,o,n){var i=n||this,k=m.dateOptions||i.get(&quot;dateOptio
 ns&quot;);j.innerHTML=a.Date.format(o,k,k.locale);},formatDropdown:function(l,u,q,j,t){var s=t||this,r=(h.isValue(j))?j:u.getData(q.field),v=(h.isArray(q.dropdownOptions))?q.dropdownOptions:null,k,p=l.getElementsByTagName(&quot;select&quot;);if(p.length===0){k=document.createElement(&quot;select&quot;);k.className=d.CLASS_DROPDOWN;k=l.appendChild(k);g.addListener(k,&quot;change&quot;,s._onDropdownChange,s);}k=p[0];if(k){k.innerHTML=&quot;&quot;;if(v){for(var n=0;n&lt;v.length;n++){var o=v[n];var m=document.createElement(&quot;option&quot;);m.value=(h.isValue(o.value))?o.value:o;m.innerHTML=(h.isValue(o.text))?o.text:(h.isValue(o.label))?o.label:o;m=k.appendChild(m);if(m.value==r){m.selected=true;}}}else{k.innerHTML='&lt;option selected value=&quot;'+r+'&quot;&gt;'+r+&quot;&lt;/option&gt;&quot;;}}else{l.innerHTML=h.isValue(j)?j:&quot;&quot;;}},formatEmail:function(i,j,k,m,l){if(h.isString(m)){m=h.escapeHTML(m);i.innerHTML='&lt;a href=&quot;mailto:'+m+'&quot;&gt;'+m+&quot;&lt;
 /a&gt;&quot;;}else{i.innerHTML=h.isValue(m)?h.escapeHTML(m.toString()):&quot;&quot;;}},formatLink:function(i,j,k,m,l){if(h.isString(m)){m=h.escapeHTML(m);i.innerHTML='&lt;a href=&quot;'+m+'&quot;&gt;'+m+&quot;&lt;/a&gt;&quot;;}else{i.innerHTML=h.isValue(m)?h.escapeHTML(m.toString()):&quot;&quot;;}},formatNumber:function(j,k,l,n,m){var i=m||this;j.innerHTML=a.Number.format(n,l.numberOptions||i.get(&quot;numberOptions&quot;));},formatRadio:function(j,k,l,o,n){var i=n||this,m=o;m=(m)?' checked=&quot;checked&quot;':&quot;&quot;;j.innerHTML='&lt;input type=&quot;radio&quot;'+m+' name=&quot;'+i.getId()+&quot;-col-&quot;+l.getSanitizedKey()+'&quot;'+' class=&quot;'+d.CLASS_RADIO+'&quot; /&gt;';},formatText:function(i,j,l,n,m){var k=(h.isValue(n))?n:&quot;&quot;;i.innerHTML=h.escapeHTML(k.toString());},formatTextarea:function(j,k,m,o,n){var l=(h.isValue(o))?h.escapeHTML(o.toString()):&quot;&quot;,i=&quot;&lt;textarea&gt;&quot;+l+&quot;&lt;/textarea&gt;&quot;;j.innerHTML=i;},formatTe
 xtbox:function(j,k,m,o,n){var l=(h.isValue(o))?h.escapeHTML(o.toString()):&quot;&quot;,i='&lt;input type=&quot;text&quot; value=&quot;'+l+'&quot; /&gt;';j.innerHTML=i;},formatDefault:function(i,j,k,m,l){i.innerHTML=(h.isValue(m)&amp;&amp;m!==&quot;&quot;)?m.toString():&quot;&amp;#160;&quot;;},validateNumber:function(j){var i=j*1;if(h.isNumber(i)){return i;}else{return undefined;}}});d.Formatter={button:d.formatButton,checkbox:d.formatCheckbox,currency:d.formatCurrency,&quot;date&quot;:d.formatDate,dropdown:d.formatDropdown,email:d.formatEmail,link:d.formatLink,&quot;number&quot;:d.formatNumber,radio:d.formatRadio,text:d.formatText,textarea:d.formatTextarea,textbox:d.formatTextbox,defaultFormatter:d.formatDefault};h.extend(d,a.Element,{initAttributes:function(i){i=i||{};d.superclass.initAttributes.call(this,i);this.setAttributeConfig(&quot;summary&quot;,{value:&quot;&quot;,validator:h.isString,method:function(j){if(this._elTable){this._elTable.summary=j;}}});this.setAttribute
 Config(&quot;selectionMode&quot;,{value:&quot;standard&quot;,validator:h.isString});this.setAttributeConfig(&quot;sortedBy&quot;,{value:null,validator:function(j){if(j){return(h.isObject(j)&amp;&amp;j.key);
+}else{return(j===null);}},method:function(k){var r=this.get(&quot;sortedBy&quot;);this._configs.sortedBy.value=k;var j,o,m,q;if(this._elThead){if(r&amp;&amp;r.key&amp;&amp;r.dir){j=this._oColumnSet.getColumn(r.key);o=j.getKeyIndex();var u=j.getThEl();c.removeClass(u,r.dir);this.formatTheadCell(j.getThLinerEl().firstChild,j,k);}if(k){m=(k.column)?k.column:this._oColumnSet.getColumn(k.key);q=m.getKeyIndex();var v=m.getThEl();if(k.dir&amp;&amp;((k.dir==&quot;asc&quot;)||(k.dir==&quot;desc&quot;))){var p=(k.dir==&quot;desc&quot;)?d.CLASS_DESC:d.CLASS_ASC;c.addClass(v,p);}else{var l=k.dir||d.CLASS_ASC;c.addClass(v,l);}this.formatTheadCell(m.getThLinerEl().firstChild,m,k);}}if(this._elTbody){this._elTbody.style.display=&quot;none&quot;;var s=this._elTbody.rows,t;for(var n=s.length-1;n&gt;-1;n--){t=s[n].childNodes;if(t[o]){c.removeClass(t[o],r.dir);}if(t[q]){c.addClass(t[q],k.dir);}}this._elTbody.style.display=&quot;&quot;;}this._clearTrTemplateEl();}});this.setAttributeConfig(&quo
 t;paginator&quot;,{value:null,validator:function(j){return j===null||j instanceof e.Paginator;},method:function(){this._updatePaginator.apply(this,arguments);}});this.setAttributeConfig(&quot;caption&quot;,{value:null,validator:h.isString,method:function(j){this._initCaptionEl(j);}});this.setAttributeConfig(&quot;draggableColumns&quot;,{value:false,validator:h.isBoolean,method:function(j){if(this._elThead){if(j){this._initDraggableColumns();}else{this._destroyDraggableColumns();}}}});this.setAttributeConfig(&quot;renderLoopSize&quot;,{value:0,validator:h.isNumber});this.setAttributeConfig(&quot;sortFunction&quot;,{value:function(k,j,o,n){var m=YAHOO.util.Sort.compare,l=m(k.getData(n),j.getData(n),o);if(l===0){return m(k.getCount(),j.getCount(),o);}else{return l;}}});this.setAttributeConfig(&quot;formatRow&quot;,{value:null,validator:h.isFunction});this.setAttributeConfig(&quot;generateRequest&quot;,{value:function(k,n){k=k||{pagination:null,sortedBy:null};var m=encodeURIComp
 onent((k.sortedBy)?k.sortedBy.key:n.getColumnSet().keys[0].getKey());var j=(k.sortedBy&amp;&amp;k.sortedBy.dir===YAHOO.widget.DataTable.CLASS_DESC)?&quot;desc&quot;:&quot;asc&quot;;var o=(k.pagination)?k.pagination.recordOffset:0;var l=(k.pagination)?k.pagination.rowsPerPage:null;return&quot;sort=&quot;+m+&quot;&amp;dir=&quot;+j+&quot;&amp;startIndex=&quot;+o+((l!==null)?&quot;&amp;results=&quot;+l:&quot;&quot;);},validator:h.isFunction});this.setAttributeConfig(&quot;initialRequest&quot;,{value:null});this.setAttributeConfig(&quot;initialLoad&quot;,{value:true});this.setAttributeConfig(&quot;dynamicData&quot;,{value:false,validator:h.isBoolean});this.setAttributeConfig(&quot;MSG_EMPTY&quot;,{value:&quot;No records found.&quot;,validator:h.isString});this.setAttributeConfig(&quot;MSG_LOADING&quot;,{value:&quot;Loading...&quot;,validator:h.isString});this.setAttributeConfig(&quot;MSG_ERROR&quot;,{value:&quot;Data error.&quot;,validator:h.isString});this.setAttributeConfig(&qu
 ot;MSG_SORTASC&quot;,{value:&quot;Click to sort ascending&quot;,validator:h.isString,method:function(k){if(this._elThead){for(var l=0,m=this.getColumnSet().keys,j=m.length;l&lt;j;l++){if(m[l].sortable&amp;&amp;this.getColumnSortDir(m[l])===d.CLASS_ASC){m[l]._elThLabel.firstChild.title=k;}}}}});this.setAttributeConfig(&quot;MSG_SORTDESC&quot;,{value:&quot;Click to sort descending&quot;,validator:h.isString,method:function(k){if(this._elThead){for(var l=0,m=this.getColumnSet().keys,j=m.length;l&lt;j;l++){if(m[l].sortable&amp;&amp;this.getColumnSortDir(m[l])===d.CLASS_DESC){m[l]._elThLabel.firstChild.title=k;}}}}});this.setAttributeConfig(&quot;currencySymbol&quot;,{value:&quot;$&quot;,validator:h.isString});this.setAttributeConfig(&quot;currencyOptions&quot;,{value:{prefix:this.get(&quot;currencySymbol&quot;),decimalPlaces:2,decimalSeparator:&quot;.&quot;,thousandsSeparator:&quot;,&quot;}});this.setAttributeConfig(&quot;dateOptions&quot;,{value:{format:&quot;%m/%d/%Y&quot;,loc
 ale:&quot;en&quot;}});this.setAttributeConfig(&quot;numberOptions&quot;,{value:{decimalPlaces:0,thousandsSeparator:&quot;,&quot;}});},_bInit:true,_nIndex:null,_nTrCount:0,_nTdCount:0,_sId:null,_oChainRender:null,_elContainer:null,_elMask:null,_elTable:null,_elCaption:null,_elColgroup:null,_elThead:null,_elTbody:null,_elMsgTbody:null,_elMsgTr:null,_elMsgTd:null,_elColumnDragTarget:null,_elColumnResizerProxy:null,_oDataSource:null,_oColumnSet:null,_oRecordSet:null,_oCellEditor:null,_sFirstTrId:null,_sLastTrId:null,_elTrTemplate:null,_aDynFunctions:[],_disabled:false,clearTextSelection:function(){var i;if(window.getSelection){i=window.getSelection();}else{if(document.getSelection){i=document.getSelection();}else{if(document.selection){i=document.selection;}}}if(i){if(i.empty){i.empty();}else{if(i.removeAllRanges){i.removeAllRanges();}else{if(i.collapse){i.collapse();}}}}},_focusEl:function(i){i=i||this._elTbody;setTimeout(function(){try{i.focus();}catch(j){}},0);},_repaintGecko
 :(b.gecko)?function(j){j=j||this._elContainer;var i=j.parentNode;var k=j.nextSibling;i.insertBefore(i.removeChild(j),k);}:function(){},_repaintOpera:(b.opera)?function(){if(b.opera){document.documentElement.className+=&quot; &quot;;document.documentElement.className=YAHOO.lang.trim(document.documentElement.className);}}:function(){},_repaintWebkit:(b.webkit)?function(j){j=j||this._elContainer;var i=j.parentNode;var k=j.nextSibling;i.insertBefore(i.removeChild(j),k);}:function(){},_initConfigs:function(i){if(!i||!h.isObject(i)){i={};}this.configs=i;},_initColumnSet:function(n){var m,k,j;if(this._oColumnSet){for(k=0,j=this._oColumnSet.keys.length;k&lt;j;k++){m=this._oColumnSet.keys[k];d._oDynStyles[&quot;.&quot;+this.getId()+&quot;-col-&quot;+m.getSanitizedKey()+&quot; .&quot;+d.CLASS_LINER]=undefined;if(m.editor&amp;&amp;m.editor.unsubscribeAll){m.editor.unsubscribeAll();}}this._oColumnSet=null;this._clearTrTemplateEl();}if(h.isArray(n)){this._oColumnSet=new YAHOO.widget.Colu
 mnSet(n);}else{if(n instanceof YAHOO.widget.ColumnSet){this._oColumnSet=n;}}var l=this._oColumnSet.keys;for(k=0,j=l.length;k&lt;j;k++){m=l[k];if(m.editor&amp;&amp;m.editor.subscribe){m.editor.subscribe(&quot;showEvent&quot;,this._onEditorShowEvent,this,true);m.editor.subscribe(&quot;keydownEvent&quot;,this._onEditorKeydownEvent,this,true);m.editor.subscribe(&quot;revertEvent&quot;,this._onEditorRevertEvent,this,true);m.editor.subscribe(&quot;saveEvent&quot;,this._onEditorSaveEvent,this,true);m.editor.subscribe(&quot;cancelEvent&quot;,this._onEditorCancelEvent,this,true);m.editor.subscribe(&quot;blurEvent&quot;,this._onEditorBlurEvent,this,true);m.editor.subscribe(&quot;blockEvent&quot;,this._onEditorBlockEvent,this,true);
+m.editor.subscribe(&quot;unblockEvent&quot;,this._onEditorUnblockEvent,this,true);}}},_initDataSource:function(j){this._oDataSource=null;if(j&amp;&amp;(h.isFunction(j.sendRequest))){this._oDataSource=j;}else{var k=null;var o=this._elContainer;var l=0;if(o.hasChildNodes()){var n=o.childNodes;for(l=0;l&lt;n.length;l++){if(n[l].nodeName&amp;&amp;n[l].nodeName.toLowerCase()==&quot;table&quot;){k=n[l];break;}}if(k){var m=[];for(;l&lt;this._oColumnSet.keys.length;l++){m.push({key:this._oColumnSet.keys[l].key});}this._oDataSource=new f(k);this._oDataSource.responseType=f.TYPE_HTMLTABLE;this._oDataSource.responseSchema={fields:m};}}}},_initRecordSet:function(){if(this._oRecordSet){this._oRecordSet.reset();}else{this._oRecordSet=new YAHOO.widget.RecordSet();}},_initDomElements:function(i){this._initContainerEl(i);this._initTableEl(this._elContainer);this._initColgroupEl(this._elTable);this._initTheadEl(this._elTable);this._initMsgTbodyEl(this._elTable);this._initTbodyEl(this._elTable
 );if(!this._elContainer||!this._elTable||!this._elColgroup||!this._elThead||!this._elTbody||!this._elMsgTbody){return false;}else{return true;}},_destroyContainerEl:function(m){var k=this._oColumnSet.keys,l,j;c.removeClass(m,d.CLASS_DATATABLE);g.purgeElement(m);g.purgeElement(this._elThead,true);g.purgeElement(this._elTbody);g.purgeElement(this._elMsgTbody);l=m.getElementsByTagName(&quot;select&quot;);if(l.length){g.detachListener(l,&quot;change&quot;);}for(j=k.length-1;j&gt;=0;--j){if(k[j].editor){g.purgeElement(k[j].editor._elContainer);}}m.innerHTML=&quot;&quot;;this._elContainer=null;this._elColgroup=null;this._elThead=null;this._elTbody=null;},_initContainerEl:function(j){j=c.get(j);if(j&amp;&amp;j.nodeName&amp;&amp;(j.nodeName.toLowerCase()==&quot;div&quot;)){this._destroyContainerEl(j);c.addClass(j,d.CLASS_DATATABLE);g.addListener(j,&quot;focus&quot;,this._onTableFocus,this);g.addListener(j,&quot;dblclick&quot;,this._onTableDblclick,this);this._elContainer=j;var i=doc
 ument.createElement(&quot;div&quot;);i.className=d.CLASS_MASK;i.style.display=&quot;none&quot;;this._elMask=j.appendChild(i);}},_destroyTableEl:function(){var i=this._elTable;if(i){g.purgeElement(i,true);i.parentNode.removeChild(i);this._elCaption=null;this._elColgroup=null;this._elThead=null;this._elTbody=null;}},_initCaptionEl:function(i){if(this._elTable&amp;&amp;i){if(!this._elCaption){this._elCaption=this._elTable.createCaption();}this._elCaption.innerHTML=i;}else{if(this._elCaption){this._elCaption.parentNode.removeChild(this._elCaption);}}},_initTableEl:function(i){if(i){this._destroyTableEl();this._elTable=i.appendChild(document.createElement(&quot;table&quot;));this._elTable.summary=this.get(&quot;summary&quot;);if(this.get(&quot;caption&quot;)){this._initCaptionEl(this.get(&quot;caption&quot;));}g.delegate(this._elTable,&quot;mouseenter&quot;,this._onTableMouseover,&quot;thead .&quot;+d.CLASS_LABEL,this);g.delegate(this._elTable,&quot;mouseleave&quot;,this._onTable
 Mouseout,&quot;thead .&quot;+d.CLASS_LABEL,this);g.delegate(this._elTable,&quot;mouseenter&quot;,this._onTableMouseover,&quot;tbody.yui-dt-data&gt;tr&gt;td&quot;,this);g.delegate(this._elTable,&quot;mouseleave&quot;,this._onTableMouseout,&quot;tbody.yui-dt-data&gt;tr&gt;td&quot;,this);g.delegate(this._elTable,&quot;mouseenter&quot;,this._onTableMouseover,&quot;tbody.yui-dt-message&gt;tr&gt;td&quot;,this);g.delegate(this._elTable,&quot;mouseleave&quot;,this._onTableMouseout,&quot;tbody.yui-dt-message&gt;tr&gt;td&quot;,this);}},_destroyColgroupEl:function(){var i=this._elColgroup;if(i){var j=i.parentNode;g.purgeElement(i,true);j.removeChild(i);this._elColgroup=null;}},_initColgroupEl:function(s){if(s){this._destroyColgroupEl();var l=this._aColIds||[],r=this._oColumnSet.keys,m=0,p=l.length,j,o,q=document.createDocumentFragment(),n=document.createElement(&quot;col&quot;);for(m=0,p=r.length;m&lt;p;m++){o=r[m];j=q.appendChild(n.cloneNode(false));}var k=s.insertBefore(document.crea
 teElement(&quot;colgroup&quot;),s.firstChild);k.appendChild(q);this._elColgroup=k;}},_insertColgroupColEl:function(i){if(h.isNumber(i)&amp;&amp;this._elColgroup){var j=this._elColgroup.childNodes[i]||null;this._elColgroup.insertBefore(document.createElement(&quot;col&quot;),j);}},_removeColgroupColEl:function(i){if(h.isNumber(i)&amp;&amp;this._elColgroup&amp;&amp;this._elColgroup.childNodes[i]){this._elColgroup.removeChild(this._elColgroup.childNodes[i]);}},_reorderColgroupColEl:function(l,k){if(h.isArray(l)&amp;&amp;h.isNumber(k)&amp;&amp;this._elColgroup&amp;&amp;(this._elColgroup.childNodes.length&gt;l[l.length-1])){var j,n=[];for(j=l.length-1;j&gt;-1;j--){n.push(this._elColgroup.removeChild(this._elColgroup.childNodes[l[j]]));}var m=this._elColgroup.childNodes[k]||null;for(j=n.length-1;j&gt;-1;j--){this._elColgroup.insertBefore(n[j],m);}}},_destroyTheadEl:function(){var j=this._elThead;if(j){var i=j.parentNode;g.purgeElement(j,true);this._destroyColumnHelpers();i.removeC
 hild(j);this._elThead=null;}},_initTheadEl:function(v){v=v||this._elTable;if(v){this._destroyTheadEl();var q=(this._elColgroup)?v.insertBefore(document.createElement(&quot;thead&quot;),this._elColgroup.nextSibling):v.appendChild(document.createElement(&quot;thead&quot;));g.addListener(q,&quot;focus&quot;,this._onTheadFocus,this);g.addListener(q,&quot;keydown&quot;,this._onTheadKeydown,this);g.addListener(q,&quot;mousedown&quot;,this._onTableMousedown,this);g.addListener(q,&quot;mouseup&quot;,this._onTableMouseup,this);g.addListener(q,&quot;click&quot;,this._onTheadClick,this);var x=this._oColumnSet,t,r,p,n;var w=x.tree;var o;for(r=0;r&lt;w.length;r++){var m=q.appendChild(document.createElement(&quot;tr&quot;));for(p=0;p&lt;w[r].length;p++){t=w[r][p];o=m.appendChild(document.createElement(&quot;th&quot;));this._initThEl(o,t);}if(r===0){c.addClass(m,d.CLASS_FIRST);}if(r===(w.length-1)){c.addClass(m,d.CLASS_LAST);}}var k=x.headers[0]||[];for(r=0;r&lt;k.length;r++){c.addClass(c.
 get(this.getId()+&quot;-th-&quot;+k[r]),d.CLASS_FIRST);}var s=x.headers[x.headers.length-1]||[];for(r=0;r&lt;s.length;r++){c.addClass(c.get(this.getId()+&quot;-th-&quot;+s[r]),d.CLASS_LAST);}if(b.webkit&amp;&amp;b.webkit&lt;420){var u=this;setTimeout(function(){q.style.display=&quot;&quot;;},0);q.style.display=&quot;none&quot;;}this._elThead=q;this._initColumnHelpers();}},_initThEl:function(m,l){m.id=this.getId()+&quot;-th-&quot;+l.getSanitizedKey();m.innerHTML=&quot;&quot;;m.rowSpan=l.getRowspan();m.colSpan=l.getColspan();l._elTh=m;var i=m.appendChild(document.createElement(&quot;div&quot;));i.id=m.id+&quot;-liner&quot;;i.className=d.CLASS_LINER;l._elThLiner=i;var j=i.appendChild(document.createElement(&quot;span&quot;));
+j.className=d.CLASS_LABEL;if(l.abbr){m.abbr=l.abbr;}if(l.hidden){this._clearMinWidth(l);}m.className=this._getColumnClassNames(l);if(l.width){var k=(l.minWidth&amp;&amp;(l.width&lt;l.minWidth))?l.minWidth:l.width;if(d._bDynStylesFallback){m.firstChild.style.overflow=&quot;hidden&quot;;m.firstChild.style.width=k+&quot;px&quot;;}else{this._setColumnWidthDynStyles(l,k+&quot;px&quot;,&quot;hidden&quot;);}}this.formatTheadCell(j,l,this.get(&quot;sortedBy&quot;));l._elThLabel=j;},formatTheadCell:function(i,m,k){var q=m.getKey();var p=h.isValue(m.label)?m.label:q;if(m.sortable){var n=this.getColumnSortDir(m,k);var j=(n===d.CLASS_DESC);if(k&amp;&amp;(m.key===k.key)){j=!(k.dir===d.CLASS_DESC);}var l=this.getId()+&quot;-href-&quot;+m.getSanitizedKey();var o=(j)?this.get(&quot;MSG_SORTDESC&quot;):this.get(&quot;MSG_SORTASC&quot;);i.innerHTML='&lt;a href=&quot;'+l+'&quot; title=&quot;'+o+'&quot; class=&quot;'+d.CLASS_SORTABLE+'&quot;&gt;'+p+&quot;&lt;/a&gt;&quot;;}else{i.innerHTML=p;}},
 _destroyDraggableColumns:function(){var l,m;for(var k=0,j=this._oColumnSet.tree[0].length;k&lt;j;k++){l=this._oColumnSet.tree[0][k];if(l._dd){l._dd=l._dd.unreg();c.removeClass(l.getThEl(),d.CLASS_DRAGGABLE);}}this._destroyColumnDragTargetEl();},_initDraggableColumns:function(){this._destroyDraggableColumns();if(a.DD){var m,n,k;for(var l=0,j=this._oColumnSet.tree[0].length;l&lt;j;l++){m=this._oColumnSet.tree[0][l];n=m.getThEl();c.addClass(n,d.CLASS_DRAGGABLE);k=this._initColumnDragTargetEl();m._dd=new YAHOO.widget.ColumnDD(this,m,n,k);}}else{}},_destroyColumnDragTargetEl:function(){if(this._elColumnDragTarget){var i=this._elColumnDragTarget;YAHOO.util.Event.purgeElement(i);i.parentNode.removeChild(i);this._elColumnDragTarget=null;}},_initColumnDragTargetEl:function(){if(!this._elColumnDragTarget){var i=document.createElement(&quot;div&quot;);i.id=this.getId()+&quot;-coltarget&quot;;i.className=d.CLASS_COLTARGET;i.style.display=&quot;none&quot;;document.body.insertBefore(i,doc
 ument.body.firstChild);this._elColumnDragTarget=i;}return this._elColumnDragTarget;},_destroyResizeableColumns:function(){var k=this._oColumnSet.keys;for(var l=0,j=k.length;l&lt;j;l++){if(k[l]._ddResizer){k[l]._ddResizer=k[l]._ddResizer.unreg();c.removeClass(k[l].getThEl(),d.CLASS_RESIZEABLE);}}this._destroyColumnResizerProxyEl();},_initResizeableColumns:function(){this._destroyResizeableColumns();if(a.DD){var p,k,n,q,j,r,m;for(var l=0,o=this._oColumnSet.keys.length;l&lt;o;l++){p=this._oColumnSet.keys[l];if(p.resizeable){k=p.getThEl();c.addClass(k,d.CLASS_RESIZEABLE);n=p.getThLinerEl();q=k.appendChild(document.createElement(&quot;div&quot;));q.className=d.CLASS_RESIZERLINER;q.appendChild(n);j=q.appendChild(document.createElement(&quot;div&quot;));j.id=k.id+&quot;-resizer&quot;;j.className=d.CLASS_RESIZER;p._elResizer=j;r=this._initColumnResizerProxyEl();p._ddResizer=new YAHOO.util.ColumnResizer(this,p,k,j,r);m=function(i){g.stopPropagation(i);};g.addListener(j,&quot;click&qu
 ot;,m);}}}else{}},_destroyColumnResizerProxyEl:function(){if(this._elColumnResizerProxy){var i=this._elColumnResizerProxy;YAHOO.util.Event.purgeElement(i);i.parentNode.removeChild(i);this._elColumnResizerProxy=null;}},_initColumnResizerProxyEl:function(){if(!this._elColumnResizerProxy){var i=document.createElement(&quot;div&quot;);i.id=this.getId()+&quot;-colresizerproxy&quot;;i.className=d.CLASS_RESIZERPROXY;document.body.insertBefore(i,document.body.firstChild);this._elColumnResizerProxy=i;}return this._elColumnResizerProxy;},_destroyColumnHelpers:function(){this._destroyDraggableColumns();this._destroyResizeableColumns();},_initColumnHelpers:function(){if(this.get(&quot;draggableColumns&quot;)){this._initDraggableColumns();}this._initResizeableColumns();},_destroyTbodyEl:function(){var i=this._elTbody;if(i){var j=i.parentNode;g.purgeElement(i,true);j.removeChild(i);this._elTbody=null;}},_initTbodyEl:function(j){if(j){this._destroyTbodyEl();var i=j.appendChild(document.cre
 ateElement(&quot;tbody&quot;));i.tabIndex=0;i.className=d.CLASS_DATA;g.addListener(i,&quot;focus&quot;,this._onTbodyFocus,this);g.addListener(i,&quot;mousedown&quot;,this._onTableMousedown,this);g.addListener(i,&quot;mouseup&quot;,this._onTableMouseup,this);g.addListener(i,&quot;keydown&quot;,this._onTbodyKeydown,this);g.addListener(i,&quot;click&quot;,this._onTbodyClick,this);if(b.ie){i.hideFocus=true;}this._elTbody=i;}},_destroyMsgTbodyEl:function(){var i=this._elMsgTbody;if(i){var j=i.parentNode;g.purgeElement(i,true);j.removeChild(i);this._elTbody=null;}},_initMsgTbodyEl:function(l){if(l){var k=document.createElement(&quot;tbody&quot;);k.className=d.CLASS_MESSAGE;var j=k.appendChild(document.createElement(&quot;tr&quot;));j.className=d.CLASS_FIRST+&quot; &quot;+d.CLASS_LAST;this._elMsgTr=j;var m=j.appendChild(document.createElement(&quot;td&quot;));m.colSpan=this._oColumnSet.keys.length||1;m.className=d.CLASS_FIRST+&quot; &quot;+d.CLASS_LAST;this._elMsgTd=m;k=l.insertBef
 ore(k,this._elTbody);var i=m.appendChild(document.createElement(&quot;div&quot;));i.className=d.CLASS_LINER;this._elMsgTbody=k;g.addListener(k,&quot;focus&quot;,this._onTbodyFocus,this);g.addListener(k,&quot;mousedown&quot;,this._onTableMousedown,this);g.addListener(k,&quot;mouseup&quot;,this._onTableMouseup,this);g.addListener(k,&quot;keydown&quot;,this._onTbodyKeydown,this);g.addListener(k,&quot;click&quot;,this._onTbodyClick,this);}},_initEvents:function(){this._initColumnSort();YAHOO.util.Event.addListener(document,&quot;click&quot;,this._onDocumentClick,this);this.subscribe(&quot;paginatorChange&quot;,function(){this._handlePaginatorChange.apply(this,arguments);});this.subscribe(&quot;initEvent&quot;,function(){this.renderPaginator();});this._initCellEditing();},_initColumnSort:function(){this.subscribe(&quot;theadCellClickEvent&quot;,this.onEventSortColumn);var i=this.get(&quot;sortedBy&quot;);if(i){if(i.dir==&quot;desc&quot;){this._configs.sortedBy.value.dir=d.CLASS_D
 ESC;}else{if(i.dir==&quot;asc&quot;){this._configs.sortedBy.value.dir=d.CLASS_ASC;}}}},_initCellEditing:function(){this.subscribe(&quot;editorBlurEvent&quot;,function(){this.onEditorBlurEvent.apply(this,arguments);});this.subscribe(&quot;editorBlockEvent&quot;,function(){this.onEditorBlockEvent.apply(this,arguments);});this.subscribe(&quot;editorUnblockEvent&quot;,function(){this.onEditorUnblockEvent.apply(this,arguments);});},_getColumnClassNames:function(l,k){var i;if(h.isString(l.className)){i=[l.className];}else{if(h.isArray(l.className)){i=l.className;}else{i=[];}}i[i.length]=this.getId()+&quot;-col-&quot;+l.getSanitizedKey();
+i[i.length]=&quot;yui-dt-col-&quot;+l.getSanitizedKey();var j=this.get(&quot;sortedBy&quot;)||{};if(l.key===j.key){i[i.length]=j.dir||&quot;&quot;;}if(l.hidden){i[i.length]=d.CLASS_HIDDEN;}if(l.selected){i[i.length]=d.CLASS_SELECTED;}if(l.sortable){i[i.length]=d.CLASS_SORTABLE;}if(l.resizeable){i[i.length]=d.CLASS_RESIZEABLE;}if(l.editor){i[i.length]=d.CLASS_EDITABLE;}if(k){i=i.concat(k);}return i.join(&quot; &quot;);},_clearTrTemplateEl:function(){this._elTrTemplate=null;},_getTrTemplateEl:function(u,o){if(this._elTrTemplate){return this._elTrTemplate;}else{var q=document,s=q.createElement(&quot;tr&quot;),l=q.createElement(&quot;td&quot;),k=q.createElement(&quot;div&quot;);l.appendChild(k);var t=document.createDocumentFragment(),r=this._oColumnSet.keys,n;var p;for(var m=0,j=r.length;m&lt;j;m++){n=l.cloneNode(true);n=this._formatTdEl(r[m],n,m,(m===j-1));t.appendChild(n);}s.appendChild(t);s.className=d.CLASS_REC;this._elTrTemplate=s;return s;}},_formatTdEl:function(n,p,q,m){v
 ar t=this._oColumnSet;var i=t.headers,k=i[q],o=&quot;&quot;,v;for(var l=0,u=k.length;l&lt;u;l++){v=this._sId+&quot;-th-&quot;+k[l]+&quot; &quot;;o+=v;}p.headers=o;var s=[];if(q===0){s[s.length]=d.CLASS_FIRST;}if(m){s[s.length]=d.CLASS_LAST;}p.className=this._getColumnClassNames(n,s);p.firstChild.className=d.CLASS_LINER;if(n.width&amp;&amp;d._bDynStylesFallback){var r=(n.minWidth&amp;&amp;(n.width&lt;n.minWidth))?n.minWidth:n.width;p.firstChild.style.overflow=&quot;hidden&quot;;p.firstChild.style.width=r+&quot;px&quot;;}return p;},_addTrEl:function(k){var j=this._getTrTemplateEl();var i=j.cloneNode(true);return this._updateTrEl(i,k);},_updateTrEl:function(q,r){var p=this.get(&quot;formatRow&quot;)?this.get(&quot;formatRow&quot;).call(this,q,r):true;if(p){q.style.display=&quot;none&quot;;var o=q.childNodes,m;for(var l=0,n=o.length;l&lt;n;++l){m=o[l];this.formatCell(o[l].firstChild,r,this._oColumnSet.keys[l]);}q.style.display=&quot;&quot;;}var j=q.id,k=r.getId();if(this._sFirst
 TrId===j){this._sFirstTrId=k;}if(this._sLastTrId===j){this._sLastTrId=k;}q.id=k;return q;},_deleteTrEl:function(i){var j;if(!h.isNumber(i)){j=c.get(i).sectionRowIndex;}else{j=i;}if(h.isNumber(j)&amp;&amp;(j&gt;-2)&amp;&amp;(j&lt;this._elTbody.rows.length)){return this._elTbody.removeChild(this._elTbody.rows[i]);}else{return null;}},_unsetFirstRow:function(){if(this._sFirstTrId){c.removeClass(this._sFirstTrId,d.CLASS_FIRST);this._sFirstTrId=null;}},_setFirstRow:function(){this._unsetFirstRow();var i=this.getFirstTrEl();if(i){c.addClass(i,d.CLASS_FIRST);this._sFirstTrId=i.id;}},_unsetLastRow:function(){if(this._sLastTrId){c.removeClass(this._sLastTrId,d.CLASS_LAST);this._sLastTrId=null;}},_setLastRow:function(){this._unsetLastRow();var i=this.getLastTrEl();if(i){c.addClass(i,d.CLASS_LAST);this._sLastTrId=i.id;}},_setRowStripes:function(t,l){var m=this._elTbody.rows,q=0,s=m.length,p=[],r=0,n=[],j=0;if((t!==null)&amp;&amp;(t!==undefined)){var o=this.getTrEl(t);if(o){q=o.sectionR
 owIndex;if(h.isNumber(l)&amp;&amp;(l&gt;1)){s=q+l;}}}for(var k=q;k&lt;s;k++){if(k%2){p[r++]=m[k];}else{n[j++]=m[k];}}if(p.length){c.replaceClass(p,d.CLASS_EVEN,d.CLASS_ODD);}if(n.length){c.replaceClass(n,d.CLASS_ODD,d.CLASS_EVEN);}},_setSelections:function(){var l=this.getSelectedRows();var n=this.getSelectedCells();if((l.length&gt;0)||(n.length&gt;0)){var m=this._oColumnSet,k;for(var j=0;j&lt;l.length;j++){k=c.get(l[j]);if(k){c.addClass(k,d.CLASS_SELECTED);}}for(j=0;j&lt;n.length;j++){k=c.get(n[j].recordId);if(k){c.addClass(k.childNodes[m.getColumn(n[j].columnKey).getKeyIndex()],d.CLASS_SELECTED);}}}},_onRenderChainEnd:function(){this.hideTableMessage();if(this._elTbody.rows.length===0){this.showTableMessage(this.get(&quot;MSG_EMPTY&quot;),d.CLASS_EMPTY);}var i=this;setTimeout(function(){if((i instanceof d)&amp;&amp;i._sId){if(i._bInit){i._bInit=false;i.fireEvent(&quot;initEvent&quot;);}i.fireEvent(&quot;renderEvent&quot;);i.fireEvent(&quot;refreshEvent&quot;);i.validateCol
 umnWidths();i.fireEvent(&quot;postRenderEvent&quot;);}},0);},_onDocumentClick:function(l,j){var m=g.getTarget(l);var i=m.nodeName.toLowerCase();if(!c.isAncestor(j._elContainer,m)){j.fireEvent(&quot;tableBlurEvent&quot;);if(j._oCellEditor){if(j._oCellEditor.getContainerEl){var k=j._oCellEditor.getContainerEl();if(!c.isAncestor(k,m)&amp;&amp;(k.id!==m.id)){j._oCellEditor.fireEvent(&quot;blurEvent&quot;,{editor:j._oCellEditor});}}else{if(j._oCellEditor.isActive){if(!c.isAncestor(j._oCellEditor.container,m)&amp;&amp;(j._oCellEditor.container.id!==m.id)){j.fireEvent(&quot;editorBlurEvent&quot;,{editor:j._oCellEditor});}}}}}},_onTableFocus:function(j,i){i.fireEvent(&quot;tableFocusEvent&quot;);},_onTheadFocus:function(j,i){i.fireEvent(&quot;theadFocusEvent&quot;);i.fireEvent(&quot;tableFocusEvent&quot;);},_onTbodyFocus:function(j,i){i.fireEvent(&quot;tbodyFocusEvent&quot;);i.fireEvent(&quot;tableFocusEvent&quot;);},_onTableMouseover:function(n,m,i,k){var o=m;var j=o.nodeName&amp;&
 amp;o.nodeName.toLowerCase();var l=true;while(o&amp;&amp;(j!=&quot;table&quot;)){switch(j){case&quot;body&quot;:return;case&quot;a&quot;:break;case&quot;td&quot;:l=k.fireEvent(&quot;cellMouseoverEvent&quot;,{target:o,event:n});break;case&quot;span&quot;:if(c.hasClass(o,d.CLASS_LABEL)){l=k.fireEvent(&quot;theadLabelMouseoverEvent&quot;,{target:o,event:n});l=k.fireEvent(&quot;headerLabelMouseoverEvent&quot;,{target:o,event:n});}break;case&quot;th&quot;:l=k.fireEvent(&quot;theadCellMouseoverEvent&quot;,{target:o,event:n});l=k.fireEvent(&quot;headerCellMouseoverEvent&quot;,{target:o,event:n});break;case&quot;tr&quot;:if(o.parentNode.nodeName.toLowerCase()==&quot;thead&quot;){l=k.fireEvent(&quot;theadRowMouseoverEvent&quot;,{target:o,event:n});l=k.fireEvent(&quot;headerRowMouseoverEvent&quot;,{target:o,event:n});}else{l=k.fireEvent(&quot;rowMouseoverEvent&quot;,{target:o,event:n});}break;default:break;}if(l===false){return;}else{o=o.parentNode;if(o){j=o.nodeName.toLowerCase();}}}
 k.fireEvent(&quot;tableMouseoverEvent&quot;,{target:(o||k._elContainer),event:n});},_onTableMouseout:function(n,m,i,k){var o=m;var j=o.nodeName&amp;&amp;o.nodeName.toLowerCase();var l=true;while(o&amp;&amp;(j!=&quot;table&quot;)){switch(j){case&quot;body&quot;:return;case&quot;a&quot;:break;case&quot;td&quot;:l=k.fireEvent(&quot;cellMouseoutEvent&quot;,{target:o,event:n});break;case&quot;span&quot;:if(c.hasClass(o,d.CLASS_LABEL)){l=k.fireEvent(&quot;theadLabelMouseoutEvent&quot;,{target:o,event:n});l=k.fireEvent(&quot;headerLabelMouseoutEvent&quot;,{target:o,event:n});}break;case&quot;th&quot;:l=k.fireEvent(&quot;theadCellMouseoutEvent&quot;,{target:o,event:n});l=k.fireEvent(&quot;headerCellMouseoutEvent&quot;,{target:o,event:n});break;case&quot;tr&quot;:if(o.parentNode.nodeName.toLowerCase()==&quot;thead&quot;){l=k.fireEvent(&quot;theadRowMouseoutEvent&quot;,{target:o,event:n});
+l=k.fireEvent(&quot;headerRowMouseoutEvent&quot;,{target:o,event:n});}else{l=k.fireEvent(&quot;rowMouseoutEvent&quot;,{target:o,event:n});}break;default:break;}if(l===false){return;}else{o=o.parentNode;if(o){j=o.nodeName.toLowerCase();}}}k.fireEvent(&quot;tableMouseoutEvent&quot;,{target:(o||k._elContainer),event:n});},_onTableMousedown:function(l,j){var m=g.getTarget(l);var i=m.nodeName&amp;&amp;m.nodeName.toLowerCase();var k=true;while(m&amp;&amp;(i!=&quot;table&quot;)){switch(i){case&quot;body&quot;:return;case&quot;a&quot;:break;case&quot;td&quot;:k=j.fireEvent(&quot;cellMousedownEvent&quot;,{target:m,event:l});break;case&quot;span&quot;:if(c.hasClass(m,d.CLASS_LABEL)){k=j.fireEvent(&quot;theadLabelMousedownEvent&quot;,{target:m,event:l});k=j.fireEvent(&quot;headerLabelMousedownEvent&quot;,{target:m,event:l});}break;case&quot;th&quot;:k=j.fireEvent(&quot;theadCellMousedownEvent&quot;,{target:m,event:l});k=j.fireEvent(&quot;headerCellMousedownEvent&quot;,{target:m,event:l
 });break;case&quot;tr&quot;:if(m.parentNode.nodeName.toLowerCase()==&quot;thead&quot;){k=j.fireEvent(&quot;theadRowMousedownEvent&quot;,{target:m,event:l});k=j.fireEvent(&quot;headerRowMousedownEvent&quot;,{target:m,event:l});}else{k=j.fireEvent(&quot;rowMousedownEvent&quot;,{target:m,event:l});}break;default:break;}if(k===false){return;}else{m=m.parentNode;if(m){i=m.nodeName.toLowerCase();}}}j.fireEvent(&quot;tableMousedownEvent&quot;,{target:(m||j._elContainer),event:l});},_onTableMouseup:function(l,j){var m=g.getTarget(l);var i=m.nodeName&amp;&amp;m.nodeName.toLowerCase();var k=true;while(m&amp;&amp;(i!=&quot;table&quot;)){switch(i){case&quot;body&quot;:return;case&quot;a&quot;:break;case&quot;td&quot;:k=j.fireEvent(&quot;cellMouseupEvent&quot;,{target:m,event:l});break;case&quot;span&quot;:if(c.hasClass(m,d.CLASS_LABEL)){k=j.fireEvent(&quot;theadLabelMouseupEvent&quot;,{target:m,event:l});k=j.fireEvent(&quot;headerLabelMouseupEvent&quot;,{target:m,event:l});}break;case&q
 uot;th&quot;:k=j.fireEvent(&quot;theadCellMouseupEvent&quot;,{target:m,event:l});k=j.fireEvent(&quot;headerCellMouseupEvent&quot;,{target:m,event:l});break;case&quot;tr&quot;:if(m.parentNode.nodeName.toLowerCase()==&quot;thead&quot;){k=j.fireEvent(&quot;theadRowMouseupEvent&quot;,{target:m,event:l});k=j.fireEvent(&quot;headerRowMouseupEvent&quot;,{target:m,event:l});}else{k=j.fireEvent(&quot;rowMouseupEvent&quot;,{target:m,event:l});}break;default:break;}if(k===false){return;}else{m=m.parentNode;if(m){i=m.nodeName.toLowerCase();}}}j.fireEvent(&quot;tableMouseupEvent&quot;,{target:(m||j._elContainer),event:l});},_onTableDblclick:function(l,j){var m=g.getTarget(l);var i=m.nodeName&amp;&amp;m.nodeName.toLowerCase();var k=true;while(m&amp;&amp;(i!=&quot;table&quot;)){switch(i){case&quot;body&quot;:return;case&quot;td&quot;:k=j.fireEvent(&quot;cellDblclickEvent&quot;,{target:m,event:l});break;case&quot;span&quot;:if(c.hasClass(m,d.CLASS_LABEL)){k=j.fireEvent(&quot;theadLabelDblcl
 ickEvent&quot;,{target:m,event:l});k=j.fireEvent(&quot;headerLabelDblclickEvent&quot;,{target:m,event:l});}break;case&quot;th&quot;:k=j.fireEvent(&quot;theadCellDblclickEvent&quot;,{target:m,event:l});k=j.fireEvent(&quot;headerCellDblclickEvent&quot;,{target:m,event:l});break;case&quot;tr&quot;:if(m.parentNode.nodeName.toLowerCase()==&quot;thead&quot;){k=j.fireEvent(&quot;theadRowDblclickEvent&quot;,{target:m,event:l});k=j.fireEvent(&quot;headerRowDblclickEvent&quot;,{target:m,event:l});}else{k=j.fireEvent(&quot;rowDblclickEvent&quot;,{target:m,event:l});}break;default:break;}if(k===false){return;}else{m=m.parentNode;if(m){i=m.nodeName.toLowerCase();}}}j.fireEvent(&quot;tableDblclickEvent&quot;,{target:(m||j._elContainer),event:l});},_onTheadKeydown:function(l,j){var m=g.getTarget(l);var i=m.nodeName&amp;&amp;m.nodeName.toLowerCase();var k=true;while(m&amp;&amp;(i!=&quot;table&quot;)){switch(i){case&quot;body&quot;:return;case&quot;input&quot;:case&quot;textarea&quot;:break;
 case&quot;thead&quot;:k=j.fireEvent(&quot;theadKeyEvent&quot;,{target:m,event:l});break;default:break;}if(k===false){return;}else{m=m.parentNode;if(m){i=m.nodeName.toLowerCase();}}}j.fireEvent(&quot;tableKeyEvent&quot;,{target:(m||j._elContainer),event:l});},_onTbodyKeydown:function(m,k){var j=k.get(&quot;selectionMode&quot;);if(j==&quot;standard&quot;){k._handleStandardSelectionByKey(m);}else{if(j==&quot;single&quot;){k._handleSingleSelectionByKey(m);}else{if(j==&quot;cellblock&quot;){k._handleCellBlockSelectionByKey(m);}else{if(j==&quot;cellrange&quot;){k._handleCellRangeSelectionByKey(m);}else{if(j==&quot;singlecell&quot;){k._handleSingleCellSelectionByKey(m);}}}}}if(k._oCellEditor){if(k._oCellEditor.fireEvent){k._oCellEditor.fireEvent(&quot;blurEvent&quot;,{editor:k._oCellEditor});}else{if(k._oCellEditor.isActive){k.fireEvent(&quot;editorBlurEvent&quot;,{editor:k._oCellEditor});}}}var n=g.getTarget(m);var i=n.nodeName&amp;&amp;n.nodeName.toLowerCase();var l=true;while(n&
 amp;&amp;(i!=&quot;table&quot;)){switch(i){case&quot;body&quot;:return;case&quot;tbody&quot;:l=k.fireEvent(&quot;tbodyKeyEvent&quot;,{target:n,event:m});break;default:break;}if(l===false){return;}else{n=n.parentNode;if(n){i=n.nodeName.toLowerCase();}}}k.fireEvent(&quot;tableKeyEvent&quot;,{target:(n||k._elContainer),event:m});},_onTheadClick:function(l,j){if(j._oCellEditor){if(j._oCellEditor.fireEvent){j._oCellEditor.fireEvent(&quot;blurEvent&quot;,{editor:j._oCellEditor});}else{if(j._oCellEditor.isActive){j.fireEvent(&quot;editorBlurEvent&quot;,{editor:j._oCellEditor});}}}var m=g.getTarget(l),i=m.nodeName&amp;&amp;m.nodeName.toLowerCase(),k=true;while(m&amp;&amp;(i!=&quot;table&quot;)){switch(i){case&quot;body&quot;:return;case&quot;input&quot;:var n=m.type.toLowerCase();if(n==&quot;checkbox&quot;){k=j.fireEvent(&quot;theadCheckboxClickEvent&quot;,{target:m,event:l});}else{if(n==&quot;radio&quot;){k=j.fireEvent(&quot;theadRadioClickEvent&quot;,{target:m,event:l});}else{if((
 n==&quot;button&quot;)||(n==&quot;image&quot;)||(n==&quot;submit&quot;)||(n==&quot;reset&quot;)){if(!m.disabled){k=j.fireEvent(&quot;theadButtonClickEvent&quot;,{target:m,event:l});}else{k=false;}}else{if(m.disabled){k=false;}}}}break;case&quot;a&quot;:k=j.fireEvent(&quot;theadLinkClickEvent&quot;,{target:m,event:l});break;case&quot;button&quot;:if(!m.disabled){k=j.fireEvent(&quot;theadButtonClickEvent&quot;,{target:m,event:l});}else{k=false;}break;case&quot;span&quot;:if(c.hasClass(m,d.CLASS_LABEL)){k=j.fireEvent(&quot;theadLabelClickEvent&quot;,{target:m,event:l});k=j.fireEvent(&quot;headerLabelClickEvent&quot;,{target:m,event:l});}break;case&quot;th&quot;:k=j.fireEvent(&quot;theadCellClickEvent&quot;,{target:m,event:l});k=j.fireEvent(&quot;headerCellClickEvent&quot;,{target:m,event:l});break;case&quot;tr&quot;:k=j.fireEvent(&quot;theadRowClickEvent&quot;,{target:m,event:l});k=j.fireEvent(&quot;headerRowClickEvent&quot;,{target:m,event:l});break;default:break;}if(k===false
 ){return;}else{m=m.parentNode;if(m){i=m.nodeName.toLowerCase();}}}j.fireEvent(&quot;tableClickEvent&quot;,{target:(m||j._elContainer),event:l});},_onTbodyClick:function(l,j){if(j._oCellEditor){if(j._oCellEditor.fireEvent){j._oCellEditor.fireEvent(&quot;blurEvent&quot;,{editor:j._oCellEditor});
+}else{if(j._oCellEditor.isActive){j.fireEvent(&quot;editorBlurEvent&quot;,{editor:j._oCellEditor});}}}var m=g.getTarget(l),i=m.nodeName&amp;&amp;m.nodeName.toLowerCase(),k=true;while(m&amp;&amp;(i!=&quot;table&quot;)){switch(i){case&quot;body&quot;:return;case&quot;input&quot;:var n=m.type.toLowerCase();if(n==&quot;checkbox&quot;){k=j.fireEvent(&quot;checkboxClickEvent&quot;,{target:m,event:l});}else{if(n==&quot;radio&quot;){k=j.fireEvent(&quot;radioClickEvent&quot;,{target:m,event:l});}else{if((n==&quot;button&quot;)||(n==&quot;image&quot;)||(n==&quot;submit&quot;)||(n==&quot;reset&quot;)){if(!m.disabled){k=j.fireEvent(&quot;buttonClickEvent&quot;,{target:m,event:l});}else{k=false;}}else{if(m.disabled){k=false;}}}}break;case&quot;a&quot;:k=j.fireEvent(&quot;linkClickEvent&quot;,{target:m,event:l});break;case&quot;button&quot;:if(!m.disabled){k=j.fireEvent(&quot;buttonClickEvent&quot;,{target:m,event:l});}else{k=false;}break;case&quot;td&quot;:k=j.fireEvent(&quot;cellClickEv
 ent&quot;,{target:m,event:l});break;case&quot;tr&quot;:k=j.fireEvent(&quot;rowClickEvent&quot;,{target:m,event:l});break;default:break;}if(k===false){return;}else{m=m.parentNode;if(m){i=m.nodeName.toLowerCase();}}}j.fireEvent(&quot;tableClickEvent&quot;,{target:(m||j._elContainer),event:l});},_onDropdownChange:function(j,i){var k=g.getTarget(j);i.fireEvent(&quot;dropdownChangeEvent&quot;,{event:j,target:k});},configs:null,getId:function(){return this._sId;},toString:function(){return&quot;DataTable instance &quot;+this._sId;},getDataSource:function(){return this._oDataSource;},getColumnSet:function(){return this._oColumnSet;},getRecordSet:function(){return this._oRecordSet;},getState:function(){return{totalRecords:this.get(&quot;paginator&quot;)?this.get(&quot;paginator&quot;).get(&quot;totalRecords&quot;):this._oRecordSet.getLength(),pagination:this.get(&quot;paginator&quot;)?this.get(&quot;paginator&quot;).getState():null,sortedBy:this.get(&quot;sortedBy&quot;),selectedRow
 s:this.getSelectedRows(),selectedCells:this.getSelectedCells()};},getContainerEl:function(){return this._elContainer;},getTableEl:function(){return this._elTable;},getTheadEl:function(){return this._elThead;},getTbodyEl:function(){return this._elTbody;},getMsgTbodyEl:function(){return this._elMsgTbody;},getMsgTdEl:function(){return this._elMsgTd;},getTrEl:function(k){if(k instanceof YAHOO.widget.Record){return document.getElementById(k.getId());}else{if(h.isNumber(k)){var j=c.getElementsByClassName(d.CLASS_REC,&quot;tr&quot;,this._elTbody);return j&amp;&amp;j[k]?j[k]:null;}else{if(k){var i=(h.isString(k))?document.getElementById(k):k;if(i&amp;&amp;i.ownerDocument==document){if(i.nodeName.toLowerCase()!=&quot;tr&quot;){i=c.getAncestorByTagName(i,&quot;tr&quot;);}return i;}}}}return null;},getFirstTrEl:function(){var k=this._elTbody.rows,j=0;while(k[j]){if(this.getRecord(k[j])){return k[j];}j++;}return null;},getLastTrEl:function(){var k=this._elTbody.rows,j=k.length-1;while(j
 &gt;-1){if(this.getRecord(k[j])){return k[j];}j--;}return null;},getNextTrEl:function(l,i){var j=this.getTrIndex(l);if(j!==null){var k=this._elTbody.rows;if(i){while(j&lt;k.length-1){l=k[j+1];if(this.getRecord(l)){return l;}j++;}}else{if(j&lt;k.length-1){return k[j+1];}}}return null;},getPreviousTrEl:function(l,i){var j=this.getTrIndex(l);if(j!==null){var k=this._elTbody.rows;if(i){while(j&gt;0){l=k[j-1];if(this.getRecord(l)){return l;}j--;}}else{if(j&gt;0){return k[j-1];}}}return null;},getCellIndex:function(k){k=this.getTdEl(k);if(k){if(b.ie&gt;0){var l=0,n=k.parentNode,m=n.childNodes,j=m.length;for(;l&lt;j;l++){if(m[l]==k){return l;}}}else{return k.cellIndex;}}},getTdLinerEl:function(i){var j=this.getTdEl(i);return j.firstChild||null;},getTdEl:function(i){var n;var l=c.get(i);if(l&amp;&amp;(l.ownerDocument==document)){if(l.nodeName.toLowerCase()!=&quot;td&quot;){n=c.getAncestorByTagName(l,&quot;td&quot;);}else{n=l;}if(n&amp;&amp;((n.parentNode.parentNode==this._elTbody)||
 (n.parentNode.parentNode===null)||(n.parentNode.parentNode.nodeType===11))){return n;}}else{if(i){var m,k;if(h.isString(i.columnKey)&amp;&amp;h.isString(i.recordId)){m=this.getRecord(i.recordId);var o=this.getColumn(i.columnKey);if(o){k=o.getKeyIndex();}}if(i.record&amp;&amp;i.column&amp;&amp;i.column.getKeyIndex){m=i.record;k=i.column.getKeyIndex();}var j=this.getTrEl(m);if((k!==null)&amp;&amp;j&amp;&amp;j.cells&amp;&amp;j.cells.length&gt;0){return j.cells[k]||null;}}}return null;},getFirstTdEl:function(j){var i=h.isValue(j)?this.getTrEl(j):this.getFirstTrEl();if(i){if(i.cells&amp;&amp;i.cells.length&gt;0){return i.cells[0];}else{if(i.childNodes&amp;&amp;i.childNodes.length&gt;0){return i.childNodes[0];}}}return null;},getLastTdEl:function(j){var i=h.isValue(j)?this.getTrEl(j):this.getLastTrEl();if(i){if(i.cells&amp;&amp;i.cells.length&gt;0){return i.cells[i.cells.length-1];}else{if(i.childNodes&amp;&amp;i.childNodes.length&gt;0){return i.childNodes[i.childNodes.length-1];}
 }}return null;},getNextTdEl:function(i){var m=this.getTdEl(i);if(m){var k=this.getCellIndex(m);var j=this.getTrEl(m);if(j.cells&amp;&amp;(j.cells.length)&gt;0&amp;&amp;(k&lt;j.cells.length-1)){return j.cells[k+1];}else{if(j.childNodes&amp;&amp;(j.childNodes.length)&gt;0&amp;&amp;(k&lt;j.childNodes.length-1)){return j.childNodes[k+1];}else{var l=this.getNextTrEl(j);if(l){return l.cells[0];}}}}return null;},getPreviousTdEl:function(i){var m=this.getTdEl(i);if(m){var k=this.getCellIndex(m);var j=this.getTrEl(m);if(k&gt;0){if(j.cells&amp;&amp;j.cells.length&gt;0){return j.cells[k-1];}else{if(j.childNodes&amp;&amp;j.childNodes.length&gt;0){return j.childNodes[k-1];}}}else{var l=this.getPreviousTrEl(j);if(l){return this.getLastTdEl(l);}}}return null;},getAboveTdEl:function(j,i){var m=this.getTdEl(j);if(m){var l=this.getPreviousTrEl(m,i);if(l){var k=this.getCellIndex(m);if(l.cells&amp;&amp;l.cells.length&gt;0){return l.cells[k]?l.cells[k]:null;}else{if(l.childNodes&amp;&amp;l.child
 Nodes.length&gt;0){return l.childNodes[k]?l.childNodes[k]:null;}}}}return null;},getBelowTdEl:function(j,i){var m=this.getTdEl(j);if(m){var l=this.getNextTrEl(m,i);if(l){var k=this.getCellIndex(m);if(l.cells&amp;&amp;l.cells.length&gt;0){return l.cells[k]?l.cells[k]:null;}else{if(l.childNodes&amp;&amp;l.childNodes.length&gt;0){return l.childNodes[k]?l.childNodes[k]:null;}}}}return null;},getThLinerEl:function(j){var i=this.getColumn(j);return(i)?i.getThLinerEl():null;},getThEl:function(k){var l;if(k instanceof YAHOO.widget.Column){var j=k;l=j.getThEl();if(l){return l;}}else{var i=c.get(k);if(i&amp;&amp;(i.ownerDocument==document)){if(i.nodeName.toLowerCase()!=&quot;th&quot;){l=c.getAncestorByTagName(i,&quot;th&quot;);
+}else{l=i;}return l;}}return null;},getTrIndex:function(m){var i=this.getRecord(m),k=this.getRecordIndex(i),l;if(i){l=this.getTrEl(i);if(l){return l.sectionRowIndex;}else{var j=this.get(&quot;paginator&quot;);if(j){return j.get(&quot;recordOffset&quot;)+k;}else{return k;}}}return null;},load:function(i){i=i||{};(i.datasource||this._oDataSource).sendRequest(i.request||this.get(&quot;initialRequest&quot;),i.callback||{success:this.onDataReturnInitializeTable,failure:this.onDataReturnInitializeTable,scope:this,argument:this.getState()});},initializeTable:function(){this._bInit=true;this._oRecordSet.reset();var i=this.get(&quot;paginator&quot;);if(i){i.set(&quot;totalRecords&quot;,0);}this._unselectAllTrEls();this._unselectAllTdEls();this._aSelections=null;this._oAnchorRecord=null;this._oAnchorCell=null;this.set(&quot;sortedBy&quot;,null);},_runRenderChain:function(){this._oChainRender.run();},_getViewRecords:function(){var i=this.get(&quot;paginator&quot;);if(i){return this._oR
 ecordSet.getRecords(i.getStartIndex(),i.getRowsPerPage());}else{return this._oRecordSet.getRecords();}},render:function(){this._oChainRender.stop();this.fireEvent(&quot;beforeRenderEvent&quot;);var r,p,o,s,l=this._getViewRecords();var m=this._elTbody,q=this.get(&quot;renderLoopSize&quot;),t=l.length;if(t&gt;0){m.style.display=&quot;none&quot;;while(m.lastChild){m.removeChild(m.lastChild);}m.style.display=&quot;&quot;;this._oChainRender.add({method:function(u){if((this instanceof d)&amp;&amp;this._sId){var k=u.nCurrentRecord,w=((u.nCurrentRecord+u.nLoopLength)&gt;t)?t:(u.nCurrentRecord+u.nLoopLength),j,v;m.style.display=&quot;none&quot;;for(;k&lt;w;k++){j=c.get(l[k].getId());j=j||this._addTrEl(l[k]);v=m.childNodes[k]||null;m.insertBefore(j,v);}m.style.display=&quot;&quot;;u.nCurrentRecord=k;}},scope:this,iterations:(q&gt;0)?Math.ceil(t/q):1,argument:{nCurrentRecord:0,nLoopLength:(q&gt;0)?q:t},timeout:(q&gt;0)?0:-1});this._oChainRender.add({method:function(i){if((this instance
 of d)&amp;&amp;this._sId){while(m.rows.length&gt;t){m.removeChild(m.lastChild);}this._setFirstRow();this._setLastRow();this._setRowStripes();this._setSelections();}},scope:this,timeout:(q&gt;0)?0:-1});}else{var n=m.rows.length;if(n&gt;0){this._oChainRender.add({method:function(k){if((this instanceof d)&amp;&amp;this._sId){var j=k.nCurrent,v=k.nLoopLength,u=(j-v&lt;0)?0:j-v;m.style.display=&quot;none&quot;;for(;j&gt;u;j--){m.deleteRow(-1);}m.style.display=&quot;&quot;;k.nCurrent=j;}},scope:this,iterations:(q&gt;0)?Math.ceil(n/q):1,argument:{nCurrent:n,nLoopLength:(q&gt;0)?q:n},timeout:(q&gt;0)?0:-1});}}this._runRenderChain();},disable:function(){this._disabled=true;var i=this._elTable;var j=this._elMask;j.style.width=i.offsetWidth+&quot;px&quot;;j.style.height=i.offsetHeight+&quot;px&quot;;j.style.left=i.offsetLeft+&quot;px&quot;;j.style.display=&quot;&quot;;this.fireEvent(&quot;disableEvent&quot;);},undisable:function(){this._disabled=false;this._elMask.style.display=&quot;n
 one&quot;;this.fireEvent(&quot;undisableEvent&quot;);},isDisabled:function(){return this._disabled;},destroy:function(){var k=this.toString();this._oChainRender.stop();this._destroyColumnHelpers();var m;for(var l=0,j=this._oColumnSet.flat.length;l&lt;j;l++){m=this._oColumnSet.flat[l].editor;if(m&amp;&amp;m.destroy){m.destroy();this._oColumnSet.flat[l].editor=null;}}this._destroyPaginator();this._oRecordSet.unsubscribeAll();this.unsubscribeAll();g.removeListener(document,&quot;click&quot;,this._onDocumentClick);this._destroyContainerEl(this._elContainer);for(var n in this){if(h.hasOwnProperty(this,n)){this[n]=null;}}d._nCurrentCount--;if(d._nCurrentCount&lt;1){if(d._elDynStyleNode){document.getElementsByTagName(&quot;head&quot;)[0].removeChild(d._elDynStyleNode);d._elDynStyleNode=null;}}},showTableMessage:function(j,i){var k=this._elMsgTd;if(h.isString(j)){k.firstChild.innerHTML=j;}if(h.isString(i)){k.className=i;}this._elMsgTbody.style.display=&quot;&quot;;this.fireEvent(&qu
 ot;tableMsgShowEvent&quot;,{html:j,className:i});},hideTableMessage:function(){if(this._elMsgTbody.style.display!=&quot;none&quot;){this._elMsgTbody.style.display=&quot;none&quot;;this._elMsgTbody.parentNode.style.width=&quot;&quot;;this.fireEvent(&quot;tableMsgHideEvent&quot;);}},focus:function(){this.focusTbodyEl();},focusTheadEl:function(){this._focusEl(this._elThead);},focusTbodyEl:function(){this._focusEl(this._elTbody);},onShow:function(){this.validateColumnWidths();for(var m=this._oColumnSet.keys,l=0,j=m.length,k;l&lt;j;l++){k=m[l];if(k._ddResizer){k._ddResizer.resetResizerEl();}}},getRecordIndex:function(l){var k;if(!h.isNumber(l)){if(l instanceof YAHOO.widget.Record){return this._oRecordSet.getRecordIndex(l);}else{var j=this.getTrEl(l);if(j){k=j.sectionRowIndex;}}}else{k=l;}if(h.isNumber(k)){var i=this.get(&quot;paginator&quot;);if(i){return i.get(&quot;recordOffset&quot;)+k;}else{return k;}}return null;},getRecord:function(k){var j=this._oRecordSet.getRecord(k);if(
 !j){var i=this.getTrEl(k);if(i){j=this._oRecordSet.getRecord(i.id);}}if(j instanceof YAHOO.widget.Record){return this._oRecordSet.getRecord(j);}else{return null;}},getColumn:function(m){var o=this._oColumnSet.getColumn(m);if(!o){var n=this.getTdEl(m);if(n){o=this._oColumnSet.getColumn(this.getCellIndex(n));}else{n=this.getThEl(m);if(n){var k=this._oColumnSet.flat;for(var l=0,j=k.length;l&lt;j;l++){if(k[l].getThEl().id===n.id){o=k[l];}}}}}if(!o){}return o;},getColumnById:function(i){return this._oColumnSet.getColumnById(i);},getColumnSortDir:function(k,l){if(k.sortOptions&amp;&amp;k.sortOptions.defaultDir){if(k.sortOptions.defaultDir==&quot;asc&quot;){k.sortOptions.defaultDir=d.CLASS_ASC;}else{if(k.sortOptions.defaultDir==&quot;desc&quot;){k.sortOptions.defaultDir=d.CLASS_DESC;}}}var j=(k.sortOptions&amp;&amp;k.sortOptions.defaultDir)?k.sortOptions.defaultDir:d.CLASS_ASC;var i=false;l=l||this.get(&quot;sortedBy&quot;);if(l&amp;&amp;(l.key===k.key)){i=true;if(l.dir){j=(l.dir==
 =d.CLASS_ASC)?d.CLASS_DESC:d.CLASS_ASC;}else{j=(j===d.CLASS_ASC)?d.CLASS_DESC:d.CLASS_ASC;}}return j;},doBeforeSortColumn:function(j,i){this.showTableMessage(this.get(&quot;MSG_LOADING&quot;),d.CLASS_LOADING);return true;},sortColumn:function(m,j){if(m&amp;&amp;(m instanceof YAHOO.widget.Column)){if(!m.sortable){c.addClass(this.getThEl(m),d.CLASS_SORTABLE);}if(j&amp;&amp;(j!==d.CLASS_ASC)&amp;&amp;(j!==d.CLASS_DESC)){j=null;}var n=j||this.getColumnSortDir(m);var l=this.get(&quot;sortedBy&quot;)||{};var t=(l.key===m.key)?true:false;var p=this.doBeforeSortColumn(m,n);
+if(p){if(this.get(&quot;dynamicData&quot;)){var s=this.getState();if(s.pagination){s.pagination.recordOffset=0;}s.sortedBy={key:m.key,dir:n};var k=this.get(&quot;generateRequest&quot;)(s,this);this.unselectAllRows();this.unselectAllCells();var r={success:this.onDataReturnSetRows,failure:this.onDataReturnSetRows,argument:s,scope:this};this._oDataSource.sendRequest(k,r);}else{var i=(m.sortOptions&amp;&amp;h.isFunction(m.sortOptions.sortFunction))?m.sortOptions.sortFunction:null;if(!t||j||i){i=i||this.get(&quot;sortFunction&quot;);var q=(m.sortOptions&amp;&amp;m.sortOptions.field)?m.sortOptions.field:m.field;this._oRecordSet.sortRecords(i,((n==d.CLASS_DESC)?true:false),q);}else{this._oRecordSet.reverseRecords();}var o=this.get(&quot;paginator&quot;);if(o){o.setPage(1,true);}this.render();this.set(&quot;sortedBy&quot;,{key:m.key,dir:n,column:m});}this.fireEvent(&quot;columnSortEvent&quot;,{column:m,dir:n});return;}}},setColumnWidth:function(j,i){if(!(j instanceof YAHOO.widget.Co
 lumn)){j=this.getColumn(j);}if(j){if(h.isNumber(i)){i=(i&gt;j.minWidth)?i:j.minWidth;j.width=i;this._setColumnWidth(j,i+&quot;px&quot;);this.fireEvent(&quot;columnSetWidthEvent&quot;,{column:j,width:i});}else{if(i===null){j.width=i;this._setColumnWidth(j,&quot;auto&quot;);this.validateColumnWidths(j);this.fireEvent(&quot;columnUnsetWidthEvent&quot;,{column:j});}}this._clearTrTemplateEl();}else{}},_setColumnWidth:function(j,i,k){if(j&amp;&amp;(j.getKeyIndex()!==null)){k=k||(((i===&quot;&quot;)||(i===&quot;auto&quot;))?&quot;visible&quot;:&quot;hidden&quot;);if(!d._bDynStylesFallback){this._setColumnWidthDynStyles(j,i,k);}else{this._setColumnWidthDynFunction(j,i,k);}}else{}},_setColumnWidthDynStyles:function(m,l,n){var j=d._elDynStyleNode,k;if(!j){j=document.createElement(&quot;style&quot;);j.type=&quot;text/css&quot;;j=document.getElementsByTagName(&quot;head&quot;).item(0).appendChild(j);d._elDynStyleNode=j;}if(j){var i=&quot;.&quot;+this.getId()+&quot;-col-&quot;+m.getSanit
 izedKey()+&quot; .&quot;+d.CLASS_LINER;if(this._elTbody){this._elTbody.style.display=&quot;none&quot;;}k=d._oDynStyles[i];if(!k){if(j.styleSheet&amp;&amp;j.styleSheet.addRule){j.styleSheet.addRule(i,&quot;overflow:&quot;+n);j.styleSheet.addRule(i,&quot;width:&quot;+l);k=j.styleSheet.rules[j.styleSheet.rules.length-1];d._oDynStyles[i]=k;}else{if(j.sheet&amp;&amp;j.sheet.insertRule){j.sheet.insertRule(i+&quot; {overflow:&quot;+n+&quot;;width:&quot;+l+&quot;;}&quot;,j.sheet.cssRules.length);k=j.sheet.cssRules[j.sheet.cssRules.length-1];d._oDynStyles[i]=k;}}}else{k.style.overflow=n;k.style.width=l;}if(this._elTbody){this._elTbody.style.display=&quot;&quot;;}}if(!k){d._bDynStylesFallback=true;this._setColumnWidthDynFunction(m,l);}},_setColumnWidthDynFunction:function(r,m,s){if(m==&quot;auto&quot;){m=&quot;&quot;;}var l=this._elTbody?this._elTbody.rows.length:0;if(!this._aDynFunctions[l]){var q,p,o;var t=[&quot;var colIdx=oColumn.getKeyIndex();&quot;,&quot;oColumn.getThLinerEl().s
 tyle.overflow=&quot;];for(q=l-1,p=2;q&gt;=0;--q){t[p++]=&quot;this._elTbody.rows[&quot;;t[p++]=q;t[p++]=&quot;].cells[colIdx].firstChild.style.overflow=&quot;;}t[p]=&quot;sOverflow;&quot;;t[p+1]=&quot;oColumn.getThLinerEl().style.width=&quot;;for(q=l-1,o=p+2;q&gt;=0;--q){t[o++]=&quot;this._elTbody.rows[&quot;;t[o++]=q;t[o++]=&quot;].cells[colIdx].firstChild.style.width=&quot;;}t[o]=&quot;sWidth;&quot;;this._aDynFunctions[l]=new Function(&quot;oColumn&quot;,&quot;sWidth&quot;,&quot;sOverflow&quot;,t.join(&quot;&quot;));}var n=this._aDynFunctions[l];if(n){n.call(this,r,m,s);}},validateColumnWidths:function(o){var l=this._elColgroup;var q=l.cloneNode(true);var p=false;var n=this._oColumnSet.keys;var k;if(o&amp;&amp;!o.hidden&amp;&amp;!o.width&amp;&amp;(o.getKeyIndex()!==null)){k=o.getThLinerEl();if((o.minWidth&gt;0)&amp;&amp;(k.offsetWidth&lt;o.minWidth)){q.childNodes[o.getKeyIndex()].style.width=o.minWidth+(parseInt(c.getStyle(k,&quot;paddingLeft&quot;),10)|0)+(parseInt(c.getS
 tyle(k,&quot;paddingRight&quot;),10)|0)+&quot;px&quot;;p=true;}else{if((o.maxAutoWidth&gt;0)&amp;&amp;(k.offsetWidth&gt;o.maxAutoWidth)){this._setColumnWidth(o,o.maxAutoWidth+&quot;px&quot;,&quot;hidden&quot;);}}}else{for(var m=0,j=n.length;m&lt;j;m++){o=n[m];if(!o.hidden&amp;&amp;!o.width){k=o.getThLinerEl();if((o.minWidth&gt;0)&amp;&amp;(k.offsetWidth&lt;o.minWidth)){q.childNodes[m].style.width=o.minWidth+(parseInt(c.getStyle(k,&quot;paddingLeft&quot;),10)|0)+(parseInt(c.getStyle(k,&quot;paddingRight&quot;),10)|0)+&quot;px&quot;;p=true;}else{if((o.maxAutoWidth&gt;0)&amp;&amp;(k.offsetWidth&gt;o.maxAutoWidth)){this._setColumnWidth(o,o.maxAutoWidth+&quot;px&quot;,&quot;hidden&quot;);}}}}}if(p){l.parentNode.replaceChild(q,l);this._elColgroup=q;}},_clearMinWidth:function(i){if(i.getKeyIndex()!==null){this._elColgroup.childNodes[i.getKeyIndex()].style.width=&quot;&quot;;}},_restoreMinWidth:function(i){if(i.minWidth&amp;&amp;(i.getKeyIndex()!==null)){this._elColgroup.childNodes[
 i.getKeyIndex()].style.width=i.minWidth+&quot;px&quot;;}},hideColumn:function(r){if(!(r instanceof YAHOO.widget.Column)){r=this.getColumn(r);}if(r&amp;&amp;!r.hidden&amp;&amp;r.getTreeIndex()!==null){var o=this.getTbodyEl().rows;var n=o.length;var m=this._oColumnSet.getDescendants(r);for(var q=0,s=m.length;q&lt;s;q++){var t=m[q];t.hidden=true;c.addClass(t.getThEl(),d.CLASS_HIDDEN);var k=t.getKeyIndex();if(k!==null){this._clearMinWidth(r);for(var p=0;p&lt;n;p++){c.addClass(o[p].cells[k],d.CLASS_HIDDEN);}}this.fireEvent(&quot;columnHideEvent&quot;,{column:t});}this._repaintOpera();this._clearTrTemplateEl();}else{}},showColumn:function(r){if(!(r instanceof YAHOO.widget.Column)){r=this.getColumn(r);}if(r&amp;&amp;r.hidden&amp;&amp;(r.getTreeIndex()!==null)){var o=this.getTbodyEl().rows;var n=o.length;var m=this._oColumnSet.getDescendants(r);for(var q=0,s=m.length;q&lt;s;q++){var t=m[q];t.hidden=false;c.removeClass(t.getThEl(),d.CLASS_HIDDEN);var k=t.getKeyIndex();if(k!==null){th
 is._restoreMinWidth(r);for(var p=0;p&lt;n;p++){c.removeClass(o[p].cells[k],d.CLASS_HIDDEN);}}this.fireEvent(&quot;columnShowEvent&quot;,{column:t});}this._clearTrTemplateEl();}else{}},removeColumn:function(p){if(!(p instanceof YAHOO.widget.Column)){p=this.getColumn(p);}if(p){var m=p.getTreeIndex();if(m!==null){var o,r,q=p.getKeyIndex();if(q===null){var u=[];var j=this._oColumnSet.getDescendants(p);for(o=0,r=j.length;o&lt;r;o++){var s=j[o].getKeyIndex();if(s!==null){u[u.length]=s;}}if(u.length&gt;0){q=u;}}else{q=[q];}if(q!==null){q.sort(function(v,i){return YAHOO.util.Sort.compare(v,i);});this._destroyTheadEl();var k=this._oColumnSet.getDefinitions();p=k.splice(m,1)[0];this._initColumnSet(k);this._initTheadEl();for(o=q.length-1;o&gt;-1;o--){this._removeColgroupColEl(q[o]);}var t=this._elTbody.rows;if(t.length&gt;0){var n=this.get(&quot;renderLoopSize&quot;),l=t.length;
+this._oChainRender.add({method:function(y){if((this instanceof d)&amp;&amp;this._sId){var x=y.nCurrentRow,v=n&gt;0?Math.min(x+n,t.length):t.length,z=y.aIndexes,w;for(;x&lt;v;++x){for(w=z.length-1;w&gt;-1;w--){t[x].removeChild(t[x].childNodes[z[w]]);}}y.nCurrentRow=x;}},iterations:(n&gt;0)?Math.ceil(l/n):1,argument:{nCurrentRow:0,aIndexes:q},scope:this,timeout:(n&gt;0)?0:-1});this._runRenderChain();}this.fireEvent(&quot;columnRemoveEvent&quot;,{column:p});return p;}}}},insertColumn:function(r,s){if(r instanceof YAHOO.widget.Column){r=r.getDefinition();}else{if(r.constructor!==Object){return;}}var x=this._oColumnSet;if(!h.isValue(s)||!h.isNumber(s)){s=x.tree[0].length;}this._destroyTheadEl();var z=this._oColumnSet.getDefinitions();z.splice(s,0,r);this._initColumnSet(z);this._initTheadEl();x=this._oColumnSet;var n=x.tree[0][s];var p,t,w=[];var l=x.getDescendants(n);for(p=0,t=l.length;p&lt;t;p++){var u=l[p].getKeyIndex();if(u!==null){w[w.length]=u;}}if(w.length&gt;0){var y=w.sor
 t(function(A,i){return YAHOO.util.Sort.compare(A,i);})[0];for(p=w.length-1;p&gt;-1;p--){this._insertColgroupColEl(w[p]);}var v=this._elTbody.rows;if(v.length&gt;0){var o=this.get(&quot;renderLoopSize&quot;),m=v.length;var k=[],q;for(p=0,t=w.length;p&lt;t;p++){var j=w[p];q=this._getTrTemplateEl().childNodes[p].cloneNode(true);q=this._formatTdEl(this._oColumnSet.keys[j],q,j,(j===this._oColumnSet.keys.length-1));k[j]=q;}this._oChainRender.add({method:function(D){if((this instanceof d)&amp;&amp;this._sId){var C=D.nCurrentRow,B,F=D.descKeyIndexes,A=o&gt;0?Math.min(C+o,v.length):v.length,E;for(;C&lt;A;++C){E=v[C].childNodes[y]||null;for(B=F.length-1;B&gt;-1;B--){v[C].insertBefore(D.aTdTemplates[F[B]].cloneNode(true),E);}}D.nCurrentRow=C;}},iterations:(o&gt;0)?Math.ceil(m/o):1,argument:{nCurrentRow:0,aTdTemplates:k,descKeyIndexes:w},scope:this,timeout:(o&gt;0)?0:-1});this._runRenderChain();}this.fireEvent(&quot;columnInsertEvent&quot;,{column:r,index:s});return n;}},reorderColumn:f
 unction(q,r){if(!(q instanceof YAHOO.widget.Column)){q=this.getColumn(q);}if(q&amp;&amp;YAHOO.lang.isNumber(r)){var z=q.getTreeIndex();if((z!==null)&amp;&amp;(z!==r)){var p,s,l=q.getKeyIndex(),k,v=[],t;if(l===null){k=this._oColumnSet.getDescendants(q);for(p=0,s=k.length;p&lt;s;p++){t=k[p].getKeyIndex();if(t!==null){v[v.length]=t;}}if(v.length&gt;0){l=v;}}else{l=[l];}if(l!==null){l.sort(function(A,i){return YAHOO.util.Sort.compare(A,i);});this._destroyTheadEl();var w=this._oColumnSet.getDefinitions();var j=w.splice(z,1)[0];w.splice(r,0,j);this._initColumnSet(w);this._initTheadEl();var n=this._oColumnSet.tree[0][r];var y=n.getKeyIndex();if(y===null){v=[];k=this._oColumnSet.getDescendants(n);for(p=0,s=k.length;p&lt;s;p++){t=k[p].getKeyIndex();if(t!==null){v[v.length]=t;}}if(v.length&gt;0){y=v;}}else{y=[y];}var x=y.sort(function(A,i){return YAHOO.util.Sort.compare(A,i);})[0];this._reorderColgroupColEl(l,x);var u=this._elTbody.rows;if(u.length&gt;0){var o=this.get(&quot;renderLoo
 pSize&quot;),m=u.length;this._oChainRender.add({method:function(D){if((this instanceof d)&amp;&amp;this._sId){var C=D.nCurrentRow,B,F,E,A=o&gt;0?Math.min(C+o,u.length):u.length,H=D.aIndexes,G;for(;C&lt;A;++C){F=[];G=u[C];for(B=H.length-1;B&gt;-1;B--){F.push(G.removeChild(G.childNodes[H[B]]));}E=G.childNodes[x]||null;for(B=F.length-1;B&gt;-1;B--){G.insertBefore(F[B],E);}}D.nCurrentRow=C;}},iterations:(o&gt;0)?Math.ceil(m/o):1,argument:{nCurrentRow:0,aIndexes:l},scope:this,timeout:(o&gt;0)?0:-1});this._runRenderChain();}this.fireEvent(&quot;columnReorderEvent&quot;,{column:n,oldIndex:z});return n;}}}},selectColumn:function(k){k=this.getColumn(k);if(k&amp;&amp;!k.selected){if(k.getKeyIndex()!==null){k.selected=true;var l=k.getThEl();c.addClass(l,d.CLASS_SELECTED);var j=this.getTbodyEl().rows;var i=this._oChainRender;i.add({method:function(m){if((this instanceof d)&amp;&amp;this._sId&amp;&amp;j[m.rowIndex]&amp;&amp;j[m.rowIndex].cells[m.cellIndex]){c.addClass(j[m.rowIndex].cells
 [m.cellIndex],d.CLASS_SELECTED);}m.rowIndex++;},scope:this,iterations:j.length,argument:{rowIndex:0,cellIndex:k.getKeyIndex()}});this._clearTrTemplateEl();this._elTbody.style.display=&quot;none&quot;;this._runRenderChain();this._elTbody.style.display=&quot;&quot;;this.fireEvent(&quot;columnSelectEvent&quot;,{column:k});}else{}}},unselectColumn:function(k){k=this.getColumn(k);if(k&amp;&amp;k.selected){if(k.getKeyIndex()!==null){k.selected=false;var l=k.getThEl();c.removeClass(l,d.CLASS_SELECTED);var j=this.getTbodyEl().rows;var i=this._oChainRender;i.add({method:function(m){if((this instanceof d)&amp;&amp;this._sId&amp;&amp;j[m.rowIndex]&amp;&amp;j[m.rowIndex].cells[m.cellIndex]){c.removeClass(j[m.rowIndex].cells[m.cellIndex],d.CLASS_SELECTED);}m.rowIndex++;},scope:this,iterations:j.length,argument:{rowIndex:0,cellIndex:k.getKeyIndex()}});this._clearTrTemplateEl();this._elTbody.style.display=&quot;none&quot;;this._runRenderChain();this._elTbody.style.display=&quot;&quot;;this
 .fireEvent(&quot;columnUnselectEvent&quot;,{column:k});}else{}}},getSelectedColumns:function(n){var k=[];var l=this._oColumnSet.keys;for(var m=0,j=l.length;m&lt;j;m++){if(l[m].selected){k[k.length]=l[m];}}return k;},highlightColumn:function(i){var l=this.getColumn(i);if(l&amp;&amp;(l.getKeyIndex()!==null)){var m=l.getThEl();c.addClass(m,d.CLASS_HIGHLIGHTED);var k=this.getTbodyEl().rows;var j=this._oChainRender;j.add({method:function(n){if((this instanceof d)&amp;&amp;this._sId&amp;&amp;k[n.rowIndex]&amp;&amp;k[n.rowIndex].cells[n.cellIndex]){c.addClass(k[n.rowIndex].cells[n.cellIndex],d.CLASS_HIGHLIGHTED);}n.rowIndex++;},scope:this,iterations:k.length,argument:{rowIndex:0,cellIndex:l.getKeyIndex()},timeout:-1});this._elTbody.style.display=&quot;none&quot;;this._runRenderChain();this._elTbody.style.display=&quot;&quot;;this.fireEvent(&quot;columnHighlightEvent&quot;,{column:l});}else{}},unhighlightColumn:function(i){var l=this.getColumn(i);if(l&amp;&amp;(l.getKeyIndex()!==nul
 l)){var m=l.getThEl();c.removeClass(m,d.CLASS_HIGHLIGHTED);var k=this.getTbodyEl().rows;var j=this._oChainRender;j.add({method:function(n){if((this instanceof d)&amp;&amp;this._sId&amp;&amp;k[n.rowIndex]&amp;&amp;k[n.rowIndex].cells[n.cellIndex]){c.removeClass(k[n.rowIndex].cells[n.cellIndex],d.CLASS_HIGHLIGHTED);}n.rowIndex++;},scope:this,iterations:k.length,argument:{rowIndex:0,cellIndex:l.getKeyIndex()},timeout:-1});this._elTbody.style.display=&quot;none&quot;;
+this._runRenderChain();this._elTbody.style.display=&quot;&quot;;this.fireEvent(&quot;columnUnhighlightEvent&quot;,{column:l});}else{}},addRow:function(o,k){if(h.isNumber(k)&amp;&amp;(k&lt;0||k&gt;this._oRecordSet.getLength())){return;}if(o&amp;&amp;h.isObject(o)){var m=this._oRecordSet.addRecord(o,k);if(m){var i;var j=this.get(&quot;paginator&quot;);if(j){var n=j.get(&quot;totalRecords&quot;);if(n!==e.Paginator.VALUE_UNLIMITED){j.set(&quot;totalRecords&quot;,n+1);}i=this.getRecordIndex(m);var l=(j.getPageRecords())[1];if(i&lt;=l){this.render();}this.fireEvent(&quot;rowAddEvent&quot;,{record:m});return;}else{i=this.getRecordIndex(m);if(h.isNumber(i)){this._oChainRender.add({method:function(r){if((this instanceof d)&amp;&amp;this._sId){var s=r.record;var p=r.recIndex;var t=this._addTrEl(s);if(t){var q=(this._elTbody.rows[p])?this._elTbody.rows[p]:null;this._elTbody.insertBefore(t,q);if(p===0){this._setFirstRow();}if(q===null){this._setLastRow();}this._setRowStripes();this.hide
 TableMessage();this.fireEvent(&quot;rowAddEvent&quot;,{record:s});}}},argument:{record:m,recIndex:i},scope:this,timeout:(this.get(&quot;renderLoopSize&quot;)&gt;0)?0:-1});this._runRenderChain();return;}}}}},addRows:function(k,n){if(h.isNumber(n)&amp;&amp;(n&lt;0||n&gt;this._oRecordSet.getLength())){return;}if(h.isArray(k)){var o=this._oRecordSet.addRecords(k,n);if(o){var s=this.getRecordIndex(o[0]);var r=this.get(&quot;paginator&quot;);if(r){var p=r.get(&quot;totalRecords&quot;);if(p!==e.Paginator.VALUE_UNLIMITED){r.set(&quot;totalRecords&quot;,p+o.length);}var q=(r.getPageRecords())[1];if(s&lt;=q){this.render();}this.fireEvent(&quot;rowsAddEvent&quot;,{records:o});return;}else{var m=this.get(&quot;renderLoopSize&quot;);var j=s+k.length;var i=(j-s);var l=(s&gt;=this._elTbody.rows.length);this._oChainRender.add({method:function(x){if((this instanceof d)&amp;&amp;this._sId){var y=x.aRecords,w=x.nCurrentRow,v=x.nCurrentRecord,t=m&gt;0?Math.min(w+m,j):j,z=document.createDocument
 Fragment(),u=(this._elTbody.rows[w])?this._elTbody.rows[w]:null;for(;w&lt;t;w++,v++){z.appendChild(this._addTrEl(y[v]));}this._elTbody.insertBefore(z,u);x.nCurrentRow=w;x.nCurrentRecord=v;}},iterations:(m&gt;0)?Math.ceil(j/m):1,argument:{nCurrentRow:s,nCurrentRecord:0,aRecords:o},scope:this,timeout:(m&gt;0)?0:-1});this._oChainRender.add({method:function(u){var t=u.recIndex;if(t===0){this._setFirstRow();}if(u.isLast){this._setLastRow();}this._setRowStripes();this.fireEvent(&quot;rowsAddEvent&quot;,{records:o});},argument:{recIndex:s,isLast:l},scope:this,timeout:-1});this._runRenderChain();this.hideTableMessage();return;}}}},updateRow:function(u,k){var r=u;if(!h.isNumber(r)){r=this.getRecordIndex(u);}if(h.isNumber(r)&amp;&amp;(r&gt;=0)){var s=this._oRecordSet,q=s.getRecord(r);if(q){var o=this._oRecordSet.setRecord(k,r),j=this.getTrEl(q),p=q?q.getData():null;if(o){var t=this._aSelections||[],n=0,l=q.getId(),m=o.getId();for(;n&lt;t.length;n++){if((t[n]===l)){t[n]=m;}else{if(t[n]
 .recordId===l){t[n].recordId=m;}}}if(this._oAnchorRecord&amp;&amp;this._oAnchorRecord.getId()===l){this._oAnchorRecord=o;}if(this._oAnchorCell&amp;&amp;this._oAnchorCell.record.getId()===l){this._oAnchorCell.record=o;}this._oChainRender.add({method:function(){if((this instanceof d)&amp;&amp;this._sId){var v=this.get(&quot;paginator&quot;);if(v){var i=(v.getPageRecords())[0],w=(v.getPageRecords())[1];if((r&gt;=i)||(r&lt;=w)){this.render();}}else{if(j){this._updateTrEl(j,o);}else{this.getTbodyEl().appendChild(this._addTrEl(o));}}this.fireEvent(&quot;rowUpdateEvent&quot;,{record:o,oldData:p});}},scope:this,timeout:(this.get(&quot;renderLoopSize&quot;)&gt;0)?0:-1});this._runRenderChain();return;}}}return;},updateRows:function(A,m){if(h.isArray(m)){var s=A,l=this._oRecordSet,o=l.getLength();if(!h.isNumber(A)){s=this.getRecordIndex(A);}if(h.isNumber(s)&amp;&amp;(s&gt;=0)&amp;&amp;(s&lt;l.getLength())){var E=s+m.length,B=l.getRecords(s,m.length),G=l.setRecords(m,s);if(G){var t=this
 ._aSelections||[],D=0,C,u,x,z,y=this._oAnchorRecord?this._oAnchorRecord.getId():null,n=this._oAnchorCell?this._oAnchorCell.record.getId():null;for(;D&lt;B.length;D++){z=B[D].getId();u=G[D];x=u.getId();for(C=0;C&lt;t.length;C++){if((t[C]===z)){t[C]=x;}else{if(t[C].recordId===z){t[C].recordId=x;}}}if(y&amp;&amp;y===z){this._oAnchorRecord=u;}if(n&amp;&amp;n===z){this._oAnchorCell.record=u;}}var F=this.get(&quot;paginator&quot;);if(F){var r=(F.getPageRecords())[0],p=(F.getPageRecords())[1];if((s&gt;=r)||(E&lt;=p)){this.render();}this.fireEvent(&quot;rowsAddEvent&quot;,{newRecords:G,oldRecords:B});return;}else{var k=this.get(&quot;renderLoopSize&quot;),v=m.length,w=(E&gt;=o),q=(E&gt;o);this._oChainRender.add({method:function(K){if((this instanceof d)&amp;&amp;this._sId){var L=K.aRecords,J=K.nCurrentRow,I=K.nDataPointer,H=k&gt;0?Math.min(J+k,s+L.length):s+L.length;for(;J&lt;H;J++,I++){if(q&amp;&amp;(J&gt;=o)){this._elTbody.appendChild(this._addTrEl(L[I]));}else{this._updateTrEl(th
 is._elTbody.rows[J],L[I]);}}K.nCurrentRow=J;K.nDataPointer=I;}},iterations:(k&gt;0)?Math.ceil(v/k):1,argument:{nCurrentRow:s,aRecords:G,nDataPointer:0,isAdding:q},scope:this,timeout:(k&gt;0)?0:-1});this._oChainRender.add({method:function(j){var i=j.recIndex;if(i===0){this._setFirstRow();}if(j.isLast){this._setLastRow();}this._setRowStripes();this.fireEvent(&quot;rowsAddEvent&quot;,{newRecords:G,oldRecords:B});},argument:{recIndex:s,isLast:w},scope:this,timeout:-1});this._runRenderChain();this.hideTableMessage();return;}}}}},deleteRow:function(s){var k=(h.isNumber(s))?s:this.getRecordIndex(s);if(h.isNumber(k)){var t=this.getRecord(k);if(t){var m=this.getTrIndex(k);var p=t.getId();var r=this._aSelections||[];for(var n=r.length-1;n&gt;-1;n--){if((h.isString(r[n])&amp;&amp;(r[n]===p))||(h.isObject(r[n])&amp;&amp;(r[n].recordId===p))){r.splice(n,1);}}var l=this._oRecordSet.deleteRecord(k);if(l){var q=this.get(&quot;paginator&quot;);if(q){var o=q.get(&quot;totalRecords&quot;),i=q.
 getPageRecords();if(o!==e.Paginator.VALUE_UNLIMITED){q.set(&quot;totalRecords&quot;,o-1);}if(!i||k&lt;=i[1]){this.render();}this._oChainRender.add({method:function(){if((this instanceof d)&amp;&amp;this._sId){this.fireEvent(&quot;rowDeleteEvent&quot;,{recordIndex:k,oldData:l,trElIndex:m});}},scope:this,timeout:(this.get(&quot;renderLoopSize&quot;)&gt;0)?0:-1});this._runRenderChain();}else{if(h.isNumber(m)){this._oChainRender.add({method:function(){if((this instanceof d)&amp;&amp;this._sId){var j=(k===this._oRecordSet.getLength());this._deleteTrEl(m);if(this._elTbody.rows.length&gt;0){if(m===0){this._setFirstRow();
+}if(j){this._setLastRow();}if(m!=this._elTbody.rows.length){this._setRowStripes(m);}}this.fireEvent(&quot;rowDeleteEvent&quot;,{recordIndex:k,oldData:l,trElIndex:m});}},scope:this,timeout:(this.get(&quot;renderLoopSize&quot;)&gt;0)?0:-1});this._runRenderChain();return;}}}}}return null;},deleteRows:function(y,s){var l=(h.isNumber(y))?y:this.getRecordIndex(y);if(h.isNumber(l)){var z=this.getRecord(l);if(z){var m=this.getTrIndex(l);var u=z.getId();var x=this._aSelections||[];for(var q=x.length-1;q&gt;-1;q--){if((h.isString(x[q])&amp;&amp;(x[q]===u))||(h.isObject(x[q])&amp;&amp;(x[q].recordId===u))){x.splice(q,1);}}var n=l;var w=l;if(s&amp;&amp;h.isNumber(s)){n=(s&gt;0)?l+s-1:l;w=(s&gt;0)?l:l+s+1;s=(s&gt;0)?s:s*-1;if(w&lt;0){w=0;s=n-w+1;}}else{s=1;}var p=this._oRecordSet.deleteRecords(w,s);if(p){var v=this.get(&quot;paginator&quot;),r=this.get(&quot;renderLoopSize&quot;);if(v){var t=v.get(&quot;totalRecords&quot;),k=v.getPageRecords();if(t!==e.Paginator.VALUE_UNLIMITED){v.set(&q
 uot;totalRecords&quot;,t-p.length);}if(!k||w&lt;=k[1]){this.render();}this._oChainRender.add({method:function(j){if((this instanceof d)&amp;&amp;this._sId){this.fireEvent(&quot;rowsDeleteEvent&quot;,{recordIndex:w,oldData:p,count:s});}},scope:this,timeout:(r&gt;0)?0:-1});this._runRenderChain();return;}else{if(h.isNumber(m)){var o=w;var i=s;this._oChainRender.add({method:function(B){if((this instanceof d)&amp;&amp;this._sId){var A=B.nCurrentRow,j=(r&gt;0)?(Math.max(A-r,o)-1):o-1;for(;A&gt;j;--A){this._deleteTrEl(A);}B.nCurrentRow=A;}},iterations:(r&gt;0)?Math.ceil(s/r):1,argument:{nCurrentRow:n},scope:this,timeout:(r&gt;0)?0:-1});this._oChainRender.add({method:function(){if(this._elTbody.rows.length&gt;0){this._setFirstRow();this._setLastRow();this._setRowStripes();}this.fireEvent(&quot;rowsDeleteEvent&quot;,{recordIndex:w,oldData:p,count:s});},scope:this,timeout:-1});this._runRenderChain();return;}}}}}return null;},formatCell:function(j,l,m){if(!l){l=this.getRecord(j);}if(!m
 ){m=this.getColumn(this.getCellIndex(j.parentNode));}if(l&amp;&amp;m){var i=m.field;var n=l.getData(i);var k=typeof m.formatter===&quot;function&quot;?m.formatter:d.Formatter[m.formatter+&quot;&quot;]||d.Formatter.defaultFormatter;if(k){k.call(this,j,l,m,n);}else{j.innerHTML=n;}this.fireEvent(&quot;cellFormatEvent&quot;,{record:l,column:m,key:m.key,el:j});}else{}},updateCell:function(k,m,o,j){m=(m instanceof YAHOO.widget.Column)?m:this.getColumn(m);if(m&amp;&amp;m.getField()&amp;&amp;(k instanceof YAHOO.widget.Record)){var l=m.getField(),n=k.getData(l);this._oRecordSet.updateRecordValue(k,l,o);var i=this.getTdEl({record:k,column:m});if(i){this._oChainRender.add({method:function(){if((this instanceof d)&amp;&amp;this._sId){this.formatCell(i.firstChild,k,m);this.fireEvent(&quot;cellUpdateEvent&quot;,{record:k,column:m,oldData:n});}},scope:this,timeout:(this.get(&quot;renderLoopSize&quot;)&gt;0)?0:-1});if(!j){this._runRenderChain();}}else{this.fireEvent(&quot;cellUpdateEvent&qu
 ot;,{record:k,column:m,oldData:n});}}},_updatePaginator:function(j){var i=this.get(&quot;paginator&quot;);if(i&amp;&amp;j!==i){i.unsubscribe(&quot;changeRequest&quot;,this.onPaginatorChangeRequest,this,true);}if(j){j.subscribe(&quot;changeRequest&quot;,this.onPaginatorChangeRequest,this,true);}},_handlePaginatorChange:function(l){if(l.prevValue===l.newValue){return;}var n=l.newValue,m=l.prevValue,k=this._defaultPaginatorContainers();if(m){if(m.getContainerNodes()[0]==k[0]){m.set(&quot;containers&quot;,[]);}m.destroy();if(k[0]){if(n&amp;&amp;!n.getContainerNodes().length){n.set(&quot;containers&quot;,k);}else{for(var j=k.length-1;j&gt;=0;--j){if(k[j]){k[j].parentNode.removeChild(k[j]);}}}}}if(!this._bInit){this.render();}if(n){this.renderPaginator();}},_defaultPaginatorContainers:function(l){var j=this._sId+&quot;-paginator0&quot;,k=this._sId+&quot;-paginator1&quot;,i=c.get(j),m=c.get(k);if(l&amp;&amp;(!i||!m)){if(!i){i=document.createElement(&quot;div&quot;);i.id=j;c.addClas
 s(i,d.CLASS_PAGINATOR);this._elContainer.insertBefore(i,this._elContainer.firstChild);}if(!m){m=document.createElement(&quot;div&quot;);m.id=k;c.addClass(m,d.CLASS_PAGINATOR);this._elContainer.appendChild(m);}}return[i,m];},_destroyPaginator:function(){var i=this.get(&quot;paginator&quot;);if(i){i.destroy();}},renderPaginator:function(){var i=this.get(&quot;paginator&quot;);if(!i){return;}if(!i.getContainerNodes().length){i.set(&quot;containers&quot;,this._defaultPaginatorContainers(true));}i.render();},doBeforePaginatorChange:function(i){this.showTableMessage(this.get(&quot;MSG_LOADING&quot;),d.CLASS_LOADING);return true;},onPaginatorChangeRequest:function(l){var j=this.doBeforePaginatorChange(l);if(j){if(this.get(&quot;dynamicData&quot;)){var i=this.getState();i.pagination=l;var k=this.get(&quot;generateRequest&quot;)(i,this);this.unselectAllRows();this.unselectAllCells();var m={success:this.onDataReturnSetRows,failure:this.onDataReturnSetRows,argument:i,scope:this};this._
 oDataSource.sendRequest(k,m);}else{l.paginator.setStartIndex(l.recordOffset,true);l.paginator.setRowsPerPage(l.rowsPerPage,true);this.render();}}else{}},_elLastHighlightedTd:null,_aSelections:null,_oAnchorRecord:null,_oAnchorCell:null,_unselectAllTrEls:function(){var i=c.getElementsByClassName(d.CLASS_SELECTED,&quot;tr&quot;,this._elTbody);c.removeClass(i,d.CLASS_SELECTED);},_getSelectionTrigger:function(){var l=this.get(&quot;selectionMode&quot;);var k={};var o,i,j,n,m;if((l==&quot;cellblock&quot;)||(l==&quot;cellrange&quot;)||(l==&quot;singlecell&quot;)){o=this.getLastSelectedCell();if(!o){return null;}else{i=this.getRecord(o.recordId);j=this.getRecordIndex(i);n=this.getTrEl(i);m=this.getTrIndex(n);if(m===null){return null;}else{k.record=i;k.recordIndex=j;k.el=this.getTdEl(o);k.trIndex=m;k.column=this.getColumn(o.columnKey);k.colKeyIndex=k.column.getKeyIndex();k.cell=o;return k;}}}else{i=this.getLastSelectedRecord();if(!i){return null;}else{i=this.getRecord(i);j=this.getRe
 cordIndex(i);n=this.getTrEl(i);m=this.getTrIndex(n);if(m===null){return null;}else{k.record=i;k.recordIndex=j;k.el=n;k.trIndex=m;return k;}}}},_getSelectionAnchor:function(k){var j=this.get(&quot;selectionMode&quot;);var l={};var m,o,i;if((j==&quot;cellblock&quot;)||(j==&quot;cellrange&quot;)||(j==&quot;singlecell&quot;)){var n=this._oAnchorCell;if(!n){if(k){n=this._oAnchorCell=k.cell;}else{return null;}}m=this._oAnchorCell.record;o=this._oRecordSet.getRecordIndex(m);i=this.getTrIndex(m);if(i===null){if(o&lt;this.getRecordIndex(this.getFirstTrEl())){i=0;}else{i=this.getRecordIndex(this.getLastTrEl());
+}}l.record=m;l.recordIndex=o;l.trIndex=i;l.column=this._oAnchorCell.column;l.colKeyIndex=l.column.getKeyIndex();l.cell=n;return l;}else{m=this._oAnchorRecord;if(!m){if(k){m=this._oAnchorRecord=k.record;}else{return null;}}o=this.getRecordIndex(m);i=this.getTrIndex(m);if(i===null){if(o&lt;this.getRecordIndex(this.getFirstTrEl())){i=0;}else{i=this.getRecordIndex(this.getLastTrEl());}}l.record=m;l.recordIndex=o;l.trIndex=i;return l;}},_handleStandardSelectionByMouse:function(k){var j=k.target;var m=this.getTrEl(j);if(m){var p=k.event;var s=p.shiftKey;var o=p.ctrlKey||((navigator.userAgent.toLowerCase().indexOf(&quot;mac&quot;)!=-1)&amp;&amp;p.metaKey);var r=this.getRecord(m);var l=this._oRecordSet.getRecordIndex(r);var q=this._getSelectionAnchor();var n;if(s&amp;&amp;o){if(q){if(this.isSelected(q.record)){if(q.recordIndex&lt;l){for(n=q.recordIndex+1;n&lt;=l;n++){if(!this.isSelected(n)){this.selectRow(n);}}}else{for(n=q.recordIndex-1;n&gt;=l;n--){if(!this.isSelected(n)){this.sel
 ectRow(n);}}}}else{if(q.recordIndex&lt;l){for(n=q.recordIndex+1;n&lt;=l-1;n++){if(this.isSelected(n)){this.unselectRow(n);}}}else{for(n=l+1;n&lt;=q.recordIndex-1;n++){if(this.isSelected(n)){this.unselectRow(n);}}}this.selectRow(r);}}else{this._oAnchorRecord=r;if(this.isSelected(r)){this.unselectRow(r);}else{this.selectRow(r);}}}else{if(s){this.unselectAllRows();if(q){if(q.recordIndex&lt;l){for(n=q.recordIndex;n&lt;=l;n++){this.selectRow(n);}}else{for(n=q.recordIndex;n&gt;=l;n--){this.selectRow(n);}}}else{this._oAnchorRecord=r;this.selectRow(r);}}else{if(o){this._oAnchorRecord=r;if(this.isSelected(r)){this.unselectRow(r);}else{this.selectRow(r);}}else{this._handleSingleSelectionByMouse(k);return;}}}}},_handleStandardSelectionByKey:function(m){var i=g.getCharCode(m);if((i==38)||(i==40)){var k=m.shiftKey;var j=this._getSelectionTrigger();if(!j){return null;}g.stopEvent(m);var l=this._getSelectionAnchor(j);if(k){if((i==40)&amp;&amp;(l.recordIndex&lt;=j.trIndex)){this.selectRow(t
 his.getNextTrEl(j.el));}else{if((i==38)&amp;&amp;(l.recordIndex&gt;=j.trIndex)){this.selectRow(this.getPreviousTrEl(j.el));}else{this.unselectRow(j.el);}}}else{this._handleSingleSelectionByKey(m);}}},_handleSingleSelectionByMouse:function(k){var l=k.target;var j=this.getTrEl(l);if(j){var i=this.getRecord(j);this._oAnchorRecord=i;this.unselectAllRows();this.selectRow(i);}},_handleSingleSelectionByKey:function(l){var i=g.getCharCode(l);if((i==38)||(i==40)){var j=this._getSelectionTrigger();if(!j){return null;}g.stopEvent(l);var k;if(i==38){k=this.getPreviousTrEl(j.el);if(k===null){k=this.getFirstTrEl();}}else{if(i==40){k=this.getNextTrEl(j.el);if(k===null){k=this.getLastTrEl();}}}this.unselectAllRows();this.selectRow(k);this._oAnchorRecord=this.getRecord(k);}},_handleCellBlockSelectionByMouse:function(A){var B=A.target;var l=this.getTdEl(B);if(l){var z=A.event;var q=z.shiftKey;var m=z.ctrlKey||((navigator.userAgent.toLowerCase().indexOf(&quot;mac&quot;)!=-1)&amp;&amp;z.metaKey
 );var s=this.getTrEl(l);var r=this.getTrIndex(s);var v=this.getColumn(l);var w=v.getKeyIndex();var u=this.getRecord(s);var D=this._oRecordSet.getRecordIndex(u);var p={record:u,column:v};var t=this._getSelectionAnchor();var o=this.getTbodyEl().rows;var n,k,C,y,x;if(q&amp;&amp;m){if(t){if(this.isSelected(t.cell)){if(t.recordIndex===D){if(t.colKeyIndex&lt;w){for(y=t.colKeyIndex+1;y&lt;=w;y++){this.selectCell(s.cells[y]);}}else{if(w&lt;t.colKeyIndex){for(y=w;y&lt;t.colKeyIndex;y++){this.selectCell(s.cells[y]);}}}}else{if(t.recordIndex&lt;D){n=Math.min(t.colKeyIndex,w);k=Math.max(t.colKeyIndex,w);for(y=t.trIndex;y&lt;=r;y++){for(x=n;x&lt;=k;x++){this.selectCell(o[y].cells[x]);}}}else{n=Math.min(t.trIndex,w);k=Math.max(t.trIndex,w);for(y=t.trIndex;y&gt;=r;y--){for(x=k;x&gt;=n;x--){this.selectCell(o[y].cells[x]);}}}}}else{if(t.recordIndex===D){if(t.colKeyIndex&lt;w){for(y=t.colKeyIndex+1;y&lt;w;y++){this.unselectCell(s.cells[y]);}}else{if(w&lt;t.colKeyIndex){for(y=w+1;y&lt;t.colKey
 Index;y++){this.unselectCell(s.cells[y]);}}}}if(t.recordIndex&lt;D){for(y=t.trIndex;y&lt;=r;y++){C=o[y];for(x=0;x&lt;C.cells.length;x++){if(C.sectionRowIndex===t.trIndex){if(x&gt;t.colKeyIndex){this.unselectCell(C.cells[x]);}}else{if(C.sectionRowIndex===r){if(x&lt;w){this.unselectCell(C.cells[x]);}}else{this.unselectCell(C.cells[x]);}}}}}else{for(y=r;y&lt;=t.trIndex;y++){C=o[y];for(x=0;x&lt;C.cells.length;x++){if(C.sectionRowIndex==r){if(x&gt;w){this.unselectCell(C.cells[x]);}}else{if(C.sectionRowIndex==t.trIndex){if(x&lt;t.colKeyIndex){this.unselectCell(C.cells[x]);}}else{this.unselectCell(C.cells[x]);}}}}}this.selectCell(l);}}else{this._oAnchorCell=p;if(this.isSelected(p)){this.unselectCell(p);}else{this.selectCell(p);}}}else{if(q){this.unselectAllCells();if(t){if(t.recordIndex===D){if(t.colKeyIndex&lt;w){for(y=t.colKeyIndex;y&lt;=w;y++){this.selectCell(s.cells[y]);}}else{if(w&lt;t.colKeyIndex){for(y=w;y&lt;=t.colKeyIndex;y++){this.selectCell(s.cells[y]);}}}}else{if(t.reco
 rdIndex&lt;D){n=Math.min(t.colKeyIndex,w);k=Math.max(t.colKeyIndex,w);for(y=t.trIndex;y&lt;=r;y++){for(x=n;x&lt;=k;x++){this.selectCell(o[y].cells[x]);}}}else{n=Math.min(t.colKeyIndex,w);k=Math.max(t.colKeyIndex,w);for(y=r;y&lt;=t.trIndex;y++){for(x=n;x&lt;=k;x++){this.selectCell(o[y].cells[x]);}}}}}else{this._oAnchorCell=p;this.selectCell(p);}}else{if(m){this._oAnchorCell=p;if(this.isSelected(p)){this.unselectCell(p);}else{this.selectCell(p);}}else{this._handleSingleCellSelectionByMouse(A);}}}}},_handleCellBlockSelectionByKey:function(o){var j=g.getCharCode(o);var t=o.shiftKey;if((j==9)||!t){this._handleSingleCellSelectionByKey(o);return;}if((j&gt;36)&amp;&amp;(j&lt;41)){var u=this._getSelectionTrigger();if(!u){return null;}g.stopEvent(o);var r=this._getSelectionAnchor(u);var k,s,l,q,m;var p=this.getTbodyEl().rows;var n=u.el.parentNode;if(j==40){if(r.recordIndex&lt;=u.recordIndex){m=this.getNextTrEl(u.el);if(m){s=r.colKeyIndex;l=u.colKeyIndex;if(s&gt;l){for(k=s;k&gt;=l;k--)
 {q=m.cells[k];this.selectCell(q);}}else{for(k=s;k&lt;=l;k++){q=m.cells[k];this.selectCell(q);}}}}else{s=Math.min(r.colKeyIndex,u.colKeyIndex);l=Math.max(r.colKeyIndex,u.colKeyIndex);for(k=s;k&lt;=l;k++){this.unselectCell(n.cells[k]);}}}else{if(j==38){if(r.recordIndex&gt;=u.recordIndex){m=this.getPreviousTrEl(u.el);
+if(m){s=r.colKeyIndex;l=u.colKeyIndex;if(s&gt;l){for(k=s;k&gt;=l;k--){q=m.cells[k];this.selectCell(q);}}else{for(k=s;k&lt;=l;k++){q=m.cells[k];this.selectCell(q);}}}}else{s=Math.min(r.colKeyIndex,u.colKeyIndex);l=Math.max(r.colKeyIndex,u.colKeyIndex);for(k=s;k&lt;=l;k++){this.unselectCell(n.cells[k]);}}}else{if(j==39){if(r.colKeyIndex&lt;=u.colKeyIndex){if(u.colKeyIndex&lt;n.cells.length-1){s=r.trIndex;l=u.trIndex;if(s&gt;l){for(k=s;k&gt;=l;k--){q=p[k].cells[u.colKeyIndex+1];this.selectCell(q);}}else{for(k=s;k&lt;=l;k++){q=p[k].cells[u.colKeyIndex+1];this.selectCell(q);}}}}else{s=Math.min(r.trIndex,u.trIndex);l=Math.max(r.trIndex,u.trIndex);for(k=s;k&lt;=l;k++){this.unselectCell(p[k].cells[u.colKeyIndex]);}}}else{if(j==37){if(r.colKeyIndex&gt;=u.colKeyIndex){if(u.colKeyIndex&gt;0){s=r.trIndex;l=u.trIndex;if(s&gt;l){for(k=s;k&gt;=l;k--){q=p[k].cells[u.colKeyIndex-1];this.selectCell(q);}}else{for(k=s;k&lt;=l;k++){q=p[k].cells[u.colKeyIndex-1];this.selectCell(q);}}}}else{s=Math
 .min(r.trIndex,u.trIndex);l=Math.max(r.trIndex,u.trIndex);for(k=s;k&lt;=l;k++){this.unselectCell(p[k].cells[u.colKeyIndex]);}}}}}}}},_handleCellRangeSelectionByMouse:function(y){var z=y.target;var k=this.getTdEl(z);if(k){var x=y.event;var o=x.shiftKey;var l=x.ctrlKey||((navigator.userAgent.toLowerCase().indexOf(&quot;mac&quot;)!=-1)&amp;&amp;x.metaKey);var q=this.getTrEl(k);var p=this.getTrIndex(q);var t=this.getColumn(k);var u=t.getKeyIndex();var s=this.getRecord(q);var B=this._oRecordSet.getRecordIndex(s);var n={record:s,column:t};var r=this._getSelectionAnchor();var m=this.getTbodyEl().rows;var A,w,v;if(o&amp;&amp;l){if(r){if(this.isSelected(r.cell)){if(r.recordIndex===B){if(r.colKeyIndex&lt;u){for(w=r.colKeyIndex+1;w&lt;=u;w++){this.selectCell(q.cells[w]);}}else{if(u&lt;r.colKeyIndex){for(w=u;w&lt;r.colKeyIndex;w++){this.selectCell(q.cells[w]);}}}}else{if(r.recordIndex&lt;B){for(w=r.colKeyIndex+1;w&lt;q.cells.length;w++){this.selectCell(q.cells[w]);}for(w=r.trIndex+1;w&l
 t;p;w++){for(v=0;v&lt;m[w].cells.length;v++){this.selectCell(m[w].cells[v]);}}for(w=0;w&lt;=u;w++){this.selectCell(q.cells[w]);}}else{for(w=u;w&lt;q.cells.length;w++){this.selectCell(q.cells[w]);}for(w=p+1;w&lt;r.trIndex;w++){for(v=0;v&lt;m[w].cells.length;v++){this.selectCell(m[w].cells[v]);}}for(w=0;w&lt;r.colKeyIndex;w++){this.selectCell(q.cells[w]);}}}}else{if(r.recordIndex===B){if(r.colKeyIndex&lt;u){for(w=r.colKeyIndex+1;w&lt;u;w++){this.unselectCell(q.cells[w]);}}else{if(u&lt;r.colKeyIndex){for(w=u+1;w&lt;r.colKeyIndex;w++){this.unselectCell(q.cells[w]);}}}}if(r.recordIndex&lt;B){for(w=r.trIndex;w&lt;=p;w++){A=m[w];for(v=0;v&lt;A.cells.length;v++){if(A.sectionRowIndex===r.trIndex){if(v&gt;r.colKeyIndex){this.unselectCell(A.cells[v]);}}else{if(A.sectionRowIndex===p){if(v&lt;u){this.unselectCell(A.cells[v]);}}else{this.unselectCell(A.cells[v]);}}}}}else{for(w=p;w&lt;=r.trIndex;w++){A=m[w];for(v=0;v&lt;A.cells.length;v++){if(A.sectionRowIndex==p){if(v&gt;u){this.unselect
 Cell(A.cells[v]);}}else{if(A.sectionRowIndex==r.trIndex){if(v&lt;r.colKeyIndex){this.unselectCell(A.cells[v]);}}else{this.unselectCell(A.cells[v]);}}}}}this.selectCell(k);}}else{this._oAnchorCell=n;if(this.isSelected(n)){this.unselectCell(n);}else{this.selectCell(n);}}}else{if(o){this.unselectAllCells();if(r){if(r.recordIndex===B){if(r.colKeyIndex&lt;u){for(w=r.colKeyIndex;w&lt;=u;w++){this.selectCell(q.cells[w]);}}else{if(u&lt;r.colKeyIndex){for(w=u;w&lt;=r.colKeyIndex;w++){this.selectCell(q.cells[w]);}}}}else{if(r.recordIndex&lt;B){for(w=r.trIndex;w&lt;=p;w++){A=m[w];for(v=0;v&lt;A.cells.length;v++){if(A.sectionRowIndex==r.trIndex){if(v&gt;=r.colKeyIndex){this.selectCell(A.cells[v]);}}else{if(A.sectionRowIndex==p){if(v&lt;=u){this.selectCell(A.cells[v]);}}else{this.selectCell(A.cells[v]);}}}}}else{for(w=p;w&lt;=r.trIndex;w++){A=m[w];for(v=0;v&lt;A.cells.length;v++){if(A.sectionRowIndex==p){if(v&gt;=u){this.selectCell(A.cells[v]);}}else{if(A.sectionRowIndex==r.trIndex){if(v
 &lt;=r.colKeyIndex){this.selectCell(A.cells[v]);}}else{this.selectCell(A.cells[v]);}}}}}}}else{this._oAnchorCell=n;this.selectCell(n);}}else{if(l){this._oAnchorCell=n;if(this.isSelected(n)){this.unselectCell(n);}else{this.selectCell(n);}}else{this._handleSingleCellSelectionByMouse(y);}}}}},_handleCellRangeSelectionByKey:function(n){var j=g.getCharCode(n);var r=n.shiftKey;if((j==9)||!r){this._handleSingleCellSelectionByKey(n);return;}if((j&gt;36)&amp;&amp;(j&lt;41)){var s=this._getSelectionTrigger();if(!s){return null;}g.stopEvent(n);var q=this._getSelectionAnchor(s);var k,l,p;var o=this.getTbodyEl().rows;var m=s.el.parentNode;if(j==40){l=this.getNextTrEl(s.el);if(q.recordIndex&lt;=s.recordIndex){for(k=s.colKeyIndex+1;k&lt;m.cells.length;k++){p=m.cells[k];this.selectCell(p);}if(l){for(k=0;k&lt;=s.colKeyIndex;k++){p=l.cells[k];this.selectCell(p);}}}else{for(k=s.colKeyIndex;k&lt;m.cells.length;k++){this.unselectCell(m.cells[k]);}if(l){for(k=0;k&lt;s.colKeyIndex;k++){this.unsele
 ctCell(l.cells[k]);}}}}else{if(j==38){l=this.getPreviousTrEl(s.el);if(q.recordIndex&gt;=s.recordIndex){for(k=s.colKeyIndex-1;k&gt;-1;k--){p=m.cells[k];this.selectCell(p);}if(l){for(k=m.cells.length-1;k&gt;=s.colKeyIndex;k--){p=l.cells[k];this.selectCell(p);}}}else{for(k=s.colKeyIndex;k&gt;-1;k--){this.unselectCell(m.cells[k]);}if(l){for(k=m.cells.length-1;k&gt;s.colKeyIndex;k--){this.unselectCell(l.cells[k]);}}}}else{if(j==39){l=this.getNextTrEl(s.el);if(q.recordIndex&lt;s.recordIndex){if(s.colKeyIndex&lt;m.cells.length-1){p=m.cells[s.colKeyIndex+1];this.selectCell(p);}else{if(l){p=l.cells[0];this.selectCell(p);}}}else{if(q.recordIndex&gt;s.recordIndex){this.unselectCell(m.cells[s.colKeyIndex]);if(s.colKeyIndex&lt;m.cells.length-1){}else{}}else{if(q.colKeyIndex&lt;=s.colKeyIndex){if(s.colKeyIndex&lt;m.cells.length-1){p=m.cells[s.colKeyIndex+1];this.selectCell(p);}else{if(s.trIndex&lt;o.length-1){p=l.cells[0];this.selectCell(p);}}}else{this.unselectCell(m.cells[s.colKeyIndex]
 );}}}}else{if(j==37){l=this.getPreviousTrEl(s.el);if(q.recordIndex&lt;s.recordIndex){this.unselectCell(m.cells[s.colKeyIndex]);if(s.colKeyIndex&gt;0){}else{}}else{if(q.recordIndex&gt;s.recordIndex){if(s.colKeyIndex&gt;0){p=m.cells[s.colKeyIndex-1];this.selectCell(p);}else{if(s.trIndex&gt;0){p=l.cells[l.cells.length-1];this.selectCell(p);
+}}}else{if(q.colKeyIndex&gt;=s.colKeyIndex){if(s.colKeyIndex&gt;0){p=m.cells[s.colKeyIndex-1];this.selectCell(p);}else{if(s.trIndex&gt;0){p=l.cells[l.cells.length-1];this.selectCell(p);}}}else{this.unselectCell(m.cells[s.colKeyIndex]);if(s.colKeyIndex&gt;0){}else{}}}}}}}}}},_handleSingleCellSelectionByMouse:function(n){var o=n.target;var k=this.getTdEl(o);if(k){var j=this.getTrEl(k);var i=this.getRecord(j);var m=this.getColumn(k);var l={record:i,column:m};this._oAnchorCell=l;this.unselectAllCells();this.selectCell(l);}},_handleSingleCellSelectionByKey:function(m){var i=g.getCharCode(m);if((i==9)||((i&gt;36)&amp;&amp;(i&lt;41))){var k=m.shiftKey;var j=this._getSelectionTrigger();if(!j){return null;}var l;if(i==40){l=this.getBelowTdEl(j.el);if(l===null){l=j.el;}}else{if(i==38){l=this.getAboveTdEl(j.el);if(l===null){l=j.el;}}else{if((i==39)||(!k&amp;&amp;(i==9))){l=this.getNextTdEl(j.el);if(l===null){return;}}else{if((i==37)||(k&amp;&amp;(i==9))){l=this.getPreviousTdEl(j.el);if
 (l===null){return;}}}}}g.stopEvent(m);this.unselectAllCells();this.selectCell(l);this._oAnchorCell={record:this.getRecord(l),column:this.getColumn(l)};}},getSelectedTrEls:function(){return c.getElementsByClassName(d.CLASS_SELECTED,&quot;tr&quot;,this._elTbody);},selectRow:function(p){var o,i;if(p instanceof YAHOO.widget.Record){o=this._oRecordSet.getRecord(p);i=this.getTrEl(o);}else{if(h.isNumber(p)){o=this.getRecord(p);i=this.getTrEl(o);}else{i=this.getTrEl(p);o=this.getRecord(i);}}if(o){var n=this._aSelections||[];var m=o.getId();var l=-1;if(n.indexOf){l=n.indexOf(m);}else{for(var k=n.length-1;k&gt;-1;k--){if(n[k]===m){l=k;break;}}}if(l&gt;-1){n.splice(l,1);}n.push(m);this._aSelections=n;if(!this._oAnchorRecord){this._oAnchorRecord=o;}if(i){c.addClass(i,d.CLASS_SELECTED);}this.fireEvent(&quot;rowSelectEvent&quot;,{record:o,el:i});}else{}},unselectRow:function(p){var i=this.getTrEl(p);var o;if(p instanceof YAHOO.widget.Record){o=this._oRecordSet.getRecord(p);}else{if(h.isNu
 mber(p)){o=this.getRecord(p);}else{o=this.getRecord(i);}}if(o){var n=this._aSelections||[];var m=o.getId();var l=-1;if(n.indexOf){l=n.indexOf(m);}else{for(var k=n.length-1;k&gt;-1;k--){if(n[k]===m){l=k;break;}}}if(l&gt;-1){n.splice(l,1);this._aSelections=n;c.removeClass(i,d.CLASS_SELECTED);this.fireEvent(&quot;rowUnselectEvent&quot;,{record:o,el:i});return;}}},unselectAllRows:function(){var k=this._aSelections||[],m,l=[];for(var i=k.length-1;i&gt;-1;i--){if(h.isString(k[i])){m=k.splice(i,1);l[l.length]=this.getRecord(h.isArray(m)?m[0]:m);}}this._aSelections=k;this._unselectAllTrEls();this.fireEvent(&quot;unselectAllRowsEvent&quot;,{records:l});},_unselectAllTdEls:function(){var i=c.getElementsByClassName(d.CLASS_SELECTED,&quot;td&quot;,this._elTbody);c.removeClass(i,d.CLASS_SELECTED);},getSelectedTdEls:function(){return c.getElementsByClassName(d.CLASS_SELECTED,&quot;td&quot;,this._elTbody);},selectCell:function(i){var p=this.getTdEl(i);if(p){var o=this.getRecord(p);var q=th
 is.getColumn(this.getCellIndex(p));var m=q.getKey();if(o&amp;&amp;m){var n=this._aSelections||[];var l=o.getId();for(var k=n.length-1;k&gt;-1;k--){if((n[k].recordId===l)&amp;&amp;(n[k].columnKey===m)){n.splice(k,1);break;}}n.push({recordId:l,columnKey:m});this._aSelections=n;if(!this._oAnchorCell){this._oAnchorCell={record:o,column:q};}c.addClass(p,d.CLASS_SELECTED);this.fireEvent(&quot;cellSelectEvent&quot;,{record:o,column:q,key:m,el:p});return;}}},unselectCell:function(i){var o=this.getTdEl(i);if(o){var n=this.getRecord(o);var p=this.getColumn(this.getCellIndex(o));var l=p.getKey();if(n&amp;&amp;l){var m=this._aSelections||[];var q=n.getId();for(var k=m.length-1;k&gt;-1;k--){if((m[k].recordId===q)&amp;&amp;(m[k].columnKey===l)){m.splice(k,1);this._aSelections=m;c.removeClass(o,d.CLASS_SELECTED);this.fireEvent(&quot;cellUnselectEvent&quot;,{record:n,column:p,key:l,el:o});return;}}}}},unselectAllCells:function(){var k=this._aSelections||[];for(var i=k.length-1;i&gt;-1;i--){
 if(h.isObject(k[i])){k.splice(i,1);}}this._aSelections=k;this._unselectAllTdEls();this.fireEvent(&quot;unselectAllCellsEvent&quot;);},isSelected:function(p){if(p&amp;&amp;(p.ownerDocument==document)){return(c.hasClass(this.getTdEl(p),d.CLASS_SELECTED)||c.hasClass(this.getTrEl(p),d.CLASS_SELECTED));}else{var n,k,i;var m=this._aSelections;if(m&amp;&amp;m.length&gt;0){if(p instanceof YAHOO.widget.Record){n=p;}else{if(h.isNumber(p)){n=this.getRecord(p);}}if(n){k=n.getId();if(m.indexOf){if(m.indexOf(k)&gt;-1){return true;}}else{for(i=m.length-1;i&gt;-1;i--){if(m[i]===k){return true;}}}}else{if(p.record&amp;&amp;p.column){k=p.record.getId();var l=p.column.getKey();for(i=m.length-1;i&gt;-1;i--){if((m[i].recordId===k)&amp;&amp;(m[i].columnKey===l)){return true;}}}}}}return false;},getSelectedRows:function(){var i=[];var l=this._aSelections||[];for(var k=0;k&lt;l.length;k++){if(h.isString(l[k])){i.push(l[k]);}}return i;},getSelectedCells:function(){var k=[];var l=this._aSelections||[
 ];for(var i=0;i&lt;l.length;i++){if(l[i]&amp;&amp;h.isObject(l[i])){k.push(l[i]);}}return k;},getLastSelectedRecord:function(){var k=this._aSelections;if(k&amp;&amp;k.length&gt;0){for(var j=k.length-1;j&gt;-1;j--){if(h.isString(k[j])){return k[j];}}}},getLastSelectedCell:function(){var k=this._aSelections;if(k&amp;&amp;k.length&gt;0){for(var j=k.length-1;j&gt;-1;j--){if(k[j].recordId&amp;&amp;k[j].columnKey){return k[j];}}}},highlightRow:function(k){var i=this.getTrEl(k);if(i){var j=this.getRecord(i);c.addClass(i,d.CLASS_HIGHLIGHTED);this.fireEvent(&quot;rowHighlightEvent&quot;,{record:j,el:i});return;}},unhighlightRow:function(k){var i=this.getTrEl(k);if(i){var j=this.getRecord(i);c.removeClass(i,d.CLASS_HIGHLIGHTED);this.fireEvent(&quot;rowUnhighlightEvent&quot;,{record:j,el:i});return;}},highlightCell:function(i){var l=this.getTdEl(i);if(l){if(this._elLastHighlightedTd){this.unhighlightCell(this._elLastHighlightedTd);}var k=this.getRecord(l);var m=this.getColumn(this.getC
 ellIndex(l));var j=m.getKey();c.addClass(l,d.CLASS_HIGHLIGHTED);this._elLastHighlightedTd=l;this.fireEvent(&quot;cellHighlightEvent&quot;,{record:k,column:m,key:j,el:l});return;}},unhighlightCell:function(i){var k=this.getTdEl(i);if(k){var j=this.getRecord(k);c.removeClass(k,d.CLASS_HIGHLIGHTED);this._elLastHighlightedTd=null;this.fireEvent(&quot;cellUnhighlightEvent&quot;,{record:j,column:this.getColumn(this.getCellIndex(k)),key:this.getColumn(this.getCellIndex(k)).getKey(),el:k});
+return;}},addCellEditor:function(j,i){j.editor=i;j.editor.subscribe(&quot;showEvent&quot;,this._onEditorShowEvent,this,true);j.editor.subscribe(&quot;keydownEvent&quot;,this._onEditorKeydownEvent,this,true);j.editor.subscribe(&quot;revertEvent&quot;,this._onEditorRevertEvent,this,true);j.editor.subscribe(&quot;saveEvent&quot;,this._onEditorSaveEvent,this,true);j.editor.subscribe(&quot;cancelEvent&quot;,this._onEditorCancelEvent,this,true);j.editor.subscribe(&quot;blurEvent&quot;,this._onEditorBlurEvent,this,true);j.editor.subscribe(&quot;blockEvent&quot;,this._onEditorBlockEvent,this,true);j.editor.subscribe(&quot;unblockEvent&quot;,this._onEditorUnblockEvent,this,true);},getCellEditor:function(){return this._oCellEditor;},showCellEditor:function(p,q,l){p=this.getTdEl(p);if(p){l=this.getColumn(p);if(l&amp;&amp;l.editor){var j=this._oCellEditor;if(j){if(this._oCellEditor.cancel){this._oCellEditor.cancel();}else{if(j.isActive){this.cancelCellEditor();}}}if(l.editor instanceof 
 YAHOO.widget.BaseCellEditor){j=l.editor;var n=j.attach(this,p);if(n){j.render();j.move();n=this.doBeforeShowCellEditor(j);if(n){j.show();this._oCellEditor=j;}}}else{if(!q||!(q instanceof YAHOO.widget.Record)){q=this.getRecord(p);}if(!l||!(l instanceof YAHOO.widget.Column)){l=this.getColumn(p);}if(q&amp;&amp;l){if(!this._oCellEditor||this._oCellEditor.container){this._initCellEditorEl();}j=this._oCellEditor;j.cell=p;j.record=q;j.column=l;j.validator=(l.editorOptions&amp;&amp;h.isFunction(l.editorOptions.validator))?l.editorOptions.validator:null;j.value=q.getData(l.key);j.defaultValue=null;var k=j.container;var o=c.getX(p);var m=c.getY(p);if(isNaN(o)||isNaN(m)){o=p.offsetLeft+c.getX(this._elTbody.parentNode)-this._elTbody.scrollLeft;m=p.offsetTop+c.getY(this._elTbody.parentNode)-this._elTbody.scrollTop+this._elThead.offsetHeight;}k.style.left=o+&quot;px&quot;;k.style.top=m+&quot;px&quot;;this.doBeforeShowCellEditor(this._oCellEditor);k.style.display=&quot;&quot;;g.addListener
 (k,&quot;keydown&quot;,function(s,r){if((s.keyCode==27)){r.cancelCellEditor();r.focusTbodyEl();}else{r.fireEvent(&quot;editorKeydownEvent&quot;,{editor:r._oCellEditor,event:s});}},this);var i;if(h.isString(l.editor)){switch(l.editor){case&quot;checkbox&quot;:i=d.editCheckbox;break;case&quot;date&quot;:i=d.editDate;break;case&quot;dropdown&quot;:i=d.editDropdown;break;case&quot;radio&quot;:i=d.editRadio;break;case&quot;textarea&quot;:i=d.editTextarea;break;case&quot;textbox&quot;:i=d.editTextbox;break;default:i=null;}}else{if(h.isFunction(l.editor)){i=l.editor;}}if(i){i(this._oCellEditor,this);if(!l.editorOptions||!l.editorOptions.disableBtns){this.showCellEditorBtns(k);}j.isActive=true;this.fireEvent(&quot;editorShowEvent&quot;,{editor:j});return;}}}}}},_initCellEditorEl:function(){var i=document.createElement(&quot;div&quot;);i.id=this._sId+&quot;-celleditor&quot;;i.style.display=&quot;none&quot;;i.tabIndex=0;c.addClass(i,d.CLASS_EDITOR);var k=c.getFirstChild(document.body)
 ;if(k){i=c.insertBefore(i,k);}else{i=document.body.appendChild(i);}var j={};j.container=i;j.value=null;j.isActive=false;this._oCellEditor=j;},doBeforeShowCellEditor:function(i){return true;},saveCellEditor:function(){if(this._oCellEditor){if(this._oCellEditor.save){this._oCellEditor.save();}else{if(this._oCellEditor.isActive){var i=this._oCellEditor.value;var j=this._oCellEditor.record.getData(this._oCellEditor.column.key);if(this._oCellEditor.validator){i=this._oCellEditor.value=this._oCellEditor.validator.call(this,i,j,this._oCellEditor);if(i===null){this.resetCellEditor();this.fireEvent(&quot;editorRevertEvent&quot;,{editor:this._oCellEditor,oldData:j,newData:i});return;}}this._oRecordSet.updateRecordValue(this._oCellEditor.record,this._oCellEditor.column.key,this._oCellEditor.value);this.formatCell(this._oCellEditor.cell.firstChild,this._oCellEditor.record,this._oCellEditor.column);this._oChainRender.add({method:function(){this.validateColumnWidths();},scope:this});this.
 _oChainRender.run();this.resetCellEditor();this.fireEvent(&quot;editorSaveEvent&quot;,{editor:this._oCellEditor,oldData:j,newData:i});}}}},cancelCellEditor:function(){if(this._oCellEditor){if(this._oCellEditor.cancel){this._oCellEditor.cancel();}else{if(this._oCellEditor.isActive){this.resetCellEditor();this.fireEvent(&quot;editorCancelEvent&quot;,{editor:this._oCellEditor});}}}},destroyCellEditor:function(){if(this._oCellEditor){this._oCellEditor.destroy();this._oCellEditor=null;}},_onEditorShowEvent:function(i){this.fireEvent(&quot;editorShowEvent&quot;,i);},_onEditorKeydownEvent:function(i){this.fireEvent(&quot;editorKeydownEvent&quot;,i);},_onEditorRevertEvent:function(i){this.fireEvent(&quot;editorRevertEvent&quot;,i);},_onEditorSaveEvent:function(i){this.fireEvent(&quot;editorSaveEvent&quot;,i);},_onEditorCancelEvent:function(i){this.fireEvent(&quot;editorCancelEvent&quot;,i);},_onEditorBlurEvent:function(i){this.fireEvent(&quot;editorBlurEvent&quot;,i);},_onEditorBloc
 kEvent:function(i){this.fireEvent(&quot;editorBlockEvent&quot;,i);},_onEditorUnblockEvent:function(i){this.fireEvent(&quot;editorUnblockEvent&quot;,i);},onEditorBlurEvent:function(i){if(i.editor.disableBtns){if(i.editor.save){i.editor.save();}}else{if(i.editor.cancel){i.editor.cancel();}}},onEditorBlockEvent:function(i){this.disable();},onEditorUnblockEvent:function(i){this.undisable();},doBeforeLoadData:function(i,j,k){return true;},onEventSortColumn:function(k){var i=k.event;var m=k.target;var j=this.getThEl(m)||this.getTdEl(m);if(j){var l=this.getColumn(j);if(l.sortable){g.stopEvent(i);this.sortColumn(l);}}else{}},onEventSelectColumn:function(i){this.selectColumn(i.target);},onEventHighlightColumn:function(i){this.highlightColumn(i.target);},onEventUnhighlightColumn:function(i){this.unhighlightColumn(i.target);},onEventSelectRow:function(j){var i=this.get(&quot;selectionMode&quot;);if(i==&quot;single&quot;){this._handleSingleSelectionByMouse(j);}else{this._handleStandardS
 electionByMouse(j);}},onEventSelectCell:function(j){var i=this.get(&quot;selectionMode&quot;);if(i==&quot;cellblock&quot;){this._handleCellBlockSelectionByMouse(j);}else{if(i==&quot;cellrange&quot;){this._handleCellRangeSelectionByMouse(j);}else{this._handleSingleCellSelectionByMouse(j);}}},onEventHighlightRow:function(i){this.highlightRow(i.target);},onEventUnhighlightRow:function(i){this.unhighlightRow(i.target);},onEventHighlightCell:function(i){this.highlightCell(i.target);
+},onEventUnhighlightCell:function(i){this.unhighlightCell(i.target);},onEventFormatCell:function(i){var l=i.target;var j=this.getTdEl(l);if(j){var k=this.getColumn(this.getCellIndex(j));this.formatCell(j.firstChild,this.getRecord(j),k);}else{}},onEventShowCellEditor:function(i){if(!this.isDisabled()){this.showCellEditor(i.target);}},onEventSaveCellEditor:function(i){if(this._oCellEditor){if(this._oCellEditor.save){this._oCellEditor.save();}else{this.saveCellEditor();}}},onEventCancelCellEditor:function(i){if(this._oCellEditor){if(this._oCellEditor.cancel){this._oCellEditor.cancel();}else{this.cancelCellEditor();}}},onDataReturnInitializeTable:function(i,j,k){if((this instanceof d)&amp;&amp;this._sId){this.initializeTable();this.onDataReturnSetRows(i,j,k);}},onDataReturnReplaceRows:function(m,l,n){if((this instanceof d)&amp;&amp;this._sId){this.fireEvent(&quot;dataReturnEvent&quot;,{request:m,response:l,payload:n});var j=this.doBeforeLoadData(m,l,n),k=this.get(&quot;paginator
 &quot;),i=0;if(j&amp;&amp;l&amp;&amp;!l.error&amp;&amp;h.isArray(l.results)){this._oRecordSet.reset();if(this.get(&quot;dynamicData&quot;)){if(n&amp;&amp;n.pagination&amp;&amp;h.isNumber(n.pagination.recordOffset)){i=n.pagination.recordOffset;}else{if(k){i=k.getStartIndex();}}}this._oRecordSet.setRecords(l.results,i|0);this._handleDataReturnPayload(m,l,n);this.render();}else{if(j&amp;&amp;l.error){this.showTableMessage(this.get(&quot;MSG_ERROR&quot;),d.CLASS_ERROR);}}}},onDataReturnAppendRows:function(j,k,l){if((this instanceof d)&amp;&amp;this._sId){this.fireEvent(&quot;dataReturnEvent&quot;,{request:j,response:k,payload:l});var i=this.doBeforeLoadData(j,k,l);if(i&amp;&amp;k&amp;&amp;!k.error&amp;&amp;h.isArray(k.results)){this.addRows(k.results);this._handleDataReturnPayload(j,k,l);}else{if(i&amp;&amp;k.error){this.showTableMessage(this.get(&quot;MSG_ERROR&quot;),d.CLASS_ERROR);}}}},onDataReturnInsertRows:function(j,k,l){if((this instanceof d)&amp;&amp;this._sId){this.fire
 Event(&quot;dataReturnEvent&quot;,{request:j,response:k,payload:l});var i=this.doBeforeLoadData(j,k,l);if(i&amp;&amp;k&amp;&amp;!k.error&amp;&amp;h.isArray(k.results)){this.addRows(k.results,(l?l.insertIndex:0));this._handleDataReturnPayload(j,k,l);}else{if(i&amp;&amp;k.error){this.showTableMessage(this.get(&quot;MSG_ERROR&quot;),d.CLASS_ERROR);}}}},onDataReturnUpdateRows:function(j,k,l){if((this instanceof d)&amp;&amp;this._sId){this.fireEvent(&quot;dataReturnEvent&quot;,{request:j,response:k,payload:l});var i=this.doBeforeLoadData(j,k,l);if(i&amp;&amp;k&amp;&amp;!k.error&amp;&amp;h.isArray(k.results)){this.updateRows((l?l.updateIndex:0),k.results);this._handleDataReturnPayload(j,k,l);}else{if(i&amp;&amp;k.error){this.showTableMessage(this.get(&quot;MSG_ERROR&quot;),d.CLASS_ERROR);}}}},onDataReturnSetRows:function(m,l,n){if((this instanceof d)&amp;&amp;this._sId){this.fireEvent(&quot;dataReturnEvent&quot;,{request:m,response:l,payload:n});var j=this.doBeforeLoadData(m,l,n),
 k=this.get(&quot;paginator&quot;),i=0;if(j&amp;&amp;l&amp;&amp;!l.error&amp;&amp;h.isArray(l.results)){if(this.get(&quot;dynamicData&quot;)){if(n&amp;&amp;n.pagination&amp;&amp;h.isNumber(n.pagination.recordOffset)){i=n.pagination.recordOffset;}else{if(k){i=k.getStartIndex();}}this._oRecordSet.reset();}this._oRecordSet.setRecords(l.results,i|0);this._handleDataReturnPayload(m,l,n);this.render();}else{if(j&amp;&amp;l.error){this.showTableMessage(this.get(&quot;MSG_ERROR&quot;),d.CLASS_ERROR);}}}else{}},handleDataReturnPayload:function(j,i,k){return k||{};},_handleDataReturnPayload:function(k,j,l){l=this.handleDataReturnPayload(k,j,l);if(l){var i=this.get(&quot;paginator&quot;);if(i){if(this.get(&quot;dynamicData&quot;)){if(e.Paginator.isNumeric(l.totalRecords)){i.set(&quot;totalRecords&quot;,l.totalRecords);}}else{i.set(&quot;totalRecords&quot;,this._oRecordSet.getLength());}if(h.isObject(l.pagination)){i.set(&quot;rowsPerPage&quot;,l.pagination.rowsPerPage);i.set(&quot;recor
 dOffset&quot;,l.pagination.recordOffset);}}if(l.sortedBy){this.set(&quot;sortedBy&quot;,l.sortedBy);}else{if(l.sorting){this.set(&quot;sortedBy&quot;,l.sorting);}}}},showCellEditorBtns:function(k){var l=k.appendChild(document.createElement(&quot;div&quot;));c.addClass(l,d.CLASS_BUTTON);var j=l.appendChild(document.createElement(&quot;button&quot;));c.addClass(j,d.CLASS_DEFAULT);j.innerHTML=&quot;OK&quot;;g.addListener(j,&quot;click&quot;,function(n,m){m.onEventSaveCellEditor(n,m);m.focusTbodyEl();},this,true);var i=l.appendChild(document.createElement(&quot;button&quot;));i.innerHTML=&quot;Cancel&quot;;g.addListener(i,&quot;click&quot;,function(n,m){m.onEventCancelCellEditor(n,m);m.focusTbodyEl();},this,true);},resetCellEditor:function(){var i=this._oCellEditor.container;i.style.display=&quot;none&quot;;g.purgeElement(i,true);i.innerHTML=&quot;&quot;;this._oCellEditor.value=null;this._oCellEditor.isActive=false;},getBody:function(){return this.getTbodyEl();},getCell:function
 (i){return this.getTdEl(i);},getRow:function(i){return this.getTrEl(i);},refreshView:function(){this.render();},select:function(k){if(!h.isArray(k)){k=[k];}for(var j=0;j&lt;k.length;j++){this.selectRow(k[j]);}},onEventEditCell:function(i){this.onEventShowCellEditor(i);},_syncColWidths:function(){this.validateColumnWidths();}});d.prototype.onDataReturnSetRecords=d.prototype.onDataReturnSetRows;d.prototype.onPaginatorChange=d.prototype.onPaginatorChangeRequest;d.editCheckbox=function(){};d.editDate=function(){};d.editDropdown=function(){};d.editRadio=function(){};d.editTextarea=function(){};d.editTextbox=function(){};})();(function(){var c=YAHOO.lang,f=YAHOO.util,e=YAHOO.widget,a=YAHOO.env.ua,d=f.Dom,j=f.Event,i=f.DataSourceBase,g=e.DataTable,b=e.Paginator;e.ScrollingDataTable=function(n,m,k,l){l=l||{};if(l.scrollable){l.scrollable=false;}this._init();e.ScrollingDataTable.superclass.constructor.call(this,n,m,k,l);this.subscribe(&quot;columnShowEvent&quot;,this._onColumnChange)
 ;};var h=e.ScrollingDataTable;c.augmentObject(h,{CLASS_HEADER:&quot;yui-dt-hd&quot;,CLASS_BODY:&quot;yui-dt-bd&quot;});c.extend(h,g,{_elHdContainer:null,_elHdTable:null,_elBdContainer:null,_elBdThead:null,_elTmpContainer:null,_elTmpTable:null,_bScrollbarX:null,initAttributes:function(k){k=k||{};h.superclass.initAttributes.call(this,k);this.setAttributeConfig(&quot;width&quot;,{value:null,validator:c.isString,method:function(l){if(this._elHdContainer&amp;&amp;this._elBdContainer){this._elHdContainer.style.width=l;this._elBdContainer.style.width=l;this._syncScrollX();this._syncScrollOverhang();}}});this.setAttributeConfig(&quot;height&quot;,{value:null,validator:c.isString,method:function(l){if(this._elHdContainer&amp;&amp;this._elBdContainer){this._elBdContainer.style.height=l;
+this._syncScrollX();this._syncScrollY();this._syncScrollOverhang();}}});this.setAttributeConfig(&quot;COLOR_COLUMNFILLER&quot;,{value:&quot;#F2F2F2&quot;,validator:c.isString,method:function(l){if(this._elHdContainer){this._elHdContainer.style.backgroundColor=l;}}});},_init:function(){this._elHdContainer=null;this._elHdTable=null;this._elBdContainer=null;this._elBdThead=null;this._elTmpContainer=null;this._elTmpTable=null;},_initDomElements:function(k){this._initContainerEl(k);if(this._elContainer&amp;&amp;this._elHdContainer&amp;&amp;this._elBdContainer){this._initTableEl();if(this._elHdTable&amp;&amp;this._elTable){this._initColgroupEl(this._elHdTable);this._initTheadEl(this._elHdTable,this._elTable);this._initTbodyEl(this._elTable);this._initMsgTbodyEl(this._elTable);}}if(!this._elContainer||!this._elTable||!this._elColgroup||!this._elThead||!this._elTbody||!this._elMsgTbody||!this._elHdTable||!this._elBdThead){return false;}else{return true;}},_destroyContainerEl:functio
 n(k){d.removeClass(k,g.CLASS_SCROLLABLE);h.superclass._destroyContainerEl.call(this,k);this._elHdContainer=null;this._elBdContainer=null;},_initContainerEl:function(l){h.superclass._initContainerEl.call(this,l);if(this._elContainer){l=this._elContainer;d.addClass(l,g.CLASS_SCROLLABLE);var k=document.createElement(&quot;div&quot;);k.style.width=this.get(&quot;width&quot;)||&quot;&quot;;k.style.backgroundColor=this.get(&quot;COLOR_COLUMNFILLER&quot;);d.addClass(k,h.CLASS_HEADER);this._elHdContainer=k;l.appendChild(k);var m=document.createElement(&quot;div&quot;);m.style.width=this.get(&quot;width&quot;)||&quot;&quot;;m.style.height=this.get(&quot;height&quot;)||&quot;&quot;;d.addClass(m,h.CLASS_BODY);j.addListener(m,&quot;scroll&quot;,this._onScroll,this);this._elBdContainer=m;l.appendChild(m);}},_initCaptionEl:function(k){},_destroyHdTableEl:function(){var k=this._elHdTable;if(k){j.purgeElement(k,true);k.parentNode.removeChild(k);this._elBdThead=null;}},_initTableEl:function(
 ){if(this._elHdContainer){this._destroyHdTableEl();this._elHdTable=this._elHdContainer.appendChild(document.createElement(&quot;table&quot;));j.delegate(this._elHdTable,&quot;mouseenter&quot;,this._onTableMouseover,&quot;thead .&quot;+g.CLASS_LABEL,this);j.delegate(this._elHdTable,&quot;mouseleave&quot;,this._onTableMouseout,&quot;thead .&quot;+g.CLASS_LABEL,this);}h.superclass._initTableEl.call(this,this._elBdContainer);},_initTheadEl:function(l,k){l=l||this._elHdTable;k=k||this._elTable;this._initBdTheadEl(k);h.superclass._initTheadEl.call(this,l);},_initThEl:function(l,k){h.superclass._initThEl.call(this,l,k);l.id=this.getId()+&quot;-fixedth-&quot;+k.getSanitizedKey();},_destroyBdTheadEl:function(){var k=this._elBdThead;if(k){var l=k.parentNode;j.purgeElement(k,true);l.removeChild(k);this._elBdThead=null;this._destroyColumnHelpers();}},_initBdTheadEl:function(t){if(t){this._destroyBdTheadEl();var p=t.insertBefore(document.createElement(&quot;thead&quot;),t.firstChild);var
  v=this._oColumnSet,u=v.tree,o,l,s,q,n,m,r;for(q=0,m=u.length;q&lt;m;q++){l=p.appendChild(document.createElement(&quot;tr&quot;));for(n=0,r=u[q].length;n&lt;r;n++){s=u[q][n];o=l.appendChild(document.createElement(&quot;th&quot;));this._initBdThEl(o,s,q,n);}}this._elBdThead=p;}},_initBdThEl:function(n,m){n.id=this.getId()+&quot;-th-&quot;+m.getSanitizedKey();n.rowSpan=m.getRowspan();n.colSpan=m.getColspan();if(m.abbr){n.abbr=m.abbr;}var l=m.getKey();var k=c.isValue(m.label)?m.label:l;n.innerHTML=k;},_initTbodyEl:function(k){h.superclass._initTbodyEl.call(this,k);k.style.marginTop=(this._elTbody.offsetTop&gt;0)?&quot;-&quot;+this._elTbody.offsetTop+&quot;px&quot;:0;},_focusEl:function(l){l=l||this._elTbody;var k=this;this._storeScrollPositions();setTimeout(function(){setTimeout(function(){try{l.focus();k._restoreScrollPositions();}catch(m){}},0);},0);},_runRenderChain:function(){this._storeScrollPositions();this._oChainRender.run();},_storeScrollPositions:function(){this._nScr
 ollTop=this._elBdContainer.scrollTop;this._nScrollLeft=this._elBdContainer.scrollLeft;},clearScrollPositions:function(){this._nScrollTop=0;this._nScrollLeft=0;},_restoreScrollPositions:function(){if(this._nScrollTop){this._elBdContainer.scrollTop=this._nScrollTop;this._nScrollTop=null;}if(this._nScrollLeft){this._elBdContainer.scrollLeft=this._nScrollLeft;this._elHdContainer.scrollLeft=this._nScrollLeft;this._nScrollLeft=null;}},_validateColumnWidth:function(n,k){if(!n.width&amp;&amp;!n.hidden){var p=n.getThEl();if(n._calculatedWidth){this._setColumnWidth(n,&quot;auto&quot;,&quot;visible&quot;);}if(p.offsetWidth!==k.offsetWidth){var m=(p.offsetWidth&gt;k.offsetWidth)?n.getThLinerEl():k.firstChild;var l=Math.max(0,(m.offsetWidth-(parseInt(d.getStyle(m,&quot;paddingLeft&quot;),10)|0)-(parseInt(d.getStyle(m,&quot;paddingRight&quot;),10)|0)),n.minWidth);var o=&quot;visible&quot;;if((n.maxAutoWidth&gt;0)&amp;&amp;(l&gt;n.maxAutoWidth)){l=n.maxAutoWidth;o=&quot;hidden&quot;;}this.
 _elTbody.style.display=&quot;none&quot;;this._setColumnWidth(n,l+&quot;px&quot;,o);n._calculatedWidth=l;this._elTbody.style.display=&quot;&quot;;}}},validateColumnWidths:function(s){var u=this._oColumnSet.keys,w=u.length,l=this.getFirstTrEl();if(a.ie){this._setOverhangValue(1);}if(u&amp;&amp;l&amp;&amp;(l.childNodes.length===w)){var m=this.get(&quot;width&quot;);if(m){this._elHdContainer.style.width=&quot;&quot;;this._elBdContainer.style.width=&quot;&quot;;}this._elContainer.style.width=&quot;&quot;;if(s&amp;&amp;c.isNumber(s.getKeyIndex())){this._validateColumnWidth(s,l.childNodes[s.getKeyIndex()]);}else{var t,k=[],o,q,r;for(q=0;q&lt;w;q++){s=u[q];if(!s.width&amp;&amp;!s.hidden&amp;&amp;s._calculatedWidth){k[k.length]=s;}}this._elTbody.style.display=&quot;none&quot;;for(q=0,r=k.length;q&lt;r;q++){this._setColumnWidth(k[q],&quot;auto&quot;,&quot;visible&quot;);}this._elTbody.style.display=&quot;&quot;;k=[];for(q=0;q&lt;w;q++){s=u[q];t=l.childNodes[q];if(!s.width&amp;&amp;!s.
 hidden){var n=s.getThEl();if(n.offsetWidth!==t.offsetWidth){var v=(n.offsetWidth&gt;t.offsetWidth)?s.getThLinerEl():t.firstChild;var p=Math.max(0,(v.offsetWidth-(parseInt(d.getStyle(v,&quot;paddingLeft&quot;),10)|0)-(parseInt(d.getStyle(v,&quot;paddingRight&quot;),10)|0)),s.minWidth);var x=&quot;visible&quot;;if((s.maxAutoWidth&gt;0)&amp;&amp;(p&gt;s.maxAutoWidth)){p=s.maxAutoWidth;x=&quot;hidden&quot;;}k[k.length]=[s,p,x];}}}this._elTbody.style.display=&quot;none&quot;;for(q=0,r=k.length;q&lt;r;q++){o=k[q];this._setColumnWidth(o[0],o[1]+&quot;px&quot;,o[2]);o[0]._calculatedWidth=o[1];}this._elTbody.style.display=&quot;&quot;;}if(m){this._elHdContainer.style.width=m;this._elBdContainer.style.width=m;
+}}this._syncScroll();this._restoreScrollPositions();},_syncScroll:function(){this._syncScrollX();this._syncScrollY();this._syncScrollOverhang();if(a.opera){this._elHdContainer.scrollLeft=this._elBdContainer.scrollLeft;if(!this.get(&quot;width&quot;)){document.body.style+=&quot;&quot;;}}},_syncScrollY:function(){var k=this._elTbody,l=this._elBdContainer;if(!this.get(&quot;width&quot;)){this._elContainer.style.width=(l.scrollHeight&gt;l.clientHeight)?(k.parentNode.clientWidth+19)+&quot;px&quot;:(k.parentNode.clientWidth+2)+&quot;px&quot;;}},_syncScrollX:function(){var k=this._elTbody,l=this._elBdContainer;if(!this.get(&quot;height&quot;)&amp;&amp;(a.ie)){l.style.height=(l.scrollWidth&gt;l.offsetWidth)?(k.parentNode.offsetHeight+18)+&quot;px&quot;:k.parentNode.offsetHeight+&quot;px&quot;;}if(this._elTbody.rows.length===0){this._elMsgTbody.parentNode.style.width=this.getTheadEl().parentNode.offsetWidth+&quot;px&quot;;}else{this._elMsgTbody.parentNode.style.width=&quot;&quot;;}},
 _syncScrollOverhang:function(){var l=this._elBdContainer,k=1;if((l.scrollHeight&gt;l.clientHeight)&amp;&amp;(l.scrollWidth&gt;l.clientWidth)){k=18;}this._setOverhangValue(k);},_setOverhangValue:function(n){var p=this._oColumnSet.headers[this._oColumnSet.headers.length-1]||[],l=p.length,k=this._sId+&quot;-fixedth-&quot;,o=n+&quot;px solid &quot;+this.get(&quot;COLOR_COLUMNFILLER&quot;);this._elThead.style.display=&quot;none&quot;;for(var m=0;m&lt;l;m++){d.get(k+p[m]).style.borderRight=o;}this._elThead.style.display=&quot;&quot;;},getHdContainerEl:function(){return this._elHdContainer;},getBdContainerEl:function(){return this._elBdContainer;},getHdTableEl:function(){return this._elHdTable;},getBdTableEl:function(){return this._elTable;},disable:function(){var k=this._elMask;k.style.width=this._elBdContainer.offsetWidth+&quot;px&quot;;k.style.height=this._elHdContainer.offsetHeight+this._elBdContainer.offsetHeight+&quot;px&quot;;k.style.display=&quot;&quot;;this.fireEvent(&quot
 ;disableEvent&quot;);},removeColumn:function(m){var k=this._elHdContainer.scrollLeft;var l=this._elBdContainer.scrollLeft;m=h.superclass.removeColumn.call(this,m);this._elHdContainer.scrollLeft=k;this._elBdContainer.scrollLeft=l;return m;},insertColumn:function(n,l){var k=this._elHdContainer.scrollLeft;var m=this._elBdContainer.scrollLeft;var o=h.superclass.insertColumn.call(this,n,l);this._elHdContainer.scrollLeft=k;this._elBdContainer.scrollLeft=m;return o;},reorderColumn:function(n,l){var k=this._elHdContainer.scrollLeft;var m=this._elBdContainer.scrollLeft;var o=h.superclass.reorderColumn.call(this,n,l);this._elHdContainer.scrollLeft=k;this._elBdContainer.scrollLeft=m;return o;},setColumnWidth:function(l,k){l=this.getColumn(l);if(l){this._storeScrollPositions();if(c.isNumber(k)){k=(k&gt;l.minWidth)?k:l.minWidth;l.width=k;this._setColumnWidth(l,k+&quot;px&quot;);this._syncScroll();this.fireEvent(&quot;columnSetWidthEvent&quot;,{column:l,width:k});}else{if(k===null){l.widt
 h=k;this._setColumnWidth(l,&quot;auto&quot;);this.validateColumnWidths(l);this.fireEvent(&quot;columnUnsetWidthEvent&quot;,{column:l});}}this._clearTrTemplateEl();}else{}},scrollTo:function(m){var l=this.getTdEl(m);if(l){this.clearScrollPositions();this.getBdContainerEl().scrollLeft=l.offsetLeft;this.getBdContainerEl().scrollTop=l.parentNode.offsetTop;}else{var k=this.getTrEl(m);if(k){this.clearScrollPositions();this.getBdContainerEl().scrollTop=k.offsetTop;}}},showTableMessage:function(o,k){var p=this._elMsgTd;if(c.isString(o)){p.firstChild.innerHTML=o;}if(c.isString(k)){d.addClass(p.firstChild,k);}var n=this.getTheadEl();var l=n.parentNode;var m=l.offsetWidth;this._elMsgTbody.parentNode.style.width=this.getTheadEl().parentNode.offsetWidth+&quot;px&quot;;this._elMsgTbody.style.display=&quot;&quot;;this.fireEvent(&quot;tableMsgShowEvent&quot;,{html:o,className:k});},_onColumnChange:function(k){var l=(k.column)?k.column:(k.editor)?k.editor.column:null;this._storeScrollPositio
 ns();this.validateColumnWidths(l);},_onScroll:function(m,l){l._elHdContainer.scrollLeft=l._elBdContainer.scrollLeft;if(l._oCellEditor&amp;&amp;l._oCellEditor.isActive){l.fireEvent(&quot;editorBlurEvent&quot;,{editor:l._oCellEditor});l.cancelCellEditor();}var n=j.getTarget(m);var k=n.nodeName.toLowerCase();l.fireEvent(&quot;tableScrollEvent&quot;,{event:m,target:n});},_onTheadKeydown:function(n,l){if(j.getCharCode(n)===9){setTimeout(function(){if((l instanceof h)&amp;&amp;l._sId){l._elBdContainer.scrollLeft=l._elHdContainer.scrollLeft;}},0);}var o=j.getTarget(n);var k=o.nodeName.toLowerCase();var m=true;while(o&amp;&amp;(k!=&quot;table&quot;)){switch(k){case&quot;body&quot;:return;case&quot;input&quot;:case&quot;textarea&quot;:break;case&quot;thead&quot;:m=l.fireEvent(&quot;theadKeyEvent&quot;,{target:o,event:n});break;default:break;}if(m===false){return;}else{o=o.parentNode;if(o){k=o.nodeName.toLowerCase();}}}l.fireEvent(&quot;tableKeyEvent&quot;,{target:(o||l._elContainer),
 event:n});}});})();(function(){var c=YAHOO.lang,f=YAHOO.util,e=YAHOO.widget,b=YAHOO.env.ua,d=f.Dom,i=f.Event,h=e.DataTable;e.BaseCellEditor=function(k,j){this._sId=this._sId||d.generateId(null,&quot;yui-ceditor&quot;);YAHOO.widget.BaseCellEditor._nCount++;this._sType=k;this._initConfigs(j);this._initEvents();this._needsRender=true;};var a=e.BaseCellEditor;c.augmentObject(a,{_nCount:0,CLASS_CELLEDITOR:&quot;yui-ceditor&quot;});a.prototype={_sId:null,_sType:null,_oDataTable:null,_oColumn:null,_oRecord:null,_elTd:null,_elContainer:null,_elCancelBtn:null,_elSaveBtn:null,_initConfigs:function(k){if(k&amp;&amp;YAHOO.lang.isObject(k)){for(var j in k){if(j){this[j]=k[j];}}}},_initEvents:function(){this.createEvent(&quot;showEvent&quot;);this.createEvent(&quot;keydownEvent&quot;);this.createEvent(&quot;invalidDataEvent&quot;);this.createEvent(&quot;revertEvent&quot;);this.createEvent(&quot;saveEvent&quot;);this.createEvent(&quot;cancelEvent&quot;);this.createEvent(&quot;blurEvent&quo
 t;);this.createEvent(&quot;blockEvent&quot;);this.createEvent(&quot;unblockEvent&quot;);},_initContainerEl:function(){if(this._elContainer){YAHOO.util.Event.purgeElement(this._elContainer,true);this._elContainer.innerHTML=&quot;&quot;;}var j=document.createElement(&quot;div&quot;);j.id=this.getId()+&quot;-container&quot;;j.style.display=&quot;none&quot;;j.tabIndex=0;this.className=c.isArray(this.className)?this.className:this.className?[this.className]:[];this.className[this.className.length]=h.CLASS_EDITOR;j.className=this.className.join(&quot; &quot;);document.body.insertBefore(j,document.body.firstChild);this._elContainer=j;},_initShimEl:function(){if(this.useIFrame){if(!this._elIFrame){var j=document.createElement(&quot;iframe&quot;);
+j.src=&quot;javascript:false&quot;;j.frameBorder=0;j.scrolling=&quot;no&quot;;j.style.display=&quot;none&quot;;j.className=h.CLASS_EDITOR_SHIM;j.tabIndex=-1;j.role=&quot;presentation&quot;;j.title=&quot;Presentational iframe shim&quot;;document.body.insertBefore(j,document.body.firstChild);this._elIFrame=j;}}},_hide:function(){this.getContainerEl().style.display=&quot;none&quot;;if(this._elIFrame){this._elIFrame.style.display=&quot;none&quot;;}this.isActive=false;this.getDataTable()._oCellEditor=null;},asyncSubmitter:null,value:null,defaultValue:null,validator:null,resetInvalidData:true,isActive:false,LABEL_SAVE:&quot;Save&quot;,LABEL_CANCEL:&quot;Cancel&quot;,disableBtns:false,useIFrame:false,className:null,toString:function(){return&quot;CellEditor instance &quot;+this._sId;},getId:function(){return this._sId;},getDataTable:function(){return this._oDataTable;},getColumn:function(){return this._oColumn;},getRecord:function(){return this._oRecord;},getTdEl:function(){return 
 this._elTd;},getContainerEl:function(){return this._elContainer;},destroy:function(){this.unsubscribeAll();var k=this.getColumn();if(k){k.editor=null;}var j=this.getContainerEl();if(j){i.purgeElement(j,true);j.parentNode.removeChild(j);}},render:function(){if(!this._needsRender){return;}this._initContainerEl();this._initShimEl();i.addListener(this.getContainerEl(),&quot;keydown&quot;,function(l,j){if((l.keyCode==27)){var k=i.getTarget(l);if(k.nodeName&amp;&amp;k.nodeName.toLowerCase()===&quot;select&quot;){k.blur();}j.cancel();}j.fireEvent(&quot;keydownEvent&quot;,{editor:j,event:l});},this);this.renderForm();if(!this.disableBtns){this.renderBtns();}this.doAfterRender();this._needsRender=false;},renderBtns:function(){var l=this.getContainerEl().appendChild(document.createElement(&quot;div&quot;));l.className=h.CLASS_BUTTON;var k=l.appendChild(document.createElement(&quot;button&quot;));k.className=h.CLASS_DEFAULT;k.innerHTML=this.LABEL_SAVE;i.addListener(k,&quot;click&quot;,
 function(m){this.save();},this,true);this._elSaveBtn=k;var j=l.appendChild(document.createElement(&quot;button&quot;));j.innerHTML=this.LABEL_CANCEL;i.addListener(j,&quot;click&quot;,function(m){this.cancel();},this,true);this._elCancelBtn=j;},attach:function(n,l){if(n instanceof YAHOO.widget.DataTable){this._oDataTable=n;l=n.getTdEl(l);if(l){this._elTd=l;var m=n.getColumn(l);if(m){this._oColumn=m;var j=n.getRecord(l);if(j){this._oRecord=j;var k=j.getData(this.getColumn().getField());this.value=(k!==undefined)?k:this.defaultValue;return true;}}}}return false;},move:function(){var m=this.getContainerEl(),l=this.getTdEl(),j=d.getX(l),n=d.getY(l);if(isNaN(j)||isNaN(n)){var k=this.getDataTable().getTbodyEl();j=l.offsetLeft+d.getX(k.parentNode)-k.scrollLeft;n=l.offsetTop+d.getY(k.parentNode)-k.scrollTop+this.getDataTable().getTheadEl().offsetHeight;}m.style.left=j+&quot;px&quot;;m.style.top=n+&quot;px&quot;;if(this._elIFrame){this._elIFrame.style.left=j+&quot;px&quot;;this._elIFr
 ame.style.top=n+&quot;px&quot;;}},show:function(){var k=this.getContainerEl(),j=this._elIFrame;this.resetForm();this.isActive=true;k.style.display=&quot;&quot;;if(j){j.style.width=k.offsetWidth+&quot;px&quot;;j.style.height=k.offsetHeight+&quot;px&quot;;j.style.display=&quot;&quot;;}this.focus();this.fireEvent(&quot;showEvent&quot;,{editor:this});},block:function(){this.fireEvent(&quot;blockEvent&quot;,{editor:this});},unblock:function(){this.fireEvent(&quot;unblockEvent&quot;,{editor:this});},save:function(){var k=this.getInputValue();var l=k;if(this.validator){l=this.validator.call(this.getDataTable(),k,this.value,this);if(l===undefined){if(this.resetInvalidData){this.resetForm();}this.fireEvent(&quot;invalidDataEvent&quot;,{editor:this,oldData:this.value,newData:k});return;}}var m=this;var j=function(o,n){var p=m.value;if(o){m.value=n;m.getDataTable().updateCell(m.getRecord(),m.getColumn(),n);m._hide();m.fireEvent(&quot;saveEvent&quot;,{editor:m,oldData:p,newData:m.value}
 );}else{m.resetForm();m.fireEvent(&quot;revertEvent&quot;,{editor:m,oldData:p,newData:n});}m.unblock();};this.block();if(c.isFunction(this.asyncSubmitter)){this.asyncSubmitter.call(this,j,l);}else{j(true,l);}},cancel:function(){if(this.isActive){this._hide();this.fireEvent(&quot;cancelEvent&quot;,{editor:this});}else{}},renderForm:function(){},doAfterRender:function(){},handleDisabledBtns:function(){},resetForm:function(){},focus:function(){},getInputValue:function(){}};c.augmentProto(a,f.EventProvider);e.CheckboxCellEditor=function(j){j=j||{};this._sId=this._sId||d.generateId(null,&quot;yui-checkboxceditor&quot;);YAHOO.widget.BaseCellEditor._nCount++;e.CheckboxCellEditor.superclass.constructor.call(this,j.type||&quot;checkbox&quot;,j);};c.extend(e.CheckboxCellEditor,a,{checkboxOptions:null,checkboxes:null,value:null,renderForm:function(){if(c.isArray(this.checkboxOptions)){var n,o,q,l,m,k;for(m=0,k=this.checkboxOptions.length;m&lt;k;m++){n=this.checkboxOptions[m];o=c.isValu
 e(n.value)?n.value:n;q=this.getId()+&quot;-chk&quot;+m;this.getContainerEl().innerHTML+='&lt;input type=&quot;checkbox&quot;'+' id=&quot;'+q+'&quot;'+' value=&quot;'+o+'&quot; /&gt;';l=this.getContainerEl().appendChild(document.createElement(&quot;label&quot;));l.htmlFor=q;l.innerHTML=c.isValue(n.label)?n.label:n;}var p=[];for(m=0;m&lt;k;m++){p[p.length]=this.getContainerEl().childNodes[m*2];}this.checkboxes=p;if(this.disableBtns){this.handleDisabledBtns();}}else{}},handleDisabledBtns:function(){i.addListener(this.getContainerEl(),&quot;click&quot;,function(j){if(i.getTarget(j).tagName.toLowerCase()===&quot;input&quot;){this.save();}},this,true);},resetForm:function(){var p=c.isArray(this.value)?this.value:[this.value];for(var o=0,n=this.checkboxes.length;o&lt;n;o++){this.checkboxes[o].checked=false;for(var m=0,l=p.length;m&lt;l;m++){if(this.checkboxes[o].value==p[m]){this.checkboxes[o].checked=true;}}}},focus:function(){this.checkboxes[0].focus();},getInputValue:function(){
 var k=[];for(var m=0,l=this.checkboxes.length;m&lt;l;m++){if(this.checkboxes[m].checked){k[k.length]=this.checkboxes[m].value;}}return k;}});c.augmentObject(e.CheckboxCellEditor,a);e.DateCellEditor=function(j){j=j||{};this._sId=this._sId||d.generateId(null,&quot;yui-dateceditor&quot;);YAHOO.widget.BaseCellEditor._nCount++;e.DateCellEditor.superclass.constructor.call(this,j.type||&quot;date&quot;,j);};c.extend(e.DateCellEditor,a,{calendar:null,calendarOptions:null,defaultValue:new Date(),renderForm:function(){if(YAHOO.widget.Calendar){var k=this.getContainerEl().appendChild(document.createElement(&quot;div&quot;));
+k.id=this.getId()+&quot;-dateContainer&quot;;var l=new YAHOO.widget.Calendar(this.getId()+&quot;-date&quot;,k.id,this.calendarOptions);l.render();k.style.cssFloat=&quot;none&quot;;l.hideEvent.subscribe(function(){this.cancel();},this,true);if(b.ie){var j=this.getContainerEl().appendChild(document.createElement(&quot;div&quot;));j.style.clear=&quot;both&quot;;}this.calendar=l;if(this.disableBtns){this.handleDisabledBtns();}}else{}},handleDisabledBtns:function(){this.calendar.selectEvent.subscribe(function(j){this.save();},this,true);},resetForm:function(){var j=this.value||(new Date());this.calendar.select(j);this.calendar.cfg.setProperty(&quot;pagedate&quot;,j,false);this.calendar.render();this.calendar.show();},focus:function(){},getInputValue:function(){return this.calendar.getSelectedDates()[0];}});c.augmentObject(e.DateCellEditor,a);e.DropdownCellEditor=function(j){j=j||{};this._sId=this._sId||d.generateId(null,&quot;yui-dropdownceditor&quot;);YAHOO.widget.BaseCellEditor
 ._nCount++;e.DropdownCellEditor.superclass.constructor.call(this,j.type||&quot;dropdown&quot;,j);};c.extend(e.DropdownCellEditor,a,{dropdownOptions:null,dropdown:null,multiple:false,size:null,renderForm:function(){var n=this.getContainerEl().appendChild(document.createElement(&quot;select&quot;));n.style.zoom=1;if(this.multiple){n.multiple=&quot;multiple&quot;;}if(c.isNumber(this.size)){n.size=this.size;}this.dropdown=n;if(c.isArray(this.dropdownOptions)){var o,m;for(var l=0,k=this.dropdownOptions.length;l&lt;k;l++){o=this.dropdownOptions[l];m=document.createElement(&quot;option&quot;);m.value=(c.isValue(o.value))?o.value:o;m.innerHTML=(c.isValue(o.label))?o.label:o;m=n.appendChild(m);}if(this.disableBtns){this.handleDisabledBtns();}}},handleDisabledBtns:function(){if(this.multiple){i.addListener(this.dropdown,&quot;blur&quot;,function(j){this.save();},this,true);}else{if(!b.ie){i.addListener(this.dropdown,&quot;change&quot;,function(j){this.save();},this,true);}else{i.addLi
 stener(this.dropdown,&quot;blur&quot;,function(j){this.save();},this,true);i.addListener(this.dropdown,&quot;click&quot;,function(j){this.save();},this,true);}}},resetForm:function(){var s=this.dropdown.options,p=0,o=s.length;if(c.isArray(this.value)){var l=this.value,k=0,r=l.length,q={};for(;p&lt;o;p++){s[p].selected=false;q[s[p].value]=s[p];}for(;k&lt;r;k++){if(q[l[k]]){q[l[k]].selected=true;}}}else{for(;p&lt;o;p++){if(this.value==s[p].value){s[p].selected=true;}}}},focus:function(){this.getDataTable()._focusEl(this.dropdown);},getInputValue:function(){var n=this.dropdown.options;if(this.multiple){var k=[],m=0,l=n.length;for(;m&lt;l;m++){if(n[m].selected){k.push(n[m].value);}}return k;}else{return n[n.selectedIndex].value;}}});c.augmentObject(e.DropdownCellEditor,a);e.RadioCellEditor=function(j){j=j||{};this._sId=this._sId||d.generateId(null,&quot;yui-radioceditor&quot;);YAHOO.widget.BaseCellEditor._nCount++;e.RadioCellEditor.superclass.constructor.call(this,j.type||&quot;
 radio&quot;,j);};c.extend(e.RadioCellEditor,a,{radios:null,radioOptions:null,renderForm:function(){if(c.isArray(this.radioOptions)){var k,l,r,o;for(var n=0,p=this.radioOptions.length;n&lt;p;n++){k=this.radioOptions[n];l=c.isValue(k.value)?k.value:k;r=this.getId()+&quot;-radio&quot;+n;this.getContainerEl().innerHTML+='&lt;input type=&quot;radio&quot;'+' name=&quot;'+this.getId()+'&quot;'+' value=&quot;'+l+'&quot;'+' id=&quot;'+r+'&quot; /&gt;';o=this.getContainerEl().appendChild(document.createElement(&quot;label&quot;));o.htmlFor=r;o.innerHTML=(c.isValue(k.label))?k.label:k;}var q=[],s;for(var m=0;m&lt;p;m++){s=this.getContainerEl().childNodes[m*2];q[q.length]=s;}this.radios=q;if(this.disableBtns){this.handleDisabledBtns();}}else{}},handleDisabledBtns:function(){i.addListener(this.getContainerEl(),&quot;click&quot;,function(j){if(i.getTarget(j).tagName.toLowerCase()===&quot;input&quot;){this.save();}},this,true);},resetForm:function(){for(var m=0,l=this.radios.length;m&lt;l;
 m++){var k=this.radios[m];if(this.value==k.value){k.checked=true;return;}}},focus:function(){for(var l=0,k=this.radios.length;l&lt;k;l++){if(this.radios[l].checked){this.radios[l].focus();return;}}},getInputValue:function(){for(var l=0,k=this.radios.length;l&lt;k;l++){if(this.radios[l].checked){return this.radios[l].value;}}}});c.augmentObject(e.RadioCellEditor,a);e.TextareaCellEditor=function(j){j=j||{};this._sId=this._sId||d.generateId(null,&quot;yui-textareaceditor&quot;);YAHOO.widget.BaseCellEditor._nCount++;e.TextareaCellEditor.superclass.constructor.call(this,j.type||&quot;textarea&quot;,j);};c.extend(e.TextareaCellEditor,a,{textarea:null,renderForm:function(){var j=this.getContainerEl().appendChild(document.createElement(&quot;textarea&quot;));this.textarea=j;if(this.disableBtns){this.handleDisabledBtns();}},handleDisabledBtns:function(){i.addListener(this.textarea,&quot;blur&quot;,function(j){this.save();},this,true);},move:function(){this.textarea.style.width=this.g
 etTdEl().offsetWidth+&quot;px&quot;;this.textarea.style.height=&quot;3em&quot;;YAHOO.widget.TextareaCellEditor.superclass.move.call(this);},resetForm:function(){this.textarea.value=this.value;},focus:function(){this.getDataTable()._focusEl(this.textarea);this.textarea.select();},getInputValue:function(){return this.textarea.value;}});c.augmentObject(e.TextareaCellEditor,a);e.TextboxCellEditor=function(j){j=j||{};this._sId=this._sId||d.generateId(null,&quot;yui-textboxceditor&quot;);YAHOO.widget.BaseCellEditor._nCount++;e.TextboxCellEditor.superclass.constructor.call(this,j.type||&quot;textbox&quot;,j);};c.extend(e.TextboxCellEditor,a,{textbox:null,renderForm:function(){var j;if(b.webkit&gt;420){j=this.getContainerEl().appendChild(document.createElement(&quot;form&quot;)).appendChild(document.createElement(&quot;input&quot;));}else{j=this.getContainerEl().appendChild(document.createElement(&quot;input&quot;));}j.type=&quot;text&quot;;this.textbox=j;i.addListener(j,&quot;keypr
 ess&quot;,function(k){if((k.keyCode===13)){YAHOO.util.Event.preventDefault(k);this.save();}},this,true);if(this.disableBtns){this.handleDisabledBtns();}},move:function(){this.textbox.style.width=this.getTdEl().offsetWidth+&quot;px&quot;;e.TextboxCellEditor.superclass.move.call(this);},resetForm:function(){this.textbox.value=c.isValue(this.value)?this.value.toString():&quot;&quot;;},focus:function(){this.getDataTable()._focusEl(this.textbox);this.textbox.select();},getInputValue:function(){return this.textbox.value;
+}});c.augmentObject(e.TextboxCellEditor,a);h.Editors={checkbox:e.CheckboxCellEditor,&quot;date&quot;:e.DateCellEditor,dropdown:e.DropdownCellEditor,radio:e.RadioCellEditor,textarea:e.TextareaCellEditor,textbox:e.TextboxCellEditor};e.CellEditor=function(k,j){if(k&amp;&amp;h.Editors[k]){c.augmentObject(a,h.Editors[k]);return new h.Editors[k](j);}else{return new a(null,j);}};var g=e.CellEditor;c.augmentObject(g,a);})();YAHOO.register(&quot;datatable&quot;,YAHOO.widget.DataTable,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuidatemathdatemathminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/datemath/datemath-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/datemath/datemath-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/datemath/datemath-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+YAHOO.widget.DateMath={DAY:&quot;D&quot;,WEEK:&quot;W&quot;,YEAR:&quot;Y&quot;,MONTH:&quot;M&quot;,ONE_DAY_MS:1000*60*60*24,WEEK_ONE_JAN_DATE:1,add:function(A,D,C){var F=new Date(A.getTime());switch(D){case this.MONTH:var E=A.getMonth()+C;var B=0;if(E&lt;0){while(E&lt;0){E+=12;B-=1;}}else{if(E&gt;11){while(E&gt;11){E-=12;B+=1;}}}F.setMonth(E);F.setFullYear(A.getFullYear()+B);break;case this.DAY:this._addDays(F,C);break;case this.YEAR:F.setFullYear(A.getFullYear()+C);break;case this.WEEK:this._addDays(F,(C*7));break;}return F;},_addDays:function(D,C){if(YAHOO.env.ua.webkit&amp;&amp;YAHOO.env.ua.webkit&lt;420){if(C&lt;0){for(var B=-128;C&lt;B;C-=B){D.setDate(D.getDate()+B);}}else{for(var A=96;C&gt;A;C-=A){D.setDate(D.getDate()+A);}}}D.setDate(D.getDate()+C);},subtract:function(A,C,B){return this.add(A,C,(B*-1));},before:function(C,B){var A=B.getTime();if(C.getTime()&lt;A){return true;}else{return false;}},after:function(C,B){var A=B.getTime();if(C.getTime()&gt;A){return true;}
 else{return false;}},between:function(B,A,C){if(this.after(B,A)&amp;&amp;this.before(B,C)){return true;}else{return false;}},getJan1:function(A){return this.getDate(A,0,1);},getDayOffset:function(B,D){var C=this.getJan1(D);var A=Math.ceil((B.getTime()-C.getTime())/this.ONE_DAY_MS);return A;},getWeekNumber:function(D,B,G){B=B||0;G=G||this.WEEK_ONE_JAN_DATE;var H=this.clearTime(D),L,M;if(H.getDay()===B){L=H;}else{L=this.getFirstDayOfWeek(H,B);}var I=L.getFullYear();M=new Date(L.getTime()+6*this.ONE_DAY_MS);var F;if(I!==M.getFullYear()&amp;&amp;M.getDate()&gt;=G){F=1;}else{var E=this.clearTime(this.getDate(I,0,G)),A=this.getFirstDayOfWeek(E,B);var J=Math.round((H.getTime()-A.getTime())/this.ONE_DAY_MS);var K=J%7;var C=(J-K)/7;F=C+1;}return F;},getFirstDayOfWeek:function(D,A){A=A||0;var B=D.getDay(),C=(B-A+7)%7;return this.subtract(D,this.DAY,C);},isYearOverlapWeek:function(A){var C=false;var B=this.add(A,this.DAY,6);if(B.getFullYear()!=A.getFullYear()){C=true;}return C;},isMont
 hOverlapWeek:function(A){var C=false;var B=this.add(A,this.DAY,6);if(B.getMonth()!=A.getMonth()){C=true;}return C;},findMonthStart:function(A){var B=this.getDate(A.getFullYear(),A.getMonth(),1);return B;},findMonthEnd:function(B){var D=this.findMonthStart(B);var C=this.add(D,this.MONTH,1);var A=this.subtract(C,this.DAY,1);return A;},clearTime:function(A){A.setHours(12,0,0,0);return A;},getDate:function(D,A,C){var B=null;if(YAHOO.lang.isUndefined(C)){C=1;}if(D&gt;=100){B=new Date(D,A,C);}else{B=new Date();B.setFullYear(D);B.setMonth(A);B.setDate(C);B.setHours(0,0,0,0);}return B;}};YAHOO.register(&quot;datemath&quot;,YAHOO.widget.DateMath,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuidomdomminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/dom/dom-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/dom/dom-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/dom/dom-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,9 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+(function(){YAHOO.env._id_counter=YAHOO.env._id_counter||0;var e=YAHOO.util,k=YAHOO.lang,L=YAHOO.env.ua,a=YAHOO.lang.trim,B={},F={},m=/^t(?:able|d|h)$/i,w=/color$/i,j=window.document,v=j.documentElement,C=&quot;ownerDocument&quot;,M=&quot;defaultView&quot;,U=&quot;documentElement&quot;,S=&quot;compatMode&quot;,z=&quot;offsetLeft&quot;,o=&quot;offsetTop&quot;,T=&quot;offsetParent&quot;,x=&quot;parentNode&quot;,K=&quot;nodeType&quot;,c=&quot;tagName&quot;,n=&quot;scrollLeft&quot;,H=&quot;scrollTop&quot;,p=&quot;getBoundingClientRect&quot;,V=&quot;getComputedStyle&quot;,y=&quot;currentStyle&quot;,l=&quot;CSS1Compat&quot;,A=&quot;BackCompat&quot;,E=&quot;class&quot;,f=&quot;className&quot;,i=&quot;&quot;,b=&quot; &quot;,R=&quot;(?:^|\\s)&quot;,J=&quot;(?= |$)&quot;,t=&quot;g&quot;,O=&quot;position&quot;,D=&quot;fixed&quot;,u=&quot;relative&quot;,I=&quot;left&quot;,N=&quot;top&quot;,Q=&quot;medium&quot;,P=&quot;borderLeftWidth&quot;,q=&quot;borderTopWidth&quot;,d=L.opera,h=L.webk
 it,g=L.gecko,s=L.ie;e.Dom={CUSTOM_ATTRIBUTES:(!v.hasAttribute)?{&quot;for&quot;:&quot;htmlFor&quot;,&quot;class&quot;:f}:{&quot;htmlFor&quot;:&quot;for&quot;,&quot;className&quot;:E},DOT_ATTRIBUTES:{checked:true},get:function(aa){var ac,X,ab,Z,W,G,Y=null;if(aa){if(typeof aa==&quot;string&quot;||typeof aa==&quot;number&quot;){ac=aa+&quot;&quot;;aa=j.getElementById(aa);G=(aa)?aa.attributes:null;if(aa&amp;&amp;G&amp;&amp;G.id&amp;&amp;G.id.value===ac){return aa;}else{if(aa&amp;&amp;j.all){aa=null;X=j.all[ac];if(X&amp;&amp;X.length){for(Z=0,W=X.length;Z&lt;W;++Z){if(X[Z].id===ac){return X[Z];}}}}}}else{if(e.Element&amp;&amp;aa instanceof e.Element){aa=aa.get(&quot;element&quot;);}else{if(!aa.nodeType&amp;&amp;&quot;length&quot; in aa){ab=[];for(Z=0,W=aa.length;Z&lt;W;++Z){ab[ab.length]=e.Dom.get(aa[Z]);}aa=ab;}}}Y=aa;}return Y;},getComputedStyle:function(G,W){if(window[V]){return G[C][M][V](G,null)[W];}else{if(G[y]){return e.Dom.IE_ComputedStyle.get(G,W);}}},getStyle:function(G,
 W){return e.Dom.batch(G,e.Dom._getStyle,W);},_getStyle:function(){if(window[V]){return function(G,Y){Y=(Y===&quot;float&quot;)?Y=&quot;cssFloat&quot;:e.Dom._toCamel(Y);var X=G.style[Y],W;if(!X){W=G[C][M][V](G,null);if(W){X=W[Y];}}return X;};}else{if(v[y]){return function(G,Y){var X;switch(Y){case&quot;opacity&quot;:X=100;try{X=G.filters[&quot;DXImageTransform.Microsoft.Alpha&quot;].opacity;}catch(Z){try{X=G.filters(&quot;alpha&quot;).opacity;}catch(W){}}return X/100;case&quot;float&quot;:Y=&quot;styleFloat&quot;;default:Y=e.Dom._toCamel(Y);X=G[y]?G[y][Y]:null;return(G.style[Y]||X);}};}}}(),setStyle:function(G,W,X){e.Dom.batch(G,e.Dom._setStyle,{prop:W,val:X});},_setStyle:function(){if(!window.getComputedStyle&amp;&amp;j.documentElement.currentStyle){return function(W,G){var X=e.Dom._toCamel(G.prop),Y=G.val;if(W){switch(X){case&quot;opacity&quot;:if(Y===&quot;&quot;||Y===null||Y===1){W.style.removeAttribute(&quot;filter&quot;);}else{if(k.isString(W.style.filter)){W.style.filt
 er=&quot;alpha(opacity=&quot;+Y*100+&quot;)&quot;;if(!W[y]||!W[y].hasLayout){W.style.zoom=1;}}}break;case&quot;float&quot;:X=&quot;styleFloat&quot;;default:W.style[X]=Y;}}else{}};}else{return function(W,G){var X=e.Dom._toCamel(G.prop),Y=G.val;if(W){if(X==&quot;float&quot;){X=&quot;cssFloat&quot;;}W.style[X]=Y;}else{}};}}(),getXY:function(G){return e.Dom.batch(G,e.Dom._getXY);},_canPosition:function(G){return(e.Dom._getStyle(G,&quot;display&quot;)!==&quot;none&quot;&amp;&amp;e.Dom._inDoc(G));},_getXY:function(W){var X,G,Z,ab,Y,aa,ac=Math.round,ad=false;if(e.Dom._canPosition(W)){Z=W[p]();ab=W[C];X=e.Dom.getDocumentScrollLeft(ab);G=e.Dom.getDocumentScrollTop(ab);ad=[Z[I],Z[N]];if(Y||aa){ad[0]-=aa;ad[1]-=Y;}if((G||X)){ad[0]+=X;ad[1]+=G;}ad[0]=ac(ad[0]);ad[1]=ac(ad[1]);}else{}return ad;},getX:function(G){var W=function(X){return e.Dom.getXY(X)[0];};return e.Dom.batch(G,W,e.Dom,true);},getY:function(G){var W=function(X){return e.Dom.getXY(X)[1];};return e.Dom.batch(G,W,e.Dom,true)
 ;},setXY:function(G,X,W){e.Dom.batch(G,e.Dom._setXY,{pos:X,noRetry:W});},_setXY:function(G,Z){var aa=e.Dom._getStyle(G,O),Y=e.Dom.setStyle,ad=Z.pos,W=Z.noRetry,ab=[parseInt(e.Dom.getComputedStyle(G,I),10),parseInt(e.Dom.getComputedStyle(G,N),10)],ac,X;ac=e.Dom._getXY(G);if(!ad||ac===false){return false;}if(aa==&quot;static&quot;){aa=u;Y(G,O,aa);}if(isNaN(ab[0])){ab[0]=(aa==u)?0:G[z];}if(isNaN(ab[1])){ab[1]=(aa==u)?0:G[o];}if(ad[0]!==null){Y(G,I,ad[0]-ac[0]+ab[0]+&quot;px&quot;);}if(ad[1]!==null){Y(G,N,ad[1]-ac[1]+ab[1]+&quot;px&quot;);}if(!W){X=e.Dom._getXY(G);if((ad[0]!==null&amp;&amp;X[0]!=ad[0])||(ad[1]!==null&amp;&amp;X[1]!=ad[1])){e.Dom._setXY(G,{pos:ad,noRetry:true});}}},setX:function(W,G){e.Dom.setXY(W,[G,null]);},setY:function(G,W){e.Dom.setXY(G,[null,W]);},getRegion:function(G){var W=function(X){var Y=false;if(e.Dom._canPosition(X)){Y=e.Region.getRegion(X);}else{}return Y;};return e.Dom.batch(G,W,e.Dom,true);},getClientWidth:function(){return e.Dom.getViewportWidth(
 );},getClientHeight:function(){return e.Dom.getViewportHeight();},getElementsByClassName:function(ab,af,ac,ae,X,ad){af=af||&quot;*&quot;;ac=(ac)?e.Dom.get(ac):null||j;if(!ac){return[];}var W=[],G=ac.getElementsByTagName(af),Z=e.Dom.hasClass;for(var Y=0,aa=G.length;Y&lt;aa;++Y){if(Z(G[Y],ab)){W[W.length]=G[Y];}}if(ae){e.Dom.batch(W,ae,X,ad);}return W;},hasClass:function(W,G){return e.Dom.batch(W,e.Dom._hasClass,G);},_hasClass:function(X,W){var G=false,Y;if(X&amp;&amp;W){Y=e.Dom._getAttribute(X,f)||i;if(Y){Y=Y.replace(/\s+/g,b);}if(W.exec){G=W.test(Y);}else{G=W&amp;&amp;(b+Y+b).indexOf(b+W+b)&gt;-1;}}else{}return G;},addClass:function(W,G){return e.Dom.batch(W,e.Dom._addClass,G);},_addClass:function(X,W){var G=false,Y;if(X&amp;&amp;W){Y=e.Dom._getAttribute(X,f)||i;if(!e.Dom._hasClass(X,W)){e.Dom.setAttribute(X,f,a(Y+b+W));G=true;}}else{}return G;},removeClass:function(W,G){return e.Dom.batch(W,e.Dom._removeClass,G);},_removeClass:function(Y,X){var W=false,aa,Z,G;if(Y&amp;&amp;
 X){aa=e.Dom._getAttribute(Y,f)||i;e.Dom.setAttribute(Y,f,aa.replace(e.Dom._getClassRegex(X),i));Z=e.Dom._getAttribute(Y,f);if(aa!==Z){e.Dom.setAttribute(Y,f,a(Z));W=true;if(e.Dom._getAttribute(Y,f)===&quot;&quot;){G=(Y.hasAttribute&amp;&amp;Y.hasAttribute(E))?E:f;Y.removeAttribute(G);}}}else{}return W;},replaceClass:function(X,W,G){return e.Dom.batch(X,e.Dom._replaceClass,{from:W,to:G});},_replaceClass:function(Y,X){var W,ab,aa,G=false,Z;if(Y&amp;&amp;X){ab=X.from;aa=X.to;if(!aa){G=false;}else{if(!ab){G=e.Dom._addClass(Y,X.to);}else{if(ab!==aa){Z=e.Dom._getAttribute(Y,f)||i;W=(b+Z.replace(e.Dom._getClassRegex(ab),b+aa).replace(/\s+/g,b)).split(e.Dom._getClassRegex(aa));W.splice(1,0,b+aa);e.Dom.setAttribute(Y,f,a(W.join(i)));G=true;}}}}else{}return G;},generateId:function(G,X){X=X||&quot;yui-gen&quot;;var W=function(Y){if(Y&amp;&amp;Y.id){return Y.id;}var Z=X+YAHOO.env._id_counter++;
+if(Y){if(Y[C]&amp;&amp;Y[C].getElementById(Z)){return e.Dom.generateId(Y,Z+X);}Y.id=Z;}return Z;};return e.Dom.batch(G,W,e.Dom,true)||W.apply(e.Dom,arguments);},isAncestor:function(W,X){W=e.Dom.get(W);X=e.Dom.get(X);var G=false;if((W&amp;&amp;X)&amp;&amp;(W[K]&amp;&amp;X[K])){if(W.contains&amp;&amp;W!==X){G=W.contains(X);}else{if(W.compareDocumentPosition){G=!!(W.compareDocumentPosition(X)&amp;16);}}}else{}return G;},inDocument:function(G,W){return e.Dom._inDoc(e.Dom.get(G),W);},_inDoc:function(W,X){var G=false;if(W&amp;&amp;W[c]){X=X||W[C];G=e.Dom.isAncestor(X[U],W);}else{}return G;},getElementsBy:function(W,af,ab,ad,X,ac,ae){af=af||&quot;*&quot;;ab=(ab)?e.Dom.get(ab):null||j;var aa=(ae)?null:[],G;if(ab){G=ab.getElementsByTagName(af);for(var Y=0,Z=G.length;Y&lt;Z;++Y){if(W(G[Y])){if(ae){aa=G[Y];break;}else{aa[aa.length]=G[Y];}}}if(ad){e.Dom.batch(aa,ad,X,ac);}}return aa;},getElementBy:function(X,G,W){return e.Dom.getElementsBy(X,G,W,null,null,null,true);},batch:function(X,a
 b,aa,Z){var Y=[],W=(Z)?aa:null;X=(X&amp;&amp;(X[c]||X.item))?X:e.Dom.get(X);if(X&amp;&amp;ab){if(X[c]||X.length===undefined){return ab.call(W,X,aa);}for(var G=0;G&lt;X.length;++G){Y[Y.length]=ab.call(W||X[G],X[G],aa);}}else{return false;}return Y;},getDocumentHeight:function(){var W=(j[S]!=l||h)?j.body.scrollHeight:v.scrollHeight,G=Math.max(W,e.Dom.getViewportHeight());return G;},getDocumentWidth:function(){var W=(j[S]!=l||h)?j.body.scrollWidth:v.scrollWidth,G=Math.max(W,e.Dom.getViewportWidth());return G;},getViewportHeight:function(){var G=self.innerHeight,W=j[S];if((W||s)&amp;&amp;!d){G=(W==l)?v.clientHeight:j.body.clientHeight;}return G;},getViewportWidth:function(){var G=self.innerWidth,W=j[S];if(W||s){G=(W==l)?v.clientWidth:j.body.clientWidth;}return G;},getAncestorBy:function(G,W){while((G=G[x])){if(e.Dom._testElement(G,W)){return G;}}return null;},getAncestorByClassName:function(W,G){W=e.Dom.get(W);if(!W){return null;}var X=function(Y){return e.Dom.hasClass(Y,G);};re
 turn e.Dom.getAncestorBy(W,X);},getAncestorByTagName:function(W,G){W=e.Dom.get(W);if(!W){return null;}var X=function(Y){return Y[c]&amp;&amp;Y[c].toUpperCase()==G.toUpperCase();};return e.Dom.getAncestorBy(W,X);},getPreviousSiblingBy:function(G,W){while(G){G=G.previousSibling;if(e.Dom._testElement(G,W)){return G;}}return null;},getPreviousSibling:function(G){G=e.Dom.get(G);if(!G){return null;}return e.Dom.getPreviousSiblingBy(G);},getNextSiblingBy:function(G,W){while(G){G=G.nextSibling;if(e.Dom._testElement(G,W)){return G;}}return null;},getNextSibling:function(G){G=e.Dom.get(G);if(!G){return null;}return e.Dom.getNextSiblingBy(G);},getFirstChildBy:function(G,X){var W=(e.Dom._testElement(G.firstChild,X))?G.firstChild:null;return W||e.Dom.getNextSiblingBy(G.firstChild,X);},getFirstChild:function(G,W){G=e.Dom.get(G);if(!G){return null;}return e.Dom.getFirstChildBy(G);},getLastChildBy:function(G,X){if(!G){return null;}var W=(e.Dom._testElement(G.lastChild,X))?G.lastChild:null;r
 eturn W||e.Dom.getPreviousSiblingBy(G.lastChild,X);},getLastChild:function(G){G=e.Dom.get(G);return e.Dom.getLastChildBy(G);},getChildrenBy:function(W,Y){var X=e.Dom.getFirstChildBy(W,Y),G=X?[X]:[];e.Dom.getNextSiblingBy(X,function(Z){if(!Y||Y(Z)){G[G.length]=Z;}return false;});return G;},getChildren:function(G){G=e.Dom.get(G);if(!G){}return e.Dom.getChildrenBy(G);},getDocumentScrollLeft:function(G){G=G||j;return Math.max(G[U].scrollLeft,G.body.scrollLeft);},getDocumentScrollTop:function(G){G=G||j;return Math.max(G[U].scrollTop,G.body.scrollTop);},insertBefore:function(W,G){W=e.Dom.get(W);G=e.Dom.get(G);if(!W||!G||!G[x]){return null;}return G[x].insertBefore(W,G);},insertAfter:function(W,G){W=e.Dom.get(W);G=e.Dom.get(G);if(!W||!G||!G[x]){return null;}if(G.nextSibling){return G[x].insertBefore(W,G.nextSibling);}else{return G[x].appendChild(W);}},getClientRegion:function(){var X=e.Dom.getDocumentScrollTop(),W=e.Dom.getDocumentScrollLeft(),Y=e.Dom.getViewportWidth()+W,G=e.Dom.g
 etViewportHeight()+X;return new e.Region(X,Y,G,W);},setAttribute:function(W,G,X){e.Dom.batch(W,e.Dom._setAttribute,{attr:G,val:X});},_setAttribute:function(X,W){var G=e.Dom._toCamel(W.attr),Y=W.val;if(X&amp;&amp;X.setAttribute){if(e.Dom.DOT_ATTRIBUTES[G]&amp;&amp;X.tagName&amp;&amp;X.tagName!=&quot;BUTTON&quot;){X[G]=Y;}else{G=e.Dom.CUSTOM_ATTRIBUTES[G]||G;X.setAttribute(G,Y);}}else{}},getAttribute:function(W,G){return e.Dom.batch(W,e.Dom._getAttribute,G);},_getAttribute:function(W,G){var X;G=e.Dom.CUSTOM_ATTRIBUTES[G]||G;if(e.Dom.DOT_ATTRIBUTES[G]){X=W[G];}else{if(W&amp;&amp;&quot;getAttribute&quot; in W){if(/^(?:href|src)$/.test(G)){X=W.getAttribute(G,2);}else{X=W.getAttribute(G);}}else{}}return X;},_toCamel:function(W){var X=B;function G(Y,Z){return Z.toUpperCase();}return X[W]||(X[W]=W.indexOf(&quot;-&quot;)===-1?W:W.replace(/-([a-z])/gi,G));},_getClassRegex:function(W){var G;if(W!==undefined){if(W.exec){G=W;}else{G=F[W];if(!G){W=W.replace(e.Dom._patterns.CLASS_RE_TOKENS
 ,&quot;\\$1&quot;);W=W.replace(/\s+/g,b);G=F[W]=new RegExp(R+W+J,t);}}}return G;},_patterns:{ROOT_TAG:/^body|html$/i,CLASS_RE_TOKENS:/([\.\(\)\^\$\*\+\?\|\[\]\{\}\\])/g},_testElement:function(G,W){return G&amp;&amp;G[K]==1&amp;&amp;(!W||W(G));},_calcBorders:function(X,Y){var W=parseInt(e.Dom[V](X,q),10)||0,G=parseInt(e.Dom[V](X,P),10)||0;if(g){if(m.test(X[c])){W=0;G=0;}}Y[0]+=G;Y[1]+=W;return Y;}};var r=e.Dom[V];if(L.opera){e.Dom[V]=function(W,G){var X=r(W,G);if(w.test(G)){X=e.Dom.Color.toRGB(X);}return X;};}if(L.webkit){e.Dom[V]=function(W,G){var X=r(W,G);if(X===&quot;rgba(0, 0, 0, 0)&quot;){X=&quot;transparent&quot;;}return X;};}if(L.ie&amp;&amp;L.ie&gt;=8){e.Dom.DOT_ATTRIBUTES.type=true;}})();YAHOO.util.Region=function(d,e,a,c){this.top=d;this.y=d;this[1]=d;this.right=e;this.bottom=a;this.left=c;this.x=c;this[0]=c;this.width=this.right-this.left;this.height=this.bottom-this.top;};YAHOO.util.Region.prototype.contains=function(a){return(a.left&gt;=this.left&amp;&amp;a.right
 &lt;=this.right&amp;&amp;a.top&gt;=this.top&amp;&amp;a.bottom&lt;=this.bottom);};YAHOO.util.Region.prototype.getArea=function(){return((this.bottom-this.top)*(this.right-this.left));};YAHOO.util.Region.prototype.intersect=function(f){var d=Math.max(this.top,f.top),e=Math.min(this.right,f.right),a=Math.min(this.bottom,f.bottom),c=Math.max(this.left,f.left);
+if(a&gt;=d&amp;&amp;e&gt;=c){return new YAHOO.util.Region(d,e,a,c);}else{return null;}};YAHOO.util.Region.prototype.union=function(f){var d=Math.min(this.top,f.top),e=Math.max(this.right,f.right),a=Math.max(this.bottom,f.bottom),c=Math.min(this.left,f.left);return new YAHOO.util.Region(d,e,a,c);};YAHOO.util.Region.prototype.toString=function(){return(&quot;Region {&quot;+&quot;top: &quot;+this.top+&quot;, right: &quot;+this.right+&quot;, bottom: &quot;+this.bottom+&quot;, left: &quot;+this.left+&quot;, height: &quot;+this.height+&quot;, width: &quot;+this.width+&quot;}&quot;);};YAHOO.util.Region.getRegion=function(e){var g=YAHOO.util.Dom.getXY(e),d=g[1],f=g[0]+e.offsetWidth,a=g[1]+e.offsetHeight,c=g[0];return new YAHOO.util.Region(d,f,a,c);};YAHOO.util.Point=function(a,b){if(YAHOO.lang.isArray(a)){b=a[1];a=a[0];}YAHOO.util.Point.superclass.constructor.call(this,b,a,b,a);};YAHOO.extend(YAHOO.util.Point,YAHOO.util.Region);(function(){var b=YAHOO.util,a=&quot;clientTop&quot;,f=
 &quot;clientLeft&quot;,j=&quot;parentNode&quot;,k=&quot;right&quot;,w=&quot;hasLayout&quot;,i=&quot;px&quot;,u=&quot;opacity&quot;,l=&quot;auto&quot;,d=&quot;borderLeftWidth&quot;,g=&quot;borderTopWidth&quot;,p=&quot;borderRightWidth&quot;,v=&quot;borderBottomWidth&quot;,s=&quot;visible&quot;,q=&quot;transparent&quot;,n=&quot;height&quot;,e=&quot;width&quot;,h=&quot;style&quot;,t=&quot;currentStyle&quot;,r=/^width|height$/,o=/^(\d[.\d]*)+(em|ex|px|gd|rem|vw|vh|vm|ch|mm|cm|in|pt|pc|deg|rad|ms|s|hz|khz|%){1}?/i,m={get:function(x,z){var y=&quot;&quot;,A=x[t][z];if(z===u){y=b.Dom.getStyle(x,u);}else{if(!A||(A.indexOf&amp;&amp;A.indexOf(i)&gt;-1)){y=A;}else{if(b.Dom.IE_COMPUTED[z]){y=b.Dom.IE_COMPUTED[z](x,z);}else{if(o.test(A)){y=b.Dom.IE.ComputedStyle.getPixel(x,z);}else{y=A;}}}}return y;},getOffset:function(z,E){var B=z[t][E],x=E.charAt(0).toUpperCase()+E.substr(1),C=&quot;offset&quot;+x,y=&quot;pixel&quot;+x,A=&quot;&quot;,D;if(B==l){D=z[C];if(D===undefined){A=0;}A=D;if(r.tes
 t(E)){z[h][E]=D;if(z[C]&gt;D){A=D-(z[C]-D);}z[h][E]=l;}}else{if(!z[h][y]&amp;&amp;!z[h][E]){z[h][E]=B;}A=z[h][y];}return A+i;},getBorderWidth:function(x,z){var y=null;if(!x[t][w]){x[h].zoom=1;}switch(z){case g:y=x[a];break;case v:y=x.offsetHeight-x.clientHeight-x[a];break;case d:y=x[f];break;case p:y=x.offsetWidth-x.clientWidth-x[f];break;}return y+i;},getPixel:function(y,x){var A=null,B=y[t][k],z=y[t][x];y[h][k]=z;A=y[h].pixelRight;y[h][k]=B;return A+i;},getMargin:function(y,x){var z;if(y[t][x]==l){z=0+i;}else{z=b.Dom.IE.ComputedStyle.getPixel(y,x);}return z;},getVisibility:function(y,x){var z;while((z=y[t])&amp;&amp;z[x]==&quot;inherit&quot;){y=y[j];}return(z)?z[x]:s;},getColor:function(y,x){return b.Dom.Color.toRGB(y[t][x])||q;},getBorderColor:function(y,x){var z=y[t],A=z[x]||z.color;return b.Dom.Color.toRGB(b.Dom.Color.toHex(A));}},c={};c.top=c.right=c.bottom=c.left=c[e]=c[n]=m.getOffset;c.color=m.getColor;c[g]=c[p]=c[v]=c[d]=m.getBorderWidth;c.marginTop=c.marginRight=c.
 marginBottom=c.marginLeft=m.getMargin;c.visibility=m.getVisibility;c.borderColor=c.borderTopColor=c.borderRightColor=c.borderBottomColor=c.borderLeftColor=m.getBorderColor;b.Dom.IE_COMPUTED=c;b.Dom.IE_ComputedStyle=m;})();(function(){var c=&quot;toString&quot;,a=parseInt,b=RegExp,d=YAHOO.util;d.Dom.Color={KEYWORDS:{black:&quot;000&quot;,silver:&quot;c0c0c0&quot;,gray:&quot;808080&quot;,white:&quot;fff&quot;,maroon:&quot;800000&quot;,red:&quot;f00&quot;,purple:&quot;800080&quot;,fuchsia:&quot;f0f&quot;,green:&quot;008000&quot;,lime:&quot;0f0&quot;,olive:&quot;808000&quot;,yellow:&quot;ff0&quot;,navy:&quot;000080&quot;,blue:&quot;00f&quot;,teal:&quot;008080&quot;,aqua:&quot;0ff&quot;},re_RGB:/^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i,re_hex:/^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i,re_hex3:/([0-9A-F])/gi,toRGB:function(e){if(!d.Dom.Color.re_RGB.test(e)){e=d.Dom.Color.toHex(e);}if(d.Dom.Color.re_hex.exec(e)){e=&quot;rgb(&quot;+[a(b.$1,16),a(b.$2,16),a(b.$3,16)].joi
 n(&quot;, &quot;)+&quot;)&quot;;}return e;},toHex:function(f){f=d.Dom.Color.KEYWORDS[f]||f;if(d.Dom.Color.re_RGB.exec(f)){f=[Number(b.$1).toString(16),Number(b.$2).toString(16),Number(b.$3).toString(16)];for(var e=0;e&lt;f.length;e++){if(f[e].length&lt;2){f[e]=&quot;0&quot;+f[e];}}f=f.join(&quot;&quot;);}if(f.length&lt;6){f=f.replace(d.Dom.Color.re_hex3,&quot;$1$1&quot;);}if(f!==&quot;transparent&quot;&amp;&amp;f.indexOf(&quot;#&quot;)&lt;0){f=&quot;#&quot;+f;}return f.toUpperCase();}};}());YAHOO.register(&quot;dom&quot;,YAHOO.util.Dom,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuidragdropdragdropminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/dragdrop/dragdrop-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/dragdrop/dragdrop-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/dragdrop/dragdrop-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+if(!YAHOO.util.DragDropMgr){YAHOO.util.DragDropMgr=function(){var A=YAHOO.util.Event,B=YAHOO.util.Dom;return{useShim:false,_shimActive:false,_shimState:false,_debugShim:false,_createShim:function(){var C=document.createElement(&quot;div&quot;);C.id=&quot;yui-ddm-shim&quot;;if(document.body.firstChild){document.body.insertBefore(C,document.body.firstChild);}else{document.body.appendChild(C);}C.style.display=&quot;none&quot;;C.style.backgroundColor=&quot;red&quot;;C.style.position=&quot;absolute&quot;;C.style.zIndex=&quot;99999&quot;;B.setStyle(C,&quot;opacity&quot;,&quot;0&quot;);this._shim=C;A.on(C,&quot;mouseup&quot;,this.handleMouseUp,this,true);A.on(C,&quot;mousemove&quot;,this.handleMouseMove,this,true);A.on(window,&quot;scroll&quot;,this._sizeShim,this,true);},_sizeShim:function(){if(this._shimActive){var C=this._shim;C.style.height=B.getDocumentHeight()+&quot;px&quot;;C.style.width=B.getDocumentWidth()+&quot;px&quot;;C.style.top=&quot;0&quot;;C.style.left=&quot;0&quot;
 ;}},_activateShim:function(){if(this.useShim){if(!this._shim){this._createShim();}this._shimActive=true;var C=this._shim,D=&quot;0&quot;;if(this._debugShim){D=&quot;.5&quot;;}B.setStyle(C,&quot;opacity&quot;,D);this._sizeShim();C.style.display=&quot;block&quot;;}},_deactivateShim:function(){this._shim.style.display=&quot;none&quot;;this._shimActive=false;},_shim:null,ids:{},handleIds:{},dragCurrent:null,dragOvers:{},deltaX:0,deltaY:0,preventDefault:true,stopPropagation:true,initialized:false,locked:false,interactionInfo:null,init:function(){this.initialized=true;},POINT:0,INTERSECT:1,STRICT_INTERSECT:2,mode:0,_execOnAll:function(E,D){for(var F in this.ids){for(var C in this.ids[F]){var G=this.ids[F][C];if(!this.isTypeOfDD(G)){continue;}G[E].apply(G,D);}}},_onLoad:function(){this.init();A.on(document,&quot;mouseup&quot;,this.handleMouseUp,this,true);A.on(document,&quot;mousemove&quot;,this.handleMouseMove,this,true);A.on(window,&quot;unload&quot;,this._onUnload,this,true);A.o
 n(window,&quot;resize&quot;,this._onResize,this,true);},_onResize:function(C){this._execOnAll(&quot;resetConstraints&quot;,[]);},lock:function(){this.locked=true;},unlock:function(){this.locked=false;},isLocked:function(){return this.locked;},locationCache:{},useCache:true,clickPixelThresh:3,clickTimeThresh:1000,dragThreshMet:false,clickTimeout:null,startX:0,startY:0,fromTimeout:false,regDragDrop:function(D,C){if(!this.initialized){this.init();}if(!this.ids[C]){this.ids[C]={};}this.ids[C][D.id]=D;},removeDDFromGroup:function(E,C){if(!this.ids[C]){this.ids[C]={};}var D=this.ids[C];if(D&amp;&amp;D[E.id]){delete D[E.id];}},_remove:function(E){for(var D in E.groups){if(D){var C=this.ids[D];if(C&amp;&amp;C[E.id]){delete C[E.id];}}}delete this.handleIds[E.id];},regHandle:function(D,C){if(!this.handleIds[D]){this.handleIds[D]={};}this.handleIds[D][C]=C;},isDragDrop:function(C){return(this.getDDById(C))?true:false;},getRelated:function(H,D){var G=[];for(var F in H.groups){for(var E 
 in this.ids[F]){var C=this.ids[F][E];if(!this.isTypeOfDD(C)){continue;}if(!D||C.isTarget){G[G.length]=C;}}}return G;},isLegalTarget:function(G,F){var D=this.getRelated(G,true);for(var E=0,C=D.length;E&lt;C;++E){if(D[E].id==F.id){return true;}}return false;},isTypeOfDD:function(C){return(C&amp;&amp;C.__ygDragDrop);},isHandle:function(D,C){return(this.handleIds[D]&amp;&amp;this.handleIds[D][C]);},getDDById:function(D){for(var C in this.ids){if(this.ids[C][D]){return this.ids[C][D];}}return null;},handleMouseDown:function(E,D){this.currentTarget=YAHOO.util.Event.getTarget(E);this.dragCurrent=D;var C=D.getEl();this.startX=YAHOO.util.Event.getPageX(E);this.startY=YAHOO.util.Event.getPageY(E);this.deltaX=this.startX-C.offsetLeft;this.deltaY=this.startY-C.offsetTop;this.dragThreshMet=false;this.clickTimeout=setTimeout(function(){var F=YAHOO.util.DDM;F.startDrag(F.startX,F.startY);F.fromTimeout=true;},this.clickTimeThresh);},startDrag:function(C,E){if(this.dragCurrent&amp;&amp;this.
 dragCurrent.useShim){this._shimState=this.useShim;this.useShim=true;}this._activateShim();clearTimeout(this.clickTimeout);var D=this.dragCurrent;if(D&amp;&amp;D.events.b4StartDrag){D.b4StartDrag(C,E);D.fireEvent(&quot;b4StartDragEvent&quot;,{x:C,y:E});}if(D&amp;&amp;D.events.startDrag){D.startDrag(C,E);D.fireEvent(&quot;startDragEvent&quot;,{x:C,y:E});}this.dragThreshMet=true;},handleMouseUp:function(C){if(this.dragCurrent){clearTimeout(this.clickTimeout);if(this.dragThreshMet){if(this.fromTimeout){this.fromTimeout=false;this.handleMouseMove(C);}this.fromTimeout=false;this.fireEvents(C,true);}else{}this.stopDrag(C);this.stopEvent(C);}},stopEvent:function(C){if(this.stopPropagation){YAHOO.util.Event.stopPropagation(C);}if(this.preventDefault){YAHOO.util.Event.preventDefault(C);}},stopDrag:function(E,D){var C=this.dragCurrent;if(C&amp;&amp;!D){if(this.dragThreshMet){if(C.events.b4EndDrag){C.b4EndDrag(E);C.fireEvent(&quot;b4EndDragEvent&quot;,{e:E});}if(C.events.endDrag){C.endD
 rag(E);C.fireEvent(&quot;endDragEvent&quot;,{e:E});}}if(C.events.mouseUp){C.onMouseUp(E);C.fireEvent(&quot;mouseUpEvent&quot;,{e:E});}}if(this._shimActive){this._deactivateShim();if(this.dragCurrent&amp;&amp;this.dragCurrent.useShim){this.useShim=this._shimState;this._shimState=false;}}this.dragCurrent=null;this.dragOvers={};},handleMouseMove:function(F){var C=this.dragCurrent;if(C){if(YAHOO.env.ua.ie&amp;&amp;(YAHOO.env.ua.ie&lt;9)&amp;&amp;!F.button){this.stopEvent(F);return this.handleMouseUp(F);}else{if(F.clientX&lt;0||F.clientY&lt;0){}}if(!this.dragThreshMet){var E=Math.abs(this.startX-YAHOO.util.Event.getPageX(F));var D=Math.abs(this.startY-YAHOO.util.Event.getPageY(F));if(E&gt;this.clickPixelThresh||D&gt;this.clickPixelThresh){this.startDrag(this.startX,this.startY);}}if(this.dragThreshMet){if(C&amp;&amp;C.events.b4Drag){C.b4Drag(F);C.fireEvent(&quot;b4DragEvent&quot;,{e:F});}if(C&amp;&amp;C.events.drag){C.onDrag(F);C.fireEvent(&quot;dragEvent&quot;,{e:F});}if(C){this
 .fireEvents(F,false);}}this.stopEvent(F);}},fireEvents:function(W,M){var c=this.dragCurrent;if(!c||c.isLocked()||c.dragOnly){return;}var O=YAHOO.util.Event.getPageX(W),N=YAHOO.util.Event.getPageY(W),Q=new YAHOO.util.Point(O,N),K=c.getTargetCoord(Q.x,Q.y),F=c.getDragEl(),E=[&quot;out&quot;,&quot;over&quot;,&quot;drop&quot;,&quot;enter&quot;],V=new YAHOO.util.Region(K.y,K.x+F.offsetWidth,K.y+F.offsetHeight,K.x),I=[],D={},L={},R=[],d={outEvts:[],overEvts:[],dropEvts:[],enterEvts:[]};for(var T in this.dragOvers){var f=this.dragOvers[T];if(!this.isTypeOfDD(f)){continue;
+}if(!this.isOverTarget(Q,f,this.mode,V)){d.outEvts.push(f);}I[T]=true;delete this.dragOvers[T];}for(var S in c.groups){if(&quot;string&quot;!=typeof S){continue;}for(T in this.ids[S]){var G=this.ids[S][T];if(!this.isTypeOfDD(G)){continue;}if(G.isTarget&amp;&amp;!G.isLocked()&amp;&amp;G!=c){if(this.isOverTarget(Q,G,this.mode,V)){D[S]=true;if(M){d.dropEvts.push(G);}else{if(!I[G.id]){d.enterEvts.push(G);}else{d.overEvts.push(G);}this.dragOvers[G.id]=G;}}}}}this.interactionInfo={out:d.outEvts,enter:d.enterEvts,over:d.overEvts,drop:d.dropEvts,point:Q,draggedRegion:V,sourceRegion:this.locationCache[c.id],validDrop:M};for(var C in D){R.push(C);}if(M&amp;&amp;!d.dropEvts.length){this.interactionInfo.validDrop=false;if(c.events.invalidDrop){c.onInvalidDrop(W);c.fireEvent(&quot;invalidDropEvent&quot;,{e:W});}}for(T=0;T&lt;E.length;T++){var Z=null;if(d[E[T]+&quot;Evts&quot;]){Z=d[E[T]+&quot;Evts&quot;];}if(Z&amp;&amp;Z.length){var H=E[T].charAt(0).toUpperCase()+E[T].substr(1),Y=&quot;o
 nDrag&quot;+H,J=&quot;b4Drag&quot;+H,P=&quot;drag&quot;+H+&quot;Event&quot;,X=&quot;drag&quot;+H;if(this.mode){if(c.events[J]){c[J](W,Z,R);L[Y]=c.fireEvent(J+&quot;Event&quot;,{event:W,info:Z,group:R});}if(c.events[X]&amp;&amp;(L[Y]!==false)){c[Y](W,Z,R);c.fireEvent(P,{event:W,info:Z,group:R});}}else{for(var a=0,U=Z.length;a&lt;U;++a){if(c.events[J]){c[J](W,Z[a].id,R[0]);L[Y]=c.fireEvent(J+&quot;Event&quot;,{event:W,info:Z[a].id,group:R[0]});}if(c.events[X]&amp;&amp;(L[Y]!==false)){c[Y](W,Z[a].id,R[0]);c.fireEvent(P,{event:W,info:Z[a].id,group:R[0]});}}}}}},getBestMatch:function(E){var G=null;var D=E.length;if(D==1){G=E[0];}else{for(var F=0;F&lt;D;++F){var C=E[F];if(this.mode==this.INTERSECT&amp;&amp;C.cursorIsOver){G=C;break;}else{if(!G||!G.overlap||(C.overlap&amp;&amp;G.overlap.getArea()&lt;C.overlap.getArea())){G=C;}}}}return G;},refreshCache:function(D){var F=D||this.ids;for(var C in F){if(&quot;string&quot;!=typeof C){continue;}for(var E in this.ids[C]){var G=this.ids[C
 ][E];if(this.isTypeOfDD(G)){var H=this.getLocation(G);if(H){this.locationCache[G.id]=H;}else{delete this.locationCache[G.id];}}}}},verifyEl:function(D){try{if(D){var C=D.offsetParent;if(C){return true;}}}catch(E){}return false;},getLocation:function(H){if(!this.isTypeOfDD(H)){return null;}var F=H.getEl(),K,E,D,M,L,N,C,J,G;try{K=YAHOO.util.Dom.getXY(F);}catch(I){}if(!K){return null;}E=K[0];D=E+F.offsetWidth;M=K[1];L=M+F.offsetHeight;N=M-H.padding[0];C=D+H.padding[1];J=L+H.padding[2];G=E-H.padding[3];return new YAHOO.util.Region(N,C,J,G);},isOverTarget:function(K,C,E,F){var G=this.locationCache[C.id];if(!G||!this.useCache){G=this.getLocation(C);this.locationCache[C.id]=G;}if(!G){return false;}C.cursorIsOver=G.contains(K);var J=this.dragCurrent;if(!J||(!E&amp;&amp;!J.constrainX&amp;&amp;!J.constrainY)){return C.cursorIsOver;}C.overlap=null;if(!F){var H=J.getTargetCoord(K.x,K.y);var D=J.getDragEl();F=new YAHOO.util.Region(H.y,H.x+D.offsetWidth,H.y+D.offsetHeight,H.x);}var I=F.in
 tersect(G);if(I){C.overlap=I;return(E)?true:C.cursorIsOver;}else{return false;}},_onUnload:function(D,C){this.unregAll();},unregAll:function(){if(this.dragCurrent){this.stopDrag();this.dragCurrent=null;}this._execOnAll(&quot;unreg&quot;,[]);this.ids={};},elementCache:{},getElWrapper:function(D){var C=this.elementCache[D];if(!C||!C.el){C=this.elementCache[D]=new this.ElementWrapper(YAHOO.util.Dom.get(D));}return C;},getElement:function(C){return YAHOO.util.Dom.get(C);},getCss:function(D){var C=YAHOO.util.Dom.get(D);return(C)?C.style:null;},ElementWrapper:function(C){this.el=C||null;this.id=this.el&amp;&amp;C.id;this.css=this.el&amp;&amp;C.style;},getPosX:function(C){return YAHOO.util.Dom.getX(C);},getPosY:function(C){return YAHOO.util.Dom.getY(C);},swapNode:function(E,C){if(E.swapNode){E.swapNode(C);}else{var F=C.parentNode;var D=C.nextSibling;if(D==E){F.insertBefore(E,C);}else{if(C==E.nextSibling){F.insertBefore(C,E);}else{E.parentNode.replaceChild(C,E);F.insertBefore(E,D);}
 }}},getScroll:function(){var E,C,F=document.documentElement,D=document.body;if(F&amp;&amp;(F.scrollTop||F.scrollLeft)){E=F.scrollTop;C=F.scrollLeft;}else{if(D){E=D.scrollTop;C=D.scrollLeft;}else{}}return{top:E,left:C};},getStyle:function(D,C){return YAHOO.util.Dom.getStyle(D,C);},getScrollTop:function(){return this.getScroll().top;},getScrollLeft:function(){return this.getScroll().left;},moveToEl:function(C,E){var D=YAHOO.util.Dom.getXY(E);YAHOO.util.Dom.setXY(C,D);},getClientHeight:function(){return YAHOO.util.Dom.getViewportHeight();},getClientWidth:function(){return YAHOO.util.Dom.getViewportWidth();},numericSort:function(D,C){return(D-C);},_timeoutCount:0,_addListeners:function(){var C=YAHOO.util.DDM;if(YAHOO.util.Event&amp;&amp;document){C._onLoad();}else{if(C._timeoutCount&gt;2000){}else{setTimeout(C._addListeners,10);if(document&amp;&amp;document.body){C._timeoutCount+=1;}}}},handleWasClicked:function(C,E){if(this.isHandle(E,C.id)){return true;}else{var D=C.parentNode
 ;while(D){if(this.isHandle(E,D.id)){return true;}else{D=D.parentNode;}}}return false;}};}();YAHOO.util.DDM=YAHOO.util.DragDropMgr;YAHOO.util.DDM._addListeners();}(function(){var A=YAHOO.util.Event;var B=YAHOO.util.Dom;YAHOO.util.DragDrop=function(E,C,D){if(E){this.init(E,C,D);}};YAHOO.util.DragDrop.prototype={events:null,on:function(){this.subscribe.apply(this,arguments);},id:null,config:null,dragElId:null,handleElId:null,invalidHandleTypes:null,invalidHandleIds:null,invalidHandleClasses:null,startPageX:0,startPageY:0,groups:null,locked:false,lock:function(){this.locked=true;},unlock:function(){this.locked=false;},isTarget:true,padding:null,dragOnly:false,useShim:false,_domRef:null,__ygDragDrop:true,constrainX:false,constrainY:false,minX:0,maxX:0,minY:0,maxY:0,deltaX:0,deltaY:0,maintainOffset:false,xTicks:null,yTicks:null,primaryButtonOnly:true,available:false,hasOuterHandles:false,cursorIsOver:false,overlap:null,b4StartDrag:function(C,D){},startDrag:function(C,D){},b4Drag:f
 unction(C){},onDrag:function(C){},onDragEnter:function(C,D){},b4DragOver:function(C){},onDragOver:function(C,D){},b4DragOut:function(C){},onDragOut:function(C,D){},b4DragDrop:function(C){},onDragDrop:function(C,D){},onInvalidDrop:function(C){},b4EndDrag:function(C){},endDrag:function(C){},b4MouseDown:function(C){},onMouseDown:function(C){},onMouseUp:function(C){},onAvailable:function(){},getEl:function(){if(!this._domRef){this._domRef=B.get(this.id);
+}return this._domRef;},getDragEl:function(){return B.get(this.dragElId);},init:function(F,C,D){this.initTarget(F,C,D);A.on(this._domRef||this.id,&quot;mousedown&quot;,this.handleMouseDown,this,true);for(var E in this.events){this.createEvent(E+&quot;Event&quot;);}},initTarget:function(E,C,D){this.config=D||{};this.events={};this.DDM=YAHOO.util.DDM;this.groups={};if(typeof E!==&quot;string&quot;){this._domRef=E;E=B.generateId(E);}this.id=E;this.addToGroup((C)?C:&quot;default&quot;);this.handleElId=E;A.onAvailable(E,this.handleOnAvailable,this,true);this.setDragElId(E);this.invalidHandleTypes={A:&quot;A&quot;};this.invalidHandleIds={};this.invalidHandleClasses=[];this.applyConfig();},applyConfig:function(){this.events={mouseDown:true,b4MouseDown:true,mouseUp:true,b4StartDrag:true,startDrag:true,b4EndDrag:true,endDrag:true,drag:true,b4Drag:true,invalidDrop:true,b4DragOut:true,dragOut:true,dragEnter:true,b4DragOver:true,dragOver:true,b4DragDrop:true,dragDrop:true};if(this.config
 .events){for(var C in this.config.events){if(this.config.events[C]===false){this.events[C]=false;}}}this.padding=this.config.padding||[0,0,0,0];this.isTarget=(this.config.isTarget!==false);this.maintainOffset=(this.config.maintainOffset);this.primaryButtonOnly=(this.config.primaryButtonOnly!==false);this.dragOnly=((this.config.dragOnly===true)?true:false);this.useShim=((this.config.useShim===true)?true:false);},handleOnAvailable:function(){this.available=true;this.resetConstraints();this.onAvailable();},setPadding:function(E,C,F,D){if(!C&amp;&amp;0!==C){this.padding=[E,E,E,E];}else{if(!F&amp;&amp;0!==F){this.padding=[E,C,E,C];}else{this.padding=[E,C,F,D];}}},setInitPosition:function(F,E){var G=this.getEl();if(!this.DDM.verifyEl(G)){if(G&amp;&amp;G.style&amp;&amp;(G.style.display==&quot;none&quot;)){}else{}return;}var D=F||0;var C=E||0;var H=B.getXY(G);this.initPageX=H[0]-D;this.initPageY=H[1]-C;this.lastPageX=H[0];this.lastPageY=H[1];this.setStartPosition(H);},setStartPositi
 on:function(D){var C=D||B.getXY(this.getEl());this.deltaSetXY=null;this.startPageX=C[0];this.startPageY=C[1];},addToGroup:function(C){this.groups[C]=true;this.DDM.regDragDrop(this,C);},removeFromGroup:function(C){if(this.groups[C]){delete this.groups[C];}this.DDM.removeDDFromGroup(this,C);},setDragElId:function(C){this.dragElId=C;},setHandleElId:function(C){if(typeof C!==&quot;string&quot;){C=B.generateId(C);}this.handleElId=C;this.DDM.regHandle(this.id,C);},setOuterHandleElId:function(C){if(typeof C!==&quot;string&quot;){C=B.generateId(C);}A.on(C,&quot;mousedown&quot;,this.handleMouseDown,this,true);this.setHandleElId(C);this.hasOuterHandles=true;},unreg:function(){A.removeListener(this.id,&quot;mousedown&quot;,this.handleMouseDown);this._domRef=null;this.DDM._remove(this);},isLocked:function(){return(this.DDM.isLocked()||this.locked);},handleMouseDown:function(J,I){var D=J.which||J.button;if(this.primaryButtonOnly&amp;&amp;D&gt;1){return;}if(this.isLocked()){return;}var C=
 this.b4MouseDown(J),F=true;if(this.events.b4MouseDown){F=this.fireEvent(&quot;b4MouseDownEvent&quot;,J);}var E=this.onMouseDown(J),H=true;if(this.events.mouseDown){if(E===false){H=false;}else{H=this.fireEvent(&quot;mouseDownEvent&quot;,J);}}if((C===false)||(E===false)||(F===false)||(H===false)){return;}this.DDM.refreshCache(this.groups);var G=new YAHOO.util.Point(A.getPageX(J),A.getPageY(J));if(!this.hasOuterHandles&amp;&amp;!this.DDM.isOverTarget(G,this)){}else{if(this.clickValidator(J)){this.setStartPosition();this.DDM.handleMouseDown(J,this);this.DDM.stopEvent(J);}else{}}},clickValidator:function(D){var C=YAHOO.util.Event.getTarget(D);return(this.isValidHandleChild(C)&amp;&amp;(this.id==this.handleElId||this.DDM.handleWasClicked(C,this.id)));},getTargetCoord:function(E,D){var C=E-this.deltaX;var F=D-this.deltaY;if(this.constrainX){if(C&lt;this.minX){C=this.minX;}if(C&gt;this.maxX){C=this.maxX;}}if(this.constrainY){if(F&lt;this.minY){F=this.minY;}if(F&gt;this.maxY){F=this.
 maxY;}}C=this.getTick(C,this.xTicks);F=this.getTick(F,this.yTicks);return{x:C,y:F};},addInvalidHandleType:function(C){var D=C.toUpperCase();this.invalidHandleTypes[D]=D;},addInvalidHandleId:function(C){if(typeof C!==&quot;string&quot;){C=B.generateId(C);}this.invalidHandleIds[C]=C;},addInvalidHandleClass:function(C){this.invalidHandleClasses.push(C);},removeInvalidHandleType:function(C){var D=C.toUpperCase();delete this.invalidHandleTypes[D];},removeInvalidHandleId:function(C){if(typeof C!==&quot;string&quot;){C=B.generateId(C);}delete this.invalidHandleIds[C];},removeInvalidHandleClass:function(D){for(var E=0,C=this.invalidHandleClasses.length;E&lt;C;++E){if(this.invalidHandleClasses[E]==D){delete this.invalidHandleClasses[E];}}},isValidHandleChild:function(F){var E=true;var H;try{H=F.nodeName.toUpperCase();}catch(G){H=F.nodeName;}E=E&amp;&amp;!this.invalidHandleTypes[H];E=E&amp;&amp;!this.invalidHandleIds[F.id];for(var D=0,C=this.invalidHandleClasses.length;E&amp;&amp;D&lt
 ;C;++D){E=!B.hasClass(F,this.invalidHandleClasses[D]);}return E;},setXTicks:function(F,C){this.xTicks=[];this.xTickSize=C;var E={};for(var D=this.initPageX;D&gt;=this.minX;D=D-C){if(!E[D]){this.xTicks[this.xTicks.length]=D;E[D]=true;}}for(D=this.initPageX;D&lt;=this.maxX;D=D+C){if(!E[D]){this.xTicks[this.xTicks.length]=D;E[D]=true;}}this.xTicks.sort(this.DDM.numericSort);},setYTicks:function(F,C){this.yTicks=[];this.yTickSize=C;var E={};for(var D=this.initPageY;D&gt;=this.minY;D=D-C){if(!E[D]){this.yTicks[this.yTicks.length]=D;E[D]=true;}}for(D=this.initPageY;D&lt;=this.maxY;D=D+C){if(!E[D]){this.yTicks[this.yTicks.length]=D;E[D]=true;}}this.yTicks.sort(this.DDM.numericSort);},setXConstraint:function(E,D,C){this.leftConstraint=parseInt(E,10);this.rightConstraint=parseInt(D,10);this.minX=this.initPageX-this.leftConstraint;this.maxX=this.initPageX+this.rightConstraint;if(C){this.setXTicks(this.initPageX,C);}this.constrainX=true;},clearConstraints:function(){this.constrainX=fal
 se;this.constrainY=false;this.clearTicks();},clearTicks:function(){this.xTicks=null;this.yTicks=null;this.xTickSize=0;this.yTickSize=0;},setYConstraint:function(C,E,D){this.topConstraint=parseInt(C,10);this.bottomConstraint=parseInt(E,10);this.minY=this.initPageY-this.topConstraint;this.maxY=this.initPageY+this.bottomConstraint;
+if(D){this.setYTicks(this.initPageY,D);}this.constrainY=true;},resetConstraints:function(){if(this.initPageX||this.initPageX===0){var D=(this.maintainOffset)?this.lastPageX-this.initPageX:0;var C=(this.maintainOffset)?this.lastPageY-this.initPageY:0;this.setInitPosition(D,C);}else{this.setInitPosition();}if(this.constrainX){this.setXConstraint(this.leftConstraint,this.rightConstraint,this.xTickSize);}if(this.constrainY){this.setYConstraint(this.topConstraint,this.bottomConstraint,this.yTickSize);}},getTick:function(I,F){if(!F){return I;}else{if(F[0]&gt;=I){return F[0];}else{for(var D=0,C=F.length;D&lt;C;++D){var E=D+1;if(F[E]&amp;&amp;F[E]&gt;=I){var H=I-F[D];var G=F[E]-I;return(G&gt;H)?F[D]:F[E];}}return F[F.length-1];}}},toString:function(){return(&quot;DragDrop &quot;+this.id);}};YAHOO.augment(YAHOO.util.DragDrop,YAHOO.util.EventProvider);})();YAHOO.util.DD=function(C,A,B){if(C){this.init(C,A,B);}};YAHOO.extend(YAHOO.util.DD,YAHOO.util.DragDrop,{scroll:true,autoOffset:fun
 ction(C,B){var A=C-this.startPageX;var D=B-this.startPageY;this.setDelta(A,D);},setDelta:function(B,A){this.deltaX=B;this.deltaY=A;},setDragElPos:function(C,B){var A=this.getDragEl();this.alignElWithMouse(A,C,B);},alignElWithMouse:function(C,G,F){var E=this.getTargetCoord(G,F);if(!this.deltaSetXY){var H=[E.x,E.y];YAHOO.util.Dom.setXY(C,H);var D=parseInt(YAHOO.util.Dom.getStyle(C,&quot;left&quot;),10);var B=parseInt(YAHOO.util.Dom.getStyle(C,&quot;top&quot;),10);this.deltaSetXY=[D-E.x,B-E.y];}else{YAHOO.util.Dom.setStyle(C,&quot;left&quot;,(E.x+this.deltaSetXY[0])+&quot;px&quot;);YAHOO.util.Dom.setStyle(C,&quot;top&quot;,(E.y+this.deltaSetXY[1])+&quot;px&quot;);}this.cachePosition(E.x,E.y);var A=this;setTimeout(function(){A.autoScroll.call(A,E.x,E.y,C.offsetHeight,C.offsetWidth);},0);},cachePosition:function(B,A){if(B){this.lastPageX=B;this.lastPageY=A;}else{var C=YAHOO.util.Dom.getXY(this.getEl());this.lastPageX=C[0];this.lastPageY=C[1];}},autoScroll:function(J,I,E,K){if(thi
 s.scroll){var L=this.DDM.getClientHeight();var B=this.DDM.getClientWidth();var N=this.DDM.getScrollTop();var D=this.DDM.getScrollLeft();var H=E+I;var M=K+J;var G=(L+N-I-this.deltaY);var F=(B+D-J-this.deltaX);var C=40;var A=(document.all)?80:30;if(H&gt;L&amp;&amp;G&lt;C){window.scrollTo(D,N+A);}if(I&lt;N&amp;&amp;N&gt;0&amp;&amp;I-N&lt;C){window.scrollTo(D,N-A);}if(M&gt;B&amp;&amp;F&lt;C){window.scrollTo(D+A,N);}if(J&lt;D&amp;&amp;D&gt;0&amp;&amp;J-D&lt;C){window.scrollTo(D-A,N);}}},applyConfig:function(){YAHOO.util.DD.superclass.applyConfig.call(this);this.scroll=(this.config.scroll!==false);},b4MouseDown:function(A){this.setStartPosition();this.autoOffset(YAHOO.util.Event.getPageX(A),YAHOO.util.Event.getPageY(A));},b4Drag:function(A){this.setDragElPos(YAHOO.util.Event.getPageX(A),YAHOO.util.Event.getPageY(A));},toString:function(){return(&quot;DD &quot;+this.id);}});YAHOO.util.DDProxy=function(C,A,B){if(C){this.init(C,A,B);this.initFrame();}};YAHOO.util.DDProxy.dragElId=&qu
 ot;ygddfdiv&quot;;YAHOO.extend(YAHOO.util.DDProxy,YAHOO.util.DD,{resizeFrame:true,centerFrame:false,createFrame:function(){var B=this,A=document.body;if(!A||!A.firstChild){setTimeout(function(){B.createFrame();},50);return;}var F=this.getDragEl(),E=YAHOO.util.Dom;if(!F){F=document.createElement(&quot;div&quot;);F.id=this.dragElId;var D=F.style;D.position=&quot;absolute&quot;;D.visibility=&quot;hidden&quot;;D.cursor=&quot;move&quot;;D.border=&quot;2px solid #aaa&quot;;D.zIndex=999;D.height=&quot;25px&quot;;D.width=&quot;25px&quot;;var C=document.createElement(&quot;div&quot;);E.setStyle(C,&quot;height&quot;,&quot;100%&quot;);E.setStyle(C,&quot;width&quot;,&quot;100%&quot;);E.setStyle(C,&quot;background-color&quot;,&quot;#ccc&quot;);E.setStyle(C,&quot;opacity&quot;,&quot;0&quot;);F.appendChild(C);A.insertBefore(F,A.firstChild);}},initFrame:function(){this.createFrame();},applyConfig:function(){YAHOO.util.DDProxy.superclass.applyConfig.call(this);this.resizeFrame=(this.config.r
 esizeFrame!==false);this.centerFrame=(this.config.centerFrame);this.setDragElId(this.config.dragElId||YAHOO.util.DDProxy.dragElId);},showFrame:function(E,D){var C=this.getEl();var A=this.getDragEl();var B=A.style;this._resizeProxy();if(this.centerFrame){this.setDelta(Math.round(parseInt(B.width,10)/2),Math.round(parseInt(B.height,10)/2));}this.setDragElPos(E,D);YAHOO.util.Dom.setStyle(A,&quot;visibility&quot;,&quot;visible&quot;);},_resizeProxy:function(){if(this.resizeFrame){var H=YAHOO.util.Dom;var B=this.getEl();var C=this.getDragEl();var G=parseInt(H.getStyle(C,&quot;borderTopWidth&quot;),10);var I=parseInt(H.getStyle(C,&quot;borderRightWidth&quot;),10);var F=parseInt(H.getStyle(C,&quot;borderBottomWidth&quot;),10);var D=parseInt(H.getStyle(C,&quot;borderLeftWidth&quot;),10);if(isNaN(G)){G=0;}if(isNaN(I)){I=0;}if(isNaN(F)){F=0;}if(isNaN(D)){D=0;}var E=Math.max(0,B.offsetWidth-I-D);var A=Math.max(0,B.offsetHeight-G-F);H.setStyle(C,&quot;width&quot;,E+&quot;px&quot;);H.set
 Style(C,&quot;height&quot;,A+&quot;px&quot;);}},b4MouseDown:function(B){this.setStartPosition();var A=YAHOO.util.Event.getPageX(B);var C=YAHOO.util.Event.getPageY(B);this.autoOffset(A,C);},b4StartDrag:function(A,B){this.showFrame(A,B);},b4EndDrag:function(A){YAHOO.util.Dom.setStyle(this.getDragEl(),&quot;visibility&quot;,&quot;hidden&quot;);},endDrag:function(D){var C=YAHOO.util.Dom;var B=this.getEl();var A=this.getDragEl();C.setStyle(A,&quot;visibility&quot;,&quot;&quot;);C.setStyle(B,&quot;visibility&quot;,&quot;hidden&quot;);YAHOO.util.DDM.moveToEl(B,A);C.setStyle(A,&quot;visibility&quot;,&quot;hidden&quot;);C.setStyle(B,&quot;visibility&quot;,&quot;&quot;);},toString:function(){return(&quot;DDProxy &quot;+this.id);}});YAHOO.util.DDTarget=function(C,A,B){if(C){this.initTarget(C,A,B);}};YAHOO.extend(YAHOO.util.DDTarget,YAHOO.util.DragDrop,{toString:function(){return(&quot;DDTarget &quot;+this.id);}});YAHOO.register(&quot;dragdrop&quot;,YAHOO.util.DragDropMgr,{version:&quot
 ;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuielementelementminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/element/element-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/element/element-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/element/element-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,8 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+YAHOO.util.Attribute=function(b,a){if(a){this.owner=a;this.configure(b,true);}};YAHOO.util.Attribute.INVALID_VALUE={};YAHOO.util.Attribute.prototype={name:undefined,value:null,owner:null,readOnly:false,writeOnce:false,_initialConfig:null,_written:false,method:null,setter:null,getter:null,validator:null,getValue:function(){var a=this.value;if(this.getter){a=this.getter.call(this.owner,this.name,a);}return a;},setValue:function(f,b){var e,a=this.owner,c=this.name,g=YAHOO.util.Attribute.INVALID_VALUE,d={type:c,prevValue:this.getValue(),newValue:f};if(this.readOnly||(this.writeOnce&amp;&amp;this._written)){return false;}if(this.validator&amp;&amp;!this.validator.call(a,f)){return false;}if(!b){e=a.fireBeforeChangeEvent(d);if(e===false){return false;}}if(this.setter){f=this.setter.call(a,f,this.name);if(f===undefined){}if(f===g){return false;}}if(this.method){if(this.method.call(a,f,this.name)===g){return false;}}this.value=f;this._written=true;d.type=c;if(!b){this.owner.fireChan
 geEvent(d);}return true;},configure:function(b,c){b=b||{};if(c){this._written=false;}this._initialConfig=this._initialConfig||{};for(var a in b){if(b.hasOwnProperty(a)){this[a]=b[a];if(c){this._initialConfig[a]=b[a];}}}},resetValue:function(){return this.setValue(this._initialConfig.value);},resetConfig:function(){this.configure(this._initialConfig,true);},refresh:function(a){this.setValue(this.value,a);}};(function(){var a=YAHOO.util.Lang;YAHOO.util.AttributeProvider=function(){};YAHOO.util.AttributeProvider.prototype={_configs:null,get:function(c){this._configs=this._configs||{};var b=this._configs[c];if(!b||!this._configs.hasOwnProperty(c)){return null;}return b.getValue();},set:function(d,e,b){this._configs=this._configs||{};var c=this._configs[d];if(!c){return false;}return c.setValue(e,b);},getAttributeKeys:function(){this._configs=this._configs;var c=[],b;for(b in this._configs){if(a.hasOwnProperty(this._configs,b)&amp;&amp;!a.isUndefined(this._configs[b])){c[c.length
 ]=b;}}return c;},setAttributes:function(d,b){for(var c in d){if(a.hasOwnProperty(d,c)){this.set(c,d[c],b);}}},resetValue:function(c,b){this._configs=this._configs||{};if(this._configs[c]){this.set(c,this._configs[c]._initialConfig.value,b);return true;}return false;},refresh:function(e,c){this._configs=this._configs||{};var f=this._configs;e=((a.isString(e))?[e]:e)||this.getAttributeKeys();for(var d=0,b=e.length;d&lt;b;++d){if(f.hasOwnProperty(e[d])){this._configs[e[d]].refresh(c);}}},register:function(b,c){this.setAttributeConfig(b,c);},getAttributeConfig:function(c){this._configs=this._configs||{};var b=this._configs[c]||{};var d={};for(c in b){if(a.hasOwnProperty(b,c)){d[c]=b[c];}}return d;},setAttributeConfig:function(b,c,d){this._configs=this._configs||{};c=c||{};if(!this._configs[b]){c.name=b;this._configs[b]=this.createAttribute(c);}else{this._configs[b].configure(c,d);}},configureAttribute:function(b,c,d){this.setAttributeConfig(b,c,d);},resetAttributeConfig:function
 (b){this._configs=this._configs||{};this._configs[b].resetConfig();},subscribe:function(b,c){this._events=this._events||{};if(!(b in this._events)){this._events[b]=this.createEvent(b);}YAHOO.util.EventProvider.prototype.subscribe.apply(this,arguments);},on:function(){this.subscribe.apply(this,arguments);},addListener:function(){this.subscribe.apply(this,arguments);},fireBeforeChangeEvent:function(c){var b=&quot;before&quot;;b+=c.type.charAt(0).toUpperCase()+c.type.substr(1)+&quot;Change&quot;;c.type=b;return this.fireEvent(c.type,c);},fireChangeEvent:function(b){b.type+=&quot;Change&quot;;return this.fireEvent(b.type,b);},createAttribute:function(b){return new YAHOO.util.Attribute(b,this);}};YAHOO.augment(YAHOO.util.AttributeProvider,YAHOO.util.EventProvider);})();(function(){var b=YAHOO.util.Dom,d=YAHOO.util.AttributeProvider,c={mouseenter:true,mouseleave:true};var a=function(e,f){this.init.apply(this,arguments);};a.DOM_EVENTS={&quot;click&quot;:true,&quot;dblclick&quot;:tr
 ue,&quot;keydown&quot;:true,&quot;keypress&quot;:true,&quot;keyup&quot;:true,&quot;mousedown&quot;:true,&quot;mousemove&quot;:true,&quot;mouseout&quot;:true,&quot;mouseover&quot;:true,&quot;mouseup&quot;:true,&quot;mouseenter&quot;:true,&quot;mouseleave&quot;:true,&quot;focus&quot;:true,&quot;blur&quot;:true,&quot;submit&quot;:true,&quot;change&quot;:true};a.prototype={DOM_EVENTS:null,DEFAULT_HTML_SETTER:function(g,e){var f=this.get(&quot;element&quot;);if(f){f[e]=g;}return g;},DEFAULT_HTML_GETTER:function(e){var f=this.get(&quot;element&quot;),g;if(f){g=f[e];}return g;},appendChild:function(e){e=e.get?e.get(&quot;element&quot;):e;return this.get(&quot;element&quot;).appendChild(e);},getElementsByTagName:function(e){return this.get(&quot;element&quot;).getElementsByTagName(e);},hasChildNodes:function(){return this.get(&quot;element&quot;).hasChildNodes();},insertBefore:function(e,f){e=e.get?e.get(&quot;element&quot;):e;f=(f&amp;&amp;f.get)?f.get(&quot;element&quot;):f;return
  this.get(&quot;element&quot;).insertBefore(e,f);},removeChild:function(e){e=e.get?e.get(&quot;element&quot;):e;return this.get(&quot;element&quot;).removeChild(e);},replaceChild:function(e,f){e=e.get?e.get(&quot;element&quot;):e;f=f.get?f.get(&quot;element&quot;):f;return this.get(&quot;element&quot;).replaceChild(e,f);},initAttributes:function(e){},addListener:function(j,i,k,h){h=h||this;var e=YAHOO.util.Event,g=this.get(&quot;element&quot;)||this.get(&quot;id&quot;),f=this;if(c[j]&amp;&amp;!e._createMouseDelegate){return false;}if(!this._events[j]){if(g&amp;&amp;this.DOM_EVENTS[j]){e.on(g,j,function(m,l){if(m.srcElement&amp;&amp;!m.target){m.target=m.srcElement;}if((m.toElement&amp;&amp;!m.relatedTarget)||(m.fromElement&amp;&amp;!m.relatedTarget)){m.relatedTarget=e.getRelatedTarget(m);}if(!m.currentTarget){m.currentTarget=g;}f.fireEvent(j,m,l);},k,h);}this.createEvent(j,{scope:this});}return YAHOO.util.EventProvider.prototype.subscribe.apply(this,arguments);},on:function(
 ){return this.addListener.apply(this,arguments);},subscribe:function(){return this.addListener.apply(this,arguments);},removeListener:function(f,e){return this.unsubscribe.apply(this,arguments);},addClass:function(e){b.addClass(this.get(&quot;element&quot;),e);},getElementsByClassName:function(f,e){return b.getElementsByClassName(f,e,this.get(&quot;element&quot;));},hasClass:function(e){return b.hasClass(this.get(&quot;element&quot;),e);},removeClass:function(e){return b.removeClass(this.get(&quot;element&quot;),e);},replaceClass:function(f,e){return b.replaceClass(this.get(&quot;element&quot;),f,e);
+},setStyle:function(f,e){return b.setStyle(this.get(&quot;element&quot;),f,e);},getStyle:function(e){return b.getStyle(this.get(&quot;element&quot;),e);},fireQueue:function(){var f=this._queue;for(var g=0,e=f.length;g&lt;e;++g){this[f[g][0]].apply(this,f[g][1]);}},appendTo:function(f,g){f=(f.get)?f.get(&quot;element&quot;):b.get(f);this.fireEvent(&quot;beforeAppendTo&quot;,{type:&quot;beforeAppendTo&quot;,target:f});g=(g&amp;&amp;g.get)?g.get(&quot;element&quot;):b.get(g);var e=this.get(&quot;element&quot;);if(!e){return false;}if(!f){return false;}if(e.parent!=f){if(g){f.insertBefore(e,g);}else{f.appendChild(e);}}this.fireEvent(&quot;appendTo&quot;,{type:&quot;appendTo&quot;,target:f});return e;},get:function(e){var g=this._configs||{},f=g.element;if(f&amp;&amp;!g[e]&amp;&amp;!YAHOO.lang.isUndefined(f.value[e])){this._setHTMLAttrConfig(e);}return d.prototype.get.call(this,e);},setAttributes:function(l,h){var f={},j=this._configOrder;for(var k=0,e=j.length;k&lt;e;++k){if(l[j
 [k]]!==undefined){f[j[k]]=true;this.set(j[k],l[j[k]],h);}}for(var g in l){if(l.hasOwnProperty(g)&amp;&amp;!f[g]){this.set(g,l[g],h);}}},set:function(f,h,e){var g=this.get(&quot;element&quot;);if(!g){this._queue[this._queue.length]=[&quot;set&quot;,arguments];if(this._configs[f]){this._configs[f].value=h;}return;}if(!this._configs[f]&amp;&amp;!YAHOO.lang.isUndefined(g[f])){this._setHTMLAttrConfig(f);}return d.prototype.set.apply(this,arguments);},setAttributeConfig:function(e,f,g){this._configOrder.push(e);d.prototype.setAttributeConfig.apply(this,arguments);},createEvent:function(f,e){this._events[f]=true;return d.prototype.createEvent.apply(this,arguments);},init:function(f,e){this._initElement(f,e);},destroy:function(){var e=this.get(&quot;element&quot;);YAHOO.util.Event.purgeElement(e,true);this.unsubscribeAll();if(e&amp;&amp;e.parentNode){e.parentNode.removeChild(e);}this._queue=[];this._events={};this._configs={};this._configOrder=[];},_initElement:function(g,f){this._q
 ueue=this._queue||[];this._events=this._events||{};this._configs=this._configs||{};this._configOrder=[];f=f||{};f.element=f.element||g||null;var i=false;var e=a.DOM_EVENTS;this.DOM_EVENTS=this.DOM_EVENTS||{};for(var h in e){if(e.hasOwnProperty(h)){this.DOM_EVENTS[h]=e[h];}}if(typeof f.element===&quot;string&quot;){this._setHTMLAttrConfig(&quot;id&quot;,{value:f.element});}if(b.get(f.element)){i=true;this._initHTMLElement(f);this._initContent(f);}YAHOO.util.Event.onAvailable(f.element,function(){if(!i){this._initHTMLElement(f);}this.fireEvent(&quot;available&quot;,{type:&quot;available&quot;,target:b.get(f.element)});},this,true);YAHOO.util.Event.onContentReady(f.element,function(){if(!i){this._initContent(f);}this.fireEvent(&quot;contentReady&quot;,{type:&quot;contentReady&quot;,target:b.get(f.element)});},this,true);},_initHTMLElement:function(e){this.setAttributeConfig(&quot;element&quot;,{value:b.get(e.element),readOnly:true});},_initContent:function(e){this.initAttribute
 s(e);this.setAttributes(e,true);this.fireQueue();},_setHTMLAttrConfig:function(e,g){var f=this.get(&quot;element&quot;);g=g||{};g.name=e;g.setter=g.setter||this.DEFAULT_HTML_SETTER;g.getter=g.getter||this.DEFAULT_HTML_GETTER;g.value=g.value||f[e];this._configs[e]=new YAHOO.util.Attribute(g,this);}};YAHOO.augment(a,d);YAHOO.util.Element=a;})();YAHOO.register(&quot;element&quot;,YAHOO.util.Element,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuielementdelegateelementdelegateminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/element-delegate/element-delegate-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/element-delegate/element-delegate-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/element-delegate/element-delegate-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+(function(){var A=YAHOO.util.Event,B=[],C={mouseenter:true,mouseleave:true};YAHOO.lang.augmentObject(YAHOO.util.Element.prototype,{delegate:function(J,L,F,H,I){if(YAHOO.lang.isString(F)&amp;&amp;!YAHOO.util.Selector){return false;}if(!A._createDelegate){return false;}var E=A._getType(J),G=this.get(&quot;element&quot;),M,K,D=function(N){return M.call(G,N);};if(C[J]){if(!A._createMouseDelegate){return false;}K=A._createMouseDelegate(L,H,I);M=A._createDelegate(function(P,O,N){return K.call(O,P,N);},F,H,I);}else{M=A._createDelegate(L,F,H,I);}B.push([G,E,L,D]);return this.on(E,D);},removeDelegate:function(H,G){var I=A._getType(H),E=A._getCacheIndex(B,this.get(&quot;element&quot;),I,G),F,D;if(E&gt;=0){D=B[E];}if(D){F=this.removeListener(D[1],D[3]);if(F){delete B[E][2];delete B[E][3];B.splice(E,1);}}return F;}});}());YAHOO.register(&quot;element-delegate&quot;,YAHOO.util.Element,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuieventeventminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/event/event-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/event/event-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/event/event-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,11 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+YAHOO.util.CustomEvent=function(d,c,b,a,e){this.type=d;this.scope=c||window;this.silent=b;this.fireOnce=e;this.fired=false;this.firedWith=null;this.signature=a||YAHOO.util.CustomEvent.LIST;this.subscribers=[];if(!this.silent){}var f=&quot;_YUICEOnSubscribe&quot;;if(d!==f){this.subscribeEvent=new YAHOO.util.CustomEvent(f,this,true);}this.lastError=null;};YAHOO.util.CustomEvent.LIST=0;YAHOO.util.CustomEvent.FLAT=1;YAHOO.util.CustomEvent.prototype={subscribe:function(b,c,d){if(!b){throw new Error(&quot;Invalid callback for subscriber to '&quot;+this.type+&quot;'&quot;);}if(this.subscribeEvent){this.subscribeEvent.fire(b,c,d);}var a=new YAHOO.util.Subscriber(b,c,d);if(this.fireOnce&amp;&amp;this.fired){this.notify(a,this.firedWith);}else{this.subscribers.push(a);}},unsubscribe:function(d,f){if(!d){return this.unsubscribeAll();}var e=false;for(var b=0,a=this.subscribers.length;b&lt;a;++b){var c=this.subscribers[b];if(c&amp;&amp;c.contains(d,f)){this._delete(b);e=true;}}return e;}
 ,fire:function(){this.lastError=null;var h=[],a=this.subscribers.length;var d=[].slice.call(arguments,0),c=true,f,b=false;if(this.fireOnce){if(this.fired){return true;}else{this.firedWith=d;}}this.fired=true;if(!a&amp;&amp;this.silent){return true;}if(!this.silent){}var e=this.subscribers.slice();for(f=0;f&lt;a;++f){var g=e[f];if(!g||!g.fn){b=true;}else{c=this.notify(g,d);if(false===c){if(!this.silent){}break;}}}return(c!==false);},notify:function(g,c){var b,i=null,f=g.getScope(this.scope),a=YAHOO.util.Event.throwErrors;if(!this.silent){}if(this.signature==YAHOO.util.CustomEvent.FLAT){if(c.length&gt;0){i=c[0];}try{b=g.fn.call(f,i,g.obj);}catch(h){this.lastError=h;if(a){throw h;}}}else{try{b=g.fn.call(f,this.type,c,g.obj);}catch(d){this.lastError=d;if(a){throw d;}}}return b;},unsubscribeAll:function(){var a=this.subscribers.length,b;for(b=a-1;b&gt;-1;b--){this._delete(b);}this.subscribers=[];return a;},_delete:function(a){var b=this.subscribers[a];if(b){delete b.fn;delete b.o
 bj;}this.subscribers.splice(a,1);},toString:function(){return&quot;CustomEvent: &quot;+&quot;'&quot;+this.type+&quot;', &quot;+&quot;context: &quot;+this.scope;}};YAHOO.util.Subscriber=function(a,b,c){this.fn=a;this.obj=YAHOO.lang.isUndefined(b)?null:b;this.overrideContext=c;};YAHOO.util.Subscriber.prototype.getScope=function(a){if(this.overrideContext){if(this.overrideContext===true){return this.obj;}else{return this.overrideContext;}}return a;};YAHOO.util.Subscriber.prototype.contains=function(a,b){if(b){return(this.fn==a&amp;&amp;this.obj==b);}else{return(this.fn==a);}};YAHOO.util.Subscriber.prototype.toString=function(){return&quot;Subscriber { obj: &quot;+this.obj+&quot;, overrideContext: &quot;+(this.overrideContext||&quot;no&quot;)+&quot; }&quot;;};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var g=false,h=[],j=[],a=0,e=[],b=0,c={63232:38,63233:40,63234:37,63235:39,63276:33,63277:34,25:9},d=YAHOO.env.ua.ie,f=&quot;focusin&quot;,i=&quot;focusout&quot;;return{POLL_
 RETRYS:500,POLL_INTERVAL:40,EL:0,TYPE:1,FN:2,WFN:3,UNLOAD_OBJ:3,ADJ_SCOPE:4,OBJ:5,OVERRIDE:6,CAPTURE:7,lastError:null,isSafari:YAHOO.env.ua.webkit,webkit:YAHOO.env.ua.webkit,isIE:d,_interval:null,_dri:null,_specialTypes:{focusin:(d?&quot;focusin&quot;:&quot;focus&quot;),focusout:(d?&quot;focusout&quot;:&quot;blur&quot;)},DOMReady:false,throwErrors:false,startInterval:function(){if(!this._interval){this._interval=YAHOO.lang.later(this.POLL_INTERVAL,this,this._tryPreloadAttach,null,true);}},onAvailable:function(q,m,o,p,n){var k=(YAHOO.lang.isString(q))?[q]:q;for(var l=0;l&lt;k.length;l=l+1){e.push({id:k[l],fn:m,obj:o,overrideContext:p,checkReady:n});}a=this.POLL_RETRYS;this.startInterval();},onContentReady:function(n,k,l,m){this.onAvailable(n,k,l,m,true);},onDOMReady:function(){this.DOMReadyEvent.subscribe.apply(this.DOMReadyEvent,arguments);},_addListener:function(m,k,v,p,t,y){if(!v||!v.call){return false;}if(this._isValidCollection(m)){var w=true;for(var q=0,s=m.length;q&lt;
 s;++q){w=this.on(m[q],k,v,p,t)&amp;&amp;w;}return w;}else{if(YAHOO.lang.isString(m)){var o=this.getEl(m);if(o){m=o;}else{this.onAvailable(m,function(){YAHOO.util.Event._addListener(m,k,v,p,t,y);});return true;}}}if(!m){return false;}if(&quot;unload&quot;==k&amp;&amp;p!==this){j[j.length]=[m,k,v,p,t];return true;}var l=m;if(t){if(t===true){l=p;}else{l=t;}}var n=function(z){return v.call(l,YAHOO.util.Event.getEvent(z,m),p);};var x=[m,k,v,n,l,p,t,y];var r=h.length;h[r]=x;try{this._simpleAdd(m,k,n,y);}catch(u){this.lastError=u;this.removeListener(m,k,v);return false;}return true;},_getType:function(k){return this._specialTypes[k]||k;},addListener:function(m,p,l,n,o){var k=((p==f||p==i)&amp;&amp;!YAHOO.env.ua.ie)?true:false;return this._addListener(m,this._getType(p),l,n,o,k);},addFocusListener:function(l,k,m,n){return this.on(l,f,k,m,n);},removeFocusListener:function(l,k){return this.removeListener(l,f,k);},addBlurListener:function(l,k,m,n){return this.on(l,i,k,m,n);},removeBlur
 Listener:function(l,k){return this.removeListener(l,i,k);},removeListener:function(l,k,r){var m,p,u;k=this._getType(k);if(typeof l==&quot;string&quot;){l=this.getEl(l);}else{if(this._isValidCollection(l)){var s=true;for(m=l.length-1;m&gt;-1;m--){s=(this.removeListener(l[m],k,r)&amp;&amp;s);}return s;}}if(!r||!r.call){return this.purgeElement(l,false,k);}if(&quot;unload&quot;==k){for(m=j.length-1;m&gt;-1;m--){u=j[m];if(u&amp;&amp;u[0]==l&amp;&amp;u[1]==k&amp;&amp;u[2]==r){j.splice(m,1);return true;}}return false;}var n=null;var o=arguments[3];if(&quot;undefined&quot;===typeof o){o=this._getCacheIndex(h,l,k,r);}if(o&gt;=0){n=h[o];}if(!l||!n){return false;}var t=n[this.CAPTURE]===true?true:false;try{this._simpleRemove(l,k,n[this.WFN],t);}catch(q){this.lastError=q;return false;}delete h[o][this.WFN];delete h[o][this.FN];h.splice(o,1);return true;},getTarget:function(m,l){var k=m.target||m.srcElement;return this.resolveTextNode(k);},resolveTextNode:function(l){try{if(l&amp;&amp;3
 ==l.nodeType){return l.parentNode;}}catch(k){return null;}return l;},getPageX:function(l){var k=l.pageX;if(!k&amp;&amp;0!==k){k=l.clientX||0;if(this.isIE){k+=this._getScrollLeft();}}return k;},getPageY:function(k){var l=k.pageY;if(!l&amp;&amp;0!==l){l=k.clientY||0;if(this.isIE){l+=this._getScrollTop();}}return l;},getXY:function(k){return[this.getPageX(k),this.getPageY(k)];},getRelatedTarget:function(l){var k=l.relatedTarget;
+if(!k){if(l.type==&quot;mouseout&quot;){k=l.toElement;}else{if(l.type==&quot;mouseover&quot;){k=l.fromElement;}}}return this.resolveTextNode(k);},getTime:function(m){if(!m.time){var l=new Date().getTime();try{m.time=l;}catch(k){this.lastError=k;return l;}}return m.time;},stopEvent:function(k){this.stopPropagation(k);this.preventDefault(k);},stopPropagation:function(k){if(k.stopPropagation){k.stopPropagation();}else{k.cancelBubble=true;}},preventDefault:function(k){if(k.preventDefault){k.preventDefault();}else{k.returnValue=false;}},getEvent:function(m,k){var l=m||window.event;if(!l){var n=this.getEvent.caller;while(n){l=n.arguments[0];if(l&amp;&amp;Event==l.constructor){break;}n=n.caller;}}return l;},getCharCode:function(l){var k=l.keyCode||l.charCode||0;if(YAHOO.env.ua.webkit&amp;&amp;(k in c)){k=c[k];}return k;},_getCacheIndex:function(n,q,r,p){for(var o=0,m=n.length;o&lt;m;o=o+1){var k=n[o];if(k&amp;&amp;k[this.FN]==p&amp;&amp;k[this.EL]==q&amp;&amp;k[this.TYPE]==r){retur
 n o;}}return -1;},generateId:function(k){var l=k.id;if(!l){l=&quot;yuievtautoid-&quot;+b;++b;k.id=l;}return l;},_isValidCollection:function(l){try{return(l&amp;&amp;typeof l!==&quot;string&quot;&amp;&amp;l.length&amp;&amp;!l.tagName&amp;&amp;!l.alert&amp;&amp;typeof l[0]!==&quot;undefined&quot;);}catch(k){return false;}},elCache:{},getEl:function(k){return(typeof k===&quot;string&quot;)?document.getElementById(k):k;},clearCache:function(){},DOMReadyEvent:new YAHOO.util.CustomEvent(&quot;DOMReady&quot;,YAHOO,0,0,1),_load:function(l){if(!g){g=true;var k=YAHOO.util.Event;k._ready();k._tryPreloadAttach();}},_ready:function(l){var k=YAHOO.util.Event;if(!k.DOMReady){k.DOMReady=true;k.DOMReadyEvent.fire();k._simpleRemove(document,&quot;DOMContentLoaded&quot;,k._ready);}},_tryPreloadAttach:function(){if(e.length===0){a=0;if(this._interval){this._interval.cancel();this._interval=null;}return;}if(this.locked){return;}if(this.isIE){if(!this.DOMReady){this.startInterval();return;}}this.
 locked=true;var q=!g;if(!q){q=(a&gt;0&amp;&amp;e.length&gt;0);}var p=[];var r=function(t,u){var s=t;if(u.overrideContext){if(u.overrideContext===true){s=u.obj;}else{s=u.overrideContext;}}u.fn.call(s,u.obj);};var l,k,o,n,m=[];for(l=0,k=e.length;l&lt;k;l=l+1){o=e[l];if(o){n=this.getEl(o.id);if(n){if(o.checkReady){if(g||n.nextSibling||!q){m.push(o);e[l]=null;}}else{r(n,o);e[l]=null;}}else{p.push(o);}}}for(l=0,k=m.length;l&lt;k;l=l+1){o=m[l];r(this.getEl(o.id),o);}a--;if(q){for(l=e.length-1;l&gt;-1;l--){o=e[l];if(!o||!o.id){e.splice(l,1);}}this.startInterval();}else{if(this._interval){this._interval.cancel();this._interval=null;}}this.locked=false;},purgeElement:function(p,q,s){var n=(YAHOO.lang.isString(p))?this.getEl(p):p;var r=this.getListeners(n,s),o,k;if(r){for(o=r.length-1;o&gt;-1;o--){var m=r[o];this.removeListener(n,m.type,m.fn);}}if(q&amp;&amp;n&amp;&amp;n.childNodes){for(o=0,k=n.childNodes.length;o&lt;k;++o){this.purgeElement(n.childNodes[o],q,s);}}},getListeners:funct
 ion(n,k){var q=[],m;if(!k){m=[h,j];}else{if(k===&quot;unload&quot;){m=[j];}else{k=this._getType(k);m=[h];}}var s=(YAHOO.lang.isString(n))?this.getEl(n):n;for(var p=0;p&lt;m.length;p=p+1){var u=m[p];if(u){for(var r=0,t=u.length;r&lt;t;++r){var o=u[r];if(o&amp;&amp;o[this.EL]===s&amp;&amp;(!k||k===o[this.TYPE])){q.push({type:o[this.TYPE],fn:o[this.FN],obj:o[this.OBJ],adjust:o[this.OVERRIDE],scope:o[this.ADJ_SCOPE],index:r});}}}}return(q.length)?q:null;},_unload:function(s){var m=YAHOO.util.Event,p,o,n,r,q,t=j.slice(),k;for(p=0,r=j.length;p&lt;r;++p){n=t[p];if(n){try{k=window;if(n[m.ADJ_SCOPE]){if(n[m.ADJ_SCOPE]===true){k=n[m.UNLOAD_OBJ];}else{k=n[m.ADJ_SCOPE];}}n[m.FN].call(k,m.getEvent(s,n[m.EL]),n[m.UNLOAD_OBJ]);}catch(w){}t[p]=null;}}n=null;k=null;j=null;if(h){for(o=h.length-1;o&gt;-1;o--){n=h[o];if(n){try{m.removeListener(n[m.EL],n[m.TYPE],n[m.FN],o);}catch(v){}}}n=null;}try{m._simpleRemove(window,&quot;unload&quot;,m._unload);m._simpleRemove(window,&quot;load&quot;,m._loa
 d);}catch(u){}},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var k=document.documentElement,l=document.body;if(k&amp;&amp;(k.scrollTop||k.scrollLeft)){return[k.scrollTop,k.scrollLeft];}else{if(l){return[l.scrollTop,l.scrollLeft];}else{return[0,0];}}},regCE:function(){},_simpleAdd:function(){if(window.addEventListener){return function(m,n,l,k){m.addEventListener(n,l,(k));};}else{if(window.attachEvent){return function(m,n,l,k){m.attachEvent(&quot;on&quot;+n,l);};}else{return function(){};}}}(),_simpleRemove:function(){if(window.removeEventListener){return function(m,n,l,k){m.removeEventListener(n,l,(k));};}else{if(window.detachEvent){return function(l,m,k){l.detachEvent(&quot;on&quot;+m,k);};}else{return function(){};}}}()};}();(function(){var a=YAHOO.util.Event;a.on=a.addListener;a.onFocus=a.addFocusListener;a.onBlur=a.addBlurListener;
+/*! DOMReady: based on work by: Dean Edwards/John Resig/Matthias Miller/Diego Perini */
+if(a.isIE){if(self!==self.top){document.onreadystatechange=function(){if(document.readyState==&quot;complete&quot;){document.onreadystatechange=null;a._ready();}};}else{YAHOO.util.Event.onDOMReady(YAHOO.util.Event._tryPreloadAttach,YAHOO.util.Event,true);var b=document.createElement(&quot;p&quot;);a._dri=setInterval(function(){try{b.doScroll(&quot;left&quot;);clearInterval(a._dri);a._dri=null;a._ready();b=null;}catch(c){}},a.POLL_INTERVAL);}}else{if(a.webkit&amp;&amp;a.webkit&lt;525){a._dri=setInterval(function(){var c=document.readyState;if(&quot;loaded&quot;==c||&quot;complete&quot;==c){clearInterval(a._dri);a._dri=null;a._ready();}},a.POLL_INTERVAL);}else{a._simpleAdd(document,&quot;DOMContentLoaded&quot;,a._ready);}}a._simpleAdd(window,&quot;load&quot;,a._load);a._simpleAdd(window,&quot;unload&quot;,a._unload);a._tryPreloadAttach();})();}YAHOO.util.EventProvider=function(){};YAHOO.util.EventProvider.prototype={__yui_events:null,__yui_subscribers:null,subscribe:function(a
 ,c,f,e){this.__yui_events=this.__yui_events||{};var d=this.__yui_events[a];if(d){d.subscribe(c,f,e);}else{this.__yui_subscribers=this.__yui_subscribers||{};var b=this.__yui_subscribers;if(!b[a]){b[a]=[];}b[a].push({fn:c,obj:f,overrideContext:e});}},unsubscribe:function(c,e,g){this.__yui_events=this.__yui_events||{};var a=this.__yui_events;if(c){var f=a[c];if(f){return f.unsubscribe(e,g);}}else{var b=true;for(var d in a){if(YAHOO.lang.hasOwnProperty(a,d)){b=b&amp;&amp;a[d].unsubscribe(e,g);
+}}return b;}return false;},unsubscribeAll:function(a){return this.unsubscribe(a);},createEvent:function(b,g){this.__yui_events=this.__yui_events||{};var e=g||{},d=this.__yui_events,f;if(d[b]){}else{f=new YAHOO.util.CustomEvent(b,e.scope||this,e.silent,YAHOO.util.CustomEvent.FLAT,e.fireOnce);d[b]=f;if(e.onSubscribeCallback){f.subscribeEvent.subscribe(e.onSubscribeCallback);}this.__yui_subscribers=this.__yui_subscribers||{};var a=this.__yui_subscribers[b];if(a){for(var c=0;c&lt;a.length;++c){f.subscribe(a[c].fn,a[c].obj,a[c].overrideContext);}}}return d[b];},fireEvent:function(b){this.__yui_events=this.__yui_events||{};var d=this.__yui_events[b];if(!d){return null;}var a=[];for(var c=1;c&lt;arguments.length;++c){a.push(arguments[c]);}return d.fire.apply(d,a);},hasEvent:function(a){if(this.__yui_events){if(this.__yui_events[a]){return true;}}return false;}};(function(){var a=YAHOO.util.Event,c=YAHOO.lang;YAHOO.util.KeyListener=function(d,i,e,f){if(!d){}else{if(!i){}else{if(!e){
 }}}if(!f){f=YAHOO.util.KeyListener.KEYDOWN;}var g=new YAHOO.util.CustomEvent(&quot;keyPressed&quot;);this.enabledEvent=new YAHOO.util.CustomEvent(&quot;enabled&quot;);this.disabledEvent=new YAHOO.util.CustomEvent(&quot;disabled&quot;);if(c.isString(d)){d=document.getElementById(d);}if(c.isFunction(e)){g.subscribe(e);}else{g.subscribe(e.fn,e.scope,e.correctScope);}function h(o,n){if(!i.shift){i.shift=false;}if(!i.alt){i.alt=false;}if(!i.ctrl){i.ctrl=false;}if(o.shiftKey==i.shift&amp;&amp;o.altKey==i.alt&amp;&amp;o.ctrlKey==i.ctrl){var j,m=i.keys,l;if(YAHOO.lang.isArray(m)){for(var k=0;k&lt;m.length;k++){j=m[k];l=a.getCharCode(o);if(j==l){g.fire(l,o);break;}}}else{l=a.getCharCode(o);if(m==l){g.fire(l,o);}}}}this.enable=function(){if(!this.enabled){a.on(d,f,h);this.enabledEvent.fire(i);}this.enabled=true;};this.disable=function(){if(this.enabled){a.removeListener(d,f,h);this.disabledEvent.fire(i);}this.enabled=false;};this.toString=function(){return&quot;KeyListener [&quot;+i.k
 eys+&quot;] &quot;+d.tagName+(d.id?&quot;[&quot;+d.id+&quot;]&quot;:&quot;&quot;);};};var b=YAHOO.util.KeyListener;b.KEYDOWN=&quot;keydown&quot;;b.KEYUP=&quot;keyup&quot;;b.KEY={ALT:18,BACK_SPACE:8,CAPS_LOCK:20,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,META:224,NUM_LOCK:144,PAGE_DOWN:34,PAGE_UP:33,PAUSE:19,PRINTSCREEN:44,RIGHT:39,SCROLL_LOCK:145,SHIFT:16,SPACE:32,TAB:9,UP:38};})();YAHOO.register(&quot;event&quot;,YAHOO.util.Event,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuieventdelegateeventdelegateminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/event-delegate/event-delegate-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/event-delegate/event-delegate-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/event-delegate/event-delegate-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+(function(){var A=YAHOO.util.Event,C=YAHOO.lang,B=[],D=function(H,E,F){var G;if(!H||H===F){G=false;}else{G=YAHOO.util.Selector.test(H,E)?H:D(H.parentNode,E,F);}return G;};C.augmentObject(A,{_createDelegate:function(F,E,G,H){return function(I){var J=this,N=A.getTarget(I),L=E,P=(J.nodeType===9),Q,K,O,M;if(C.isFunction(E)){Q=E(N);}else{if(C.isString(E)){if(!P){O=J.id;if(!O){O=A.generateId(J);}M=(&quot;#&quot;+O+&quot; &quot;);L=(M+E).replace(/,/gi,(&quot;,&quot;+M));}if(YAHOO.util.Selector.test(N,L)){Q=N;}else{if(YAHOO.util.Selector.test(N,((L.replace(/,/gi,&quot; *,&quot;))+&quot; *&quot;))){Q=D(N,L,J);}}}}if(Q){K=Q;if(H){if(H===true){K=G;}else{K=H;}}return F.call(K,I,Q,J,G);}};},delegate:function(F,J,L,G,H,I){var E=J,K,M;if(C.isString(G)&amp;&amp;!YAHOO.util.Selector){return false;}if(J==&quot;mouseenter&quot;||J==&quot;mouseleave&quot;){if(!A._createMouseDelegate){return false;}E=A._getType(J);K=A._createMouseDelegate(L,H,I);M=A._createDelegate(function(P,O,N){return K.call(
 O,P,N);},G,H,I);}else{M=A._createDelegate(L,G,H,I);}B.push([F,E,L,M]);return A.on(F,E,M);},removeDelegate:function(F,J,I){var K=J,H=false,G,E;if(J==&quot;mouseenter&quot;||J==&quot;mouseleave&quot;){K=A._getType(J);}G=A._getCacheIndex(B,F,K,I);if(G&gt;=0){E=B[G];}if(F&amp;&amp;E){H=A.removeListener(E[0],E[1],E[3]);if(H){delete B[G][2];delete B[G][3];B.splice(G,1);}}return H;}});}());YAHOO.register(&quot;event-delegate&quot;,YAHOO.util.Event,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuieventmouseentereventmouseenterminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/event-mouseenter/event-mouseenter-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/event-mouseenter/event-mouseenter-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/event-mouseenter/event-mouseenter-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+(function(){var b=YAHOO.util.Event,g=YAHOO.lang,e=b.addListener,f=b.removeListener,c=b.getListeners,d=[],h={mouseenter:&quot;mouseover&quot;,mouseleave:&quot;mouseout&quot;},a=function(n,m,l){var j=b._getCacheIndex(d,n,m,l),i,k;if(j&gt;=0){i=d[j];}if(n&amp;&amp;i){k=f.call(b,i[0],m,i[3]);if(k){delete d[j][2];delete d[j][3];d.splice(j,1);}}return k;};g.augmentObject(b._specialTypes,h);g.augmentObject(b,{_createMouseDelegate:function(i,j,k){return function(q,m){var p=this,l=b.getRelatedTarget(q),o,n;if(p!=l&amp;&amp;!YAHOO.util.Dom.isAncestor(p,l)){o=p;if(k){if(k===true){o=j;}else{o=k;}}n=[q,j];if(m){n.splice(1,0,p,m);}return i.apply(o,n);}};},addListener:function(m,l,k,n,o){var i,j;if(h[l]){i=b._createMouseDelegate(k,n,o);i.mouseDelegate=true;d.push([m,l,k,i]);j=e.call(b,m,l,i);}else{j=e.apply(b,arguments);}return j;},removeListener:function(l,k,j){var i;if(h[k]){i=a.apply(b,arguments);}else{i=f.apply(b,arguments);}return i;},getListeners:function(p,o){var n=[],r,m=(o===&quot
 ;mouseover&quot;||o===&quot;mouseout&quot;),q,k,j;if(o&amp;&amp;(m||h[o])){r=c.call(b,p,this._getType(o));if(r){for(k=r.length-1;k&gt;-1;k--){j=r[k];q=j.fn.mouseDelegate;if((h[o]&amp;&amp;q)||(m&amp;&amp;!q)){n.push(j);}}}}else{n=c.apply(b,arguments);}return(n&amp;&amp;n.length)?n:null;}},true);b.on=b.addListener;}());YAHOO.register(&quot;event-mouseenter&quot;,YAHOO.util.Event,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuieventsimulateeventsimulateminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/event-simulate/event-simulate-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/event-simulate/event-simulate-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/event-simulate/event-simulate-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+YAHOO.util.UserAction={simulateKeyEvent:function(f,j,e,c,l,b,a,k,h,n,m){f=YAHOO.util.Dom.get(f);if(!f){throw new Error(&quot;simulateKeyEvent(): Invalid target.&quot;);}if(YAHOO.lang.isString(j)){j=j.toLowerCase();switch(j){case&quot;keyup&quot;:case&quot;keydown&quot;:case&quot;keypress&quot;:break;case&quot;textevent&quot;:j=&quot;keypress&quot;;break;default:throw new Error(&quot;simulateKeyEvent(): Event type '&quot;+j+&quot;' not supported.&quot;);}}else{throw new Error(&quot;simulateKeyEvent(): Event type must be a string.&quot;);}if(!YAHOO.lang.isBoolean(e)){e=true;}if(!YAHOO.lang.isBoolean(c)){c=true;}if(!YAHOO.lang.isObject(l)){l=window;}if(!YAHOO.lang.isBoolean(b)){b=false;}if(!YAHOO.lang.isBoolean(a)){a=false;}if(!YAHOO.lang.isBoolean(k)){k=false;}if(!YAHOO.lang.isBoolean(h)){h=false;}if(!YAHOO.lang.isNumber(n)){n=0;}if(!YAHOO.lang.isNumber(m)){m=0;}var i=null;if(YAHOO.lang.isFunction(document.createEvent)){try{i=document.createEvent(&quot;KeyEvents&quot;);i.initK
 eyEvent(j,e,c,l,b,a,k,h,n,m);}catch(g){try{i=document.createEvent(&quot;Events&quot;);}catch(d){i=document.createEvent(&quot;UIEvents&quot;);}finally{i.initEvent(j,e,c);i.view=l;i.altKey=a;i.ctrlKey=b;i.shiftKey=k;i.metaKey=h;i.keyCode=n;i.charCode=m;}}f.dispatchEvent(i);}else{if(YAHOO.lang.isObject(document.createEventObject)){i=document.createEventObject();i.bubbles=e;i.cancelable=c;i.view=l;i.ctrlKey=b;i.altKey=a;i.shiftKey=k;i.metaKey=h;i.keyCode=(m&gt;0)?m:n;f.fireEvent(&quot;on&quot;+j,i);}else{throw new Error(&quot;simulateKeyEvent(): No event simulation framework present.&quot;);}}},simulateMouseEvent:function(k,p,h,e,q,j,g,f,d,b,c,a,o,m,i,l){k=YAHOO.util.Dom.get(k);if(!k){throw new Error(&quot;simulateMouseEvent(): Invalid target.&quot;);}l=l||null;if(YAHOO.lang.isString(p)){p=p.toLowerCase();switch(p){case&quot;mouseover&quot;:case&quot;mouseout&quot;:case&quot;mousedown&quot;:case&quot;mouseup&quot;:case&quot;click&quot;:case&quot;dblclick&quot;:case&quot;mousemov
 e&quot;:break;default:throw new Error(&quot;simulateMouseEvent(): Event type '&quot;+p+&quot;' not supported.&quot;);}}else{throw new Error(&quot;simulateMouseEvent(): Event type must be a string.&quot;);}if(!YAHOO.lang.isBoolean(h)){h=true;}if(!YAHOO.lang.isBoolean(e)){e=(p!=&quot;mousemove&quot;);}if(!YAHOO.lang.isObject(q)){q=window;}if(!YAHOO.lang.isNumber(j)){j=1;}if(!YAHOO.lang.isNumber(g)){g=0;}if(!YAHOO.lang.isNumber(f)){f=0;}if(!YAHOO.lang.isNumber(d)){d=0;}if(!YAHOO.lang.isNumber(b)){b=0;}if(!YAHOO.lang.isBoolean(c)){c=false;}if(!YAHOO.lang.isBoolean(a)){a=false;}if(!YAHOO.lang.isBoolean(o)){o=false;}if(!YAHOO.lang.isBoolean(m)){m=false;}if(!YAHOO.lang.isNumber(i)){i=0;}var n=null;if(YAHOO.lang.isFunction(document.createEvent)){n=document.createEvent(&quot;MouseEvents&quot;);if(n.initMouseEvent){n.initMouseEvent(p,h,e,q,j,g,f,d,b,c,a,o,m,i,l);}else{n=document.createEvent(&quot;UIEvents&quot;);n.initEvent(p,h,e);n.view=q;n.detail=j;n.screenX=g;n.screenY=f;n.clientX=
 d;n.clientY=b;n.ctrlKey=c;n.altKey=a;n.metaKey=m;n.shiftKey=o;n.button=i;n.relatedTarget=l;}if(l&amp;&amp;!n.relatedTarget){if(p==&quot;mouseout&quot;){n.toElement=l;}else{if(p==&quot;mouseover&quot;){n.fromElement=l;}}}k.dispatchEvent(n);}else{if(YAHOO.lang.isObject(document.createEventObject)){n=document.createEventObject();n.bubbles=h;n.cancelable=e;n.view=q;n.detail=j;n.screenX=g;n.screenY=f;n.clientX=d;n.clientY=b;n.ctrlKey=c;n.altKey=a;n.metaKey=m;n.shiftKey=o;switch(i){case 0:n.button=1;break;case 1:n.button=4;break;case 2:break;default:n.button=0;}n.relatedTarget=l;k.fireEvent(&quot;on&quot;+p,n);}else{throw new Error(&quot;simulateMouseEvent(): No event simulation framework present.&quot;);}}},fireMouseEvent:function(c,b,a){a=a||{};this.simulateMouseEvent(c,b,a.bubbles,a.cancelable,a.view,a.detail,a.screenX,a.screenY,a.clientX,a.clientY,a.ctrlKey,a.altKey,a.shiftKey,a.metaKey,a.button,a.relatedTarget);},click:function(b,a){this.fireMouseEvent(b,&quot;click&quot;,a);
 },dblclick:function(b,a){this.fireMouseEvent(b,&quot;dblclick&quot;,a);},mousedown:function(b,a){this.fireMouseEvent(b,&quot;mousedown&quot;,a);},mousemove:function(b,a){this.fireMouseEvent(b,&quot;mousemove&quot;,a);},mouseout:function(b,a){this.fireMouseEvent(b,&quot;mouseout&quot;,a);},mouseover:function(b,a){this.fireMouseEvent(b,&quot;mouseover&quot;,a);},mouseup:function(b,a){this.fireMouseEvent(b,&quot;mouseup&quot;,a);},fireKeyEvent:function(b,c,a){a=a||{};this.simulateKeyEvent(c,b,a.bubbles,a.cancelable,a.view,a.ctrlKey,a.altKey,a.shiftKey,a.metaKey,a.keyCode,a.charCode);},keydown:function(b,a){this.fireKeyEvent(&quot;keydown&quot;,b,a);},keypress:function(b,a){this.fireKeyEvent(&quot;keypress&quot;,b,a);},keyup:function(b,a){this.fireKeyEvent(&quot;keyup&quot;,b,a);}};YAHOO.register(&quot;event-simulate&quot;,YAHOO.util.UserAction,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuifontsfontsmincss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/fonts/fonts-min.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/fonts/fonts-min.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/fonts/fonts-min.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+body{font:13px/1.231 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small}select,input,textarea,button{font:99% arial,helvetica,clean,sans-serif}table{font-size:inherit;font:100%}pre,code,kbd,samp,tt{font-family:monospace;*font-size:108%;line-height:100%}
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuifontsfontscss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/fonts/fonts.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/fonts/fonts.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/fonts/fonts.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,55 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+/**
+ * YUI Fonts
+ * @module fonts
+ * @namespace yui-
+ * @requires 
+ */
+
+/**
+ * Percents could work for IE, but for backCompat purposes, we are using keywords.
+ * x-small is for IE6/7 quirks mode.
+ */
+body {
+        font:13px/1.231 arial,helvetica,clean,sans-serif;
+        /* for IE6/7 */ 
+        *font-size:small; 
+        /* for IE Quirks Mode */
+        *font:x-small; 
+}
+
+/**
+ * Nudge down to get to 13px equivalent for these form elements
+ */ 
+select,
+input,
+textarea,
+button {
+        font:99% arial,helvetica,clean,sans-serif;
+}
+
+/**
+ * To help tables remember to inherit
+ */
+table {
+        font-size:inherit;
+        font:100%;
+}
+
+/**
+ * Bump up IE to get to 13px equivalent for these fixed-width elements
+ */
+pre,
+code,
+kbd,
+samp,
+tt {
+        font-family:monospace;
+        *font-size:108%;
+        line-height:100%;
+}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuigetgetminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/get/get-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/get/get-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/get/get-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+YAHOO.util.Get=function(){var m={},k=0,r=0,l=false,n=YAHOO.env.ua,s=YAHOO.lang,q,d,e,i=function(x,t,y){var u=y||window,z=u.document,A=z.createElement(x),v;for(v in t){if(t.hasOwnProperty(v)){A.setAttribute(v,t[v]);}}return A;},h=function(u,v,t){var w={id:&quot;yui__dyn_&quot;+(r++),type:&quot;text/css&quot;,rel:&quot;stylesheet&quot;,href:u};if(t){s.augmentObject(w,t);}return i(&quot;link&quot;,w,v);},p=function(u,v,t){var w={id:&quot;yui__dyn_&quot;+(r++),type:&quot;text/javascript&quot;,src:u};if(t){s.augmentObject(w,t);}return i(&quot;script&quot;,w,v);},a=function(t,u){return{tId:t.tId,win:t.win,data:t.data,nodes:t.nodes,msg:u,purge:function(){d(this.tId);}};},b=function(t,w){var u=m[w],v=(s.isString(t))?u.win.document.getElementById(t):t;if(!v){q(w,&quot;target node not found: &quot;+t);}return v;},c=function(w){var u=m[w],v,t;u.finished=true;if(u.aborted){v=&quot;transaction &quot;+w+&quot; was aborted&quot;;q(w,v);return;}if(u.onSuccess){t=u.scope||u.win;u.onSuccess.c
 all(t,a(u));}},o=function(v){var u=m[v],t;if(u.onTimeout){t=u.scope||u;u.onTimeout.call(t,a(u));}},f=function(v,A){var u=m[v],D=u.win,C=D.document,B=C.getElementsByTagName(&quot;head&quot;)[0],x,y,t,E,z;if(u.timer){u.timer.cancel();}if(u.aborted){y=&quot;transaction &quot;+v+&quot; was aborted&quot;;q(v,y);return;}if(A){u.url.shift();if(u.varName){u.varName.shift();}}else{u.url=(s.isString(u.url))?[u.url]:u.url;if(u.varName){u.varName=(s.isString(u.varName))?[u.varName]:u.varName;}}if(u.url.length===0){if(u.type===&quot;script&quot;&amp;&amp;n.webkit&amp;&amp;n.webkit&lt;420&amp;&amp;!u.finalpass&amp;&amp;!u.varName){z=p(null,u.win,u.attributes);z.innerHTML='YAHOO.util.Get._finalize(&quot;'+v+'&quot;);';u.nodes.push(z);B.appendChild(z);}else{c(v);}return;}t=u.url[0];if(!t){u.url.shift();return f(v);}if(u.timeout){u.timer=s.later(u.timeout,u,o,v);}if(u.type===&quot;script&quot;){x=p(t,D,u.attributes);}else{x=h(t,D,u.attributes);}e(u.type,x,v,t,D,u.url.length);u.nodes.push(x);
 if(u.insertBefore){E=b(u.insertBefore,v);if(E){E.parentNode.insertBefore(x,E);}}else{B.appendChild(x);}if((n.webkit||n.gecko)&amp;&amp;u.type===&quot;css&quot;){f(v,t);}},j=function(){if(l){return;}l=true;var t,u;for(t in m){if(m.hasOwnProperty(t)){u=m[t];if(u.autopurge&amp;&amp;u.finished){d(u.tId);delete m[t];}}}l=false;},g=function(u,t,v){var x=&quot;q&quot;+(k++),w;v=v||{};if(k%YAHOO.util.Get.PURGE_THRESH===0){j();}m[x]=s.merge(v,{tId:x,type:u,url:t,finished:false,aborted:false,nodes:[]});w=m[x];w.win=w.win||window;w.scope=w.scope||w.win;w.autopurge=(&quot;autopurge&quot; in w)?w.autopurge:(u===&quot;script&quot;)?true:false;w.attributes=w.attributes||{};w.attributes.charset=v.charset||w.attributes.charset||&quot;utf-8&quot;;s.later(0,w,f,x);return{tId:x};};e=function(H,z,x,u,D,E,G){var F=G||f,B,t,I,v,J,A,C,y;if(n.ie){z.onreadystatechange=function(){B=this.readyState;if(&quot;loaded&quot;===B||&quot;complete&quot;===B){z.onreadystatechange=null;F(x,u);}};}else{if(n.webki
 t){if(H===&quot;script&quot;){if(n.webkit&gt;=420){z.addEventListener(&quot;load&quot;,function(){F(x,u);});}else{t=m[x];if(t.varName){v=YAHOO.util.Get.POLL_FREQ;t.maxattempts=YAHOO.util.Get.TIMEOUT/v;t.attempts=0;t._cache=t.varName[0].split(&quot;.&quot;);t.timer=s.later(v,t,function(w){I=this._cache;A=I.length;J=this.win;for(C=0;C&lt;A;C=C+1){J=J[I[C]];if(!J){this.attempts++;if(this.attempts++&gt;this.maxattempts){y=&quot;Over retry limit, giving up&quot;;t.timer.cancel();q(x,y);}else{}return;}}t.timer.cancel();F(x,u);},null,true);}else{s.later(YAHOO.util.Get.POLL_FREQ,null,F,[x,u]);}}}}else{z.onload=function(){F(x,u);};}}};q=function(w,v){var u=m[w],t;if(u.onFailure){t=u.scope||u.win;u.onFailure.call(t,a(u,v));}};d=function(z){if(m[z]){var t=m[z],u=t.nodes,x=u.length,C=t.win.document,A=C.getElementsByTagName(&quot;head&quot;)[0],v,y,w,B;if(t.insertBefore){v=b(t.insertBefore,z);if(v){A=v.parentNode;}}for(y=0;y&lt;x;y=y+1){w=u[y];if(w.clearAttributes){w.clearAttributes();}e
 lse{for(B in w){if(w.hasOwnProperty(B)){delete w[B];}}}A.removeChild(w);}t.nodes=[];}};return{POLL_FREQ:10,PURGE_THRESH:20,TIMEOUT:2000,_finalize:function(t){s.later(0,null,c,t);},abort:function(u){var v=(s.isString(u))?u:u.tId,t=m[v];if(t){t.aborted=true;}},script:function(t,u){return g(&quot;script&quot;,t,u);},css:function(t,u){return g(&quot;css&quot;,t,u);}};}();YAHOO.register(&quot;get&quot;,YAHOO.util.Get,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuigridsgridsmincss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/grids/grids-min.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/grids/grids-min.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/grids/grids-min.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+body{text-align:center}#doc,#doc2,#doc3,#doc4,.yui-t1,.yui-t2,.yui-t3,.yui-t4,.yui-t5,.yui-t6,.yui-t7{margin:auto;text-align:left;width:57.69em;*width:56.25em}#doc2{width:73.076em;*width:71.25em}#doc3{margin:auto 10px;width:auto}#doc4{width:74.923em;*width:73.05em}.yui-b{position:relative}.yui-b{_position:static}#yui-main .yui-b{position:static}#yui-main,.yui-g .yui-u .yui-g{width:100%}.yui-t1 #yui-main,.yui-t2 #yui-main,.yui-t3 #yui-main{float:right;margin-left:-25em}.yui-t4 #yui-main,.yui-t5 #yui-main,.yui-t6 #yui-main{float:left;margin-right:-25em}.yui-t1 .yui-b{float:left;width:12.30769em;*width:12.00em}.yui-t1 #yui-main .yui-b{margin-left:13.30769em;*margin-left:13.05em}.yui-t2 .yui-b{float:left;width:13.8461em;*width:13.50em}.yui-t2 #yui-main .yui-b{margin-left:14.8461em;*margin-left:14.55em}.yui-t3 .yui-b{float:left;width:23.0769em;*width:22.50em}.yui-t3 #yui-main .yui-b{margin-left:24.0769em;*margin-left:23.62em}.yui-t4 .yui-b{float:right;width:13.8456em;*width:13.50
 em}.yui-t4 #yui-main .yui-b{margin-right:14.8456em;*margin-right:14.55em}.yui-t5 .yui-b{float:right;width:18.4615em;*width:18.00em}.yui-t5 #yui-main .yui-b{margin-right:19.4615em;*margin-right:19.125em}.yui-t6 .yui-b{float:right;width:23.0769em;*width:22.50em}.yui-t6 #yui-main .yui-b{margin-right:24.0769em;*margin-right:23.62em}.yui-t7 #yui-main .yui-b{display:block;margin:0 0 1em 0}#yui-main .yui-b{float:none;width:auto}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{float:left}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf,.yui-gc .yui-u,.yui-gd .yui-g,.yui-g .yui-gc .yui-u,.yui-ge .yui-u,.yui-ge .yui-g,.yui-gf .yui-g,.yui-gf .yui-u{float:right}.yui-g div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first,.yui-ge div.first,.yui-gf div.first,.yui-g .yui-gc div.first,.yui-g .yui-ge di
 v.first,.yui-gc div.first div.first{float:left}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf{width:49.1%}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{width:32%;margin-left:1.99%}.yui-gb .yui-u{*margin-left:1.9%;*width:31.9%}.yui-gc div.first,.yui-gd .yui-u{width:66%}.yui-gd div.first{width:32%}.yui-ge div.first,.yui-gf .yui-u{width:74.2%}.yui-ge .yui-u,.yui-gf div.first{width:24%}.yui-g .yui-gb div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first{margin-left:0}.yui-g .yui-g .yui-u,.yui-gb .yui-g .yui-u,.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u,.yui-ge .yui-g .yui-u,.yui-gf .yui-g .yui-u{width:49%;*width:48.1%;*margin-left:0}.yui-g .yui-g .yui-u{width:48.1%}.yui-g .yui-gb div.first,.yui-gb .yui-gb div.first{*margin-right:0;*width:32%;_width:31.7%}.yui-g .yui-gc div.first,.yui-g
 d .yui-g{width:66%}.yui-gb .yui-g div.first{*margin-right:4%;_margin-right:1.3%}.yui-gb .yui-gc div.first,.yui-gb .yui-gd div.first{*margin-right:0}.yui-gb .yui-gb .yui-u,.yui-gb .yui-gc .yui-u{*margin-left:1.8%;_margin-left:4%}.yui-g .yui-gb .yui-u{_margin-left:1.0%}.yui-gb .yui-gd .yui-u{*width:66%;_width:61.2%}.yui-gb .yui-gd div.first{*width:31%;_width:29.5%}.yui-g .yui-gc .yui-u,.yui-gb .yui-gc .yui-u{width:32%;_float:right;margin-right:0;_margin-left:0}.yui-gb .yui-gc div.first{width:66%;*float:left;*margin-left:0}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf .yui-u{margin:0}.yui-gb .yui-gb .yui-u{_margin-left:.7%}.yui-gb .yui-g div.first,.yui-gb .yui-gb div.first{*margin-left:0}.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u{*width:48.1%;*margin-left:0}.yui-gb .yui-gd div.first{width:32%}.yui-g .yui-gd div.first{_width:29.9%}.yui-ge .yui-g{width:24%}.yui-gf .yui-g{width:74.2%}.yui-gb .yui-ge div.yui-u,.yui-gb .yui-gf div.yui-u{float:right}.yui-gb .yui-ge div.first,.yui-gb .yui-g
 f div.first{float:left}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf div.first{*width:24%;_width:20%}.yui-gb .yui-ge div.first,.yui-gb .yui-gf .yui-u{*width:73.5%;_width:65.5%}.yui-ge div.first .yui-gd .yui-u{width:65%}.yui-ge div.first .yui-gd div.first{width:32%}#hd:after,#bd:after,#ft:after,.yui-g:after,.yui-gb:after,.yui-gc:after,.yui-gd:after,.yui-ge:after,.yui-gf:after{content:&quot;&quot;;display:block;clear:both}#hd,#bd,#ft,.yui-g,.yui-gb,.yui-gc,.yui-gd,.yui-ge,.yui-gf{zoom:1}
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuigridsgridscss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/grids/grids.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/grids/grids.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/grids/grids.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,465 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+/**
+ * YUI Grids
+ * @module grids
+ * @namespace yui-
+ * @requires reset, fonts
+ */
+
+/**  
+ * Note: Throughout this file, the *property (star-property) filter is used 
+ * to give a value to IE &lt; 8 that other browsers do not see. The _property (underscore-property)
+ * is only seen by IE &lt; 7, so the combo of *prop and _prop can differentiate between IE6 and IE7.
+ * 
+ * More information on these filters and related validation errors:
+ * http://tech.groups.yahoo.com/group/ydn-javascript/message/40059
+ */
+
+/**
+ * Section: General Rules
+ */
+
+body {
+        text-align: center;
+}
+
+/**
+ * Section: Page Width Rules (#doc, #doc2, #doc3, #doc4)
+ */
+
+#doc,#doc2,#doc3,#doc4,
+.yui-t1,.yui-t2,.yui-t3,.yui-t4,.yui-t5,.yui-t6,.yui-t7 {
+        margin: auto;
+        text-align: left;
+        width: 57.69em;
+        *width: 56.25em;
+}
+
+/* 950 Centered (doc2) */
+#doc2 {
+        width: 73.076em;
+        *width: 71.25em;
+}
+
+/* 100% (doc3) */
+#doc3 {
+/**
+ * Left and Right margins are not a structural part of Grids. Without them 
+ * Grids works fine, but content bleeds to the very edge of the document, which
+ * often impairs readability and usability. They are provided because they 
+ * prevent the content from &quot;bleeding&quot; into the browser's chrome. 
+ */
+        margin: auto 10px;
+        width: auto;
+}
+
+/* 974 Centered (doc4) */
+#doc4 {
+        width: 74.923em;
+        *width: 73.05em;
+}
+
+/**
+ * Section: Preset Template Rules (.yui-t[1-6])
+ */
+
+
+.yui-b {
+        /* to preserve source-order independence for Gecko */
+        position: relative;
+}
+
+.yui-b {
+        /* to preserve source-order independence for IE */
+        _position: static;
+}
+
+#yui-main .yui-b {
+        /* to preserve source-order independence for Gecko */
+        position: static;
+}
+
+#yui-main,
+.yui-g .yui-u .yui-g {
+        width: 100%;
+}
+
+.yui-t1 #yui-main,
+.yui-t2 #yui-main,
+.yui-t3 #yui-main {
+        float: right;
+        /* IE: preserve layout at narrow widths */
+        margin-left: -25em;
+}
+
+.yui-t4 #yui-main,
+.yui-t5 #yui-main,
+.yui-t6 #yui-main {
+        float: left;
+        /* IE: preserve layout at narrow widths */
+        margin-right: -25em;
+}
+
+/** 
+ * For Specific Template Presets
+ */
+
+.yui-t1 .yui-b {
+        float: left;
+        width: 12.30769em;
+        *width: 12.00em;
+}
+
+.yui-t1 #yui-main .yui-b {
+        margin-left: 13.30769em;
+        *margin-left: 13.05em;
+}
+
+.yui-t2 .yui-b {
+        float: left;
+        width: 13.8461em;
+        *width: 13.50em;
+}
+
+.yui-t2 #yui-main .yui-b {
+        margin-left: 14.8461em;
+        *margin-left: 14.55em;
+}
+
+.yui-t3 .yui-b {
+        float: left;
+        width: 23.0769em;
+        *width: 22.50em;
+}
+
+.yui-t3 #yui-main .yui-b {
+        margin-left: 24.0769em;
+        *margin-left: 23.62em;
+}
+
+.yui-t4 .yui-b {
+        float: right;
+        width: 13.8456em;
+        *width: 13.50em;
+}
+
+.yui-t4 #yui-main .yui-b {
+        margin-right: 14.8456em;
+        *margin-right: 14.55em;
+}
+
+.yui-t5 .yui-b {
+        float: right;
+        width: 18.4615em;
+        *width: 18.00em;
+}
+
+.yui-t5 #yui-main .yui-b {
+        margin-right: 19.4615em;
+        *margin-right: 19.125em;
+}
+
+.yui-t6 .yui-b {
+        float: right;
+        width: 23.0769em;
+        *width: 22.50em;
+}
+
+.yui-t6 #yui-main .yui-b {
+        margin-right: 24.0769em;
+        *margin-right: 23.62em;
+}
+
+.yui-t7 #yui-main .yui-b {
+        display: block;
+        margin: 0 0 1em 0;
+}
+
+#yui-main .yui-b {
+        float: none;
+        width: auto;
+}
+
+/**
+ * Section: Grids and Nesting Grids
+ */
+
+/* Children generally take half the available space */
+.yui-gb .yui-u,
+.yui-g .yui-gb .yui-u,
+.yui-gb .yui-g,
+.yui-gb .yui-gb,
+.yui-gb .yui-gc,
+.yui-gb .yui-gd,
+.yui-gb .yui-ge,
+.yui-gb .yui-gf,
+.yui-gc .yui-u, 
+.yui-gc .yui-g,
+.yui-gd .yui-u {
+        float: left;
+}
+
+/* Float units (and sub grids) to the right */
+.yui-g .yui-u,
+.yui-g .yui-g,
+.yui-g .yui-gb, 
+.yui-g .yui-gc, 
+.yui-g .yui-gd, 
+.yui-g .yui-ge, 
+.yui-g .yui-gf, 
+.yui-gc .yui-u, 
+.yui-gd .yui-g,
+.yui-g .yui-gc .yui-u,
+.yui-ge .yui-u, 
+.yui-ge .yui-g, 
+.yui-gf .yui-g,
+.yui-gf .yui-u {
+        float: right;
+}
+
+/*Float units (and sub grids) to the left */
+.yui-g div.first, 
+.yui-gb div.first,
+.yui-gc div.first,
+.yui-gd div.first, 
+.yui-ge div.first, 
+.yui-gf div.first,
+.yui-g .yui-gc div.first,
+.yui-g .yui-ge div.first,
+.yui-gc div.first div.first {
+        float: left;
+}
+
+.yui-g .yui-u,
+.yui-g .yui-g,
+.yui-g .yui-gb,
+.yui-g .yui-gc,
+.yui-g .yui-gd,
+.yui-g .yui-ge,
+.yui-g .yui-gf {
+        width: 49.1%;
+}
+
+.yui-gb .yui-u,
+.yui-g .yui-gb .yui-u,
+.yui-gb .yui-g,
+.yui-gb .yui-gb,
+.yui-gb .yui-gc,
+.yui-gb .yui-gd,
+.yui-gb .yui-ge,
+.yui-gb .yui-gf,
+.yui-gc .yui-u, 
+.yui-gc .yui-g,
+.yui-gd .yui-u {
+        width: 32%;
+        margin-left: 1.99%;
+}
+
+/* Give IE some extra breathing room for 1/3-based rounding issues */
+.yui-gb .yui-u {
+        *margin-left: 1.9%;
+        *width: 31.9%;
+}
+
+.yui-gc div.first, 
+        .yui-gd .yui-u {
+        width: 66%;
+}
+
+.yui-gd div.first {
+        width: 32%;
+}
+
+.yui-ge div.first, 
+        .yui-gf .yui-u {
+        width: 74.2%;
+}
+
+.yui-ge .yui-u,
+        .yui-gf div.first {
+        width: 24%;
+}
+
+.yui-g .yui-gb div.first,
+.yui-gb div.first, 
+.yui-gc div.first, 
+.yui-gd div.first {
+        margin-left: 0;
+}
+
+/**
+ * Section: Deep Nesting 
+ */
+
+.yui-g .yui-g .yui-u,
+.yui-gb .yui-g .yui-u,
+.yui-gc .yui-g .yui-u,
+.yui-gd .yui-g .yui-u,
+.yui-ge .yui-g .yui-u,
+.yui-gf .yui-g .yui-u {
+        width: 49%;
+        *width: 48.1%;
+        *margin-left: 0;
+}
+
+.yui-g .yui-g .yui-u {
+        width: 48.1%;
+}
+
+/* YUILibrary bug #1927599 from 1.14 to 2.6.0*/
+.yui-g .yui-gb div.first,
+        .yui-gb .yui-gb div.first {
+        *margin-right: 0;
+        *width: 32%;
+        _width: 31.7%;
+}
+
+.yui-g .yui-gc div.first, 
+        .yui-gd .yui-g {
+        width: 66%;
+}
+
+.yui-gb .yui-g div.first {
+        *margin-right: 4%;
+        _margin-right: 1.3%;
+}
+
+.yui-gb .yui-gc div.first, 
+        .yui-gb .yui-gd div.first {
+        *margin-right: 0;
+}
+
+.yui-gb .yui-gb .yui-u,
+        .yui-gb .yui-gc .yui-u {
+        *margin-left: 1.8%;
+        _margin-left: 4%;
+}
+
+.yui-g .yui-gb .yui-u {
+        _margin-left: 1.0%;
+}
+
+.yui-gb .yui-gd .yui-u {
+        *width: 66%;
+        _width: 61.2%;
+}
+
+.yui-gb .yui-gd div.first {
+        *width: 31%;
+        _width: 29.5%;
+}
+
+.yui-g .yui-gc .yui-u, 
+        .yui-gb .yui-gc .yui-u {
+        width: 32%;
+        _float: right;
+        margin-right: 0;
+        _margin-left: 0;
+}
+
+.yui-gb .yui-gc div.first {
+        width: 66%;
+        *float: left;
+        *margin-left: 0;
+}
+
+.yui-gb .yui-ge .yui-u, 
+        .yui-gb .yui-gf .yui-u {
+        margin: 0;
+}
+
+.yui-gb .yui-gb .yui-u {
+        _margin-left: .7%;
+}
+
+.yui-gb .yui-g div.first, 
+        .yui-gb .yui-gb div.first {
+        *margin-left: 0;
+}
+
+.yui-gc .yui-g .yui-u,
+        .yui-gd .yui-g .yui-u {
+        *width: 48.1%;
+        *margin-left: 0;
+}
+
+.yui-gb .yui-gd div.first {
+        width: 32%;
+}
+
+.yui-g .yui-gd div.first {
+        _width: 29.9%;
+}
+
+.yui-ge .yui-g {
+        width: 24%;
+}
+
+.yui-gf .yui-g {
+        width: 74.2%;
+}
+
+.yui-gb .yui-ge div.yui-u,
+        .yui-gb .yui-gf div.yui-u {
+        float: right;
+}
+
+.yui-gb .yui-ge div.first,
+        .yui-gb .yui-gf div.first {
+        float: left;
+}
+
+/* Width Accommodation for Nested Contexts */
+.yui-gb .yui-ge .yui-u,
+        .yui-gb .yui-gf div.first {
+        *width: 24%;
+        _width: 20%;
+}
+
+/* Width Accommodation for Nested Contexts */
+.yui-gb .yui-ge div.first, 
+        .yui-gb .yui-gf .yui-u {
+        *width: 73.5%;
+        _width: 65.5%;
+}
+
+/* Patch for GD within GE */
+.yui-ge div.first .yui-gd .yui-u {
+        width: 65%;
+}
+
+.yui-ge div.first .yui-gd div.first {
+        width: 32%;
+}
+
+/* @group Clearing */
+#hd:after,
+#bd:after,
+#ft:after,
+.yui-g:after, 
+.yui-gb:after, 
+.yui-gc:after, 
+.yui-gd:after, 
+.yui-ge:after, 
+.yui-gf:after {
+        content: &quot;&quot;;
+        display: block;
+        clear: both;
+}
+
+#hd,
+#bd,
+#ft,
+.yui-g, 
+.yui-gb, 
+.yui-gc, 
+.yui-gd, 
+.yui-ge, 
+.yui-gf {
+        zoom: 1;
+}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuihistoryhistoryminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/history/history-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/history/history-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/history/history-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+YAHOO.util.History=(function(){var d=null;var m=null;var g=false;var e=[];var c=[];function k(){var o,n;n=self.location.href;o=n.indexOf(&quot;#&quot;);return o&gt;=0?n.substr(o+1):null;}function b(){var o,p,q=[],n=[];for(o in e){if(YAHOO.lang.hasOwnProperty(e,o)){p=e[o];q.push(o+&quot;=&quot;+p.initialState);n.push(o+&quot;=&quot;+p.currentState);}}m.value=q.join(&quot;&amp;&quot;)+&quot;|&quot;+n.join(&quot;&amp;&quot;);}function j(n){var s,t,o,q,r,v,u,p;if(!n){for(o in e){if(YAHOO.lang.hasOwnProperty(e,o)){q=e[o];q.currentState=q.initialState;q.onStateChange(i(q.currentState));}}return;}r=[];v=n.split(&quot;&amp;&quot;);for(s=0,t=v.length;s&lt;t;s++){u=v[s].split(&quot;=&quot;);if(u.length===2){o=u[0];p=u[1];r[o]=p;}}for(o in e){if(YAHOO.lang.hasOwnProperty(e,o)){q=e[o];p=r[o];if(!p||q.currentState!==p){q.currentState=typeof p===&quot;undefined&quot;?q.initialState:p;q.onStateChange(i(q.currentState));}}}}function l(q){var n,p;n='&lt;html&gt;&lt;body&gt;&lt;div id=&quot;s
 tate&quot;&gt;'+YAHOO.lang.escapeHTML(q)+&quot;&lt;/div&gt;&lt;/body&gt;&lt;/html&gt;&quot;;try{p=d.contentWindow.document;p.open();p.write(n);p.close();return true;}catch(o){return false;}}function h(){var q,n,p,o;if(!d.contentWindow||!d.contentWindow.document){setTimeout(h,10);return;}q=d.contentWindow.document;n=q.getElementById(&quot;state&quot;);p=n?n.innerText:null;o=k();setInterval(function(){var w,s,t,u,v,r;q=d.contentWindow.document;n=q.getElementById(&quot;state&quot;);w=n?n.innerText:null;v=k();if(w!==p){p=w;j(p);if(!p){s=[];for(t in e){if(YAHOO.lang.hasOwnProperty(e,t)){u=e[t];s.push(t+&quot;=&quot;+u.initialState);}}v=s.join(&quot;&amp;&quot;);}else{v=p;}self.location.hash=v;o=v;b();}else{if(v!==o){o=v;l(v);}}},50);g=true;YAHOO.util.History.onLoadEvent.fire();}function f(){var u,w,s,y,o,q,x,r,v,p,n,t;s=m.value.split(&quot;|&quot;);if(s.length&gt;1){x=s[0].split(&quot;&amp;&quot;);for(u=0,w=x.length;u&lt;w;u++){y=x[u].split(&quot;=&quot;);if(y.length===2){o=y[0];
 r=y[1];q=YAHOO.lang.hasOwnProperty(e,o)&amp;&amp;e[o];if(q){q.initialState=r;}}}v=s[1].split(&quot;&amp;&quot;);for(u=0,w=v.length;u&lt;w;u++){y=v[u].split(&quot;=&quot;);if(y.length&gt;=2){o=y[0];p=y[1];q=YAHOO.lang.hasOwnProperty(e,o)&amp;&amp;e[o];if(q){q.currentState=p;}}}}if(s.length&gt;2){c=s[2].split(&quot;,&quot;);}if(YAHOO.env.ua.ie){if(typeof document.documentMode===&quot;undefined&quot;||document.documentMode&lt;8){h();}else{YAHOO.util.Event.on(top,&quot;hashchange&quot;,function(){var z=k();j(z);b();});g=true;YAHOO.util.History.onLoadEvent.fire();}}else{t=k();setInterval(function(){var B,z,A;z=k();if(z!==t){t=z;j(t);b();}},50);g=true;YAHOO.util.History.onLoadEvent.fire();}}function i(n){return decodeURIComponent(n.replace(/\+/g,&quot; &quot;));}function a(n){return encodeURIComponent(n).replace(/%20/g,&quot;+&quot;);}return{onLoadEvent:new YAHOO.util.CustomEvent(&quot;onLoad&quot;),onReady:function(n,o,p){if(g){setTimeout(function(){var q=window;if(p){if(p===true
 ){q=o;}else{q=p;}}n.call(q,&quot;onLoad&quot;,[],o);},0);}else{YAHOO.util.History.onLoadEvent.subscribe(n,o,p);}},register:function(p,n,r,s,t){var q,o;if(typeof p!==&quot;string&quot;||YAHOO.lang.trim(p)===&quot;&quot;||typeof n!==&quot;string&quot;||typeof r!==&quot;function&quot;){throw new Error(&quot;Missing or invalid argument&quot;);}if(YAHOO.lang.hasOwnProperty(e,p)){return;}if(g){throw new Error(&quot;All modules must be registered before calling YAHOO.util.History.initialize&quot;);}p=a(p);n=a(n);q=null;if(t===true){q=s;}else{q=t;}o=function(u){return r.call(q,u,s);};e[p]={name:p,initialState:n,currentState:n,onStateChange:o};},initialize:function(n,o){if(g){return;}if(YAHOO.env.ua.opera&amp;&amp;typeof history.navigationMode!==&quot;undefined&quot;){history.navigationMode=&quot;compatible&quot;;}if(typeof n===&quot;string&quot;){n=document.getElementById(n);}if(!n||n.tagName.toUpperCase()!==&quot;TEXTAREA&quot;&amp;&amp;(n.tagName.toUpperCase()!==&quot;INPUT&quot;|
 |n.type!==&quot;hidden&quot;&amp;&amp;n.type!==&quot;text&quot;)){throw new Error(&quot;Missing or invalid argument&quot;);}m=n;if(YAHOO.env.ua.ie&amp;&amp;(typeof document.documentMode===&quot;undefined&quot;||document.documentMode&lt;8)){if(typeof o===&quot;string&quot;){o=document.getElementById(o);}if(!o||o.tagName.toUpperCase()!==&quot;IFRAME&quot;){throw new Error(&quot;Missing or invalid argument&quot;);}d=o;}YAHOO.util.Event.onDOMReady(f);},navigate:function(o,p){var n;if(typeof o!==&quot;string&quot;||typeof p!==&quot;string&quot;){throw new Error(&quot;Missing or invalid argument&quot;);}n={};n[o]=p;return YAHOO.util.History.multiNavigate(n);},multiNavigate:function(o){var n,p,r,q,s;if(typeof o!==&quot;object&quot;){throw new Error(&quot;Missing or invalid argument&quot;);}if(!g){throw new Error(&quot;The Browser History Manager is not initialized&quot;);}for(p in o){if(!YAHOO.lang.hasOwnProperty(e,a(p))){throw new Error(&quot;The following module has not been regi
 stered: &quot;+p);}}n=[];for(p in e){if(YAHOO.lang.hasOwnProperty(e,p)){r=e[p];if(YAHOO.lang.hasOwnProperty(o,p)){q=o[i(p)];}else{q=i(r.currentState);}p=a(p);q=a(q);n.push(p+&quot;=&quot;+q);}}s=n.join(&quot;&amp;&quot;);if(YAHOO.env.ua.ie&amp;&amp;(typeof document.documentMode===&quot;undefined&quot;||document.documentMode&lt;8)){return l(s);}else{self.location.hash=s;return true;}},getCurrentState:function(n){var o;if(typeof n!==&quot;string&quot;){throw new Error(&quot;Missing or invalid argument&quot;);}if(!g){throw new Error(&quot;The Browser History Manager is not initialized&quot;);}o=YAHOO.lang.hasOwnProperty(e,n)&amp;&amp;e[n];if(!o){throw new Error(&quot;No such registered module: &quot;+n);}return i(o.currentState);},getBookmarkedState:function(s){var r,o,n,u,p,t,q;if(typeof s!==&quot;string&quot;){throw new Error(&quot;Missing or invalid argument&quot;);}n=self.location.href.indexOf(&quot;#&quot;);if(n&gt;=0){u=self.location.href.substr(n+1);p=u.split(&quot;&amp;
 &quot;);for(r=0,o=p.length;r&lt;o;r++){t=p[r].split(&quot;=&quot;);if(t.length===2){q=t[0];if(q===s){return i(t[1]);}}}}return null;},getQueryStringParameter:function(s,p){var q,o,n,u,t,r;p=p||self.location.href;n=p.indexOf(&quot;?&quot;);u=n&gt;=0?p.substr(n+1):p;n=u.lastIndexOf(&quot;#&quot;);u=n&gt;=0?u.substr(0,n):u;t=u.split(&quot;&amp;&quot;);for(q=0,o=t.length;q&lt;o;q++){r=t[q].split(&quot;=&quot;);if(r.length&gt;=2){if(r[0]===s){return i(r[1]);}}}return null;}};})();YAHOO.register(&quot;history&quot;,YAHOO.util.History,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiimagecropperimagecropperminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/imagecropper/imagecropper-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/imagecropper/imagecropper-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/imagecropper/imagecropper-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,8 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+(function(){var C=YAHOO.util.Dom,A=YAHOO.util.Event,D=YAHOO.lang;var B=function(F,E){var G={element:F,attributes:E||{}};B.superclass.constructor.call(this,G.element,G.attributes);};B._instances={};B.getCropperById=function(E){if(B._instances[E]){return B._instances[E];}return false;};YAHOO.extend(B,YAHOO.util.Element,{CSS_MAIN:&quot;yui-crop&quot;,CSS_MASK:&quot;yui-crop-mask&quot;,CSS_RESIZE_MASK:&quot;yui-crop-resize-mask&quot;,_image:null,_active:null,_resize:null,_resizeEl:null,_resizeMaskEl:null,_wrap:null,_mask:null,_createWrap:function(){this._wrap=document.createElement(&quot;div&quot;);this._wrap.id=this.get(&quot;element&quot;).id+&quot;_wrap&quot;;this._wrap.className=this.CSS_MAIN;var F=this.get(&quot;element&quot;);this._wrap.style.width=F.width?F.width+&quot;px&quot;:C.getStyle(F,&quot;width&quot;);this._wrap.style.height=F.height?F.height+&quot;px&quot;:C.getStyle(F,&quot;height&quot;);var E=this.get(&quot;element&quot;).parentNode;E.replaceChild(this._wrap,th
 is.get(&quot;element&quot;));this._wrap.appendChild(this.get(&quot;element&quot;));A.on(this._wrap,&quot;mouseover&quot;,this._handleMouseOver,this,true);A.on(this._wrap,&quot;mouseout&quot;,this._handleMouseOut,this,true);A.on(this._wrap,&quot;click&quot;,function(G){A.stopEvent(G);},this,true);},_createMask:function(){this._mask=document.createElement(&quot;div&quot;);this._mask.className=this.CSS_MASK;this._wrap.appendChild(this._mask);},_createResize:function(){this._resizeEl=document.createElement(&quot;div&quot;);this._resizeEl.className=YAHOO.util.Resize.prototype.CSS_RESIZE;this._resizeEl.style.position=&quot;absolute&quot;;this._resizeEl.innerHTML='&lt;div class=&quot;'+this.CSS_RESIZE_MASK+'&quot;&gt;&lt;/div&gt;';this._resizeMaskEl=this._resizeEl.firstChild;this._wrap.appendChild(this._resizeEl);this._resizeEl.style.top=this.get(&quot;initialXY&quot;)[1]+&quot;px&quot;;this._resizeEl.style.left=this.get(&quot;initialXY&quot;)[0]+&quot;px&quot;;this._resizeMaskEl.s
 tyle.height=Math.floor(this.get(&quot;initHeight&quot;))+&quot;px&quot;;this._resizeMaskEl.style.width=Math.floor(this.get(&quot;initWidth&quot;))+&quot;px&quot;;this._resize=new YAHOO.util.Resize(this._resizeEl,{knobHandles:true,handles:&quot;all&quot;,draggable:true,status:this.get(&quot;status&quot;),minWidth:this.get(&quot;minWidth&quot;),minHeight:this.get(&quot;minHeight&quot;),ratio:this.get(&quot;ratio&quot;),autoRatio:this.get(&quot;autoRatio&quot;),height:this.get(&quot;initHeight&quot;),width:this.get(&quot;initWidth&quot;)});this._setBackgroundImage(this.get(&quot;element&quot;).getAttribute(&quot;src&quot;,2));this._setBackgroundPosition(-(this.get(&quot;initialXY&quot;)[0]),-(this.get(&quot;initialXY&quot;)[1]));this._resize.on(&quot;startResize&quot;,this._handleStartResizeEvent,this,true);this._resize.on(&quot;endResize&quot;,this._handleEndResizeEvent,this,true);this._resize.on(&quot;dragEvent&quot;,this._handleDragEvent,this,true);this._resize.on(&quot;befo
 reResize&quot;,this._handleBeforeResizeEvent,this,true);this._resize.on(&quot;resize&quot;,this._handleResizeEvent,this,true);this._resize.dd.on(&quot;b4StartDragEvent&quot;,this._handleB4DragEvent,this,true);},_handleMouseOver:function(F){var E=&quot;keydown&quot;;if(YAHOO.env.ua.gecko||YAHOO.env.ua.opera){E=&quot;keypress&quot;;}if(!this._active){this._active=true;if(this.get(&quot;useKeys&quot;)){A.on(document,E,this._handleKeyPress,this,true);}}},_handleMouseOut:function(F){var E=&quot;keydown&quot;;if(YAHOO.env.ua.gecko||YAHOO.env.ua.opera){E=&quot;keypress&quot;;}this._active=false;if(this.get(&quot;useKeys&quot;)){A.removeListener(document,E,this._handleKeyPress);}},_moveEl:function(G,J){var H=0,E=0,I=this._setConstraints(),F=true;switch(G){case&quot;down&quot;:H=-(J);if((I.bottom-J)&lt;0){F=false;this._resizeEl.style.top=(I.top+I.bottom)+&quot;px&quot;;}break;case&quot;up&quot;:H=(J);if((I.top-J)&lt;0){F=false;this._resizeEl.style.top=&quot;0px&quot;;}break;case&quot
 ;right&quot;:E=-(J);if((I.right-J)&lt;0){F=false;this._resizeEl.style.left=(I.left+I.right)+&quot;px&quot;;}break;case&quot;left&quot;:E=J;if((I.left-J)&lt;0){F=false;this._resizeEl.style.left=&quot;0px&quot;;}break;}if(F){this._resizeEl.style.left=(parseInt(this._resizeEl.style.left,10)-E)+&quot;px&quot;;this._resizeEl.style.top=(parseInt(this._resizeEl.style.top,10)-H)+&quot;px&quot;;this.fireEvent(&quot;moveEvent&quot;,{target:&quot;keypress&quot;});}else{this._setConstraints();}this._syncBackgroundPosition();},_handleKeyPress:function(G){var E=A.getCharCode(G),F=false,H=((G.shiftKey)?this.get(&quot;shiftKeyTick&quot;):this.get(&quot;keyTick&quot;));switch(E){case 37:this._moveEl(&quot;left&quot;,H);F=true;break;case 38:this._moveEl(&quot;up&quot;,H);F=true;break;case 39:this._moveEl(&quot;right&quot;,H);F=true;break;case 40:this._moveEl(&quot;down&quot;,H);F=true;break;default:}if(F){A.preventDefault(G);}},_handleB4DragEvent:function(){this._setConstraints();},_handleDra
 gEvent:function(){this._syncBackgroundPosition();this.fireEvent(&quot;dragEvent&quot;,arguments);this.fireEvent(&quot;moveEvent&quot;,{target:&quot;dragevent&quot;});},_handleBeforeResizeEvent:function(F){var I=C.getRegion(this.get(&quot;element&quot;)),J=this._resize._cache,H=this._resize._currentHandle,G=0,E=0;if(F.top&amp;&amp;(F.top&lt;I.top)){G=(J.height+J.top)-I.top;C.setY(this._resize.getWrapEl(),I.top);this._resize.getWrapEl().style.height=G+&quot;px&quot;;this._resize._cache.height=G;this._resize._cache.top=I.top;this._syncBackgroundPosition();return false;}if(F.left&amp;&amp;(F.left&lt;I.left)){E=(J.width+J.left)-I.left;C.setX(this._resize.getWrapEl(),I.left);this._resize._cache.left=I.left;this._resize.getWrapEl().style.width=E+&quot;px&quot;;this._resize._cache.width=E;this._syncBackgroundPosition();return false;}if(H!=&quot;tl&quot;&amp;&amp;H!=&quot;l&quot;&amp;&amp;H!=&quot;bl&quot;){if(J.left&amp;&amp;F.width&amp;&amp;((J.left+F.width)&gt;I.right)){E=(I.right
 -J.left);C.setX(this._resize.getWrapEl(),(I.right-E));this._resize.getWrapEl().style.width=E+&quot;px&quot;;this._resize._cache.left=(I.right-E);this._resize._cache.width=E;this._syncBackgroundPosition();return false;}}if(H!=&quot;t&quot;&amp;&amp;H!=&quot;tr&quot;&amp;&amp;H!=&quot;tl&quot;){if(J.top&amp;&amp;F.height&amp;&amp;((J.top+F.height)&gt;I.bottom)){G=(I.bottom-J.top);C.setY(this._resize.getWrapEl(),(I.bottom-G));this._resize.getWrapEl().style.height=G+&quot;px&quot;;this._resize._cache.height=G;this._resize._cache.top=(I.bottom-G);this._syncBackgroundPosition();return false;}}},_handleResizeMaskEl:function(){var E=this._resize._cache;this._resizeMaskEl.style.height=Math.floor(E.height)+&quot;px&quot;;this._resizeMaskEl.style.width=Math.floor(E.width)+&quot;px&quot;;},_handleResizeEvent:function(E){this._setConstraints(true);this._syncBackgroundPosition();this.fireEvent(&quot;resizeEvent&quot;,arguments);this.fireEvent(&quot;moveEvent&quot;,{target:&quot;resizeeven
 t&quot;});},_syncBackgroundPosition:function(){this._handleResizeMaskEl();this._setBackgroundPosition(-(parseInt(this._resizeEl.style.left,10)),-(parseInt(this._resizeEl.style.top,10)));
+},_setBackgroundPosition:function(F,H){var J=parseInt(C.getStyle(this._resize.get(&quot;element&quot;),&quot;borderLeftWidth&quot;),10);var G=parseInt(C.getStyle(this._resize.get(&quot;element&quot;),&quot;borderTopWidth&quot;),10);if(isNaN(J)){J=0;}if(isNaN(G)){G=0;}var E=this._resize.getWrapEl().firstChild;var I=(F-J)+&quot;px &quot;+(H-G)+&quot;px&quot;;this._resizeMaskEl.style.backgroundPosition=I;},_setBackgroundImage:function(F){var E=this._resize.getWrapEl().firstChild;this._image=F;E.style.backgroundImage=&quot;url(&quot;+F+&quot;#)&quot;;},_handleEndResizeEvent:function(){this._setConstraints(true);},_handleStartResizeEvent:function(){this._setConstraints(true);var I=this._resize._cache.height,F=this._resize._cache.width,H=parseInt(this._resize.getWrapEl().style.top,10),E=parseInt(this._resize.getWrapEl().style.left,10),G=0,J=0;switch(this._resize._currentHandle){case&quot;b&quot;:G=(I+this._resize.dd.bottomConstraint);break;case&quot;l&quot;:J=(F+this._resize.dd.le
 ftConstraint);break;case&quot;r&quot;:G=(I+H);J=(F+this._resize.dd.rightConstraint);break;case&quot;br&quot;:G=(I+this._resize.dd.bottomConstraint);J=(F+this._resize.dd.rightConstraint);break;case&quot;tr&quot;:G=(I+H);J=(F+this._resize.dd.rightConstraint);break;}if(G){}if(J){}this.fireEvent(&quot;startResizeEvent&quot;,arguments);},_setConstraints:function(J){var H=this._resize;H.dd.resetConstraints();var N=parseInt(H.get(&quot;height&quot;),10),F=parseInt(H.get(&quot;width&quot;),10);if(J){N=H._cache.height;F=H._cache.width;}var L=C.getRegion(this.get(&quot;element&quot;));var G=H.getWrapEl();var O=C.getXY(G);var I=O[0]-L.left;var M=L.right-O[0]-F;var K=O[1]-L.top;var E=L.bottom-O[1]-N;if(K&lt;0){K=0;}H.dd.setXConstraint(I,M);H.dd.setYConstraint(K,E);return{top:K,right:M,bottom:E,left:I};},getCropCoords:function(){var E={top:parseInt(this._resize.getWrapEl().style.top,10),left:parseInt(this._resize.getWrapEl().style.left,10),height:this._resize._cache.height,width:this._re
 size._cache.width,image:this._image};return E;},reset:function(){this._resize.resize(null,this.get(&quot;initHeight&quot;),this.get(&quot;initWidth&quot;),0,0,true);this._resizeEl.style.top=this.get(&quot;initialXY&quot;)[1]+&quot;px&quot;;this._resizeEl.style.left=this.get(&quot;initialXY&quot;)[0]+&quot;px&quot;;this._syncBackgroundPosition();return this;},getEl:function(){return this.get(&quot;element&quot;);},getResizeEl:function(){return this._resizeEl;},getWrapEl:function(){return this._wrap;},getMaskEl:function(){return this._mask;},getResizeMaskEl:function(){return this._resizeMaskEl;},getResizeObject:function(){return this._resize;},init:function(G,E){B.superclass.init.call(this,G,E);var H=G;if(!D.isString(H)){if(H.tagName&amp;&amp;(H.tagName.toLowerCase()==&quot;img&quot;)){H=C.generateId(H);}else{return false;}}else{var F=C.get(H);if(F.tagName&amp;&amp;F.tagName.toLowerCase()==&quot;img&quot;){}else{return false;}}B._instances[H]=this;this._createWrap();this._crea
 teMask();this._createResize();this._setConstraints();},initAttributes:function(E){B.superclass.initAttributes.call(this,E);this.setAttributeConfig(&quot;initialXY&quot;,{validator:YAHOO.lang.isArray,value:E.initialXY||[10,10]});this.setAttributeConfig(&quot;keyTick&quot;,{validator:YAHOO.lang.isNumber,value:E.keyTick||1});this.setAttributeConfig(&quot;shiftKeyTick&quot;,{validator:YAHOO.lang.isNumber,value:E.shiftKeyTick||10});this.setAttributeConfig(&quot;useKeys&quot;,{validator:YAHOO.lang.isBoolean,value:((E.useKeys===false)?false:true)});this.setAttributeConfig(&quot;status&quot;,{validator:YAHOO.lang.isBoolean,value:((E.status===false)?false:true),method:function(F){if(this._resize){this._resize.set(&quot;status&quot;,F);}}});this.setAttributeConfig(&quot;minHeight&quot;,{validator:YAHOO.lang.isNumber,value:E.minHeight||50,method:function(F){if(this._resize){this._resize.set(&quot;minHeight&quot;,F);}}});this.setAttributeConfig(&quot;minWidth&quot;,{validator:YAHOO.lang
 .isNumber,value:E.minWidth||50,method:function(F){if(this._resize){this._resize.set(&quot;minWidth&quot;,F);}}});this.setAttributeConfig(&quot;ratio&quot;,{validator:YAHOO.lang.isBoolean,value:E.ratio||false,method:function(F){if(this._resize){this._resize.set(&quot;ratio&quot;,F);}}});this.setAttributeConfig(&quot;autoRatio&quot;,{validator:YAHOO.lang.isBoolean,value:((E.autoRatio===false)?false:true),method:function(F){if(this._resize){this._resize.set(&quot;autoRatio&quot;,F);}}});this.setAttributeConfig(&quot;initHeight&quot;,{writeOnce:true,validator:YAHOO.lang.isNumber,value:E.initHeight||(this.get(&quot;element&quot;).height/4)});this.setAttributeConfig(&quot;initWidth&quot;,{validator:YAHOO.lang.isNumber,writeOnce:true,value:E.initWidth||(this.get(&quot;element&quot;).width/4)});},destroy:function(){this._resize.destroy();this._resizeEl.parentNode.removeChild(this._resizeEl);this._mask.parentNode.removeChild(this._mask);A.purgeElement(this._wrap);this._wrap.parentNod
 e.replaceChild(this.get(&quot;element&quot;),this._wrap);for(var E in this){if(D.hasOwnProperty(this,E)){this[E]=null;}}},toString:function(){if(this.get){return&quot;ImageCropper (#&quot;+this.get(&quot;id&quot;)+&quot;)&quot;;}return&quot;Image Cropper&quot;;}});YAHOO.widget.ImageCropper=B;})();YAHOO.register(&quot;imagecropper&quot;,YAHOO.widget.ImageCropper,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiimageloaderimageloaderminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/imageloader/imageloader-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/imageloader/imageloader-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/imageloader/imageloader-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+if(typeof(YAHOO.util.ImageLoader)==&quot;undefined&quot;){YAHOO.util.ImageLoader={};}YAHOO.util.ImageLoader.group=function(A,B,C){this.name=&quot;unnamed&quot;;this._imgObjs={};this.timeoutLen=C;this._timeout=null;this._triggers=[];this._customTriggers=[];this.foldConditional=false;this.className=null;this._classImageEls=null;if(YAHOO.util.Event.DOMReady){this._onloadTasks();}else{YAHOO.util.Event.onDOMReady(this._onloadTasks,this,true);}this.addTrigger(A,B);};YAHOO.util.ImageLoader.group.prototype.addTrigger=function(B,C){if(!B||!C){return;}var A=function(){this.fetch();};this._triggers.push([B,C,A]);YAHOO.util.Event.addListener(B,C,A,this,true);};YAHOO.util.ImageLoader.group.prototype.addCustomTrigger=function(B){if(!B||!B instanceof YAHOO.util.CustomEvent){return;}var A=function(){this.fetch();};this._customTriggers.push([B,A]);B.subscribe(A,this,true);};YAHOO.util.ImageLoader.group.prototype._onloadTasks=function(){if(this.timeoutLen&amp;&amp;typeof(this.timeoutLen)==&qu
 ot;number&quot;&amp;&amp;this.timeoutLen&gt;0){this._timeout=setTimeout(this._getFetchTimeout(),this.timeoutLen*1000);}if(this.foldConditional){this._foldCheck();}};YAHOO.util.ImageLoader.group.prototype._getFetchTimeout=function(){var A=this;return function(){A.fetch();};};YAHOO.util.ImageLoader.group.prototype.registerBgImage=function(B,A){this._imgObjs[B]=new YAHOO.util.ImageLoader.bgImgObj(B,A);return this._imgObjs[B];};YAHOO.util.ImageLoader.group.prototype.registerSrcImage=function(D,B,C,A){this._imgObjs[D]=new YAHOO.util.ImageLoader.srcImgObj(D,B,C,A);return this._imgObjs[D];};YAHOO.util.ImageLoader.group.prototype.registerPngBgImage=function(C,B,A){this._imgObjs[C]=new YAHOO.util.ImageLoader.pngBgImgObj(C,B,A);return this._imgObjs[C];};YAHOO.util.ImageLoader.group.prototype.fetch=function(){var B,A,C;clearTimeout(this._timeout);for(B=0,A=this._triggers.length;B&lt;A;B++){YAHOO.util.Event.removeListener(this._triggers[B][0],this._triggers[B][1],this._triggers[B][2]);}
 for(B=0,A=this._customTriggers.length;B&lt;A;B++){this._customTriggers[B][0].unsubscribe(this._customTriggers[B][1],this);}this._fetchByClass();for(C in this._imgObjs){if(YAHOO.lang.hasOwnProperty(this._imgObjs,C)){this._imgObjs[C].fetch();}}};YAHOO.util.ImageLoader.group.prototype._foldCheck=function(){var C=(document.compatMode!=&quot;CSS1Compat&quot;)?document.body.scrollTop:document.documentElement.scrollTop,D=YAHOO.util.Dom.getViewportHeight(),A=C+D,E=(document.compatMode!=&quot;CSS1Compat&quot;)?document.body.scrollLeft:document.documentElement.scrollLeft,G=YAHOO.util.Dom.getViewportWidth(),I=E+G,B,J,F,H;for(B in this._imgObjs){if(YAHOO.lang.hasOwnProperty(this._imgObjs,B)){J=YAHOO.util.Dom.getXY(this._imgObjs[B].domId);if(J[1]&lt;A&amp;&amp;J[0]&lt;I){this._imgObjs[B].fetch();}}}if(this.className){this._classImageEls=YAHOO.util.Dom.getElementsByClassName(this.className);for(F=0,H=this._classImageEls.length;F&lt;H;F++){J=YAHOO.util.Dom.getXY(this._classImageEls[F]);if(
 J[1]&lt;A&amp;&amp;J[0]&lt;I){YAHOO.util.Dom.removeClass(this._classImageEls[F],this.className);}}}};YAHOO.util.ImageLoader.group.prototype._fetchByClass=function(){if(!this.className){return;}if(this._classImageEls===null){this._classImageEls=YAHOO.util.Dom.getElementsByClassName(this.className);}YAHOO.util.Dom.removeClass(this._classImageEls,this.className);};YAHOO.util.ImageLoader.imgObj=function(B,A){this.domId=B;this.url=A;this.width=null;this.height=null;this.setVisible=false;this._fetched=false;};YAHOO.util.ImageLoader.imgObj.prototype.fetch=function(){if(this._fetched){return;}var A=document.getElementById(this.domId);if(!A){return;}this._applyUrl(A);if(this.setVisible){A.style.visibility=&quot;visible&quot;;}if(this.width){A.width=this.width;}if(this.height){A.height=this.height;}this._fetched=true;};YAHOO.util.ImageLoader.imgObj.prototype._applyUrl=function(A){};YAHOO.util.ImageLoader.bgImgObj=function(B,A){YAHOO.util.ImageLoader.bgImgObj.superclass.constructor.cal
 l(this,B,A);};YAHOO.lang.extend(YAHOO.util.ImageLoader.bgImgObj,YAHOO.util.ImageLoader.imgObj);YAHOO.util.ImageLoader.bgImgObj.prototype._applyUrl=function(A){A.style.backgroundImage=&quot;url('&quot;+this.url+&quot;')&quot;;};YAHOO.util.ImageLoader.srcImgObj=function(D,B,C,A){YAHOO.util.ImageLoader.srcImgObj.superclass.constructor.call(this,D,B);this.width=C;this.height=A;};YAHOO.lang.extend(YAHOO.util.ImageLoader.srcImgObj,YAHOO.util.ImageLoader.imgObj);YAHOO.util.ImageLoader.srcImgObj.prototype._applyUrl=function(A){A.src=this.url;};YAHOO.util.ImageLoader.pngBgImgObj=function(C,B,A){YAHOO.util.ImageLoader.pngBgImgObj.superclass.constructor.call(this,C,B);this.props=A||{};};YAHOO.lang.extend(YAHOO.util.ImageLoader.pngBgImgObj,YAHOO.util.ImageLoader.imgObj);YAHOO.util.ImageLoader.pngBgImgObj.prototype._applyUrl=function(B){if(YAHOO.env.ua.ie&amp;&amp;YAHOO.env.ua.ie&lt;=6){var C=(YAHOO.lang.isUndefined(this.props.sizingMethod))?&quot;scale&quot;:this.props.sizingMethod,A=(Y
 AHOO.lang.isUndefined(this.props.enabled))?&quot;true&quot;:this.props.enabled;B.style.filter='progid:DXImageTransform.Microsoft.AlphaImageLoader(src=&quot;'+this.url+'&quot;, sizingMethod=&quot;'+C+'&quot;, enabled=&quot;'+A+'&quot;)';}else{B.style.backgroundImage=&quot;url('&quot;+this.url+&quot;')&quot;;}};YAHOO.register(&quot;imageloader&quot;,YAHOO.util.ImageLoader,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuijsonjsonminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/json/json-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/json/json-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/json/json-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+(function(){var l=YAHOO.lang,isFunction=l.isFunction,isObject=l.isObject,isArray=l.isArray,_toStr=Object.prototype.toString,Native=(YAHOO.env.ua.caja?window:this).JSON,_UNICODE_EXCEPTIONS=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,_ESCAPES=/\\(?:[&quot;\\\/bfnrt]|u[0-9a-fA-F]{4})/g,_VALUES=/&quot;[^&quot;\\\n\r]*&quot;|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,_BRACKETS=/(?:^|:|,)(?:\s*\[)+/g,_UNSAFE=/[^\],:{}\s]/,_SPECIAL_CHARS=/[\\\&quot;\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,_CHARS={&quot;\b&quot;:&quot;\\b&quot;,&quot;\t&quot;:&quot;\\t&quot;,&quot;\n&quot;:&quot;\\n&quot;,&quot;\f&quot;:&quot;\\f&quot;,&quot;\r&quot;:&quot;\\r&quot;,'&quot;':'\\&quot;',&quot;\\&quot;:&quot;\\\\&quot;},UNDEFINED=&quot;undefined&quot;,OBJECT=&quot;object&quot;,NULL=&quot;null&quot;,STRING=&quot;string&quot;,NUMBER=&quot;number&quot;,BOOLEA
 N=&quot;boolean&quot;,DATE=&quot;date&quot;,_allowable={&quot;undefined&quot;:UNDEFINED,&quot;string&quot;:STRING,&quot;[object String]&quot;:STRING,&quot;number&quot;:NUMBER,&quot;[object Number]&quot;:NUMBER,&quot;boolean&quot;:BOOLEAN,&quot;[object Boolean]&quot;:BOOLEAN,&quot;[object Date]&quot;:DATE,&quot;[object RegExp]&quot;:OBJECT},EMPTY=&quot;&quot;,OPEN_O=&quot;{&quot;,CLOSE_O=&quot;}&quot;,OPEN_A=&quot;[&quot;,CLOSE_A=&quot;]&quot;,COMMA=&quot;,&quot;,COMMA_CR=&quot;,\n&quot;,CR=&quot;\n&quot;,COLON=&quot;:&quot;,COLON_SP=&quot;: &quot;,QUOTE='&quot;';Native=_toStr.call(Native)===&quot;[object JSON]&quot;&amp;&amp;Native;function _char(c){if(!_CHARS[c]){_CHARS[c]=&quot;\\u&quot;+(&quot;0000&quot;+(+(c.charCodeAt(0))).toString(16)).slice(-4);}return _CHARS[c];}function _revive(data,reviver){var walk=function(o,key){var k,v,value=o[key];if(value&amp;&amp;typeof value===&quot;object&quot;){for(k in value){if(l.hasOwnProperty(value,k)){v=walk(value,k);if(v===undefined
 ){delete value[k];}else{value[k]=v;}}}}return reviver.call(o,key,value);};return typeof reviver===&quot;function&quot;?walk({&quot;&quot;:data},&quot;&quot;):data;}function _prepare(s){return s.replace(_UNICODE_EXCEPTIONS,_char);}function _isSafe(str){return l.isString(str)&amp;&amp;!_UNSAFE.test(str.replace(_ESCAPES,&quot;@&quot;).replace(_VALUES,&quot;]&quot;).replace(_BRACKETS,&quot;&quot;));}function _parse(s,reviver){s=_prepare(s);if(_isSafe(s)){return _revive(eval(&quot;(&quot;+s+&quot;)&quot;),reviver);}throw new SyntaxError(&quot;JSON.parse&quot;);}function _type(o){var t=typeof o;return _allowable[t]||_allowable[_toStr.call(o)]||(t===OBJECT?(o?OBJECT:NULL):UNDEFINED);}function _string(s){return QUOTE+s.replace(_SPECIAL_CHARS,_char)+QUOTE;}function _indent(s,space){return s.replace(/^/gm,space);}function _stringify(o,w,space){if(o===undefined){return undefined;}var replacer=isFunction(w)?w:null,format=_toStr.call(space).match(/String|Number/)||[],_date=YAHOO.lang.JSO
 N.dateToString,stack=[],tmp,i,len;if(replacer||!isArray(w)){w=undefined;}if(w){tmp={};for(i=0,len=w.length;i&lt;len;++i){tmp[w[i]]=true;}w=tmp;}space=format[0]===&quot;Number&quot;?new Array(Math.min(Math.max(0,space),10)+1).join(&quot; &quot;):(space||EMPTY).slice(0,10);function _serialize(h,key){var value=h[key],t=_type(value),a=[],colon=space?COLON_SP:COLON,arr,i,keys,k,v;if(isObject(value)&amp;&amp;isFunction(value.toJSON)){value=value.toJSON(key);}else{if(t===DATE){value=_date(value);}}if(isFunction(replacer)){value=replacer.call(h,key,value);}if(value!==h[key]){t=_type(value);}switch(t){case DATE:case OBJECT:break;case STRING:return _string(value);case NUMBER:return isFinite(value)?value+EMPTY:NULL;case BOOLEAN:return value+EMPTY;case NULL:return NULL;default:return undefined;}for(i=stack.length-1;i&gt;=0;--i){if(stack[i]===value){throw new Error(&quot;JSON.stringify. Cyclical reference&quot;);}}arr=isArray(value);stack.push(value);if(arr){for(i=value.length-1;i&gt;=0;
 --i){a[i]=_serialize(value,i)||NULL;}}else{keys=w||value;i=0;for(k in keys){if(l.hasOwnProperty(keys,k)){v=_serialize(value,k);if(v){a[i++]=_string(k)+colon+v;}}}}stack.pop();if(space&amp;&amp;a.length){return arr?OPEN_A+CR+_indent(a.join(COMMA_CR),space)+CR+CLOSE_A:OPEN_O+CR+_indent(a.join(COMMA_CR),space)+CR+CLOSE_O;}else{return arr?OPEN_A+a.join(COMMA)+CLOSE_A:OPEN_O+a.join(COMMA)+CLOSE_O;}}return _serialize({&quot;&quot;:o},&quot;&quot;);}YAHOO.lang.JSON={useNativeParse:!!Native,useNativeStringify:!!Native,isSafe:function(s){return _isSafe(_prepare(s));},parse:function(s,reviver){if(typeof s!==&quot;string&quot;){s+=&quot;&quot;;}return Native&amp;&amp;YAHOO.lang.JSON.useNativeParse?Native.parse(s,reviver):_parse(s,reviver);},stringify:function(o,w,space){return Native&amp;&amp;YAHOO.lang.JSON.useNativeStringify?Native.stringify(o,w,space):_stringify(o,w,space);},dateToString:function(d){function _zeroPad(v){return v&lt;10?&quot;0&quot;+v:v;}return d.getUTCFullYear()+&qu
 ot;-&quot;+_zeroPad(d.getUTCMonth()+1)+&quot;-&quot;+_zeroPad(d.getUTCDate())+&quot;T&quot;+_zeroPad(d.getUTCHours())+COLON+_zeroPad(d.getUTCMinutes())+COLON+_zeroPad(d.getUTCSeconds())+&quot;Z&quot;;},stringToDate:function(str){var m=str.match(/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d{3}))?Z$/);if(m){var d=new Date();d.setUTCFullYear(m[1],m[2]-1,m[3]);d.setUTCHours(m[4],m[5],m[6],(m[7]||0));return d;}return str;}};YAHOO.lang.JSON.isValid=YAHOO.lang.JSON.isSafe;})();YAHOO.register(&quot;json&quot;,YAHOO.lang.JSON,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuilayoutlayoutminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/layout/layout-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/layout/layout-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/layout/layout-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,11 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+(function(){var C=YAHOO.util.Dom,A=YAHOO.util.Event,D=YAHOO.lang;var B=function(F,E){if(D.isObject(F)&amp;&amp;!F.tagName){E=F;F=null;}if(D.isString(F)){if(C.get(F)){F=C.get(F);}}if(!F){F=document.body;}var G={element:F,attributes:E||{}};B.superclass.constructor.call(this,G.element,G.attributes);};B._instances={};B.getLayoutById=function(E){if(B._instances[E]){return B._instances[E];}return false;};YAHOO.extend(B,YAHOO.util.Element,{browser:function(){var E=YAHOO.env.ua;E.standardsMode=false;E.secure=false;return E;}(),_units:null,_rendered:null,_zIndex:null,_sizes:null,_setBodySize:function(G){var F=0,E=0;G=((G===false)?false:true);if(this._isBody){F=C.getClientHeight();E=C.getClientWidth();}else{F=parseInt(this.getStyle(&quot;height&quot;),10);E=parseInt(this.getStyle(&quot;width&quot;),10);if(isNaN(E)){E=this.get(&quot;element&quot;).clientWidth;}if(isNaN(F)){F=this.get(&quot;element&quot;).clientHeight;}}if(this.get(&quot;minWidth&quot;)){if(E&lt;this.get(&quot;minWidth&
 quot;)){E=this.get(&quot;minWidth&quot;);}}if(this.get(&quot;minHeight&quot;)){if(F&lt;this.get(&quot;minHeight&quot;)){F=this.get(&quot;minHeight&quot;);}}if(G){if(F&lt;0){F=0;}if(E&lt;0){E=0;}C.setStyle(this._doc,&quot;height&quot;,F+&quot;px&quot;);C.setStyle(this._doc,&quot;width&quot;,E+&quot;px&quot;);}this._sizes.doc={h:F,w:E};this._setSides(G);},_setSides:function(J){var H=((this._units.top)?this._units.top.get(&quot;height&quot;):0),G=((this._units.bottom)?this._units.bottom.get(&quot;height&quot;):0),I=this._sizes.doc.h,E=this._sizes.doc.w;J=((J===false)?false:true);this._sizes.top={h:H,w:((this._units.top)?E:0),t:0};this._sizes.bottom={h:G,w:((this._units.bottom)?E:0)};var F=(I-(H+G));this._sizes.left={h:F,w:((this._units.left)?this._units.left.get(&quot;width&quot;):0)};this._sizes.right={h:F,w:((this._units.right)?this._units.right.get(&quot;width&quot;):0),l:((this._units.right)?(E-this._units.right.get(&quot;width&quot;)):0),t:((this._units.top)?this._sizes.to
 p.h:0)};if(this._units.right&amp;&amp;J){this._units.right.set(&quot;top&quot;,this._sizes.right.t);if(!this._units.right._collapsing){this._units.right.set(&quot;left&quot;,this._sizes.right.l);}this._units.right.set(&quot;height&quot;,this._sizes.right.h,true);}if(this._units.left){this._sizes.left.l=0;if(this._units.top){this._sizes.left.t=this._sizes.top.h;}else{this._sizes.left.t=0;}if(J){this._units.left.set(&quot;top&quot;,this._sizes.left.t);this._units.left.set(&quot;height&quot;,this._sizes.left.h,true);this._units.left.set(&quot;left&quot;,0);}}if(this._units.bottom){this._sizes.bottom.t=this._sizes.top.h+this._sizes.left.h;if(J){this._units.bottom.set(&quot;top&quot;,this._sizes.bottom.t);this._units.bottom.set(&quot;width&quot;,this._sizes.bottom.w,true);}}if(this._units.top){if(J){this._units.top.set(&quot;width&quot;,this._sizes.top.w,true);}}this._setCenter(J);},_setCenter:function(G){G=((G===false)?false:true);var F=this._sizes.left.h;var E=(this._sizes.doc.
 w-(this._sizes.left.w+this._sizes.right.w));if(G){this._units.center.set(&quot;height&quot;,F,true);this._units.center.set(&quot;width&quot;,E,true);this._units.center.set(&quot;top&quot;,this._sizes.top.h);this._units.center.set(&quot;left&quot;,this._sizes.left.w);}this._sizes.center={h:F,w:E,t:this._sizes.top.h,l:this._sizes.left.w};},getSizes:function(){return this._sizes;},getUnitById:function(E){return YAHOO.widget.LayoutUnit.getLayoutUnitById(E);},getUnitByPosition:function(E){if(E){E=E.toLowerCase();if(this._units[E]){return this._units[E];}return false;}return false;},removeUnit:function(E){delete this._units[E.get(&quot;position&quot;)];this.resize();},addUnit:function(G){if(!G.position){return false;}if(this._units[G.position]){return false;}var H=null,J=null;if(G.id){if(C.get(G.id)){H=C.get(G.id);delete G.id;}}if(G.element){H=G.element;}if(!J){J=document.createElement(&quot;div&quot;);var L=C.generateId();J.id=L;}if(!H){H=document.createElement(&quot;div&quot;);}
 C.addClass(H,&quot;yui-layout-wrap&quot;);if(this.browser.ie&amp;&amp;!this.browser.standardsMode){J.style.zoom=1;H.style.zoom=1;}if(J.firstChild){J.insertBefore(H,J.firstChild);}else{J.appendChild(H);}this._doc.appendChild(J);var I=false,F=false;if(G.height){I=parseInt(G.height,10);}if(G.width){F=parseInt(G.width,10);}var E={};YAHOO.lang.augmentObject(E,G);E.parent=this;E.wrap=H;E.height=I;E.width=F;var K=new YAHOO.widget.LayoutUnit(J,E);K.on(&quot;heightChange&quot;,this.resize,{unit:K},this);K.on(&quot;widthChange&quot;,this.resize,{unit:K},this);K.on(&quot;gutterChange&quot;,this.resize,{unit:K},this);this._units[G.position]=K;if(this._rendered){this.resize();}return K;},_createUnits:function(){var E=this.get(&quot;units&quot;);for(var F in E){if(D.hasOwnProperty(E,F)){this.addUnit(E[F]);}}},resize:function(H,G){var E=H;if(E&amp;&amp;E.prevValue&amp;&amp;E.newValue){if(E.prevValue==E.newValue){if(G){if(G.unit){if(!G.unit.get(&quot;animate&quot;)){H=false;}}}}}H=((H===fal
 se)?false:true);if(H){var F=this.fireEvent(&quot;beforeResize&quot;);if(F===false){H=false;}if(this.browser.ie){if(this._isBody){C.removeClass(document.documentElement,&quot;yui-layout&quot;);C.addClass(document.documentElement,&quot;yui-layout&quot;);}else{this.removeClass(&quot;yui-layout&quot;);this.addClass(&quot;yui-layout&quot;);}}}this._setBodySize(H);if(H){this.fireEvent(&quot;resize&quot;,{target:this,sizes:this._sizes,event:E});}return this;},_setupBodyElements:function(){this._doc=C.get(&quot;layout-doc&quot;);if(!this._doc){this._doc=document.createElement(&quot;div&quot;);this._doc.id=&quot;layout-doc&quot;;if(document.body.firstChild){document.body.insertBefore(this._doc,document.body.firstChild);}else{document.body.appendChild(this._doc);}}this._createUnits();this._setBodySize();A.on(window,&quot;resize&quot;,this.resize,this,true);C.addClass(this._doc,&quot;yui-layout-doc&quot;);},_setupElements:function(){this._doc=this.getElementsByClassName(&quot;yui-layou
 t-doc&quot;)[0];if(!this._doc){this._doc=document.createElement(&quot;div&quot;);this.get(&quot;element&quot;).appendChild(this._doc);}this._createUnits();this._setBodySize();C.addClass(this._doc,&quot;yui-layout-doc&quot;);},_isBody:null,_doc:null,init:function(F,E){this._zIndex=0;B.superclass.init.call(this,F,E);if(this.get(&quot;parent&quot;)){this._zIndex=this.get(&quot;parent&quot;)._zIndex+10;}this._sizes={};this._units={};var G=F;if(!D.isString(G)){G=C.generateId(G);}B._instances[G]=this;},render:function(){this._stamp();var E=this.get(&quot;element&quot;);if(E&amp;&amp;E.tagName&amp;&amp;(E.tagName.toLowerCase()==&quot;body&quot;)){this._isBody=true;C.addClass(document.body,&quot;yui-layout&quot;);if(C.hasClass(document.body,&quot;yui-skin-sam&quot;)){C.addClass(document.documentElement,&quot;yui-skin-sam&quot;);
+C.removeClass(document.body,&quot;yui-skin-sam&quot;);}this._setupBodyElements();}else{this._isBody=false;this.addClass(&quot;yui-layout&quot;);this._setupElements();}this.resize();this._rendered=true;this.fireEvent(&quot;render&quot;);return this;},_stamp:function(){if(document.compatMode==&quot;CSS1Compat&quot;){this.browser.standardsMode=true;}if(window.location.href.toLowerCase().indexOf(&quot;https&quot;)===0){C.addClass(document.documentElement,&quot;secure&quot;);this.browser.secure=true;}},initAttributes:function(E){B.superclass.initAttributes.call(this,E);this.setAttributeConfig(&quot;units&quot;,{writeOnce:true,validator:YAHOO.lang.isArray,value:E.units||[]});this.setAttributeConfig(&quot;minHeight&quot;,{value:E.minHeight||false,validator:YAHOO.lang.isNumber});this.setAttributeConfig(&quot;minWidth&quot;,{value:E.minWidth||false,validator:YAHOO.lang.isNumber});this.setAttributeConfig(&quot;height&quot;,{value:E.height||false,validator:YAHOO.lang.isNumber,method:fu
 nction(F){if(F&lt;0){F=0;}this.setStyle(&quot;height&quot;,F+&quot;px&quot;);}});this.setAttributeConfig(&quot;width&quot;,{value:E.width||false,validator:YAHOO.lang.isNumber,method:function(F){if(F&lt;0){F=0;}this.setStyle(&quot;width&quot;,F+&quot;px&quot;);}});this.setAttributeConfig(&quot;parent&quot;,{writeOnce:true,value:E.parent||false,method:function(F){if(F){F.on(&quot;resize&quot;,this.resize,this,true);}}});},destroy:function(){var G=this.get(&quot;parent&quot;);if(G){G.removeListener(&quot;resize&quot;,this.resize,this,true);}A.removeListener(window,&quot;resize&quot;,this.resize,this,true);this.unsubscribeAll();for(var E in this._units){if(D.hasOwnProperty(this._units,E)){if(this._units[E]){this._units[E].destroy(true);}}}A.purgeElement(this.get(&quot;element&quot;),true);this.get(&quot;parentNode&quot;).removeChild(this.get(&quot;element&quot;));delete YAHOO.widget.Layout._instances[this.get(&quot;id&quot;)];for(var F in this){if(D.hasOwnProperty(this,F)){this[
 F]=null;delete this[F];}}if(G){G.resize();}},toString:function(){if(this.get){return&quot;Layout #&quot;+this.get(&quot;id&quot;);}return&quot;Layout&quot;;}});YAHOO.widget.Layout=B;})();(function(){var D=YAHOO.util.Dom,C=YAHOO.util.Selector,A=YAHOO.util.Event,E=YAHOO.lang;var B=function(G,F){var H={element:G,attributes:F||{}};B.superclass.constructor.call(this,H.element,H.attributes);};B._instances={};B.getLayoutUnitById=function(F){if(B._instances[F]){return B._instances[F];}return false;};YAHOO.extend(B,YAHOO.util.Element,{STR_CLOSE:&quot;Click to close this pane.&quot;,STR_COLLAPSE:&quot;Click to collapse this pane.&quot;,STR_EXPAND:&quot;Click to expand this pane.&quot;,LOADING_CLASSNAME:&quot;loading&quot;,browser:null,_sizes:null,_anim:null,_resize:null,_clip:null,_gutter:null,header:null,body:null,footer:null,_collapsed:null,_collapsing:null,_lastWidth:null,_lastHeight:null,_lastTop:null,_lastLeft:null,_lastScroll:null,_lastCenterScroll:null,_lastScrollTop:null,resiz
 e:function(F){var G=this.fireEvent(&quot;beforeResize&quot;);if(G===false){return this;}if(!this._collapsing||(F===true)){var N=this.get(&quot;scroll&quot;);this.set(&quot;scroll&quot;,false);var K=this._getBoxSize(this.header),J=this._getBoxSize(this.footer),L=[this.get(&quot;height&quot;),this.get(&quot;width&quot;)];var H=(L[0]-K[0]-J[0])-(this._gutter.top+this._gutter.bottom),M=L[1]-(this._gutter.left+this._gutter.right);var O=(H+(K[0]+J[0])),I=M;if(this._collapsed&amp;&amp;!this._collapsing){this._setHeight(this._clip,O);this._setWidth(this._clip,I);D.setStyle(this._clip,&quot;top&quot;,this.get(&quot;top&quot;)+this._gutter.top+&quot;px&quot;);D.setStyle(this._clip,&quot;left&quot;,this.get(&quot;left&quot;)+this._gutter.left+&quot;px&quot;);}else{if(!this._collapsed||(this._collapsed&amp;&amp;this._collapsing)){O=this._setHeight(this.get(&quot;wrap&quot;),O);I=this._setWidth(this.get(&quot;wrap&quot;),I);this._sizes.wrap.h=O;this._sizes.wrap.w=I;D.setStyle(this.get(&q
 uot;wrap&quot;),&quot;top&quot;,this._gutter.top+&quot;px&quot;);D.setStyle(this.get(&quot;wrap&quot;),&quot;left&quot;,this._gutter.left+&quot;px&quot;);this._sizes.header.w=this._setWidth(this.header,I);this._sizes.header.h=K[0];this._sizes.footer.w=this._setWidth(this.footer,I);this._sizes.footer.h=J[0];D.setStyle(this.footer,&quot;bottom&quot;,&quot;0px&quot;);this._sizes.body.h=this._setHeight(this.body,(O-(K[0]+J[0])));this._sizes.body.w=this._setWidth(this.body,I);D.setStyle(this.body,&quot;top&quot;,K[0]+&quot;px&quot;);this.set(&quot;scroll&quot;,N);this.fireEvent(&quot;resize&quot;);}}}return this;},_setWidth:function(H,G){if(H){var F=this._getBorderSizes(H);G=(G-(F[1]+F[3]));G=this._fixQuirks(H,G,&quot;w&quot;);if(G&lt;0){G=0;}D.setStyle(H,&quot;width&quot;,G+&quot;px&quot;);}return G;},_setHeight:function(H,G){if(H){var F=this._getBorderSizes(H);G=(G-(F[0]+F[2]));G=this._fixQuirks(H,G,&quot;h&quot;);if(G&lt;0){G=0;}D.setStyle(H,&quot;height&quot;,G+&quot;px&quot;
 );}return G;},_fixQuirks:function(I,L,G){var K=0,H=2;if(G==&quot;w&quot;){K=1;H=3;}if((this.browser.ie&lt;8)&amp;&amp;!this.browser.standardsMode){var F=this._getBorderSizes(I),J=this._getBorderSizes(I.parentNode);if((F[K]===0)&amp;&amp;(F[H]===0)){if((J[K]!==0)&amp;&amp;(J[H]!==0)){L=(L-(J[K]+J[H]));}}else{if((J[K]===0)&amp;&amp;(J[H]===0)){L=(L+(F[K]+F[H]));}}}return L;},_getBoxSize:function(H){var G=[0,0];if(H){if(this.browser.ie&amp;&amp;!this.browser.standardsMode){H.style.zoom=1;}var F=this._getBorderSizes(H);G[0]=H.clientHeight+(F[0]+F[2]);G[1]=H.clientWidth+(F[1]+F[3]);}return G;},_getBorderSizes:function(H){var G=[];H=H||this.get(&quot;element&quot;);if(this.browser.ie&amp;&amp;!this.browser.standardsMode){H.style.zoom=1;}G[0]=parseInt(D.getStyle(H,&quot;borderTopWidth&quot;),10);G[1]=parseInt(D.getStyle(H,&quot;borderRightWidth&quot;),10);G[2]=parseInt(D.getStyle(H,&quot;borderBottomWidth&quot;),10);G[3]=parseInt(D.getStyle(H,&quot;borderLeftWidth&quot;),10);for(va
 r F=0;F&lt;G.length;F++){if(isNaN(G[F])){G[F]=0;}}return G;},_createClip:function(){if(!this._clip){this._clip=document.createElement(&quot;div&quot;);this._clip.className=&quot;yui-layout-clip yui-layout-clip-&quot;+this.get(&quot;position&quot;);this._clip.innerHTML='&lt;div class=&quot;collapse&quot;&gt;&lt;/div&gt;';var F=this._clip.firstChild;F.title=this.STR_EXPAND;A.on(F,&quot;click&quot;,this.expand,this,true);this.get(&quot;element&quot;).parentNode.appendChild(this._clip);}},_toggleClip:function(){if(!this._collapsed){var J=this._getBoxSize(this.header),K=this._getBoxSize(this.footer),I=[this.get(&quot;height&quot;),this.get(&quot;width&quot;)];var H=(I[0]-J[0]-K[0])-(this._gutter.top+this._gutter.bottom),F=I[1]-(this._gutter.left+this._gutter.right),G=(H+(J[0]+K[0]));switch(this.get(&quot;position&quot;)){case&quot;top&quot;:case&quot;bottom&quot;:this._setWidth(this._clip,F);this._setHeight(this._clip,this.get(&quot;collapseSize&quot;));
+D.setStyle(this._clip,&quot;left&quot;,(this._lastLeft+this._gutter.left)+&quot;px&quot;);if(this.get(&quot;position&quot;)==&quot;bottom&quot;){D.setStyle(this._clip,&quot;top&quot;,((this._lastTop+this._lastHeight)-(this.get(&quot;collapseSize&quot;)-this._gutter.top))+&quot;px&quot;);}else{D.setStyle(this._clip,&quot;top&quot;,this.get(&quot;top&quot;)+this._gutter.top+&quot;px&quot;);}break;case&quot;left&quot;:case&quot;right&quot;:this._setWidth(this._clip,this.get(&quot;collapseSize&quot;));this._setHeight(this._clip,G);D.setStyle(this._clip,&quot;top&quot;,(this.get(&quot;top&quot;)+this._gutter.top)+&quot;px&quot;);if(this.get(&quot;position&quot;)==&quot;right&quot;){D.setStyle(this._clip,&quot;left&quot;,(((this._lastLeft+this._lastWidth)-this.get(&quot;collapseSize&quot;))-this._gutter.left)+&quot;px&quot;);}else{D.setStyle(this._clip,&quot;left&quot;,(this.get(&quot;left&quot;)+this._gutter.left)+&quot;px&quot;);}break;}D.setStyle(this._clip,&quot;display&quot;,
 &quot;block&quot;);this.setStyle(&quot;display&quot;,&quot;none&quot;);}else{D.setStyle(this._clip,&quot;display&quot;,&quot;none&quot;);}},getSizes:function(){return this._sizes;},toggle:function(){if(this._collapsed){this.expand();}else{this.collapse();}return this;},expand:function(){if(!this._collapsed){return this;}var L=this.fireEvent(&quot;beforeExpand&quot;);if(L===false){return this;}this._collapsing=true;this.setStyle(&quot;zIndex&quot;,this._zIndex);if(this._anim){this.setStyle(&quot;display&quot;,&quot;none&quot;);var F={},H;switch(this.get(&quot;position&quot;)){case&quot;left&quot;:case&quot;right&quot;:this.set(&quot;width&quot;,this._lastWidth,true);this.setStyle(&quot;width&quot;,this._lastWidth+&quot;px&quot;);this.get(&quot;parent&quot;).resize(false);H=this.get(&quot;parent&quot;).getSizes()[this.get(&quot;position&quot;)];this.set(&quot;height&quot;,H.h,true);var K=H.l;F={left:{to:K}};if(this.get(&quot;position&quot;)==&quot;left&quot;){F.left.from=(K-H.
 w);this.setStyle(&quot;left&quot;,(K-H.w)+&quot;px&quot;);}break;case&quot;top&quot;:case&quot;bottom&quot;:this.set(&quot;height&quot;,this._lastHeight,true);this.setStyle(&quot;height&quot;,this._lastHeight+&quot;px&quot;);this.get(&quot;parent&quot;).resize(false);H=this.get(&quot;parent&quot;).getSizes()[this.get(&quot;position&quot;)];this.set(&quot;width&quot;,H.w,true);var J=H.t;F={top:{to:J}};if(this.get(&quot;position&quot;)==&quot;top&quot;){this.setStyle(&quot;top&quot;,(J-H.h)+&quot;px&quot;);F.top.from=(J-H.h);}break;}this._anim.attributes=F;var I=function(){this.setStyle(&quot;display&quot;,&quot;block&quot;);this.resize(true);this._anim.onStart.unsubscribe(I,this,true);};var G=function(){this._collapsing=false;this.setStyle(&quot;zIndex&quot;,this._zIndex);this.set(&quot;width&quot;,this._lastWidth);this.set(&quot;height&quot;,this._lastHeight);this._collapsed=false;this.resize();this.set(&quot;scroll&quot;,this._lastScroll);if(this._lastScrollTop&gt;0){this.b
 ody.scrollTop=this._lastScrollTop;}this._anim.onComplete.unsubscribe(G,this,true);this.fireEvent(&quot;expand&quot;);};this._anim.onStart.subscribe(I,this,true);this._anim.onComplete.subscribe(G,this,true);this._anim.animate();this._toggleClip();}else{this._collapsing=false;this._toggleClip();this._collapsed=false;this._zIndex=this.getStyle(&quot;zIndex&quot;);this.setStyle(&quot;zIndex&quot;,this.get(&quot;parent&quot;)._zIndex);this.setStyle(&quot;display&quot;,&quot;block&quot;);this.set(&quot;width&quot;,this._lastWidth);this.set(&quot;height&quot;,this._lastHeight);this.resize();this.set(&quot;scroll&quot;,this._lastScroll);if(this._lastScrollTop&gt;0){this.body.scrollTop=this._lastScrollTop;}this.fireEvent(&quot;expand&quot;);}return this;},collapse:function(){if(this._collapsed){return this;}var J=this.fireEvent(&quot;beforeCollapse&quot;);if(J===false){return this;}if(!this._clip){this._createClip();}this._collapsing=true;var G=this.get(&quot;width&quot;),H=this.get(
 &quot;height&quot;),F={};this._lastWidth=G;this._lastHeight=H;this._lastScroll=this.get(&quot;scroll&quot;);this._lastScrollTop=this.body.scrollTop;this.set(&quot;scroll&quot;,false,true);this._lastLeft=parseInt(this.get(&quot;element&quot;).style.left,10);this._lastTop=parseInt(this.get(&quot;element&quot;).style.top,10);if(isNaN(this._lastTop)){this._lastTop=0;this.set(&quot;top&quot;,0);}if(isNaN(this._lastLeft)){this._lastLeft=0;this.set(&quot;left&quot;,0);}this._zIndex=this.getStyle(&quot;zIndex&quot;);this.setStyle(&quot;zIndex&quot;,this.get(&quot;parent&quot;)._zIndex+1);var K=this.get(&quot;position&quot;);switch(K){case&quot;top&quot;:case&quot;bottom&quot;:this.set(&quot;height&quot;,(this.get(&quot;collapseSize&quot;)+(this._gutter.top+this._gutter.bottom)));F={top:{to:(this.get(&quot;top&quot;)-H)}};if(K==&quot;bottom&quot;){F.top.to=(this.get(&quot;top&quot;)+H);}break;case&quot;left&quot;:case&quot;right&quot;:this.set(&quot;width&quot;,(this.get(&quot;collap
 seSize&quot;)+(this._gutter.left+this._gutter.right)));F={left:{to:-(this._lastWidth)}};if(K==&quot;right&quot;){F.left={to:(this.get(&quot;left&quot;)+G)};}break;}if(this._anim){this._anim.attributes=F;var I=function(){this._collapsing=false;this._toggleClip();this.setStyle(&quot;zIndex&quot;,this.get(&quot;parent&quot;)._zIndex);this._collapsed=true;this.get(&quot;parent&quot;).resize();this._anim.onComplete.unsubscribe(I,this,true);this.fireEvent(&quot;collapse&quot;);};this._anim.onComplete.subscribe(I,this,true);this._anim.animate();}else{this._collapsing=false;this.setStyle(&quot;display&quot;,&quot;none&quot;);this._toggleClip();this.setStyle(&quot;zIndex&quot;,this.get(&quot;parent&quot;)._zIndex);this.get(&quot;parent&quot;).resize();this._collapsed=true;this.fireEvent(&quot;collapse&quot;);}return this;},close:function(){this.setStyle(&quot;display&quot;,&quot;none&quot;);this.get(&quot;parent&quot;).removeUnit(this);this.fireEvent(&quot;close&quot;);if(this._clip)
 {this._clip.parentNode.removeChild(this._clip);this._clip=null;}return this.get(&quot;parent&quot;);},loadHandler:{success:function(F){this.body.innerHTML=F.responseText;this.resize(true);},failure:function(F){}},dataConnection:null,_loading:false,loadContent:function(){if(YAHOO.util.Connect&amp;&amp;this.get(&quot;dataSrc&quot;)&amp;&amp;!this._loading&amp;&amp;!this.get(&quot;dataLoaded&quot;)){this._loading=true;D.addClass(this.body,this.LOADING_CLASSNAME);this.dataConnection=YAHOO.util.Connect.asyncRequest(this.get(&quot;loadMethod&quot;),this.get(&quot;dataSrc&quot;),{success:function(F){this.loadHandler.success.call(this,F);this.set(&quot;dataLoaded&quot;,true);this.dataConnection=null;D.removeClass(this.body,this.LOADING_CLASSNAME);this._loading=false;this.fireEvent(&quot;load&quot;);},failure:function(F){this.loadHandler.failure.call(this,F);this.dataConnection=null;D.removeClass(this.body,this.LOADING_CLASSNAME);this._loading=false;this.fireEvent(&quot;loadError&quo
 t;,{error:F});},scope:this,timeout:this.get(&quot;dataTimeout&quot;)});return this.dataConnection;}return false;},init:function(H,G){this._gutter={left:0,right:0,top:0,bottom:0};this._sizes={wrap:{h:0,w:0},header:{h:0,w:0},body:{h:0,w:0},footer:{h:0,w:0}};B.superclass.init.call(this,H,G);this.browser=this.get(&quot;parent&quot;).browser;var K=H;if(!E.isString(K)){K=D.generateId(K);
+}B._instances[K]=this;this.setStyle(&quot;position&quot;,&quot;absolute&quot;);this.addClass(&quot;yui-layout-unit&quot;);this.addClass(&quot;yui-layout-unit-&quot;+this.get(&quot;position&quot;));var J=this.getElementsByClassName(&quot;yui-layout-hd&quot;,&quot;div&quot;)[0];if(J){this.header=J;}var F=this.getElementsByClassName(&quot;yui-layout-bd&quot;,&quot;div&quot;)[0];if(F){this.body=F;}var I=this.getElementsByClassName(&quot;yui-layout-ft&quot;,&quot;div&quot;)[0];if(I){this.footer=I;}this.on(&quot;contentChange&quot;,this.resize,this,true);this._lastScrollTop=0;this.set(&quot;animate&quot;,this.get(&quot;animate&quot;));},initAttributes:function(F){B.superclass.initAttributes.call(this,F);this.setAttributeConfig(&quot;wrap&quot;,{value:F.wrap||null,method:function(G){if(G){var H=D.generateId(G);B._instances[H]=this;}}});this.setAttributeConfig(&quot;grids&quot;,{value:F.grids||false});this.setAttributeConfig(&quot;top&quot;,{value:F.top||0,validator:E.isNumber,metho
 d:function(G){if(!this._collapsing){this.setStyle(&quot;top&quot;,G+&quot;px&quot;);}}});this.setAttributeConfig(&quot;left&quot;,{value:F.left||0,validator:E.isNumber,method:function(G){if(!this._collapsing){this.setStyle(&quot;left&quot;,G+&quot;px&quot;);}}});this.setAttributeConfig(&quot;minWidth&quot;,{value:F.minWidth||false,method:function(G){if(this._resize){this._resize.set(&quot;minWidth&quot;,G);}},validator:YAHOO.lang.isNumber});this.setAttributeConfig(&quot;maxWidth&quot;,{value:F.maxWidth||false,method:function(G){if(this._resize){this._resize.set(&quot;maxWidth&quot;,G);}},validator:YAHOO.lang.isNumber});this.setAttributeConfig(&quot;minHeight&quot;,{value:F.minHeight||false,method:function(G){if(this._resize){this._resize.set(&quot;minHeight&quot;,G);}},validator:YAHOO.lang.isNumber});this.setAttributeConfig(&quot;maxHeight&quot;,{value:F.maxHeight||false,method:function(G){if(this._resize){this._resize.set(&quot;maxHeight&quot;,G);}},validator:YAHOO.lang.isN
 umber});this.setAttributeConfig(&quot;height&quot;,{value:F.height,validator:E.isNumber,method:function(G){if(!this._collapsing){if(G&lt;0){G=0;}this.setStyle(&quot;height&quot;,G+&quot;px&quot;);}}});this.setAttributeConfig(&quot;width&quot;,{value:F.width,validator:E.isNumber,method:function(G){if(!this._collapsing){if(G&lt;0){G=0;}this.setStyle(&quot;width&quot;,G+&quot;px&quot;);}}});this.setAttributeConfig(&quot;zIndex&quot;,{value:F.zIndex||false,method:function(G){this.setStyle(&quot;zIndex&quot;,G);}});this.setAttributeConfig(&quot;position&quot;,{value:F.position});this.setAttributeConfig(&quot;gutter&quot;,{value:F.gutter||0,validator:YAHOO.lang.isString,method:function(H){var G=H.split(&quot; &quot;);if(G.length){this._gutter.top=parseInt(G[0],10);if(G[1]){this._gutter.right=parseInt(G[1],10);}else{this._gutter.right=this._gutter.top;}if(G[2]){this._gutter.bottom=parseInt(G[2],10);}else{this._gutter.bottom=this._gutter.top;}if(G[3]){this._gutter.left=parseInt(G[3]
 ,10);}else{if(G[1]){this._gutter.left=this._gutter.right;}else{this._gutter.left=this._gutter.top;}}}}});this.setAttributeConfig(&quot;parent&quot;,{writeOnce:true,value:F.parent||false,method:function(G){if(G){G.on(&quot;resize&quot;,this.resize,this,true);}}});this.setAttributeConfig(&quot;collapseSize&quot;,{value:F.collapseSize||25,validator:YAHOO.lang.isNumber});this.setAttributeConfig(&quot;duration&quot;,{value:F.duration||0.5});this.setAttributeConfig(&quot;easing&quot;,{value:F.easing||((YAHOO.util&amp;&amp;YAHOO.util.Easing)?YAHOO.util.Easing.BounceIn:&quot;false&quot;)});this.setAttributeConfig(&quot;animate&quot;,{value:((F.animate===false)?false:true),validator:function(){var G=false;if(YAHOO.util.Anim){G=true;}return G;},method:function(G){if(G){this._anim=new YAHOO.util.Anim(this.get(&quot;element&quot;),{},this.get(&quot;duration&quot;),this.get(&quot;easing&quot;));}else{this._anim=false;}}});this.setAttributeConfig(&quot;header&quot;,{value:F.header||false,
 method:function(G){if(G===false){if(this.header){D.addClass(this.body,&quot;yui-layout-bd-nohd&quot;);this.header.parentNode.removeChild(this.header);this.header=null;}}else{if(!this.header){var I=this.getElementsByClassName(&quot;yui-layout-hd&quot;,&quot;div&quot;)[0];if(!I){I=this._createHeader();}this.header=I;}var H=this.header.getElementsByTagName(&quot;h2&quot;)[0];if(!H){H=document.createElement(&quot;h2&quot;);this.header.appendChild(H);}H.innerHTML=G;if(this.body){D.removeClass(this.body,&quot;yui-layout-bd-nohd&quot;);}}this.fireEvent(&quot;contentChange&quot;,{target:&quot;header&quot;});}});this.setAttributeConfig(&quot;proxy&quot;,{writeOnce:true,value:((F.proxy===false)?false:true)});this.setAttributeConfig(&quot;body&quot;,{value:F.body||false,method:function(I){if(!this.body){var G=this.getElementsByClassName(&quot;yui-layout-bd&quot;,&quot;div&quot;)[0];if(G){this.body=G;}else{G=document.createElement(&quot;div&quot;);G.className=&quot;yui-layout-bd&quot;;t
 his.body=G;this.get(&quot;wrap&quot;).appendChild(G);}}if(!this.header){D.addClass(this.body,&quot;yui-layout-bd-nohd&quot;);}D.addClass(this.body,&quot;yui-layout-bd-noft&quot;);var H=null;if(E.isString(I)){H=D.get(I);}else{if(I&amp;&amp;I.tagName){H=I;}}if(H){var J=D.generateId(H);B._instances[J]=this;this.body.appendChild(H);}else{this.body.innerHTML=I;}this._cleanGrids();this.fireEvent(&quot;contentChange&quot;,{target:&quot;body&quot;});}});this.setAttributeConfig(&quot;footer&quot;,{value:F.footer||false,method:function(H){if(H===false){if(this.footer){D.addClass(this.body,&quot;yui-layout-bd-noft&quot;);this.footer.parentNode.removeChild(this.footer);this.footer=null;}}else{if(!this.footer){var I=this.getElementsByClassName(&quot;yui-layout-ft&quot;,&quot;div&quot;)[0];if(!I){I=document.createElement(&quot;div&quot;);I.className=&quot;yui-layout-ft&quot;;this.footer=I;this.get(&quot;wrap&quot;).appendChild(I);}else{this.footer=I;}}var G=null;if(E.isString(H)){G=D.get(
 H);}else{if(H&amp;&amp;H.tagName){G=H;}}if(G){this.footer.appendChild(G);}else{this.footer.innerHTML=H;}D.removeClass(this.body,&quot;yui-layout-bd-noft&quot;);}this.fireEvent(&quot;contentChange&quot;,{target:&quot;footer&quot;});}});this.setAttributeConfig(&quot;close&quot;,{value:F.close||false,method:function(G){if(this.get(&quot;position&quot;)==&quot;center&quot;){return false;}if(!this.header&amp;&amp;G){this._createHeader();}if(!this.header){return;}var H=this.header?D.getElementsByClassName(&quot;close&quot;,&quot;div&quot;,this.header)[0]:null;if(G){if(!this.get(&quot;header&quot;)){this.set(&quot;header&quot;,&quot;&amp;nbsp;&quot;);}if(!H){H=document.createElement(&quot;div&quot;);H.className=&quot;close&quot;;this.header.appendChild(H);A.on(H,&quot;click&quot;,this.close,this,true);}H.title=this.STR_CLOSE;}else{if(H&amp;&amp;H.parentNode){A.purgeElement(H);H.parentNode.removeChild(H);}}this._configs.close.value=G;this.set(&quot;collapse&quot;,this.get(&quot;coll
 apse&quot;));}});this.setAttributeConfig(&quot;collapse&quot;,{value:F.collapse||false,method:function(G){if(this.get(&quot;position&quot;)==&quot;center&quot;){return false;
+}if(!this.header&amp;&amp;G){this._createHeader();}if(!this.header){return;}var H=this.header?D.getElementsByClassName(&quot;collapse&quot;,&quot;div&quot;,this.header)[0]:null;if(G){if(!this.get(&quot;header&quot;)){this.set(&quot;header&quot;,&quot;&amp;nbsp;&quot;);}if(!H){H=document.createElement(&quot;div&quot;);this.header.appendChild(H);A.on(H,&quot;click&quot;,this.collapse,this,true);}H.title=this.STR_COLLAPSE;H.className=&quot;collapse&quot;+((this.get(&quot;close&quot;))?&quot; collapse-close&quot;:&quot;&quot;);}else{if(H&amp;&amp;H.parentNode){A.purgeElement(H);H.parentNode.removeChild(H);}}}});this.setAttributeConfig(&quot;scroll&quot;,{value:(((F.scroll===true)||(F.scroll===false)||(F.scroll===null))?F.scroll:false),method:function(G){if((G===false)&amp;&amp;!this._collapsed){if(this.body){if(this.body.scrollTop&gt;0){this._lastScrollTop=this.body.scrollTop;}}}if(G===true){this.addClass(&quot;yui-layout-scroll&quot;);this.removeClass(&quot;yui-layout-noscroll&
 quot;);if(this._lastScrollTop&gt;0){if(this.body){this.body.scrollTop=this._lastScrollTop;}}}else{if(G===false){this.removeClass(&quot;yui-layout-scroll&quot;);this.addClass(&quot;yui-layout-noscroll&quot;);}else{if(G===null){this.removeClass(&quot;yui-layout-scroll&quot;);this.removeClass(&quot;yui-layout-noscroll&quot;);}}}}});this.setAttributeConfig(&quot;hover&quot;,{writeOnce:true,value:F.hover||false,validator:YAHOO.lang.isBoolean});this.setAttributeConfig(&quot;useShim&quot;,{value:F.useShim||false,validator:YAHOO.lang.isBoolean,method:function(G){if(this._resize){this._resize.set(&quot;useShim&quot;,G);}}});this.setAttributeConfig(&quot;resize&quot;,{value:F.resize||false,validator:function(G){if(YAHOO.util&amp;&amp;YAHOO.util.Resize){return true;}return false;},method:function(G){if(G&amp;&amp;!this._resize){if(this.get(&quot;position&quot;)==&quot;center&quot;){return false;}var I=false;switch(this.get(&quot;position&quot;)){case&quot;top&quot;:I=&quot;b&quot;;brea
 k;case&quot;bottom&quot;:I=&quot;t&quot;;break;case&quot;right&quot;:I=&quot;l&quot;;break;case&quot;left&quot;:I=&quot;r&quot;;break;}this.setStyle(&quot;position&quot;,&quot;absolute&quot;);if(I){this._resize=new YAHOO.util.Resize(this.get(&quot;element&quot;),{proxy:this.get(&quot;proxy&quot;),hover:this.get(&quot;hover&quot;),status:false,autoRatio:false,handles:[I],minWidth:this.get(&quot;minWidth&quot;),maxWidth:this.get(&quot;maxWidth&quot;),minHeight:this.get(&quot;minHeight&quot;),maxHeight:this.get(&quot;maxHeight&quot;),height:this.get(&quot;height&quot;),width:this.get(&quot;width&quot;),setSize:false,useShim:this.get(&quot;useShim&quot;),wrap:false});this._resize._handles[I].innerHTML='&lt;div class=&quot;yui-layout-resize-knob&quot;&gt;&lt;/div&gt;';if(this.get(&quot;proxy&quot;)){var H=this._resize.getProxyEl();H.innerHTML='&lt;div class=&quot;yui-layout-handle-'+I+'&quot;&gt;&lt;/div&gt;';}this._resize.on(&quot;startResize&quot;,function(J){this._lastScroll=t
 his.get(&quot;scroll&quot;);this.set(&quot;scroll&quot;,false);if(this.get(&quot;parent&quot;)){this.get(&quot;parent&quot;).fireEvent(&quot;startResize&quot;);var K=this.get(&quot;parent&quot;).getUnitByPosition(&quot;center&quot;);this._lastCenterScroll=K.get(&quot;scroll&quot;);K.addClass(this._resize.CSS_RESIZING);K.set(&quot;scroll&quot;,false);}this.fireEvent(&quot;startResize&quot;);},this,true);this._resize.on(&quot;resize&quot;,function(J){this.set(&quot;height&quot;,J.height);this.set(&quot;width&quot;,J.width);},this,true);this._resize.on(&quot;endResize&quot;,function(J){this.set(&quot;scroll&quot;,this._lastScroll);if(this.get(&quot;parent&quot;)){var K=this.get(&quot;parent&quot;).getUnitByPosition(&quot;center&quot;);K.set(&quot;scroll&quot;,this._lastCenterScroll);K.removeClass(this._resize.CSS_RESIZING);}this.resize();this.fireEvent(&quot;endResize&quot;);},this,true);}}else{if(this._resize){this._resize.destroy();}}}});this.setAttributeConfig(&quot;dataSrc&
 quot;,{value:F.dataSrc});this.setAttributeConfig(&quot;loadMethod&quot;,{value:F.loadMethod||&quot;GET&quot;,validator:YAHOO.lang.isString});this.setAttributeConfig(&quot;dataLoaded&quot;,{value:false,validator:YAHOO.lang.isBoolean,writeOnce:true});this.setAttributeConfig(&quot;dataTimeout&quot;,{value:F.dataTimeout||null,validator:YAHOO.lang.isNumber});},_cleanGrids:function(){if(this.get(&quot;grids&quot;)){var F=C.query(&quot;div.yui-b&quot;,this.body,true);if(F){D.removeClass(F,&quot;yui-b&quot;);}A.onAvailable(&quot;yui-main&quot;,function(){D.setStyle(C.query(&quot;#yui-main&quot;),&quot;margin-left&quot;,&quot;0&quot;);D.setStyle(C.query(&quot;#yui-main&quot;),&quot;margin-right&quot;,&quot;0&quot;);});}},_createHeader:function(){var F=document.createElement(&quot;div&quot;);F.className=&quot;yui-layout-hd&quot;;if(this.get(&quot;firstChild&quot;)){this.get(&quot;wrap&quot;).insertBefore(F,this.get(&quot;wrap&quot;).firstChild);}else{this.get(&quot;wrap&quot;).appendC
 hild(F);}this.header=F;return F;},destroy:function(H){if(this._resize){this._resize.destroy();}var G=this.get(&quot;parent&quot;);this.setStyle(&quot;display&quot;,&quot;none&quot;);if(this._clip){this._clip.parentNode.removeChild(this._clip);this._clip=null;}if(!H){G.removeUnit(this);}if(G){G.removeListener(&quot;resize&quot;,this.resize,this,true);}this.unsubscribeAll();A.purgeElement(this.get(&quot;element&quot;),true);this.get(&quot;parentNode&quot;).removeChild(this.get(&quot;element&quot;));delete YAHOO.widget.LayoutUnit._instances[this.get(&quot;id&quot;)];for(var F in this){if(E.hasOwnProperty(this,F)){this[F]=null;delete this[F];}}return G;},toString:function(){if(this.get){return&quot;LayoutUnit #&quot;+this.get(&quot;id&quot;)+&quot; (&quot;+this.get(&quot;position&quot;)+&quot;)&quot;;}return&quot;LayoutUnit&quot;;}});YAHOO.widget.LayoutUnit=B;})();YAHOO.register(&quot;layout&quot;,YAHOO.widget.Layout,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiloggerloggerminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/logger/logger-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/logger/logger-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/logger/logger-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,9 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+YAHOO.widget.LogMsg=function(a){this.msg=this.time=this.category=this.source=this.sourceDetail=null;if(a&amp;&amp;(a.constructor==Object)){for(var b in a){if(a.hasOwnProperty(b)){this[b]=a[b];}}}};YAHOO.widget.LogWriter=function(a){if(!a){YAHOO.log(&quot;Could not instantiate LogWriter due to invalid source.&quot;,&quot;error&quot;,&quot;LogWriter&quot;);return;}this._source=a;};YAHOO.widget.LogWriter.prototype.toString=function(){return&quot;LogWriter &quot;+this._sSource;};YAHOO.widget.LogWriter.prototype.log=function(a,b){YAHOO.widget.Logger.log(a,b,this._source);};YAHOO.widget.LogWriter.prototype.getSource=function(){return this._source;};YAHOO.widget.LogWriter.prototype.setSource=function(a){if(!a){YAHOO.log(&quot;Could not set source due to invalid source.&quot;,&quot;error&quot;,this.toString());return;}else{this._source=a;}};YAHOO.widget.LogWriter.prototype._source=null;if(!YAHOO.widget.Logger){YAHOO.widget.Logger={loggerEnabled:true,_browserConsoleEnabled:false,cate
 gories:[&quot;info&quot;,&quot;warn&quot;,&quot;error&quot;,&quot;time&quot;,&quot;window&quot;],sources:[&quot;global&quot;],_stack:[],maxStackEntries:2500,_startTime:new Date().getTime(),_lastTime:null,_windowErrorsHandled:false,_origOnWindowError:null};YAHOO.widget.Logger.log=function(b,f,g){if(this.loggerEnabled){if(!f){f=&quot;info&quot;;}else{f=f.toLocaleLowerCase();if(this._isNewCategory(f)){this._createNewCategory(f);}}var c=&quot;global&quot;;var a=null;if(g){var d=g.indexOf(&quot; &quot;);if(d&gt;0){c=g.substring(0,d);a=g.substring(d,g.length);}else{c=g;}if(this._isNewSource(c)){this._createNewSource(c);}}var h=new Date();var j=new YAHOO.widget.LogMsg({msg:b,time:h,category:f,source:c,sourceDetail:a});var i=this._stack;var e=this.maxStackEntries;if(e&amp;&amp;!isNaN(e)&amp;&amp;(i.length&gt;=e)){i.shift();}i.push(j);this.newLogEvent.fire(j);if(this._browserConsoleEnabled){this._printToBrowserConsole(j);}return true;}else{return false;}};YAHOO.widget.Logger.reset=fu
 nction(){this._stack=[];this._startTime=new Date().getTime();this.loggerEnabled=true;this.log(&quot;Logger reset&quot;);this.logResetEvent.fire();};YAHOO.widget.Logger.getStack=function(){return this._stack;};YAHOO.widget.Logger.getStartTime=function(){return this._startTime;};YAHOO.widget.Logger.disableBrowserConsole=function(){YAHOO.log(&quot;Logger output to the function console.log() has been disabled.&quot;);this._browserConsoleEnabled=false;};YAHOO.widget.Logger.enableBrowserConsole=function(){this._browserConsoleEnabled=true;YAHOO.log(&quot;Logger output to the function console.log() has been enabled.&quot;);};YAHOO.widget.Logger.handleWindowErrors=function(){if(!YAHOO.widget.Logger._windowErrorsHandled){if(window.error){YAHOO.widget.Logger._origOnWindowError=window.onerror;}window.onerror=YAHOO.widget.Logger._onWindowError;YAHOO.widget.Logger._windowErrorsHandled=true;YAHOO.log(&quot;Logger handling of window.onerror has been enabled.&quot;);}else{YAHOO.log(&quot;Log
 ger handling of window.onerror had already been enabled.&quot;);}};YAHOO.widget.Logger.unhandleWindowErrors=function(){if(YAHOO.widget.Logger._windowErrorsHandled){if(YAHOO.widget.Logger._origOnWindowError){window.onerror=YAHOO.widget.Logger._origOnWindowError;YAHOO.widget.Logger._origOnWindowError=null;}else{window.onerror=null;}YAHOO.widget.Logger._windowErrorsHandled=false;YAHOO.log(&quot;Logger handling of window.onerror has been disabled.&quot;);}else{YAHOO.log(&quot;Logger handling of window.onerror had already been disabled.&quot;);}};YAHOO.widget.Logger.categoryCreateEvent=new YAHOO.util.CustomEvent(&quot;categoryCreate&quot;,this,true);YAHOO.widget.Logger.sourceCreateEvent=new YAHOO.util.CustomEvent(&quot;sourceCreate&quot;,this,true);YAHOO.widget.Logger.newLogEvent=new YAHOO.util.CustomEvent(&quot;newLog&quot;,this,true);YAHOO.widget.Logger.logResetEvent=new YAHOO.util.CustomEvent(&quot;logReset&quot;,this,true);YAHOO.widget.Logger._createNewCategory=function(a){th
 is.categories.push(a);this.categoryCreateEvent.fire(a);};YAHOO.widget.Logger._isNewCategory=function(b){for(var a=0;a&lt;this.categories.length;a++){if(b==this.categories[a]){return false;}}return true;};YAHOO.widget.Logger._createNewSource=function(a){this.sources.push(a);this.sourceCreateEvent.fire(a);};YAHOO.widget.Logger._isNewSource=function(a){if(a){for(var b=0;b&lt;this.sources.length;b++){if(a==this.sources[b]){return false;}}return true;}};YAHOO.widget.Logger._printToBrowserConsole=function(c){if((window.console&amp;&amp;console.log)||(window.opera&amp;&amp;opera.postError)){var e=c.category;var d=c.category.substring(0,4).toUpperCase();var g=c.time;var f;if(g.toLocaleTimeString){f=g.toLocaleTimeString();}else{f=g.toString();}var h=g.getTime();var b=(YAHOO.widget.Logger._lastTime)?(h-YAHOO.widget.Logger._lastTime):0;YAHOO.widget.Logger._lastTime=h;var a=f+&quot; (&quot;+b+&quot;ms): &quot;+c.source+&quot;: &quot;;if(window.console){console.log(a,c.msg);}else{opera.p
 ostError(a+c.msg);}}};YAHOO.widget.Logger._onWindowError=function(a,c,b){try{YAHOO.widget.Logger.log(a+&quot; (&quot;+c+&quot;, line &quot;+b+&quot;)&quot;,&quot;window&quot;);if(YAHOO.widget.Logger._origOnWindowError){YAHOO.widget.Logger._origOnWindowError();}}catch(d){return false;}};YAHOO.widget.Logger.log(&quot;Logger initialized&quot;);}(function(){var c=YAHOO.widget.Logger,e=YAHOO.util,f=e.Dom,a=e.Event,h=document;function b(i,d){i=h.createElement(i);if(d){for(var j in d){if(d.hasOwnProperty(j)){i[j]=d[j];}}}return i;}function g(i,d){this._sName=g._index;g._index++;this._init.apply(this,arguments);if(this.autoRender!==false){this.render();}}YAHOO.lang.augmentObject(g,{_index:0,ENTRY_TEMPLATE:(function(){return b(&quot;pre&quot;,{className:&quot;yui-log-entry&quot;});})(),VERBOSE_TEMPLATE:&quot;&lt;p&gt;&lt;span class='{category}'&gt;{label}&lt;/span&gt; {totalTime}ms (+{elapsedTime}) {localTime}:&lt;/p&gt;&lt;p&gt;{sourceAndDetail}&lt;/p&gt;&lt;p&gt;{message}&lt;/p&gt;
 &quot;,BASIC_TEMPLATE:&quot;&lt;p&gt;&lt;span class='{category}'&gt;{label}&lt;/span&gt; {totalTime}ms (+{elapsedTime}) {localTime}: {sourceAndDetail}: {message}&lt;/p&gt;&quot;});g.prototype={logReaderEnabled:true,width:null,height:null,top:null,left:null,right:null,bottom:null,fontSize:null,footerEnabled:true,verboseOutput:true,entryFormat:null,newestOnTop:true,outputBuffer:100,thresholdMax:500,thresholdMin:100,isCollapsed:false,isPaused:false,draggable:true,toString:function(){return&quot;LogReader instance&quot;+this._sName;},pause:function(){this.isPaused=true;this._timeout=null;
+this.logReaderEnabled=false;if(this._btnPause){this._btnPause.value=&quot;Resume&quot;;}},resume:function(){this.isPaused=false;this.logReaderEnabled=true;this._printBuffer();if(this._btnPause){this._btnPause.value=&quot;Pause&quot;;}},render:function(){if(this.rendered){return;}this._initContainerEl();this._initHeaderEl();this._initConsoleEl();this._initFooterEl();this._initCategories();this._initSources();this._initDragDrop();c.newLogEvent.subscribe(this._onNewLog,this);c.logResetEvent.subscribe(this._onReset,this);c.categoryCreateEvent.subscribe(this._onCategoryCreate,this);c.sourceCreateEvent.subscribe(this._onSourceCreate,this);this.rendered=true;this._filterLogs();},destroy:function(){a.purgeElement(this._elContainer,true);this._elContainer.innerHTML=&quot;&quot;;this._elContainer.parentNode.removeChild(this._elContainer);this.rendered=false;},hide:function(){this._elContainer.style.display=&quot;none&quot;;},show:function(){this._elContainer.style.display=&quot;block&
 quot;;},collapse:function(){this._elConsole.style.display=&quot;none&quot;;if(this._elFt){this._elFt.style.display=&quot;none&quot;;}this._btnCollapse.value=&quot;Expand&quot;;this.isCollapsed=true;},expand:function(){this._elConsole.style.display=&quot;block&quot;;if(this._elFt){this._elFt.style.display=&quot;block&quot;;}this._btnCollapse.value=&quot;Collapse&quot;;this.isCollapsed=false;},getCheckbox:function(d){return this._filterCheckboxes[d];},getCategories:function(){return this._categoryFilters;},showCategory:function(j){var l=this._categoryFilters;if(l.indexOf){if(l.indexOf(j)&gt;-1){return;}}else{for(var d=0;d&lt;l.length;d++){if(l[d]===j){return;}}}this._categoryFilters.push(j);this._filterLogs();var k=this.getCheckbox(j);if(k){k.checked=true;}},hideCategory:function(j){var l=this._categoryFilters;for(var d=0;d&lt;l.length;d++){if(j==l[d]){l.splice(d,1);break;}}this._filterLogs();var k=this.getCheckbox(j);if(k){k.checked=false;}},getSources:function(){return this.
 _sourceFilters;},showSource:function(d){var l=this._sourceFilters;if(l.indexOf){if(l.indexOf(d)&gt;-1){return;}}else{for(var j=0;j&lt;l.length;j++){if(d==l[j]){return;}}}l.push(d);this._filterLogs();var k=this.getCheckbox(d);if(k){k.checked=true;}},hideSource:function(d){var l=this._sourceFilters;for(var j=0;j&lt;l.length;j++){if(d==l[j]){l.splice(j,1);break;}}this._filterLogs();var k=this.getCheckbox(d);if(k){k.checked=false;}},clearConsole:function(){this._timeout=null;this._buffer=[];this._consoleMsgCount=0;var d=this._elConsole;d.innerHTML=&quot;&quot;;},setTitle:function(d){this._title.innerHTML=this.html2Text(d);},getLastTime:function(){return this._lastTime;},formatMsg:function(i){var d=this.entryFormat||(this.verboseOutput?g.VERBOSE_TEMPLATE:g.BASIC_TEMPLATE),j={category:i.category,label:i.category.substring(0,4).toUpperCase(),sourceAndDetail:i.sourceDetail?i.source+&quot; &quot;+i.sourceDetail:i.source,message:this.html2Text(i.msg||i.message||&quot;&quot;)};if(i.tim
 e&amp;&amp;i.time.getTime){j.localTime=i.time.toLocaleTimeString?i.time.toLocaleTimeString():i.time.toString();j.elapsedTime=i.time.getTime()-this.getLastTime();j.totalTime=i.time.getTime()-c.getStartTime();}var k=g.ENTRY_TEMPLATE.cloneNode(true);if(this.verboseOutput){k.className+=&quot; yui-log-verbose&quot;;}k.innerHTML=d.replace(/\{(\w+)\}/g,function(l,m){return(m in j)?j[m]:&quot;&quot;;});return k;},html2Text:function(d){if(d){d+=&quot;&quot;;return d.replace(/&amp;/g,&quot;&amp;#38;&quot;).replace(/&lt;/g,&quot;&amp;#60;&quot;).replace(/&gt;/g,&quot;&amp;#62;&quot;);}return&quot;&quot;;},_sName:null,_buffer:null,_consoleMsgCount:0,_lastTime:null,_timeout:null,_filterCheckboxes:null,_categoryFilters:null,_sourceFilters:null,_elContainer:null,_elHd:null,_elCollapse:null,_btnCollapse:null,_title:null,_elConsole:null,_elFt:null,_elBtns:null,_elCategoryFilters:null,_elSourceFilters:null,_btnPause:null,_btnClear:null,_init:function(d,i){this._buffer=[];this._filterCheckboxe
 s={};this._lastTime=c.getStartTime();if(i&amp;&amp;(i.constructor==Object)){for(var j in i){if(i.hasOwnProperty(j)){this[j]=i[j];}}}this._elContainer=f.get(d);YAHOO.log(&quot;LogReader initialized&quot;,null,this.toString());},_initContainerEl:function(){if(!this._elContainer||!/div$/i.test(this._elContainer.tagName)){this._elContainer=h.body.insertBefore(b(&quot;div&quot;),h.body.firstChild);f.addClass(this._elContainer,&quot;yui-log-container&quot;);}f.addClass(this._elContainer,&quot;yui-log&quot;);var k=this._elContainer.style,d=[&quot;width&quot;,&quot;right&quot;,&quot;top&quot;,&quot;fontSize&quot;],l,j;for(j=d.length-1;j&gt;=0;--j){l=d[j];if(this[l]){k[l]=this[l];}}if(this.left){k.left=this.left;k.right=&quot;auto&quot;;}if(this.bottom){k.bottom=this.bottom;k.top=&quot;auto&quot;;}if(YAHOO.env.ua.opera){h.body.style+=&quot;&quot;;}},_initHeaderEl:function(){if(this._elHd){a.purgeElement(this._elHd,true);this._elHd.innerHTML=&quot;&quot;;}this._elHd=b(&quot;div&quot;,
 {className:&quot;yui-log-hd&quot;});f.generateId(this._elHd,&quot;yui-log-hd&quot;+this._sName);this._elCollapse=b(&quot;div&quot;,{className:&quot;yui-log-btns&quot;});this._btnCollapse=b(&quot;input&quot;,{type:&quot;button&quot;,className:&quot;yui-log-button&quot;,value:&quot;Collapse&quot;});a.on(this._btnCollapse,&quot;click&quot;,this._onClickCollapseBtn,this);this._title=b(&quot;h4&quot;,{innerHTML:&quot;Logger Console&quot;});this._elCollapse.appendChild(this._btnCollapse);this._elHd.appendChild(this._elCollapse);this._elHd.appendChild(this._title);this._elContainer.appendChild(this._elHd);},_initConsoleEl:function(){if(this._elConsole){a.purgeElement(this._elConsole,true);this._elConsole.innerHTML=&quot;&quot;;}this._elConsole=b(&quot;div&quot;,{className:&quot;yui-log-bd&quot;});if(this.height){this._elConsole.style.height=this.height;}this._elContainer.appendChild(this._elConsole);},_initFooterEl:function(){if(this.footerEnabled){if(this._elFt){a.purgeElement(thi
 s._elFt,true);this._elFt.innerHTML=&quot;&quot;;}this._elFt=b(&quot;div&quot;,{className:&quot;yui-log-ft&quot;});this._elBtns=b(&quot;div&quot;,{className:&quot;yui-log-btns&quot;});this._btnPause=b(&quot;input&quot;,{type:&quot;button&quot;,className:&quot;yui-log-button&quot;,value:&quot;Pause&quot;});a.on(this._btnPause,&quot;click&quot;,this._onClickPauseBtn,this);this._btnClear=b(&quot;input&quot;,{type:&quot;button&quot;,className:&quot;yui-log-button&quot;,value:&quot;Clear&quot;});a.on(this._btnClear,&quot;click&quot;,this._onClickClearBtn,this);this._elCategoryFilters=b(&quot;div&quot;,{className:&quot;yui-log-categoryfilters&quot;});this._elSourceFilters=b(&quot;div&quot;,{className:&quot;yui-log-sourcefilters&quot;});this._elBtns.appendChild(this._btnPause);this._elBtns.appendChild(this._btnClear);
+this._elFt.appendChild(this._elBtns);this._elFt.appendChild(this._elCategoryFilters);this._elFt.appendChild(this._elSourceFilters);this._elContainer.appendChild(this._elFt);}},_initDragDrop:function(){if(e.DD&amp;&amp;this.draggable&amp;&amp;this._elHd){var d=new e.DD(this._elContainer);d.setHandleElId(this._elHd.id);this._elHd.style.cursor=&quot;move&quot;;}},_initCategories:function(){this._categoryFilters=[];var k=c.categories;for(var d=0;d&lt;k.length;d++){var i=k[d];this._categoryFilters.push(i);if(this._elCategoryFilters){this._createCategoryCheckbox(i);}}},_initSources:function(){this._sourceFilters=[];var k=c.sources;for(var i=0;i&lt;k.length;i++){var d=k[i];this._sourceFilters.push(d);if(this._elSourceFilters){this._createSourceCheckbox(d);}}},_createCategoryCheckbox:function(l){if(this._elFt){var k=b(&quot;span&quot;,{className:&quot;yui-log-filtergrp&quot;}),j=f.generateId(null,&quot;yui-log-filter-&quot;+l+this._sName),d=b(&quot;input&quot;,{id:j,className:&quot;
 yui-log-filter-&quot;+l,type:&quot;checkbox&quot;,category:l}),i=b(&quot;label&quot;,{htmlFor:j,className:l,innerHTML:l});a.on(d,&quot;click&quot;,this._onCheckCategory,this);this._filterCheckboxes[l]=d;k.appendChild(d);k.appendChild(i);this._elCategoryFilters.appendChild(k);d.checked=true;}},_createSourceCheckbox:function(d){if(this._elFt){var l=b(&quot;span&quot;,{className:&quot;yui-log-filtergrp&quot;}),k=f.generateId(null,&quot;yui-log-filter-&quot;+d+this._sName),i=b(&quot;input&quot;,{id:k,className:&quot;yui-log-filter-&quot;+d,type:&quot;checkbox&quot;,source:d}),j=b(&quot;label&quot;,{htmlFor:k,className:d,innerHTML:d});a.on(i,&quot;click&quot;,this._onCheckSource,this);this._filterCheckboxes[d]=i;l.appendChild(i);l.appendChild(j);this._elSourceFilters.appendChild(l);i.checked=true;}},_filterLogs:function(){if(this._elConsole!==null){this.clearConsole();this._printToConsole(c.getStack());}},_printBuffer:function(){this._timeout=null;if(this._elConsole!==null){var j
 =this.thresholdMax;j=(j&amp;&amp;!isNaN(j))?j:500;if(this._consoleMsgCount&lt;j){var d=[];for(var k=0;k&lt;this._buffer.length;k++){d[k]=this._buffer[k];}this._buffer=[];this._printToConsole(d);}else{this._filterLogs();}if(!this.newestOnTop){this._elConsole.scrollTop=this._elConsole.scrollHeight;}}},_printToConsole:function(r){var k=r.length,v=h.createDocumentFragment(),y=[],z=this.thresholdMin,l=this._sourceFilters.length,w=this._categoryFilters.length,t,q,p,o,u;if(isNaN(z)||(z&gt;this.thresholdMax)){z=0;}t=(k&gt;z)?(k-z):0;for(q=t;q&lt;k;q++){var n=false,s=false,x=r[q],d=x.source,m=x.category;for(p=0;p&lt;l;p++){if(d==this._sourceFilters[p]){s=true;break;}}if(s){for(p=0;p&lt;w;p++){if(m==this._categoryFilters[p]){n=true;break;}}}if(n){if(this._consoleMsgCount===0){this._lastTime=x.time.getTime();}o=this.formatMsg(x);if(typeof o===&quot;string&quot;){y[y.length]=o;}else{v.insertBefore(o,this.newestOnTop?v.firstChild||null:null);}this._consoleMsgCount++;this._lastTime=x.time
 .getTime();}}if(y.length){y.splice(0,0,this._elConsole.innerHTML);this._elConsole.innerHTML=this.newestOnTop?y.reverse().join(&quot;&quot;):y.join(&quot;&quot;);}else{if(v.firstChild){this._elConsole.insertBefore(v,this.newestOnTop?this._elConsole.firstChild||null:null);}}},_onCategoryCreate:function(k,j,d){var i=j[0];d._categoryFilters.push(i);if(d._elFt){d._createCategoryCheckbox(i);}},_onSourceCreate:function(k,j,d){var i=j[0];d._sourceFilters.push(i);if(d._elFt){d._createSourceCheckbox(i);}},_onCheckCategory:function(d,i){var j=this.category;if(!this.checked){i.hideCategory(j);}else{i.showCategory(j);}},_onCheckSource:function(d,i){var j=this.source;if(!this.checked){i.hideSource(j);}else{i.showSource(j);}},_onClickCollapseBtn:function(d,i){if(!i.isCollapsed){i.collapse();}else{i.expand();}},_onClickPauseBtn:function(d,i){if(!i.isPaused){i.pause();}else{i.resume();}},_onClickClearBtn:function(d,i){i.clearConsole();},_onNewLog:function(k,j,d){var i=j[0];d._buffer.push(i);
 if(d.logReaderEnabled===true&amp;&amp;d._timeout===null){d._timeout=setTimeout(function(){d._printBuffer();},d.outputBuffer);}},_onReset:function(j,i,d){d._filterLogs();}};YAHOO.widget.LogReader=g;})();YAHOO.register(&quot;logger&quot;,YAHOO.widget.Logger,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuimenumenuminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/menu/menu-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/menu/menu-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/menu/menu-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,16 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+(function(){var K=YAHOO.env.ua,C=YAHOO.util.Dom,Z=YAHOO.util.Event,H=YAHOO.lang,T=&quot;DIV&quot;,P=&quot;hd&quot;,M=&quot;bd&quot;,O=&quot;ft&quot;,X=&quot;LI&quot;,A=&quot;disabled&quot;,D=&quot;mouseover&quot;,F=&quot;mouseout&quot;,U=&quot;mousedown&quot;,G=&quot;mouseup&quot;,V=&quot;click&quot;,B=&quot;keydown&quot;,N=&quot;keyup&quot;,I=&quot;keypress&quot;,L=&quot;clicktohide&quot;,S=&quot;position&quot;,Q=&quot;dynamic&quot;,Y=&quot;showdelay&quot;,J=&quot;selected&quot;,E=&quot;visible&quot;,W=&quot;UL&quot;,R=&quot;MenuManager&quot;;YAHOO.widget.MenuManager=function(){var l=false,d={},o={},h={},c={&quot;click&quot;:&quot;clickEvent&quot;,&quot;mousedown&quot;:&quot;mouseDownEvent&quot;,&quot;mouseup&quot;:&quot;mouseUpEvent&quot;,&quot;mouseover&quot;:&quot;mouseOverEvent&quot;,&quot;mouseout&quot;:&quot;mouseOutEvent&quot;,&quot;keydown&quot;:&quot;keyDownEvent&quot;,&quot;keyup&quot;:&quot;keyUpEvent&quot;,&quot;keypress&quot;:&quot;keyPressEvent&quot;,&quot;foc
 us&quot;:&quot;focusEvent&quot;,&quot;focusin&quot;:&quot;focusEvent&quot;,&quot;blur&quot;:&quot;blurEvent&quot;,&quot;focusout&quot;:&quot;blurEvent&quot;},i=null;function b(r){var p,q;if(r&amp;&amp;r.tagName){switch(r.tagName.toUpperCase()){case T:p=r.parentNode;if((C.hasClass(r,P)||C.hasClass(r,M)||C.hasClass(r,O))&amp;&amp;p&amp;&amp;p.tagName&amp;&amp;p.tagName.toUpperCase()==T){q=p;}else{q=r;}break;case X:q=r;break;default:p=r.parentNode;if(p){q=b(p);}break;}}return q;}function e(t){var p=Z.getTarget(t),q=b(p),u=true,w=t.type,x,r,s,z,y;if(q){r=q.tagName.toUpperCase();if(r==X){s=q.id;if(s&amp;&amp;h[s]){z=h[s];y=z.parent;}}else{if(r==T){if(q.id){y=d[q.id];}}}}if(y){x=c[w];if(w==&quot;click&quot;&amp;&amp;(K.gecko&amp;&amp;y.platform!=&quot;mac&quot;)&amp;&amp;t.button&gt;0){u=false;}if(u&amp;&amp;z&amp;&amp;!z.cfg.getProperty(A)){z[x].fire(t);}if(u){y[x].fire(t,z);}}else{if(w==U){for(var v in o){if(H.hasOwnProperty(o,v)){y=o[v];if(y.cfg.getProperty(L)&amp;&amp;!(y inst
 anceof YAHOO.widget.MenuBar)&amp;&amp;y.cfg.getProperty(S)==Q){y.hide();if(K.ie&amp;&amp;p.focus&amp;&amp;(K.ie&lt;9)){p.setActive();}}else{if(y.cfg.getProperty(Y)&gt;0){y._cancelShowDelay();}if(y.activeItem){y.activeItem.blur();y.activeItem.cfg.setProperty(J,false);y.activeItem=null;}}}}}}}function n(q,p,r){if(d[r.id]){this.removeMenu(r);}}function k(q,p){var r=p[1];if(r){i=r;}}function f(q,p){i=null;}function a(r,q){var p=q[0],s=this.id;if(p){o[s]=this;}else{if(o[s]){delete o[s];}}}function j(q,p){m(this);}function m(q){var p=q.id;if(p&amp;&amp;h[p]){if(i==q){i=null;}delete h[p];q.destroyEvent.unsubscribe(j);}}function g(q,p){var s=p[0],r;if(s instanceof YAHOO.widget.MenuItem){r=s.id;if(!h[r]){h[r]=s;s.destroyEvent.subscribe(j);}}}return{addMenu:function(q){var p;if(q instanceof YAHOO.widget.Menu&amp;&amp;q.id&amp;&amp;!d[q.id]){d[q.id]=q;if(!l){p=document;Z.on(p,D,e,this,true);Z.on(p,F,e,this,true);Z.on(p,U,e,this,true);Z.on(p,G,e,this,true);Z.on(p,V,e,this,true);Z.on(p,B
 ,e,this,true);Z.on(p,N,e,this,true);Z.on(p,I,e,this,true);Z.onFocus(p,e,this,true);Z.onBlur(p,e,this,true);l=true;}q.cfg.subscribeToConfigEvent(E,a);q.destroyEvent.subscribe(n,q,this);q.itemAddedEvent.subscribe(g);q.focusEvent.subscribe(k);q.blurEvent.subscribe(f);}},removeMenu:function(s){var q,p,r;if(s){q=s.id;if((q in d)&amp;&amp;(d[q]==s)){p=s.getItems();if(p&amp;&amp;p.length&gt;0){r=p.length-1;do{m(p[r]);}while(r--);}delete d[q];if((q in o)&amp;&amp;(o[q]==s)){delete o[q];}if(s.cfg){s.cfg.unsubscribeFromConfigEvent(E,a);}s.destroyEvent.unsubscribe(n,s);s.itemAddedEvent.unsubscribe(g);s.focusEvent.unsubscribe(k);s.blurEvent.unsubscribe(f);}}},hideVisible:function(){var p;for(var q in o){if(H.hasOwnProperty(o,q)){p=o[q];if(!(p instanceof YAHOO.widget.MenuBar)&amp;&amp;p.cfg.getProperty(S)==Q){p.hide();}}}},getVisible:function(){return o;},getMenus:function(){return d;},getMenu:function(q){var p;if(q in d){p=d[q];}return p;},getMenuItem:function(q){var p;if(q in h){p=h[q]
 ;}return p;},getMenuItemGroup:function(t){var q=C.get(t),p,v,u,r,s;if(q&amp;&amp;q.tagName&amp;&amp;q.tagName.toUpperCase()==W){v=q.firstChild;if(v){p=[];do{r=v.id;if(r){u=this.getMenuItem(r);if(u){p[p.length]=u;}}}while((v=v.nextSibling));if(p.length&gt;0){s=p;}}}return s;},getFocusedMenuItem:function(){return i;},getFocusedMenu:function(){var p;if(i){p=i.parent.getRoot();}return p;},toString:function(){return R;}};}();})();(function(){var AM=YAHOO.lang,Aq=&quot;Menu&quot;,G=&quot;DIV&quot;,K=&quot;div&quot;,Am=&quot;id&quot;,AH=&quot;SELECT&quot;,e=&quot;xy&quot;,R=&quot;y&quot;,Ax=&quot;UL&quot;,L=&quot;ul&quot;,AJ=&quot;first-of-type&quot;,k=&quot;LI&quot;,h=&quot;OPTGROUP&quot;,Az=&quot;OPTION&quot;,Ah=&quot;disabled&quot;,AY=&quot;none&quot;,y=&quot;selected&quot;,At=&quot;groupindex&quot;,i=&quot;index&quot;,O=&quot;submenu&quot;,Au=&quot;visible&quot;,AX=&quot;hidedelay&quot;,Ac=&quot;position&quot;,AD=&quot;dynamic&quot;,C=&quot;static&quot;,An=AD+&quot;,&quot;+C,Q=
 &quot;url&quot;,M=&quot;#&quot;,V=&quot;target&quot;,AU=&quot;maxheight&quot;,T=&quot;topscrollbar&quot;,x=&quot;bottomscrollbar&quot;,d=&quot;_&quot;,P=T+d+Ah,E=x+d+Ah,b=&quot;mousemove&quot;,Av=&quot;showdelay&quot;,c=&quot;submenuhidedelay&quot;,AF=&quot;iframe&quot;,w=&quot;constraintoviewport&quot;,A4=&quot;preventcontextoverlap&quot;,AO=&quot;submenualignment&quot;,Z=&quot;autosubmenudisplay&quot;,AC=&quot;clicktohide&quot;,g=&quot;container&quot;,j=&quot;scrollincrement&quot;,Aj=&quot;minscrollheight&quot;,A2=&quot;classname&quot;,Ag=&quot;shadow&quot;,Ar=&quot;keepopen&quot;,A0=&quot;hd&quot;,D=&quot;hastitle&quot;,p=&quot;context&quot;,u=&quot;&quot;,Ak=&quot;mousedown&quot;,Ae=&quot;keydown&quot;,Ao=&quot;height&quot;,U=&quot;width&quot;,AQ=&quot;px&quot;,Ay=&quot;effect&quot;,AE=&quot;monitorresize&quot;,AW=&quot;display&quot;,AV=&quot;block&quot;,J=&quot;visibility&quot;,z=&quot;absolute&quot;,AS=&quot;zindex&quot;,l=&quot;yui-menu-body-scrolled&quot;,AK=&quot;&a
 mp;#32;&quot;,A1=&quot; &quot;,Ai=&quot;mouseover&quot;,H=&quot;mouseout&quot;,AR=&quot;itemAdded&quot;,n=&quot;itemRemoved&quot;,AL=&quot;hidden&quot;,s=&quot;yui-menu-shadow&quot;,AG=s+&quot;-visible&quot;,m=s+A1+AG;YAHOO.widget.Menu=function(A6,A5){if(A5){this.parent=A5.parent;this.lazyLoad=A5.lazyLoad||A5.lazyload;this.itemData=A5.itemData||A5.itemdata;}YAHOO.widget.Menu.superclass.constructor.call(this,A6,A5);};function B(A6){var A5=false;if(AM.isString(A6)){A5=(An.indexOf((A6.toLowerCase()))!=-1);}return A5;}var f=YAHOO.util.Dom,AA=YAHOO.util.Event,Aw=YAHOO.widget.Module,AB=YAHOO.widget.Overlay,r=YAHOO.widget.Menu,A3=YAHOO.widget.MenuManager,F=YAHOO.util.CustomEvent,As=YAHOO.env.ua,Ap,AT=false,Ad,Ab=[[&quot;mouseOverEvent&quot;,Ai],[&quot;mouseOutEvent&quot;,H],[&quot;mouseDownEvent&quot;,Ak],[&quot;mouseUpEvent&quot;,&quot;mouseup&quot;],[&quot;clickEvent&quot;,&quot;click&quot;],[&quot;keyPressEvent&quot;,&quot;keypress&quot;],[&quot;keyDownEvent&quot;,Ae],[&quot;key
 UpEvent&quot;,&quot;keyup&quot;],[&quot;focusEvent&quot;,&quot;focus&quot;],[&quot;blurEvent&quot;,&quot;blur&quot;],[&quot;itemAddedEvent&quot;,AR],[&quot;itemRemovedEvent&quot;,n]],AZ={key:Au,value:false,validator:AM.isBoolean},AP={key:w,value:true,validator:AM.isBoolean,supercedes:[AF,&quot;x&quot;,R,e]},AI={key:A4,value:true,validator:AM.isBoolean,supercedes:[w]},S={key:Ac,value:AD,validator:B,supercedes:[Au,AF]},A={key:AO,value:[&quot;tl&quot;,&quot;tr&quot;]},t={key:Z,value:true,validator:AM.isBoolean,suppressEvent:true},Y={key:Av,value:250,validator:AM.isNumber,suppressEvent:true},q={key:AX,value:0,validator:AM.isNumber,suppressEvent:true},v={key:c,value:250,validator:AM.isNumber,suppressEvent:true},o={key:AC,value:true,validator:AM.isBoolean,suppressEvent:true},AN={key:g,suppressEvent:true},Af={key:j,value:1,validator:AM.isNumber,supercedes:[AU],suppressEvent:true},N={key:Aj,value:90,validator:AM.isNumber,supercedes:[AU],suppressEvent:true},X={key:AU,value:0,validato
 r:AM.isNumber,supercedes:[AF],suppressEvent:true},W={key:A2,value:null,validator:AM.isString,suppressEvent:true},a={key:Ah,value:false,validator:AM.isBoolean,suppressEvent:true},I={key:Ag,value:true,validator:AM.isBoolean,suppressEvent:true,supercedes:[Au]},Al={key:Ar,value:false,validator:AM.isBoolean};
+function Aa(A5){Ad=AA.getTarget(A5);}YAHOO.lang.extend(r,AB,{CSS_CLASS_NAME:&quot;yuimenu&quot;,ITEM_TYPE:null,GROUP_TITLE_TAG_NAME:&quot;h6&quot;,OFF_SCREEN_POSITION:&quot;-999em&quot;,_useHideDelay:false,_bHandledMouseOverEvent:false,_bHandledMouseOutEvent:false,_aGroupTitleElements:null,_aItemGroups:null,_aListElements:null,_nCurrentMouseX:0,_bStopMouseEventHandlers:false,_sClassName:null,lazyLoad:false,itemData:null,activeItem:null,parent:null,srcElement:null,init:function(A7,A6){this._aItemGroups=[];this._aListElements=[];this._aGroupTitleElements=[];if(!this.ITEM_TYPE){this.ITEM_TYPE=YAHOO.widget.MenuItem;}var A5;if(AM.isString(A7)){A5=f.get(A7);}else{if(A7.tagName){A5=A7;}}if(A5&amp;&amp;A5.tagName){switch(A5.tagName.toUpperCase()){case G:this.srcElement=A5;if(!A5.id){A5.setAttribute(Am,f.generateId());}r.superclass.init.call(this,A5);this.beforeInitEvent.fire(r);break;case AH:this.srcElement=A5;r.superclass.init.call(this,f.generateId());this.beforeInitEvent.fire(r);
 break;}}else{r.superclass.init.call(this,A7);this.beforeInitEvent.fire(r);}if(this.element){f.addClass(this.element,this.CSS_CLASS_NAME);this.initEvent.subscribe(this._onInit);this.beforeRenderEvent.subscribe(this._onBeforeRender);this.renderEvent.subscribe(this._onRender);this.beforeShowEvent.subscribe(this._onBeforeShow);this.hideEvent.subscribe(this._onHide);this.showEvent.subscribe(this._onShow);this.beforeHideEvent.subscribe(this._onBeforeHide);this.mouseOverEvent.subscribe(this._onMouseOver);this.mouseOutEvent.subscribe(this._onMouseOut);this.clickEvent.subscribe(this._onClick);this.keyDownEvent.subscribe(this._onKeyDown);this.keyPressEvent.subscribe(this._onKeyPress);this.blurEvent.subscribe(this._onBlur);if(!AT){AA.onFocus(document,Aa);AT=true;}if((As.gecko&amp;&amp;As.gecko&lt;1.9)||(As.webkit&amp;&amp;As.webkit&lt;523)){this.cfg.subscribeToConfigEvent(R,this._onYChange);}if(A6){this.cfg.applyConfig(A6,true);}A3.addMenu(this);this.initEvent.fire(r);}},_initSubTree:f
 unction(){var A6=this.srcElement,A5,A8,BB,BC,BA,A9,A7;if(A6){A5=(A6.tagName&amp;&amp;A6.tagName.toUpperCase());if(A5==G){BC=this.body.firstChild;if(BC){A8=0;BB=this.GROUP_TITLE_TAG_NAME.toUpperCase();do{if(BC&amp;&amp;BC.tagName){switch(BC.tagName.toUpperCase()){case BB:this._aGroupTitleElements[A8]=BC;break;case Ax:this._aListElements[A8]=BC;this._aItemGroups[A8]=[];A8++;break;}}}while((BC=BC.nextSibling));if(this._aListElements[0]){f.addClass(this._aListElements[0],AJ);}}}BC=null;if(A5){switch(A5){case G:BA=this._aListElements;A9=BA.length;if(A9&gt;0){A7=A9-1;do{BC=BA[A7].firstChild;if(BC){do{if(BC&amp;&amp;BC.tagName&amp;&amp;BC.tagName.toUpperCase()==k){this.addItem(new this.ITEM_TYPE(BC,{parent:this}),A7);}}while((BC=BC.nextSibling));}}while(A7--);}break;case AH:BC=A6.firstChild;do{if(BC&amp;&amp;BC.tagName){switch(BC.tagName.toUpperCase()){case h:case Az:this.addItem(new this.ITEM_TYPE(BC,{parent:this}));break;}}}while((BC=BC.nextSibling));break;}}}},_getFirstEnabledIt
 em:function(){var A5=this.getItems(),A9=A5.length,A8,A7;for(var A6=0;A6&lt;A9;A6++){A8=A5[A6];if(A8&amp;&amp;!A8.cfg.getProperty(Ah)&amp;&amp;A8.element.style.display!=AY){A7=A8;break;}}return A7;},_addItemToGroup:function(BA,BB,BF){var BD,BG,A8,BE,A9,A6,A7,BC;function A5(BH,BI){return(BH[BI]||A5(BH,(BI+1)));}if(BB instanceof this.ITEM_TYPE){BD=BB;BD.parent=this;}else{if(AM.isString(BB)){BD=new this.ITEM_TYPE(BB,{parent:this});}else{if(AM.isObject(BB)){BB.parent=this;BD=new this.ITEM_TYPE(BB.text,BB);}}}if(BD){if(BD.cfg.getProperty(y)){this.activeItem=BD;}BG=AM.isNumber(BA)?BA:0;A8=this._getItemGroup(BG);if(!A8){A8=this._createItemGroup(BG);}if(AM.isNumber(BF)){A9=(BF&gt;=A8.length);if(A8[BF]){A8.splice(BF,0,BD);}else{A8[BF]=BD;}BE=A8[BF];if(BE){if(A9&amp;&amp;(!BE.element.parentNode||BE.element.parentNode.nodeType==11)){this._aListElements[BG].appendChild(BE.element);}else{A6=A5(A8,(BF+1));if(A6&amp;&amp;(!BE.element.parentNode||BE.element.parentNode.nodeType==11)){this._aL
 istElements[BG].insertBefore(BE.element,A6.element);}}BE.parent=this;this._subscribeToItemEvents(BE);this._configureSubmenu(BE);this._updateItemProperties(BG);this.itemAddedEvent.fire(BE);this.changeContentEvent.fire();BC=BE;}}else{A7=A8.length;A8[A7]=BD;BE=A8[A7];if(BE){if(!f.isAncestor(this._aListElements[BG],BE.element)){this._aListElements[BG].appendChild(BE.element);}BE.element.setAttribute(At,BG);BE.element.setAttribute(i,A7);BE.parent=this;BE.index=A7;BE.groupIndex=BG;this._subscribeToItemEvents(BE);this._configureSubmenu(BE);if(A7===0){f.addClass(BE.element,AJ);}this.itemAddedEvent.fire(BE);this.changeContentEvent.fire();BC=BE;}}}return BC;},_removeItemFromGroupByIndex:function(A8,A6){var A7=AM.isNumber(A8)?A8:0,A9=this._getItemGroup(A7),BB,BA,A5;if(A9){BB=A9.splice(A6,1);BA=BB[0];if(BA){this._updateItemProperties(A7);if(A9.length===0){A5=this._aListElements[A7];if(A5&amp;&amp;A5.parentNode){A5.parentNode.removeChild(A5);}this._aItemGroups.splice(A7,1);this._aListEle
 ments.splice(A7,1);A5=this._aListElements[0];if(A5){f.addClass(A5,AJ);}}this.itemRemovedEvent.fire(BA);this.changeContentEvent.fire();}}return BA;},_removeItemFromGroupByValue:function(A8,A5){var BA=this._getItemGroup(A8),BB,A9,A7,A6;if(BA){BB=BA.length;A9=-1;if(BB&gt;0){A6=BB-1;do{if(BA[A6]==A5){A9=A6;break;}}while(A6--);if(A9&gt;-1){A7=this._removeItemFromGroupByIndex(A8,A9);}}}return A7;},_updateItemProperties:function(A6){var A7=this._getItemGroup(A6),BA=A7.length,A9,A8,A5;if(BA&gt;0){A5=BA-1;do{A9=A7[A5];if(A9){A8=A9.element;A9.index=A5;A9.groupIndex=A6;A8.setAttribute(At,A6);A8.setAttribute(i,A5);f.removeClass(A8,AJ);}}while(A5--);if(A8){f.addClass(A8,AJ);}}},_createItemGroup:function(A7){var A5,A6;if(!this._aItemGroups[A7]){this._aItemGroups[A7]=[];A5=document.createElement(L);this._aListElements[A7]=A5;A6=this._aItemGroups[A7];}return A6;},_getItemGroup:function(A7){var A5=AM.isNumber(A7)?A7:0,A8=this._aItemGroups,A6;if(A5 in A8){A6=A8[A5];}return A6;},_configureSubm
 enu:function(A5){var A6=A5.cfg.getProperty(O);if(A6){this.cfg.configChangedEvent.subscribe(this._onParentMenuConfigChange,A6,true);this.renderEvent.subscribe(this._onParentMenuRender,A6,true);}},_subscribeToItemEvents:function(A5){A5.destroyEvent.subscribe(this._onMenuItemDestroy,A5,this);
+A5.cfg.configChangedEvent.subscribe(this._onMenuItemConfigChange,A5,this);},_onVisibleChange:function(A7,A6){var A5=A6[0];if(A5){f.addClass(this.element,Au);}else{f.removeClass(this.element,Au);}},_cancelHideDelay:function(){var A5=this.getRoot()._hideDelayTimer;if(A5){A5.cancel();}},_execHideDelay:function(){this._cancelHideDelay();var A5=this.getRoot();A5._hideDelayTimer=AM.later(A5.cfg.getProperty(AX),this,function(){if(A5.activeItem){if(A5.hasFocus()){A5.activeItem.focus();}A5.clearActiveItem();}if(A5==this&amp;&amp;!(this instanceof YAHOO.widget.MenuBar)&amp;&amp;this.cfg.getProperty(Ac)==AD){this.hide();}});},_cancelShowDelay:function(){var A5=this.getRoot()._showDelayTimer;if(A5){A5.cancel();}},_execSubmenuHideDelay:function(A7,A6,A5){A7._submenuHideDelayTimer=AM.later(50,this,function(){if(this._nCurrentMouseX&gt;(A6+10)){A7._submenuHideDelayTimer=AM.later(A5,A7,function(){this.hide();});}else{A7.hide();}});},_disableScrollHeader:function(){if(!this._bHeaderDisabled)
 {f.addClass(this.header,P);this._bHeaderDisabled=true;}},_disableScrollFooter:function(){if(!this._bFooterDisabled){f.addClass(this.footer,E);this._bFooterDisabled=true;}},_enableScrollHeader:function(){if(this._bHeaderDisabled){f.removeClass(this.header,P);this._bHeaderDisabled=false;}},_enableScrollFooter:function(){if(this._bFooterDisabled){f.removeClass(this.footer,E);this._bFooterDisabled=false;}},_onMouseOver:function(BH,BA){var BI=BA[0],BE=BA[1],A5=AA.getTarget(BI),A9=this.getRoot(),BG=this._submenuHideDelayTimer,A6,A8,BD,A7,BC,BB;var BF=function(){if(this.parent.cfg.getProperty(y)){this.show();}};if(!this._bStopMouseEventHandlers){if(!this._bHandledMouseOverEvent&amp;&amp;(A5==this.element||f.isAncestor(this.element,A5))){if(this._useHideDelay){this._cancelHideDelay();}this._nCurrentMouseX=0;AA.on(this.element,b,this._onMouseMove,this,true);if(!(BE&amp;&amp;f.isAncestor(BE.element,AA.getRelatedTarget(BI)))){this.clearActiveItem();}if(this.parent&amp;&amp;BG){BG.cance
 l();this.parent.cfg.setProperty(y,true);A6=this.parent.parent;A6._bHandledMouseOutEvent=true;A6._bHandledMouseOverEvent=false;}this._bHandledMouseOverEvent=true;this._bHandledMouseOutEvent=false;}if(BE&amp;&amp;!BE.handledMouseOverEvent&amp;&amp;!BE.cfg.getProperty(Ah)&amp;&amp;(A5==BE.element||f.isAncestor(BE.element,A5))){A8=this.cfg.getProperty(Av);BD=(A8&gt;0);if(BD){this._cancelShowDelay();}A7=this.activeItem;if(A7){A7.cfg.setProperty(y,false);}BC=BE.cfg;BC.setProperty(y,true);if(this.hasFocus()||A9._hasFocus){BE.focus();A9._hasFocus=false;}if(this.cfg.getProperty(Z)){BB=BC.getProperty(O);if(BB){if(BD){A9._showDelayTimer=AM.later(A9.cfg.getProperty(Av),BB,BF);}else{BB.show();}}}BE.handledMouseOverEvent=true;BE.handledMouseOutEvent=false;}}},_onMouseOut:function(BD,A7){var BE=A7[0],BB=A7[1],A8=AA.getRelatedTarget(BE),BC=false,BA,A9,A5,A6;if(!this._bStopMouseEventHandlers){if(BB&amp;&amp;!BB.cfg.getProperty(Ah)){BA=BB.cfg;A9=BA.getProperty(O);if(A9&amp;&amp;(A8==A9.elemen
 t||f.isAncestor(A9.element,A8))){BC=true;}if(!BB.handledMouseOutEvent&amp;&amp;((A8!=BB.element&amp;&amp;!f.isAncestor(BB.element,A8))||BC)){if(!BC){BB.cfg.setProperty(y,false);if(A9){A5=this.cfg.getProperty(c);A6=this.cfg.getProperty(Av);if(!(this instanceof YAHOO.widget.MenuBar)&amp;&amp;A5&gt;0&amp;&amp;A5&gt;=A6){this._execSubmenuHideDelay(A9,AA.getPageX(BE),A5);}else{A9.hide();}}}BB.handledMouseOutEvent=true;BB.handledMouseOverEvent=false;}}if(!this._bHandledMouseOutEvent){if(this._didMouseLeave(A8)||BC){if(this._useHideDelay){this._execHideDelay();}AA.removeListener(this.element,b,this._onMouseMove);this._nCurrentMouseX=AA.getPageX(BE);this._bHandledMouseOutEvent=true;this._bHandledMouseOverEvent=false;}}}},_didMouseLeave:function(A5){return(A5===this._shadow||(A5!=this.element&amp;&amp;!f.isAncestor(this.element,A5)));},_onMouseMove:function(A6,A5){if(!this._bStopMouseEventHandlers){this._nCurrentMouseX=AA.getPageX(A6);}},_onClick:function(BG,A7){var BH=A7[0],BB=A7[1]
 ,BD=false,A9,BE,A6,A5,BA,BC,BF;var A8=function(){A6=this.getRoot();if(A6 instanceof YAHOO.widget.MenuBar||A6.cfg.getProperty(Ac)==C){A6.clearActiveItem();}else{A6.hide();}};if(BB){if(BB.cfg.getProperty(Ah)){AA.preventDefault(BH);A8.call(this);}else{A9=BB.cfg.getProperty(O);BA=BB.cfg.getProperty(Q);if(BA){BC=BA.indexOf(M);BF=BA.length;if(BC!=-1){BA=BA.substr(BC,BF);BF=BA.length;if(BF&gt;1){A5=BA.substr(1,BF);BE=YAHOO.widget.MenuManager.getMenu(A5);if(BE){BD=(this.getRoot()===BE.getRoot());}}else{if(BF===1){BD=true;}}}}if(BD&amp;&amp;!BB.cfg.getProperty(V)){AA.preventDefault(BH);if(As.webkit){BB.focus();}else{BB.focusEvent.fire();}}if(!A9&amp;&amp;!this.cfg.getProperty(Ar)){A8.call(this);}}}},_stopMouseEventHandlers:function(){this._bStopMouseEventHandlers=true;AM.later(10,this,function(){this._bStopMouseEventHandlers=false;});},_onKeyDown:function(BJ,BD){var BG=BD[0],BF=BD[1],BC,BH,A6,A9,BK,A5,BN,A8,BI,A7,BE,BM,BA,BB;if(this._useHideDelay){this._cancelHideDelay();}if(BF&amp;&
 amp;!BF.cfg.getProperty(Ah)){BH=BF.cfg;A6=this.parent;switch(BG.keyCode){case 38:case 40:BK=(BG.keyCode==38)?BF.getPreviousEnabledSibling():BF.getNextEnabledSibling();if(BK){this.clearActiveItem();BK.cfg.setProperty(y,true);BK.focus();if(this.cfg.getProperty(AU)&gt;0||f.hasClass(this.body,l)){A5=this.body;BN=A5.scrollTop;A8=A5.offsetHeight;BI=this.getItems();A7=BI.length-1;BE=BK.element.offsetTop;if(BG.keyCode==40){if(BE&gt;=(A8+BN)){A5.scrollTop=BE-A8;}else{if(BE&lt;=BN){A5.scrollTop=0;}}if(BK==BI[A7]){A5.scrollTop=BK.element.offsetTop;}}else{if(BE&lt;=BN){A5.scrollTop=BE-BK.element.offsetHeight;}else{if(BE&gt;=(BN+A8)){A5.scrollTop=BE;}}if(BK==BI[0]){A5.scrollTop=0;}}BN=A5.scrollTop;BM=A5.scrollHeight-A5.offsetHeight;if(BN===0){this._disableScrollHeader();this._enableScrollFooter();}else{if(BN==BM){this._enableScrollHeader();this._disableScrollFooter();}else{this._enableScrollHeader();this._enableScrollFooter();}}}}AA.preventDefault(BG);this._stopMouseEventHandlers();break
 ;case 39:BC=BH.getProperty(O);if(BC){if(!BH.getProperty(y)){BH.setProperty(y,true);}BC.show();BC.setInitialFocus();BC.setInitialSelection();}else{A9=this.getRoot();if(A9 instanceof YAHOO.widget.MenuBar){BK=A9.activeItem.getNextEnabledSibling();
+if(BK){A9.clearActiveItem();BK.cfg.setProperty(y,true);BC=BK.cfg.getProperty(O);if(BC){BC.show();BC.setInitialFocus();}else{BK.focus();}}}}AA.preventDefault(BG);this._stopMouseEventHandlers();break;case 37:if(A6){BA=A6.parent;if(BA instanceof YAHOO.widget.MenuBar){BK=BA.activeItem.getPreviousEnabledSibling();if(BK){BA.clearActiveItem();BK.cfg.setProperty(y,true);BC=BK.cfg.getProperty(O);if(BC){BC.show();BC.setInitialFocus();}else{BK.focus();}}}else{this.hide();A6.focus();}}AA.preventDefault(BG);this._stopMouseEventHandlers();break;}}if(BG.keyCode==27){if(this.cfg.getProperty(Ac)==AD){this.hide();if(this.parent){this.parent.focus();}else{BB=this._focusedElement;if(BB&amp;&amp;BB.focus){try{BB.focus();}catch(BL){}}}}else{if(this.activeItem){BC=this.activeItem.cfg.getProperty(O);if(BC&amp;&amp;BC.cfg.getProperty(Au)){BC.hide();this.activeItem.focus();}else{this.activeItem.blur();this.activeItem.cfg.setProperty(y,false);}}}AA.preventDefault(BG);}},_onKeyPress:function(A7,A6){var
  A5=A6[0];if(A5.keyCode==40||A5.keyCode==38){AA.preventDefault(A5);}},_onBlur:function(A6,A5){if(this._hasFocus){this._hasFocus=false;}},_onYChange:function(A6,A5){var A8=this.parent,BA,A7,A9;if(A8){BA=A8.parent.body.scrollTop;if(BA&gt;0){A9=(this.cfg.getProperty(R)-BA);f.setY(this.element,A9);A7=this.iframe;if(A7){f.setY(A7,A9);}this.cfg.setProperty(R,A9,true);}}},_onScrollTargetMouseOver:function(BB,BE){var BD=this._bodyScrollTimer;if(BD){BD.cancel();}this._cancelHideDelay();var A7=AA.getTarget(BB),A9=this.body,A8=this.cfg.getProperty(j),A5,A6;function BC(){var BF=A9.scrollTop;if(BF&lt;A5){A9.scrollTop=(BF+A8);this._enableScrollHeader();}else{A9.scrollTop=A5;this._bodyScrollTimer.cancel();this._disableScrollFooter();}}function BA(){var BF=A9.scrollTop;if(BF&gt;0){A9.scrollTop=(BF-A8);this._enableScrollFooter();}else{A9.scrollTop=0;this._bodyScrollTimer.cancel();this._disableScrollHeader();}}if(f.hasClass(A7,A0)){A6=BA;}else{A5=A9.scrollHeight-A9.offsetHeight;A6=BC;}this._b
 odyScrollTimer=AM.later(10,this,A6,null,true);},_onScrollTargetMouseOut:function(A7,A5){var A6=this._bodyScrollTimer;if(A6){A6.cancel();}this._cancelHideDelay();},_onInit:function(A6,A5){this.cfg.subscribeToConfigEvent(Au,this._onVisibleChange);var A7=!this.parent,A8=this.lazyLoad;if(((A7&amp;&amp;!A8)||(A7&amp;&amp;(this.cfg.getProperty(Au)||this.cfg.getProperty(Ac)==C))||(!A7&amp;&amp;!A8))&amp;&amp;this.getItemGroups().length===0){if(this.srcElement){this._initSubTree();}if(this.itemData){this.addItems(this.itemData);}}else{if(A8){this.cfg.fireQueue();}}},_onBeforeRender:function(A8,A7){var A9=this.element,BC=this._aListElements.length,A6=true,BB=0,A5,BA;if(BC&gt;0){do{A5=this._aListElements[BB];if(A5){if(A6){f.addClass(A5,AJ);A6=false;}if(!f.isAncestor(A9,A5)){this.appendToBody(A5);}BA=this._aGroupTitleElements[BB];if(BA){if(!f.isAncestor(A9,BA)){A5.parentNode.insertBefore(BA,A5);}f.addClass(A5,D);}}BB++;}while(BB&lt;BC);}},_onRender:function(A6,A5){if(this.cfg.getProper
 ty(Ac)==AD){if(!this.cfg.getProperty(Au)){this.positionOffScreen();}}},_onBeforeShow:function(A7,A6){var A9,BC,A8,BA=this.cfg.getProperty(g);if(this.lazyLoad&amp;&amp;this.getItemGroups().length===0){if(this.srcElement){this._initSubTree();}if(this.itemData){if(this.parent&amp;&amp;this.parent.parent&amp;&amp;this.parent.parent.srcElement&amp;&amp;this.parent.parent.srcElement.tagName.toUpperCase()==AH){A9=this.itemData.length;for(BC=0;BC&lt;A9;BC++){if(this.itemData[BC].tagName){this.addItem((new this.ITEM_TYPE(this.itemData[BC])));}}}else{this.addItems(this.itemData);}}A8=this.srcElement;if(A8){if(A8.tagName.toUpperCase()==AH){if(f.inDocument(A8)){this.render(A8.parentNode);}else{this.render(BA);}}else{this.render();}}else{if(this.parent){this.render(this.parent.element);}else{this.render(BA);}}}var BB=this.parent,A5;if(!BB&amp;&amp;this.cfg.getProperty(Ac)==AD){this.cfg.refireEvent(e);}if(BB){A5=BB.parent.cfg.getProperty(AO);this.cfg.setProperty(p,[BB.element,A5[0],A5[1]]
 );this.align();}},getConstrainedY:function(BH){var BS=this,BO=BS.cfg.getProperty(p),BV=BS.cfg.getProperty(AU),BR,BG={&quot;trbr&quot;:true,&quot;tlbl&quot;:true,&quot;bltl&quot;:true,&quot;brtr&quot;:true},BA=(BO&amp;&amp;BG[BO[1]+BO[2]]),BC=BS.element,BW=BC.offsetHeight,BQ=AB.VIEWPORT_OFFSET,BL=f.getViewportHeight(),BP=f.getDocumentScrollTop(),BM=(BS.cfg.getProperty(Aj)+BQ&lt;BL),BU,BD,BJ,BK,BF=false,BE,A7,BI=BP+BQ,A9=BP+BL-BW-BQ,A5=BH;var BB=function(){var BX;if((BS.cfg.getProperty(R)-BP)&gt;BJ){BX=(BJ-BW);}else{BX=(BJ+BK);}BS.cfg.setProperty(R,(BX+BP),true);return BX;};var A8=function(){if((BS.cfg.getProperty(R)-BP)&gt;BJ){return(A7-BQ);}else{return(BE-BQ);}};var BN=function(){var BX;if((BS.cfg.getProperty(R)-BP)&gt;BJ){BX=(BJ+BK);}else{BX=(BJ-BC.offsetHeight);}BS.cfg.setProperty(R,(BX+BP),true);};var A6=function(){BS._setScrollHeight(this.cfg.getProperty(AU));BS.hideEvent.unsubscribe(A6);};var BT=function(){var Ba=A8(),BX=(BS.getItems().length&gt;0),BZ,BY;if(BW&gt;Ba){BZ
 =BX?BS.cfg.getProperty(Aj):BW;if((Ba&gt;BZ)&amp;&amp;BX){BR=Ba;}else{BR=BV;}BS._setScrollHeight(BR);BS.hideEvent.subscribe(A6);BN();if(Ba&lt;BZ){if(BF){BB();}else{BB();BF=true;BY=BT();}}}else{if(BR&amp;&amp;(BR!==BV)){BS._setScrollHeight(BV);BS.hideEvent.subscribe(A6);BN();}}return BY;};if(BH&lt;BI||BH&gt;A9){if(BM){if(BS.cfg.getProperty(A4)&amp;&amp;BA){BD=BO[0];BK=BD.offsetHeight;BJ=(f.getY(BD)-BP);BE=BJ;A7=(BL-(BJ+BK));BT();A5=BS.cfg.getProperty(R);}else{if(!(BS instanceof YAHOO.widget.MenuBar)&amp;&amp;BW&gt;=BL){BU=(BL-(BQ*2));if(BU&gt;BS.cfg.getProperty(Aj)){BS._setScrollHeight(BU);BS.hideEvent.subscribe(A6);BN();A5=BS.cfg.getProperty(R);}}else{if(BH&lt;BI){A5=BI;}else{if(BH&gt;A9){A5=A9;}}}}}else{A5=BQ+BP;}}return A5;},_onHide:function(A6,A5){if(this.cfg.getProperty(Ac)===AD){this.positionOffScreen();}},_onShow:function(BD,BB){var A5=this.parent,A7,A8,BA,A6;function A9(BF){var BE;if(BF.type==Ak||(BF.type==Ae&amp;&amp;BF.keyCode==27)){BE=AA.getTarget(BF);if(BE!=A7.elem
 ent||!f.isAncestor(A7.element,BE)){A7.cfg.setProperty(Z,false);AA.removeListener(document,Ak,A9);AA.removeListener(document,Ae,A9);}}}function BC(BF,BE,BG){this.cfg.setProperty(U,u);this.hideEvent.unsubscribe(BC,BG);}if(A5){A7=A5.parent;if(!A7.cfg.getProperty(Z)&amp;&amp;(A7 instanceof YAHOO.widget.MenuBar||A7.cfg.getProperty(Ac)==C)){A7.cfg.setProperty(Z,true);
+AA.on(document,Ak,A9);AA.on(document,Ae,A9);}if((this.cfg.getProperty(&quot;x&quot;)&lt;A7.cfg.getProperty(&quot;x&quot;))&amp;&amp;(As.gecko&amp;&amp;As.gecko&lt;1.9)&amp;&amp;!this.cfg.getProperty(U)){A8=this.element;BA=A8.offsetWidth;A8.style.width=BA+AQ;A6=(BA-(A8.offsetWidth-BA))+AQ;this.cfg.setProperty(U,A6);this.hideEvent.subscribe(BC,A6);}}if(this===this.getRoot()&amp;&amp;this.cfg.getProperty(Ac)===AD){this._focusedElement=Ad;this.focus();}},_onBeforeHide:function(A7,A6){var A5=this.activeItem,A9=this.getRoot(),BA,A8;if(A5){BA=A5.cfg;BA.setProperty(y,false);A8=BA.getProperty(O);if(A8){A8.hide();}}if(As.ie&amp;&amp;this.cfg.getProperty(Ac)===AD&amp;&amp;this.parent){A9._hasFocus=this.hasFocus();}if(A9==this){A9.blur();}},_onParentMenuConfigChange:function(A6,A5,A9){var A7=A5[0][0],A8=A5[0][1];switch(A7){case AF:case w:case AX:case Av:case c:case AC:case Ay:case A2:case j:case AU:case Aj:case AE:case Ag:case A4:case Ar:A9.cfg.setProperty(A7,A8);break;case AO:if(!(this
 .parent.parent instanceof YAHOO.widget.MenuBar)){A9.cfg.setProperty(A7,A8);}break;}},_onParentMenuRender:function(A6,A5,BB){var A8=BB.parent.parent,A7=A8.cfg,A9={constraintoviewport:A7.getProperty(w),xy:[0,0],clicktohide:A7.getProperty(AC),effect:A7.getProperty(Ay),showdelay:A7.getProperty(Av),hidedelay:A7.getProperty(AX),submenuhidedelay:A7.getProperty(c),classname:A7.getProperty(A2),scrollincrement:A7.getProperty(j),maxheight:A7.getProperty(AU),minscrollheight:A7.getProperty(Aj),iframe:A7.getProperty(AF),shadow:A7.getProperty(Ag),preventcontextoverlap:A7.getProperty(A4),monitorresize:A7.getProperty(AE),keepopen:A7.getProperty(Ar)},BA;if(!(A8 instanceof YAHOO.widget.MenuBar)){A9[AO]=A7.getProperty(AO);}BB.cfg.applyConfig(A9);if(!this.lazyLoad){BA=this.parent.element;if(this.element.parentNode==BA){this.render();}else{this.render(BA);}}},_onMenuItemDestroy:function(A7,A6,A5){this._removeItemFromGroupByValue(A5.groupIndex,A5);},_onMenuItemConfigChange:function(A7,A6,A5){var A
 9=A6[0][0],BA=A6[0][1],A8;switch(A9){case y:if(BA===true){this.activeItem=A5;}break;case O:A8=A6[0][1];if(A8){this._configureSubmenu(A5);}break;}},configVisible:function(A7,A6,A8){var A5,A9;if(this.cfg.getProperty(Ac)==AD){r.superclass.configVisible.call(this,A7,A6,A8);}else{A5=A6[0];A9=f.getStyle(this.element,AW);f.setStyle(this.element,J,Au);if(A5){if(A9!=AV){this.beforeShowEvent.fire();f.setStyle(this.element,AW,AV);this.showEvent.fire();}}else{if(A9==AV){this.beforeHideEvent.fire();f.setStyle(this.element,AW,AY);this.hideEvent.fire();}}}},configPosition:function(A7,A6,BA){var A9=this.element,A8=A6[0]==C?C:z,BB=this.cfg,A5;f.setStyle(A9,Ac,A8);if(A8==C){f.setStyle(A9,AW,AV);BB.setProperty(Au,true);}else{f.setStyle(A9,J,AL);}if(A8==z){A5=BB.getProperty(AS);if(!A5||A5===0){BB.setProperty(AS,1);}}},configIframe:function(A6,A5,A7){if(this.cfg.getProperty(Ac)==AD){r.superclass.configIframe.call(this,A6,A5,A7);}},configHideDelay:function(A6,A5,A7){var A8=A5[0];this._useHideDela
 y=(A8&gt;0);},configContainer:function(A6,A5,A8){var A7=A5[0];if(AM.isString(A7)){this.cfg.setProperty(g,f.get(A7),true);}},_clearSetWidthFlag:function(){this._widthSetForScroll=false;this.cfg.unsubscribeFromConfigEvent(U,this._clearSetWidthFlag);},_subscribeScrollHandlers:function(A6,A5){var A8=this._onScrollTargetMouseOver;var A7=this._onScrollTargetMouseOut;AA.on(A6,Ai,A8,this,true);AA.on(A6,H,A7,this,true);AA.on(A5,Ai,A8,this,true);AA.on(A5,H,A7,this,true);},_unsubscribeScrollHandlers:function(A6,A5){var A8=this._onScrollTargetMouseOver;var A7=this._onScrollTargetMouseOut;AA.removeListener(A6,Ai,A8);AA.removeListener(A6,H,A7);AA.removeListener(A5,Ai,A8);AA.removeListener(A5,H,A7);},_setScrollHeight:function(BF){var BC=BF,BB=false,BG=false,A8,A9,BE,A6,A5,BD,BA,A7;if(this.getItems().length&gt;0){A8=this.element;A9=this.body;BE=this.header;A6=this.footer;A5=this.cfg.getProperty(Aj);if(BC&gt;0&amp;&amp;BC&lt;A5){BC=A5;}f.setStyle(A9,Ao,u);f.removeClass(A9,l);A9.scrollTop=0;B
 G=((As.gecko&amp;&amp;As.gecko&lt;1.9)||As.ie);if(BC&gt;0&amp;&amp;BG&amp;&amp;!this.cfg.getProperty(U)){BA=A8.offsetWidth;A8.style.width=BA+AQ;A7=(BA-(A8.offsetWidth-BA))+AQ;this.cfg.unsubscribeFromConfigEvent(U,this._clearSetWidthFlag);this.cfg.setProperty(U,A7);this._widthSetForScroll=true;this.cfg.subscribeToConfigEvent(U,this._clearSetWidthFlag);}if(BC&gt;0&amp;&amp;(!BE&amp;&amp;!A6)){this.setHeader(AK);this.setFooter(AK);BE=this.header;A6=this.footer;f.addClass(BE,T);f.addClass(A6,x);A8.insertBefore(BE,A9);A8.appendChild(A6);}BD=BC;if(BE&amp;&amp;A6){BD=(BD-(BE.offsetHeight+A6.offsetHeight));}if((BD&gt;0)&amp;&amp;(A9.offsetHeight&gt;BC)){f.addClass(A9,l);f.setStyle(A9,Ao,(BD+AQ));if(!this._hasScrollEventHandlers){this._subscribeScrollHandlers(BE,A6);this._hasScrollEventHandlers=true;}this._disableScrollHeader();this._enableScrollFooter();BB=true;}else{if(BE&amp;&amp;A6){if(this._widthSetForScroll){this._widthSetForScroll=false;this.cfg.unsubscribeFromConfigEvent(U,th
 is._clearSetWidthFlag);this.cfg.setProperty(U,u);}this._enableScrollHeader();this._enableScrollFooter();if(this._hasScrollEventHandlers){this._unsubscribeScrollHandlers(BE,A6);this._hasScrollEventHandlers=false;}A8.removeChild(BE);A8.removeChild(A6);this.header=null;this.footer=null;BB=true;}}if(BB){this.cfg.refireEvent(AF);this.cfg.refireEvent(Ag);}}},_setMaxHeight:function(A6,A5,A7){this._setScrollHeight(A7);this.renderEvent.unsubscribe(this._setMaxHeight);},configMaxHeight:function(A6,A5,A7){var A8=A5[0];if(this.lazyLoad&amp;&amp;!this.body&amp;&amp;A8&gt;0){this.renderEvent.subscribe(this._setMaxHeight,A8,this);}else{this._setScrollHeight(A8);}},configClassName:function(A7,A6,A8){var A5=A6[0];if(this._sClassName){f.removeClass(this.element,this._sClassName);}f.addClass(this.element,A5);this._sClassName=A5;},_onItemAdded:function(A6,A5){var A7=A5[0];if(A7){A7.cfg.setProperty(Ah,true);}},configDisabled:function(A7,A6,BA){var A9=A6[0],A5=this.getItems(),BB,A8;if(AM.isArray(
 A5)){BB=A5.length;if(BB&gt;0){A8=BB-1;do{A5[A8].cfg.setProperty(Ah,A9);}while(A8--);}if(A9){this.clearActiveItem(true);f.addClass(this.element,Ah);this.itemAddedEvent.subscribe(this._onItemAdded);}else{f.removeClass(this.element,Ah);this.itemAddedEvent.unsubscribe(this._onItemAdded);
+}}},_sizeShadow:function(){var A6=this.element,A5=this._shadow;if(A5&amp;&amp;A6){if(A5.style.width&amp;&amp;A5.style.height){A5.style.width=u;A5.style.height=u;}A5.style.width=(A6.offsetWidth+6)+AQ;A5.style.height=(A6.offsetHeight+1)+AQ;}},_replaceShadow:function(){this.element.appendChild(this._shadow);},_addShadowVisibleClass:function(){f.addClass(this._shadow,AG);},_removeShadowVisibleClass:function(){f.removeClass(this._shadow,AG);},_removeShadow:function(){var A5=(this._shadow&amp;&amp;this._shadow.parentNode);if(A5){A5.removeChild(this._shadow);}this.beforeShowEvent.unsubscribe(this._addShadowVisibleClass);this.beforeHideEvent.unsubscribe(this._removeShadowVisibleClass);this.cfg.unsubscribeFromConfigEvent(U,this._sizeShadow);this.cfg.unsubscribeFromConfigEvent(Ao,this._sizeShadow);this.cfg.unsubscribeFromConfigEvent(AU,this._sizeShadow);this.cfg.unsubscribeFromConfigEvent(AU,this._replaceShadow);this.changeContentEvent.unsubscribe(this._sizeShadow);Aw.textResizeEvent.
 unsubscribe(this._sizeShadow);},_createShadow:function(){var A6=this._shadow,A5;if(!A6){A5=this.element;if(!Ap){Ap=document.createElement(K);Ap.className=m;}A6=Ap.cloneNode(false);A5.appendChild(A6);this._shadow=A6;this.beforeShowEvent.subscribe(this._addShadowVisibleClass);this.beforeHideEvent.subscribe(this._removeShadowVisibleClass);if(As.ie){AM.later(0,this,function(){this._sizeShadow();this.syncIframe();});this.cfg.subscribeToConfigEvent(U,this._sizeShadow);this.cfg.subscribeToConfigEvent(Ao,this._sizeShadow);this.cfg.subscribeToConfigEvent(AU,this._sizeShadow);this.changeContentEvent.subscribe(this._sizeShadow);Aw.textResizeEvent.subscribe(this._sizeShadow,this,true);this.destroyEvent.subscribe(function(){Aw.textResizeEvent.unsubscribe(this._sizeShadow,this);});}this.cfg.subscribeToConfigEvent(AU,this._replaceShadow);}},_shadowBeforeShow:function(){if(this._shadow){this._replaceShadow();if(As.ie){this._sizeShadow();}}else{this._createShadow();}this.beforeShowEvent.unsu
 bscribe(this._shadowBeforeShow);},configShadow:function(A6,A5,A7){var A8=A5[0];if(A8&amp;&amp;this.cfg.getProperty(Ac)==AD){if(this.cfg.getProperty(Au)){if(this._shadow){this._replaceShadow();if(As.ie){this._sizeShadow();}}else{this._createShadow();}}else{this.beforeShowEvent.subscribe(this._shadowBeforeShow);}}else{if(!A8){this.beforeShowEvent.unsubscribe(this._shadowBeforeShow);this._removeShadow();}}},initEvents:function(){r.superclass.initEvents.call(this);var A6=Ab.length-1,A7,A5;do{A7=Ab[A6];A5=this.createEvent(A7[1]);A5.signature=F.LIST;this[A7[0]]=A5;}while(A6--);},positionOffScreen:function(){var A6=this.iframe,A7=this.element,A5=this.OFF_SCREEN_POSITION;A7.style.top=u;A7.style.left=u;if(A6){A6.style.top=A5;A6.style.left=A5;}},getRoot:function(){var A7=this.parent,A6,A5;if(A7){A6=A7.parent;A5=A6?A6.getRoot():this;}else{A5=this;}return A5;},toString:function(){var A6=Aq,A5=this.id;if(A5){A6+=(A1+A5);}return A6;},setItemGroupTitle:function(BA,A9){var A8,A7,A6,A5;if(AM
 .isString(BA)&amp;&amp;BA.length&gt;0){A8=AM.isNumber(A9)?A9:0;A7=this._aGroupTitleElements[A8];if(A7){A7.innerHTML=BA;}else{A7=document.createElement(this.GROUP_TITLE_TAG_NAME);A7.innerHTML=BA;this._aGroupTitleElements[A8]=A7;}A6=this._aGroupTitleElements.length-1;do{if(this._aGroupTitleElements[A6]){f.removeClass(this._aGroupTitleElements[A6],AJ);A5=A6;}}while(A6--);if(A5!==null){f.addClass(this._aGroupTitleElements[A5],AJ);}this.changeContentEvent.fire();}},addItem:function(A5,A6){return this._addItemToGroup(A6,A5);},addItems:function(A9,A8){var BB,A5,BA,A6,A7;if(AM.isArray(A9)){BB=A9.length;A5=[];for(A6=0;A6&lt;BB;A6++){BA=A9[A6];if(BA){if(AM.isArray(BA)){A5[A5.length]=this.addItems(BA,A6);}else{A5[A5.length]=this._addItemToGroup(A8,BA);}}}if(A5.length){A7=A5;}}return A7;},insertItem:function(A5,A6,A7){return this._addItemToGroup(A7,A5,A6);},removeItem:function(A5,A7){var A8,A6;if(!AM.isUndefined(A5)){if(A5 instanceof YAHOO.widget.MenuItem){A8=this._removeItemFromGroupBy
 Value(A7,A5);}else{if(AM.isNumber(A5)){A8=this._removeItemFromGroupByIndex(A7,A5);}}if(A8){A8.destroy();A6=A8;}}return A6;},getItems:function(){var A8=this._aItemGroups,A6,A7,A5=[];if(AM.isArray(A8)){A6=A8.length;A7=((A6==1)?A8[0]:(Array.prototype.concat.apply(A5,A8)));}return A7;},getItemGroups:function(){return this._aItemGroups;},getItem:function(A6,A7){var A8,A5;if(AM.isNumber(A6)){A8=this._getItemGroup(A7);if(A8){A5=A8[A6];}}return A5;},getSubmenus:function(){var A6=this.getItems(),BA=A6.length,A5,A7,A9,A8;if(BA&gt;0){A5=[];for(A8=0;A8&lt;BA;A8++){A9=A6[A8];if(A9){A7=A9.cfg.getProperty(O);if(A7){A5[A5.length]=A7;}}}}return A5;},clearContent:function(){var A9=this.getItems(),A6=A9.length,A7=this.element,A8=this.body,BD=this.header,A5=this.footer,BC,BB,BA;if(A6&gt;0){BA=A6-1;do{BC=A9[BA];if(BC){BB=BC.cfg.getProperty(O);if(BB){this.cfg.configChangedEvent.unsubscribe(this._onParentMenuConfigChange,BB);this.renderEvent.unsubscribe(this._onParentMenuRender,BB);}this.removeIte
 m(BC,BC.groupIndex);}}while(BA--);}if(BD){AA.purgeElement(BD);A7.removeChild(BD);}if(A5){AA.purgeElement(A5);A7.removeChild(A5);}if(A8){AA.purgeElement(A8);A8.innerHTML=u;}this.activeItem=null;this._aItemGroups=[];this._aListElements=[];this._aGroupTitleElements=[];this.cfg.setProperty(U,null);},destroy:function(A5){this.clearContent();this._aItemGroups=null;this._aListElements=null;this._aGroupTitleElements=null;r.superclass.destroy.call(this,A5);},setInitialFocus:function(){var A5=this._getFirstEnabledItem();if(A5){A5.focus();}},setInitialSelection:function(){var A5=this._getFirstEnabledItem();if(A5){A5.cfg.setProperty(y,true);}},clearActiveItem:function(A7){if(this.cfg.getProperty(Av)&gt;0){this._cancelShowDelay();}var A5=this.activeItem,A8,A6;if(A5){A8=A5.cfg;if(A7){A5.blur();this.getRoot()._hasFocus=true;}A8.setProperty(y,false);A6=A8.getProperty(O);if(A6){A6.hide();}this.activeItem=null;}},focus:function(){if(!this.hasFocus()){this.setInitialFocus();}},blur:function(){
 var A5;if(this.hasFocus()){A5=A3.getFocusedMenuItem();if(A5){A5.blur();}}},hasFocus:function(){return(A3.getFocusedMenu()==this.getRoot());
+},_doItemSubmenuSubscribe:function(A6,A5,A8){var A9=A5[0],A7=A9.cfg.getProperty(O);if(A7){A7.subscribe.apply(A7,A8);}},_doSubmenuSubscribe:function(A6,A5,A8){var A7=this.cfg.getProperty(O);if(A7){A7.subscribe.apply(A7,A8);}},subscribe:function(){r.superclass.subscribe.apply(this,arguments);r.superclass.subscribe.call(this,AR,this._doItemSubmenuSubscribe,arguments);var A5=this.getItems(),A9,A8,A6,A7;if(A5){A9=A5.length;if(A9&gt;0){A7=A9-1;do{A8=A5[A7];A6=A8.cfg.getProperty(O);if(A6){A6.subscribe.apply(A6,arguments);}else{A8.cfg.subscribeToConfigEvent(O,this._doSubmenuSubscribe,arguments);}}while(A7--);}}},unsubscribe:function(){r.superclass.unsubscribe.apply(this,arguments);r.superclass.unsubscribe.call(this,AR,this._doItemSubmenuSubscribe,arguments);var A5=this.getItems(),A9,A8,A6,A7;if(A5){A9=A5.length;if(A9&gt;0){A7=A9-1;do{A8=A5[A7];A6=A8.cfg.getProperty(O);if(A6){A6.unsubscribe.apply(A6,arguments);}else{A8.cfg.unsubscribeFromConfigEvent(O,this._doSubmenuSubscribe,argumen
 ts);}}while(A7--);}}},initDefaultConfig:function(){r.superclass.initDefaultConfig.call(this);var A5=this.cfg;A5.addProperty(AZ.key,{handler:this.configVisible,value:AZ.value,validator:AZ.validator});A5.addProperty(AP.key,{handler:this.configConstrainToViewport,value:AP.value,validator:AP.validator,supercedes:AP.supercedes});A5.addProperty(AI.key,{value:AI.value,validator:AI.validator,supercedes:AI.supercedes});A5.addProperty(S.key,{handler:this.configPosition,value:S.value,validator:S.validator,supercedes:S.supercedes});A5.addProperty(A.key,{value:A.value,suppressEvent:A.suppressEvent});A5.addProperty(t.key,{value:t.value,validator:t.validator,suppressEvent:t.suppressEvent});A5.addProperty(Y.key,{value:Y.value,validator:Y.validator,suppressEvent:Y.suppressEvent});A5.addProperty(q.key,{handler:this.configHideDelay,value:q.value,validator:q.validator,suppressEvent:q.suppressEvent});A5.addProperty(v.key,{value:v.value,validator:v.validator,suppressEvent:v.suppressEvent});A5.add
 Property(o.key,{value:o.value,validator:o.validator,suppressEvent:o.suppressEvent});A5.addProperty(AN.key,{handler:this.configContainer,value:document.body,suppressEvent:AN.suppressEvent});A5.addProperty(Af.key,{value:Af.value,validator:Af.validator,supercedes:Af.supercedes,suppressEvent:Af.suppressEvent});A5.addProperty(N.key,{value:N.value,validator:N.validator,supercedes:N.supercedes,suppressEvent:N.suppressEvent});A5.addProperty(X.key,{handler:this.configMaxHeight,value:X.value,validator:X.validator,suppressEvent:X.suppressEvent,supercedes:X.supercedes});A5.addProperty(W.key,{handler:this.configClassName,value:W.value,validator:W.validator,supercedes:W.supercedes});A5.addProperty(a.key,{handler:this.configDisabled,value:a.value,validator:a.validator,suppressEvent:a.suppressEvent});A5.addProperty(I.key,{handler:this.configShadow,value:I.value,validator:I.validator});A5.addProperty(Al.key,{value:Al.value,validator:Al.validator});}});})();(function(){YAHOO.widget.MenuItem=f
 unction(AS,AR){if(AS){if(AR){this.parent=AR.parent;this.value=AR.value;this.id=AR.id;}this.init(AS,AR);}};var x=YAHOO.util.Dom,j=YAHOO.widget.Module,AB=YAHOO.widget.Menu,c=YAHOO.widget.MenuItem,AK=YAHOO.util.CustomEvent,k=YAHOO.env.ua,AQ=YAHOO.lang,AL=&quot;text&quot;,O=&quot;#&quot;,Q=&quot;-&quot;,L=&quot;helptext&quot;,n=&quot;url&quot;,AH=&quot;target&quot;,A=&quot;emphasis&quot;,N=&quot;strongemphasis&quot;,b=&quot;checked&quot;,w=&quot;submenu&quot;,H=&quot;disabled&quot;,B=&quot;selected&quot;,P=&quot;hassubmenu&quot;,U=&quot;checked-disabled&quot;,AI=&quot;hassubmenu-disabled&quot;,AD=&quot;hassubmenu-selected&quot;,T=&quot;checked-selected&quot;,q=&quot;onclick&quot;,J=&quot;classname&quot;,AJ=&quot;&quot;,i=&quot;OPTION&quot;,v=&quot;OPTGROUP&quot;,K=&quot;LI&quot;,AE=&quot;href&quot;,r=&quot;SELECT&quot;,X=&quot;DIV&quot;,AN='&lt;em class=&quot;helptext&quot;&gt;',a=&quot;&lt;em&gt;&quot;,I=&quot;&lt;/em&gt;&quot;,W=&quot;&lt;strong&gt;&quot;,y=&quot;&lt;/strong&g
 t;&quot;,Y=&quot;preventcontextoverlap&quot;,h=&quot;obj&quot;,AG=&quot;scope&quot;,t=&quot;none&quot;,V=&quot;visible&quot;,E=&quot; &quot;,m=&quot;MenuItem&quot;,AA=&quot;click&quot;,D=&quot;show&quot;,M=&quot;hide&quot;,S=&quot;li&quot;,AF='&lt;a href=&quot;#&quot;&gt;&lt;/a&gt;',p=[[&quot;mouseOverEvent&quot;,&quot;mouseover&quot;],[&quot;mouseOutEvent&quot;,&quot;mouseout&quot;],[&quot;mouseDownEvent&quot;,&quot;mousedown&quot;],[&quot;mouseUpEvent&quot;,&quot;mouseup&quot;],[&quot;clickEvent&quot;,AA],[&quot;keyPressEvent&quot;,&quot;keypress&quot;],[&quot;keyDownEvent&quot;,&quot;keydown&quot;],[&quot;keyUpEvent&quot;,&quot;keyup&quot;],[&quot;focusEvent&quot;,&quot;focus&quot;],[&quot;blurEvent&quot;,&quot;blur&quot;],[&quot;destroyEvent&quot;,&quot;destroy&quot;]],o={key:AL,value:AJ,validator:AQ.isString,suppressEvent:true},s={key:L,supercedes:[AL],suppressEvent:true},G={key:n,value:O,suppressEvent:true},AO={key:AH,suppressEvent:true},AP={key:A,value:false,validator
 :AQ.isBoolean,suppressEvent:true,supercedes:[AL]},d={key:N,value:false,validator:AQ.isBoolean,suppressEvent:true,supercedes:[AL]},l={key:b,value:false,validator:AQ.isBoolean,suppressEvent:true,supercedes:[H,B]},F={key:w,suppressEvent:true,supercedes:[H,B]},AM={key:H,value:false,validator:AQ.isBoolean,suppressEvent:true,supercedes:[AL,B]},f={key:B,value:false,validator:AQ.isBoolean,suppressEvent:true},u={key:q,suppressEvent:true},AC={key:J,value:null,validator:AQ.isString,suppressEvent:true},z={key:&quot;keylistener&quot;,value:null,suppressEvent:true},C=null,e={};var Z=function(AU,AT){var AR=e[AU];if(!AR){e[AU]={};AR=e[AU];}var AS=AR[AT];if(!AS){AS=AU+Q+AT;AR[AT]=AS;}return AS;};var g=function(AR){x.addClass(this.element,Z(this.CSS_CLASS_NAME,AR));x.addClass(this._oAnchor,Z(this.CSS_LABEL_CLASS_NAME,AR));};var R=function(AR){x.removeClass(this.element,Z(this.CSS_CLASS_NAME,AR));x.removeClass(this._oAnchor,Z(this.CSS_LABEL_CLASS_NAME,AR));};c.prototype={CSS_CLASS_NAME:&quot;y
 uimenuitem&quot;,CSS_LABEL_CLASS_NAME:&quot;yuimenuitemlabel&quot;,SUBMENU_TYPE:null,_oAnchor:null,_oHelpTextEM:null,_oSubmenu:null,_oOnclickAttributeValue:null,_sClassName:null,constructor:c,index:null,groupIndex:null,parent:null,element:null,srcElement:null,value:null,browser:j.prototype.browser,id:null,init:function(AR,Ab){if(!this.SUBMENU_TYPE){this.SUBMENU_TYPE=AB;}this.cfg=new YAHOO.util.Config(this);this.initDefaultConfig();var AX=this.cfg,AY=O,AT,Aa,AZ,AS,AV,AU,AW;if(AQ.isString(AR)){this._createRootNodeStructure();AX.queueProperty(AL,AR);}else{if(AR&amp;&amp;AR.tagName){switch(AR.tagName.toUpperCase()){case i:this._createRootNodeStructure();AX.queueProperty(AL,AR.text);AX.queueProperty(H,AR.disabled);this.value=AR.value;this.srcElement=AR;break;case v:this._createRootNodeStructure();
+AX.queueProperty(AL,AR.label);AX.queueProperty(H,AR.disabled);this.srcElement=AR;this._initSubTree();break;case K:AZ=x.getFirstChild(AR);if(AZ){AY=AZ.getAttribute(AE,2);AS=AZ.getAttribute(AH);AV=AZ.innerHTML;}this.srcElement=AR;this.element=AR;this._oAnchor=AZ;AX.setProperty(AL,AV,true);AX.setProperty(n,AY,true);AX.setProperty(AH,AS,true);this._initSubTree();break;}}}if(this.element){AU=(this.srcElement||this.element).id;if(!AU){AU=this.id||x.generateId();this.element.id=AU;}this.id=AU;x.addClass(this.element,this.CSS_CLASS_NAME);x.addClass(this._oAnchor,this.CSS_LABEL_CLASS_NAME);AW=p.length-1;do{Aa=p[AW];AT=this.createEvent(Aa[1]);AT.signature=AK.LIST;this[Aa[0]]=AT;}while(AW--);if(Ab){AX.applyConfig(Ab);}AX.fireQueue();}},_createRootNodeStructure:function(){var AR,AS;if(!C){C=document.createElement(S);C.innerHTML=AF;}AR=C.cloneNode(true);AR.className=this.CSS_CLASS_NAME;AS=AR.firstChild;AS.className=this.CSS_LABEL_CLASS_NAME;this.element=AR;this._oAnchor=AS;},_initSubTree
 :function(){var AX=this.srcElement,AT=this.cfg,AV,AU,AS,AR,AW;if(AX.childNodes.length&gt;0){if(this.parent.lazyLoad&amp;&amp;this.parent.srcElement&amp;&amp;this.parent.srcElement.tagName.toUpperCase()==r){AT.setProperty(w,{id:x.generateId(),itemdata:AX.childNodes});}else{AV=AX.firstChild;AU=[];do{if(AV&amp;&amp;AV.tagName){switch(AV.tagName.toUpperCase()){case X:AT.setProperty(w,AV);break;case i:AU[AU.length]=AV;break;}}}while((AV=AV.nextSibling));AS=AU.length;if(AS&gt;0){AR=new this.SUBMENU_TYPE(x.generateId());AT.setProperty(w,AR);for(AW=0;AW&lt;AS;AW++){AR.addItem((new AR.ITEM_TYPE(AU[AW])));}}}}},configText:function(Aa,AT,AV){var AS=AT[0],AU=this.cfg,AY=this._oAnchor,AR=AU.getProperty(L),AZ=AJ,AW=AJ,AX=AJ;if(AS){if(AR){AZ=AN+AR+I;}if(AU.getProperty(A)){AW=a;AX=I;}if(AU.getProperty(N)){AW=W;AX=y;}AY.innerHTML=(AW+AS+AX+AZ);}},configHelpText:function(AT,AS,AR){this.cfg.refireEvent(AL);},configURL:function(AT,AS,AR){var AV=AS[0];if(!AV){AV=O;}var AU=this._oAnchor;if(k.oper
 a){AU.removeAttribute(AE);}AU.setAttribute(AE,AV);},configTarget:function(AU,AT,AS){var AR=AT[0],AV=this._oAnchor;if(AR&amp;&amp;AR.length&gt;0){AV.setAttribute(AH,AR);}else{AV.removeAttribute(AH);}},configEmphasis:function(AT,AS,AR){var AV=AS[0],AU=this.cfg;if(AV&amp;&amp;AU.getProperty(N)){AU.setProperty(N,false);}AU.refireEvent(AL);},configStrongEmphasis:function(AU,AT,AS){var AR=AT[0],AV=this.cfg;if(AR&amp;&amp;AV.getProperty(A)){AV.setProperty(A,false);}AV.refireEvent(AL);},configChecked:function(AT,AS,AR){var AV=AS[0],AU=this.cfg;if(AV){g.call(this,b);}else{R.call(this,b);}AU.refireEvent(AL);if(AU.getProperty(H)){AU.refireEvent(H);}if(AU.getProperty(B)){AU.refireEvent(B);}},configDisabled:function(AT,AS,AR){var AV=AS[0],AW=this.cfg,AU=AW.getProperty(w),AX=AW.getProperty(b);if(AV){if(AW.getProperty(B)){AW.setProperty(B,false);}g.call(this,H);if(AU){g.call(this,AI);}if(AX){g.call(this,U);}}else{R.call(this,H);if(AU){R.call(this,AI);}if(AX){R.call(this,U);}}},configSelect
 ed:function(AT,AS,AR){var AX=this.cfg,AW=this._oAnchor,AV=AS[0],AY=AX.getProperty(b),AU=AX.getProperty(w);if(k.opera){AW.blur();}if(AV&amp;&amp;!AX.getProperty(H)){g.call(this,B);if(AU){g.call(this,AD);}if(AY){g.call(this,T);}}else{R.call(this,B);if(AU){R.call(this,AD);}if(AY){R.call(this,T);}}if(this.hasFocus()&amp;&amp;k.opera){AW.focus();}},_onSubmenuBeforeHide:function(AU,AT){var AV=this.parent,AR;function AS(){AV._oAnchor.blur();AR.beforeHideEvent.unsubscribe(AS);}if(AV.hasFocus()){AR=AV.parent;AR.beforeHideEvent.subscribe(AS);}},configSubmenu:function(AY,AT,AW){var AV=AT[0],AU=this.cfg,AS=this.parent&amp;&amp;this.parent.lazyLoad,AX,AZ,AR;if(AV){if(AV instanceof AB){AX=AV;AX.parent=this;AX.lazyLoad=AS;}else{if(AQ.isObject(AV)&amp;&amp;AV.id&amp;&amp;!AV.nodeType){AZ=AV.id;AR=AV;AR.lazyload=AS;AR.parent=this;AX=new this.SUBMENU_TYPE(AZ,AR);AU.setProperty(w,AX,true);}else{AX=new this.SUBMENU_TYPE(AV,{lazyload:AS,parent:this});AU.setProperty(w,AX,true);}}if(AX){AX.cfg.set
 Property(Y,true);g.call(this,P);if(AU.getProperty(n)===O){AU.setProperty(n,(O+AX.id));}this._oSubmenu=AX;if(k.opera){AX.beforeHideEvent.subscribe(this._onSubmenuBeforeHide);}}}else{R.call(this,P);if(this._oSubmenu){this._oSubmenu.destroy();}}if(AU.getProperty(H)){AU.refireEvent(H);}if(AU.getProperty(B)){AU.refireEvent(B);}},configOnClick:function(AT,AS,AR){var AU=AS[0];if(this._oOnclickAttributeValue&amp;&amp;(this._oOnclickAttributeValue!=AU)){this.clickEvent.unsubscribe(this._oOnclickAttributeValue.fn,this._oOnclickAttributeValue.obj);this._oOnclickAttributeValue=null;}if(!this._oOnclickAttributeValue&amp;&amp;AQ.isObject(AU)&amp;&amp;AQ.isFunction(AU.fn)){this.clickEvent.subscribe(AU.fn,((h in AU)?AU.obj:this),((AG in AU)?AU.scope:null));this._oOnclickAttributeValue=AU;}},configClassName:function(AU,AT,AS){var AR=AT[0];if(this._sClassName){x.removeClass(this.element,this._sClassName);}x.addClass(this.element,AR);this._sClassName=AR;},_dispatchClickEvent:function(){var AS=
 this,AR;if(!AS.cfg.getProperty(H)){AR=x.getFirstChild(AS.element);this._dispatchDOMClick(AR);}},_dispatchDOMClick:function(AS){var AR;if(k.ie&amp;&amp;k.ie&lt;9){AS.fireEvent(q);}else{if((k.gecko&amp;&amp;k.gecko&gt;=1.9)||k.opera||k.webkit){AR=document.createEvent(&quot;HTMLEvents&quot;);AR.initEvent(AA,true,true);}else{AR=document.createEvent(&quot;MouseEvents&quot;);AR.initMouseEvent(AA,true,true,window,0,0,0,0,0,false,false,false,false,0,null);}AS.dispatchEvent(AR);}},_createKeyListener:function(AU,AT,AW){var AV=this,AS=AV.parent;var AR=new YAHOO.util.KeyListener(AS.element.ownerDocument,AW,{fn:AV._dispatchClickEvent,scope:AV,correctScope:true});if(AS.cfg.getProperty(V)){AR.enable();}AS.subscribe(D,AR.enable,null,AR);AS.subscribe(M,AR.disable,null,AR);AV._keyListener=AR;AS.unsubscribe(D,AV._createKeyListener,AW);},configKeyListener:function(AT,AS){var AV=AS[0],AU=this,AR=AU.parent;if(AU._keyData){AR.unsubscribe(D,AU._createKeyListener,AU._keyData);AU._keyData=null;}if(AU
 ._keyListener){AR.unsubscribe(D,AU._keyListener.enable);AR.unsubscribe(M,AU._keyListener.disable);AU._keyListener.disable();AU._keyListener=null;}if(AV){AU._keyData=AV;AR.subscribe(D,AU._createKeyListener,AV,AU);}},initDefaultConfig:function(){var AR=this.cfg;
+AR.addProperty(o.key,{handler:this.configText,value:o.value,validator:o.validator,suppressEvent:o.suppressEvent});AR.addProperty(s.key,{handler:this.configHelpText,supercedes:s.supercedes,suppressEvent:s.suppressEvent});AR.addProperty(G.key,{handler:this.configURL,value:G.value,suppressEvent:G.suppressEvent});AR.addProperty(AO.key,{handler:this.configTarget,suppressEvent:AO.suppressEvent});AR.addProperty(AP.key,{handler:this.configEmphasis,value:AP.value,validator:AP.validator,suppressEvent:AP.suppressEvent,supercedes:AP.supercedes});AR.addProperty(d.key,{handler:this.configStrongEmphasis,value:d.value,validator:d.validator,suppressEvent:d.suppressEvent,supercedes:d.supercedes});AR.addProperty(l.key,{handler:this.configChecked,value:l.value,validator:l.validator,suppressEvent:l.suppressEvent,supercedes:l.supercedes});AR.addProperty(AM.key,{handler:this.configDisabled,value:AM.value,validator:AM.validator,suppressEvent:AM.suppressEvent});AR.addProperty(f.key,{handler:this.con
 figSelected,value:f.value,validator:f.validator,suppressEvent:f.suppressEvent});AR.addProperty(F.key,{handler:this.configSubmenu,supercedes:F.supercedes,suppressEvent:F.suppressEvent});AR.addProperty(u.key,{handler:this.configOnClick,suppressEvent:u.suppressEvent});AR.addProperty(AC.key,{handler:this.configClassName,value:AC.value,validator:AC.validator,suppressEvent:AC.suppressEvent});AR.addProperty(z.key,{handler:this.configKeyListener,value:z.value,suppressEvent:z.suppressEvent});},getNextSibling:function(){var AR=function(AX){return(AX.nodeName.toLowerCase()===&quot;ul&quot;);},AV=this.element,AU=x.getNextSibling(AV),AT,AS,AW;if(!AU){AT=AV.parentNode;AS=x.getNextSiblingBy(AT,AR);if(AS){AW=AS;}else{AW=x.getFirstChildBy(AT.parentNode,AR);}AU=x.getFirstChild(AW);}return YAHOO.widget.MenuManager.getMenuItem(AU.id);},getNextEnabledSibling:function(){var AR=this.getNextSibling();return(AR.cfg.getProperty(H)||AR.element.style.display==t)?AR.getNextEnabledSibling():AR;},getPrevi
 ousSibling:function(){var AR=function(AX){return(AX.nodeName.toLowerCase()===&quot;ul&quot;);},AV=this.element,AU=x.getPreviousSibling(AV),AT,AS,AW;if(!AU){AT=AV.parentNode;AS=x.getPreviousSiblingBy(AT,AR);if(AS){AW=AS;}else{AW=x.getLastChildBy(AT.parentNode,AR);}AU=x.getLastChild(AW);}return YAHOO.widget.MenuManager.getMenuItem(AU.id);},getPreviousEnabledSibling:function(){var AR=this.getPreviousSibling();return(AR.cfg.getProperty(H)||AR.element.style.display==t)?AR.getPreviousEnabledSibling():AR;},focus:function(){var AU=this.parent,AT=this._oAnchor,AR=AU.activeItem;function AS(){try{if(!(k.ie&amp;&amp;!document.hasFocus())){if(AR){AR.blurEvent.fire();}AT.focus();this.focusEvent.fire();}}catch(AV){}}if(!this.cfg.getProperty(H)&amp;&amp;AU&amp;&amp;AU.cfg.getProperty(V)&amp;&amp;this.element.style.display!=t){AQ.later(0,this,AS);}},blur:function(){var AR=this.parent;if(!this.cfg.getProperty(H)&amp;&amp;AR&amp;&amp;AR.cfg.getProperty(V)){AQ.later(0,this,function(){try{this._
 oAnchor.blur();this.blurEvent.fire();}catch(AS){}},0);}},hasFocus:function(){return(YAHOO.widget.MenuManager.getFocusedMenuItem()==this);},destroy:function(){var AT=this.element,AS,AR,AV,AU;if(AT){AS=this.cfg.getProperty(w);if(AS){AS.destroy();}AR=AT.parentNode;if(AR){AR.removeChild(AT);this.destroyEvent.fire();}AU=p.length-1;do{AV=p[AU];this[AV[0]].unsubscribeAll();}while(AU--);this.cfg.configChangedEvent.unsubscribeAll();}},toString:function(){var AS=m,AR=this.id;if(AR){AS+=(E+AR);}return AS;}};AQ.augmentProto(c,YAHOO.util.EventProvider);})();(function(){var B=&quot;xy&quot;,C=&quot;mousedown&quot;,F=&quot;ContextMenu&quot;,J=&quot; &quot;;YAHOO.widget.ContextMenu=function(L,K){YAHOO.widget.ContextMenu.superclass.constructor.call(this,L,K);};var I=YAHOO.util.Event,E=YAHOO.env.ua,G=YAHOO.widget.ContextMenu,A={&quot;TRIGGER_CONTEXT_MENU&quot;:&quot;triggerContextMenu&quot;,&quot;CONTEXT_MENU&quot;:(E.opera?C:&quot;contextmenu&quot;),&quot;CLICK&quot;:&quot;click&quot;},H={ke
 y:&quot;trigger&quot;,suppressEvent:true};function D(L,K,M){this.cfg.setProperty(B,M);this.beforeShowEvent.unsubscribe(D,M);}YAHOO.lang.extend(G,YAHOO.widget.Menu,{_oTrigger:null,_bCancelled:false,contextEventTarget:null,triggerContextMenuEvent:null,init:function(L,K){G.superclass.init.call(this,L);this.beforeInitEvent.fire(G);if(K){this.cfg.applyConfig(K,true);}this.initEvent.fire(G);},initEvents:function(){G.superclass.initEvents.call(this);this.triggerContextMenuEvent=this.createEvent(A.TRIGGER_CONTEXT_MENU);this.triggerContextMenuEvent.signature=YAHOO.util.CustomEvent.LIST;},cancel:function(){this._bCancelled=true;},_removeEventHandlers:function(){var K=this._oTrigger;if(K){I.removeListener(K,A.CONTEXT_MENU,this._onTriggerContextMenu);if(E.opera){I.removeListener(K,A.CLICK,this._onTriggerClick);}}},_onTriggerClick:function(L,K){if(L.ctrlKey){I.stopEvent(L);}},_onTriggerContextMenu:function(M,K){var L;if(!(M.type==C&amp;&amp;!M.ctrlKey)){this.contextEventTarget=I.getTarge
 t(M);this.triggerContextMenuEvent.fire(M);if(!this._bCancelled){I.stopEvent(M);YAHOO.widget.MenuManager.hideVisible();L=I.getXY(M);if(!YAHOO.util.Dom.inDocument(this.element)){this.beforeShowEvent.subscribe(D,L);}else{this.cfg.setProperty(B,L);}this.show();}this._bCancelled=false;}},toString:function(){var L=F,K=this.id;if(K){L+=(J+K);}return L;},initDefaultConfig:function(){G.superclass.initDefaultConfig.call(this);this.cfg.addProperty(H.key,{handler:this.configTrigger,suppressEvent:H.suppressEvent});},destroy:function(K){this._removeEventHandlers();G.superclass.destroy.call(this,K);},configTrigger:function(L,K,N){var M=K[0];if(M){if(this._oTrigger){this._removeEventHandlers();}this._oTrigger=M;I.on(M,A.CONTEXT_MENU,this._onTriggerContextMenu,this,true);if(E.opera){I.on(M,A.CLICK,this._onTriggerClick,this,true);}}else{this._removeEventHandlers();}}});}());YAHOO.widget.ContextMenuItem=YAHOO.widget.MenuItem;(function(){var D=YAHOO.lang,N=&quot;static&quot;,M=&quot;dynamic,&qu
 ot;+N,A=&quot;disabled&quot;,F=&quot;selected&quot;,B=&quot;autosubmenudisplay&quot;,G=&quot;submenu&quot;,C=&quot;visible&quot;,Q=&quot; &quot;,H=&quot;submenutoggleregion&quot;,P=&quot;MenuBar&quot;;YAHOO.widget.MenuBar=function(T,S){YAHOO.widget.MenuBar.superclass.constructor.call(this,T,S);};function O(T){var S=false;if(D.isString(T)){S=(M.indexOf((T.toLowerCase()))!=-1);
+}return S;}var R=YAHOO.util.Event,L=YAHOO.widget.MenuBar,K={key:&quot;position&quot;,value:N,validator:O,supercedes:[C]},E={key:&quot;submenualignment&quot;,value:[&quot;tl&quot;,&quot;bl&quot;]},J={key:B,value:false,validator:D.isBoolean,suppressEvent:true},I={key:H,value:false,validator:D.isBoolean};D.extend(L,YAHOO.widget.Menu,{init:function(T,S){if(!this.ITEM_TYPE){this.ITEM_TYPE=YAHOO.widget.MenuBarItem;}L.superclass.init.call(this,T);this.beforeInitEvent.fire(L);if(S){this.cfg.applyConfig(S,true);}this.initEvent.fire(L);},CSS_CLASS_NAME:&quot;yuimenubar&quot;,SUBMENU_TOGGLE_REGION_WIDTH:20,_onKeyDown:function(U,T,Y){var S=T[0],Z=T[1],W,X,V;if(Z&amp;&amp;!Z.cfg.getProperty(A)){X=Z.cfg;switch(S.keyCode){case 37:case 39:if(Z==this.activeItem&amp;&amp;!X.getProperty(F)){X.setProperty(F,true);}else{V=(S.keyCode==37)?Z.getPreviousEnabledSibling():Z.getNextEnabledSibling();if(V){this.clearActiveItem();V.cfg.setProperty(F,true);W=V.cfg.getProperty(G);if(W){W.show();W.setInitia
 lFocus();}else{V.focus();}}}R.preventDefault(S);break;case 40:if(this.activeItem!=Z){this.clearActiveItem();X.setProperty(F,true);Z.focus();}W=X.getProperty(G);if(W){if(W.cfg.getProperty(C)){W.setInitialSelection();W.setInitialFocus();}else{W.show();W.setInitialFocus();}}R.preventDefault(S);break;}}if(S.keyCode==27&amp;&amp;this.activeItem){W=this.activeItem.cfg.getProperty(G);if(W&amp;&amp;W.cfg.getProperty(C)){W.hide();this.activeItem.focus();}else{this.activeItem.cfg.setProperty(F,false);this.activeItem.blur();}R.preventDefault(S);}},_onClick:function(e,Y,b){L.superclass._onClick.call(this,e,Y,b);var d=Y[1],T=true,S,f,U,W,Z,a,c,V;var X=function(){if(a.cfg.getProperty(C)){a.hide();}else{a.show();}};if(d&amp;&amp;!d.cfg.getProperty(A)){f=Y[0];U=R.getTarget(f);W=this.activeItem;Z=this.cfg;if(W&amp;&amp;W!=d){this.clearActiveItem();}d.cfg.setProperty(F,true);a=d.cfg.getProperty(G);if(a){S=d.element;c=YAHOO.util.Dom.getX(S);V=c+(S.offsetWidth-this.SUBMENU_TOGGLE_REGION_WIDTH);
 if(Z.getProperty(H)){if(R.getPageX(f)&gt;V){X();R.preventDefault(f);T=false;}}else{X();}}}return T;},configSubmenuToggle:function(U,T){var S=T[0];if(S){this.cfg.setProperty(B,false);}},toString:function(){var T=P,S=this.id;if(S){T+=(Q+S);}return T;},initDefaultConfig:function(){L.superclass.initDefaultConfig.call(this);var S=this.cfg;S.addProperty(K.key,{handler:this.configPosition,value:K.value,validator:K.validator,supercedes:K.supercedes});S.addProperty(E.key,{value:E.value,suppressEvent:E.suppressEvent});S.addProperty(J.key,{value:J.value,validator:J.validator,suppressEvent:J.suppressEvent});S.addProperty(I.key,{value:I.value,validator:I.validator,handler:this.configSubmenuToggle});}});}());YAHOO.widget.MenuBarItem=function(B,A){YAHOO.widget.MenuBarItem.superclass.constructor.call(this,B,A);};YAHOO.lang.extend(YAHOO.widget.MenuBarItem,YAHOO.widget.MenuItem,{init:function(B,A){if(!this.SUBMENU_TYPE){this.SUBMENU_TYPE=YAHOO.widget.Menu;}YAHOO.widget.MenuBarItem.superclass.
 init.call(this,B);var C=this.cfg;if(A){C.applyConfig(A,true);}C.fireQueue();},CSS_CLASS_NAME:&quot;yuimenubaritem&quot;,CSS_LABEL_CLASS_NAME:&quot;yuimenubaritemlabel&quot;,toString:function(){var A=&quot;MenuBarItem&quot;;if(this.cfg&amp;&amp;this.cfg.getProperty(&quot;text&quot;)){A+=(&quot;: &quot;+this.cfg.getProperty(&quot;text&quot;));}return A;}});YAHOO.register(&quot;menu&quot;,YAHOO.widget.Menu,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuipaginatorpaginatorminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/paginator/paginator-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/paginator/paginator-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/paginator/paginator-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,11 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+(function(){var d=YAHOO.util.Dom,f=YAHOO.lang,b=f.isObject,e=f.isFunction,c=f.isArray,a=f.isString;function g(k){var n=g.VALUE_UNLIMITED,l,h,i,j,m;k=b(k)?k:{};this.initConfig();this.initEvents();this.set(&quot;rowsPerPage&quot;,k.rowsPerPage,true);if(g.isNumeric(k.totalRecords)){this.set(&quot;totalRecords&quot;,k.totalRecords,true);}this.initUIComponents();for(l in k){if(k.hasOwnProperty(l)){this.set(l,k[l],true);}}h=this.get(&quot;initialPage&quot;);i=this.get(&quot;totalRecords&quot;);j=this.get(&quot;rowsPerPage&quot;);if(h&gt;1&amp;&amp;j!==n){m=(h-1)*j;if(i===n||m&lt;i){this.set(&quot;recordOffset&quot;,m,true);}}}f.augmentObject(g,{id:0,ID_BASE:&quot;yui-pg&quot;,VALUE_UNLIMITED:-1,TEMPLATE_DEFAULT:&quot;{FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink}&quot;,TEMPLATE_ROWS_PER_PAGE:&quot;{FirstPageLink} {PreviousPageLink} {PageLinks} {NextPageLink} {LastPageLink} {RowsPerPageDropdown}&quot;,ui:{},isNumeric:function(h){return isFinite(+h);},t
 oNumber:function(h){return isFinite(+h)?+h:null;}},true);g.prototype={_containers:[],_batch:false,_pageChanged:false,_state:null,initConfig:function(){var h=g.VALUE_UNLIMITED;this.setAttributeConfig(&quot;rowsPerPage&quot;,{value:0,validator:g.isNumeric,setter:g.toNumber});this.setAttributeConfig(&quot;containers&quot;,{value:null,validator:function(l){if(!c(l)){l=[l];}for(var k=0,j=l.length;k&lt;j;++k){if(a(l[k])||(b(l[k])&amp;&amp;l[k].nodeType===1)){continue;}return false;}return true;},method:function(i){i=d.get(i);if(!c(i)){i=[i];}this._containers=i;}});this.setAttributeConfig(&quot;totalRecords&quot;,{value:0,validator:g.isNumeric,setter:g.toNumber});this.setAttributeConfig(&quot;recordOffset&quot;,{value:0,validator:function(j){var i=this.get(&quot;totalRecords&quot;);if(g.isNumeric(j)){j=+j;return i===h||i&gt;j||(i===0&amp;&amp;j===0);}return false;},setter:g.toNumber});this.setAttributeConfig(&quot;initialPage&quot;,{value:1,validator:g.isNumeric,setter:g.toNumber})
 ;this.setAttributeConfig(&quot;template&quot;,{value:g.TEMPLATE_DEFAULT,validator:a});this.setAttributeConfig(&quot;containerClass&quot;,{value:&quot;yui-pg-container&quot;,validator:a});this.setAttributeConfig(&quot;alwaysVisible&quot;,{value:true,validator:f.isBoolean});this.setAttributeConfig(&quot;updateOnChange&quot;,{value:false,validator:f.isBoolean});this.setAttributeConfig(&quot;id&quot;,{value:g.id++,readOnly:true});this.setAttributeConfig(&quot;rendered&quot;,{value:false,readOnly:true});},initUIComponents:function(){var j=g.ui,i,h;for(i in j){if(j.hasOwnProperty(i)){h=j[i];if(b(h)&amp;&amp;e(h.init)){h.init(this);}}}},initEvents:function(){this.createEvent(&quot;render&quot;);this.createEvent(&quot;rendered&quot;);this.createEvent(&quot;changeRequest&quot;);this.createEvent(&quot;pageChange&quot;);this.createEvent(&quot;beforeDestroy&quot;);this.createEvent(&quot;destroy&quot;);this._selfSubscribe();},_selfSubscribe:function(){this.subscribe(&quot;totalRecordsCha
 nge&quot;,this.updateVisibility,this,true);this.subscribe(&quot;alwaysVisibleChange&quot;,this.updateVisibility,this,true);this.subscribe(&quot;totalRecordsChange&quot;,this._handleStateChange,this,true);this.subscribe(&quot;recordOffsetChange&quot;,this._handleStateChange,this,true);this.subscribe(&quot;rowsPerPageChange&quot;,this._handleStateChange,this,true);this.subscribe(&quot;totalRecordsChange&quot;,this._syncRecordOffset,this,true);},_syncRecordOffset:function(k){var h=k.newValue,j,i;if(k.prevValue!==h){if(h!==g.VALUE_UNLIMITED){j=this.get(&quot;rowsPerPage&quot;);if(j&amp;&amp;this.get(&quot;recordOffset&quot;)&gt;=h){i=this.getState({totalRecords:k.prevValue,recordOffset:this.get(&quot;recordOffset&quot;)});this.set(&quot;recordOffset&quot;,i.before.recordOffset);this._firePageChange(i);}}}},_handleStateChange:function(i){if(i.prevValue!==i.newValue){var j=this._state||{},h;j[i.type.replace(/Change$/,&quot;&quot;)]=i.prevValue;h=this.getState(j);if(h.page!==h.befo
 re.page){if(this._batch){this._pageChanged=true;}else{this._firePageChange(h);}}}},_firePageChange:function(h){if(b(h)){var i=h.before;delete h.before;this.fireEvent(&quot;pageChange&quot;,{type:&quot;pageChange&quot;,prevValue:h.page,newValue:i.page,prevState:h,newState:i});}},render:function(){if(this.get(&quot;rendered&quot;)){return this;}var l=this.get(&quot;template&quot;),m=this.getState(),k=g.ID_BASE+this.get(&quot;id&quot;)+&quot;-&quot;,j,h;for(j=0,h=this._containers.length;j&lt;h;++j){this._renderTemplate(this._containers[j],l,k+j,true);}this.updateVisibility();if(this._containers.length){this.setAttributeConfig(&quot;rendered&quot;,{value:true});this.fireEvent(&quot;render&quot;,m);this.fireEvent(&quot;rendered&quot;,m);}return this;},_renderTemplate:function(j,n,m,l){var p=this.get(&quot;containerClass&quot;),o,k,h;if(!j){return;}d.setStyle(j,&quot;display&quot;,&quot;none&quot;);d.addClass(j,p);j.innerHTML=n.replace(/\{([a-z0-9_ \-]+)\}/gi,'&lt;span class=&quot
 ;yui-pg-ui yui-pg-ui-$1&quot;&gt;&lt;/span&gt;');o=d.getElementsByClassName(&quot;yui-pg-ui&quot;,&quot;span&quot;,j);for(k=0,h=o.length;k&lt;h;++k){this.renderUIComponent(o[k],m);}if(!l){d.setStyle(j,&quot;display&quot;,&quot;&quot;);}},renderUIComponent:function(h,m){var l=h.parentNode,k=/yui-pg-ui-(\w+)/.exec(h.className),j=k&amp;&amp;g.ui[k[1]],i;if(e(j)){i=new j(this);if(e(i.render)){l.replaceChild(i.render(m),h);}}return this;},destroy:function(){this.fireEvent(&quot;beforeDestroy&quot;);this.fireEvent(&quot;destroy&quot;);this.setAttributeConfig(&quot;rendered&quot;,{value:false});this.unsubscribeAll();},updateVisibility:function(m){var p=this.get(&quot;alwaysVisible&quot;),n,j,q,o,k,l,h;if(!m||m.type===&quot;alwaysVisibleChange&quot;||!p){n=this.get(&quot;totalRecords&quot;);j=true;q=this.get(&quot;rowsPerPage&quot;);o=this.get(&quot;rowsPerPageOptions&quot;);if(c(o)){for(k=0,l=o.length;k&lt;l;++k){h=o[k];if(f.isNumber(h||h.value)){q=Math.min(q,(h.value||h));}}}if(n!
 ==g.VALUE_UNLIMITED&amp;&amp;n&lt;=q){j=false;}j=j||p;for(k=0,l=this._containers.length;k&lt;l;++k){d.setStyle(this._containers[k],&quot;display&quot;,j?&quot;&quot;:&quot;none&quot;);}}},getContainerNodes:function(){return this._containers;},getTotalPages:function(){var h=this.get(&quot;totalRecords&quot;),i=this.get(&quot;rowsPerPage&quot;);if(!i){return null;}if(h===g.VALUE_UNLIMITED){return g.VALUE_UNLIMITED;}return Math.ceil(h/i);},hasPage:function(i){if(!f.isNumber(i)||i&lt;1){return false;}var h=this.getTotalPages();return(h===g.VALUE_UNLIMITED||h&gt;=i);},getCurrentPage:function(){var h=this.get(&quot;rowsPerPage&quot;);if(!h||!this.get(&quot;totalRecords&quot;)){return 0;}return Math.floor(this.get(&quot;recordOffset&quot;)/h)+1;},hasNextPage:function(){var h=this.getCurrentPage(),i=this.getTotalPages();return h&amp;&amp;(i===g.VALUE_UNLIMITED||h&lt;i);},getNextPage:function(){return this.hasNextPage()?this.getCurrentPage()+1:null;
+},hasPreviousPage:function(){return(this.getCurrentPage()&gt;1);},getPreviousPage:function(){return(this.hasPreviousPage()?this.getCurrentPage()-1:1);},getPageRecords:function(k){if(!f.isNumber(k)){k=this.getCurrentPage();}var j=this.get(&quot;rowsPerPage&quot;),i=this.get(&quot;totalRecords&quot;),l,h;if(!k||!j){return null;}l=(k-1)*j;if(i!==g.VALUE_UNLIMITED){if(l&gt;=i){return null;}h=Math.min(l+j,i)-1;}else{h=l+j-1;}return[l,h];},setPage:function(i,h){if(this.hasPage(i)&amp;&amp;i!==this.getCurrentPage()){if(this.get(&quot;updateOnChange&quot;)||h){this.set(&quot;recordOffset&quot;,(i-1)*this.get(&quot;rowsPerPage&quot;));}else{this.fireEvent(&quot;changeRequest&quot;,this.getState({&quot;page&quot;:i}));}}},getRowsPerPage:function(){return this.get(&quot;rowsPerPage&quot;);},setRowsPerPage:function(i,h){if(g.isNumeric(i)&amp;&amp;+i&gt;0&amp;&amp;+i!==this.get(&quot;rowsPerPage&quot;)){if(this.get(&quot;updateOnChange&quot;)||h){this.set(&quot;rowsPerPage&quot;,i);}else
 {this.fireEvent(&quot;changeRequest&quot;,this.getState({&quot;rowsPerPage&quot;:+i}));}}},getTotalRecords:function(){return this.get(&quot;totalRecords&quot;);},setTotalRecords:function(i,h){if(g.isNumeric(i)&amp;&amp;+i&gt;=0&amp;&amp;+i!==this.get(&quot;totalRecords&quot;)){if(this.get(&quot;updateOnChange&quot;)||h){this.set(&quot;totalRecords&quot;,i);}else{this.fireEvent(&quot;changeRequest&quot;,this.getState({&quot;totalRecords&quot;:+i}));}}},getStartIndex:function(){return this.get(&quot;recordOffset&quot;);},setStartIndex:function(i,h){if(g.isNumeric(i)&amp;&amp;+i&gt;=0&amp;&amp;+i!==this.get(&quot;recordOffset&quot;)){if(this.get(&quot;updateOnChange&quot;)||h){this.set(&quot;recordOffset&quot;,i);}else{this.fireEvent(&quot;changeRequest&quot;,this.getState({&quot;recordOffset&quot;:+i}));}}},getState:function(n){var p=g.VALUE_UNLIMITED,l=Math,m=l.max,o=l.ceil,j,h,k;function i(s,q,r){if(s&lt;=0||q===0){return 0;}if(q===p||q&gt;s){return s-(s%r);}return q-(q%r||r
 );}j={paginator:this,totalRecords:this.get(&quot;totalRecords&quot;),rowsPerPage:this.get(&quot;rowsPerPage&quot;),records:this.getPageRecords()};j.recordOffset=i(this.get(&quot;recordOffset&quot;),j.totalRecords,j.rowsPerPage);j.page=o(j.recordOffset/j.rowsPerPage)+1;if(!n){return j;}h={paginator:this,before:j,rowsPerPage:n.rowsPerPage||j.rowsPerPage,totalRecords:(g.isNumeric(n.totalRecords)?m(n.totalRecords,p):+j.totalRecords)};if(h.totalRecords===0){h.recordOffset=h.page=0;}else{k=g.isNumeric(n.page)?(n.page-1)*h.rowsPerPage:g.isNumeric(n.recordOffset)?+n.recordOffset:j.recordOffset;h.recordOffset=i(k,h.totalRecords,h.rowsPerPage);h.page=o(h.recordOffset/h.rowsPerPage)+1;}h.records=[h.recordOffset,h.recordOffset+h.rowsPerPage-1];if(h.totalRecords!==p&amp;&amp;h.recordOffset&lt;h.totalRecords&amp;&amp;h.records&amp;&amp;h.records[1]&gt;h.totalRecords-1){h.records[1]=h.totalRecords-1;}return h;},setState:function(i){if(b(i)){this._state=this.getState({});i={page:i.page,rows
 PerPage:i.rowsPerPage,totalRecords:i.totalRecords,recordOffset:i.recordOffset};if(i.page&amp;&amp;i.recordOffset===undefined){i.recordOffset=(i.page-1)*(i.rowsPerPage||this.get(&quot;rowsPerPage&quot;));}this._batch=true;this._pageChanged=false;for(var h in i){if(i.hasOwnProperty(h)&amp;&amp;this._configs.hasOwnProperty(h)){this.set(h,i[h]);}}this._batch=false;if(this._pageChanged){this._pageChanged=false;this._firePageChange(this.getState(this._state));}}}};f.augmentProto(g,YAHOO.util.AttributeProvider);YAHOO.widget.Paginator=g;})();(function(){var c=YAHOO.widget.Paginator,b=YAHOO.lang,a=YAHOO.util.Dom.generateId;c.ui.CurrentPageReport=function(d){this.paginator=d;d.subscribe(&quot;recordOffsetChange&quot;,this.update,this,true);d.subscribe(&quot;rowsPerPageChange&quot;,this.update,this,true);d.subscribe(&quot;totalRecordsChange&quot;,this.update,this,true);d.subscribe(&quot;pageReportTemplateChange&quot;,this.update,this,true);d.subscribe(&quot;destroy&quot;,this.destroy,t
 his,true);d.subscribe(&quot;pageReportClassChange&quot;,this.update,this,true);};c.ui.CurrentPageReport.init=function(d){d.setAttributeConfig(&quot;pageReportClass&quot;,{value:&quot;yui-pg-current&quot;,validator:b.isString});d.setAttributeConfig(&quot;pageReportTemplate&quot;,{value:&quot;({currentPage} of {totalPages})&quot;,validator:b.isString});d.setAttributeConfig(&quot;pageReportValueGenerator&quot;,{value:function(g){var f=g.getCurrentPage(),e=g.getPageRecords();return{&quot;currentPage&quot;:e?f:0,&quot;totalPages&quot;:g.getTotalPages(),&quot;startIndex&quot;:e?e[0]:0,&quot;endIndex&quot;:e?e[1]:0,&quot;startRecord&quot;:e?e[0]+1:0,&quot;endRecord&quot;:e?e[1]+1:0,&quot;totalRecords&quot;:g.get(&quot;totalRecords&quot;)};},validator:b.isFunction});};c.ui.CurrentPageReport.sprintf=function(e,d){return e.replace(/\{([\w\s\-]+)\}/g,function(f,g){return(g in d)?d[g]:&quot;&quot;;});};c.ui.CurrentPageReport.prototype={span:null,render:function(d){this.span=document.cre
 ateElement(&quot;span&quot;);this.span.className=this.paginator.get(&quot;pageReportClass&quot;);a(this.span,d+&quot;-page-report&quot;);this.update();return this.span;},update:function(d){if(d&amp;&amp;d.prevValue===d.newValue){return;}this.span.innerHTML=c.ui.CurrentPageReport.sprintf(this.paginator.get(&quot;pageReportTemplate&quot;),this.paginator.get(&quot;pageReportValueGenerator&quot;)(this.paginator));},destroy:function(){this.span.parentNode.removeChild(this.span);this.span=null;}};})();(function(){var c=YAHOO.widget.Paginator,b=YAHOO.lang,a=YAHOO.util.Dom.generateId;c.ui.PageLinks=function(d){this.paginator=d;d.subscribe(&quot;recordOffsetChange&quot;,this.update,this,true);d.subscribe(&quot;rowsPerPageChange&quot;,this.update,this,true);d.subscribe(&quot;totalRecordsChange&quot;,this.update,this,true);d.subscribe(&quot;pageLinksChange&quot;,this.rebuild,this,true);d.subscribe(&quot;pageLinkClassChange&quot;,this.rebuild,this,true);d.subscribe(&quot;currentPageClas
 sChange&quot;,this.rebuild,this,true);d.subscribe(&quot;destroy&quot;,this.destroy,this,true);d.subscribe(&quot;pageLinksContainerClassChange&quot;,this.rebuild,this,true);};c.ui.PageLinks.init=function(d){d.setAttributeConfig(&quot;pageLinkClass&quot;,{value:&quot;yui-pg-page&quot;,validator:b.isString});d.setAttributeConfig(&quot;currentPageClass&quot;,{value:&quot;yui-pg-current-page&quot;,validator:b.isString});d.setAttributeConfig(&quot;pageLinksContainerClass&quot;,{value:&quot;yui-pg-pages&quot;,validator:b.isString});d.setAttributeConfig(&quot;pageLinks&quot;,{value:10,validator:c.isNumeric});d.setAttributeConfig(&quot;pageLabelBuilder&quot;,{value:function(e,f){return e;},validator:b.isFunction});d.setAttributeConfig(&quot;pageTitleBuilder&quot;,{value:function(e,f){return&quot;Page &quot;+e;},validator:b.isFunction});};c.ui.PageLinks.calculateRange=function(f,g,e){var j=c.VALUE_UNLIMITED,i,d,h;if(!f||e===0||g===0||(g===j&amp;&amp;e===j)){return[0,-1];
+}if(g!==j){e=e===j?g:Math.min(e,g);}i=Math.max(1,Math.ceil(f-(e/2)));if(g===j){d=i+e-1;}else{d=Math.min(g,i+e-1);}h=e-(d-i+1);i=Math.max(1,i-h);return[i,d];};c.ui.PageLinks.prototype={current:0,container:null,render:function(d){var e=this.paginator;this.container=document.createElement(&quot;span&quot;);a(this.container,d+&quot;-pages&quot;);this.container.className=e.get(&quot;pageLinksContainerClass&quot;);YAHOO.util.Event.on(this.container,&quot;click&quot;,this.onClick,this,true);this.update({newValue:null,rebuild:true});return this.container;},update:function(q){if(q&amp;&amp;q.prevValue===q.newValue){return;}var g=this.paginator,m=g.getCurrentPage();if(this.current!==m||!m||q.rebuild){var r=g.get(&quot;pageLabelBuilder&quot;),l=g.get(&quot;pageTitleBuilder&quot;),k=c.ui.PageLinks.calculateRange(m,g.getTotalPages(),g.get(&quot;pageLinks&quot;)),f=k[0],h=k[1],o=&quot;&quot;,d,j,n;d='&lt;a href=&quot;#&quot; class=&quot;{class}&quot; page=&quot;{page}&quot; title=&quot;{t
 itle}&quot;&gt;{label}&lt;/a&gt;';n='&lt;span class=&quot;{class}&quot;&gt;{label}&lt;/span&gt;';for(j=f;j&lt;=h;++j){if(j===m){o+=b.substitute(n,{&quot;class&quot;:g.get(&quot;currentPageClass&quot;)+&quot; &quot;+g.get(&quot;pageLinkClass&quot;),&quot;label&quot;:r(j,g)});}else{o+=b.substitute(d,{&quot;class&quot;:g.get(&quot;pageLinkClass&quot;),&quot;page&quot;:j,&quot;label&quot;:r(j,g),&quot;title&quot;:l(j,g)});}}this.container.innerHTML=o;}},rebuild:function(d){d.rebuild=true;this.update(d);},destroy:function(){YAHOO.util.Event.purgeElement(this.container,true);this.container.parentNode.removeChild(this.container);this.container=null;},onClick:function(f){var d=YAHOO.util.Event.getTarget(f);if(d&amp;&amp;YAHOO.util.Dom.hasClass(d,this.paginator.get(&quot;pageLinkClass&quot;))){YAHOO.util.Event.stopEvent(f);this.paginator.setPage(parseInt(d.getAttribute(&quot;page&quot;),10));}}};})();(function(){var c=YAHOO.widget.Paginator,b=YAHOO.lang,a=YAHOO.util.Dom.generateId;c.
 ui.FirstPageLink=function(d){this.paginator=d;d.subscribe(&quot;recordOffsetChange&quot;,this.update,this,true);d.subscribe(&quot;rowsPerPageChange&quot;,this.update,this,true);d.subscribe(&quot;totalRecordsChange&quot;,this.update,this,true);d.subscribe(&quot;destroy&quot;,this.destroy,this,true);d.subscribe(&quot;firstPageLinkLabelChange&quot;,this.update,this,true);d.subscribe(&quot;firstPageLinkClassChange&quot;,this.update,this,true);};c.ui.FirstPageLink.init=function(d){d.setAttributeConfig(&quot;firstPageLinkLabel&quot;,{value:&quot;&amp;lt;&amp;lt; first&quot;,validator:b.isString});d.setAttributeConfig(&quot;firstPageLinkClass&quot;,{value:&quot;yui-pg-first&quot;,validator:b.isString});d.setAttributeConfig(&quot;firstPageLinkTitle&quot;,{value:&quot;First Page&quot;,validator:b.isString});};c.ui.FirstPageLink.prototype={current:null,link:null,span:null,render:function(e){var f=this.paginator,h=f.get(&quot;firstPageLinkClass&quot;),d=f.get(&quot;firstPageLinkLabel&q
 uot;),g=f.get(&quot;firstPageLinkTitle&quot;);this.link=document.createElement(&quot;a&quot;);this.span=document.createElement(&quot;span&quot;);a(this.link,e+&quot;-first-link&quot;);this.link.href=&quot;#&quot;;this.link.className=h;this.link.innerHTML=d;this.link.title=g;YAHOO.util.Event.on(this.link,&quot;click&quot;,this.onClick,this,true);a(this.span,e+&quot;-first-span&quot;);this.span.className=h;this.span.innerHTML=d;this.current=f.getCurrentPage()&gt;1?this.link:this.span;return this.current;},update:function(f){if(f&amp;&amp;f.prevValue===f.newValue){return;}var d=this.current?this.current.parentNode:null;if(this.paginator.getCurrentPage()&gt;1){if(d&amp;&amp;this.current===this.span){d.replaceChild(this.link,this.current);this.current=this.link;}}else{if(d&amp;&amp;this.current===this.link){d.replaceChild(this.span,this.current);this.current=this.span;}}},destroy:function(){YAHOO.util.Event.purgeElement(this.link);this.current.parentNode.removeChild(this.current)
 ;this.link=this.span=null;},onClick:function(d){YAHOO.util.Event.stopEvent(d);this.paginator.setPage(1);}};})();(function(){var c=YAHOO.widget.Paginator,b=YAHOO.lang,a=YAHOO.util.Dom.generateId;c.ui.LastPageLink=function(d){this.paginator=d;d.subscribe(&quot;recordOffsetChange&quot;,this.update,this,true);d.subscribe(&quot;rowsPerPageChange&quot;,this.update,this,true);d.subscribe(&quot;totalRecordsChange&quot;,this.update,this,true);d.subscribe(&quot;destroy&quot;,this.destroy,this,true);d.subscribe(&quot;lastPageLinkLabelChange&quot;,this.update,this,true);d.subscribe(&quot;lastPageLinkClassChange&quot;,this.update,this,true);};c.ui.LastPageLink.init=function(d){d.setAttributeConfig(&quot;lastPageLinkLabel&quot;,{value:&quot;last &amp;gt;&amp;gt;&quot;,validator:b.isString});d.setAttributeConfig(&quot;lastPageLinkClass&quot;,{value:&quot;yui-pg-last&quot;,validator:b.isString});d.setAttributeConfig(&quot;lastPageLinkTitle&quot;,{value:&quot;Last Page&quot;,validator:b.isSt
 ring});};c.ui.LastPageLink.prototype={current:null,link:null,span:null,na:null,render:function(e){var g=this.paginator,i=g.get(&quot;lastPageLinkClass&quot;),d=g.get(&quot;lastPageLinkLabel&quot;),f=g.getTotalPages(),h=g.get(&quot;lastPageLinkTitle&quot;);this.link=document.createElement(&quot;a&quot;);this.span=document.createElement(&quot;span&quot;);this.na=this.span.cloneNode(false);a(this.link,e+&quot;-last-link&quot;);this.link.href=&quot;#&quot;;this.link.className=i;this.link.innerHTML=d;this.link.title=h;YAHOO.util.Event.on(this.link,&quot;click&quot;,this.onClick,this,true);a(this.span,e+&quot;-last-span&quot;);this.span.className=i;this.span.innerHTML=d;a(this.na,e+&quot;-last-na&quot;);switch(f){case c.VALUE_UNLIMITED:this.current=this.na;break;case g.getCurrentPage():this.current=this.span;break;default:this.current=this.link;}return this.current;},update:function(f){if(f&amp;&amp;f.prevValue===f.newValue){return;}var d=this.current?this.current.parentNode:null,
 g=this.link;if(d){switch(this.paginator.getTotalPages()){case c.VALUE_UNLIMITED:g=this.na;break;case this.paginator.getCurrentPage():g=this.span;break;}if(this.current!==g){d.replaceChild(g,this.current);this.current=g;}}},destroy:function(){YAHOO.util.Event.purgeElement(this.link);this.current.parentNode.removeChild(this.current);this.link=this.span=null;},onClick:function(d){YAHOO.util.Event.stopEvent(d);this.paginator.setPage(this.paginator.getTotalPages());}};})();(function(){var c=YAHOO.widget.Paginator,b=YAHOO.lang,a=YAHOO.util.Dom.generateId;c.ui.NextPageLink=function(d){this.paginator=d;d.subscribe(&quot;recordOffsetChange&quot;,this.update,this,true);d.subscribe(&quot;rowsPerPageChange&quot;,this.update,this,true);d.subscribe(&quot;totalRecordsChange&quot;,this.update,this,true);d.subscribe(&quot;destroy&quot;,this.destroy,this,true);d.subscribe(&quot;nextPageLinkLabelChange&quot;,this.update,this,true);
+d.subscribe(&quot;nextPageLinkClassChange&quot;,this.update,this,true);};c.ui.NextPageLink.init=function(d){d.setAttributeConfig(&quot;nextPageLinkLabel&quot;,{value:&quot;next &amp;gt;&quot;,validator:b.isString});d.setAttributeConfig(&quot;nextPageLinkClass&quot;,{value:&quot;yui-pg-next&quot;,validator:b.isString});d.setAttributeConfig(&quot;nextPageLinkTitle&quot;,{value:&quot;Next Page&quot;,validator:b.isString});};c.ui.NextPageLink.prototype={current:null,link:null,span:null,render:function(e){var g=this.paginator,i=g.get(&quot;nextPageLinkClass&quot;),d=g.get(&quot;nextPageLinkLabel&quot;),f=g.getTotalPages(),h=g.get(&quot;nextPageLinkTitle&quot;);this.link=document.createElement(&quot;a&quot;);this.span=document.createElement(&quot;span&quot;);a(this.link,e+&quot;-next-link&quot;);this.link.href=&quot;#&quot;;this.link.className=i;this.link.innerHTML=d;this.link.title=h;YAHOO.util.Event.on(this.link,&quot;click&quot;,this.onClick,this,true);a(this.span,e+&quot;-next
 -span&quot;);this.span.className=i;this.span.innerHTML=d;this.current=g.getCurrentPage()===f?this.span:this.link;return this.current;},update:function(g){if(g&amp;&amp;g.prevValue===g.newValue){return;}var f=this.paginator.getTotalPages(),d=this.current?this.current.parentNode:null;if(this.paginator.getCurrentPage()!==f){if(d&amp;&amp;this.current===this.span){d.replaceChild(this.link,this.current);this.current=this.link;}}else{if(this.current===this.link){if(d){d.replaceChild(this.span,this.current);this.current=this.span;}}}},destroy:function(){YAHOO.util.Event.purgeElement(this.link);this.current.parentNode.removeChild(this.current);this.link=this.span=null;},onClick:function(d){YAHOO.util.Event.stopEvent(d);this.paginator.setPage(this.paginator.getNextPage());}};})();(function(){var c=YAHOO.widget.Paginator,b=YAHOO.lang,a=YAHOO.util.Dom.generateId;c.ui.PreviousPageLink=function(d){this.paginator=d;d.subscribe(&quot;recordOffsetChange&quot;,this.update,this,true);d.subscr
 ibe(&quot;rowsPerPageChange&quot;,this.update,this,true);d.subscribe(&quot;totalRecordsChange&quot;,this.update,this,true);d.subscribe(&quot;destroy&quot;,this.destroy,this,true);d.subscribe(&quot;previousPageLinkLabelChange&quot;,this.update,this,true);d.subscribe(&quot;previousPageLinkClassChange&quot;,this.update,this,true);};c.ui.PreviousPageLink.init=function(d){d.setAttributeConfig(&quot;previousPageLinkLabel&quot;,{value:&quot;&amp;lt; prev&quot;,validator:b.isString});d.setAttributeConfig(&quot;previousPageLinkClass&quot;,{value:&quot;yui-pg-previous&quot;,validator:b.isString});d.setAttributeConfig(&quot;previousPageLinkTitle&quot;,{value:&quot;Previous Page&quot;,validator:b.isString});};c.ui.PreviousPageLink.prototype={current:null,link:null,span:null,render:function(e){var f=this.paginator,h=f.get(&quot;previousPageLinkClass&quot;),d=f.get(&quot;previousPageLinkLabel&quot;),g=f.get(&quot;previousPageLinkTitle&quot;);this.link=document.createElement(&quot;a&quot;)
 ;this.span=document.createElement(&quot;span&quot;);a(this.link,e+&quot;-prev-link&quot;);this.link.href=&quot;#&quot;;this.link.className=h;this.link.innerHTML=d;this.link.title=g;YAHOO.util.Event.on(this.link,&quot;click&quot;,this.onClick,this,true);a(this.span,e+&quot;-prev-span&quot;);this.span.className=h;this.span.innerHTML=d;this.current=f.getCurrentPage()&gt;1?this.link:this.span;return this.current;},update:function(f){if(f&amp;&amp;f.prevValue===f.newValue){return;}var d=this.current?this.current.parentNode:null;if(this.paginator.getCurrentPage()&gt;1){if(d&amp;&amp;this.current===this.span){d.replaceChild(this.link,this.current);this.current=this.link;}}else{if(d&amp;&amp;this.current===this.link){d.replaceChild(this.span,this.current);this.current=this.span;}}},destroy:function(){YAHOO.util.Event.purgeElement(this.link);this.current.parentNode.removeChild(this.current);this.link=this.span=null;},onClick:function(d){YAHOO.util.Event.stopEvent(d);this.paginator.se
 tPage(this.paginator.getPreviousPage());}};})();(function(){var c=YAHOO.widget.Paginator,b=YAHOO.lang,a=YAHOO.util.Dom.generateId;c.ui.RowsPerPageDropdown=function(d){this.paginator=d;d.subscribe(&quot;rowsPerPageChange&quot;,this.update,this,true);d.subscribe(&quot;rowsPerPageOptionsChange&quot;,this.rebuild,this,true);d.subscribe(&quot;totalRecordsChange&quot;,this._handleTotalRecordsChange,this,true);d.subscribe(&quot;destroy&quot;,this.destroy,this,true);d.subscribe(&quot;rowsPerPageDropdownClassChange&quot;,this.rebuild,this,true);};c.ui.RowsPerPageDropdown.init=function(d){d.setAttributeConfig(&quot;rowsPerPageOptions&quot;,{value:[],validator:b.isArray});d.setAttributeConfig(&quot;rowsPerPageDropdownClass&quot;,{value:&quot;yui-pg-rpp-options&quot;,validator:b.isString});};c.ui.RowsPerPageDropdown.prototype={select:null,all:null,render:function(d){this.select=document.createElement(&quot;select&quot;);a(this.select,d+&quot;-rpp&quot;);this.select.className=this.pagina
 tor.get(&quot;rowsPerPageDropdownClass&quot;);this.select.title=&quot;Rows per page&quot;;YAHOO.util.Event.on(this.select,&quot;change&quot;,this.onChange,this,true);this.rebuild();return this.select;},rebuild:function(m){var d=this.paginator,g=this.select,n=d.get(&quot;rowsPerPageOptions&quot;),f,l,h,j,k;this.all=null;for(j=0,k=n.length;j&lt;k;++j){l=n[j];f=g.options[j]||g.appendChild(document.createElement(&quot;option&quot;));h=b.isValue(l.value)?l.value:l;f.text=b.isValue(l.text)?l.text:l;if(b.isString(h)&amp;&amp;h.toLowerCase()===&quot;all&quot;){this.all=f;f.value=d.get(&quot;totalRecords&quot;);}else{f.value=h;}}while(g.options.length&gt;n.length){g.removeChild(g.firstChild);}this.update();},update:function(j){if(j&amp;&amp;j.prevValue===j.newValue){return;}var h=this.paginator.get(&quot;rowsPerPage&quot;)+&quot;&quot;,f=this.select.options,g,d;for(g=0,d=f.length;g&lt;d;++g){if(f[g].value===h){f[g].selected=true;break;}}},onChange:function(d){this.paginator.setRowsPe
 rPage(parseInt(this.select.options[this.select.selectedIndex].value,10));},_handleTotalRecordsChange:function(d){if(!this.all||(d&amp;&amp;d.prevValue===d.newValue)){return;}this.all.value=d.newValue;if(this.all.selected){this.paginator.set(&quot;rowsPerPage&quot;,d.newValue);}},destroy:function(){YAHOO.util.Event.purgeElement(this.select);this.select.parentNode.removeChild(this.select);this.select=null;}};})();(function(){var c=YAHOO.widget.Paginator,b=YAHOO.lang,a=YAHOO.util.Dom.generateId;c.ui.JumpToPageDropdown=function(d){this.paginator=d;d.subscribe(&quot;rowsPerPageChange&quot;,this.rebuild,this,true);d.subscribe(&quot;rowsPerPageOptionsChange&quot;,this.rebuild,this,true);d.subscribe(&quot;pageChange&quot;,this.update,this,true);d.subscribe(&quot;totalRecordsChange&quot;,this.rebuild,this,true);
+d.subscribe(&quot;destroy&quot;,this.destroy,this,true);};c.ui.JumpToPageDropdown.init=function(d){d.setAttributeConfig(&quot;jumpToPageDropdownClass&quot;,{value:&quot;yui-pg-jtp-options&quot;,validator:b.isString});};c.ui.JumpToPageDropdown.prototype={select:null,render:function(d){this.select=document.createElement(&quot;select&quot;);a(this.select,d+&quot;-jtp&quot;);this.select.className=this.paginator.get(&quot;jumpToPageDropdownClass&quot;);this.select.title=&quot;Jump to page&quot;;YAHOO.util.Event.on(this.select,&quot;change&quot;,this.onChange,this,true);this.rebuild();return this.select;},rebuild:function(l){var k=this.paginator,j=this.select,f=k.getTotalPages(),h,g,d;this.all=null;for(g=0,d=f;g&lt;d;++g){h=j.options[g]||j.appendChild(document.createElement(&quot;option&quot;));h.innerHTML=g+1;h.value=g+1;}for(g=f,d=j.options.length;g&lt;d;g++){j.removeChild(j.lastChild);}this.update();},update:function(j){if(j&amp;&amp;j.prevValue===j.newValue){return;}var h=this
 .paginator.getCurrentPage()+&quot;&quot;,f=this.select.options,g,d;for(g=0,d=f.length;g&lt;d;++g){if(f[g].value===h){f[g].selected=true;break;}}},onChange:function(d){this.paginator.setPage(parseInt(this.select.options[this.select.selectedIndex].value,false));},destroy:function(){YAHOO.util.Event.purgeElement(this.select);this.select.parentNode.removeChild(this.select);this.select=null;}};})();YAHOO.register(&quot;paginator&quot;,YAHOO.widget.Paginator,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiprofilerprofilerminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/profiler/profiler-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/profiler/profiler-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/profiler/profiler-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+YAHOO.namespace(&quot;tool&quot;);YAHOO.tool.Profiler=function(){var container={},report={},stopwatches={},WATCH_STARTED=0,WATCH_STOPPED=1,WATCH_PAUSED=2,lang=YAHOO.lang;function createReport(name){report[name]={calls:0,max:0,min:0,avg:0,points:[]};}function saveDataPoint(name,duration){var functionData=report[name];if(!functionData){functionData=createReport(name);}functionData.calls++;functionData.points.push(duration);if(functionData.calls&gt;1){functionData.avg=((functionData.avg*(functionData.calls-1))+duration)/functionData.calls;functionData.min=Math.min(functionData.min,duration);functionData.max=Math.max(functionData.max,duration);}else{functionData.avg=duration;functionData.min=duration;functionData.max=duration;}}return{clear:function(name){if(lang.isString(name)){delete report[name];delete stopwatches[name];}else{report={};stopwatches={};}},getOriginal:function(name){return container[name];},instrument:function(name,method){var newMethod=function(){var start=new 
 Date(),retval=method.apply(this,arguments),stop=new Date();saveDataPoint(name,stop-start);return retval;};lang.augmentObject(newMethod,method);newMethod.__yuiProfiled=true;newMethod.prototype=method.prototype;container[name]=method;container[name].__yuiFuncName=name;createReport(name);return newMethod;},pause:function(name){var now=new Date(),stopwatch=stopwatches[name];if(stopwatch&amp;&amp;stopwatch.state==WATCH_STARTED){stopwatch.total+=(now-stopwatch.start);stopwatch.start=0;stopwatch.state=WATCH_PAUSED;}},start:function(name){if(container[name]){throw new Error(&quot;Cannot use '&quot;+name+&quot;' for profiling through start(), name is already in use.&quot;);}else{if(!report[name]){createReport(name);}if(!stopwatches[name]){stopwatches[name]={state:WATCH_STOPPED,start:0,total:0};}if(stopwatches[name].state==WATCH_STOPPED){stopwatches[name].state=WATCH_STARTED;stopwatches[name].start=new Date();}}},stop:function(name){var now=new Date(),stopwatch=stopwatches[name];if(st
 opwatch){if(stopwatch.state==WATCH_STARTED){saveDataPoint(name,stopwatch.total+(now-stopwatch.start));}else{if(stopwatch.state==WATCH_PAUSED){saveDataPoint(name,stopwatch.total);}}stopwatch.start=0;stopwatch.total=0;stopwatch.state=WATCH_STOPPED;}},getAverage:function(name){return report[name].avg;},getCallCount:function(name){return report[name].calls;},getMax:function(name){return report[name].max;},getMin:function(name){return report[name].min;},getFunctionReport:function(name){return report[name];},getReport:function(name){return report[name];},getFullReport:function(filter){filter=filter||function(){return true;};if(lang.isFunction(filter)){var fullReport={};for(var name in report){if(filter(report[name])){fullReport[name]=report[name];}}return fullReport;}},registerConstructor:function(name,owner){this.registerFunction(name,owner,true);},registerFunction:function(name,owner,registerPrototype){var funcName=(name.indexOf(&quot;.&quot;)&gt;-1?name.substring(name.lastIndex
 Of(&quot;.&quot;)+1):name),method,prototype;if(!lang.isObject(owner)){owner=eval(name.substring(0,name.lastIndexOf(&quot;.&quot;)));}method=owner[funcName];prototype=method.prototype;if(lang.isFunction(method)&amp;&amp;!method.__yuiProfiled){owner[funcName]=this.instrument(name,method);container[name].__yuiOwner=owner;container[name].__yuiFuncName=funcName;if(registerPrototype){this.registerObject(name+&quot;.prototype&quot;,prototype);}}},registerObject:function(name,object,recurse){object=(lang.isObject(object)?object:eval(name));container[name]=object;for(var prop in object){if(typeof object[prop]==&quot;function&quot;){if(prop!=&quot;constructor&quot;&amp;&amp;prop!=&quot;superclass&quot;){this.registerFunction(name+&quot;.&quot;+prop,object);}}else{if(typeof object[prop]==&quot;object&quot;&amp;&amp;recurse){this.registerObject(name+&quot;.&quot;+prop,object[prop],recurse);}}}},unregisterConstructor:function(name){if(lang.isFunction(container[name])){this.unregisterFunc
 tion(name,true);}},unregisterFunction:function(name,unregisterPrototype){if(lang.isFunction(container[name])){if(unregisterPrototype){this.unregisterObject(name+&quot;.prototype&quot;,container[name].prototype);}var owner=container[name].__yuiOwner,funcName=container[name].__yuiFuncName;delete container[name].__yuiOwner;delete container[name].__yuiFuncName;owner[funcName]=container[name];delete container[name];}},unregisterObject:function(name,recurse){if(lang.isObject(container[name])){var object=container[name];for(var prop in object){if(typeof object[prop]==&quot;function&quot;){this.unregisterFunction(name+&quot;.&quot;+prop);}else{if(typeof object[prop]==&quot;object&quot;&amp;&amp;recurse){this.unregisterObject(name+&quot;.&quot;+prop,recurse);}}}delete container[name];}}};}();YAHOO.register(&quot;profiler&quot;,YAHOO.tool.Profiler,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiprofilerviewerprofilerviewerminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/profilerviewer/profilerviewer-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/profilerviewer/profilerviewer-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/profilerviewer/profilerviewer-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,9 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+(function(){YAHOO.widget.ProfilerViewer=function(H,G){G=G||{};if(arguments.length==1&amp;&amp;!YAHOO.lang.isString(H)&amp;&amp;!H.nodeName){G=H;H=G.element||null;}if(!H&amp;&amp;!G.element){H=this._createProfilerViewerElement();}YAHOO.widget.ProfilerViewer.superclass.constructor.call(this,H,G);this._init();};YAHOO.extend(YAHOO.widget.ProfilerViewer,YAHOO.util.Element);YAHOO.lang.augmentObject(YAHOO.widget.ProfilerViewer,{CLASS:&quot;yui-pv&quot;,CLASS_DASHBOARD:&quot;yui-pv-dashboard&quot;,CLASS_REFRESH:&quot;yui-pv-refresh&quot;,CLASS_BUSY:&quot;yui-pv-busy&quot;,CLASS_CHART_CONTAINER:&quot;yui-pv-chartcontainer&quot;,CLASS_CHART:&quot;yui-pv-chart&quot;,CLASS_CHART_LEGEND:&quot;yui-pv-chartlegend&quot;,CLASS_TABLE:&quot;yui-pv-table&quot;,STRINGS:{title:&quot;YUI ProfilerViewer&quot;,buttons:{viewprofiler:&quot;View Profiler Data&quot;,hideprofiler:&quot;Hide Profiler Report&quot;,showchart:&quot;Show Chart&quot;,hidechart:&quot;Hide Chart&quot;,refreshdata:&quot;Refresh D
 ata&quot;},colHeads:{fn:[&quot;Function/Method&quot;,null],calls:[&quot;Calls&quot;,40],avg:[&quot;Average&quot;,80],min:[&quot;Shortest&quot;,70],max:[&quot;Longest&quot;,70],total:[&quot;Total Time&quot;,70],pct:[&quot;Percent&quot;,70]},millisecondsAbbrev:&quot;ms&quot;,initMessage:&quot;initialiazing chart...&quot;,installFlashMessage:&quot;Unable to load Flash content. The YUI Charts Control requires Flash Player 9.0.45 or higher. You can download the latest version of Flash Player from the &lt;a href='http://www.adobe.com/go/getflashplayer'&gt;Adobe Flash Player Download Center&lt;/a&gt;.&quot;},timeAxisLabelFunction:function(H){var G=(H===Math.floor(H))?H:(Math.round(H*1000))/1000;return(G+&quot; &quot;+YAHOO.widget.ProfilerViewer.STRINGS.millisecondsAbbrev);},percentAxisLabelFunction:function(H){var G=(H===Math.floor(H))?H:(Math.round(H*100))/100;return(G+&quot;%&quot;);}},true);var C=YAHOO.util.Dom;var A=YAHOO.util.Event;var B=YAHOO.tool.Profiler;var E=YAHOO.widget.
 ProfilerViewer;var D=E.prototype;D.refreshData=function(){this.fireEvent(&quot;dataRefreshEvent&quot;);};D.getHeadEl=function(){return(this._headEl)?C.get(this._headEl):false;};D.getBodyEl=function(){return(this._bodyEl)?C.get(this._bodyEl):false;};D.getChartEl=function(){return(this._chartEl)?C.get(this._chartEl):false;};D.getTableEl=function(){return(this._tableEl)?C.get(this._tableEl):false;};D.getDataTable=function(){return this._dataTable;};D.getChart=function(){return this._chart;};D._rendered=false;D._headEl=null;D._bodyEl=null;D._toggleVisibleEl=null;D._busyEl=null;D._busy=false;D._tableEl=null;D._dataTable=null;D._chartEl=null;D._chartLegendEl=null;D._chartElHeight=250;D._chart=null;D._chartInitialized=false;D._init=function(){this.createEvent(&quot;dataRefreshEvent&quot;);this.createEvent(&quot;renderEvent&quot;);this.on(&quot;dataRefreshEvent&quot;,this._refreshDataTable,this,true);this._initLauncherDOM();if(this.get(&quot;showChart&quot;)){this.on(&quot;sortedByC
 hange&quot;,this._refreshChart);}};D._createProfilerViewerElement=function(){var G=document.createElement(&quot;div&quot;);document.body.insertBefore(G,document.body.firstChild);C.addClass(G,this.SKIN_CLASS);C.addClass(G,E.CLASS);return G;};D.toString=function(){return&quot;ProfilerViewer &quot;+(this.get(&quot;id&quot;)||this.get(&quot;tagName&quot;));};D._toggleVisible=function(){var G=(this.get(&quot;visible&quot;))?false:true;this.set(&quot;visible&quot;,G);};D._show=function(){if(!this._busy){this._setBusyState(true);if(!this._rendered){var G=new YAHOO.util.YUILoader();if(this.get(&quot;base&quot;)){G.base=this.get(&quot;base&quot;);}var H=[&quot;datatable&quot;];if(this.get(&quot;showChart&quot;)){H.push(&quot;charts&quot;);}G.insert({require:H,onSuccess:function(){this._render();},scope:this});}else{var I=this.get(&quot;element&quot;);C.removeClass(I,&quot;yui-pv-minimized&quot;);this._toggleVisibleEl.innerHTML=E.STRINGS.buttons.hideprofiler;C.addClass(I,&quot;yui-pv-
 null&quot;);C.removeClass(I,&quot;yui-pv-null&quot;);this.refreshData();}}};D._hide=function(){this._toggleVisibleEl.innerHTML=E.STRINGS.buttons.viewprofiler;C.addClass(this.get(&quot;element&quot;),&quot;yui-pv-minimized&quot;);};D._render=function(){C.removeClass(this.get(&quot;element&quot;),&quot;yui-pv-minimized&quot;);this._initViewerDOM();this._initDataTable();if(this.get(&quot;showChart&quot;)){this._initChartDOM();this._initChart();}this._rendered=true;this._toggleVisibleEl.innerHTML=E.STRINGS.buttons.hideprofiler;this.fireEvent(&quot;renderEvent&quot;);};D._initLauncherDOM=function(){var I=this.get(&quot;element&quot;);C.addClass(I,E.CLASS);C.addClass(I,&quot;yui-pv-minimized&quot;);this._headEl=document.createElement(&quot;div&quot;);C.addClass(this._headEl,&quot;hd&quot;);var H=E.STRINGS.buttons;var G=(this.get(&quot;visible&quot;))?H.hideprofiler:H.viewprofiler;this._toggleVisibleEl=this._createButton(G,this._headEl);this._refreshEl=this._createButton(H.refreshd
 ata,this._headEl);C.addClass(this._refreshEl,E.CLASS_REFRESH);this._busyEl=document.createElement(&quot;span&quot;);this._headEl.appendChild(this._busyEl);var J=document.createElement(&quot;h4&quot;);J.innerHTML=E.STRINGS.title;this._headEl.appendChild(J);I.appendChild(this._headEl);A.on(this._toggleVisibleEl,&quot;click&quot;,this._toggleVisible,this,true);A.on(this._refreshEl,&quot;click&quot;,function(){if(!this._busy){this._setBusyState(true);this.fireEvent(&quot;dataRefreshEvent&quot;);}},this,true);};D._initViewerDOM=function(){var G=this.get(&quot;element&quot;);this._bodyEl=document.createElement(&quot;div&quot;);C.addClass(this._bodyEl,&quot;bd&quot;);this._tableEl=document.createElement(&quot;div&quot;);C.addClass(this._tableEl,E.CLASS_TABLE);this._bodyEl.appendChild(this._tableEl);G.appendChild(this._bodyEl);};D._initChartDOM=function(){this._chartContainer=document.createElement(&quot;div&quot;);C.addClass(this._chartContainer,E.CLASS_CHART_CONTAINER);var H=docum
 ent.createElement(&quot;div&quot;);C.addClass(H,E.CLASS_CHART_LEGEND);var G=document.createElement(&quot;div&quot;);this._chartLegendEl=document.createElement(&quot;dl&quot;);this._chartLegendEl.innerHTML=&quot;&lt;dd&gt;&quot;+E.STRINGS.initMessage+&quot;&lt;/dd&gt;&quot;;this._chartEl=document.createElement(&quot;div&quot;);C.addClass(this._chartEl,E.CLASS_CHART);var I=document.createElement(&quot;p&quot;);I.innerHTML=E.STRINGS.installFlashMessage;this._chartEl.appendChild(I);this._chartContainer.appendChild(H);H.appendChild(G);G.appendChild(this._chartLegendEl);this._chartContainer.appendChild(this._chartEl);this._bodyEl.insertBefore(this._chartContainer,this._tableEl);};D._createButton=function(I,J,H){var G=document.createElement(&quot;a&quot;);G.innerHTML=G.title=I;if(J){if(!H){J.appendChild(G);}else{J.insertBefore(G,J.firstChild);}}return G;};D._setBusyState=function(G){if(G){C.addClass(this._busyEl,E.CLASS_BUSY);
+this._busy=true;}else{C.removeClass(this._busyEl,E.CLASS_BUSY);this._busy=false;}};D._genSortFunction=function(H,G){var J=H;var I=G;return function(L,K){if(I==YAHOO.widget.DataTable.CLASS_ASC){return L[J]-K[J];}else{return((L[J]-K[J])*-1);}};};var F=function(G){var I=0;for(var H=0;H&lt;G.length;I+=G[H++]){}return I;};D._getProfilerData=function(){var L=B.getFullReport();var N=[];var H=0;for(name in L){if(YAHOO.lang.hasOwnProperty(L,name)){var G=L[name];var I={};I.fn=name;I.points=G.points.slice();I.calls=G.calls;I.min=G.min;I.max=G.max;I.avg=G.avg;I.total=F(I.points);I.points=G.points;var P=this.get(&quot;filter&quot;);if((!P)||(P(I))){N.push(I);H+=I.total;}}}for(var M=0,K=N.length;M&lt;K;M++){N[M].pct=(H)?(N[M].total*100)/H:0;}var O=this.get(&quot;sortedBy&quot;);var Q=O.key;var J=O.dir;N.sort(this._genSortFunction(Q,J));return N;};D._initDataTable=function(){var P=this;this._dataSource=new YAHOO.util.DataSource(function(){return P._getProfilerData.call(P);},{responseType:Y
 AHOO.util.DataSource.TYPE_JSARRAY,maxCacheEntries:0});var H=this._dataSource;H.responseSchema={fields:[&quot;fn&quot;,&quot;avg&quot;,&quot;calls&quot;,&quot;max&quot;,&quot;min&quot;,&quot;total&quot;,&quot;pct&quot;,&quot;points&quot;]};var O=function(S,R,T,U){var Q=(U===Math.floor(U))?U:(Math.round(U*1000))/1000;S.innerHTML=Q+&quot; &quot;+E.STRINGS.millisecondsAbbrev;};var N=function(S,R,T,U){var Q=(U===Math.floor(U))?U:(Math.round(U*100))/100;S.innerHTML=Q+&quot;%&quot;;};var M=YAHOO.widget.DataTable.CLASS_ASC;var J=YAHOO.widget.DataTable.CLASS_DESC;var K=E.STRINGS.colHeads;var I=O;var L=[{key:&quot;fn&quot;,sortable:true,label:K.fn[0],sortOptions:{defaultDir:M},resizeable:(YAHOO.util.DragDrop)?true:false,minWidth:K.fn[1]},{key:&quot;calls&quot;,sortable:true,label:K.calls[0],sortOptions:{defaultDir:J},width:K.calls[1]},{key:&quot;avg&quot;,sortable:true,label:K.avg[0],sortOptions:{defaultDir:J},formatter:I,width:K.avg[1]},{key:&quot;min&quot;,sortable:true,label:K.min[
 0],sortOptions:{defaultDir:M},formatter:I,width:K.min[1]},{key:&quot;max&quot;,sortable:true,label:K.max[0],sortOptions:{defaultDir:J},formatter:I,width:K.max[1]},{key:&quot;total&quot;,sortable:true,label:K.total[0],sortOptions:{defaultDir:J},formatter:I,width:K.total[1]},{key:&quot;pct&quot;,sortable:true,label:K.pct[0],sortOptions:{defaultDir:J},formatter:N,width:K.pct[1]}];this._dataTable=new YAHOO.widget.DataTable(this._tableEl,L,H,{scrollable:true,height:this.get(&quot;tableHeight&quot;),initialRequest:null,sortedBy:{key:&quot;total&quot;,dir:YAHOO.widget.DataTable.CLASS_DESC}});var G=this._dataTable;G.subscribe(&quot;sortedByChange&quot;,this._sortedByChange,this,true);G.subscribe(&quot;renderEvent&quot;,this._dataTableRenderHandler,this,true);G.subscribe(&quot;initEvent&quot;,this._dataTableRenderHandler,this,true);A.on(this._tableEl.getElementsByTagName(&quot;th&quot;),&quot;click&quot;,this._thClickHandler,this,true);};D._sortedByChange=function(G){if(G.newValue&am
 p;&amp;G.newValue.key){this.set(&quot;sortedBy&quot;,{key:G.newValue.key,dir:G.newValue.dir});}};D._dataTableRenderHandler=function(G){this._setBusyState(false);};D._thClickHandler=function(G){this._setBusyState(true);};D._refreshDataTable=function(G){var H=this._dataTable;H.getDataSource().sendRequest(&quot;&quot;,H.onDataReturnInitializeTable,H);};D._refreshChart=function(){switch(this.get(&quot;sortedBy&quot;).key){case&quot;fn&quot;:this._chart.set(&quot;dataSource&quot;,this._chart.get(&quot;dataSource&quot;));return;case&quot;calls&quot;:this._chart.set(&quot;xAxis&quot;,this._chartAxisDefinitionPlain);break;case&quot;pct&quot;:this._chart.set(&quot;xAxis&quot;,this._chartAxisDefinitionPercent);break;default:this._chart.set(&quot;xAxis&quot;,this._chartAxisDefinitionTime);break;}this._drawChartLegend();this._chart.set(&quot;series&quot;,this._getSeriesDef(this.get(&quot;sortedBy&quot;).key));};D._getChartData=function(){var H=this._dataTable.getRecordSet().getRecords(0
 ,this.get(&quot;maxChartFunctions&quot;));var G=[];for(var J=0,I=H.length;J&lt;I;J++){G.push(H[J].getData());}return G;};D._getSeriesDef=function(K){var J=this.get(&quot;chartSeriesDefinitions&quot;)[K];var G=[];for(var I=0,H=J.group.length;I&lt;H;I++){var L=this.get(&quot;chartSeriesDefinitions&quot;)[J.group[I]];G.push({displayName:L.displayName,xField:L.xField,style:{color:L.style.color,size:L.style.size}});}return G;};D._initChart=function(){this._sizeChartCanvas();YAHOO.widget.Chart.SWFURL=this.get(&quot;swfUrl&quot;);var G=this;var H=new YAHOO.util.DataSource(function(){return G._getChartData.call(G);},{responseType:YAHOO.util.DataSource.TYPE_JSARRAY,maxCacheEntries:0});H.responseSchema={fields:[&quot;fn&quot;,&quot;avg&quot;,&quot;calls&quot;,&quot;max&quot;,&quot;min&quot;,&quot;total&quot;,&quot;pct&quot;]};H.subscribe(&quot;responseEvent&quot;,this._sizeChartCanvas,this,true);this._chartAxisDefinitionTime=new YAHOO.widget.NumericAxis();this._chartAxisDefinitionTime
 .labelFunction=&quot;YAHOO.widget.ProfilerViewer.timeAxisLabelFunction&quot;;this._chartAxisDefinitionPercent=new YAHOO.widget.NumericAxis();this._chartAxisDefinitionPercent.labelFunction=&quot;YAHOO.widget.ProfilerViewer.percentAxisLabelFunction&quot;;this._chartAxisDefinitionPlain=new YAHOO.widget.NumericAxis();this._chart=new YAHOO.widget.BarChart(this._chartEl,H,{yField:&quot;fn&quot;,series:this._getSeriesDef(this.get(&quot;sortedBy&quot;).key),style:this.get(&quot;chartStyle&quot;),xAxis:this._chartAxisDefinitionTime});this._drawChartLegend();this._chartInitialized=true;this._dataTable.unsubscribe(&quot;initEvent&quot;,this._initChart,this);this._dataTable.subscribe(&quot;initEvent&quot;,this._refreshChart,this,true);};D._drawChartLegend=function(){var M=this.get(&quot;chartSeriesDefinitions&quot;);var I=M[this.get(&quot;sortedBy&quot;).key];var H=this._chartLegendEl;H.innerHTML=&quot;&quot;;for(var K=0,J=I.group.length;K&lt;J;K++){var N=M[I.group[K]];var L=document.cr
 eateElement(&quot;dt&quot;);C.setStyle(L,&quot;backgroundColor&quot;,&quot;#&quot;+N.style.color);var G=document.createElement(&quot;dd&quot;);G.innerHTML=N.displayName;H.appendChild(L);H.appendChild(G);}};D._sizeChartCanvas=function(I){var G=(I)?I.response.length:this.get(&quot;maxChartFunctions&quot;);var H=(G*36)+34;if(H!=parseInt(this._chartElHeight,10)){this._chartElHeight=H;C.setStyle(this._chartEl,&quot;height&quot;,H+&quot;px&quot;);}};D.initAttributes=function(G){YAHOO.widget.ProfilerViewer.superclass.initAttributes.call(this,G);this.setAttributeConfig(&quot;base&quot;,{value:G.base});this.setAttributeConfig(&quot;tableHeight&quot;,{value:G.tableHeight||&quot;15em&quot;,method:function(H){if(this._dataTable){this._dataTable.set(&quot;height&quot;,H);}}});this.setAttributeConfig(&quot;sortedBy&quot;,{value:G.sortedBy||{key:&quot;total&quot;,dir:&quot;yui-dt-desc&quot;}});
+this.setAttributeConfig(&quot;filter&quot;,{value:G.filter||null,validator:YAHOO.lang.isFunction});this.setAttributeConfig(&quot;swfUrl&quot;,{value:G.swfUrl||&quot;http://yui.yahooapis.com/2.5.0/build/charts/assets/charts.swf&quot;});this.setAttributeConfig(&quot;maxChartFunctions&quot;,{value:G.maxChartFunctions||6,method:function(H){if(this._rendered){this._sizeChartCanvas();}},validator:YAHOO.lang.isNumber});this.setAttributeConfig(&quot;chartStyle&quot;,{value:G.chartStyle||{font:{name:&quot;Arial&quot;,color:15658588,size:12},background:{color:&quot;6e6e63&quot;}},method:function(){if(this._rendered&amp;&amp;this.get(&quot;showChart&quot;)){this._refreshChart();}}});this.setAttributeConfig(&quot;chartSeriesDefinitions&quot;,{value:G.chartSeriesDefinitions||{total:{displayName:E.STRINGS.colHeads.total[0],xField:&quot;total&quot;,style:{color:&quot;4d95dd&quot;,size:20},group:[&quot;total&quot;]},calls:{displayName:E.STRINGS.colHeads.calls[0],xField:&quot;calls&quot;,sty
 le:{color:&quot;edff9f&quot;,size:20},group:[&quot;calls&quot;]},avg:{displayName:E.STRINGS.colHeads.avg[0],xField:&quot;avg&quot;,style:{color:&quot;209daf&quot;,size:9},group:[&quot;avg&quot;,&quot;min&quot;,&quot;max&quot;]},min:{displayName:E.STRINGS.colHeads.min[0],xField:&quot;min&quot;,style:{color:&quot;b6ecf4&quot;,size:9},group:[&quot;avg&quot;,&quot;min&quot;,&quot;max&quot;]},max:{displayName:E.STRINGS.colHeads.max[0],xField:&quot;max&quot;,style:{color:&quot;29c7de&quot;,size:9},group:[&quot;avg&quot;,&quot;min&quot;,&quot;max&quot;]},pct:{displayName:E.STRINGS.colHeads.pct[0],xField:&quot;pct&quot;,style:{color:&quot;C96EDB&quot;,size:20},group:[&quot;pct&quot;]}},method:function(){if(this._rendered&amp;&amp;this.get(&quot;showChart&quot;)){this._refreshChart();}}});this.setAttributeConfig(&quot;visible&quot;,{value:G.visible||false,validator:YAHOO.lang.isBoolean,method:function(H){if(H){this._show();}else{if(this._rendered){this._hide();}}}});this.setAttribute
 Config(&quot;showChart&quot;,{value:G.showChart||true,validator:YAHOO.lang.isBoolean,writeOnce:true});YAHOO.widget.ProfilerViewer.superclass.initAttributes.call(this,G);};})();YAHOO.register(&quot;profilerviewer&quot;,YAHOO.widget.ProfilerViewer,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiprogressbarprogressbarminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/progressbar/progressbar-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/progressbar/progressbar-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/progressbar/progressbar-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,8 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+(function(){var c=YAHOO.util.Dom,i=YAHOO.lang,B=&quot;yui-pb&quot;,D=B+&quot;-mask&quot;,A=B+&quot;-bar&quot;,z=B+&quot;-anim&quot;,q=B+&quot;-tl&quot;,l=B+&quot;-tr&quot;,k=B+&quot;-bl&quot;,g=B+&quot;-br&quot;,h=&quot;width&quot;,w=&quot;height&quot;,m=&quot;minValue&quot;,y=&quot;maxValue&quot;,j=&quot;value&quot;,a=&quot;anim&quot;,x=&quot;direction&quot;,e=&quot;ltr&quot;,t=&quot;rtl&quot;,G=&quot;ttb&quot;,s=&quot;btt&quot;,f=&quot;barEl&quot;,d=&quot;maskEl&quot;,v=&quot;ariaTextTemplate&quot;,n=&quot;animAcceleration&quot;,p=&quot;background-position&quot;,o=&quot;px&quot;,C=&quot;start&quot;,F=&quot;progress&quot;,u=&quot;complete&quot;;var r=function(b){r.superclass.constructor.call(this,document.createElement(&quot;div&quot;),b);this._init(b);};YAHOO.widget.ProgressBar=r;r.MARKUP=['&lt;div class=&quot;',A,'&quot;&gt;&lt;/div&gt;&lt;div class=&quot;',D,'&quot;&gt;&lt;div class=&quot;',q,'&quot;&gt;&lt;/div&gt;&lt;div class=&quot;',l,'&quot;&gt;&lt;/div&gt;&lt;div c
 lass=&quot;',k,'&quot;&gt;&lt;/div&gt;&lt;div class=&quot;',g,'&quot;&gt;&lt;/div&gt;&lt;/div&gt;'].join(&quot;&quot;);i.extend(r,YAHOO.util.Element,{_init:function(b){},initAttributes:function(I){r.superclass.initAttributes.call(this,I);this.set(&quot;innerHTML&quot;,r.MARKUP);this.addClass(B);var H,b=[&quot;id&quot;,h,w,&quot;class&quot;,&quot;style&quot;];while((H=b.pop())){if(H in I){this.set(H,I[H]);}}this.setAttributeConfig(f,{readOnly:true,value:this.getElementsByClassName(A)[0]});this.setAttributeConfig(d,{readOnly:true,value:this.getElementsByClassName(D)[0]});this.setAttributeConfig(x,{value:e,validator:function(J){if(this._rendered){return false;}switch(J){case e:case t:case G:case s:return true;default:return false;}}});this.setAttributeConfig(y,{value:100,validator:i.isNumber,method:function(J){this.get(&quot;element&quot;).setAttribute(&quot;aria-valuemax&quot;,J);if(this.get(j)&gt;J){this.set(j,J);}}});this.setAttributeConfig(m,{value:0,validator:i.isNumber,me
 thod:function(J){this.get(&quot;element&quot;).setAttribute(&quot;aria-valuemin&quot;,J);if(this.get(j)&lt;J){this.set(j,J);}}});this.setAttributeConfig(h,{getter:function(){return this.getStyle(h);},method:this._widthChange});this.setAttributeConfig(w,{getter:function(){return this.getStyle(w);},method:this._heightChange});this.setAttributeConfig(v,{value:&quot;{value}&quot;});this.setAttributeConfig(j,{value:0,validator:function(J){return i.isNumber(J)&amp;&amp;J&gt;=this.get(m)&amp;&amp;J&lt;=this.get(y);},method:this._valueChange});this.setAttributeConfig(a,{validator:function(J){return !!YAHOO.util.Anim;},setter:this._animSetter});this.setAttributeConfig(n,{value:null,validator:function(J){return i.isNumber(J)||i.isNull(J);},method:function(J){this._fixAnim(this.get(a),J);}});},render:function(H,I){if(this._rendered){return;}this._rendered=true;var J=this.get(x);this.addClass(B);this.addClass(B+&quot;-&quot;+J);var b=this.get(&quot;element&quot;);b.tabIndex=0;b.setAttri
 bute(&quot;role&quot;,&quot;progressbar&quot;);b.setAttribute(&quot;aria-valuemin&quot;,this.get(m));b.setAttribute(&quot;aria-valuemax&quot;,this.get(y));this.appendTo(H,I);this.redraw(false);this._previousValue=this.get(j);this._fixEdges();this.on(&quot;minValueChange&quot;,this.redraw);this.on(&quot;maxValueChange&quot;,this.redraw);return this;},redraw:function(b){this._recalculateConstants();this._valueChange(this.get(j),b);},destroy:function(){this.set(a,false);this.unsubscribeAll();var b=this.get(&quot;element&quot;);if(b.parentNode){b.parentNode.removeChild(b);}},_previousValue:0,_barSpace:100,_barFactor:1,_rendered:false,_heightChange:function(b){if(i.isNumber(b)){b+=o;}this.setStyle(w,b);this._fixEdges();this.redraw(false);},_widthChange:function(b){if(i.isNumber(b)){b+=o;}this.setStyle(h,b);this._fixEdges();this.redraw(false);},_fixEdges:function(){if(!this._rendered||YAHOO.env.ua.ie||YAHOO.env.ua.gecko){return;}var J=this.get(d),L=c.getElementsByClassName(q,undef
 ined,J)[0],I=c.getElementsByClassName(l,undefined,J)[0],K=c.getElementsByClassName(k,undefined,J)[0],H=c.getElementsByClassName(g,undefined,J)[0],b=(parseInt(c.getStyle(J,w),10)-parseInt(c.getStyle(L,w),10))+o;c.setStyle(K,w,b);c.setStyle(H,w,b);b=(parseInt(c.getStyle(J,h),10)-parseInt(c.getStyle(L,h),10))+o;c.setStyle(I,h,b);c.setStyle(H,h,b);},_recalculateConstants:function(){var b=this.get(f);switch(this.get(x)){case e:case t:this._barSpace=parseInt(this.get(h),10)-(parseInt(c.getStyle(b,&quot;marginLeft&quot;),10)||0)-(parseInt(c.getStyle(b,&quot;marginRight&quot;),10)||0);break;case G:case s:this._barSpace=parseInt(this.get(w),10)-(parseInt(c.getStyle(b,&quot;marginTop&quot;),10)||0)-(parseInt(c.getStyle(b,&quot;marginBottom&quot;),10)||0);break;}this._barFactor=this._barSpace/(this.get(y)-(this.get(m)||0))||1;},_animSetter:function(I){var H,b=this.get(f);if(I){if(I instanceof YAHOO.util.Anim){H=I;}else{H=new YAHOO.util.Anim(b);}H.onTween.subscribe(this._animOnTween,thi
 s,true);H.onComplete.subscribe(this._animComplete,this,true);this._fixAnim(H,this.get(n));}else{H=this.get(a);if(H){H.onTween.unsubscribeAll();H.onComplete.unsubscribeAll();}H=null;}return H;},_fixAnim:function(I,H){if(I){if(!this._oldSetAttribute){this._oldSetAttribute=I.setAttribute;}var b=this;switch(this.get(x)){case e:I.setAttribute=function(J,L,K){L=Math.round(L);b._oldSetAttribute.call(this,J,L,K);if(J==h){b._oldSetAttribute.call(this,p,-L*H,o);}};break;case t:I.setAttribute=function(J,M,K){M=Math.round(M);b._oldSetAttribute.call(this,J,M,K);if(J==h){var L=b._barSpace-M;b._oldSetAttribute.call(this,&quot;left&quot;,L,o);b._oldSetAttribute.call(this,p,-L+M*H,o);}};break;case G:I.setAttribute=function(J,L,K){L=Math.round(L);b._oldSetAttribute.call(this,J,L,K);if(J==w){b._oldSetAttribute.call(this,p,&quot;center &quot;+(-L*H),o);}};break;case s:I.setAttribute=function(J,M,K){M=Math.round(M);b._oldSetAttribute.call(this,J,M,K);if(J==w){var L=b._barSpace-M;b._oldSetAttribu
 te.call(this,&quot;top&quot;,L,o);b._oldSetAttribute.call(this,p,&quot;center &quot;+(M*H-L),o);}};break;}}},_animComplete:function(){var b=this.get(j);this._previousValue=b;this.fireEvent(F,b);this.fireEvent(u,b);c.removeClass(this.get(f),z);},_animOnTween:function(b,H){var I=Math.floor(this._tweenFactor*H[0].currentFrame+this._previousValue);this.fireEvent(F,I);},_valueChange:function(J,H){var I=this.get(a),b=Math.floor((J-this.get(m))*this._barFactor);this._setAriaText(J);if(this._rendered){if(I){I.stop();if(I.isAnimated()){I._onComplete.fire();}}this.fireEvent(C,this._previousValue);r._barSizeFunctions[((H!==false)&amp;&amp;I)?1:0][this.get(x)].call(this,J,b,this.get(f),I);}},_setAriaText:function(H){var b=this.get(&quot;element&quot;),I=i.substitute(this.get(v),{value:H,minValue:this.get(m),maxValue:this.get(y)});
+b.setAttribute(&quot;aria-valuenow&quot;,H);b.setAttribute(&quot;aria-valuetext&quot;,I);}});var E=[{},{}];r._barSizeFunctions=E;E[0][e]=function(J,b,H,I){c.setStyle(H,h,b+o);this.fireEvent(F,J);this.fireEvent(u,J);};E[0][t]=function(J,b,H,I){c.setStyle(H,h,b+o);c.setStyle(H,&quot;left&quot;,(this._barSpace-b)+o);this.fireEvent(F,J);this.fireEvent(u,J);};E[0][G]=function(J,b,H,I){c.setStyle(H,w,b+o);this.fireEvent(F,J);this.fireEvent(u,J);};E[0][s]=function(J,b,H,I){c.setStyle(H,w,b+o);c.setStyle(H,&quot;top&quot;,(this._barSpace-b)+o);this.fireEvent(F,J);this.fireEvent(u,J);};E[1][e]=function(J,b,H,I){c.addClass(H,z);this._tweenFactor=(J-this._previousValue)/I.totalFrames/I.duration;I.attributes={width:{to:b}};I.animate();};E[1][t]=E[1][e];E[1][G]=function(J,b,H,I){c.addClass(H,z);this._tweenFactor=(J-this._previousValue)/I.totalFrames/I.duration;I.attributes={height:{to:b}};I.animate();};E[1][s]=E[1][G];})();YAHOO.register(&quot;progressbar&quot;,YAHOO.widget.ProgressBar,{
 version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiresetresetmincss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/reset/reset-min.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/reset/reset-min.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/reset/reset-min.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+html{color:#000;background:#FFF}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,select,p,blockquote,th,td{margin:0;padding:0}table{border-collapse:collapse;border-spacing:0}fieldset,img{border:0}address,button,caption,cite,code,dfn,em,input,optgroup,option,select,strong,textarea,th,var{font:inherit}del,ins{text-decoration:none}li{list-style:none}caption,th{text-align:left}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal}q:before,q:after{content:''}abbr,acronym{border:0;font-variant:normal}sup{vertical-align:baseline}sub{vertical-align:baseline}legend{color:#000}
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiresetresetcss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/reset/reset.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/reset/reset.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/reset/reset.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,123 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+/**
+ * YUI Reset
+ * @module reset
+ * @namespace
+ * @requires 
+ */
+html {
+        color: #000;
+        background: #FFF;
+}
+
+body,
+div,
+dl,
+dt,
+dd,
+ul,
+ol,
+li,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+pre,
+code,
+form,
+fieldset,
+legend,
+input,
+button,
+textarea,
+select,
+p,
+blockquote,
+th,
+td {
+        margin: 0;
+        padding: 0;
+}
+
+table {
+        border-collapse: collapse;
+        border-spacing: 0;
+}
+
+fieldset,
+img {
+        border: 0;
+}
+
+address,
+button,
+caption,
+cite,
+code,
+dfn,
+em,
+input,
+optgroup,
+option,
+select,
+strong,
+textarea,
+th,
+var {
+    font:inherit;
+}
+
+del,
+ins {
+        text-decoration: none;
+}
+
+li {
+        list-style: none;
+}
+
+caption,
+th {
+        text-align: left;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+        font-size: 100%;
+        font-weight: normal;
+}
+
+q:before,
+q:after {
+        content: '';
+}
+
+abbr,
+acronym {
+        border: 0;
+        font-variant: normal;
+}
+
+sup {
+        vertical-align: baseline;
+}
+
+sub {
+        vertical-align: baseline;
+}
+
+/*because legend doesn't inherit in IE */
+legend {
+        color: #000;
+}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiresetfontsresetfontscss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/reset-fonts/reset-fonts.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/reset-fonts/reset-fonts.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/reset-fonts/reset-fonts.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+html{color:#000;background:#FFF}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,select,p,blockquote,th,td{margin:0;padding:0}table{border-collapse:collapse;border-spacing:0}fieldset,img{border:0}address,button,caption,cite,code,dfn,em,input,optgroup,option,select,strong,textarea,th,var{font:inherit}del,ins{text-decoration:none}li{list-style:none}caption,th{text-align:left}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal}q:before,q:after{content:''}abbr,acronym{border:0;font-variant:normal}sup{vertical-align:baseline}sub{vertical-align:baseline}legend{color:#000}body{font:13px/1.231 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small}select,input,textarea,button{font:99% arial,helvetica,clean,sans-serif}table{font-size:inherit;font:100%}pre,code,kbd,samp,tt{font-family:monospace;*font-size:108%;line-height:100%}
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiresetfontsgridsresetfontsgridscss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/reset-fonts-grids/reset-fonts-grids.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/reset-fonts-grids/reset-fonts-grids.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/reset-fonts-grids/reset-fonts-grids.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+html{color:#000;background:#FFF}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,button,textarea,select,p,blockquote,th,td{margin:0;padding:0}table{border-collapse:collapse;border-spacing:0}fieldset,img{border:0}address,button,caption,cite,code,dfn,em,input,optgroup,option,select,strong,textarea,th,var{font:inherit}del,ins{text-decoration:none}li{list-style:none}caption,th{text-align:left}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal}q:before,q:after{content:''}abbr,acronym{border:0;font-variant:normal}sup{vertical-align:baseline}sub{vertical-align:baseline}legend{color:#000}body{font:13px/1.231 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small}select,input,textarea,button{font:99% arial,helvetica,clean,sans-serif}table{font-size:inherit;font:100%}pre,code,kbd,samp,tt{font-family:monospace;*font-size:108%;line-height:100%}body{text-align:center}#doc,#doc2,#doc3,#doc4,.yui-t1,.yui-t2,.yui-t3,.yui-t4,.yui-t5,.yui-t6,.yui-t7{m
 argin:auto;text-align:left;width:57.69em;*width:56.25em}#doc2{width:73.076em;*width:71.25em}#doc3{margin:auto 10px;width:auto}#doc4{width:74.923em;*width:73.05em}.yui-b{position:relative}.yui-b{_position:static}#yui-main .yui-b{position:static}#yui-main,.yui-g .yui-u .yui-g{width:100%}.yui-t1 #yui-main,.yui-t2 #yui-main,.yui-t3 #yui-main{float:right;margin-left:-25em}.yui-t4 #yui-main,.yui-t5 #yui-main,.yui-t6 #yui-main{float:left;margin-right:-25em}.yui-t1 .yui-b{float:left;width:12.30769em;*width:12.00em}.yui-t1 #yui-main .yui-b{margin-left:13.30769em;*margin-left:13.05em}.yui-t2 .yui-b{float:left;width:13.8461em;*width:13.50em}.yui-t2 #yui-main .yui-b{margin-left:14.8461em;*margin-left:14.55em}.yui-t3 .yui-b{float:left;width:23.0769em;*width:22.50em}.yui-t3 #yui-main .yui-b{margin-left:24.0769em;*margin-left:23.62em}.yui-t4 .yui-b{float:right;width:13.8456em;*width:13.50em}.yui-t4 #yui-main .yui-b{margin-right:14.8456em;*margin-right:14.55em}.yui-t5 .yui-b{float:right;wid
 th:18.4615em;*width:18.00em}.yui-t5 #yui-main .yui-b{margin-right:19.4615em;*margin-right:19.125em}.yui-t6 .yui-b{float:right;width:23.0769em;*width:22.50em}.yui-t6 #yui-main .yui-b{margin-right:24.0769em;*margin-right:23.62em}.yui-t7 #yui-main .yui-b{display:block;margin:0 0 1em 0}#yui-main .yui-b{float:none;width:auto}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{float:left}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-gc,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf,.yui-gc .yui-u,.yui-gd .yui-g,.yui-g .yui-gc .yui-u,.yui-ge .yui-u,.yui-ge .yui-g,.yui-gf .yui-g,.yui-gf .yui-u{float:right}.yui-g div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first,.yui-ge div.first,.yui-gf div.first,.yui-g .yui-gc div.first,.yui-g .yui-ge div.first,.yui-gc div.first div.first{float:left}.yui-g .yui-u,.yui-g .yui-g,.yui-g .yui-gb,.yui-g .yui-g
 c,.yui-g .yui-gd,.yui-g .yui-ge,.yui-g .yui-gf{width:49.1%}.yui-gb .yui-u,.yui-g .yui-gb .yui-u,.yui-gb .yui-g,.yui-gb .yui-gb,.yui-gb .yui-gc,.yui-gb .yui-gd,.yui-gb .yui-ge,.yui-gb .yui-gf,.yui-gc .yui-u,.yui-gc .yui-g,.yui-gd .yui-u{width:32%;margin-left:1.99%}.yui-gb .yui-u{*margin-left:1.9%;*width:31.9%}.yui-gc div.first,.yui-gd .yui-u{width:66%}.yui-gd div.first{width:32%}.yui-ge div.first,.yui-gf .yui-u{width:74.2%}.yui-ge .yui-u,.yui-gf div.first{width:24%}.yui-g .yui-gb div.first,.yui-gb div.first,.yui-gc div.first,.yui-gd div.first{margin-left:0}.yui-g .yui-g .yui-u,.yui-gb .yui-g .yui-u,.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u,.yui-ge .yui-g .yui-u,.yui-gf .yui-g .yui-u{width:49%;*width:48.1%;*margin-left:0}.yui-g .yui-g .yui-u{width:48.1%}.yui-g .yui-gb div.first,.yui-gb .yui-gb div.first{*margin-right:0;*width:32%;_width:31.7%}.yui-g .yui-gc div.first,.yui-gd .yui-g{width:66%}.yui-gb .yui-g div.first{*margin-right:4%;_margin-right:1.3%}.yui-gb .yui-gc div.fir
 st,.yui-gb .yui-gd div.first{*margin-right:0}.yui-gb .yui-gb .yui-u,.yui-gb .yui-gc .yui-u{*margin-left:1.8%;_margin-left:4%}.yui-g .yui-gb .yui-u{_margin-left:1.0%}.yui-gb .yui-gd .yui-u{*width:66%;_width:61.2%}.yui-gb .yui-gd div.first{*width:31%;_width:29.5%}.yui-g .yui-gc .yui-u,.yui-gb .yui-gc .yui-u{width:32%;_float:right;margin-right:0;_margin-left:0}.yui-gb .yui-gc div.first{width:66%;*float:left;*margin-left:0}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf .yui-u{margin:0}.yui-gb .yui-gb .yui-u{_margin-left:.7%}.yui-gb .yui-g div.first,.yui-gb .yui-gb div.first{*margin-left:0}.yui-gc .yui-g .yui-u,.yui-gd .yui-g .yui-u{*width:48.1%;*margin-left:0}.yui-gb .yui-gd div.first{width:32%}.yui-g .yui-gd div.first{_width:29.9%}.yui-ge .yui-g{width:24%}.yui-gf .yui-g{width:74.2%}.yui-gb .yui-ge div.yui-u,.yui-gb .yui-gf div.yui-u{float:right}.yui-gb .yui-ge div.first,.yui-gb .yui-gf div.first{float:left}.yui-gb .yui-ge .yui-u,.yui-gb .yui-gf div.first{*width:24%;_width:20%}.yui-gb .
 yui-ge div.first,.yui-gb .yui-gf .yui-u{*width:73.5%;_width:65.5%}.yui-ge div.first .yui-gd .yui-u{width:65%}.yui-ge div.first .yui-gd div.first{width:32%}#hd:after,#bd:after,#ft:after,.yui-g:after,.yui-gb:after,.yui-gc:after,.yui-gd:after,.yui-ge:after,.yui-gf:after{content:&quot;&quot;;display:block;clear:both}#hd,#bd,#ft,.yui-g,.yui-gb,.yui-gc,.yui-gd,.yui-ge,.yui-gf{zoom:1}
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiresizeresizeminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/resize/resize-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/resize/resize-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/resize/resize-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,10 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+(function(){var E=YAHOO.util.Dom,A=YAHOO.util.Event,C=YAHOO.lang;var B=function(F,D){var G={element:F,attributes:D||{}};B.superclass.constructor.call(this,G.element,G.attributes);};B._instances={};B.getResizeById=function(D){if(B._instances[D]){return B._instances[D];}return false;};YAHOO.extend(B,YAHOO.util.Element,{CSS_RESIZE:&quot;yui-resize&quot;,CSS_DRAG:&quot;yui-draggable&quot;,CSS_HOVER:&quot;yui-resize-hover&quot;,CSS_PROXY:&quot;yui-resize-proxy&quot;,CSS_WRAP:&quot;yui-resize-wrap&quot;,CSS_KNOB:&quot;yui-resize-knob&quot;,CSS_HIDDEN:&quot;yui-resize-hidden&quot;,CSS_HANDLE:&quot;yui-resize-handle&quot;,CSS_STATUS:&quot;yui-resize-status&quot;,CSS_GHOST:&quot;yui-resize-ghost&quot;,CSS_RESIZING:&quot;yui-resize-resizing&quot;,_resizeEvent:null,dd:null,browser:YAHOO.env.ua,_locked:null,_positioned:null,_dds:null,_wrap:null,_proxy:null,_handles:null,_currentHandle:null,_currentDD:null,_cache:null,_active:null,_createProxy:function(){if(this.get(&quot;proxy&quot;)){t
 his._proxy=document.createElement(&quot;div&quot;);this._proxy.className=this.CSS_PROXY;this._proxy.style.height=this.get(&quot;element&quot;).clientHeight+&quot;px&quot;;this._proxy.style.width=this.get(&quot;element&quot;).clientWidth+&quot;px&quot;;this._wrap.parentNode.appendChild(this._proxy);}else{this.set(&quot;animate&quot;,false);}},_createWrap:function(){this._positioned=false;if(this.get(&quot;wrap&quot;)===false){switch(this.get(&quot;element&quot;).tagName.toLowerCase()){case&quot;img&quot;:case&quot;textarea&quot;:case&quot;input&quot;:case&quot;iframe&quot;:case&quot;select&quot;:this.set(&quot;wrap&quot;,true);break;}}if(this.get(&quot;wrap&quot;)===true){this._wrap=document.createElement(&quot;div&quot;);this._wrap.id=this.get(&quot;element&quot;).id+&quot;_wrap&quot;;this._wrap.className=this.CSS_WRAP;if(this.get(&quot;element&quot;).tagName.toLowerCase()==&quot;textarea&quot;){E.addClass(this._wrap,&quot;yui-resize-textarea&quot;);}E.setStyle(this._wrap,&q
 uot;width&quot;,this.get(&quot;width&quot;)+&quot;px&quot;);E.setStyle(this._wrap,&quot;height&quot;,this.get(&quot;height&quot;)+&quot;px&quot;);E.setStyle(this._wrap,&quot;z-index&quot;,this.getStyle(&quot;z-index&quot;));this.setStyle(&quot;z-index&quot;,0);var F=E.getStyle(this.get(&quot;element&quot;),&quot;position&quot;);E.setStyle(this._wrap,&quot;position&quot;,((F==&quot;static&quot;)?&quot;relative&quot;:F));E.setStyle(this._wrap,&quot;top&quot;,E.getStyle(this.get(&quot;element&quot;),&quot;top&quot;));E.setStyle(this._wrap,&quot;left&quot;,E.getStyle(this.get(&quot;element&quot;),&quot;left&quot;));if(E.getStyle(this.get(&quot;element&quot;),&quot;position&quot;)==&quot;absolute&quot;){this._positioned=true;E.setStyle(this.get(&quot;element&quot;),&quot;position&quot;,&quot;relative&quot;);E.setStyle(this.get(&quot;element&quot;),&quot;top&quot;,&quot;0&quot;);E.setStyle(this.get(&quot;element&quot;),&quot;left&quot;,&quot;0&quot;);}var D=this.get(&quot;element&
 quot;).parentNode;D.replaceChild(this._wrap,this.get(&quot;element&quot;));this._wrap.appendChild(this.get(&quot;element&quot;));}else{this._wrap=this.get(&quot;element&quot;);if(E.getStyle(this._wrap,&quot;position&quot;)==&quot;absolute&quot;){this._positioned=true;}}if(this.get(&quot;draggable&quot;)){this._setupDragDrop();}if(this.get(&quot;hover&quot;)){E.addClass(this._wrap,this.CSS_HOVER);}if(this.get(&quot;knobHandles&quot;)){E.addClass(this._wrap,this.CSS_KNOB);}if(this.get(&quot;hiddenHandles&quot;)){E.addClass(this._wrap,this.CSS_HIDDEN);}E.addClass(this._wrap,this.CSS_RESIZE);},_setupDragDrop:function(){E.addClass(this._wrap,this.CSS_DRAG);this.dd=new YAHOO.util.DD(this._wrap,this.get(&quot;id&quot;)+&quot;-resize&quot;,{dragOnly:true,useShim:this.get(&quot;useShim&quot;)});this.dd.on(&quot;dragEvent&quot;,function(){this.fireEvent(&quot;dragEvent&quot;,arguments);},this,true);},_createHandles:function(){this._handles={};this._dds={};var G=this.get(&quot;handles&
 quot;);for(var F=0;F&lt;G.length;F++){this._handles[G[F]]=document.createElement(&quot;div&quot;);this._handles[G[F]].id=E.generateId(this._handles[G[F]]);this._handles[G[F]].className=this.CSS_HANDLE+&quot; &quot;+this.CSS_HANDLE+&quot;-&quot;+G[F];var D=document.createElement(&quot;div&quot;);D.className=this.CSS_HANDLE+&quot;-inner-&quot;+G[F];this._handles[G[F]].appendChild(D);this._wrap.appendChild(this._handles[G[F]]);A.on(this._handles[G[F]],&quot;mouseover&quot;,this._handleMouseOver,this,true);A.on(this._handles[G[F]],&quot;mouseout&quot;,this._handleMouseOut,this,true);this._dds[G[F]]=new YAHOO.util.DragDrop(this._handles[G[F]],this.get(&quot;id&quot;)+&quot;-handle-&quot;+G,{useShim:this.get(&quot;useShim&quot;)});this._dds[G[F]].setPadding(15,15,15,15);this._dds[G[F]].on(&quot;startDragEvent&quot;,this._handleStartDrag,this._dds[G[F]],this);this._dds[G[F]].on(&quot;mouseDownEvent&quot;,this._handleMouseDown,this._dds[G[F]],this);}this._status=document.createEleme
 nt(&quot;span&quot;);this._status.className=this.CSS_STATUS;document.body.insertBefore(this._status,document.body.firstChild);},_ieSelectFix:function(){return false;},_ieSelectBack:null,_setAutoRatio:function(D){if(this.get(&quot;autoRatio&quot;)){if(D&amp;&amp;D.shiftKey){this.set(&quot;ratio&quot;,true);}else{this.set(&quot;ratio&quot;,this._configs.ratio._initialConfig.value);}}},_handleMouseDown:function(D){if(this._locked){return false;}if(E.getStyle(this._wrap,&quot;position&quot;)==&quot;absolute&quot;){this._positioned=true;}if(D){this._setAutoRatio(D);}if(this.browser.ie){this._ieSelectBack=document.body.onselectstart;document.body.onselectstart=this._ieSelectFix;}},_handleMouseOver:function(G){if(this._locked){return false;}E.removeClass(this._wrap,this.CSS_RESIZE);if(this.get(&quot;hover&quot;)){E.removeClass(this._wrap,this.CSS_HOVER);}var D=A.getTarget(G);if(!E.hasClass(D,this.CSS_HANDLE)){D=D.parentNode;}if(E.hasClass(D,this.CSS_HANDLE)&amp;&amp;!this._active){
 E.addClass(D,this.CSS_HANDLE+&quot;-active&quot;);for(var F in this._handles){if(C.hasOwnProperty(this._handles,F)){if(this._handles[F]==D){E.addClass(D,this.CSS_HANDLE+&quot;-&quot;+F+&quot;-active&quot;);break;}}}}E.addClass(this._wrap,this.CSS_RESIZE);},_handleMouseOut:function(G){E.removeClass(this._wrap,this.CSS_RESIZE);if(this.get(&quot;hover&quot;)&amp;&amp;!this._active){E.addClass(this._wrap,this.CSS_HOVER);}var D=A.getTarget(G);if(!E.hasClass(D,this.CSS_HANDLE)){D=D.parentNode;}if(E.hasClass(D,this.CSS_HANDLE)&amp;&amp;!this._active){E.removeClass(D,this.CSS_HANDLE+&quot;-active&quot;);for(var F in this._handles){if(C.hasOwnProperty(this._handles,F)){if(this._handles[F]==D){E.removeClass(D,this.CSS_HANDLE+&quot;-&quot;+F+&quot;-active&quot;);break;}}}}E.addClass(this._wrap,this.CSS_RESIZE);},_handleStartDrag:function(G,F){var D=F.getDragEl();if(E.hasClass(D,this.CSS_HANDLE)){if(E.getStyle(this._wrap,&quot;position&quot;)==&quot;absolute&quot;){this._positioned=true
 ;}this._active=true;this._currentDD=F;if(this._proxy){this._proxy.style.visibility=&quot;visible&quot;;this._proxy.style.zIndex=&quot;1000&quot;;this._proxy.style.height=this.get(&quot;element&quot;).clientHeight+&quot;px&quot;;this._proxy.style.width=this.get(&quot;element&quot;).clientWidth+&quot;px&quot;;
+}for(var H in this._handles){if(C.hasOwnProperty(this._handles,H)){if(this._handles[H]==D){this._currentHandle=H;var I=&quot;_handle_for_&quot;+H;E.addClass(D,this.CSS_HANDLE+&quot;-&quot;+H+&quot;-active&quot;);F.on(&quot;dragEvent&quot;,this[I],this,true);F.on(&quot;mouseUpEvent&quot;,this._handleMouseUp,this,true);break;}}}E.addClass(D,this.CSS_HANDLE+&quot;-active&quot;);if(this.get(&quot;proxy&quot;)){var J=E.getXY(this.get(&quot;element&quot;));E.setXY(this._proxy,J);if(this.get(&quot;ghost&quot;)){this.addClass(this.CSS_GHOST);}}E.addClass(this._wrap,this.CSS_RESIZING);this._setCache();this._updateStatus(this._cache.height,this._cache.width,this._cache.top,this._cache.left);this.fireEvent(&quot;startResize&quot;,{type:&quot;startresize&quot;,target:this});}},_setCache:function(){this._cache.xy=E.getXY(this._wrap);E.setXY(this._wrap,this._cache.xy);this._cache.height=this.get(&quot;clientHeight&quot;);this._cache.width=this.get(&quot;clientWidth&quot;);this._cache.star
 t.height=this._cache.height;this._cache.start.width=this._cache.width;this._cache.start.top=this._cache.xy[1];this._cache.start.left=this._cache.xy[0];this._cache.top=this._cache.xy[1];this._cache.left=this._cache.xy[0];this.set(&quot;height&quot;,this._cache.height,true);this.set(&quot;width&quot;,this._cache.width,true);},_handleMouseUp:function(F){this._active=false;var G=&quot;_handle_for_&quot;+this._currentHandle;this._currentDD.unsubscribe(&quot;dragEvent&quot;,this[G],this,true);this._currentDD.unsubscribe(&quot;mouseUpEvent&quot;,this._handleMouseUp,this,true);if(this._proxy){this._proxy.style.visibility=&quot;hidden&quot;;this._proxy.style.zIndex=&quot;-1&quot;;if(this.get(&quot;setSize&quot;)){this.resize(F,this._cache.height,this._cache.width,this._cache.top,this._cache.left,true);}else{this.fireEvent(&quot;resize&quot;,{ev:&quot;resize&quot;,target:this,height:this._cache.height,width:this._cache.width,top:this._cache.top,left:this._cache.left});}if(this.get(&qu
 ot;ghost&quot;)){this.removeClass(this.CSS_GHOST);}}if(this.get(&quot;hover&quot;)){E.addClass(this._wrap,this.CSS_HOVER);}if(this._status){E.setStyle(this._status,&quot;display&quot;,&quot;none&quot;);}if(this.browser.ie){document.body.onselectstart=this._ieSelectBack;}if(this.browser.ie){E.removeClass(this._wrap,this.CSS_RESIZE);}for(var D in this._handles){if(C.hasOwnProperty(this._handles,D)){E.removeClass(this._handles[D],this.CSS_HANDLE+&quot;-active&quot;);}}if(this.get(&quot;hover&quot;)&amp;&amp;!this._active){E.addClass(this._wrap,this.CSS_HOVER);}E.removeClass(this._wrap,this.CSS_RESIZING);E.removeClass(this._handles[this._currentHandle],this.CSS_HANDLE+&quot;-&quot;+this._currentHandle+&quot;-active&quot;);E.removeClass(this._handles[this._currentHandle],this.CSS_HANDLE+&quot;-active&quot;);if(this.browser.ie){E.addClass(this._wrap,this.CSS_RESIZE);}this._resizeEvent=null;this._currentHandle=null;if(!this.get(&quot;animate&quot;)){this.set(&quot;height&quot;,this
 ._cache.height,true);this.set(&quot;width&quot;,this._cache.width,true);}this.fireEvent(&quot;endResize&quot;,{ev:&quot;endResize&quot;,target:this,height:this._cache.height,width:this._cache.width,top:this._cache.top,left:this._cache.left});},_setRatio:function(K,N,Q,I){var O=K,G=N;if(this.get(&quot;ratio&quot;)){var P=this._cache.height,H=this._cache.width,F=parseInt(this.get(&quot;height&quot;),10),L=parseInt(this.get(&quot;width&quot;),10),M=this.get(&quot;maxHeight&quot;),R=this.get(&quot;minHeight&quot;),D=this.get(&quot;maxWidth&quot;),J=this.get(&quot;minWidth&quot;);switch(this._currentHandle){case&quot;l&quot;:K=F*(N/L);K=Math.min(Math.max(R,K),M);N=L*(K/F);Q=(this._cache.start.top-(-((F-K)/2)));I=(this._cache.start.left-(-((L-N))));break;case&quot;r&quot;:K=F*(N/L);K=Math.min(Math.max(R,K),M);N=L*(K/F);Q=(this._cache.start.top-(-((F-K)/2)));break;case&quot;t&quot;:N=L*(K/F);K=F*(N/L);I=(this._cache.start.left-(-((L-N)/2)));Q=(this._cache.start.top-(-((F-K))));brea
 k;case&quot;b&quot;:N=L*(K/F);K=F*(N/L);I=(this._cache.start.left-(-((L-N)/2)));break;case&quot;bl&quot;:K=F*(N/L);N=L*(K/F);I=(this._cache.start.left-(-((L-N))));break;case&quot;br&quot;:K=F*(N/L);N=L*(K/F);break;case&quot;tl&quot;:K=F*(N/L);N=L*(K/F);I=(this._cache.start.left-(-((L-N))));Q=(this._cache.start.top-(-((F-K))));break;case&quot;tr&quot;:K=F*(N/L);N=L*(K/F);I=(this._cache.start.left);Q=(this._cache.start.top-(-((F-K))));break;}O=this._checkHeight(K);G=this._checkWidth(N);if((O!=K)||(G!=N)){Q=0;I=0;if(O!=K){G=this._cache.width;}if(G!=N){O=this._cache.height;}}}return[O,G,Q,I];},_updateStatus:function(K,G,J,F){if(this._resizeEvent&amp;&amp;(!C.isString(this._resizeEvent))){K=((K===0)?this._cache.start.height:K);G=((G===0)?this._cache.start.width:G);var I=parseInt(this.get(&quot;height&quot;),10),D=parseInt(this.get(&quot;width&quot;),10);if(isNaN(I)){I=parseInt(K,10);}if(isNaN(D)){D=parseInt(G,10);}var L=(parseInt(K,10)-I);var H=(parseInt(G,10)-D);this._cache.offs
 etHeight=L;this._cache.offsetWidth=H;if(this.get(&quot;status&quot;)){E.setStyle(this._status,&quot;display&quot;,&quot;inline&quot;);this._status.innerHTML=&quot;&lt;strong&gt;&quot;+parseInt(K,10)+&quot; x &quot;+parseInt(G,10)+&quot;&lt;/strong&gt;&lt;em&gt;&quot;+((L&gt;0)?&quot;+&quot;:&quot;&quot;)+L+&quot; x &quot;+((H&gt;0)?&quot;+&quot;:&quot;&quot;)+H+&quot;&lt;/em&gt;&quot;;E.setXY(this._status,[A.getPageX(this._resizeEvent)+12,A.getPageY(this._resizeEvent)+12]);}}},lock:function(D){this._locked=true;if(D&amp;&amp;this.dd){E.removeClass(this._wrap,&quot;yui-draggable&quot;);this.dd.lock();}return this;},unlock:function(D){this._locked=false;if(D&amp;&amp;this.dd){E.addClass(this._wrap,&quot;yui-draggable&quot;);this.dd.unlock();}return this;},isLocked:function(){return this._locked;},reset:function(){this.resize(null,this._cache.start.height,this._cache.start.width,this._cache.start.top,this._cache.start.left,true);return this;},resize:function(M,J,P,Q,H,F,K){if(t
 his._locked){return false;}this._resizeEvent=M;var G=this._wrap,I=this.get(&quot;animate&quot;),O=true;if(this._proxy&amp;&amp;!F){G=this._proxy;I=false;}this._setAutoRatio(M);if(this._positioned){if(this._proxy){Q=this._cache.top-Q;H=this._cache.left-H;}}var L=this._setRatio(J,P,Q,H);J=parseInt(L[0],10);P=parseInt(L[1],10);Q=parseInt(L[2],10);H=parseInt(L[3],10);if(Q==0){Q=E.getY(G);}if(H==0){H=E.getX(G);}if(this._positioned){if(this._proxy&amp;&amp;F){if(!I){G.style.top=this._proxy.style.top;G.style.left=this._proxy.style.left;}else{Q=this._proxy.style.top;H=this._proxy.style.left;}}else{if(!this.get(&quot;ratio&quot;)&amp;&amp;!this._proxy){Q=this._cache.top+-(Q);H=this._cache.left+-(H);}if(Q){if(this.get(&quot;minY&quot;)){if(Q&lt;this.get(&quot;minY&quot;)){Q=this.get(&quot;minY&quot;);}}if(this.get(&quot;maxY&quot;)){if(Q&gt;this.get(&quot;maxY&quot;)){Q=this.get(&quot;maxY&quot;);}}}if(H){if(this.get(&quot;minX&quot;)){if(H&lt;this.get(&quot;minX&quot;)){H=this.get(&q
 uot;minX&quot;);
+}}if(this.get(&quot;maxX&quot;)){if((H+P)&gt;this.get(&quot;maxX&quot;)){H=(this.get(&quot;maxX&quot;)-P);}}}}}if(!K){var N=this.fireEvent(&quot;beforeResize&quot;,{ev:&quot;beforeResize&quot;,target:this,height:J,width:P,top:Q,left:H});if(N===false){return false;}}this._updateStatus(J,P,Q,H);if(this._positioned){if(this._proxy&amp;&amp;F){}else{if(Q){E.setY(G,Q);this._cache.top=Q;}if(H){E.setX(G,H);this._cache.left=H;}}}if(J){if(!I){O=true;if(this._proxy&amp;&amp;F){if(!this.get(&quot;setSize&quot;)){O=false;}}if(O){G.style.height=J+&quot;px&quot;;}if((this._proxy&amp;&amp;F)||!this._proxy){if(this._wrap!=this.get(&quot;element&quot;)){this.get(&quot;element&quot;).style.height=J+&quot;px&quot;;}}}this._cache.height=J;}if(P){this._cache.width=P;if(!I){O=true;if(this._proxy&amp;&amp;F){if(!this.get(&quot;setSize&quot;)){O=false;}}if(O){G.style.width=P+&quot;px&quot;;}if((this._proxy&amp;&amp;F)||!this._proxy){if(this._wrap!=this.get(&quot;element&quot;)){this.get(&quot;eleme
 nt&quot;).style.width=P+&quot;px&quot;;}}}}if(I){if(YAHOO.util.Anim){var D=new YAHOO.util.Anim(G,{height:{to:this._cache.height},width:{to:this._cache.width}},this.get(&quot;animateDuration&quot;),this.get(&quot;animateEasing&quot;));if(this._positioned){if(Q){D.attributes.top={to:parseInt(Q,10)};}if(H){D.attributes.left={to:parseInt(H,10)};}}if(this._wrap!=this.get(&quot;element&quot;)){D.onTween.subscribe(function(){this.get(&quot;element&quot;).style.height=G.style.height;this.get(&quot;element&quot;).style.width=G.style.width;},this,true);}D.onComplete.subscribe(function(){this.set(&quot;height&quot;,J);this.set(&quot;width&quot;,P);this.fireEvent(&quot;resize&quot;,{ev:&quot;resize&quot;,target:this,height:J,width:P,top:Q,left:H});},this,true);D.animate();}}else{if(this._proxy&amp;&amp;!F){this.fireEvent(&quot;proxyResize&quot;,{ev:&quot;proxyresize&quot;,target:this,height:J,width:P,top:Q,left:H});}else{this.fireEvent(&quot;resize&quot;,{ev:&quot;resize&quot;,target:th
 is,height:J,width:P,top:Q,left:H});}}return this;},_handle_for_br:function(F){var G=this._setWidth(F.e);var D=this._setHeight(F.e);this.resize(F.e,D,G,0,0);},_handle_for_bl:function(G){var H=this._setWidth(G.e,true);var F=this._setHeight(G.e);var D=(H-this._cache.width);this.resize(G.e,F,H,0,D);},_handle_for_tl:function(G){var I=this._setWidth(G.e,true);var F=this._setHeight(G.e,true);var H=(F-this._cache.height);var D=(I-this._cache.width);this.resize(G.e,F,I,H,D);},_handle_for_tr:function(F){var H=this._setWidth(F.e);var D=this._setHeight(F.e,true);var G=(D-this._cache.height);this.resize(F.e,D,H,G,0);},_handle_for_r:function(D){this._dds.r.setYConstraint(0,0);var F=this._setWidth(D.e);this.resize(D.e,0,F,0,0);},_handle_for_l:function(F){this._dds.l.setYConstraint(0,0);var G=this._setWidth(F.e,true);var D=(G-this._cache.width);this.resize(F.e,0,G,0,D);},_handle_for_b:function(F){this._dds.b.setXConstraint(0,0);var D=this._setHeight(F.e);this.resize(F.e,D,0,0,0);},_handle_f
 or_t:function(F){this._dds.t.setXConstraint(0,0);var D=this._setHeight(F.e,true);var G=(D-this._cache.height);this.resize(F.e,D,0,G,0);},_setWidth:function(H,J){var I=this._cache.xy[0],G=this._cache.width,D=A.getPageX(H),F=(D-I);if(J){F=(I-D)+parseInt(this.get(&quot;width&quot;),10);}F=this._snapTick(F,this.get(&quot;xTicks&quot;));F=this._checkWidth(F);return F;},_checkWidth:function(D){if(this.get(&quot;minWidth&quot;)){if(D&lt;=this.get(&quot;minWidth&quot;)){D=this.get(&quot;minWidth&quot;);}}if(this.get(&quot;maxWidth&quot;)){if(D&gt;=this.get(&quot;maxWidth&quot;)){D=this.get(&quot;maxWidth&quot;);}}return D;},_checkHeight:function(D){if(this.get(&quot;minHeight&quot;)){if(D&lt;=this.get(&quot;minHeight&quot;)){D=this.get(&quot;minHeight&quot;);}}if(this.get(&quot;maxHeight&quot;)){if(D&gt;=this.get(&quot;maxHeight&quot;)){D=this.get(&quot;maxHeight&quot;);}}return D;},_setHeight:function(G,I){var H=this._cache.xy[1],F=this._cache.height,J=A.getPageY(G),D=(J-H);if(I){D
 =(H-J)+parseInt(this.get(&quot;height&quot;),10);}D=this._snapTick(D,this.get(&quot;yTicks&quot;));D=this._checkHeight(D);return D;},_snapTick:function(G,F){if(!G||!F){return G;}var H=G;var D=G%F;if(D&gt;0){if(D&gt;(F/2)){H=G+(F-D);}else{H=G-D;}}return H;},init:function(H,F){this._locked=false;this._cache={xy:[],height:0,width:0,top:0,left:0,offsetHeight:0,offsetWidth:0,start:{height:0,width:0,top:0,left:0}};B.superclass.init.call(this,H,F);this.set(&quot;setSize&quot;,this.get(&quot;setSize&quot;));if(F.height){this.set(&quot;height&quot;,parseInt(F.height,10));}else{var G=this.getStyle(&quot;height&quot;);if(G==&quot;auto&quot;){this.set(&quot;height&quot;,parseInt(this.get(&quot;element&quot;).offsetHeight,10));}}if(F.width){this.set(&quot;width&quot;,parseInt(F.width,10));}else{var D=this.getStyle(&quot;width&quot;);if(D==&quot;auto&quot;){this.set(&quot;width&quot;,parseInt(this.get(&quot;element&quot;).offsetWidth,10));}}var I=H;if(!C.isString(I)){I=E.generateId(I);}B.
 _instances[I]=this;this._active=false;this._createWrap();this._createProxy();this._createHandles();},getProxyEl:function(){return this._proxy;},getWrapEl:function(){return this._wrap;},getStatusEl:function(){return this._status;},getActiveHandleEl:function(){return this._handles[this._currentHandle];},isActive:function(){return((this._active)?true:false);},initAttributes:function(D){B.superclass.initAttributes.call(this,D);this.setAttributeConfig(&quot;useShim&quot;,{value:((D.useShim===true)?true:false),validator:YAHOO.lang.isBoolean,method:function(F){for(var G in this._dds){if(C.hasOwnProperty(this._dds,G)){this._dds[G].useShim=F;}}if(this.dd){this.dd.useShim=F;}}});this.setAttributeConfig(&quot;setSize&quot;,{value:((D.setSize===false)?false:true),validator:YAHOO.lang.isBoolean});this.setAttributeConfig(&quot;wrap&quot;,{writeOnce:true,validator:YAHOO.lang.isBoolean,value:D.wrap||false});this.setAttributeConfig(&quot;handles&quot;,{writeOnce:true,value:D.handles||[&quot;
 r&quot;,&quot;b&quot;,&quot;br&quot;],validator:function(F){if(C.isString(F)&amp;&amp;F.toLowerCase()==&quot;all&quot;){F=[&quot;t&quot;,&quot;b&quot;,&quot;r&quot;,&quot;l&quot;,&quot;bl&quot;,&quot;br&quot;,&quot;tl&quot;,&quot;tr&quot;];}if(!C.isArray(F)){F=F.replace(/, /g,&quot;,&quot;);F=F.split(&quot;,&quot;);}this._configs.handles.value=F;}});this.setAttributeConfig(&quot;width&quot;,{value:D.width||parseInt(this.getStyle(&quot;width&quot;),10),validator:YAHOO.lang.isNumber,method:function(F){F=parseInt(F,10);if(F&gt;0){if(this.get(&quot;setSize&quot;)){this.setStyle(&quot;width&quot;,F+&quot;px&quot;);}this._cache.width=F;this._configs.width.value=F;}}});this.setAttributeConfig(&quot;height&quot;,{value:D.height||parseInt(this.getStyle(&quot;height&quot;),10),validator:YAHOO.lang.isNumber,method:function(F){F=parseInt(F,10);if(F&gt;0){if(this.get(&quot;setSize&quot;)){this.setStyle(&quot;height&quot;,F+&quot;px&quot;);}this._cache.height=F;this._configs.height.value=
 F;
+}}});this.setAttributeConfig(&quot;minWidth&quot;,{value:D.minWidth||15,validator:YAHOO.lang.isNumber});this.setAttributeConfig(&quot;minHeight&quot;,{value:D.minHeight||15,validator:YAHOO.lang.isNumber});this.setAttributeConfig(&quot;maxWidth&quot;,{value:D.maxWidth||10000,validator:YAHOO.lang.isNumber});this.setAttributeConfig(&quot;maxHeight&quot;,{value:D.maxHeight||10000,validator:YAHOO.lang.isNumber});this.setAttributeConfig(&quot;minY&quot;,{value:D.minY||false});this.setAttributeConfig(&quot;minX&quot;,{value:D.minX||false});this.setAttributeConfig(&quot;maxY&quot;,{value:D.maxY||false});this.setAttributeConfig(&quot;maxX&quot;,{value:D.maxX||false});this.setAttributeConfig(&quot;animate&quot;,{value:D.animate||false,validator:function(G){var F=true;if(!YAHOO.util.Anim){F=false;}return F;}});this.setAttributeConfig(&quot;animateEasing&quot;,{value:D.animateEasing||function(){var F=false;if(YAHOO.util.Easing&amp;&amp;YAHOO.util.Easing.easeOut){F=YAHOO.util.Easing.ease
 Out;}return F;}()});this.setAttributeConfig(&quot;animateDuration&quot;,{value:D.animateDuration||0.5});this.setAttributeConfig(&quot;proxy&quot;,{value:D.proxy||false,validator:YAHOO.lang.isBoolean});this.setAttributeConfig(&quot;ratio&quot;,{value:D.ratio||false,validator:YAHOO.lang.isBoolean});this.setAttributeConfig(&quot;ghost&quot;,{value:D.ghost||false,validator:YAHOO.lang.isBoolean});this.setAttributeConfig(&quot;draggable&quot;,{value:D.draggable||false,validator:YAHOO.lang.isBoolean,method:function(F){if(F&amp;&amp;this._wrap&amp;&amp;!this.dd){this._setupDragDrop();}else{if(this.dd){if(F){E.addClass(this._wrap,this.CSS_DRAG);this.dd.DDM.regDragDrop(this.dd,&quot;default&quot;);}else{E.removeClass(this._wrap,this.CSS_DRAG);this.dd.unreg();}}}}});this.setAttributeConfig(&quot;hover&quot;,{value:D.hover||false,validator:YAHOO.lang.isBoolean});this.setAttributeConfig(&quot;hiddenHandles&quot;,{value:D.hiddenHandles||false,validator:YAHOO.lang.isBoolean});this.setAttri
 buteConfig(&quot;knobHandles&quot;,{value:D.knobHandles||false,validator:YAHOO.lang.isBoolean});this.setAttributeConfig(&quot;xTicks&quot;,{value:D.xTicks||false});this.setAttributeConfig(&quot;yTicks&quot;,{value:D.yTicks||false});this.setAttributeConfig(&quot;status&quot;,{value:D.status||false,validator:YAHOO.lang.isBoolean});this.setAttributeConfig(&quot;autoRatio&quot;,{value:D.autoRatio||false,validator:YAHOO.lang.isBoolean});},destroy:function(){for(var F in this._handles){if(C.hasOwnProperty(this._handles,F)){A.purgeElement(this._handles[F]);this._handles[F].parentNode.removeChild(this._handles[F]);}}if(this._proxy){this._proxy.parentNode.removeChild(this._proxy);}if(this._status){this._status.parentNode.removeChild(this._status);}if(this.dd){this.dd.unreg();E.removeClass(this._wrap,this.CSS_DRAG);}if(this._wrap!=this.get(&quot;element&quot;)){this.setStyle(&quot;position&quot;,(this._positioned?&quot;absolute&quot;:&quot;relative&quot;));this.setStyle(&quot;top&quot
 ;,E.getStyle(this._wrap,&quot;top&quot;));this.setStyle(&quot;left&quot;,E.getStyle(this._wrap,&quot;left&quot;));this._wrap.parentNode.replaceChild(this.get(&quot;element&quot;),this._wrap);}this.removeClass(this.CSS_RESIZE);delete YAHOO.util.Resize._instances[this.get(&quot;id&quot;)];for(var D in this){if(C.hasOwnProperty(this,D)){this[D]=null;delete this[D];}}},toString:function(){if(this.get){return&quot;Resize (#&quot;+this.get(&quot;id&quot;)+&quot;)&quot;;}return&quot;Resize Utility&quot;;}});YAHOO.util.Resize=B;})();YAHOO.register(&quot;resize&quot;,YAHOO.util.Resize,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiselectorselectorminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/selector/selector-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/selector/selector-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/selector/selector-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,8 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+var Y=YAHOO,Y_DOM=YAHOO.util.Dom,EMPTY_ARRAY=[],Y_UA=Y.env.ua,Y_Lang=Y.lang,Y_DOC=document,Y_DOCUMENT_ELEMENT=Y_DOC.documentElement,Y_DOM_inDoc=Y_DOM.inDocument,Y_mix=Y_Lang.augmentObject,Y_guid=Y_DOM.generateId,Y_getDoc=function(a){var b=Y_DOC;if(a){b=(a.nodeType===9)?a:a.ownerDocument||a.document||Y_DOC;}return b;},Y_Array=function(g,d){var c,b,h=d||0;try{return Array.prototype.slice.call(g,h);}catch(f){b=[];c=g.length;for(;h&lt;c;h++){b.push(g[h]);}return b;}},Y_DOM_allById=function(f,a){a=a||Y_DOC;var b=[],c=[],d,e;if(a.querySelectorAll){c=a.querySelectorAll('[id=&quot;'+f+'&quot;]');}else{if(a.all){b=a.all(f);if(b){if(b.nodeName){if(b.id===f){c.push(b);b=EMPTY_ARRAY;}else{b=[b];}}if(b.length){for(d=0;e=b[d++];){if(e.id===f||(e.attributes&amp;&amp;e.attributes.id&amp;&amp;e.attributes.id.value===f)){c.push(e);}}}}}else{c=[Y_getDoc(a).getElementById(f)];}}return c;};var COMPARE_DOCUMENT_POSITION=&quot;compareDocumentPosition&quot;,OWNER_DOCUMENT=&quot;ownerDocument&quot;,
 Selector={_foundCache:[],useNative:true,_compare:(&quot;sourceIndex&quot; in Y_DOCUMENT_ELEMENT)?function(f,e){var d=f.sourceIndex,c=e.sourceIndex;if(d===c){return 0;}else{if(d&gt;c){return 1;}}return -1;}:(Y_DOCUMENT_ELEMENT[COMPARE_DOCUMENT_POSITION]?function(b,a){if(b[COMPARE_DOCUMENT_POSITION](a)&amp;4){return -1;}else{return 1;}}:function(e,d){var c,a,b;if(e&amp;&amp;d){c=e[OWNER_DOCUMENT].createRange();c.setStart(e,0);a=d[OWNER_DOCUMENT].createRange();a.setStart(d,0);b=c.compareBoundaryPoints(1,a);}return b;}),_sort:function(a){if(a){a=Y_Array(a,0,true);if(a.sort){a.sort(Selector._compare);}}return a;},_deDupe:function(a){var b=[],c,d;for(c=0;(d=a[c++]);){if(!d._found){b[b.length]=d;d._found=true;}}for(c=0;(d=b[c++]);){d._found=null;d.removeAttribute(&quot;_found&quot;);}return b;},query:function(b,j,k,a){if(j&amp;&amp;typeof j==&quot;string&quot;){j=Y_DOM.get(j);if(!j){return(k)?null:[];}}else{j=j||Y_DOC;}var f=[],c=(Selector.useNative&amp;&amp;Y_DOC.querySelector&amp
 ;&amp;!a),e=[[b,j]],g,l,d,h=(c)?Selector._nativeQuery:Selector._bruteQuery;if(b&amp;&amp;h){if(!a&amp;&amp;(!c||j.tagName)){e=Selector._splitQueries(b,j);}for(d=0;(g=e[d++]);){l=h(g[0],g[1],k);if(!k){l=Y_Array(l,0,true);}if(l){f=f.concat(l);}}if(e.length&gt;1){f=Selector._sort(Selector._deDupe(f));}}return(k)?(f[0]||null):f;},_splitQueries:function(c,f){var b=c.split(&quot;,&quot;),d=[],g=&quot;&quot;,e,a;if(f){if(f.tagName){f.id=f.id||Y_guid();g='[id=&quot;'+f.id+'&quot;] ';}for(e=0,a=b.length;e&lt;a;++e){c=g+b[e];d.push([c,f]);}}return d;},_nativeQuery:function(a,b,c){if(Y_UA.webkit&amp;&amp;a.indexOf(&quot;:checked&quot;)&gt;-1&amp;&amp;(Selector.pseudos&amp;&amp;Selector.pseudos.checked)){return Selector.query(a,b,c,true);}try{return b[&quot;querySelector&quot;+(c?&quot;&quot;:&quot;All&quot;)](a);}catch(d){return Selector.query(a,b,c,true);}},filter:function(b,a){var c=[],d,e;if(b&amp;&amp;a){for(d=0;(e=b[d++]);){if(Selector.test(e,a)){c[c.length]=e;}}}else{}return c;},
 test:function(c,d,k){var g=false,b=d.split(&quot;,&quot;),a=false,l,o,h,n,f,e,m;if(c&amp;&amp;c.tagName){if(!k&amp;&amp;!Y_DOM_inDoc(c)){l=c.parentNode;if(l){k=l;}else{n=c[OWNER_DOCUMENT].createDocumentFragment();n.appendChild(c);k=n;a=true;}}k=k||c[OWNER_DOCUMENT];if(!c.id){c.id=Y_guid();}for(f=0;(m=b[f++]);){m+='[id=&quot;'+c.id+'&quot;]';h=Selector.query(m,k);for(e=0;o=h[e++];){if(o===c){g=true;break;}}if(g){break;}}if(a){n.removeChild(c);}}return g;}};YAHOO.util.Selector=Selector;var PARENT_NODE=&quot;parentNode&quot;,TAG_NAME=&quot;tagName&quot;,ATTRIBUTES=&quot;attributes&quot;,COMBINATOR=&quot;combinator&quot;,PSEUDOS=&quot;pseudos&quot;,SelectorCSS2={_reRegExpTokens:/([\^\$\?\[\]\*\+\-\.\(\)\|\\])/,SORT_RESULTS:true,_children:function(e,a){var b=e.children,d,c=[],f,g;if(e.children&amp;&amp;a&amp;&amp;e.children.tags){c=e.children.tags(a);}else{if((!b&amp;&amp;e[TAG_NAME])||(b&amp;&amp;a)){f=b||e.childNodes;b=[];for(d=0;(g=f[d++]);){if(g.tagName){if(!a||a===g.tagName)
 {b.push(g);}}}}}return b||[];},_re:{attr:/(\[[^\]]*\])/g,esc:/\\[:\[\]\(\)#\.\'\&gt;+~&quot;]/gi,pseudos:/(\([^\)]*\))/g},shorthand:{&quot;\\#(-?[_a-z]+[-\\w\\uE000]*)&quot;:&quot;[id=$1]&quot;,&quot;\\.(-?[_a-z]+[-\\w\\uE000]*)&quot;:&quot;[className~=$1]&quot;},operators:{&quot;&quot;:function(b,a){return !!b.getAttribute(a);},&quot;~=&quot;:&quot;(?:^|\\s+){val}(?:\\s+|$)&quot;,&quot;|=&quot;:&quot;^{val}(?:-|$)&quot;},pseudos:{&quot;first-child&quot;:function(a){return Selector._children(a[PARENT_NODE])[0]===a;}},_bruteQuery:function(f,j,l){var g=[],a=[],i=Selector._tokenize(f),e=i[i.length-1],k=Y_getDoc(j),c,b,h,d;if(e){b=e.id;h=e.className;d=e.tagName||&quot;*&quot;;if(j.getElementsByTagName){if(b&amp;&amp;(j.all||(j.nodeType===9||Y_DOM_inDoc(j)))){a=Y_DOM_allById(b,j);}else{if(h){a=j.getElementsByClassName(h);}else{a=j.getElementsByTagName(d);}}}else{c=j.firstChild;while(c){if(c.tagName){a.push(c);}c=c.nextSilbing||c.firstChild;}}if(a.length){g=Selector._filterNodes(a
 ,i,l);}}return g;},_filterNodes:function(l,f,h){var r=0,q,s=f.length,k=s-1,e=[],o=l[0],v=o,t=Selector.getters,d,p,c,g,a,m,b,u;for(r=0;(v=o=l[r++]);){k=s-1;g=null;testLoop:while(v&amp;&amp;v.tagName){c=f[k];b=c.tests;q=b.length;if(q&amp;&amp;!a){while((u=b[--q])){d=u[1];if(t[u[0]]){m=t[u[0]](v,u[0]);}else{m=v[u[0]];if(m===undefined&amp;&amp;v.getAttribute){m=v.getAttribute(u[0]);}}if((d===&quot;=&quot;&amp;&amp;m!==u[2])||(typeof d!==&quot;string&quot;&amp;&amp;d.test&amp;&amp;!d.test(m))||(!d.test&amp;&amp;typeof d===&quot;function&quot;&amp;&amp;!d(v,u[0],u[2]))){if((v=v[g])){while(v&amp;&amp;(!v.tagName||(c.tagName&amp;&amp;c.tagName!==v.tagName))){v=v[g];}}continue testLoop;}}}k--;if(!a&amp;&amp;(p=c.combinator)){g=p.axis;v=v[g];while(v&amp;&amp;!v.tagName){v=v[g];}if(p.direct){g=null;}}else{e.push(o);if(h){return e;}break;}}}o=v=null;return e;},combinators:{&quot; &quot;:{axis:&quot;parentNode&quot;},&quot;&gt;&quot;:{axis:&quot;parentNode&quot;,direct:true},&quot;+&quot
 ;:{axis:&quot;previousSibling&quot;,direct:true}},_parsers:[{name:ATTRIBUTES,re:/^\uE003(-?[a-z]+[\w\-]*)+([~\|\^\$\*!=]=?)?['&quot;]?([^\uE004'&quot;]*)['&quot;]?\uE004/i,fn:function(d,e){var c=d[2]||&quot;&quot;,a=Selector.operators,b=(d[3])?d[3].replace(/\\/g,&quot;&quot;):&quot;&quot;,f;if((d[1]===&quot;id&quot;&amp;&amp;c===&quot;=&quot;)||(d[1]===&quot;className&quot;&amp;&amp;Y_DOCUMENT_ELEMENT.getElementsByClassName&amp;&amp;(c===&quot;~=&quot;||c===&quot;=&quot;))){e.prefilter=d[1];d[3]=b;e[d[1]]=(d[1]===&quot;id&quot;)?d[3]:b;}if(c in a){f=a[c];if(typeof f===&quot;string&quot;){d[3]=b.replace(Selector._reRegExpTokens,&quot;\\$1&quot;);f=new RegExp(f.replace(&quot;{val}&quot;,d[3]));}d[2]=f;}if(!e.last||e.prefilter!==d[1]){return d.slice(1);}}},{name:TAG_NAME,re:/^((?:-?[_a-z]+[\w-]*)|\*)/i,fn:function(b,c){var a=b[1].toUpperCase();c.tagName=a;if(a!==&quot;*&quot;&amp;&amp;(!c.last||c.prefilter)){return[TAG_NAME,&quot;=&quot;,a];
+}if(!c.prefilter){c.prefilter=&quot;tagName&quot;;}}},{name:COMBINATOR,re:/^\s*([&gt;+~]|\s)\s*/,fn:function(a,b){}},{name:PSEUDOS,re:/^:([\-\w]+)(?:\uE005['&quot;]?([^\uE005]*)['&quot;]?\uE006)*/i,fn:function(a,b){var c=Selector[PSEUDOS][a[1]];if(c){if(a[2]){a[2]=a[2].replace(/\\/g,&quot;&quot;);}return[a[2],c];}else{return false;}}}],_getToken:function(a){return{tagName:null,id:null,className:null,attributes:{},combinator:null,tests:[]};},_tokenize:function(c){c=c||&quot;&quot;;c=Selector._replaceShorthand(Y_Lang.trim(c));var b=Selector._getToken(),h=c,g=[],j=false,e,f,d,a;outer:do{j=false;for(d=0;(a=Selector._parsers[d++]);){if((e=a.re.exec(c))){if(a.name!==COMBINATOR){b.selector=c;}c=c.replace(e[0],&quot;&quot;);if(!c.length){b.last=true;}if(Selector._attrFilters[e[1]]){e[1]=Selector._attrFilters[e[1]];}f=a.fn(e,b);if(f===false){j=false;break outer;}else{if(f){b.tests.push(f);}}if(!c.length||a.name===COMBINATOR){g.push(b);b=Selector._getToken(b);if(a.name===COMBINATOR){b
 .combinator=Selector.combinators[e[1]];}}j=true;}}}while(j&amp;&amp;c.length);if(!j||c.length){g=[];}return g;},_replaceShorthand:function(b){var d=Selector.shorthand,c=b.match(Selector._re.esc),e,h,g,f,a;if(c){b=b.replace(Selector._re.esc,&quot;\uE000&quot;);}e=b.match(Selector._re.attr);h=b.match(Selector._re.pseudos);if(e){b=b.replace(Selector._re.attr,&quot;\uE001&quot;);}if(h){b=b.replace(Selector._re.pseudos,&quot;\uE002&quot;);}for(g in d){if(d.hasOwnProperty(g)){b=b.replace(new RegExp(g,&quot;gi&quot;),d[g]);}}if(e){for(f=0,a=e.length;f&lt;a;++f){b=b.replace(/\uE001/,e[f]);}}if(h){for(f=0,a=h.length;f&lt;a;++f){b=b.replace(/\uE002/,h[f]);}}b=b.replace(/\[/g,&quot;\uE003&quot;);b=b.replace(/\]/g,&quot;\uE004&quot;);b=b.replace(/\(/g,&quot;\uE005&quot;);b=b.replace(/\)/g,&quot;\uE006&quot;);if(c){for(f=0,a=c.length;f&lt;a;++f){b=b.replace(&quot;\uE000&quot;,c[f]);}}return b;},_attrFilters:{&quot;class&quot;:&quot;className&quot;,&quot;for&quot;:&quot;htmlFor&quot;},get
 ters:{href:function(b,a){return Y_DOM.getAttribute(b,a);}}};Y_mix(Selector,SelectorCSS2,true);Selector.getters.src=Selector.getters.rel=Selector.getters.href;if(Selector.useNative&amp;&amp;Y_DOC.querySelector){Selector.shorthand[&quot;\\.([^\\s\\\\(\\[:]*)&quot;]=&quot;[class~=$1]&quot;;}Selector._reNth=/^(?:([\-]?\d*)(n){1}|(odd|even)$)*([\-+]?\d*)$/;Selector._getNth=function(d,o,q,h){Selector._reNth.test(o);var m=parseInt(RegExp.$1,10),c=RegExp.$2,j=RegExp.$3,k=parseInt(RegExp.$4,10)||0,p=[],l=Selector._children(d.parentNode,q),f;if(j){m=2;f=&quot;+&quot;;c=&quot;n&quot;;k=(j===&quot;odd&quot;)?1:0;}else{if(isNaN(m)){m=(c)?1:0;}}if(m===0){if(h){k=l.length-k+1;}if(l[k-1]===d){return true;}else{return false;}}else{if(m&lt;0){h=!!h;m=Math.abs(m);}}if(!h){for(var e=k-1,g=l.length;e&lt;g;e+=m){if(e&gt;=0&amp;&amp;l[e]===d){return true;}}}else{for(var e=l.length-k,g=l.length;e&gt;=0;e-=m){if(e&lt;g&amp;&amp;l[e]===d){return true;}}}return false;};Y_mix(Selector.pseudos,{&quot;ro
 ot&quot;:function(a){return a===a.ownerDocument.documentElement;},&quot;nth-child&quot;:function(a,b){return Selector._getNth(a,b);},&quot;nth-last-child&quot;:function(a,b){return Selector._getNth(a,b,null,true);},&quot;nth-of-type&quot;:function(a,b){return Selector._getNth(a,b,a.tagName);},&quot;nth-last-of-type&quot;:function(a,b){return Selector._getNth(a,b,a.tagName,true);},&quot;last-child&quot;:function(b){var a=Selector._children(b.parentNode);return a[a.length-1]===b;},&quot;first-of-type&quot;:function(a){return Selector._children(a.parentNode,a.tagName)[0]===a;},&quot;last-of-type&quot;:function(b){var a=Selector._children(b.parentNode,b.tagName);return a[a.length-1]===b;},&quot;only-child&quot;:function(b){var a=Selector._children(b.parentNode);return a.length===1&amp;&amp;a[0]===b;},&quot;only-of-type&quot;:function(b){var a=Selector._children(b.parentNode,b.tagName);return a.length===1&amp;&amp;a[0]===b;},&quot;empty&quot;:function(a){return a.childNodes.lengt
 h===0;},&quot;not&quot;:function(a,b){return !Selector.test(a,b);},&quot;contains&quot;:function(a,b){var c=a.innerText||a.textContent||&quot;&quot;;return c.indexOf(b)&gt;-1;},&quot;checked&quot;:function(a){return(a.checked===true||a.selected===true);},enabled:function(a){return(a.disabled!==undefined&amp;&amp;!a.disabled);},disabled:function(a){return(a.disabled);}});Y_mix(Selector.operators,{&quot;^=&quot;:&quot;^{val}&quot;,&quot;!=&quot;:function(b,a,c){return b[a]!==c;},&quot;$=&quot;:&quot;{val}$&quot;,&quot;*=&quot;:&quot;{val}&quot;});Selector.combinators[&quot;~&quot;]={axis:&quot;previousSibling&quot;};YAHOO.register(&quot;selector&quot;,YAHOO.util.Selector,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuislidersliderminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/slider/slider-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/slider/slider-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/slider/slider-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,9 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+(function(){var B=YAHOO.util.Dom.getXY,A=YAHOO.util.Event,D=Array.prototype.slice;function C(G,E,F,H){C.ANIM_AVAIL=(!YAHOO.lang.isUndefined(YAHOO.util.Anim));if(G){this.init(G,E,true);this.initSlider(H);this.initThumb(F);}}YAHOO.lang.augmentObject(C,{getHorizSlider:function(F,G,I,H,E){return new C(F,F,new YAHOO.widget.SliderThumb(G,F,I,H,0,0,E),&quot;horiz&quot;);},getVertSlider:function(G,H,E,I,F){return new C(G,G,new YAHOO.widget.SliderThumb(H,G,0,0,E,I,F),&quot;vert&quot;);},getSliderRegion:function(G,H,J,I,E,K,F){return new C(G,G,new YAHOO.widget.SliderThumb(H,G,J,I,E,K,F),&quot;region&quot;);},SOURCE_UI_EVENT:1,SOURCE_SET_VALUE:2,SOURCE_KEY_EVENT:3,ANIM_AVAIL:false},true);YAHOO.extend(C,YAHOO.util.DragDrop,{_mouseDown:false,dragOnly:true,initSlider:function(E){this.type=E;this.createEvent(&quot;change&quot;,this);this.createEvent(&quot;slideStart&quot;,this);this.createEvent(&quot;slideEnd&quot;,this);this.isTarget=false;this.animate=C.ANIM_AVAIL;this.backgroundEnabled=
 true;this.tickPause=40;this.enableKeys=true;this.keyIncrement=20;this.moveComplete=true;this.animationDuration=0.2;this.SOURCE_UI_EVENT=1;this.SOURCE_SET_VALUE=2;this.valueChangeSource=0;this._silent=false;this.lastOffset=[0,0];},initThumb:function(F){var E=this;this.thumb=F;F.cacheBetweenDrags=true;if(F._isHoriz&amp;&amp;F.xTicks&amp;&amp;F.xTicks.length){this.tickPause=Math.round(360/F.xTicks.length);}else{if(F.yTicks&amp;&amp;F.yTicks.length){this.tickPause=Math.round(360/F.yTicks.length);}}F.onAvailable=function(){return E.setStartSliderState();};F.onMouseDown=function(){E._mouseDown=true;return E.focus();};F.startDrag=function(){E._slideStart();};F.onDrag=function(){E.fireEvents(true);};F.onMouseUp=function(){E.thumbMouseUp();};},onAvailable:function(){this._bindKeyEvents();},_bindKeyEvents:function(){A.on(this.id,&quot;keydown&quot;,this.handleKeyDown,this,true);A.on(this.id,&quot;keypress&quot;,this.handleKeyPress,this,true);},handleKeyPress:function(F){if(this.enable
 Keys){var E=A.getCharCode(F);switch(E){case 37:case 38:case 39:case 40:case 36:case 35:A.preventDefault(F);break;default:}}},handleKeyDown:function(J){if(this.enableKeys){var G=A.getCharCode(J),F=this.thumb,H=this.getXValue(),E=this.getYValue(),I=true;switch(G){case 37:H-=this.keyIncrement;break;case 38:E-=this.keyIncrement;break;case 39:H+=this.keyIncrement;break;case 40:E+=this.keyIncrement;break;case 36:H=F.leftConstraint;E=F.topConstraint;break;case 35:H=F.rightConstraint;E=F.bottomConstraint;break;default:I=false;}if(I){if(F._isRegion){this._setRegionValue(C.SOURCE_KEY_EVENT,H,E,true);}else{this._setValue(C.SOURCE_KEY_EVENT,(F._isHoriz?H:E),true);}A.stopEvent(J);}}},setStartSliderState:function(){this.setThumbCenterPoint();this.baselinePos=B(this.getEl());this.thumb.startOffset=this.thumb.getOffsetFromParent(this.baselinePos);if(this.thumb._isRegion){if(this.deferredSetRegionValue){this._setRegionValue.apply(this,this.deferredSetRegionValue);this.deferredSetRegionValue=
 null;}else{this.setRegionValue(0,0,true,true,true);}}else{if(this.deferredSetValue){this._setValue.apply(this,this.deferredSetValue);this.deferredSetValue=null;}else{this.setValue(0,true,true,true);}}},setThumbCenterPoint:function(){var E=this.thumb.getEl();if(E){this.thumbCenterPoint={x:parseInt(E.offsetWidth/2,10),y:parseInt(E.offsetHeight/2,10)};}},lock:function(){this.thumb.lock();this.locked=true;},unlock:function(){this.thumb.unlock();this.locked=false;},thumbMouseUp:function(){this._mouseDown=false;if(!this.isLocked()){this.endMove();}},onMouseUp:function(){this._mouseDown=false;if(this.backgroundEnabled&amp;&amp;!this.isLocked()){this.endMove();}},getThumb:function(){return this.thumb;},focus:function(){this.valueChangeSource=C.SOURCE_UI_EVENT;var E=this.getEl();if(E.focus){try{E.focus();}catch(F){}}this.verifyOffset();return !this.isLocked();},onChange:function(E,F){},onSlideStart:function(){},onSlideEnd:function(){},getValue:function(){return this.thumb.getValue();
 },getXValue:function(){return this.thumb.getXValue();},getYValue:function(){return this.thumb.getYValue();},setValue:function(){var E=D.call(arguments);E.unshift(C.SOURCE_SET_VALUE);return this._setValue.apply(this,E);},_setValue:function(I,L,G,H,E){var F=this.thumb,K,J;if(!F.available){this.deferredSetValue=arguments;return false;}if(this.isLocked()&amp;&amp;!H){return false;}if(isNaN(L)){return false;}if(F._isRegion){return false;}this._silent=E;this.valueChangeSource=I||C.SOURCE_SET_VALUE;F.lastOffset=[L,L];this.verifyOffset();this._slideStart();if(F._isHoriz){K=F.initPageX+L+this.thumbCenterPoint.x;this.moveThumb(K,F.initPageY,G);}else{J=F.initPageY+L+this.thumbCenterPoint.y;this.moveThumb(F.initPageX,J,G);}return true;},setRegionValue:function(){var E=D.call(arguments);E.unshift(C.SOURCE_SET_VALUE);return this._setRegionValue.apply(this,E);},_setRegionValue:function(F,J,H,I,G,K){var L=this.thumb,E,M;if(!L.available){this.deferredSetRegionValue=arguments;return false;}if
 (this.isLocked()&amp;&amp;!G){return false;}if(isNaN(J)){return false;}if(!L._isRegion){return false;}this._silent=K;this.valueChangeSource=F||C.SOURCE_SET_VALUE;L.lastOffset=[J,H];this.verifyOffset();this._slideStart();E=L.initPageX+J+this.thumbCenterPoint.x;M=L.initPageY+H+this.thumbCenterPoint.y;this.moveThumb(E,M,I);return true;},verifyOffset:function(){var F=B(this.getEl()),E=this.thumb;if(!this.thumbCenterPoint||!this.thumbCenterPoint.x){this.setThumbCenterPoint();}if(F){if(F[0]!=this.baselinePos[0]||F[1]!=this.baselinePos[1]){this.setInitPosition();this.baselinePos=F;E.initPageX=this.initPageX+E.startOffset[0];E.initPageY=this.initPageY+E.startOffset[1];E.deltaSetXY=null;this.resetThumbConstraints();return false;}}return true;},moveThumb:function(K,J,I,G){var L=this.thumb,M=this,F,E,H;if(!L.available){return;}L.setDelta(this.thumbCenterPoint.x,this.thumbCenterPoint.y);E=L.getTargetCoord(K,J);F=[Math.round(E.x),Math.round(E.y)];if(this.animate&amp;&amp;L._graduated&amp
 ;&amp;!I){this.lock();this.curCoord=B(this.thumb.getEl());this.curCoord=[Math.round(this.curCoord[0]),Math.round(this.curCoord[1])];setTimeout(function(){M.moveOneTick(F);},this.tickPause);}else{if(this.animate&amp;&amp;C.ANIM_AVAIL&amp;&amp;!I){this.lock();
+H=new YAHOO.util.Motion(L.id,{points:{to:F}},this.animationDuration,YAHOO.util.Easing.easeOut);H.onComplete.subscribe(function(){M.unlock();if(!M._mouseDown){M.endMove();}});H.animate();}else{L.setDragElPos(K,J);if(!G&amp;&amp;!this._mouseDown){this.endMove();}}}},_slideStart:function(){if(!this._sliding){if(!this._silent){this.onSlideStart();this.fireEvent(&quot;slideStart&quot;);}this._sliding=true;this.moveComplete=false;}},_slideEnd:function(){if(this._sliding){var E=this._silent;this._sliding=false;this.moveComplete=true;this._silent=false;if(!E){this.onSlideEnd();this.fireEvent(&quot;slideEnd&quot;);}}},moveOneTick:function(F){var H=this.thumb,G=this,I=null,E,J;if(H._isRegion){I=this._getNextX(this.curCoord,F);E=(I!==null)?I[0]:this.curCoord[0];I=this._getNextY(this.curCoord,F);J=(I!==null)?I[1]:this.curCoord[1];I=E!==this.curCoord[0]||J!==this.curCoord[1]?[E,J]:null;}else{if(H._isHoriz){I=this._getNextX(this.curCoord,F);}else{I=this._getNextY(this.curCoord,F);}}if(I){
 this.curCoord=I;this.thumb.alignElWithMouse(H.getEl(),I[0]+this.thumbCenterPoint.x,I[1]+this.thumbCenterPoint.y);if(!(I[0]==F[0]&amp;&amp;I[1]==F[1])){setTimeout(function(){G.moveOneTick(F);},this.tickPause);}else{this.unlock();if(!this._mouseDown){this.endMove();}}}else{this.unlock();if(!this._mouseDown){this.endMove();}}},_getNextX:function(E,F){var H=this.thumb,J,G=[],I=null;if(E[0]&gt;F[0]){J=H.tickSize-this.thumbCenterPoint.x;G=H.getTargetCoord(E[0]-J,E[1]);I=[G.x,G.y];}else{if(E[0]&lt;F[0]){J=H.tickSize+this.thumbCenterPoint.x;G=H.getTargetCoord(E[0]+J,E[1]);I=[G.x,G.y];}else{}}return I;},_getNextY:function(E,F){var H=this.thumb,J,G=[],I=null;if(E[1]&gt;F[1]){J=H.tickSize-this.thumbCenterPoint.y;G=H.getTargetCoord(E[0],E[1]-J);I=[G.x,G.y];}else{if(E[1]&lt;F[1]){J=H.tickSize+this.thumbCenterPoint.y;G=H.getTargetCoord(E[0],E[1]+J);I=[G.x,G.y];}else{}}return I;},b4MouseDown:function(E){if(!this.backgroundEnabled){return false;}this.thumb.autoOffset();this.baselinePos=[];}
 ,onMouseDown:function(F){if(!this.backgroundEnabled||this.isLocked()){return false;}this._mouseDown=true;var E=A.getPageX(F),G=A.getPageY(F);this.focus();this._slideStart();this.moveThumb(E,G);},onDrag:function(F){if(this.backgroundEnabled&amp;&amp;!this.isLocked()){var E=A.getPageX(F),G=A.getPageY(F);this.moveThumb(E,G,true,true);this.fireEvents();}},endMove:function(){this.unlock();this.fireEvents();this._slideEnd();},resetThumbConstraints:function(){var E=this.thumb;E.setXConstraint(E.leftConstraint,E.rightConstraint,E.xTickSize);E.setYConstraint(E.topConstraint,E.bottomConstraint,E.xTickSize);},fireEvents:function(G){var F=this.thumb,I,H,E;if(!G){F.cachePosition();}if(!this.isLocked()){if(F._isRegion){I=F.getXValue();H=F.getYValue();if(I!=this.previousX||H!=this.previousY){if(!this._silent){this.onChange(I,H);this.fireEvent(&quot;change&quot;,{x:I,y:H});}}this.previousX=I;this.previousY=H;}else{E=F.getValue();if(E!=this.previousVal){if(!this._silent){this.onChange(E);thi
 s.fireEvent(&quot;change&quot;,E);}}this.previousVal=E;}}},toString:function(){return(&quot;Slider (&quot;+this.type+&quot;) &quot;+this.id);}});YAHOO.lang.augmentProto(C,YAHOO.util.EventProvider);YAHOO.widget.Slider=C;})();YAHOO.widget.SliderThumb=function(G,B,E,D,A,F,C){if(G){YAHOO.widget.SliderThumb.superclass.constructor.call(this,G,B);this.parentElId=B;}this.isTarget=false;this.tickSize=C;this.maintainOffset=true;this.initSlider(E,D,A,F,C);this.scroll=false;};YAHOO.extend(YAHOO.widget.SliderThumb,YAHOO.util.DD,{startOffset:null,dragOnly:true,_isHoriz:false,_prevVal:0,_graduated:false,getOffsetFromParent0:function(C){var A=YAHOO.util.Dom.getXY(this.getEl()),B=C||YAHOO.util.Dom.getXY(this.parentElId);return[(A[0]-B[0]),(A[1]-B[1])];},getOffsetFromParent:function(H){var A=this.getEl(),E,I,F,B,K,D,C,J,G;if(!this.deltaOffset){I=YAHOO.util.Dom.getXY(A);F=H||YAHOO.util.Dom.getXY(this.parentElId);E=[(I[0]-F[0]),(I[1]-F[1])];B=parseInt(YAHOO.util.Dom.getStyle(A,&quot;left&quot;)
 ,10);K=parseInt(YAHOO.util.Dom.getStyle(A,&quot;top&quot;),10);D=B-E[0];C=K-E[1];if(isNaN(D)||isNaN(C)){}else{this.deltaOffset=[D,C];}}else{J=parseInt(YAHOO.util.Dom.getStyle(A,&quot;left&quot;),10);G=parseInt(YAHOO.util.Dom.getStyle(A,&quot;top&quot;),10);E=[J+this.deltaOffset[0],G+this.deltaOffset[1]];}return E;},initSlider:function(D,C,A,E,B){this.initLeft=D;this.initRight=C;this.initUp=A;this.initDown=E;this.setXConstraint(D,C,B);this.setYConstraint(A,E,B);if(B&amp;&amp;B&gt;1){this._graduated=true;}this._isHoriz=(D||C);this._isVert=(A||E);this._isRegion=(this._isHoriz&amp;&amp;this._isVert);},clearTicks:function(){YAHOO.widget.SliderThumb.superclass.clearTicks.call(this);this.tickSize=0;this._graduated=false;},getValue:function(){return(this._isHoriz)?this.getXValue():this.getYValue();},getXValue:function(){if(!this.available){return 0;}var A=this.getOffsetFromParent();if(YAHOO.lang.isNumber(A[0])){this.lastOffset=A;return(A[0]-this.startOffset[0]);}else{return(this.las
 tOffset[0]-this.startOffset[0]);}},getYValue:function(){if(!this.available){return 0;}var A=this.getOffsetFromParent();if(YAHOO.lang.isNumber(A[1])){this.lastOffset=A;return(A[1]-this.startOffset[1]);}else{return(this.lastOffset[1]-this.startOffset[1]);}},toString:function(){return&quot;SliderThumb &quot;+this.id;},onChange:function(A,B){}});(function(){var A=YAHOO.util.Event,B=YAHOO.widget;function C(I,F,H,D){var G=this,J={min:false,max:false},E,K;this.minSlider=I;this.maxSlider=F;this.activeSlider=I;this.isHoriz=I.thumb._isHoriz;E=this.minSlider.thumb.onMouseDown;K=this.maxSlider.thumb.onMouseDown;this.minSlider.thumb.onMouseDown=function(){G.activeSlider=G.minSlider;E.apply(this,arguments);};this.maxSlider.thumb.onMouseDown=function(){G.activeSlider=G.maxSlider;K.apply(this,arguments);};this.minSlider.thumb.onAvailable=function(){I.setStartSliderState();J.min=true;if(J.max){G.fireEvent(&quot;ready&quot;,G);}};this.maxSlider.thumb.onAvailable=function(){F.setStartSliderSta
 te();J.max=true;if(J.min){G.fireEvent(&quot;ready&quot;,G);}};I.onMouseDown=F.onMouseDown=function(L){return this.backgroundEnabled&amp;&amp;G._handleMouseDown(L);};I.onDrag=F.onDrag=function(L){G._handleDrag(L);};I.onMouseUp=F.onMouseUp=function(L){G._handleMouseUp(L);
+};I._bindKeyEvents=function(){G._bindKeyEvents(this);};F._bindKeyEvents=function(){};I.subscribe(&quot;change&quot;,this._handleMinChange,I,this);I.subscribe(&quot;slideStart&quot;,this._handleSlideStart,I,this);I.subscribe(&quot;slideEnd&quot;,this._handleSlideEnd,I,this);F.subscribe(&quot;change&quot;,this._handleMaxChange,F,this);F.subscribe(&quot;slideStart&quot;,this._handleSlideStart,F,this);F.subscribe(&quot;slideEnd&quot;,this._handleSlideEnd,F,this);this.createEvent(&quot;ready&quot;,this);this.createEvent(&quot;change&quot;,this);this.createEvent(&quot;slideStart&quot;,this);this.createEvent(&quot;slideEnd&quot;,this);D=YAHOO.lang.isArray(D)?D:[0,H];D[0]=Math.min(Math.max(parseInt(D[0],10)|0,0),H);D[1]=Math.max(Math.min(parseInt(D[1],10)|0,H),0);if(D[0]&gt;D[1]){D.splice(0,2,D[1],D[0]);}this.minVal=D[0];this.maxVal=D[1];this.minSlider.setValue(this.minVal,true,true,true);this.maxSlider.setValue(this.maxVal,true,true,true);}C.prototype={minVal:-1,maxVal:-1,minRange:
 0,_handleSlideStart:function(E,D){this.fireEvent(&quot;slideStart&quot;,D);},_handleSlideEnd:function(E,D){this.fireEvent(&quot;slideEnd&quot;,D);},_handleDrag:function(D){B.Slider.prototype.onDrag.call(this.activeSlider,D);},_handleMinChange:function(){this.activeSlider=this.minSlider;this.updateValue();},_handleMaxChange:function(){this.activeSlider=this.maxSlider;this.updateValue();},_bindKeyEvents:function(D){A.on(D.id,&quot;keydown&quot;,this._handleKeyDown,this,true);A.on(D.id,&quot;keypress&quot;,this._handleKeyPress,this,true);},_handleKeyDown:function(D){this.activeSlider.handleKeyDown.apply(this.activeSlider,arguments);},_handleKeyPress:function(D){this.activeSlider.handleKeyPress.apply(this.activeSlider,arguments);},setValues:function(H,K,I,E,J){var F=this.minSlider,M=this.maxSlider,D=F.thumb,L=M.thumb,N=this,G={min:false,max:false};if(D._isHoriz){D.setXConstraint(D.leftConstraint,L.rightConstraint,D.tickSize);L.setXConstraint(D.leftConstraint,L.rightConstraint,L.
 tickSize);}else{D.setYConstraint(D.topConstraint,L.bottomConstraint,D.tickSize);L.setYConstraint(D.topConstraint,L.bottomConstraint,L.tickSize);}this._oneTimeCallback(F,&quot;slideEnd&quot;,function(){G.min=true;if(G.max){N.updateValue(J);setTimeout(function(){N._cleanEvent(F,&quot;slideEnd&quot;);N._cleanEvent(M,&quot;slideEnd&quot;);},0);}});this._oneTimeCallback(M,&quot;slideEnd&quot;,function(){G.max=true;if(G.min){N.updateValue(J);setTimeout(function(){N._cleanEvent(F,&quot;slideEnd&quot;);N._cleanEvent(M,&quot;slideEnd&quot;);},0);}});F.setValue(H,I,E,false);M.setValue(K,I,E,false);},setMinValue:function(F,H,I,E){var G=this.minSlider,D=this;this.activeSlider=G;D=this;this._oneTimeCallback(G,&quot;slideEnd&quot;,function(){D.updateValue(E);setTimeout(function(){D._cleanEvent(G,&quot;slideEnd&quot;);},0);});G.setValue(F,H,I);},setMaxValue:function(D,H,I,F){var G=this.maxSlider,E=this;this.activeSlider=G;this._oneTimeCallback(G,&quot;slideEnd&quot;,function(){E.updateValu
 e(F);setTimeout(function(){E._cleanEvent(G,&quot;slideEnd&quot;);},0);});G.setValue(D,H,I);},updateValue:function(J){var E=this.minSlider.getValue(),K=this.maxSlider.getValue(),F=false,D,M,H,I,L,G;if(E!=this.minVal||K!=this.maxVal){F=true;D=this.minSlider.thumb;M=this.maxSlider.thumb;H=this.isHoriz?&quot;x&quot;:&quot;y&quot;;G=this.minSlider.thumbCenterPoint[H]+this.maxSlider.thumbCenterPoint[H];I=Math.max(K-G-this.minRange,0);L=Math.min(-E-G-this.minRange,0);if(this.isHoriz){I=Math.min(I,M.rightConstraint);D.setXConstraint(D.leftConstraint,I,D.tickSize);M.setXConstraint(L,M.rightConstraint,M.tickSize);}else{I=Math.min(I,M.bottomConstraint);D.setYConstraint(D.leftConstraint,I,D.tickSize);M.setYConstraint(L,M.bottomConstraint,M.tickSize);}}this.minVal=E;this.maxVal=K;if(F&amp;&amp;!J){this.fireEvent(&quot;change&quot;,this);}},selectActiveSlider:function(H){var E=this.minSlider,D=this.maxSlider,J=E.isLocked()||!E.backgroundEnabled,G=D.isLocked()||!E.backgroundEnabled,F=YAHOO
 .util.Event,I;if(J||G){this.activeSlider=J?D:E;}else{if(this.isHoriz){I=F.getPageX(H)-E.thumb.initPageX-E.thumbCenterPoint.x;}else{I=F.getPageY(H)-E.thumb.initPageY-E.thumbCenterPoint.y;}this.activeSlider=I*2&gt;D.getValue()+E.getValue()?D:E;}},_handleMouseDown:function(D){if(!D._handled&amp;&amp;!this.minSlider._sliding&amp;&amp;!this.maxSlider._sliding){D._handled=true;this.selectActiveSlider(D);return B.Slider.prototype.onMouseDown.call(this.activeSlider,D);}else{return false;}},_handleMouseUp:function(D){B.Slider.prototype.onMouseUp.apply(this.activeSlider,arguments);},_oneTimeCallback:function(G,D,F){var E=function(){G.unsubscribe(D,E);F.apply({},arguments);};G.subscribe(D,E);},_cleanEvent:function(K,E){var J,I,D,G,H,F;if(K.__yui_events&amp;&amp;K.events[E]){for(I=K.__yui_events.length;I&gt;=0;--I){if(K.__yui_events[I].type===E){J=K.__yui_events[I];break;}}if(J){H=J.subscribers;F=[];G=0;for(I=0,D=H.length;I&lt;D;++I){if(H[I]){F[G++]=H[I];}}J.subscribers=F;}}}};YAHOO.lan
 g.augmentProto(C,YAHOO.util.EventProvider);B.Slider.getHorizDualSlider=function(H,J,K,G,F,D){var I=new B.SliderThumb(J,H,0,G,0,0,F),E=new B.SliderThumb(K,H,0,G,0,0,F);return new C(new B.Slider(H,H,I,&quot;horiz&quot;),new B.Slider(H,H,E,&quot;horiz&quot;),G,D);};B.Slider.getVertDualSlider=function(H,J,K,G,F,D){var I=new B.SliderThumb(J,H,0,0,0,G,F),E=new B.SliderThumb(K,H,0,0,0,G,F);return new B.DualSlider(new B.Slider(H,H,I,&quot;vert&quot;),new B.Slider(H,H,E,&quot;vert&quot;),G,D);};YAHOO.widget.DualSlider=C;})();YAHOO.register(&quot;slider&quot;,YAHOO.widget.Slider,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuistoragestorageminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/storage/storage-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/storage/storage-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/storage/storage-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,8 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+(function(){var g=YAHOO,f=g.util,e=g.lang,c,d,b=/^type=(\w+)/i,a=/&amp;value=(.*)/i;if(!f.Storage){c=function(h){g.log(&quot;Exception in YAHOO.util.Storage.?? - must be extended by a storage engine&quot;.replace(&quot;??&quot;,h).replace(&quot;??&quot;,this.getName?this.getName():&quot;Unknown&quot;),&quot;error&quot;);};d=function(h,k,j){var i=this;g.env._id_counter+=1;i._cfg=e.isObject(j)?j:{};i._location=h;i._name=k;i.isReady=false;i.createEvent(d.CE_READY,{scope:i,fireOnce:true});i.createEvent(d.CE_CHANGE,{scope:i});i.subscribe(d.CE_READY,function(){i.isReady=true;});};d.CE_READY=&quot;YUIStorageReady&quot;;d.CE_CHANGE=&quot;YUIStorageChange&quot;;d.prototype={CE_READY:d.CE_READY,CE_CHANGE:d.CE_CHANGE,_cfg:&quot;&quot;,_name:&quot;&quot;,_location:&quot;&quot;,length:0,isReady:false,clear:function(){this._clear();this.length=0;},getItem:function(h){g.log(&quot;Fetching item at  &quot;+h);var i=this._getItem(h);return e.isValue(i)?this._getValue(i):null;},getName:functio
 n(){return this._name;},hasKey:function(h){return e.isString(h)&amp;&amp;this._hasKey(h);},key:function(h){g.log(&quot;Fetching key at &quot;+h);if(e.isNumber(h)&amp;&amp;-1&lt;h&amp;&amp;this.length&gt;h){var i=this._key(h);if(i){return i;}}throw (&quot;INDEX_SIZE_ERR - Storage.setItem - The provided index (&quot;+h+&quot;) is not available&quot;);},removeItem:function(j){g.log(&quot;removing &quot;+j);var i=this,h;if(i.hasKey(j)){h=i._getItem(j);if(!h){h=null;}i._removeItem(j);i.fireEvent(d.CE_CHANGE,new f.StorageEvent(i,j,h,null,f.StorageEvent.TYPE_REMOVE_ITEM));}else{}},setItem:function(j,k){g.log(&quot;SETTING &quot;+k+&quot; to &quot;+j);if(e.isString(j)){var i=this,h=i._getItem(j);if(!h){h=null;}if(i._setItem(j,i._createValue(k))){i.fireEvent(d.CE_CHANGE,new f.StorageEvent(i,j,h,k,i.hasKey(j)?f.StorageEvent.TYPE_UPDATE_ITEM:f.StorageEvent.TYPE_ADD_ITEM));}else{throw (&quot;QUOTA_EXCEEDED_ERROR - Storage.setItem - The choosen storage method (&quot;+i.getName()+&quot;) 
 has exceeded capacity&quot;);}}else{}},_clear:function(){c(&quot;_clear&quot;);return&quot;&quot;;},_createValue:function(h){var i=(e.isNull(h)||e.isUndefined(h))?(&quot;&quot;+h):typeof h;return&quot;type=&quot;+i+&quot;&amp;value=&quot;+encodeURIComponent(&quot;&quot;+h);},_getItem:function(h){c(&quot;_getItem&quot;);return&quot;&quot;;},_getValue:function(h){var j=h.match(b)[1],i=h.match(a)[1];switch(j){case&quot;boolean&quot;:return&quot;true&quot;==i;case&quot;number&quot;:return parseFloat(i);case&quot;null&quot;:return null;default:return decodeURIComponent(i);}},_key:function(h){c(&quot;_key&quot;);return&quot;&quot;;},_hasKey:function(h){return null!==this._getItem(h);},_removeItem:function(h){c(&quot;_removeItem&quot;);return&quot;&quot;;},_setItem:function(h,i){c(&quot;_setItem&quot;);return&quot;&quot;;}};e.augmentProto(d,f.EventProvider);f.Storage=d;}}());(function(){var h=YAHOO.util,e=YAHOO.lang,d={},g=[],f={},b=function(i){return(i&amp;&amp;i.isAvailable())?i:
 null;},a=function(i,l,k){var j=d[i+l.ENGINE_NAME];if(!j){j=new l(i,k);d[i+l.ENGINE_NAME]=j;}return j;},c=function(i){switch(i){case h.StorageManager.LOCATION_LOCAL:case h.StorageManager.LOCATION_SESSION:return i;default:return h.StorageManager.LOCATION_SESSION;}};h.StorageManager={LOCATION_SESSION:&quot;sessionStorage&quot;,LOCATION_LOCAL:&quot;localStorage&quot;,get:function(q,k,p){var n=e.isObject(p)?p:{},o=b(f[q]),m,l;if(!o&amp;&amp;!n.force){if(n.order){l=n.order.length;for(m=0;m&lt;l&amp;&amp;!o;m+=1){o=b(n.order[m]);}}if(!o){l=g.length;for(m=0;m&lt;l&amp;&amp;!o;m+=1){o=b(g[m]);}}}if(o){return a(c(k),o,n.engine);}throw (&quot;YAHOO.util.StorageManager.get - No engine available, please include an engine before calling this function.&quot;);},getByteSize:function(i){return encodeURIComponent(&quot;&quot;+i).length;},register:function(i){if(e.isFunction(i)&amp;&amp;e.isFunction(i.isAvailable)&amp;&amp;e.isString(i.ENGINE_NAME)){f[i.ENGINE_NAME]=i;g.push(i);return true;}re
 turn false;}};YAHOO.register(&quot;StorageManager&quot;,h.SWFStore,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});}());(function(){function a(e,d,c,b,f){this.key=d;this.oldValue=c;this.newValue=b;this.url=window.location.href;this.window=window;this.storageArea=e;this.type=f;}YAHOO.lang.augmentObject(a,{TYPE_ADD_ITEM:&quot;addItem&quot;,TYPE_REMOVE_ITEM:&quot;removeItem&quot;,TYPE_UPDATE_ITEM:&quot;updateItem&quot;});a.prototype={key:null,newValue:null,oldValue:null,source:null,storageArea:null,type:null,url:null};YAHOO.util.StorageEvent=a;}());(function(){var a=YAHOO.util;a.StorageEngineKeyed=function(){a.StorageEngineKeyed.superclass.constructor.apply(this,arguments);this._keys=[];this._keyMap={};};YAHOO.lang.extend(a.StorageEngineKeyed,a.Storage,{_keys:null,_keyMap:null,_addKey:function(b){if(!this._keyMap.hasOwnProperty(b)){this._keys.push(b);this._keyMap[b]=this.length;this.length=this._keys.length;}},_clear:function(){this._keys=[];this.length=0;},_indexOfKey:func
 tion(c){var b=this._keyMap[c];return undefined===b?-1:b;},_key:function(b){return this._keys[b];},_removeItem:function(f){var e=this,c=e._indexOfKey(f),d=e._keys.slice(c+1),b;delete e._keyMap[f];for(b in e._keyMap){if(c&lt;e._keyMap[b]){e._keyMap[b]-=1;}}e._keys.length=c;e._keys=e._keys.concat(d);e.length=e._keys.length;}});}());(function(){var e=YAHOO.util,c=YAHOO.lang,a=function(f){f.begin();},b=function(f){f.commit();},d=function(f,h){var g=this,i=window[f];d.superclass.constructor.call(g,f,d.ENGINE_NAME,h);if(!i.begin){a=function(){};}if(!i.commit){b=function(){};}g.length=i.length;g._driver=i;g.fireEvent(e.Storage.CE_READY);};c.extend(d,e.Storage,{_driver:null,_clear:function(){var g=this,f,h;if(g._driver.clear){g._driver.clear();}else{for(f=g.length;0&lt;=f;f-=1){h=g._key(f);g._removeItem(h);}}},_getItem:function(f){var g=this._driver.getItem(f);return c.isObject(g)?g.value:g;},_key:function(f){return this._driver.key(f);},_removeItem:function(f){var g=this._driver;a(g
 );g.removeItem(f);b(g);this.length=g.length;},_setItem:function(g,f){var i=this._driver;try{a(i);i.setItem(g,f);b(i);this.length=i.length;return true;}catch(h){return false;}}},true);d.ENGINE_NAME=&quot;html5&quot;;d.isAvailable=function(){try{return(&quot;localStorage&quot; in window)&amp;&amp;window[&quot;localStorage&quot;]!==null&amp;&amp;(&quot;sessionStorage&quot; in window)&amp;&amp;window[&quot;sessionStorage&quot;]!==null;}catch(f){return false;}};e.StorageManager.register(d);e.StorageEngineHTML5=d;}());(function(){var h=YAHOO.util,d=YAHOO.lang,e=9948,g=&quot;YUIStorageEngine&quot;,b=null,f=encodeURIComponent,a=decodeURIComponent,c=function(l,o){var n=this,p={},k,i,j;c.superclass.constructor.call(n,l,c.ENGINE_NAME,o);
+if(!b){b=google.gears.factory.create(c.GEARS);b.open(window.location.host.replace(/[\/\:\*\?&quot;\&lt;\&gt;\|;,]/g,&quot;&quot;)+&quot;-&quot;+c.DATABASE);b.execute(&quot;CREATE TABLE IF NOT EXISTS &quot;+g+&quot; (key TEXT, location TEXT, value TEXT)&quot;);}k=h.StorageManager.LOCATION_SESSION===n._location;i=h.Cookie.get(&quot;sessionKey&quot;+c.ENGINE_NAME);if(!i){b.execute(&quot;BEGIN&quot;);b.execute(&quot;DELETE FROM &quot;+g+' WHERE location=&quot;'+f(h.StorageManager.LOCATION_SESSION)+'&quot;');b.execute(&quot;COMMIT&quot;);}j=b.execute(&quot;SELECT key FROM &quot;+g+' WHERE location=&quot;'+f(n._location)+'&quot;');p={};try{while(j.isValidRow()){var m=a(j.field(0));if(!p[m]){p[m]=true;n._addKey(m);}j.next();}}finally{j.close();}if(k){h.Cookie.set(&quot;sessionKey&quot;+c.ENGINE_NAME,true);}n.fireEvent(h.Storage.CE_READY);};d.extend(c,h.StorageEngineKeyed,{_clear:function(){c.superclass._clear.call(this);b.execute(&quot;BEGIN&quot;);b.execute(&quot;DELETE FROM &quot
 ;+g+' WHERE location=&quot;'+f(this._location)+'&quot;');b.execute(&quot;COMMIT&quot;);},_getItem:function(k){var i=b.execute(&quot;SELECT value FROM &quot;+g+' WHERE key=&quot;'+f(k)+'&quot; AND location=&quot;'+f(this._location)+'&quot;'),j=&quot;&quot;;try{while(i.isValidRow()){j+=i.field(0);i.next();}}finally{i.close();}return j?a(j):null;},_removeItem:function(i){c.superclass._removeItem.call(this,i);b.execute(&quot;BEGIN&quot;);b.execute(&quot;DELETE FROM &quot;+g+' WHERE key=&quot;'+f(i)+'&quot; AND location=&quot;'+f(this._location)+'&quot;');b.execute(&quot;COMMIT&quot;);},_setItem:function(r,k){this._addKey(r);var l=f(r),m=f(this._location),p=f(k),q=[],s=e-(l+m).length,o=0,n;if(s&lt;p.length){for(n=p.length;o&lt;n;o+=s){q.push(p.substr(o,s));}}else{q.push(p);}b.execute(&quot;BEGIN&quot;);b.execute(&quot;DELETE FROM &quot;+g+' WHERE key=&quot;'+l+'&quot; AND location=&quot;'+m+'&quot;');for(o=0,n=q.length;o&lt;n;o+=1){b.execute(&quot;INSERT INTO &quot;+g+' VALUES (&
 quot;'+l+'&quot;, &quot;'+m+'&quot;, &quot;'+q[o]+'&quot;)');}b.execute(&quot;COMMIT&quot;);return true;}});h.Event.on(&quot;unload&quot;,function(){if(b){b.close();}});c.ENGINE_NAME=&quot;gears&quot;;c.GEARS=&quot;beta.database&quot;;c.DATABASE=&quot;yui.database&quot;;c.isAvailable=function(){if((&quot;google&quot; in window)&amp;&amp;(&quot;gears&quot; in window.google)){try{google.gears.factory.create(c.GEARS);return true;}catch(i){}}return false;};h.StorageManager.register(c);h.StorageEngineGears=c;}());(function(){var b=YAHOO,i=b.util,g=b.lang,f=i.Dom,j=i.StorageManager,c=215,h=138,d=new RegExp(&quot;^(&quot;+j.LOCATION_SESSION+&quot;|&quot;+j.LOCATION_LOCAL+&quot;)&quot;),e=null,k=function(m,n){return m._location+n;},a=function(n){if(!e){if(!g.isString(n.swfURL)){n.swfURL=l.SWFURL;}if(!n.containerID){var o=document.getElementsByTagName(&quot;body&quot;)[0],m=o.appendChild(document.createElement(&quot;div&quot;));n.containerID=f.generateId(m);}if(!n.attributes){n.attri
 butes={};}if(!n.attributes.flashVars){n.attributes.flashVars={};}n.attributes.flashVars.allowedDomain=document.location.hostname;n.attributes.flashVars.useCompression=&quot;true&quot;;n.attributes.version=9.115;e=new b.widget.SWF(n.containerID,n.swfURL,n.attributes);e.subscribe(&quot;save&quot;,function(p){b.log(p.message,&quot;info&quot;);});e.subscribe(&quot;quotaExceededError&quot;,function(p){b.log(p.message,&quot;error&quot;);});e.subscribe(&quot;inadequateDimensions&quot;,function(p){b.log(p.message,&quot;error&quot;);});e.subscribe(&quot;error&quot;,function(p){b.log(p.message,&quot;error&quot;);});e.subscribe(&quot;securityError&quot;,function(p){b.log(p.message,&quot;error&quot;);});}},l=function(m,p){var o=this;l.superclass.constructor.call(o,m,l.ENGINE_NAME,p);a(o._cfg);var n=function(){o._swf=e._swf;e.initialized=true;var s=j.LOCATION_SESSION===o._location,r=i.Cookie.get(&quot;sessionKey&quot;+l.ENGINE_NAME),u,t,q;for(u=e.callSWF(&quot;getLength&quot;,[])-1;0&lt;
 =u;u-=1){t=e.callSWF(&quot;getNameAt&quot;,[u]);q=s&amp;&amp;(-1&lt;t.indexOf(j.LOCATION_SESSION));if(q&amp;&amp;!r){e.callSWF(&quot;removeItem&quot;,[t]);}else{if(s===q){o._addKey(t);}}}if(s){i.Cookie.set(&quot;sessionKey&quot;+l.ENGINE_NAME,true);}o.fireEvent(i.Storage.CE_READY);};if(e.initialized){n();}else{e.addListener(&quot;contentReady&quot;,n);}};g.extend(l,i.StorageEngineKeyed,{_swf:null,_clear:function(){for(var m=this._keys.length-1,n;0&lt;=m;m-=1){n=this._keys[m];e.callSWF(&quot;removeItem&quot;,[n]);}l.superclass._clear.call(this);},_getItem:function(m){var n=k(this,m);return e.callSWF(&quot;getValueOf&quot;,[n]);},_key:function(m){return l.superclass._key.call(this,m).replace(d,&quot;&quot;);},_removeItem:function(m){b.log(&quot;removing SWF key: &quot;+m);var n=k(this,m);l.superclass._removeItem.call(this,n);e.callSWF(&quot;removeItem&quot;,[n]);},_setItem:function(m,p){var n=k(this,m),o;if(e.callSWF(&quot;setItem&quot;,[n,p])){this._addKey(n);return true;}els
 e{o=f.get(e._id);if(c&gt;f.getStyle(o,&quot;width&quot;).replace(/\D+/g,&quot;&quot;)){f.setStyle(o,&quot;width&quot;,c+&quot;px&quot;);}if(h&gt;f.getStyle(o,&quot;height&quot;).replace(/\D+/g,&quot;&quot;)){f.setStyle(o,&quot;height&quot;,h+&quot;px&quot;);}b.log(&quot;attempting to show settings. are dimensions adequate? &quot;+e.callSWF(&quot;hasAdequateDimensions&quot;));return e.callSWF(&quot;displaySettings&quot;,[]);}}});l.SWFURL=&quot;swfstore.swf&quot;;l.ENGINE_NAME=&quot;swf&quot;;l.isAvailable=function(){return(6&lt;=b.env.ua.flash&amp;&amp;b.widget.SWF);};j.register(l);i.StorageEngineSWF=l;}());YAHOO.register(&quot;storage&quot;,YAHOO.util.Storage,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuistylesheetstylesheetminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/stylesheet/stylesheet-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/stylesheet/stylesheet-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/stylesheet/stylesheet-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+(function(){var j=document,b=j.createElement(&quot;p&quot;),e=b.style,c=YAHOO.lang,m={},i={},f=0,k=(&quot;cssFloat&quot; in e)?&quot;cssFloat&quot;:&quot;styleFloat&quot;,g,a,l;a=(&quot;opacity&quot; in e)?function(d){d.opacity=&quot;&quot;;}:function(d){d.filter=&quot;&quot;;};e.border=&quot;1px solid red&quot;;e.border=&quot;&quot;;l=e.borderLeft?function(d,o){var n;if(o!==k&amp;&amp;o.toLowerCase().indexOf(&quot;float&quot;)!=-1){o=k;}if(typeof d[o]===&quot;string&quot;){switch(o){case&quot;opacity&quot;:case&quot;filter&quot;:a(d);break;case&quot;font&quot;:d.font=d.fontStyle=d.fontVariant=d.fontWeight=d.fontSize=d.lineHeight=d.fontFamily=&quot;&quot;;break;default:for(n in d){if(n.indexOf(o)===0){d[n]=&quot;&quot;;}}}}}:function(d,n){if(n!==k&amp;&amp;n.toLowerCase().indexOf(&quot;float&quot;)!=-1){n=k;}if(c.isString(d[n])){if(n===&quot;opacity&quot;){a(d);}else{d[n]=&quot;&quot;;}}};function h(u,o){var x,s,w,v={},n,y,q,t,d,p;if(!(this instanceof h)){return new h(u,o);}
 s=u&amp;&amp;(u.nodeName?u:j.getElementById(u));if(u&amp;&amp;i[u]){return i[u];}else{if(s&amp;&amp;s.yuiSSID&amp;&amp;i[s.yuiSSID]){return i[s.yuiSSID];}}if(!s||!/^(?:style|link)$/i.test(s.nodeName)){s=j.createElement(&quot;style&quot;);s.type=&quot;text/css&quot;;}if(c.isString(u)){if(u.indexOf(&quot;{&quot;)!=-1){if(s.styleSheet){s.styleSheet.cssText=u;}else{s.appendChild(j.createTextNode(u));}}else{if(!o){o=u;}}}if(!s.parentNode||s.parentNode.nodeName.toLowerCase()!==&quot;head&quot;){x=(s.ownerDocument||j).getElementsByTagName(&quot;head&quot;)[0];x.appendChild(s);}w=s.sheet||s.styleSheet;n=w&amp;&amp;(&quot;cssRules&quot; in w)?&quot;cssRules&quot;:&quot;rules&quot;;q=(&quot;deleteRule&quot; in w)?function(r){w.deleteRule(r);}:function(r){w.removeRule(r);};y=(&quot;insertRule&quot; in w)?function(A,z,r){w.insertRule(A+&quot; {&quot;+z+&quot;}&quot;,r);}:function(A,z,r){w.addRule(A,z,r);};for(t=w[n].length-1;t&gt;=0;--t){d=w[n][t];p=d.selectorText;if(v[p]){v[p].style.cs
 sText+=&quot;;&quot;+d.style.cssText;q(t);}else{v[p]=d;}}s.yuiSSID=&quot;yui-stylesheet-&quot;+(f++);h.register(s.yuiSSID,this);if(o){h.register(o,this);}c.augmentObject(this,{getId:function(){return s.yuiSSID;},node:s,enable:function(){w.disabled=false;return this;},disable:function(){w.disabled=true;return this;},isEnabled:function(){return !w.disabled;},set:function(B,A){var D=v[B],C=B.split(/\s*,\s*/),z,r;if(C.length&gt;1){for(z=C.length-1;z&gt;=0;--z){this.set(C[z],A);}return this;}if(!h.isValidSelector(B)){return this;}if(D){D.style.cssText=h.toCssText(A,D.style.cssText);}else{r=w[n].length;A=h.toCssText(A);if(A){y(B,A,r);v[B]=w[n][r];}}return this;},unset:function(B,A){var D=v[B],C=B.split(/\s*,\s*/),r=!A,E,z;if(C.length&gt;1){for(z=C.length-1;z&gt;=0;--z){this.unset(C[z],A);}return this;}if(D){if(!r){if(!c.isArray(A)){A=[A];}e.cssText=D.style.cssText;for(z=A.length-1;z&gt;=0;--z){l(e,A[z]);}if(e.cssText){D.style.cssText=e.cssText;}else{r=true;}}if(r){E=w[n];for(z=E.l
 ength-1;z&gt;=0;--z){if(E[z]===D){delete v[B];q(z);break;}}}}return this;},getCssText:function(A){var B,z,r;if(c.isString(A)){B=v[A.split(/\s*,\s*/)[0]];return B?B.style.cssText:null;}else{z=[];for(r in v){if(v.hasOwnProperty(r)){B=v[r];z.push(B.selectorText+&quot; {&quot;+B.style.cssText+&quot;}&quot;);}}return z.join(&quot;\n&quot;);}}},true);}g=function(n,p){var o=n.styleFloat||n.cssFloat||n[&quot;float&quot;],r;try{e.cssText=p||&quot;&quot;;}catch(d){b=j.createElement(&quot;p&quot;);e=b.style;e.cssText=p||&quot;&quot;;}if(c.isString(n)){e.cssText+=&quot;;&quot;+n;}else{if(o&amp;&amp;!n[k]){n=c.merge(n);delete n.styleFloat;delete n.cssFloat;delete n[&quot;float&quot;];n[k]=o;}for(r in n){if(n.hasOwnProperty(r)){try{e[r]=c.trim(n[r]);}catch(q){}}}}return e.cssText;};c.augmentObject(h,{toCssText:((&quot;opacity&quot; in e)?g:function(d,n){if(c.isObject(d)&amp;&amp;&quot;opacity&quot; in d){d=c.merge(d,{filter:&quot;alpha(opacity=&quot;+(d.opacity*100)+&quot;)&quot;});delete
  d.opacity;}return g(d,n);}),register:function(d,n){return !!(d&amp;&amp;n instanceof h&amp;&amp;!i[d]&amp;&amp;(i[d]=n));},isValidSelector:function(n){var d=false;if(n&amp;&amp;c.isString(n)){if(!m.hasOwnProperty(n)){m[n]=!/\S/.test(n.replace(/\s+|\s*[+~&gt;]\s*/g,&quot; &quot;).replace(/([^ ])\[.*?\]/g,&quot;$1&quot;).replace(/([^ ])::?[a-z][a-z\-]+[a-z](?:\(.*?\))?/ig,&quot;$1&quot;).replace(/(?:^| )[a-z0-6]+/ig,&quot; &quot;).replace(/\\./g,&quot;&quot;).replace(/[.#]\w[\w\-]*/g,&quot;&quot;));}d=m[n];}return d;}},true);YAHOO.util.StyleSheet=h;})();YAHOO.register(&quot;stylesheet&quot;,YAHOO.util.StyleSheet,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiswfswfminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/swf/swf-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/swf/swf-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/swf/swf-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+YAHOO.namespace(&quot;widget&quot;);(function(){var f=0;var m=YAHOO.env.ua;var p=&quot;ShockwaveFlash&quot;;var o,q;if(m.gecko||m.webkit||m.opera){if((o=navigator.mimeTypes[&quot;application/x-shockwave-flash&quot;])){if((q=o.enabledPlugin)){var j=[];j=q.description.replace(/\s[rd]/g,&quot;.&quot;).replace(/[A-Za-z\s]+/g,&quot;&quot;).split(&quot;.&quot;);f=j[0]+&quot;.&quot;;switch((j[2].toString()).length){case 1:f+=&quot;00&quot;;break;case 2:f+=&quot;0&quot;;break;}f+=j[2];f=parseFloat(f);}}}else{if(m.ie){try{var i=new ActiveXObject(p+&quot;.&quot;+p+&quot;.6&quot;);i.AllowScriptAccess=&quot;always&quot;;}catch(r){if(i!=null){f=6;}}if(f==0){try{var l=new ActiveXObject(p+&quot;.&quot;+p);var j=[];j=l.GetVariable(&quot;$version&quot;).replace(/[A-Za-z\s]+/g,&quot;&quot;).split(&quot;,&quot;);f=j[0]+&quot;.&quot;;switch((j[2].toString()).length){case 1:f+=&quot;00&quot;;break;case 2:f+=&quot;0&quot;;break;}f+=j[2];f=parseFloat(f);}catch(r){}}}}m.flash=f;YAHOO.util.SWFDetect
 ={getFlashVersion:function(){return f;},isFlashVersionAtLeast:function(e){return f&gt;=e;},parseFlashVersion:function(e){var u=e;if(YAHOO.lang.isString(e)){var v=e.split(&quot;.&quot;);if(v.length&gt;2){u=parseInt(v[0]);u+=parseInt(v[2])*0.001;}else{u=parseFloat(e);}}return YAHOO.lang.isNumber(u)?u:null;}};var b=YAHOO.util.Dom,t=YAHOO.util.Event,g=YAHOO.util.SWFDetect,h=YAHOO.lang,a=&quot;clsid:d27cdb6e-ae6d-11cf-96b8-444553540000&quot;,n=&quot;application/x-shockwave-flash&quot;,s=&quot;10.22&quot;,d=&quot;http://fpdownload.macromedia.com/pub/flashplayer/update/current/swf/autoUpdater.swf?&quot;+Math.random(),c=&quot;YAHOO.widget.SWF.eventHandler&quot;,k={align:&quot;&quot;,allowfullscreen:&quot;&quot;,allownetworking:&quot;&quot;,allowscriptaccess:&quot;&quot;,base:&quot;&quot;,bgcolor:&quot;&quot;,devicefont:&quot;&quot;,loop:&quot;&quot;,menu:&quot;&quot;,name:&quot;&quot;,play:&quot;&quot;,quality:&quot;&quot;,salign:&quot;&quot;,seamlesstabbing:&quot;&quot;,scale:&quot
 ;&quot;,swliveconnect:&quot;&quot;,tabindex:&quot;&quot;,wmode:&quot;&quot;};YAHOO.widget.SWF=function(e,K,F){this._queue=this._queue||[];this._events=this._events||{};this._configs=this._configs||{};this._id=b.generateId(null,&quot;yuiswf&quot;);if(F.host){this._host=F.host;}var H=this._id;var x=b.get(e);var u=g.parseFlashVersion((F[&quot;version&quot;])||s);var E=g.isFlashVersionAtLeast(u);var D=(m.flash&gt;=8);var y=D&amp;&amp;!E&amp;&amp;F[&quot;useExpressInstall&quot;];var C=(y)?d:K;var B=&quot;&lt;object &quot;;var I,A;var J=&quot;YUISwfId=&quot;+H+&quot;&amp;YUIBridgeCallback=&quot;+c;YAHOO.widget.SWF._instances[H]=this;if(x&amp;&amp;(E||y)&amp;&amp;C){B+='id=&quot;'+H+'&quot; ';if(m.ie){B+='classid=&quot;'+a+'&quot; ';}else{B+='type=&quot;'+n+'&quot; data=&quot;'+YAHOO.lang.escapeHTML(C)+'&quot; ';}I=&quot;100%&quot;;A=&quot;100%&quot;;B+='width=&quot;'+I+'&quot; height=&quot;'+A+'&quot;&gt;';if(m.ie){B+='&lt;param name=&quot;movie&quot; value=&quot;'+YAHOO.lang.esca
 peHTML(C)+'&quot;/&gt;';}for(var v in F.fixedAttributes){if(k.hasOwnProperty(v.toLowerCase())){B+='&lt;param name=&quot;'+YAHOO.lang.escapeHTML(v.toLowerCase())+'&quot; value=&quot;'+YAHOO.lang.escapeHTML(F.fixedAttributes[v])+'&quot;/&gt;';}}for(var G in F.flashVars){var z=F.flashVars[G];if(h.isString(z)){J+=&quot;&amp;&quot;+YAHOO.lang.escapeHTML(G)+&quot;=&quot;+YAHOO.lang.escapeHTML(encodeURIComponent(z));}}if(J){B+='&lt;param name=&quot;flashVars&quot; value=&quot;'+J+'&quot;/&gt;';}B+=&quot;&lt;/object&gt;&quot;;x.innerHTML=B;YAHOO.widget.SWF.superclass.constructor.call(this,b.get(H));this._swf=b.get(H);}};YAHOO.widget.SWF._instances=YAHOO.widget.SWF._instances||{};YAHOO.widget.SWF.eventHandler=function(e,u){YAHOO.widget.SWF._instances[e]._eventHandler(u);};YAHOO.extend(YAHOO.widget.SWF,YAHOO.util.Element,{_eventHandler:function(e){if(e.type==&quot;swfReady&quot;){this.createEvent(&quot;swfReady&quot;,{fireOnce:true});this.fireEvent(&quot;swfReady&quot;,e);}else{if(e.t
 ype==&quot;log&quot;){}else{if(this._host&amp;&amp;this._host.fireEvent){this._host.fireEvent(e.type,e);}else{this.fireEvent(e.type,e);}}}},callSWF:function(u,e){if(!e){e=[];}if(this._swf[u]){return(this._swf[u].apply(this._swf,e));}else{return null;}},toString:function(){return&quot;SWF &quot;+this._id;}});})();YAHOO.register(&quot;swf&quot;,YAHOO.widget.SWF,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiswfdetectswfdetectminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/swfdetect/swfdetect-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/swfdetect/swfdetect-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/swfdetect/swfdetect-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+YAHOO.namespace(&quot;util&quot;);(function(){var h=0;var f=YAHOO.env.ua;var i=&quot;ShockwaveFlash&quot;;var b,d;if(f.gecko||f.webkit||f.opera){if((b=navigator.mimeTypes[&quot;application/x-shockwave-flash&quot;])){if((d=b.enabledPlugin)){var c=[];c=d.description.replace(/\s[rd]/g,&quot;.&quot;).replace(/[A-Za-z\s]+/g,&quot;&quot;).split(&quot;.&quot;);h=c[0]+&quot;.&quot;;switch((c[2].toString()).length){case 1:h+=&quot;00&quot;;break;case 2:h+=&quot;0&quot;;break;}h+=c[2];h=parseFloat(h);}}}else{if(f.ie){try{var j=new ActiveXObject(i+&quot;.&quot;+i+&quot;.6&quot;);j.AllowScriptAccess=&quot;always&quot;;}catch(g){if(j!=null){h=6;}}if(h==0){try{var a=new ActiveXObject(i+&quot;.&quot;+i);var c=[];c=a.GetVariable(&quot;$version&quot;).replace(/[A-Za-z\s]+/g,&quot;&quot;).split(&quot;,&quot;);h=c[0]+&quot;.&quot;;switch((c[2].toString()).length){case 1:h+=&quot;00&quot;;break;case 2:h+=&quot;0&quot;;break;}h+=c[2];h=parseFloat(h);}catch(g){}}}}f.flash=h;YAHOO.util.SWFDetect={
 getFlashVersion:function(){return h;},isFlashVersionAtLeast:function(e){return h&gt;=e;},parseFlashVersion:function(e){var k=e;if(YAHOO.lang.isString(e)){var l=e.split(&quot;.&quot;);if(l.length&gt;2){k=parseInt(l[0]);k+=parseInt(l[2])*0.001;}else{k=parseFloat(e);}}return YAHOO.lang.isNumber(k)?k:null;}};})();YAHOO.register(&quot;swfdetect&quot;,YAHOO.util.SWFDetect,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiswfstoreswfstoreminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/swfstore/swfstore-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/swfstore/swfstore-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/swfstore/swfstore-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,7 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+YAHOO.util.SWFStore=function(a,c,d){var b;var e;c=c.toString();d=d.toString();if(YAHOO.env.ua.ie){b=&quot;ie&quot;;}else{if(YAHOO.env.ua.gecko){b=&quot;gecko&quot;;}else{if(YAHOO.env.ua.webkit){b=&quot;webkit&quot;;}else{if(YAHOO.env.ua.caja){b=&quot;caja&quot;;}else{if(YAHOO.env.ua.opera){b=&quot;opera&quot;;}else{b=&quot;other&quot;;}}}}}if(YAHOO.util.Cookie.get(&quot;swfstore&quot;)==null||YAHOO.util.Cookie.get(&quot;swfstore&quot;)==&quot;null&quot;||YAHOO.util.Cookie.get(&quot;swfstore&quot;)==&quot;&quot;){e=Math.round(Math.random()*Math.PI*100000);YAHOO.util.Cookie.set(&quot;swfstore&quot;,e);}else{e=YAHOO.util.Cookie.get(&quot;swfstore&quot;);}var f={version:9.115,useExpressInstall:false,fixedAttributes:{allowScriptAccess:&quot;always&quot;,allowNetworking:&quot;all&quot;,scale:&quot;noScale&quot;},flashVars:{allowedDomain:document.location.hostname,shareData:c,browser:e,useCompression:d}};this.embeddedSWF=new YAHOO.widget.SWF(a,YAHOO.util.SWFStore.SWFURL,f);this.cre
 ateEvent(&quot;error&quot;);this.createEvent(&quot;quotaExceededError&quot;);this.createEvent(&quot;securityError&quot;);this.createEvent(&quot;save&quot;);this.createEvent(&quot;clear&quot;);this.createEvent(&quot;pending&quot;);this.createEvent(&quot;openingDialog&quot;);this.createEvent(&quot;inadequateDimensions&quot;);};YAHOO.extend(YAHOO.util.SWFStore,YAHOO.util.AttributeProvider,{on:function(a,b){this.embeddedSWF.addListener(a,b);},addListener:function(a,b){this.embeddedSWF.addListener(a,b);},toString:function(){return&quot;SWFStore &quot;+this._id;},getShareData:function(){return this.embeddedSWF.callSWF(&quot;getShareData&quot;);},setShareData:function(a){this.embeddedSWF.callSWF(&quot;setShareData&quot;,[a]);},hasAdequateDimensions:function(){return this.embeddedSWF.callSWF(&quot;hasAdequateDimensions&quot;);},getUseCompression:function(){return this.embeddedSWF.callSWF(&quot;getUseCompression&quot;);},setUseCompression:function(a){this.embeddedSWF.callSWF(&quot;se
 tUseCompression&quot;,[a]);},setItem:function(a,b){if(typeof b==&quot;string&quot;){b=b.replace(/\\/g,&quot;\\\\&quot;);}return this.embeddedSWF.callSWF(&quot;setItem&quot;,[a,b]);},getValueAt:function(a){return this.embeddedSWF.callSWF(&quot;getValueAt&quot;,[a]);},getNameAt:function(a){return this.embeddedSWF.callSWF(&quot;getNameAt&quot;,[a]);},getValueOf:function(a){return this.embeddedSWF.callSWF(&quot;getValueOf&quot;,[a]);},getTypeOf:function(a){return this.embeddedSWF.callSWF(&quot;getTypeOf&quot;,[a]);},getTypeAt:function(a){return this.embeddedSWF.callSWF(&quot;getTypeAt&quot;,[a]);},getItems:function(){return this.embeddedSWF.callSWF(&quot;getItems&quot;,[]);},removeItem:function(a){return this.embeddedSWF.callSWF(&quot;removeItem&quot;,[a]);},removeItemAt:function(a){return this.embeddedSWF.callSWF(&quot;removeItemAt&quot;,[a]);},getLength:function(){return this.embeddedSWF.callSWF(&quot;getLength&quot;,[]);},clear:function(){return this.embeddedSWF.callSWF(&quot
 ;clear&quot;,[]);},calculateCurrentSize:function(){return this.embeddedSWF.callSWF(&quot;calculateCurrentSize&quot;,[]);},getModificationDate:function(){return this.embeddedSWF.callSWF(&quot;getModificationDate&quot;,[]);},setSize:function(b){var a=this.embeddedSWF.callSWF(&quot;setSize&quot;,[b]);return a;},displaySettings:function(){this.embeddedSWF.callSWF(&quot;displaySettings&quot;,[]);}});YAHOO.util.SWFStore.SWFURL=&quot;swfstore.swf&quot;;YAHOO.register(&quot;swfstore&quot;,YAHOO.util.SWFStore,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiswfstoreswfstoreswf"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/swfstore/swfstore.swf (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/swfstore/swfstore.swf                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/swfstore/swfstore.swf        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,51 @@
</span><ins>+CWS
+\x94x\xDA}Yi|[ŵ\x9Fs\x8D\xAE$\xDB\xF2\xC7v\xB6\x9BÄŽ\x97\xC8K6HL0\xF1\xA6\xD8\xC1\x89\x82\x97\xC4        8Ö•t\xAF%&quot;\xE9
+\xDD+/\x976\xD0R(P
+--\xA5.\xA5\xA5\x94.P\xA0t\x85\xB6t\xE3\xF5\xF5U\xB2I\xBE\xBFO\xFDÔ\xEF\xC3\xFB\xE2wf\xAE$\xDB\xD0\xDFs\x98\xD1Ì™3gÎœ\xF3?\xE7\xCC\xFD\x91!n\x83\x90 \xA7H\x90\xA1\xEAFB\xC8\xF5Ú¿!'\xB31\xA3w|(\xA8.\xA6\x92i\xABgw\xB7\xC6m;\xD3\xDBݽ\xB0\xB0еp\xA4\xCB\xCC\xCEu:q\xE2Dw\xCF\xE1\xEEÇ;\x91\xA3\xD3ZJ\xDB\xDAbg\xDA\xDA\xDF\xDA\xC7 \xE9V4\x9B\xC8\xD8        3\xAD\xB2\xB91s\xF6Ý­\xADE\xA9\xB1hYh&amp;\x97Mr\x91\xB1h\xB7\x9E\xD4SzÚ¶\xBAuBA\xB1h\xAFafS\x9Aݧe2\xC9DTc\xE2\xBA;\xAD\xB8\xBD\xBA\xA0\xCD\xEB\x9DFR\xB3\xE2'\xBB7\xD9;a'\xF5\xBE\xFE\x98\xD1\xD5`R_T\x8F\xA8\xFD\xFB9\xB7\xC3˜c\x8A\xF6m\xBA\xA6\xC6vwE\xCDTw&amp;k\xC6rQ\xD4\xC9@Q|\xF3\xE6-LD&amp;I&amp;\xAC\xB8\x9E\xEDË¥\xAF\xA6\xCD\xE7\x88+*\xE3\x89fu\xCD6\xB7r\x94hl=\xA9\xA5\xE7rÚœ\xDE7|\x8E\xAF\x95\xE7\G\xCD\xD6\xFB&amp;\xF4\x8Cz\xE8h@=\xDCs\xA8\xC7Q\x83QOv\xC2\xDAE
+:\xB0\x8F \xF9\xFF)\x9E$\x83\xC2\xE3/\xBF~\xD9#\xA2\x87]\xD8D\xE9\xCEf\xC2\xFF&gt;\xF7Ï–\xEA\x83\xE8\xF1\x8F=\x83\xA8\x89N&gt;\xAC\xBB\xB2\x93\xA4#\xAB\xA5\xF4C\xC4O\xBA\x88\xB4\x8EUO\xC2m\xA4\xAF\xA1\xA6\x99Ôµ\xB44o&amp;b\xAE        \x9BHω\x89\xB4-\xF7g\xB3Ú’\x94á4\x84\xBA\xF9\xB8s\xBA\xF4y\xE6Qy\x98\xFD\xF8FC\xC3Ù¬\x99å“š        =\x9A\xCB&amp;\xEC\xA5+\x92+yP\x8FÚ¢\x8B\xB9\xCE\xE5R=[yN\xB7'l\xCD\xCEY\x9C\xA1‘KX\x99\xA4\xB6$\xE3Êœ\xEE.i\xEF\x9AÈ 8\xBD&quot;ij\xB1\x8Bq\xA1\xFD\xEDmq\xCD\xEA\x8F\xE9\xE5P\xA3\xA1\xA2\xCBB#Y\xEEY-\x8D'\xE6u\xC9BU\xE5Mè¶\x97\xB1\xA8\xA5Û“\xC8[e\xA6\xB7\xE8\xA8\xCC!})\xA3\xF7\xDB]Ð’9\xD6\xCC.\x94\xCE
+&amp;\x92\xFA94\xDB6 \xD5A\xCD:\xCB+]{\xAF\x99._Æ\xFBGm=Å\x9AH&lt;\xAC3\x81\xA3阾2\xD8)LJ\xBF]\x8D\xA3)K4S\x99\xACn1Å•\xA5\&quot;\x92M\xC4\xE6\xF4J\xC4f×’7Í®\x9C\x9DH*\x97\xA6F\xF8BUFϲ`\x98;\xAB\xD9Ѹ/\xAB\xA7\xCCy\x9D\x9D\xD6o\xFBfé„Ð’xdÌ›\xD1\xEC8\xE7Ñ­Z&lt;\xEA\xACK\xC5(a\xAC\xB6&gt;y&lt;E\xAE\xF3\xB8\xA9bÖŠkY=\xE6\xB8Kq\x9C\x92\xD6m\xDF\xC4&amp;2\xBB;U\x8E&quot;Z\xB2&gt;vQ\xB6\x8A\x925j\xA6\xB9A=\x8EFb\xB7\xD3\xD3sv\xBCd\xE5\x90Q\xB6rȨ\xDF\xD0{\xF3uQ-\xCD%Q\xD9\xC1\6\x8B\xE1\xB6ܸ\xB1\xC7L3\xF5\x93:\xC2qn\x938\xB9W_*\xBA\xB0j6\xB7\xE5\x9A+[m\xDB[\xB6\xADg\xF6AkDKÇ’z\xD65k-\xA3C\x8A\xA5\xA7c\x9A\x8E浬\xE5C\xF8j\xC9dD\x8B^\xB5\x90\x8F\x81\xB4\xF2\xEC\xE8\xB9ѳSggG\x86GO\x8FLV\x94\xA6G\x87&amp;G\xF6\xCFF\xD2\xE9\x9F8\xD2}\xB8\xA7\xE7\x8E\xEEH.\x91DL\xD6m\xC1}\xAF\xF4\xE6\xAD\xC4!\xE7\xD71Ì \x89        9\x91Ö³{\xB62\x8D\xA6m=\xABEm\x84\xBEø\xE3\xFF\xB2ss\xF7\xF2[\xB2u\x8E\x98\xAC\xCC\xEF\xE5uX\x98\x99,e`\xC9Ö$cN.\x86\x98w\x81)\xEBHtG\x8BV\x96
 \x8DdΊ\xD3b\xA0Tb\x90\x86\xD2\xE7\xB3&amp;\x82\xD7^r\xE52,\xB9IH\x8DK\xE43fÆ•\xE4\xE8pY,\x93뮘Μ*\xD9\xC9B\xA7W\xE0\xD64\xEF\x82Äœ+\xE6k\xC9B\xB8KA\Q\x9C\xD7\xD2z\xB2b,4\xD8?6;1\xEF?=\xECâ\xB2PJu\x89\xB4\xF6\xA9\x9CAS\xA87*{t2\xAE\xABQn*;Z5+\xD5F\xE6!5a\xA9\xB6i\xAAV
+\xFD\x8F#\xB5hW\xF5
+c\xB0\x8A\xE2\xD5 ;\xBFK=\x8F\x81a\xE9j&quot;\xCD*\x8F6\xAF%\x92Z$\xA9\xAB \x89\x98Wmj\O\xCC\xC5m&amp;\xEE\xF0\xA1c\x99EuQ=t\xE48\xFE\x9AY5\xA9e\xE7\xF4l\x97?\xF5\x89Ø¥\x89b2\xC140\x86\xF9PϺCgÏ+O\xFB\x9EÜ—c\x98\x98t\x84\x88{44;&lt;&gt;\xAF\x9C\x9C\x9D\xBC\xE4L=I\xBEq4m\x98&quot;iW\xA3\xA7߆n\xD9b\xF0\xA2\x85K)˃\xA7\x8C\xA3\xBDtË–\xD8&amp;q\xFA\xEC\x98\xCBf\xAAÙ²\xCE\xBD\xB2\x88\xA4ED_ZKV\x8E\x86\xD5ÛŒ\:Ê”ok\xBF\x96\xD5\xED\6\x8D\xF7O\xC7Ì…\xAE\xA4\xE9ܪ+\x9EÕ\xBB\x950\xE2\x93\xD5\xD8Ì…N-E\x97tY3UamN\xD4\xF7\x95\xAD\xF2i/\xB7l9\xAB1S\xB7Ô´i\xAB\\x8C\xEA\x88a\xE6-\xC2Qeq:\xB3t\xBA\xC22F3È\xF7\x95\xE71\xC5$\x96C=Q\x8C64(\xDEZ\xD4\xE7\xF1\xCA̺\x92\x8D\xB7u\x8D\xEBsËWK[WG{ \xCD\xEA\x86\xA8\xF7\xB8si,\xD9ZF?\xC5\xC03S\xAB%1\xF9j*\x87z\xA6X\xA4\x95\xA0\xD5j\xF9\xBA&lt;\xE7\x91\xA7\xA8D\xAF
+\xAF\xB3\xC8g2W\x9C\xA8Ç6;&lt;1\xE8)\xA2\xA7Jy\xA1r\x83\xC8y2\xAB\xF8\xE8\x8BF\xB2æ‚…n\xE2\xD1Y\xA5\x9C\xA2%;\x9B\xD3+\xB7\xA6J[\xE0\xD5w\x96Õ´14W\xD2snxêrjBA`\xC7XZ\xB0&lt;\xE8\xDF\xE26#:\xF9\xC0W\xB4\xDC8R\x96f\xEC$\xAB/&quot;\x8E\xE4Û¦`\xFCf\xB8V{XQÞ¾9\xFFYqJ*+\x8EMM\x8C I        \x86׫\xFA\x92\xDBL\xC6x\x82w\xA7\xF5&gt;\x90yP\xD0\xF3\xC3\xE7\x86FÏ\xA6\x980b\x8EO\xC1T\x9A\xBE\xBA\xD4\xC1du\xEA\xB41\xBD         \xCCEjD\xD7\xD3,\xA2wL\xC5&quot;\xEB`\xA4\xE8u\xD2Tu.)P{\xE6\xBB \x83\xFE'b\x9F\x875\x92T\xAD|\x80\x962si\xBB\xCB]B\x9C M\x95K\xDArÑ”\xACy(g\xDA\xDA\xF0bT\xD7\xD1{\xDC\xC9\xD5\xE5\xC7D        \xE4RÔŒ\xE9G'\x8A\xF2]Z\x94\x85@\xD6        L\xD4X\xE7\xFB\xADM9\xA6x(\xB5r&lt;\xBC&lt;\xA7\x8F\xF0t\xE3\xE1\xE3\x8B,        U}&quot;\xF5Wl\xA9ÕŸ\xAA)\xF5\xFF\xBEU\x97\xEBh\xA9:\xBA\x912\x81e4\xA6\x94U\xAA\xBAr\xE7e\xAD\xF3\xE1\x9E\xCE]3\xCD0\x87\x81d\xD9\xDEM5U\xB6\xF14\xBD\xB6?\x86\xA6P\xA3E&quot;wUÓˆ\xE1\x98\xEA\xC6\xDA\xCC!U9\xE1\xF8X\xE5!\xA96\xD5C\xBDR_\xDDP+\x93\
 xFA\xD6\xFAC+2\x91\xC9vp\xDF\xDBT\xDB4\xD6t\xB6\xE9\S\xA8\xE9|SE\xFDx\xBD^\xBF \xB8\xD4\xDA4 U\xC8c&gt;\xA9\xA2\xB2\xCA_]S\xAB(\xB0\xDD\xD5\xE0s7Ö‚\xEB\xCF@A\xA0 R\x90(\xC8\(7&lt;T\xF0R\xC1G\xA1\x82B\xFCT\xAC\xA1PK\xC5:*o\xA3PO\xE5\xEDTj\xA0\xD0H\xA5&amp;*ï °\x93\xC2.*漣Ja/\x85}T\xDEO\xA1\x99B \x95PW\x95\xDB)tP\xF9 \x95:)tQ\xE8\xA6r\xA5\x87)\xA1p\x94\xC21*\xDFA\xE5;)\xA7p\x82B/\x95\xEE\xA2p\x92\xC2\xDDT\xEE\xA3p\x95NQ\xB9\x9F*\x83T\xA20L!H\xE14UF(\x8CR8\xA3\xF4\x82\xB2\x94]\xA04\x83r\x94NPN\x82r\x94\xBBA\xE9\xE5((\xFB@i\xE5(;A\xE9\xA5\x94c\xA0\xDCJ=Z\xE0&gt;Z7AaR\x99\xC2\xF1
+)L+\x97@\xB9 ;@y\x94P\xAE\x802 \xD47\xA3\x84\x91%J\xB7t\xDB\x858\x85\x84\x92\xC5D\xA3e(&lt;D!K\xC1\xA2`S\xC8Q\x98\xA70K} Ô·D}Sz\x8D\xC2#\xA5\xF0e\x85\\xA5\xF5\x9FÅŸ\xCFA\xE5&lt;\xFE&lt;\x81\xED:\xF5~\xA8\xF7\x8BØž\xC4\xF6%l\xF3\xD4\xFB\xFE&lt;\x8DG\x9B\xBE\x8CL\xCF\xE0\xF09\xFC}\xDB×°}\x97_\xC2\xF6+l\xDF\xC4\xF62Ò¾\xCA+\xCA
+\xB6W\xE7\xAFa\xFB\xEE\xBBL\xE1\xFB8|\xDB\x90\xF5\x87\xD8\xDE\xC4\xF6
+\xB6a\xFB1\xB2\xFCo\xF2S\ \x94(o\xA3\x84\x9Fa{Û»\xD8\xDEc\xD2~\x8E\xACoc{\xDB{\xD8~\x89\xEDl\xEA\xFD.\xBF+ʯ\x91\xF5\xC6\xFA{l*|T\xFC#\xB6?a\xFB3\xEC@\xC0}\x8Cg\xFD'\xAE\xFE\xDB\xE1Y\x82\xD2&amp;\xB6\x93\xD2~\xA5\x81\x9B\x88|&amp;\xB2N\xC2Nd#Q*v\x8C\x84a@\x80\xB1H\xCEN\xF6\xAD\xE8, \xD8(N$Ñ™\x80\xE0&amp;\x82\xE0\xD6y\x8A2q\x95\xFF/î“‘\xE4ÅG\xF6\xF9*\xC1\x87 \x82\xE0c\xFC\xC5#\xCA
+W2\xAA\xB7\xD8\xF1?\xA1ʯHÚª\x81\xD4\xD7\xD9WK\x88\x97\xD4Ù³+Hm=u;\x90\xA6 \x9EF \xEE&amp;\xFC\xAA݃p#{w\xA9\xD8\xA4f7\x90m{\x80xU \xC2^B\xF6\x91\xFD@v6\xA9ja\xC7\xD2\xD0
+\xA4\xAE+m\xD2dG!I\x88\xAB\x88\xBF \x88\xDC+\xA4\xB1\x87q\xE2; c\x81У@vR}\xEA{'\x90\xED\xC7ј'\x80\xEC\xEEe\x8C\x{3F0A6F4}\xB8\xEEBM\xC8I\xD6\xDD+\xA4\xB5\x8F)}\x9Ew\x8A\xB0+
+\xFDD\xF0        \xE2\x9F(6a?TI@\xDA`^\xB4\xAD\xE6V\xAA\xF3=WZn\x836p\xA5\xBF\xE5I\xD0\xFAO3\xCB
+\x8A\xE7\xC8\xF7\xE4GI&gt;TM\xA6Ȳ\xF7f!o\xD1\xB1ß©+aߨ+c\xBFG bH;\x8D}\xAB6\x82\xFD1m\xFB\x80v\xFB;\xB4{\xB1o\xD6Æ°\xEF\xD4\xCEb\xBFK;\x87\xFD6-\x84\xFDa\xED&lt;\xF6+\xDA}Ø·i\xE3Ø«\xDA\xF6]\xDA$\xF6ǵ\xA9\xF2\xB8F\xBB\x90\x9F\xD9\xBExf\xC4\xF7æ½\x85\xD0=p\x9A\x81 \x8F \xB54zG\xF0\xFE\x82\xA8x\xF3=\xEA\xF2\xF4\xAD|!Þ›7:\x8CK\xC6\xE5\xF0\xF4;/v\xD4 R\xDA \xF35è—™\xE93\xD3YV\xF3Fm\xE8~X+=@8\xE7\xAAvC3K[\xCBZË\xB3B\xBC':\xCA\2U&lt;\xABh \xF5FTR\x97\xBD\xB7Q\x98q\xA5\x9C\x85\x9A6B\x9C\x89^\xADC趎\xE4 \xC1#P\xE6Y\xD5Â\x{38D2FDE}\x90@eT*\xD9@+\x84&quot;\x90/D\xA4\xB5\xD5`\x9D4\xDF\x95\xAB\x84\xF81\xCE\x87oM \xFB/\x96g\x86\xDB\xF9\xAEP\x94\xF8\xFB\x91\xEAGD\xA4\xA8+p\xC4Õ„\xB1\xD4L\xFCM\xEC\x94\xE2 \xFC        ~6\xFC\xEBÝ®__\xDEX_}GoK\xD9m\x9B\xD8\xDDK7R6n4\xA2&quot;\x87[\x90O3\xB3Gpܸ\xB5Z\x8D\xC2\xD4βj\x84\xF1\xA2ke+y&amp;m\xC7fi\x9E+i/pqÆ¢pq\x8D\xF0\xBCÌ‘Ûœ=\xB2\x95\x8FX\xC5Es\x8D\xA7\xB8hÄR!\xA1:Ç&lt;D\xAC\x9BȲ|\xAB\x99
 Ø·\xFD+x\xFA*?\x8A\xF3\xAEa#\xD2a\xED9\xFB\xF6Za\xDB\xAF\xAF3q\x95.Y\xF1\xDC\xC9\xDF+Ö­\x92feo\x95L\xBC\xDA !C\xC8Úš\x8A\xBE\x91\xD17n\xAFbÛu_\xF6\xDErL\xE2\xEC]+\xED-8{\xD7ÚªZ\xD8\xD8\xEB\x97\xF1Þ­\xEC&amp;\xA1N\x92\\x9A&quot;\x81.\x90)!^\x88\xA6P\xDEM\x8E\xF5\xBB\xE1\xB2WC\x85\xD69\xFBfI5&quot;\xAA\x8E\x81\xEF(\xB4,\xBB_+\xCE0\x8F\xE0Z-\x93Σ\xA5kH\xCD.DB$\xDB,6'\x8CCW\xC1\xBF\x9D/&gt;\xB8HR+S\xC2\x82\xBD\x8E9\xA86\xDF3C\x9D\x90J\x9E\xA1\xB0L\xB9\xDBØ’\xAF\xE4\xAA`
+\x90V/\xB9O\x8Eiu{&amp;}&amp;M\x96\xD37 a\xB7a\xE6\x8D;C\xA1V\x8C\x87\xF2F7z\x8Cl\xDE؎ðeب\xF7\xAA\x91{&gt;8\x81\xC57\xD1D )\xABͤy=\xB8 \xE0Z3Y+,\x81\xCDn\xAFW\xF2F\xD3Ê\xA8\\x98Y\x8A\xC8g\x96 \xF40\xD3u\xBB,{\xAA\xFE\x85\x81y\xB1\xE3V\x8F\xEAòµ” CkJt\xC62\xFE\xDCH\xB9\xD8Ä›\xA2:R\xA0\xC3\xCC5\x92`&lt;b&lt;z\xE6\xB0+\xFE\xFD\x88ў՞ˤ\xE3vG\xCF\xC1\x84\xF7\xA2u\xAE\xAE\xEA\xF2}fJ@\xBB\xECr\xA3\xC8\xF0\xF5\xC0c\\xB8\x91\x92\x9A\xC9m#&gt;F\xF81\x8Co\xCC\xE5\x8A\xCA\xFB\x9DsqQ6&gt;\x8B\x9C\xAE&lt;%l\xAE\xE0\x81\x97R\xA2\xCB\xDDaI\xAC\xFEx}\xDD-1\xD9I\xB1Æj`\xBE\xF1\xEFd&lt;\xA8\xC1+@=\xCC=)\xF4\xC5^d\xA2\xCCEp\xB0o\xE01|\x98\xD0\xCFcy\xC9+,1@Çšr\x8D&lt;\x81\xC5\xE8\xF9\xD6\x91| \x8A\x97&lt;        ܤ\x81\xC5XM\xBE\xA7\xB0\xFC@\xF3z%Ø\x91Vt_#\xC3E\x97\x86\xF6\xB3L\xD7$\x89&lt;\x8F/O\xF1\xF3p{Wx\xEC`(\xACGQ\xE1\xA7!\xF0, @\xDEh~\x87;]\xA2\xA7\xEA\x819\xE4f\xB7&gt;\xF0^\xE0\xBD\xC8{\xC9\xF1\x87\xBCÅ \xCC`\xF8
+\xF5kd6`\xA4f\xB2i\x81\x81\x81qnZ(a\x84\x919\xAC\xD8Q\xE8\x97OI\xF8a\xB3$a\xCBBY\x92g\x9E\xE1g\x9Fa\xAA\x89\xA5\xB9\xE0̙3\x99Ǥ\xBA\x92Ǻ6{\xEC\xAB|\xEBJ\xE0l/\xC2
+\xDB\xC7C,%;&gt;\x94ÑŽ\xFEF\xB9\x83Ü­&quot;\xE4\xD88Є\xD3в&quot;\xBC&amp;&lt; Ï\xFC\xEEbt\xA5\xEC%Ï£+E\xF2Ut\xB1H^@\xA7\x8Bd\x97\x8C\xD6\xFE놵\x97\xA7\xE3N\x91\xEF\xD8\xE4E0\xBE7:\xAA\xF1\xC5\xD4\xF86^@\xC8-Õ»Qg\xF1\xEB\xF8\xBC\x89\xC5Ι\xBE\xE4L{\xF1F\xDFE\xE7\xF6\xD4 T\xF0\x98_&amp;\xDCN\x8F\xAD\xA0E\xF2\xE1\x83E#@\xF0 \xC4;0U\x84+\x8Co&quot;\xFF\x8Co\x9E8S\xC1\x97\xAA\xAB\xC9\xD6d\xE7\xBFA\xC8F\xAD\xAEI1\xA9\xE5\xF9\xCE+\x8AE\x9BÝ‚\x87\x8E\xCC]$\xB9з@\xE4&amp;|\x9FQ\xFB?e\xC3\xB6 ?9\xF8m x4+Fų\xE2\xB5\xF9\xF1\xF4\xEEy\xA6\x80Ö¿\xE0\xE0\xE1Y\x8C-y\x85\xFB;\xDC̯r\x93\x9D0M^C\x87L\x93\xDD,\xB2\xB2\xDCIX\x9D$d\x8F\xEC\xF6T\xFD\x83\xBB&quot;\xEAr\x90\xEFv\\xA1\xF3\xCE*\xD6CSDb\x97\x8C\xC8\xEC~\xEC\xAD\xC52T\xA0\x81%\xA8\xA4T\x83/\xD7\xFC =CI\xF0{@B\xF5h\x9BÞš\x83\xCCH%\xA3\xA0\xBC\xA4\xE2\xBCfب\xF4\xA0ac\xED2\xBF&quot;\x9B&quot;\x83v\x99[68CP+\xB3V\xC4\xC5\xCC\xA5\xDC^\xBB\xDC\xECDw\xF8\xFB`\xBCu\xE7\xB8{],\xC9h?\x80\xE2P\xD0
 \xDE(+A\xFBai(jo\x96\x86\x92\xF6\xA3\xD2P\xD6~ \xC2]\xBC\x86\x95d\xFF\xEA\x8B\xF1\xF1&gt;\xB0z\x84)\xB1\xCC\xD6:\xC2\xD0k\x81_8\x99n\xCB&quot;~R\xBD\x84\x9FK, \x97\x97yA\x99&amp;?e\xA9į &quot;y}\xBE\xB7\xD13\x88?c.\xF3\xF9\xDEA\x9F!\xF1]L&quot;y\xDF\xEE&quot;Q\x85\x8Dbz\xA9\xA0%1\x8D\xEDua;\xCB æ­‚\xF1s0Þ‡\xC0\xF5\xBA6^\x81\xB7!\xF0[\xE0\xF4_`_+|S\xE2F\xF4Ws\xBE\xDF\xF1\xEBlÊ\xFB|\xAD4\xE6{\xC2\x8D_B\xB8\xFF\xAD\x96\xEF\xDBq\xF6+\xBC\x85(ÙoX7&gt;t\xF6\xF6\x84+=\xE1\xDF`\xFB-\xB6\xB0\xF9\xF1\xBFi\xB2\x8B\xFFÅ«N\xB37~\x89\xF9\xB6\x88\xA2$?\xC2\xF4}n\xB1wz!~
+\xB1|\xCA`1\xEF\xCB}\x81\xBF\x80\xF1!\xCCw\xD4\xE0N;\x9B\xFF\xB58\xA7L\x87\xEB\xC6\xEF`\xBE\xE68\x80&quot;k\xFC.\x96\xC2\xFF\x83\x81\x89\xC5\xE7\xD3]\xC1\xDFc\xCC\xCA,fq=_?\x89:\x90dI\xBE\xC4 \^\xCD\xF6\xE8\xBC]`\xF5\x8F=Z\xB1\xFA\xEDfK\xAB\x85U\xDC\xFA3A\xE0\xC0\xA7+\x81&lt;\xAC\xAC\xAE\x84&gt;`\x85/\xEF\xBE&lt;\x9A\xB1P ?|&lt;K\x82$\xB7\xA1\xFD\xB8t\xAC\x83l\xFF*\xFA\xE1\x8F\xC07\x86\xAF\xA3\x86y\xE3d!\xB4 &quot;\xF2\xB7\xA19E?&gt;U\xFEÌž\xDEi\xD8߇\xF4\x8AZ\xF6\xEDW\xFE_\x8E\xF8mD\xFE\xD4B\xA1\xBE
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuitabviewtabviewminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/tabview/tabview-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/tabview/tabview-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/tabview/tabview-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,8 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+(function(){var b=YAHOO.util,c=b.Dom,i=b.Event,g=window.document,k=&quot;active&quot;,d=&quot;activeIndex&quot;,f=&quot;activeTab&quot;,e=&quot;disabled&quot;,a=&quot;contentEl&quot;,h=&quot;element&quot;,j=function(m,l){l=l||{};if(arguments.length==1&amp;&amp;!YAHOO.lang.isString(m)&amp;&amp;!m.nodeName){l=m;m=l.element||null;}if(!m&amp;&amp;!l.element){m=this._createTabViewElement(l);}j.superclass.constructor.call(this,m,l);};YAHOO.extend(j,b.Element,{CLASSNAME:&quot;yui-navset&quot;,TAB_PARENT_CLASSNAME:&quot;yui-nav&quot;,CONTENT_PARENT_CLASSNAME:&quot;yui-content&quot;,_tabParent:null,_contentParent:null,addTab:function(n,o){var p=this.get(&quot;tabs&quot;),s=this._tabParent,q=this._contentParent,l=n.get(h),m=n.get(a),t=this.get(d),r;if(!p){this._queue[this._queue.length]=[&quot;addTab&quot;,arguments];return false;}r=this.getTab(o);o=(o===undefined)?p.length:o;p.splice(o,0,n);if(r){s.insertBefore(l,r.get(h));if(m){q.appendChild(m);}}else{s.appendChild(l);if(m){q.append
 Child(m);}}if(!n.get(k)){n.set(&quot;contentVisible&quot;,false,true);if(o&lt;=t){this.set(d,t+1,true);}}else{this.set(f,n,true);this.set(&quot;activeIndex&quot;,o,true);}this._initTabEvents(n);},_initTabEvents:function(l){l.addListener(l.get(&quot;activationEvent&quot;),l._onActivate,this,l);l.addListener(&quot;activationEventChange&quot;,l._onActivationEventChange,this,l);},_removeTabEvents:function(l){l.removeListener(l.get(&quot;activationEvent&quot;),l._onActivate,this,l);l.removeListener(&quot;activationEventChange&quot;,l._onActivationEventChange,this,l);},DOMEventHandler:function(q){var r=i.getTarget(q),t=this._tabParent,s=this.get(&quot;tabs&quot;),n,m,l;if(c.isAncestor(t,r)){for(var o=0,p=s.length;o&lt;p;o++){m=s[o].get(h);l=s[o].get(a);if(r==m||c.isAncestor(m,r)){n=s[o];break;}}if(n){n.fireEvent(q.type,q);}}},getTab:function(l){return this.get(&quot;tabs&quot;)[l];},getTabIndex:function(p){var m=null,o=this.get(&quot;tabs&quot;);for(var n=0,l=o.length;n&lt;l;++n){
 if(p==o[n]){m=n;break;}}return m;},removeTab:function(o){var n=this.get(&quot;tabs&quot;).length,l=this.get(d),m=this.getTabIndex(o);if(o===this.get(f)){if(n&gt;1){if(m+1===n){this.set(d,m-1);}else{this.set(d,m+1);}}else{this.set(f,null);}}else{if(m&lt;l){this.set(d,l-1,true);}}this._removeTabEvents(o);this._tabParent.removeChild(o.get(h));this._contentParent.removeChild(o.get(a));this._configs.tabs.value.splice(m,1);o.fireEvent(&quot;remove&quot;,{type:&quot;remove&quot;,tabview:this});},toString:function(){var l=this.get(&quot;id&quot;)||this.get(&quot;tagName&quot;);return&quot;TabView &quot;+l;},contentTransition:function(m,l){if(m){m.set(&quot;contentVisible&quot;,true);}if(l){l.set(&quot;contentVisible&quot;,false);}},initAttributes:function(l){j.superclass.initAttributes.call(this,l);if(!l.orientation){l.orientation=&quot;top&quot;;}var n=this.get(h);if(!this.hasClass(this.CLASSNAME)){this.addClass(this.CLASSNAME);}this.setAttributeConfig(&quot;tabs&quot;,{value:[],re
 adOnly:true});this._tabParent=this.getElementsByClassName(this.TAB_PARENT_CLASSNAME,&quot;ul&quot;)[0]||this._createTabParent();this._contentParent=this.getElementsByClassName(this.CONTENT_PARENT_CLASSNAME,&quot;div&quot;)[0]||this._createContentParent();this.setAttributeConfig(&quot;orientation&quot;,{value:l.orientation,method:function(o){var p=this.get(&quot;orientation&quot;);this.addClass(&quot;yui-navset-&quot;+o);if(p!=o){this.removeClass(&quot;yui-navset-&quot;+p);}if(o===&quot;bottom&quot;){this.appendChild(this._tabParent);}}});this.setAttributeConfig(d,{value:l.activeIndex,validator:function(q){var o=true,p;if(q){p=this.getTab(q);if(p&amp;&amp;p.get(e)){o=false;}}return o;}});this.setAttributeConfig(f,{value:l[f],method:function(p){var o=this.get(f);if(p){p.set(k,true);}if(o&amp;&amp;o!==p){o.set(k,false);}if(o&amp;&amp;p!==o){this.contentTransition(p,o);}else{if(p){p.set(&quot;contentVisible&quot;,true);}}},validator:function(p){var o=true;if(p&amp;&amp;p.get(e))
 {o=false;}return o;}});this.on(&quot;activeTabChange&quot;,this._onActiveTabChange);this.on(&quot;activeIndexChange&quot;,this._onActiveIndexChange);if(this._tabParent){this._initTabs();}this.DOM_EVENTS.submit=false;this.DOM_EVENTS.focus=false;this.DOM_EVENTS.blur=false;this.DOM_EVENTS.change=false;for(var m in this.DOM_EVENTS){if(YAHOO.lang.hasOwnProperty(this.DOM_EVENTS,m)){this.addListener.call(this,m,this.DOMEventHandler);}}},deselectTab:function(l){if(this.getTab(l)===this.get(f)){this.set(f,null);}},selectTab:function(l){this.set(f,this.getTab(l));},_onActiveTabChange:function(n){var l=this.get(d),m=this.getTabIndex(n.newValue);if(l!==m){if(!(this.set(d,m))){this.set(f,n.prevValue);}}},_onActiveIndexChange:function(l){if(l.newValue!==this.getTabIndex(this.get(f))){if(!(this.set(f,this.getTab(l.newValue)))){this.set(d,l.prevValue);}}},_initTabs:function(){var q=c.getChildren(this._tabParent),o=c.getChildren(this._contentParent),n=this.get(d),r,m,s;for(var p=0,l=q.length
 ;p&lt;l;++p){m={};if(o[p]){m.contentEl=o[p];}r=new YAHOO.widget.Tab(q[p],m);this.addTab(r);if(r.hasClass(r.ACTIVE_CLASSNAME)){s=r;}}if(n!=undefined){this.set(f,this.getTab(n));}else{this._configs[f].value=s;this._configs[d].value=this.getTabIndex(s);}},_createTabViewElement:function(l){var m=g.createElement(&quot;div&quot;);if(this.CLASSNAME){m.className=this.CLASSNAME;}return m;},_createTabParent:function(l){var m=g.createElement(&quot;ul&quot;);if(this.TAB_PARENT_CLASSNAME){m.className=this.TAB_PARENT_CLASSNAME;}this.get(h).appendChild(m);return m;},_createContentParent:function(l){var m=g.createElement(&quot;div&quot;);if(this.CONTENT_PARENT_CLASSNAME){m.className=this.CONTENT_PARENT_CLASSNAME;}this.get(h).appendChild(m);return m;}});YAHOO.widget.TabView=j;})();(function(){var d=YAHOO.util,i=d.Dom,l=YAHOO.lang,m=&quot;activeTab&quot;,j=&quot;label&quot;,g=&quot;labelEl&quot;,q=&quot;content&quot;,c=&quot;contentEl&quot;,o=&quot;element&quot;,p=&quot;cacheData&quot;,b=&quo
 t;dataSrc&quot;,h=&quot;dataLoaded&quot;,a=&quot;dataTimeout&quot;,n=&quot;loadMethod&quot;,f=&quot;postData&quot;,k=&quot;disabled&quot;,e=function(s,r){r=r||{};if(arguments.length==1&amp;&amp;!l.isString(s)&amp;&amp;!s.nodeName){r=s;s=r.element;}if(!s&amp;&amp;!r.element){s=this._createTabElement(r);}this.loadHandler={success:function(t){this.set(q,t.responseText);},failure:function(t){}};e.superclass.constructor.call(this,s,r);this.DOM_EVENTS={};};YAHOO.extend(e,YAHOO.util.Element,{LABEL_TAGNAME:&quot;em&quot;,ACTIVE_CLASSNAME:&quot;selected&quot;,HIDDEN_CLASSNAME:&quot;yui-hidden&quot;,ACTIVE_TITLE:&quot;active&quot;,DISABLED_CLASSNAME:k,LOADING_CLASSNAME:&quot;loading&quot;,dataConnection:null,loadHandler:null,_loading:false,toString:function(){var r=this.get(o),s=r.id||r.tagName;
+return&quot;Tab &quot;+s;},initAttributes:function(r){r=r||{};e.superclass.initAttributes.call(this,r);this.setAttributeConfig(&quot;activationEvent&quot;,{value:r.activationEvent||&quot;click&quot;});this.setAttributeConfig(g,{value:r[g]||this._getLabelEl(),method:function(s){s=i.get(s);var t=this.get(g);if(t){if(t==s){return false;}t.parentNode.replaceChild(s,t);this.set(j,s.innerHTML);}}});this.setAttributeConfig(j,{value:r.label||this._getLabel(),method:function(t){var s=this.get(g);if(!s){this.set(g,this._createLabelEl());}s.innerHTML=t;}});this.setAttributeConfig(c,{value:r[c]||document.createElement(&quot;div&quot;),method:function(s){s=i.get(s);var t=this.get(c);if(t){if(t===s){return false;}if(!this.get(&quot;selected&quot;)){i.addClass(s,this.HIDDEN_CLASSNAME);}t.parentNode.replaceChild(s,t);this.set(q,s.innerHTML);}}});this.setAttributeConfig(q,{value:r[q]||this.get(c).innerHTML,method:function(s){this.get(c).innerHTML=s;}});this.setAttributeConfig(b,{value:r.data
 Src});this.setAttributeConfig(p,{value:r.cacheData||false,validator:l.isBoolean});this.setAttributeConfig(n,{value:r.loadMethod||&quot;GET&quot;,validator:l.isString});this.setAttributeConfig(h,{value:false,validator:l.isBoolean,writeOnce:true});this.setAttributeConfig(a,{value:r.dataTimeout||null,validator:l.isNumber});this.setAttributeConfig(f,{value:r.postData||null});this.setAttributeConfig(&quot;active&quot;,{value:r.active||this.hasClass(this.ACTIVE_CLASSNAME),method:function(s){if(s===true){this.addClass(this.ACTIVE_CLASSNAME);this.set(&quot;title&quot;,this.ACTIVE_TITLE);}else{this.removeClass(this.ACTIVE_CLASSNAME);this.set(&quot;title&quot;,&quot;&quot;);}},validator:function(s){return l.isBoolean(s)&amp;&amp;!this.get(k);}});this.setAttributeConfig(k,{value:r.disabled||this.hasClass(this.DISABLED_CLASSNAME),method:function(s){if(s===true){this.addClass(this.DISABLED_CLASSNAME);}else{this.removeClass(this.DISABLED_CLASSNAME);}},validator:l.isBoolean});this.setAttri
 buteConfig(&quot;href&quot;,{value:r.href||this.getElementsByTagName(&quot;a&quot;)[0].getAttribute(&quot;href&quot;,2)||&quot;#&quot;,method:function(s){this.getElementsByTagName(&quot;a&quot;)[0].href=s;},validator:l.isString});this.setAttributeConfig(&quot;contentVisible&quot;,{value:r.contentVisible,method:function(s){if(s){i.removeClass(this.get(c),this.HIDDEN_CLASSNAME);if(this.get(b)){if(!this._loading&amp;&amp;!(this.get(h)&amp;&amp;this.get(p))){this._dataConnect();}}}else{i.addClass(this.get(c),this.HIDDEN_CLASSNAME);}},validator:l.isBoolean});},_dataConnect:function(){if(!d.Connect){return false;}i.addClass(this.get(c).parentNode,this.LOADING_CLASSNAME);this._loading=true;this.dataConnection=d.Connect.asyncRequest(this.get(n),this.get(b),{success:function(r){this.loadHandler.success.call(this,r);this.set(h,true);this.dataConnection=null;i.removeClass(this.get(c).parentNode,this.LOADING_CLASSNAME);this._loading=false;},failure:function(r){this.loadHandler.failure.c
 all(this,r);this.dataConnection=null;i.removeClass(this.get(c).parentNode,this.LOADING_CLASSNAME);this._loading=false;},scope:this,timeout:this.get(a)},this.get(f));},_createTabElement:function(r){var v=document.createElement(&quot;li&quot;),s=document.createElement(&quot;a&quot;),u=r.label||null,t=r.labelEl||null;s.href=r.href||&quot;#&quot;;v.appendChild(s);if(t){if(!u){u=this._getLabel();}}else{t=this._createLabelEl();}s.appendChild(t);return v;},_getLabelEl:function(){return this.getElementsByTagName(this.LABEL_TAGNAME)[0];},_createLabelEl:function(){var r=document.createElement(this.LABEL_TAGNAME);return r;},_getLabel:function(){var r=this.get(g);if(!r){return undefined;}return r.innerHTML;},_onActivate:function(u,t){var s=this,r=false;d.Event.preventDefault(u);if(s===t.get(m)){r=true;}t.set(m,s,r);},_onActivationEventChange:function(s){var r=this;if(s.prevValue!=s.newValue){r.removeListener(s.prevValue,r._onActivate);r.addListener(s.newValue,r._onActivate,this,r);}}});
 YAHOO.widget.Tab=e;})();YAHOO.register(&quot;tabview&quot;,YAHOO.widget.TabView,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuitreeviewtreeviewminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/treeview/treeview-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/treeview/treeview-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/treeview/treeview-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,12 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+(function(){var d=YAHOO.util.Dom,b=YAHOO.util.Event,f=YAHOO.lang,e=YAHOO.widget;YAHOO.widget.TreeView=function(h,g){if(h){this.init(h);}if(g){this.buildTreeFromObject(g);}else{if(f.trim(this._el.innerHTML)){this.buildTreeFromMarkup(h);}}};var c=e.TreeView;c.prototype={id:null,_el:null,_nodes:null,locked:false,_expandAnim:null,_collapseAnim:null,_animCount:0,maxAnim:2,_hasDblClickSubscriber:false,_dblClickTimer:null,currentFocus:null,singleNodeHighlight:false,_currentlyHighlighted:null,setExpandAnim:function(g){this._expandAnim=(e.TVAnim.isValid(g))?g:null;},setCollapseAnim:function(g){this._collapseAnim=(e.TVAnim.isValid(g))?g:null;},animateExpand:function(i,j){if(this._expandAnim&amp;&amp;this._animCount&lt;this.maxAnim){var g=this;var h=e.TVAnim.getAnim(this._expandAnim,i,function(){g.expandComplete(j);});if(h){++this._animCount;this.fireEvent(&quot;animStart&quot;,{&quot;node&quot;:j,&quot;type&quot;:&quot;expand&quot;});h.animate();}return true;}return false;},animateCol
 lapse:function(i,j){if(this._collapseAnim&amp;&amp;this._animCount&lt;this.maxAnim){var g=this;var h=e.TVAnim.getAnim(this._collapseAnim,i,function(){g.collapseComplete(j);});if(h){++this._animCount;this.fireEvent(&quot;animStart&quot;,{&quot;node&quot;:j,&quot;type&quot;:&quot;collapse&quot;});h.animate();}return true;}return false;},expandComplete:function(g){--this._animCount;this.fireEvent(&quot;animComplete&quot;,{&quot;node&quot;:g,&quot;type&quot;:&quot;expand&quot;});},collapseComplete:function(g){--this._animCount;this.fireEvent(&quot;animComplete&quot;,{&quot;node&quot;:g,&quot;type&quot;:&quot;collapse&quot;});},init:function(i){this._el=d.get(i);this.id=d.generateId(this._el,&quot;yui-tv-auto-id-&quot;);this.createEvent(&quot;animStart&quot;,this);this.createEvent(&quot;animComplete&quot;,this);this.createEvent(&quot;collapse&quot;,this);this.createEvent(&quot;collapseComplete&quot;,this);this.createEvent(&quot;expand&quot;,this);this.createEvent(&quot;expandComp
 lete&quot;,this);this.createEvent(&quot;enterKeyPressed&quot;,this);this.createEvent(&quot;clickEvent&quot;,this);this.createEvent(&quot;focusChanged&quot;,this);var g=this;this.createEvent(&quot;dblClickEvent&quot;,{scope:this,onSubscribeCallback:function(){g._hasDblClickSubscriber=true;}});this.createEvent(&quot;labelClick&quot;,this);this.createEvent(&quot;highlightEvent&quot;,this);this._nodes=[];c.trees[this.id]=this;this.root=new e.RootNode(this);var h=e.LogWriter;if(this._initEditor){this._initEditor();}},buildTreeFromObject:function(g){var h=function(q,n){var m,r,l,k,p,j,o;for(m=0;m&lt;n.length;m++){r=n[m];if(f.isString(r)){l=new e.TextNode(r,q);}else{if(f.isObject(r)){k=r.children;delete r.children;p=r.type||&quot;text&quot;;delete r.type;switch(f.isString(p)&amp;&amp;p.toLowerCase()){case&quot;text&quot;:l=new e.TextNode(r,q);break;case&quot;menu&quot;:l=new e.MenuNode(r,q);break;case&quot;html&quot;:l=new e.HTMLNode(r,q);break;default:if(f.isString(p)){j=e[p];}els
 e{j=p;}if(f.isObject(j)){for(o=j;o&amp;&amp;o!==e.Node;o=o.superclass.constructor){}if(o){l=new j(r,q);}else{}}else{}}if(k){h(l,k);}}else{}}}};if(!f.isArray(g)){g=[g];}h(this.root,g);},buildTreeFromMarkup:function(i){var h=function(j){var n,q,m=[],l={},k,o;for(n=d.getFirstChild(j);n;n=d.getNextSibling(n)){switch(n.tagName.toUpperCase()){case&quot;LI&quot;:k=&quot;&quot;;l={expanded:d.hasClass(n,&quot;expanded&quot;),title:n.title||n.alt||null,className:f.trim(n.className.replace(/\bexpanded\b/,&quot;&quot;))||null};q=n.firstChild;if(q.nodeType==3){k=f.trim(q.nodeValue.replace(/[\n\t\r]*/g,&quot;&quot;));if(k){l.type=&quot;text&quot;;l.label=k;}else{q=d.getNextSibling(q);}}if(!k){if(q.tagName.toUpperCase()==&quot;A&quot;){l.type=&quot;text&quot;;l.label=q.innerHTML;l.href=q.href;l.target=q.target;l.title=q.title||q.alt||l.title;}else{l.type=&quot;html&quot;;var p=document.createElement(&quot;div&quot;);p.appendChild(q.cloneNode(true));l.html=p.innerHTML;l.hasIcon=true;}}q=d.g
 etNextSibling(q);switch(q&amp;&amp;q.tagName.toUpperCase()){case&quot;UL&quot;:case&quot;OL&quot;:l.children=h(q);break;}if(YAHOO.lang.JSON){o=n.getAttribute(&quot;yuiConfig&quot;);if(o){o=YAHOO.lang.JSON.parse(o);l=YAHOO.lang.merge(l,o);}}m.push(l);break;case&quot;UL&quot;:case&quot;OL&quot;:l={type:&quot;text&quot;,label:&quot;&quot;,children:h(q)};m.push(l);break;}}return m;};var g=d.getChildrenBy(d.get(i),function(k){var j=k.tagName.toUpperCase();return j==&quot;UL&quot;||j==&quot;OL&quot;;});if(g.length){this.buildTreeFromObject(h(g[0]));}else{}},_getEventTargetTdEl:function(h){var i=b.getTarget(h);while(i&amp;&amp;!(i.tagName.toUpperCase()==&quot;TD&quot;&amp;&amp;d.hasClass(i.parentNode,&quot;ygtvrow&quot;))){i=d.getAncestorByTagName(i,&quot;td&quot;);}if(f.isNull(i)){return null;}if(/\bygtv(blank)?depthcell/.test(i.className)){return null;}if(i.id){var g=i.id.match(/\bygtv([^\d]*)(.*)/);if(g&amp;&amp;g[2]&amp;&amp;this._nodes[g[2]]){return i;}}return null;},_onClickE
 vent:function(j){var h=this,l=this._getEventTargetTdEl(j),i,k,g=function(m){i.focus();if(m||!i.href){i.toggle();try{b.preventDefault(j);}catch(n){}}};if(!l){return;}i=this.getNodeByElement(l);if(!i){return;}k=b.getTarget(j);if(d.hasClass(k,i.labelStyle)||d.getAncestorByClassName(k,i.labelStyle)){this.fireEvent(&quot;labelClick&quot;,i);}if(this._closeEditor){this._closeEditor(false);}if(/\bygtv[tl][mp]h?h?/.test(l.className)){g(true);}else{if(this._dblClickTimer){window.clearTimeout(this._dblClickTimer);this._dblClickTimer=null;}else{if(this._hasDblClickSubscriber){this._dblClickTimer=window.setTimeout(function(){h._dblClickTimer=null;if(h.fireEvent(&quot;clickEvent&quot;,{event:j,node:i})!==false){g();}},200);}else{if(h.fireEvent(&quot;clickEvent&quot;,{event:j,node:i})!==false){g();}}}}},_onDblClickEvent:function(g){if(!this._hasDblClickSubscriber){return;}var h=this._getEventTargetTdEl(g);if(!h){return;}if(!(/\bygtv[tl][mp]h?h?/.test(h.className))){this.fireEvent(&quot;db
 lClickEvent&quot;,{event:g,node:this.getNodeByElement(h)});if(this._dblClickTimer){window.clearTimeout(this._dblClickTimer);this._dblClickTimer=null;}}},_onMouseOverEvent:function(g){var h;if((h=this._getEventTargetTdEl(g))&amp;&amp;(h=this.getNodeByElement(h))&amp;&amp;(h=h.getToggleEl())){h.className=h.className.replace(/\bygtv([lt])([mp])\b/gi,&quot;ygtv$1$2h&quot;);}},_onMouseOutEvent:function(g){var h;if((h=this._getEventTargetTdEl(g))&amp;&amp;(h=this.getNodeByElement(h))&amp;&amp;(h=h.getToggleEl())){h.className=h.className.replace(/\bygtv([lt])([mp])h\b/gi,&quot;ygtv$1$2&quot;);}},_onKeyDownEvent:function(l){var n=b.getTarget(l),k=this.getNodeByElement(n),j=k,g=YAHOO.util.KeyListener.KEY;switch(l.keyCode){case g.UP:do{if(j.previousSibling){j=j.previousSibling;}else{j=j.parent;
+}}while(j&amp;&amp;!j._canHaveFocus());if(j){j.focus();}b.preventDefault(l);break;case g.DOWN:do{if(j.nextSibling){j=j.nextSibling;}else{j.expand();j=(j.children.length||null)&amp;&amp;j.children[0];}}while(j&amp;&amp;!j._canHaveFocus);if(j){j.focus();}b.preventDefault(l);break;case g.LEFT:do{if(j.parent){j=j.parent;}else{j=j.previousSibling;}}while(j&amp;&amp;!j._canHaveFocus());if(j){j.focus();}b.preventDefault(l);break;case g.RIGHT:var i=this,m,h=function(o){i.unsubscribe(&quot;expandComplete&quot;,h);m(o);};m=function(o){do{if(o.isDynamic()&amp;&amp;!o.childrenRendered){i.subscribe(&quot;expandComplete&quot;,h);o.expand();o=null;break;}else{o.expand();if(o.children.length){o=o.children[0];}else{o=o.nextSibling;}}}while(o&amp;&amp;!o._canHaveFocus());if(o){o.focus();}};m(j);b.preventDefault(l);break;case g.ENTER:if(k.href){if(k.target){window.open(k.href,k.target);}else{window.location(k.href);}}else{k.toggle();}this.fireEvent(&quot;enterKeyPressed&quot;,k);b.preventDefau
 lt(l);break;case g.HOME:j=this.getRoot();if(j.children.length){j=j.children[0];}if(j._canHaveFocus()){j.focus();}b.preventDefault(l);break;case g.END:j=j.parent.children;j=j[j.length-1];if(j._canHaveFocus()){j.focus();}b.preventDefault(l);break;case 107:case 187:if(l.shiftKey){k.parent.expandAll();}else{k.expand();}break;case 109:case 189:if(l.shiftKey){k.parent.collapseAll();}else{k.collapse();}break;default:break;}},render:function(){var g=this.root.getHtml(),h=this.getEl();h.innerHTML=g;if(!this._hasEvents){b.on(h,&quot;click&quot;,this._onClickEvent,this,true);b.on(h,&quot;dblclick&quot;,this._onDblClickEvent,this,true);b.on(h,&quot;mouseover&quot;,this._onMouseOverEvent,this,true);b.on(h,&quot;mouseout&quot;,this._onMouseOutEvent,this,true);b.on(h,&quot;keydown&quot;,this._onKeyDownEvent,this,true);}this._hasEvents=true;},getEl:function(){if(!this._el){this._el=d.get(this.id);}return this._el;},regNode:function(g){this._nodes[g.index]=g;},getRoot:function(){return this.
 root;},setDynamicLoad:function(g,h){this.root.setDynamicLoad(g,h);},expandAll:function(){if(!this.locked){this.root.expandAll();}},collapseAll:function(){if(!this.locked){this.root.collapseAll();}},getNodeByIndex:function(h){var g=this._nodes[h];return(g)?g:null;},getNodeByProperty:function(j,h){for(var g in this._nodes){if(this._nodes.hasOwnProperty(g)){var k=this._nodes[g];if((j in k&amp;&amp;k[j]==h)||(k.data&amp;&amp;h==k.data[j])){return k;}}}return null;},getNodesByProperty:function(k,j){var g=[];for(var h in this._nodes){if(this._nodes.hasOwnProperty(h)){var l=this._nodes[h];if((k in l&amp;&amp;l[k]==j)||(l.data&amp;&amp;j==l.data[k])){g.push(l);}}}return(g.length)?g:null;},getNodesBy:function(j){var g=[];for(var h in this._nodes){if(this._nodes.hasOwnProperty(h)){var k=this._nodes[h];if(j(k)){g.push(k);}}}return(g.length)?g:null;},getNodeByElement:function(i){var j=i,g,h=/ygtv([^\d]*)(.*)/;do{if(j&amp;&amp;j.id){g=j.id.match(h);if(g&amp;&amp;g[2]){return this.getNode
 ByIndex(g[2]);}}j=j.parentNode;if(!j||!j.tagName){break;}}while(j.id!==this.id&amp;&amp;j.tagName.toLowerCase()!==&quot;body&quot;);return null;},getHighlightedNode:function(){return this._currentlyHighlighted;},removeNode:function(h,g){if(h.isRoot()){return false;}var i=h.parent;if(i.parent){i=i.parent;}this._deleteNode(h);if(g&amp;&amp;i&amp;&amp;i.childrenRendered){i.refresh();}return true;},_removeChildren_animComplete:function(g){this.unsubscribe(this._removeChildren_animComplete);this.removeChildren(g.node);},removeChildren:function(g){if(g.expanded){if(this._collapseAnim){this.subscribe(&quot;animComplete&quot;,this._removeChildren_animComplete,this,true);e.Node.prototype.collapse.call(g);return;}g.collapse();}while(g.children.length){this._deleteNode(g.children[0]);}if(g.isRoot()){e.Node.prototype.expand.call(g);}g.childrenRendered=false;g.dynamicLoadComplete=false;g.updateIcon();},_deleteNode:function(g){this.removeChildren(g);this.popNode(g);},popNode:function(k){v
 ar l=k.parent;var h=[];for(var j=0,g=l.children.length;j&lt;g;++j){if(l.children[j]!=k){h[h.length]=l.children[j];}}l.children=h;l.childrenRendered=false;if(k.previousSibling){k.previousSibling.nextSibling=k.nextSibling;}if(k.nextSibling){k.nextSibling.previousSibling=k.previousSibling;}if(this.currentFocus==k){this.currentFocus=null;}if(this._currentlyHighlighted==k){this._currentlyHighlighted=null;}k.parent=null;k.previousSibling=null;k.nextSibling=null;k.tree=null;delete this._nodes[k.index];},destroy:function(){if(this._destroyEditor){this._destroyEditor();}var h=this.getEl();b.removeListener(h,&quot;click&quot;);b.removeListener(h,&quot;dblclick&quot;);b.removeListener(h,&quot;mouseover&quot;);b.removeListener(h,&quot;mouseout&quot;);b.removeListener(h,&quot;keydown&quot;);for(var g=0;g&lt;this._nodes.length;g++){var j=this._nodes[g];if(j&amp;&amp;j.destroy){j.destroy();}}h.innerHTML=&quot;&quot;;this._hasEvents=false;},toString:function(){return&quot;TreeView &quot;+th
 is.id;},getNodeCount:function(){return this.getRoot().getNodeCount();},getTreeDefinition:function(){return this.getRoot().getNodeDefinition();},onExpand:function(g){},onCollapse:function(g){},setNodesProperty:function(g,i,h){this.root.setNodesProperty(g,i);if(h){this.root.refresh();}},onEventToggleHighlight:function(h){var g;if(&quot;node&quot; in h&amp;&amp;h.node instanceof e.Node){g=h.node;}else{if(h instanceof e.Node){g=h;}else{return false;}}g.toggleHighlight();return false;}};var a=c.prototype;a.draw=a.render;YAHOO.augment(c,YAHOO.util.EventProvider);c.nodeCount=0;c.trees=[];c.getTree=function(h){var g=c.trees[h];return(g)?g:null;};c.getNode=function(h,i){var g=c.getTree(h);return(g)?g.getNodeByIndex(i):null;};c.FOCUS_CLASS_NAME=&quot;ygtvfocus&quot;;})();(function(){var b=YAHOO.util.Dom,c=YAHOO.lang,a=YAHOO.util.Event;YAHOO.widget.Node=function(f,e,d){if(f){this.init(f,e,d);}};YAHOO.widget.Node.prototype={index:0,children:null,tree:null,data:null,parent:null,depth:-1,
 expanded:false,multiExpand:true,renderHidden:false,childrenRendered:false,dynamicLoadComplete:false,previousSibling:null,nextSibling:null,_dynLoad:false,dataLoader:null,isLoading:false,hasIcon:true,iconMode:0,nowrap:false,isLeaf:false,contentStyle:&quot;&quot;,contentElId:null,enableHighlight:true,highlightState:0,propagateHighlightUp:false,propagateHighlightDown:false,className:null,_type:&quot;Node&quot;,init:function(g,f,d){this.data={};
+this.children=[];this.index=YAHOO.widget.TreeView.nodeCount;++YAHOO.widget.TreeView.nodeCount;this.contentElId=&quot;ygtvcontentel&quot;+this.index;if(c.isObject(g)){for(var e in g){if(g.hasOwnProperty(e)){if(e.charAt(0)!=&quot;_&quot;&amp;&amp;!c.isUndefined(this[e])&amp;&amp;!c.isFunction(this[e])){this[e]=g[e];}else{this.data[e]=g[e];}}}}if(!c.isUndefined(d)){this.expanded=d;}this.createEvent(&quot;parentChange&quot;,this);if(f){f.appendChild(this);}},applyParent:function(e){if(!e){return false;}this.tree=e.tree;this.parent=e;this.depth=e.depth+1;this.tree.regNode(this);e.childrenRendered=false;for(var f=0,d=this.children.length;f&lt;d;++f){this.children[f].applyParent(this);}this.fireEvent(&quot;parentChange&quot;);return true;},appendChild:function(e){if(this.hasChildren()){var d=this.children[this.children.length-1];d.nextSibling=e;e.previousSibling=d;}this.children[this.children.length]=e;e.applyParent(this);if(this.childrenRendered&amp;&amp;this.expanded){this.getChi
 ldrenEl().style.display=&quot;&quot;;}return e;},appendTo:function(d){return d.appendChild(this);},insertBefore:function(d){var f=d.parent;if(f){if(this.tree){this.tree.popNode(this);}var e=d.isChildOf(f);f.children.splice(e,0,this);if(d.previousSibling){d.previousSibling.nextSibling=this;}this.previousSibling=d.previousSibling;this.nextSibling=d;d.previousSibling=this;this.applyParent(f);}return this;},insertAfter:function(d){var f=d.parent;if(f){if(this.tree){this.tree.popNode(this);}var e=d.isChildOf(f);if(!d.nextSibling){this.nextSibling=null;return this.appendTo(f);}f.children.splice(e+1,0,this);d.nextSibling.previousSibling=this;this.previousSibling=d;this.nextSibling=d.nextSibling;d.nextSibling=this;this.applyParent(f);}return this;},isChildOf:function(e){if(e&amp;&amp;e.children){for(var f=0,d=e.children.length;f&lt;d;++f){if(e.children[f]===this){return f;}}}return -1;},getSiblings:function(){var d=this.parent.children.slice(0);for(var e=0;e&lt;d.length&amp;&amp;d[e
 ]!=this;e++){}d.splice(e,1);if(d.length){return d;}return null;},showChildren:function(){if(!this.tree.animateExpand(this.getChildrenEl(),this)){if(this.hasChildren()){this.getChildrenEl().style.display=&quot;&quot;;}}},hideChildren:function(){if(!this.tree.animateCollapse(this.getChildrenEl(),this)){this.getChildrenEl().style.display=&quot;none&quot;;}},getElId:function(){return&quot;ygtv&quot;+this.index;},getChildrenElId:function(){return&quot;ygtvc&quot;+this.index;},getToggleElId:function(){return&quot;ygtvt&quot;+this.index;},getEl:function(){return b.get(this.getElId());},getChildrenEl:function(){return b.get(this.getChildrenElId());},getToggleEl:function(){return b.get(this.getToggleElId());},getContentEl:function(){return b.get(this.contentElId);},collapse:function(){if(!this.expanded){return;}var d=this.tree.onCollapse(this);if(false===d){return;}d=this.tree.fireEvent(&quot;collapse&quot;,this);if(false===d){return;}if(!this.getEl()){this.expanded=false;}else{this.
 hideChildren();this.expanded=false;this.updateIcon();}d=this.tree.fireEvent(&quot;collapseComplete&quot;,this);},expand:function(f){if(this.isLoading||(this.expanded&amp;&amp;!f)){return;}var d=true;if(!f){d=this.tree.onExpand(this);if(false===d){return;}d=this.tree.fireEvent(&quot;expand&quot;,this);}if(false===d){return;}if(!this.getEl()){this.expanded=true;return;}if(!this.childrenRendered){this.getChildrenEl().innerHTML=this.renderChildren();}else{}this.expanded=true;this.updateIcon();if(this.isLoading){this.expanded=false;return;}if(!this.multiExpand){var g=this.getSiblings();for(var e=0;g&amp;&amp;e&lt;g.length;++e){if(g[e]!=this&amp;&amp;g[e].expanded){g[e].collapse();}}}this.showChildren();d=this.tree.fireEvent(&quot;expandComplete&quot;,this);},updateIcon:function(){if(this.hasIcon){var d=this.getToggleEl();if(d){d.className=d.className.replace(/\bygtv(([tl][pmn]h?)|(loading))\b/gi,this.getStyle());}}d=b.get(&quot;ygtvtableel&quot;+this.index);if(d){if(this.expanded
 ){b.replaceClass(d,&quot;ygtv-collapsed&quot;,&quot;ygtv-expanded&quot;);}else{b.replaceClass(d,&quot;ygtv-expanded&quot;,&quot;ygtv-collapsed&quot;);}}},getStyle:function(){if(this.isLoading){return&quot;ygtvloading&quot;;}else{var e=(this.nextSibling)?&quot;t&quot;:&quot;l&quot;;var d=&quot;n&quot;;if(this.hasChildren(true)||(this.isDynamic()&amp;&amp;!this.getIconMode())){d=(this.expanded)?&quot;m&quot;:&quot;p&quot;;}return&quot;ygtv&quot;+e+d;}},getHoverStyle:function(){var d=this.getStyle();if(this.hasChildren(true)&amp;&amp;!this.isLoading){d+=&quot;h&quot;;}return d;},expandAll:function(){var d=this.children.length;for(var e=0;e&lt;d;++e){var f=this.children[e];if(f.isDynamic()){break;}else{if(!f.multiExpand){break;}else{f.expand();f.expandAll();}}}},collapseAll:function(){for(var d=0;d&lt;this.children.length;++d){this.children[d].collapse();this.children[d].collapseAll();}},setDynamicLoad:function(d,e){if(d){this.dataLoader=d;this._dynLoad=true;}else{this.dataLoade
 r=null;this._dynLoad=false;}if(e){this.iconMode=e;}},isRoot:function(){return(this==this.tree.root);},isDynamic:function(){if(this.isLeaf){return false;}else{return(!this.isRoot()&amp;&amp;(this._dynLoad||this.tree.root._dynLoad));}},getIconMode:function(){return(this.iconMode||this.tree.root.iconMode);},hasChildren:function(d){if(this.isLeaf){return false;}else{return(this.children.length&gt;0||(d&amp;&amp;this.isDynamic()&amp;&amp;!this.dynamicLoadComplete));}},toggle:function(){if(!this.tree.locked&amp;&amp;(this.hasChildren(true)||this.isDynamic())){if(this.expanded){this.collapse();}else{this.expand();}}},getHtml:function(){this.childrenRendered=false;return['&lt;div class=&quot;ygtvitem&quot; id=&quot;',this.getElId(),'&quot;&gt;',this.getNodeHtml(),this.getChildrenHtml(),&quot;&lt;/div&gt;&quot;].join(&quot;&quot;);},getChildrenHtml:function(){var d=[];d[d.length]='&lt;div class=&quot;ygtvchildren&quot; id=&quot;'+this.getChildrenElId()+'&quot;';if(!this.expanded||!th
 is.hasChildren()){d[d.length]=' style=&quot;display:none;&quot;';}d[d.length]=&quot;&gt;&quot;;if((this.hasChildren(true)&amp;&amp;this.expanded)||(this.renderHidden&amp;&amp;!this.isDynamic())){d[d.length]=this.renderChildren();}d[d.length]=&quot;&lt;/div&gt;&quot;;return d.join(&quot;&quot;);},renderChildren:function(){var d=this;if(this.isDynamic()&amp;&amp;!this.dynamicLoadComplete){this.isLoading=true;this.tree.locked=true;if(this.dataLoader){setTimeout(function(){d.dataLoader(d,function(){d.loadComplete();});},10);}else{if(this.tree.root.dataLoader){setTimeout(function(){d.tree.root.dataLoader(d,function(){d.loadComplete();
+});},10);}else{return&quot;Error: data loader not found or not specified.&quot;;}}return&quot;&quot;;}else{return this.completeRender();}},completeRender:function(){var e=[];for(var d=0;d&lt;this.children.length;++d){e[e.length]=this.children[d].getHtml();}this.childrenRendered=true;return e.join(&quot;&quot;);},loadComplete:function(){this.getChildrenEl().innerHTML=this.completeRender();if(this.propagateHighlightDown){if(this.highlightState===1&amp;&amp;!this.tree.singleNodeHighlight){for(var d=0;d&lt;this.children.length;d++){this.children[d].highlight(true);}}else{if(this.highlightState===0||this.tree.singleNodeHighlight){for(d=0;d&lt;this.children.length;d++){this.children[d].unhighlight(true);}}}}this.dynamicLoadComplete=true;this.isLoading=false;this.expand(true);this.tree.locked=false;},getAncestor:function(e){if(e&gt;=this.depth||e&lt;0){return null;}var d=this.parent;while(d.depth&gt;e){d=d.parent;}return d;},getDepthStyle:function(d){return(this.getAncestor(d).next
 Sibling)?&quot;ygtvdepthcell&quot;:&quot;ygtvblankdepthcell&quot;;},getNodeHtml:function(){var e=[];e[e.length]='&lt;table id=&quot;ygtvtableel'+this.index+'&quot; border=&quot;0&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; class=&quot;ygtvtable ygtvdepth'+this.depth;e[e.length]=&quot; ygtv-&quot;+(this.expanded?&quot;expanded&quot;:&quot;collapsed&quot;);if(this.enableHighlight){e[e.length]=&quot; ygtv-highlight&quot;+this.highlightState;}if(this.className){e[e.length]=&quot; &quot;+this.className;}e[e.length]='&quot;&gt;&lt;tr class=&quot;ygtvrow&quot;&gt;';for(var d=0;d&lt;this.depth;++d){e[e.length]='&lt;td class=&quot;ygtvcell '+this.getDepthStyle(d)+'&quot;&gt;&lt;div class=&quot;ygtvspacer&quot;&gt;&lt;/div&gt;&lt;/td&gt;';}if(this.hasIcon){e[e.length]='&lt;td id=&quot;'+this.getToggleElId();e[e.length]='&quot; class=&quot;ygtvcell ';e[e.length]=this.getStyle();e[e.length]='&quot;&gt;&lt;a href=&quot;#&quot; class=&quot;ygtvspacer&quot;&gt;&amp;#160;&lt;/
 a&gt;&lt;/td&gt;';}e[e.length]='&lt;td id=&quot;'+this.contentElId;e[e.length]='&quot; class=&quot;ygtvcell ';e[e.length]=this.contentStyle+' ygtvcontent&quot; ';e[e.length]=(this.nowrap)?' nowrap=&quot;nowrap&quot; ':&quot;&quot;;e[e.length]=&quot; &gt;&quot;;e[e.length]=this.getContentHtml();e[e.length]=&quot;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&quot;;return e.join(&quot;&quot;);},getContentHtml:function(){return&quot;&quot;;},refresh:function(){this.getChildrenEl().innerHTML=this.completeRender();if(this.hasIcon){var d=this.getToggleEl();if(d){d.className=d.className.replace(/\bygtv[lt][nmp]h*\b/gi,this.getStyle());}}},toString:function(){return this._type+&quot; (&quot;+this.index+&quot;)&quot;;},_focusHighlightedItems:[],_focusedItem:null,_canHaveFocus:function(){return this.getEl().getElementsByTagName(&quot;a&quot;).length&gt;0;},_removeFocus:function(){if(this._focusedItem){a.removeListener(this._focusedItem,&quot;blur&quot;);this._focusedItem=null;}var d;while((d=th
 is._focusHighlightedItems.shift())){b.removeClass(d,YAHOO.widget.TreeView.FOCUS_CLASS_NAME);}},focus:function(){var f=false,d=this;if(this.tree.currentFocus){this.tree.currentFocus._removeFocus();}var e=function(g){if(g.parent){e(g.parent);g.parent.expand();}};e(this);b.getElementsBy(function(g){return(/ygtv(([tl][pmn]h?)|(content))/).test(g.className);},&quot;td&quot;,d.getEl().firstChild,function(h){b.addClass(h,YAHOO.widget.TreeView.FOCUS_CLASS_NAME);if(!f){var g=h.getElementsByTagName(&quot;a&quot;);if(g.length){g=g[0];g.focus();d._focusedItem=g;a.on(g,&quot;blur&quot;,function(){d.tree.fireEvent(&quot;focusChanged&quot;,{oldNode:d.tree.currentFocus,newNode:null});d.tree.currentFocus=null;d._removeFocus();});f=true;}}d._focusHighlightedItems.push(h);});if(f){this.tree.fireEvent(&quot;focusChanged&quot;,{oldNode:this.tree.currentFocus,newNode:this});this.tree.currentFocus=this;}else{this.tree.fireEvent(&quot;focusChanged&quot;,{oldNode:d.tree.currentFocus,newNode:null});t
 his.tree.currentFocus=null;this._removeFocus();}return f;},getNodeCount:function(){for(var d=0,e=0;d&lt;this.children.length;d++){e+=this.children[d].getNodeCount();}return e+1;},getNodeDefinition:function(){if(this.isDynamic()){return false;}var g,d=c.merge(this.data),f=[];if(this.expanded){d.expanded=this.expanded;}if(!this.multiExpand){d.multiExpand=this.multiExpand;}if(this.renderHidden){d.renderHidden=this.renderHidden;}if(!this.hasIcon){d.hasIcon=this.hasIcon;}if(this.nowrap){d.nowrap=this.nowrap;}if(this.className){d.className=this.className;}if(this.editable){d.editable=this.editable;}if(!this.enableHighlight){d.enableHighlight=this.enableHighlight;}if(this.highlightState){d.highlightState=this.highlightState;}if(this.propagateHighlightUp){d.propagateHighlightUp=this.propagateHighlightUp;}if(this.propagateHighlightDown){d.propagateHighlightDown=this.propagateHighlightDown;}d.type=this._type;for(var e=0;e&lt;this.children.length;e++){g=this.children[e].getNodeDefiniti
 on();if(g===false){return false;}f.push(g);}if(f.length){d.children=f;}return d;},getToggleLink:function(){return&quot;return false;&quot;;},setNodesProperty:function(d,g,f){if(d.charAt(0)!=&quot;_&quot;&amp;&amp;!c.isUndefined(this[d])&amp;&amp;!c.isFunction(this[d])){this[d]=g;}else{this.data[d]=g;}for(var e=0;e&lt;this.children.length;e++){this.children[e].setNodesProperty(d,g);}if(f){this.refresh();}},toggleHighlight:function(){if(this.enableHighlight){if(this.highlightState==1){this.unhighlight();}else{this.highlight();}}},highlight:function(e){if(this.enableHighlight){if(this.tree.singleNodeHighlight){if(this.tree._currentlyHighlighted){this.tree._currentlyHighlighted.unhighlight(e);}this.tree._currentlyHighlighted=this;}this.highlightState=1;this._setHighlightClassName();if(!this.tree.singleNodeHighlight){if(this.propagateHighlightDown){for(var d=0;d&lt;this.children.length;d++){this.children[d].highlight(true);}}if(this.propagateHighlightUp){if(this.parent){this.pare
 nt._childrenHighlighted();}}}if(!e){this.tree.fireEvent(&quot;highlightEvent&quot;,this);}}},unhighlight:function(e){if(this.enableHighlight){this.tree._currentlyHighlighted=null;this.highlightState=0;this._setHighlightClassName();if(!this.tree.singleNodeHighlight){if(this.propagateHighlightDown){for(var d=0;d&lt;this.children.length;d++){this.children[d].unhighlight(true);}}if(this.propagateHighlightUp){if(this.parent){this.parent._childrenHighlighted();}}}if(!e){this.tree.fireEvent(&quot;highlightEvent&quot;,this);}}},_childrenHighlighted:function(){var f=false,e=false;if(this.enableHighlight){for(var d=0;d&lt;this.children.length;d++){switch(this.children[d].highlightState){case 0:e=true;
+break;case 1:f=true;break;case 2:f=e=true;break;}}if(f&amp;&amp;e){this.highlightState=2;}else{if(f){this.highlightState=1;}else{this.highlightState=0;}}this._setHighlightClassName();if(this.propagateHighlightUp){if(this.parent){this.parent._childrenHighlighted();}}}},_setHighlightClassName:function(){var d=b.get(&quot;ygtvtableel&quot;+this.index);if(d){d.className=d.className.replace(/\bygtv-highlight\d\b/gi,&quot;ygtv-highlight&quot;+this.highlightState);}}};YAHOO.augment(YAHOO.widget.Node,YAHOO.util.EventProvider);})();YAHOO.widget.RootNode=function(a){this.init(null,null,true);this.tree=a;};YAHOO.extend(YAHOO.widget.RootNode,YAHOO.widget.Node,{_type:&quot;RootNode&quot;,getNodeHtml:function(){return&quot;&quot;;},toString:function(){return this._type;},loadComplete:function(){this.tree.draw();},getNodeCount:function(){for(var a=0,b=0;a&lt;this.children.length;a++){b+=this.children[a].getNodeCount();}return b;},getNodeDefinition:function(){for(var c,a=[],b=0;b&lt;this.ch
 ildren.length;b++){c=this.children[b].getNodeDefinition();if(c===false){return false;}a.push(c);}return a;},collapse:function(){},expand:function(){},getSiblings:function(){return null;},focus:function(){}});(function(){var b=YAHOO.util.Dom,c=YAHOO.lang,a=YAHOO.util.Event;YAHOO.widget.TextNode=function(f,e,d){if(f){if(c.isString(f)){f={label:f};}this.init(f,e,d);this.setUpLabel(f);}};YAHOO.extend(YAHOO.widget.TextNode,YAHOO.widget.Node,{labelStyle:&quot;ygtvlabel&quot;,labelElId:null,label:null,title:null,href:null,target:&quot;_self&quot;,_type:&quot;TextNode&quot;,setUpLabel:function(d){if(c.isString(d)){d={label:d};}else{if(d.style){this.labelStyle=d.style;}}this.label=d.label;this.labelElId=&quot;ygtvlabelel&quot;+this.index;},getLabelEl:function(){return b.get(this.labelElId);},getContentHtml:function(){var d=[];d[d.length]=this.href?&quot;&lt;a&quot;:&quot;&lt;span&quot;;d[d.length]=' id=&quot;'+c.escapeHTML(this.labelElId)+'&quot;';d[d.length]=' class=&quot;'+c.escape
 HTML(this.labelStyle)+'&quot;';if(this.href){d[d.length]=' href=&quot;'+c.escapeHTML(this.href)+'&quot;';d[d.length]=' target=&quot;'+c.escapeHTML(this.target)+'&quot;';}if(this.title){d[d.length]=' title=&quot;'+c.escapeHTML(this.title)+'&quot;';}d[d.length]=&quot; &gt;&quot;;d[d.length]=c.escapeHTML(this.label);d[d.length]=this.href?&quot;&lt;/a&gt;&quot;:&quot;&lt;/span&gt;&quot;;return d.join(&quot;&quot;);},getNodeDefinition:function(){var d=YAHOO.widget.TextNode.superclass.getNodeDefinition.call(this);if(d===false){return false;}d.label=this.label;if(this.labelStyle!=&quot;ygtvlabel&quot;){d.style=this.labelStyle;}if(this.title){d.title=this.title;}if(this.href){d.href=this.href;}if(this.target!=&quot;_self&quot;){d.target=this.target;}return d;},toString:function(){return YAHOO.widget.TextNode.superclass.toString.call(this)+&quot;: &quot;+this.label;},onLabelClick:function(){return false;},refresh:function(){YAHOO.widget.TextNode.superclass.refresh.call(this);var d=th
 is.getLabelEl();d.innerHTML=this.label;if(d.tagName.toUpperCase()==&quot;A&quot;){d.href=this.href;d.target=this.target;}}});})();YAHOO.widget.MenuNode=function(c,b,a){YAHOO.widget.MenuNode.superclass.constructor.call(this,c,b,a);this.multiExpand=false;};YAHOO.extend(YAHOO.widget.MenuNode,YAHOO.widget.TextNode,{_type:&quot;MenuNode&quot;});(function(){var b=YAHOO.util.Dom,c=YAHOO.lang,a=YAHOO.util.Event;var d=function(h,g,f,e){if(h){this.init(h,g,f);this.initContent(h,e);}};YAHOO.widget.HTMLNode=d;YAHOO.extend(d,YAHOO.widget.Node,{contentStyle:&quot;ygtvhtml&quot;,html:null,_type:&quot;HTMLNode&quot;,initContent:function(f,e){this.setHtml(f);this.contentElId=&quot;ygtvcontentel&quot;+this.index;if(!c.isUndefined(e)){this.hasIcon=e;}},setHtml:function(f){this.html=(c.isObject(f)&amp;&amp;&quot;html&quot; in f)?f.html:f;var e=this.getContentEl();if(e){if(f.nodeType&amp;&amp;f.nodeType==1&amp;&amp;f.tagName){e.innerHTML=&quot;&quot;;}else{e.innerHTML=this.html;}}},getContentHtm
 l:function(){if(typeof this.html===&quot;string&quot;){return this.html;}else{d._deferredNodes.push(this);if(!d._timer){d._timer=window.setTimeout(function(){var e;while((e=d._deferredNodes.pop())){e.getContentEl().appendChild(e.html);}d._timer=null;},0);}return&quot;&quot;;}},getNodeDefinition:function(){var e=d.superclass.getNodeDefinition.call(this);if(e===false){return false;}e.html=this.html;return e;}});d._deferredNodes=[];d._timer=null;})();(function(){var b=YAHOO.util.Dom,c=YAHOO.lang,a=YAHOO.util.Event,d=YAHOO.widget.Calendar;YAHOO.widget.DateNode=function(g,f,e){YAHOO.widget.DateNode.superclass.constructor.call(this,g,f,e);};YAHOO.extend(YAHOO.widget.DateNode,YAHOO.widget.TextNode,{_type:&quot;DateNode&quot;,calendarConfig:null,fillEditorContainer:function(g){var h,f=g.inputContainer;if(c.isUndefined(d)){b.replaceClass(g.editorPanel,&quot;ygtv-edit-DateNode&quot;,&quot;ygtv-edit-TextNode&quot;);YAHOO.widget.DateNode.superclass.fillEditorContainer.call(this,g);retur
 n;}if(g.nodeType!=this._type){g.nodeType=this._type;g.saveOnEnter=false;g.node.destroyEditorContents(g);g.inputObject=h=new d(f.appendChild(document.createElement(&quot;div&quot;)));if(this.calendarConfig){h.cfg.applyConfig(this.calendarConfig,true);h.cfg.fireQueue();}h.selectEvent.subscribe(function(){this.tree._closeEditor(true);},this,true);}else{h=g.inputObject;}g.oldValue=this.label;h.cfg.setProperty(&quot;selected&quot;,this.label,false);var i=h.cfg.getProperty(&quot;DATE_FIELD_DELIMITER&quot;);var e=this.label.split(i);h.cfg.setProperty(&quot;pagedate&quot;,e[h.cfg.getProperty(&quot;MDY_MONTH_POSITION&quot;)-1]+i+e[h.cfg.getProperty(&quot;MDY_YEAR_POSITION&quot;)-1]);h.cfg.fireQueue();h.render();h.oDomContainer.focus();},getEditorValue:function(f){if(c.isUndefined(d)){return f.inputElement.value;}else{var h=f.inputObject,g=h.getSelectedDates()[0],e=[];e[h.cfg.getProperty(&quot;MDY_DAY_POSITION&quot;)-1]=g.getDate();e[h.cfg.getProperty(&quot;MDY_MONTH_POSITION&quot;)-1
 ]=g.getMonth()+1;e[h.cfg.getProperty(&quot;MDY_YEAR_POSITION&quot;)-1]=g.getFullYear();return e.join(h.cfg.getProperty(&quot;DATE_FIELD_DELIMITER&quot;));}},displayEditedValue:function(g,e){var f=e.node;f.label=g;f.getLabelEl().innerHTML=g;},getNodeDefinition:function(){var e=YAHOO.widget.DateNode.superclass.getNodeDefinition.call(this);if(e===false){return false;}if(this.calendarConfig){e.calendarConfig=this.calendarConfig;}return e;}});})();(function(){var e=YAHOO.util.Dom,f=YAHOO.lang,b=YAHOO.util.Event,d=YAHOO.widget.TreeView,c=d.prototype;d.editorData={active:false,whoHasIt:null,nodeType:null,editorPanel:null,inputContainer:null,buttonsContainer:null,node:null,saveOnEnter:true,oldValue:undefined};
+c.validator=null;c._initEditor=function(){this.createEvent(&quot;editorSaveEvent&quot;,this);this.createEvent(&quot;editorCancelEvent&quot;,this);};c._nodeEditing=function(m){if(m.fillEditorContainer&amp;&amp;m.editable){var i,k,l,j,h=d.editorData;h.active=true;h.whoHasIt=this;if(!h.nodeType){h.editorPanel=i=this.getEl().appendChild(document.createElement(&quot;div&quot;));e.addClass(i,&quot;ygtv-label-editor&quot;);i.tabIndex=0;l=h.buttonsContainer=i.appendChild(document.createElement(&quot;div&quot;));e.addClass(l,&quot;ygtv-button-container&quot;);j=l.appendChild(document.createElement(&quot;button&quot;));e.addClass(j,&quot;ygtvok&quot;);j.innerHTML=&quot; &quot;;j=l.appendChild(document.createElement(&quot;button&quot;));e.addClass(j,&quot;ygtvcancel&quot;);j.innerHTML=&quot; &quot;;b.on(l,&quot;click&quot;,function(q){var r=b.getTarget(q),o=d.editorData,p=o.node,n=o.whoHasIt;if(e.hasClass(r,&quot;ygtvok&quot;)){b.stopEvent(q);n._closeEditor(true);}if(e.hasClass(r,&quot
 ;ygtvcancel&quot;)){b.stopEvent(q);n._closeEditor(false);}});h.inputContainer=i.appendChild(document.createElement(&quot;div&quot;));e.addClass(h.inputContainer,&quot;ygtv-input&quot;);b.on(i,&quot;keydown&quot;,function(q){var p=d.editorData,n=YAHOO.util.KeyListener.KEY,o=p.whoHasIt;switch(q.keyCode){case n.ENTER:b.stopEvent(q);if(p.saveOnEnter){o._closeEditor(true);}break;case n.ESCAPE:b.stopEvent(q);o._closeEditor(false);break;}});}else{i=h.editorPanel;}h.node=m;if(h.nodeType){e.removeClass(i,&quot;ygtv-edit-&quot;+h.nodeType);}e.addClass(i,&quot; ygtv-edit-&quot;+m._type);e.setStyle(i,&quot;display&quot;,&quot;block&quot;);e.setXY(i,e.getXY(m.getContentEl()));i.focus();m.fillEditorContainer(h);return true;}};c.onEventEditNode=function(h){if(h instanceof YAHOO.widget.Node){h.editNode();}else{if(h.node instanceof YAHOO.widget.Node){h.node.editNode();}}return false;};c._closeEditor=function(j){var h=d.editorData,i=h.node,k=true;if(!i||!h.active){return;}if(j){k=h.node.saveE
 ditorValue(h)!==false;}else{this.fireEvent(&quot;editorCancelEvent&quot;,i);}if(k){e.setStyle(h.editorPanel,&quot;display&quot;,&quot;none&quot;);h.active=false;i.focus();}};c._destroyEditor=function(){var h=d.editorData;if(h&amp;&amp;h.nodeType&amp;&amp;(!h.active||h.whoHasIt===this)){b.removeListener(h.editorPanel,&quot;keydown&quot;);b.removeListener(h.buttonContainer,&quot;click&quot;);h.node.destroyEditorContents(h);document.body.removeChild(h.editorPanel);h.nodeType=h.editorPanel=h.inputContainer=h.buttonsContainer=h.whoHasIt=h.node=null;h.active=false;}};var g=YAHOO.widget.Node.prototype;g.editable=false;g.editNode=function(){this.tree._nodeEditing(this);};g.fillEditorContainer=null;g.destroyEditorContents=function(h){b.purgeElement(h.inputContainer,true);h.inputContainer.innerHTML=&quot;&quot;;};g.saveEditorValue=function(h){var j=h.node,k,i=j.tree.validator;k=this.getEditorValue(h);if(f.isFunction(i)){k=i(k,h.oldValue,j);if(f.isUndefined(k)){return false;}}if(this.t
 ree.fireEvent(&quot;editorSaveEvent&quot;,{newValue:k,oldValue:h.oldValue,node:j})!==false){this.displayEditedValue(k,h);}};g.getEditorValue=function(h){};g.displayEditedValue=function(i,h){};var a=YAHOO.widget.TextNode.prototype;a.fillEditorContainer=function(i){var h;if(i.nodeType!=this._type){i.nodeType=this._type;i.saveOnEnter=true;i.node.destroyEditorContents(i);i.inputElement=h=i.inputContainer.appendChild(document.createElement(&quot;input&quot;));}else{h=i.inputElement;}i.oldValue=this.label;h.value=this.label;h.focus();h.select();};a.getEditorValue=function(h){return h.inputElement.value;};a.displayEditedValue=function(j,h){var i=h.node;i.label=j;i.getLabelEl().innerHTML=j;};a.destroyEditorContents=function(h){h.inputContainer.innerHTML=&quot;&quot;;};})();YAHOO.widget.TVAnim=function(){return{FADE_IN:&quot;TVFadeIn&quot;,FADE_OUT:&quot;TVFadeOut&quot;,getAnim:function(b,a,c){if(YAHOO.widget[b]){return new YAHOO.widget[b](a,c);}else{return null;}},isValid:function(a
 ){return(YAHOO.widget[a]);}};}();YAHOO.widget.TVFadeIn=function(a,b){this.el=a;this.callback=b;};YAHOO.widget.TVFadeIn.prototype={animate:function(){var e=this;var d=this.el.style;d.opacity=0.1;d.filter=&quot;alpha(opacity=10)&quot;;d.display=&quot;&quot;;var c=0.4;var b=new YAHOO.util.Anim(this.el,{opacity:{from:0.1,to:1,unit:&quot;&quot;}},c);b.onComplete.subscribe(function(){e.onComplete();});b.animate();},onComplete:function(){this.callback();},toString:function(){return&quot;TVFadeIn&quot;;}};YAHOO.widget.TVFadeOut=function(a,b){this.el=a;this.callback=b;};YAHOO.widget.TVFadeOut.prototype={animate:function(){var d=this;var c=0.4;var b=new YAHOO.util.Anim(this.el,{opacity:{from:1,to:0.1,unit:&quot;&quot;}},c);b.onComplete.subscribe(function(){d.onComplete();});b.animate();},onComplete:function(){var a=this.el.style;a.display=&quot;none&quot;;a.opacity=1;a.filter=&quot;alpha(opacity=100)&quot;;this.callback();},toString:function(){return&quot;TVFadeOut&quot;;}};YAHOO.regi
 ster(&quot;treeview&quot;,YAHOO.widget.TreeView,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiuploaderuploaderminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/uploader/uploader-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/uploader/uploader-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/uploader/uploader-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,15 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+/*!
+ * SWFObject v1.5: Flash Player detection and embed - http://blog.deconcept.com/swfobject/
+ *
+ * SWFObject is (c) 2007 Geoff Stearns and is released under the MIT License:
+ * http://www.opensource.org/licenses/mit-license.php
+ * @namespace YAHOO
+ */
+YAHOO.namespace(&quot;deconcept&quot;);YAHOO.deconcept=YAHOO.deconcept||{};if(typeof YAHOO.deconcept.util==&quot;undefined&quot;||!YAHOO.deconcept.util){YAHOO.deconcept.util={};}if(typeof YAHOO.deconcept.SWFObjectUtil==&quot;undefined&quot;||!YAHOO.deconcept.SWFObjectUtil){YAHOO.deconcept.SWFObjectUtil={};}YAHOO.deconcept.SWFObject=function(f,d,m,g,j,l,n,i,a,e){if(!document.getElementById){return;}this.DETECT_KEY=e?e:&quot;detectflash&quot;;this.skipDetect=YAHOO.deconcept.util.getRequestParameter(this.DETECT_KEY);this.params={};this.variables={};this.attributes=[];if(f){this.setAttribute(&quot;swf&quot;,f);}if(d){this.setAttribute(&quot;id&quot;,d);}if(m){this.setAttribute(&quot;width&quot;,m);}if(g){this.setAttribute(&quot;height&quot;,g);}if(j){this.setAttribute(&quot;version&quot;,new YAHOO.deconcept.PlayerVersion(j.toString().split(&quot;.&quot;)));}this.installedVer=YAHOO.deconcept.SWFObjectUtil.getPlayerVersion();if(!window.opera&amp;&amp;document.all&amp;&amp;this.ins
 talledVer.major&gt;7){YAHOO.deconcept.SWFObject.doPrepUnload=true;}if(l){this.addParam(&quot;bgcolor&quot;,l);}var b=n?n:&quot;high&quot;;this.addParam(&quot;quality&quot;,b);this.setAttribute(&quot;useExpressInstall&quot;,false);this.setAttribute(&quot;doExpressInstall&quot;,false);var k=(i)?i:window.location;this.setAttribute(&quot;xiRedirectUrl&quot;,k);this.setAttribute(&quot;redirectUrl&quot;,&quot;&quot;);if(a){this.setAttribute(&quot;redirectUrl&quot;,a);}};YAHOO.deconcept.SWFObject.prototype={useExpressInstall:function(a){this.xiSWFPath=!a?&quot;expressinstall.swf&quot;:a;this.setAttribute(&quot;useExpressInstall&quot;,true);},setAttribute:function(a,b){this.attributes[a]=b;},getAttribute:function(a){return this.attributes[a];},addParam:function(a,b){this.params[a]=b;},getParams:function(){return this.params;},addVariable:function(a,b){this.variables[a]=b;},getVariable:function(a){return this.variables[a];},getVariables:function(){return this.variables;},getVariableP
 airs:function(){var a=[];var b;var c=this.getVariables();for(b in c){if(c.hasOwnProperty(b)){a[a.length]=YAHOO.lang.escapeHTML(b||&quot;&quot;)+&quot;=&quot;+YAHOO.lang.escapeHTML(encodeURIComponent(c[b]||&quot;&quot;));}}return a;},getSWFHTML:function(){var d=&quot;&quot;;var c={};var a=&quot;&quot;;var b=&quot;&quot;;if(navigator.plugins&amp;&amp;navigator.mimeTypes&amp;&amp;navigator.mimeTypes.length){if(this.getAttribute(&quot;doExpressInstall&quot;)){this.addVariable(&quot;MMplayerType&quot;,&quot;PlugIn&quot;);this.setAttribute(&quot;swf&quot;,this.xiSWFPath);}d='&lt;embed type=&quot;application/x-shockwave-flash&quot; src=&quot;'+YAHOO.lang.escapeHTML(this.getAttribute(&quot;swf&quot;)||&quot;&quot;)+'&quot; width=&quot;'+YAHOO.lang.escapeHTML(this.getAttribute(&quot;width&quot;)||&quot;&quot;)+'&quot; height=&quot;'+YAHOO.lang.escapeHTML(this.getAttribute(&quot;height&quot;)||&quot;&quot;)+'&quot; style=&quot;'+YAHOO.lang.escapeHTML(this.getAttribute(&quot;style&quot
 ;)||&quot;&quot;)+'&quot;';d+=' id=&quot;'+YAHOO.lang.escapeHTML(this.getAttribute(&quot;id&quot;)||&quot;&quot;)+'&quot; name=&quot;'+YAHOO.lang.escapeHTML(this.getAttribute(&quot;id&quot;)||&quot;&quot;)+'&quot; ';c=this.getParams();for(a in c){if(c.hasOwnProperty(a)){d+=YAHOO.lang.escapeHTML(a||&quot;&quot;)+'=&quot;'+YAHOO.lang.escapeHTML(c[a]||&quot;&quot;)+'&quot; ';}}b=this.getVariablePairs().join(&quot;&amp;&quot;);if(b.length&gt;0){d+='flashvars=&quot;'+b+'&quot;';}d+=&quot;/&gt;&quot;;}else{if(this.getAttribute(&quot;doExpressInstall&quot;)){this.addVariable(&quot;MMplayerType&quot;,&quot;ActiveX&quot;);this.setAttribute(&quot;swf&quot;,this.xiSWFPath);}d='&lt;object id=&quot;'+YAHOO.lang.escapeHTML(this.getAttribute(&quot;id&quot;)||&quot;&quot;)+'&quot; classid=&quot;clsid:D27CDB6E-AE6D-11cf-96B8-444553540000&quot; width=&quot;'+YAHOO.lang.escapeHTML(this.getAttribute(&quot;width&quot;)||&quot;&quot;)+'&quot; height=&quot;'+YAHOO.lang.escapeHTML(this.getAttribute
 (&quot;height&quot;)||&quot;&quot;)+'&quot; style=&quot;'+YAHOO.lang.escapeHTML(this.getAttribute(&quot;style&quot;)||&quot;&quot;)+'&quot;&gt;';d+='&lt;param name=&quot;movie&quot; value=&quot;'+YAHOO.lang.escapeHTML(this.getAttribute(&quot;swf&quot;)||&quot;&quot;)+'&quot; /&gt;';c=this.getParams();for(a in c){if(c.hasOwnProperty(a)){d+='&lt;param name=&quot;'+YAHOO.lang.escapeHTML(a||&quot;&quot;)+'&quot; value=&quot;'+YAHOO.lang.escapeHTML(c[a]||&quot;&quot;)+'&quot; /&gt;';}}b=this.getVariablePairs().join(&quot;&amp;&quot;);if(b.length&gt;0){d+='&lt;param name=&quot;flashvars&quot; value=&quot;'+b+'&quot; /&gt;';}d+=&quot;&lt;/object&gt;&quot;;}return d;},write:function(a){if(this.getAttribute(&quot;useExpressInstall&quot;)){var b=new YAHOO.deconcept.PlayerVersion([6,0,65]);if(this.installedVer.versionIsValid(b)&amp;&amp;!this.installedVer.versionIsValid(this.getAttribute(&quot;version&quot;))){this.setAttribute(&quot;doExpressInstall&quot;,true);this.addVariable(&quot;
 MMredirectURL&quot;,escape(this.getAttribute(&quot;xiRedirectUrl&quot;)));document.title=document.title.slice(0,47)+&quot; - Flash Player Installation&quot;;this.addVariable(&quot;MMdoctitle&quot;,document.title);}}if(this.skipDetect||this.getAttribute(&quot;doExpressInstall&quot;)||this.installedVer.versionIsValid(this.getAttribute(&quot;version&quot;))){var c=(typeof a==&quot;string&quot;)?document.getElementById(a):a;c.innerHTML=this.getSWFHTML();return true;}else{if(this.getAttribute(&quot;redirectUrl&quot;)!==&quot;&quot;){document.location.replace(this.getAttribute(&quot;redirectUrl&quot;));}}return false;}};YAHOO.deconcept.SWFObjectUtil.getPlayerVersion=function(){var d=null;var c=new YAHOO.deconcept.PlayerVersion([0,0,0]);if(navigator.plugins&amp;&amp;navigator.mimeTypes.length){var a=navigator.plugins[&quot;Shockwave Flash&quot;];if(a&amp;&amp;a.description){c=new YAHOO.deconcept.PlayerVersion(a.description.replace(/([a-zA-Z]|\s)+/,&quot;&quot;).replace(/(\s+r|\s+b[
 0-9]+)/,&quot;.&quot;).split(&quot;.&quot;));}}else{if(navigator.userAgent&amp;&amp;navigator.userAgent.indexOf(&quot;Windows CE&quot;)&gt;=0){var b=3;while(d){try{b++;d=new ActiveXObject(&quot;ShockwaveFlash.ShockwaveFlash.&quot;+b);c=new YAHOO.deconcept.PlayerVersion([b,0,0]);}catch(f){d=null;}}}else{try{d=new ActiveXObject(&quot;ShockwaveFlash.ShockwaveFlash.7&quot;);}catch(f){try{d=new ActiveXObject(&quot;ShockwaveFlash.ShockwaveFlash.6&quot;);c=new YAHOO.deconcept.PlayerVersion([6,0,21]);d.AllowScriptAccess=&quot;always&quot;;}catch(f){if(c.major==6){return c;}}try{d=new ActiveXObject(&quot;ShockwaveFlash.ShockwaveFlash&quot;);}catch(f){}}if(d!==null){c=new YAHOO.deconcept.PlayerVersion(d.GetVariable(&quot;$version&quot;).split(&quot; &quot;)[1].split(&quot;,&quot;));}}}return c;};YAHOO.deconcept.PlayerVersion=function(a){this.major=a[0]!==null?parseInt(a[0],0):0;this.minor=a[1]!==null?parseInt(a[1],0):0;this.rev=a[2]!==null?parseInt(a[2],0):0;};YAHOO.deconcept.PlayerVe
 rsion.prototype.versionIsValid=function(a){if(this.major&lt;a.major){return false;
+}if(this.major&gt;a.major){return true;}if(this.minor&lt;a.minor){return false;}if(this.minor&gt;a.minor){return true;}if(this.rev&lt;a.rev){return false;}return true;};YAHOO.deconcept.util={getRequestParameter:function(d){var c=document.location.search||document.location.hash;if(d===null){return c;}if(c){var b=c.substring(1).split(&quot;&amp;&quot;);for(var a=0;a&lt;b.length;a++){if(b[a].substring(0,b[a].indexOf(&quot;=&quot;))==d){return b[a].substring((b[a].indexOf(&quot;=&quot;)+1));}}}return&quot;&quot;;}};YAHOO.deconcept.SWFObjectUtil.cleanupSWFs=function(){var c=document.getElementsByTagName(&quot;OBJECT&quot;);for(var b=c.length-1;b&gt;=0;b--){c[b].style.display=&quot;none&quot;;for(var a in c[b]){if(typeof c[b][a]==&quot;function&quot;){c[b][a]=function(){};}}}};if(YAHOO.deconcept.SWFObject.doPrepUnload){if(!YAHOO.deconcept.unloadSet){YAHOO.deconcept.SWFObjectUtil.prepUnload=function(){__flash_unloadHandler=function(){};__flash_savedUnloadHandler=function(){};window
 .attachEvent(&quot;onunload&quot;,YAHOO.deconcept.SWFObjectUtil.cleanupSWFs);};window.attachEvent(&quot;onbeforeunload&quot;,YAHOO.deconcept.SWFObjectUtil.prepUnload);YAHOO.deconcept.unloadSet=true;}}if(!document.getElementById&amp;&amp;document.all){document.getElementById=function(a){return document.all[a];};}YAHOO.widget.FlashAdapter=function(f,a,b,c){this._queue=this._queue||[];this._events=this._events||{};this._configs=this._configs||{};b=b||{};this._id=b.id=b.id||YAHOO.util.Dom.generateId(null,&quot;yuigen&quot;);b.version=b.version||&quot;9.0.45&quot;;b.backgroundColor=b.backgroundColor||&quot;#ffffff&quot;;this._attributes=b;this._swfURL=f;this._containerID=a;this._embedSWF(this._swfURL,this._containerID,b.id,b.version,b.backgroundColor,b.expressInstall,b.wmode,c);try{this.createEvent(&quot;contentReady&quot;);}catch(d){}};YAHOO.widget.FlashAdapter.owners=YAHOO.widget.FlashAdapter.owners||{};YAHOO.extend(YAHOO.widget.FlashAdapter,YAHOO.util.AttributeProvider,{_swfUR
 L:null,_containerID:null,_swf:null,_id:null,_initialized:false,_attributes:null,toString:function(){return&quot;FlashAdapter &quot;+this._id;},destroy:function(){if(this._swf){var b=YAHOO.util.Dom.get(this._containerID);b.removeChild(this._swf);}var a=this._id;for(var c in this){if(YAHOO.lang.hasOwnProperty(this,c)){this[c]=null;}}},_embedSWF:function(j,i,e,c,f,g,b,h){var d=new YAHOO.deconcept.SWFObject(j,e,&quot;100%&quot;,&quot;100%&quot;,c,f);if(g){d.useExpressInstall(g);}d.addParam(&quot;allowScriptAccess&quot;,&quot;always&quot;);if(b){d.addParam(&quot;wmode&quot;,b);}d.addParam(&quot;menu&quot;,&quot;false&quot;);d.addVariable(&quot;allowedDomain&quot;,document.location.hostname);d.addVariable(&quot;YUISwfId&quot;,e);d.addVariable(&quot;YUIBridgeCallback&quot;,&quot;YAHOO.widget.FlashAdapter.eventHandler&quot;);if(h){d.addVariable(&quot;buttonSkin&quot;,h);}var a=YAHOO.util.Dom.get(i);var k=d.write(a);if(k){this._swf=YAHOO.util.Dom.get(e);YAHOO.widget.FlashAdapter.owne
 rs[e]=this;}else{}},_eventHandler:function(b){var a=b.type;switch(a){case&quot;swfReady&quot;:this._loadHandler();return;case&quot;log&quot;:return;}this.fireEvent(a,b);},_loadHandler:function(){this._initialized=false;this._initAttributes(this._attributes);this.setAttributes(this._attributes,true);this._initialized=true;this.fireEvent(&quot;contentReady&quot;);},set:function(a,b){this._attributes[a]=b;YAHOO.widget.FlashAdapter.superclass.set.call(this,a,b);},_initAttributes:function(a){this.getAttributeConfig(&quot;altText&quot;,{method:this._getAltText});this.setAttributeConfig(&quot;altText&quot;,{method:this._setAltText});this.getAttributeConfig(&quot;swfURL&quot;,{method:this._getSWFURL});},_getSWFURL:function(){return this._swfURL;},_getAltText:function(){return this._swf.getAltText();},_setAltText:function(a){return this._swf.setAltText(a);}});YAHOO.widget.FlashAdapter.eventHandler=function(a,b){if(!YAHOO.widget.FlashAdapter.owners[a]){setTimeout(function(){YAHOO.widg
 et.FlashAdapter.eventHandler(a,b);},0);}else{YAHOO.widget.FlashAdapter.owners[a]._eventHandler(b);}};YAHOO.widget.FlashAdapter.proxyFunctionCount=0;YAHOO.widget.FlashAdapter.createProxyFunction=function(b){var a=YAHOO.widget.FlashAdapter.proxyFunctionCount;YAHOO.widget.FlashAdapter[&quot;proxyFunction&quot;+a]=function(){return b.apply(null,arguments);};YAHOO.widget.FlashAdapter.proxyFunctionCount++;return&quot;YAHOO.widget.FlashAdapter.proxyFunction&quot;+a.toString();};YAHOO.widget.FlashAdapter.removeProxyFunction=function(a){if(!a||a.indexOf(&quot;YAHOO.widget.FlashAdapter.proxyFunction&quot;)&lt;0){return;}a=a.substr(26);YAHOO.widget.FlashAdapter[a]=null;};YAHOO.widget.Uploader=function(a,b,d){var c=&quot;window&quot;;if(!(b)||(b&amp;&amp;d)){c=&quot;transparent&quot;;}YAHOO.widget.Uploader.superclass.constructor.call(this,YAHOO.widget.Uploader.SWFURL,a,{wmode:c},b);this.createEvent(&quot;mouseDown&quot;);this.createEvent(&quot;mouseUp&quot;);this.createEvent(&quot;rollO
 ver&quot;);this.createEvent(&quot;rollOut&quot;);this.createEvent(&quot;click&quot;);this.createEvent(&quot;fileSelect&quot;);this.createEvent(&quot;uploadStart&quot;);this.createEvent(&quot;uploadProgress&quot;);this.createEvent(&quot;uploadCancel&quot;);this.createEvent(&quot;uploadComplete&quot;);this.createEvent(&quot;uploadCompleteData&quot;);this.createEvent(&quot;uploadError&quot;);};YAHOO.widget.Uploader.SWFURL=&quot;assets/uploader.swf&quot;;YAHOO.extend(YAHOO.widget.Uploader,YAHOO.widget.FlashAdapter,{upload:function(a,b,e,c,d){this._swf.upload(a,b,e,c,d);},uploadThese:function(b,a,e,c,d){this._swf.uploadThese(b,a,e,c,d);},uploadAll:function(a,d,b,c){this._swf.uploadAll(a,d,b,c);},cancel:function(a){this._swf.cancel(a);},clearFileList:function(){this._swf.clearFileList();},removeFile:function(a){this._swf.removeFile(a);},setAllowLogging:function(a){this._swf.setAllowLogging(a);},setSimUploadLimit:function(a){this._swf.setSimUploadLimit(a);},setAllowMultipleFiles:fu
 nction(a){this._swf.setAllowMultipleFiles(a);},setFileFilters:function(a){this._swf.setFileFilters(a);},enable:function(){this._swf.enable();},disable:function(){this._swf.disable();}});YAHOO.register(&quot;uploader&quot;,YAHOO.widget.Uploader,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiyahooyahoominjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/yahoo/yahoo-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/yahoo/yahoo-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/yahoo/yahoo-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,8 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+if(typeof YAHOO==&quot;undefined&quot;||!YAHOO){var YAHOO={};}YAHOO.namespace=function(){var b=arguments,g=null,e,c,f;for(e=0;e&lt;b.length;e=e+1){f=(&quot;&quot;+b[e]).split(&quot;.&quot;);g=YAHOO;for(c=(f[0]==&quot;YAHOO&quot;)?1:0;c&lt;f.length;c=c+1){g[f[c]]=g[f[c]]||{};g=g[f[c]];}}return g;};YAHOO.log=function(d,a,c){var b=YAHOO.widget.Logger;if(b&amp;&amp;b.log){return b.log(d,a,c);}else{return false;}};YAHOO.register=function(a,f,e){var k=YAHOO.env.modules,c,j,h,g,d;if(!k[a]){k[a]={versions:[],builds:[]};}c=k[a];j=e.version;h=e.build;g=YAHOO.env.listeners;c.name=a;c.version=j;c.build=h;c.versions.push(j);c.builds.push(h);c.mainClass=f;for(d=0;d&lt;g.length;d=d+1){g[d](c);}if(f){f.VERSION=j;f.BUILD=h;}else{YAHOO.log(&quot;mainClass is undefined for module &quot;+a,&quot;warn&quot;);}};YAHOO.env=YAHOO.env||{modules:[],listeners:[]};YAHOO.env.getVersion=function(a){return YAHOO.env.modules[a]||null;};YAHOO.env.parseUA=function(d){var e=function(i){var j=0;return parseFlo
 at(i.replace(/\./g,function(){return(j++==1)?&quot;&quot;:&quot;.&quot;;}));},h=navigator,g={ie:0,opera:0,gecko:0,webkit:0,chrome:0,mobile:null,air:0,ipad:0,iphone:0,ipod:0,ios:null,android:0,webos:0,caja:h&amp;&amp;h.cajaVersion,secure:false,os:null},c=d||(navigator&amp;&amp;navigator.userAgent),f=window&amp;&amp;window.location,b=f&amp;&amp;f.href,a;g.secure=b&amp;&amp;(b.toLowerCase().indexOf(&quot;https&quot;)===0);if(c){if((/windows|win32/i).test(c)){g.os=&quot;windows&quot;;}else{if((/macintosh/i).test(c)){g.os=&quot;macintosh&quot;;}else{if((/rhino/i).test(c)){g.os=&quot;rhino&quot;;}}}if((/KHTML/).test(c)){g.webkit=1;}a=c.match(/AppleWebKit\/([^\s]*)/);if(a&amp;&amp;a[1]){g.webkit=e(a[1]);if(/ Mobile\//.test(c)){g.mobile=&quot;Apple&quot;;a=c.match(/OS ([^\s]*)/);if(a&amp;&amp;a[1]){a=e(a[1].replace(&quot;_&quot;,&quot;.&quot;));}g.ios=a;g.ipad=g.ipod=g.iphone=0;a=c.match(/iPad|iPod|iPhone/);if(a&amp;&amp;a[0]){g[a[0].toLowerCase()]=g.ios;}}else{a=c.match(/NokiaN[^\/
 ]*|Android \d\.\d|webOS\/\d\.\d/);if(a){g.mobile=a[0];}if(/webOS/.test(c)){g.mobile=&quot;WebOS&quot;;a=c.match(/webOS\/([^\s]*);/);if(a&amp;&amp;a[1]){g.webos=e(a[1]);}}if(/ Android/.test(c)){g.mobile=&quot;Android&quot;;a=c.match(/Android ([^\s]*);/);if(a&amp;&amp;a[1]){g.android=e(a[1]);}}}a=c.match(/Chrome\/([^\s]*)/);if(a&amp;&amp;a[1]){g.chrome=e(a[1]);}else{a=c.match(/AdobeAIR\/([^\s]*)/);if(a){g.air=a[0];}}}if(!g.webkit){a=c.match(/Opera[\s\/]([^\s]*)/);if(a&amp;&amp;a[1]){g.opera=e(a[1]);a=c.match(/Version\/([^\s]*)/);if(a&amp;&amp;a[1]){g.opera=e(a[1]);}a=c.match(/Opera Mini[^;]*/);if(a){g.mobile=a[0];}}else{a=c.match(/MSIE\s([^;]*)/);if(a&amp;&amp;a[1]){g.ie=e(a[1]);}else{a=c.match(/Gecko\/([^\s]*)/);if(a){g.gecko=1;a=c.match(/rv:([^\s\)]*)/);if(a&amp;&amp;a[1]){g.gecko=e(a[1]);}}}}}}return g;};YAHOO.env.ua=YAHOO.env.parseUA();(function(){YAHOO.namespace(&quot;util&quot;,&quot;widget&quot;,&quot;example&quot;);if(&quot;undefined&quot;!==typeof YAHOO_config){var b=
 YAHOO_config.listener,a=YAHOO.env.listeners,d=true,c;if(b){for(c=0;c&lt;a.length;c++){if(a[c]==b){d=false;break;}}if(d){a.push(b);}}}})();YAHOO.lang=YAHOO.lang||{};(function(){var f=YAHOO.lang,a=Object.prototype,c=&quot;[object Array]&quot;,h=&quot;[object Function]&quot;,i=&quot;[object Object]&quot;,b=[],g={&quot;&amp;&quot;:&quot;&amp;amp;&quot;,&quot;&lt;&quot;:&quot;&amp;lt;&quot;,&quot;&gt;&quot;:&quot;&amp;gt;&quot;,'&quot;':&quot;&amp;quot;&quot;,&quot;'&quot;:&quot;&amp;#x27;&quot;,&quot;/&quot;:&quot;&amp;#x2F;&quot;,&quot;`&quot;:&quot;&amp;#x60;&quot;},d=[&quot;toString&quot;,&quot;valueOf&quot;],e={isArray:function(j){return a.toString.apply(j)===c;},isBoolean:function(j){return typeof j===&quot;boolean&quot;;},isFunction:function(j){return(typeof j===&quot;function&quot;)||a.toString.apply(j)===h;},isNull:function(j){return j===null;},isNumber:function(j){return typeof j===&quot;number&quot;&amp;&amp;isFinite(j);},isObject:function(j){return(j&amp;&amp;(typeof 
 j===&quot;object&quot;||f.isFunction(j)))||false;},isString:function(j){return typeof j===&quot;string&quot;;},isUndefined:function(j){return typeof j===&quot;undefined&quot;;},_IEEnumFix:(YAHOO.env.ua.ie)?function(l,k){var j,n,m;for(j=0;j&lt;d.length;j=j+1){n=d[j];m=k[n];if(f.isFunction(m)&amp;&amp;m!=a[n]){l[n]=m;}}}:function(){},escapeHTML:function(j){return j.replace(/[&amp;&lt;&gt;&quot;'\/`]/g,function(k){return g[k];});},extend:function(m,n,l){if(!n||!m){throw new Error(&quot;extend failed, please check that &quot;+&quot;all dependencies are included.&quot;);}var k=function(){},j;k.prototype=n.prototype;m.prototype=new k();m.prototype.constructor=m;m.superclass=n.prototype;if(n.prototype.constructor==a.constructor){n.prototype.constructor=n;}if(l){for(j in l){if(f.hasOwnProperty(l,j)){m.prototype[j]=l[j];}}f._IEEnumFix(m.prototype,l);}},augmentObject:function(n,m){if(!m||!n){throw new Error(&quot;Absorb failed, verify dependencies.&quot;);}var j=arguments,l,o,k=j[2];i
 f(k&amp;&amp;k!==true){for(l=2;l&lt;j.length;l=l+1){n[j[l]]=m[j[l]];}}else{for(o in m){if(k||!(o in n)){n[o]=m[o];}}f._IEEnumFix(n,m);}return n;},augmentProto:function(m,l){if(!l||!m){throw new Error(&quot;Augment failed, verify dependencies.&quot;);}var j=[m.prototype,l.prototype],k;for(k=2;k&lt;arguments.length;k=k+1){j.push(arguments[k]);}f.augmentObject.apply(this,j);return m;},dump:function(j,p){var l,n,r=[],t=&quot;{...}&quot;,k=&quot;f(){...}&quot;,q=&quot;, &quot;,m=&quot; =&gt; &quot;;if(!f.isObject(j)){return j+&quot;&quot;;}else{if(j instanceof Date||(&quot;nodeType&quot; in j&amp;&amp;&quot;tagName&quot; in j)){return j;}else{if(f.isFunction(j)){return k;}}}p=(f.isNumber(p))?p:3;if(f.isArray(j)){r.push(&quot;[&quot;);for(l=0,n=j.length;l&lt;n;l=l+1){if(f.isObject(j[l])){r.push((p&gt;0)?f.dump(j[l],p-1):t);}else{r.push(j[l]);}r.push(q);}if(r.length&gt;1){r.pop();}r.push(&quot;]&quot;);}else{r.push(&quot;{&quot;);for(l in j){if(f.hasOwnProperty(j,l)){r.push(l+m);if
 (f.isObject(j[l])){r.push((p&gt;0)?f.dump(j[l],p-1):t);}else{r.push(j[l]);}r.push(q);}}if(r.length&gt;1){r.pop();}r.push(&quot;}&quot;);}return r.join(&quot;&quot;);},substitute:function(x,y,E,l){var D,C,B,G,t,u,F=[],p,z=x.length,A=&quot;dump&quot;,r=&quot; &quot;,q=&quot;{&quot;,m=&quot;}&quot;,n,w;for(;;){D=x.lastIndexOf(q,z);if(D&lt;0){break;}C=x.indexOf(m,D);if(D+1&gt;C){break;}p=x.substring(D+1,C);G=p;u=null;B=G.indexOf(r);if(B&gt;-1){u=G.substring(B+1);G=G.substring(0,B);}t=y[G];if(E){t=E(G,t,u);}if(f.isObject(t)){if(f.isArray(t)){t=f.dump(t,parseInt(u,10));}else{u=u||&quot;&quot;;n=u.indexOf(A);if(n&gt;-1){u=u.substring(4);}w=t.toString();if(w===i||n&gt;-1){t=f.dump(t,parseInt(u,10));}else{t=w;}}}else{if(!f.isString(t)&amp;&amp;!f.isNumber(t)){t=&quot;~-&quot;+F.length+&quot;-~&quot;;F[F.length]=p;}}x=x.substring(0,D)+t+x.substring(C+1);if(l===false){z=D-1;}}for(D=F.length-1;D&gt;=0;D=D-1){x=x.replace(new RegExp(&quot;~-&quot;+D+&quot;-~&quot;),&quot;{&quot;+F[D]+&quo
 t;}&quot;,&quot;g&quot;);}return x;},trim:function(j){try{return j.replace(/^\s+|\s+$/g,&quot;&quot;);}catch(k){return j;
+}},merge:function(){var n={},k=arguments,j=k.length,m;for(m=0;m&lt;j;m=m+1){f.augmentObject(n,k[m],true);}return n;},later:function(t,k,u,n,p){t=t||0;k=k||{};var l=u,s=n,q,j;if(f.isString(u)){l=k[u];}if(!l){throw new TypeError(&quot;method undefined&quot;);}if(!f.isUndefined(n)&amp;&amp;!f.isArray(s)){s=[n];}q=function(){l.apply(k,s||b);};j=(p)?setInterval(q,t):setTimeout(q,t);return{interval:p,cancel:function(){if(this.interval){clearInterval(j);}else{clearTimeout(j);}}};},isValue:function(j){return(f.isObject(j)||f.isString(j)||f.isNumber(j)||f.isBoolean(j));}};f.hasOwnProperty=(a.hasOwnProperty)?function(j,k){return j&amp;&amp;j.hasOwnProperty&amp;&amp;j.hasOwnProperty(k);}:function(j,k){return !f.isUndefined(j[k])&amp;&amp;j.constructor.prototype[k]!==j[k];};e.augmentObject(f,e,true);YAHOO.util.Lang=f;f.augment=f.augmentProto;YAHOO.augment=f.augmentProto;YAHOO.extend=f.extend;})();YAHOO.register(&quot;yahoo&quot;,YAHOO,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiyahoodomeventyahoodomeventjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/yahoo-dom-event/yahoo-dom-event.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/yahoo-dom-event/yahoo-dom-event.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/yahoo-dom-event/yahoo-dom-event.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,14 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+if(typeof YAHOO==&quot;undefined&quot;||!YAHOO){var YAHOO={};}YAHOO.namespace=function(){var b=arguments,g=null,e,c,f;for(e=0;e&lt;b.length;e=e+1){f=(&quot;&quot;+b[e]).split(&quot;.&quot;);g=YAHOO;for(c=(f[0]==&quot;YAHOO&quot;)?1:0;c&lt;f.length;c=c+1){g[f[c]]=g[f[c]]||{};g=g[f[c]];}}return g;};YAHOO.log=function(d,a,c){var b=YAHOO.widget.Logger;if(b&amp;&amp;b.log){return b.log(d,a,c);}else{return false;}};YAHOO.register=function(a,f,e){var k=YAHOO.env.modules,c,j,h,g,d;if(!k[a]){k[a]={versions:[],builds:[]};}c=k[a];j=e.version;h=e.build;g=YAHOO.env.listeners;c.name=a;c.version=j;c.build=h;c.versions.push(j);c.builds.push(h);c.mainClass=f;for(d=0;d&lt;g.length;d=d+1){g[d](c);}if(f){f.VERSION=j;f.BUILD=h;}else{YAHOO.log(&quot;mainClass is undefined for module &quot;+a,&quot;warn&quot;);}};YAHOO.env=YAHOO.env||{modules:[],listeners:[]};YAHOO.env.getVersion=function(a){return YAHOO.env.modules[a]||null;};YAHOO.env.parseUA=function(d){var e=function(i){var j=0;return parseFlo
 at(i.replace(/\./g,function(){return(j++==1)?&quot;&quot;:&quot;.&quot;;}));},h=navigator,g={ie:0,opera:0,gecko:0,webkit:0,chrome:0,mobile:null,air:0,ipad:0,iphone:0,ipod:0,ios:null,android:0,webos:0,caja:h&amp;&amp;h.cajaVersion,secure:false,os:null},c=d||(navigator&amp;&amp;navigator.userAgent),f=window&amp;&amp;window.location,b=f&amp;&amp;f.href,a;g.secure=b&amp;&amp;(b.toLowerCase().indexOf(&quot;https&quot;)===0);if(c){if((/windows|win32/i).test(c)){g.os=&quot;windows&quot;;}else{if((/macintosh/i).test(c)){g.os=&quot;macintosh&quot;;}else{if((/rhino/i).test(c)){g.os=&quot;rhino&quot;;}}}if((/KHTML/).test(c)){g.webkit=1;}a=c.match(/AppleWebKit\/([^\s]*)/);if(a&amp;&amp;a[1]){g.webkit=e(a[1]);if(/ Mobile\//.test(c)){g.mobile=&quot;Apple&quot;;a=c.match(/OS ([^\s]*)/);if(a&amp;&amp;a[1]){a=e(a[1].replace(&quot;_&quot;,&quot;.&quot;));}g.ios=a;g.ipad=g.ipod=g.iphone=0;a=c.match(/iPad|iPod|iPhone/);if(a&amp;&amp;a[0]){g[a[0].toLowerCase()]=g.ios;}}else{a=c.match(/NokiaN[^\/
 ]*|Android \d\.\d|webOS\/\d\.\d/);if(a){g.mobile=a[0];}if(/webOS/.test(c)){g.mobile=&quot;WebOS&quot;;a=c.match(/webOS\/([^\s]*);/);if(a&amp;&amp;a[1]){g.webos=e(a[1]);}}if(/ Android/.test(c)){g.mobile=&quot;Android&quot;;a=c.match(/Android ([^\s]*);/);if(a&amp;&amp;a[1]){g.android=e(a[1]);}}}a=c.match(/Chrome\/([^\s]*)/);if(a&amp;&amp;a[1]){g.chrome=e(a[1]);}else{a=c.match(/AdobeAIR\/([^\s]*)/);if(a){g.air=a[0];}}}if(!g.webkit){a=c.match(/Opera[\s\/]([^\s]*)/);if(a&amp;&amp;a[1]){g.opera=e(a[1]);a=c.match(/Version\/([^\s]*)/);if(a&amp;&amp;a[1]){g.opera=e(a[1]);}a=c.match(/Opera Mini[^;]*/);if(a){g.mobile=a[0];}}else{a=c.match(/MSIE\s([^;]*)/);if(a&amp;&amp;a[1]){g.ie=e(a[1]);}else{a=c.match(/Gecko\/([^\s]*)/);if(a){g.gecko=1;a=c.match(/rv:([^\s\)]*)/);if(a&amp;&amp;a[1]){g.gecko=e(a[1]);}}}}}}return g;};YAHOO.env.ua=YAHOO.env.parseUA();(function(){YAHOO.namespace(&quot;util&quot;,&quot;widget&quot;,&quot;example&quot;);if(&quot;undefined&quot;!==typeof YAHOO_config){var b=
 YAHOO_config.listener,a=YAHOO.env.listeners,d=true,c;if(b){for(c=0;c&lt;a.length;c++){if(a[c]==b){d=false;break;}}if(d){a.push(b);}}}})();YAHOO.lang=YAHOO.lang||{};(function(){var f=YAHOO.lang,a=Object.prototype,c=&quot;[object Array]&quot;,h=&quot;[object Function]&quot;,i=&quot;[object Object]&quot;,b=[],g={&quot;&amp;&quot;:&quot;&amp;amp;&quot;,&quot;&lt;&quot;:&quot;&amp;lt;&quot;,&quot;&gt;&quot;:&quot;&amp;gt;&quot;,'&quot;':&quot;&amp;quot;&quot;,&quot;'&quot;:&quot;&amp;#x27;&quot;,&quot;/&quot;:&quot;&amp;#x2F;&quot;,&quot;`&quot;:&quot;&amp;#x60;&quot;},d=[&quot;toString&quot;,&quot;valueOf&quot;],e={isArray:function(j){return a.toString.apply(j)===c;},isBoolean:function(j){return typeof j===&quot;boolean&quot;;},isFunction:function(j){return(typeof j===&quot;function&quot;)||a.toString.apply(j)===h;},isNull:function(j){return j===null;},isNumber:function(j){return typeof j===&quot;number&quot;&amp;&amp;isFinite(j);},isObject:function(j){return(j&amp;&amp;(typeof 
 j===&quot;object&quot;||f.isFunction(j)))||false;},isString:function(j){return typeof j===&quot;string&quot;;},isUndefined:function(j){return typeof j===&quot;undefined&quot;;},_IEEnumFix:(YAHOO.env.ua.ie)?function(l,k){var j,n,m;for(j=0;j&lt;d.length;j=j+1){n=d[j];m=k[n];if(f.isFunction(m)&amp;&amp;m!=a[n]){l[n]=m;}}}:function(){},escapeHTML:function(j){return j.replace(/[&amp;&lt;&gt;&quot;'\/`]/g,function(k){return g[k];});},extend:function(m,n,l){if(!n||!m){throw new Error(&quot;extend failed, please check that &quot;+&quot;all dependencies are included.&quot;);}var k=function(){},j;k.prototype=n.prototype;m.prototype=new k();m.prototype.constructor=m;m.superclass=n.prototype;if(n.prototype.constructor==a.constructor){n.prototype.constructor=n;}if(l){for(j in l){if(f.hasOwnProperty(l,j)){m.prototype[j]=l[j];}}f._IEEnumFix(m.prototype,l);}},augmentObject:function(n,m){if(!m||!n){throw new Error(&quot;Absorb failed, verify dependencies.&quot;);}var j=arguments,l,o,k=j[2];i
 f(k&amp;&amp;k!==true){for(l=2;l&lt;j.length;l=l+1){n[j[l]]=m[j[l]];}}else{for(o in m){if(k||!(o in n)){n[o]=m[o];}}f._IEEnumFix(n,m);}return n;},augmentProto:function(m,l){if(!l||!m){throw new Error(&quot;Augment failed, verify dependencies.&quot;);}var j=[m.prototype,l.prototype],k;for(k=2;k&lt;arguments.length;k=k+1){j.push(arguments[k]);}f.augmentObject.apply(this,j);return m;},dump:function(j,p){var l,n,r=[],t=&quot;{...}&quot;,k=&quot;f(){...}&quot;,q=&quot;, &quot;,m=&quot; =&gt; &quot;;if(!f.isObject(j)){return j+&quot;&quot;;}else{if(j instanceof Date||(&quot;nodeType&quot; in j&amp;&amp;&quot;tagName&quot; in j)){return j;}else{if(f.isFunction(j)){return k;}}}p=(f.isNumber(p))?p:3;if(f.isArray(j)){r.push(&quot;[&quot;);for(l=0,n=j.length;l&lt;n;l=l+1){if(f.isObject(j[l])){r.push((p&gt;0)?f.dump(j[l],p-1):t);}else{r.push(j[l]);}r.push(q);}if(r.length&gt;1){r.pop();}r.push(&quot;]&quot;);}else{r.push(&quot;{&quot;);for(l in j){if(f.hasOwnProperty(j,l)){r.push(l+m);if
 (f.isObject(j[l])){r.push((p&gt;0)?f.dump(j[l],p-1):t);}else{r.push(j[l]);}r.push(q);}}if(r.length&gt;1){r.pop();}r.push(&quot;}&quot;);}return r.join(&quot;&quot;);},substitute:function(x,y,E,l){var D,C,B,G,t,u,F=[],p,z=x.length,A=&quot;dump&quot;,r=&quot; &quot;,q=&quot;{&quot;,m=&quot;}&quot;,n,w;for(;;){D=x.lastIndexOf(q,z);if(D&lt;0){break;}C=x.indexOf(m,D);if(D+1&gt;C){break;}p=x.substring(D+1,C);G=p;u=null;B=G.indexOf(r);if(B&gt;-1){u=G.substring(B+1);G=G.substring(0,B);}t=y[G];if(E){t=E(G,t,u);}if(f.isObject(t)){if(f.isArray(t)){t=f.dump(t,parseInt(u,10));}else{u=u||&quot;&quot;;n=u.indexOf(A);if(n&gt;-1){u=u.substring(4);}w=t.toString();if(w===i||n&gt;-1){t=f.dump(t,parseInt(u,10));}else{t=w;}}}else{if(!f.isString(t)&amp;&amp;!f.isNumber(t)){t=&quot;~-&quot;+F.length+&quot;-~&quot;;F[F.length]=p;}}x=x.substring(0,D)+t+x.substring(C+1);if(l===false){z=D-1;}}for(D=F.length-1;D&gt;=0;D=D-1){x=x.replace(new RegExp(&quot;~-&quot;+D+&quot;-~&quot;),&quot;{&quot;+F[D]+&quo
 t;}&quot;,&quot;g&quot;);}return x;},trim:function(j){try{return j.replace(/^\s+|\s+$/g,&quot;&quot;);}catch(k){return j;
+}},merge:function(){var n={},k=arguments,j=k.length,m;for(m=0;m&lt;j;m=m+1){f.augmentObject(n,k[m],true);}return n;},later:function(t,k,u,n,p){t=t||0;k=k||{};var l=u,s=n,q,j;if(f.isString(u)){l=k[u];}if(!l){throw new TypeError(&quot;method undefined&quot;);}if(!f.isUndefined(n)&amp;&amp;!f.isArray(s)){s=[n];}q=function(){l.apply(k,s||b);};j=(p)?setInterval(q,t):setTimeout(q,t);return{interval:p,cancel:function(){if(this.interval){clearInterval(j);}else{clearTimeout(j);}}};},isValue:function(j){return(f.isObject(j)||f.isString(j)||f.isNumber(j)||f.isBoolean(j));}};f.hasOwnProperty=(a.hasOwnProperty)?function(j,k){return j&amp;&amp;j.hasOwnProperty&amp;&amp;j.hasOwnProperty(k);}:function(j,k){return !f.isUndefined(j[k])&amp;&amp;j.constructor.prototype[k]!==j[k];};e.augmentObject(f,e,true);YAHOO.util.Lang=f;f.augment=f.augmentProto;YAHOO.augment=f.augmentProto;YAHOO.extend=f.extend;})();YAHOO.register(&quot;yahoo&quot;,YAHOO,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
 (function(){YAHOO.env._id_counter=YAHOO.env._id_counter||0;var e=YAHOO.util,k=YAHOO.lang,L=YAHOO.env.ua,a=YAHOO.lang.trim,B={},F={},m=/^t(?:able|d|h)$/i,w=/color$/i,j=window.document,v=j.documentElement,C=&quot;ownerDocument&quot;,M=&quot;defaultView&quot;,U=&quot;documentElement&quot;,S=&quot;compatMode&quot;,z=&quot;offsetLeft&quot;,o=&quot;offsetTop&quot;,T=&quot;offsetParent&quot;,x=&quot;parentNode&quot;,K=&quot;nodeType&quot;,c=&quot;tagName&quot;,n=&quot;scrollLeft&quot;,H=&quot;scrollTop&quot;,p=&quot;getBoundingClientRect&quot;,V=&quot;getComputedStyle&quot;,y=&quot;currentStyle&quot;,l=&quot;CSS1Compat&quot;,A=&quot;BackCompat&quot;,E=&quot;class&quot;,f=&quot;className&quot;,i=&quot;&quot;,b=&quot; &quot;,R=&quot;(?:^|\\s)&quot;,J=&quot;(?= |$)&quot;,t=&quot;g&quot;,O=&quot;position&quot;,D=&quot;fixed&quot;,u=&quot;relative&quot;,I=&quot;left&quot;,N=&quot;top&quot;,Q=&quot;medium&quot;,P=&quot;borderLeftWidth&quot;,q=&quot;borderTopWidth&quot;,d=L.opera,h=L.webk
 it,g=L.gecko,s=L.ie;e.Dom={CUSTOM_ATTRIBUTES:(!v.hasAttribute)?{&quot;for&quot;:&quot;htmlFor&quot;,&quot;class&quot;:f}:{&quot;htmlFor&quot;:&quot;for&quot;,&quot;className&quot;:E},DOT_ATTRIBUTES:{checked:true},get:function(aa){var ac,X,ab,Z,W,G,Y=null;if(aa){if(typeof aa==&quot;string&quot;||typeof aa==&quot;number&quot;){ac=aa+&quot;&quot;;aa=j.getElementById(aa);G=(aa)?aa.attributes:null;if(aa&amp;&amp;G&amp;&amp;G.id&amp;&amp;G.id.value===ac){return aa;}else{if(aa&amp;&amp;j.all){aa=null;X=j.all[ac];if(X&amp;&amp;X.length){for(Z=0,W=X.length;Z&lt;W;++Z){if(X[Z].id===ac){return X[Z];}}}}}}else{if(e.Element&amp;&amp;aa instanceof e.Element){aa=aa.get(&quot;element&quot;);}else{if(!aa.nodeType&amp;&amp;&quot;length&quot; in aa){ab=[];for(Z=0,W=aa.length;Z&lt;W;++Z){ab[ab.length]=e.Dom.get(aa[Z]);}aa=ab;}}}Y=aa;}return Y;},getComputedStyle:function(G,W){if(window[V]){return G[C][M][V](G,null)[W];}else{if(G[y]){return e.Dom.IE_ComputedStyle.get(G,W);}}},getStyle:function(G,
 W){return e.Dom.batch(G,e.Dom._getStyle,W);},_getStyle:function(){if(window[V]){return function(G,Y){Y=(Y===&quot;float&quot;)?Y=&quot;cssFloat&quot;:e.Dom._toCamel(Y);var X=G.style[Y],W;if(!X){W=G[C][M][V](G,null);if(W){X=W[Y];}}return X;};}else{if(v[y]){return function(G,Y){var X;switch(Y){case&quot;opacity&quot;:X=100;try{X=G.filters[&quot;DXImageTransform.Microsoft.Alpha&quot;].opacity;}catch(Z){try{X=G.filters(&quot;alpha&quot;).opacity;}catch(W){}}return X/100;case&quot;float&quot;:Y=&quot;styleFloat&quot;;default:Y=e.Dom._toCamel(Y);X=G[y]?G[y][Y]:null;return(G.style[Y]||X);}};}}}(),setStyle:function(G,W,X){e.Dom.batch(G,e.Dom._setStyle,{prop:W,val:X});},_setStyle:function(){if(!window.getComputedStyle&amp;&amp;j.documentElement.currentStyle){return function(W,G){var X=e.Dom._toCamel(G.prop),Y=G.val;if(W){switch(X){case&quot;opacity&quot;:if(Y===&quot;&quot;||Y===null||Y===1){W.style.removeAttribute(&quot;filter&quot;);}else{if(k.isString(W.style.filter)){W.style.filt
 er=&quot;alpha(opacity=&quot;+Y*100+&quot;)&quot;;if(!W[y]||!W[y].hasLayout){W.style.zoom=1;}}}break;case&quot;float&quot;:X=&quot;styleFloat&quot;;default:W.style[X]=Y;}}else{}};}else{return function(W,G){var X=e.Dom._toCamel(G.prop),Y=G.val;if(W){if(X==&quot;float&quot;){X=&quot;cssFloat&quot;;}W.style[X]=Y;}else{}};}}(),getXY:function(G){return e.Dom.batch(G,e.Dom._getXY);},_canPosition:function(G){return(e.Dom._getStyle(G,&quot;display&quot;)!==&quot;none&quot;&amp;&amp;e.Dom._inDoc(G));},_getXY:function(W){var X,G,Z,ab,Y,aa,ac=Math.round,ad=false;if(e.Dom._canPosition(W)){Z=W[p]();ab=W[C];X=e.Dom.getDocumentScrollLeft(ab);G=e.Dom.getDocumentScrollTop(ab);ad=[Z[I],Z[N]];if(Y||aa){ad[0]-=aa;ad[1]-=Y;}if((G||X)){ad[0]+=X;ad[1]+=G;}ad[0]=ac(ad[0]);ad[1]=ac(ad[1]);}else{}return ad;},getX:function(G){var W=function(X){return e.Dom.getXY(X)[0];};return e.Dom.batch(G,W,e.Dom,true);},getY:function(G){var W=function(X){return e.Dom.getXY(X)[1];};return e.Dom.batch(G,W,e.Dom,true)
 ;},setXY:function(G,X,W){e.Dom.batch(G,e.Dom._setXY,{pos:X,noRetry:W});},_setXY:function(G,Z){var aa=e.Dom._getStyle(G,O),Y=e.Dom.setStyle,ad=Z.pos,W=Z.noRetry,ab=[parseInt(e.Dom.getComputedStyle(G,I),10),parseInt(e.Dom.getComputedStyle(G,N),10)],ac,X;ac=e.Dom._getXY(G);if(!ad||ac===false){return false;}if(aa==&quot;static&quot;){aa=u;Y(G,O,aa);}if(isNaN(ab[0])){ab[0]=(aa==u)?0:G[z];}if(isNaN(ab[1])){ab[1]=(aa==u)?0:G[o];}if(ad[0]!==null){Y(G,I,ad[0]-ac[0]+ab[0]+&quot;px&quot;);}if(ad[1]!==null){Y(G,N,ad[1]-ac[1]+ab[1]+&quot;px&quot;);}if(!W){X=e.Dom._getXY(G);if((ad[0]!==null&amp;&amp;X[0]!=ad[0])||(ad[1]!==null&amp;&amp;X[1]!=ad[1])){e.Dom._setXY(G,{pos:ad,noRetry:true});}}},setX:function(W,G){e.Dom.setXY(W,[G,null]);},setY:function(G,W){e.Dom.setXY(G,[null,W]);},getRegion:function(G){var W=function(X){var Y=false;if(e.Dom._canPosition(X)){Y=e.Region.getRegion(X);}else{}return Y;};return e.Dom.batch(G,W,e.Dom,true);},getClientWidth:function(){return e.Dom.getViewportWidth(
 );},getClientHeight:function(){return e.Dom.getViewportHeight();},getElementsByClassName:function(ab,af,ac,ae,X,ad){af=af||&quot;*&quot;;ac=(ac)?e.Dom.get(ac):null||j;if(!ac){return[];}var W=[],G=ac.getElementsByTagName(af),Z=e.Dom.hasClass;for(var Y=0,aa=G.length;Y&lt;aa;++Y){if(Z(G[Y],ab)){W[W.length]=G[Y];}}if(ae){e.Dom.batch(W,ae,X,ad);}return W;},hasClass:function(W,G){return e.Dom.batch(W,e.Dom._hasClass,G);},_hasClass:function(X,W){var G=false,Y;if(X&amp;&amp;W){Y=e.Dom._getAttribute(X,f)||i;if(Y){Y=Y.replace(/\s+/g,b);}if(W.exec){G=W.test(Y);}else{G=W&amp;&amp;(b+Y+b).indexOf(b+W+b)&gt;-1;}}else{}return G;},addClass:function(W,G){return e.Dom.batch(W,e.Dom._addClass,G);},_addClass:function(X,W){var G=false,Y;if(X&amp;&amp;W){Y=e.Dom._getAttribute(X,f)||i;if(!e.Dom._hasClass(X,W)){e.Dom.setAttribute(X,f,a(Y+b+W));G=true;}}else{}return G;},removeClass:function(W,G){return e.Dom.batch(W,e.Dom._removeClass,G);},_removeClass:function(Y,X){var W=false,aa,Z,G;if(Y&amp;&amp;
 X){aa=e.Dom._getAttribute(Y,f)||i;e.Dom.setAttribute(Y,f,aa.replace(e.Dom._getClassRegex(X),i));Z=e.Dom._getAttribute(Y,f);if(aa!==Z){e.Dom.setAttribute(Y,f,a(Z));W=true;if(e.Dom._getAttribute(Y,f)===&quot;&quot;){G=(Y.hasAttribute&amp;&amp;Y.hasAttribute(E))?E:f;Y.removeAttribute(G);}}}else{}return W;},replaceClass:function(X,W,G){return e.Dom.batch(X,e.Dom._replaceClass,{from:W,to:G});},_replaceClass:function(Y,X){var W,ab,aa,G=false,Z;if(Y&amp;&amp;X){ab=X.from;aa=X.to;if(!aa){G=false;}else{if(!ab){G=e.Dom._addClass(Y,X.to);}else{if(ab!==aa){Z=e.Dom._getAttribute(Y,f)||i;W=(b+Z.replace(e.Dom._getClassRegex(ab),b+aa).replace(/\s+/g,b)).split(e.Dom._getClassRegex(aa));W.splice(1,0,b+aa);e.Dom.setAttribute(Y,f,a(W.join(i)));G=true;}}}}else{}return G;},generateId:function(G,X){X=X||&quot;yui-gen&quot;;var W=function(Y){if(Y&amp;&amp;Y.id){return Y.id;}var Z=X+YAHOO.env._id_counter++;
+if(Y){if(Y[C]&amp;&amp;Y[C].getElementById(Z)){return e.Dom.generateId(Y,Z+X);}Y.id=Z;}return Z;};return e.Dom.batch(G,W,e.Dom,true)||W.apply(e.Dom,arguments);},isAncestor:function(W,X){W=e.Dom.get(W);X=e.Dom.get(X);var G=false;if((W&amp;&amp;X)&amp;&amp;(W[K]&amp;&amp;X[K])){if(W.contains&amp;&amp;W!==X){G=W.contains(X);}else{if(W.compareDocumentPosition){G=!!(W.compareDocumentPosition(X)&amp;16);}}}else{}return G;},inDocument:function(G,W){return e.Dom._inDoc(e.Dom.get(G),W);},_inDoc:function(W,X){var G=false;if(W&amp;&amp;W[c]){X=X||W[C];G=e.Dom.isAncestor(X[U],W);}else{}return G;},getElementsBy:function(W,af,ab,ad,X,ac,ae){af=af||&quot;*&quot;;ab=(ab)?e.Dom.get(ab):null||j;var aa=(ae)?null:[],G;if(ab){G=ab.getElementsByTagName(af);for(var Y=0,Z=G.length;Y&lt;Z;++Y){if(W(G[Y])){if(ae){aa=G[Y];break;}else{aa[aa.length]=G[Y];}}}if(ad){e.Dom.batch(aa,ad,X,ac);}}return aa;},getElementBy:function(X,G,W){return e.Dom.getElementsBy(X,G,W,null,null,null,true);},batch:function(X,a
 b,aa,Z){var Y=[],W=(Z)?aa:null;X=(X&amp;&amp;(X[c]||X.item))?X:e.Dom.get(X);if(X&amp;&amp;ab){if(X[c]||X.length===undefined){return ab.call(W,X,aa);}for(var G=0;G&lt;X.length;++G){Y[Y.length]=ab.call(W||X[G],X[G],aa);}}else{return false;}return Y;},getDocumentHeight:function(){var W=(j[S]!=l||h)?j.body.scrollHeight:v.scrollHeight,G=Math.max(W,e.Dom.getViewportHeight());return G;},getDocumentWidth:function(){var W=(j[S]!=l||h)?j.body.scrollWidth:v.scrollWidth,G=Math.max(W,e.Dom.getViewportWidth());return G;},getViewportHeight:function(){var G=self.innerHeight,W=j[S];if((W||s)&amp;&amp;!d){G=(W==l)?v.clientHeight:j.body.clientHeight;}return G;},getViewportWidth:function(){var G=self.innerWidth,W=j[S];if(W||s){G=(W==l)?v.clientWidth:j.body.clientWidth;}return G;},getAncestorBy:function(G,W){while((G=G[x])){if(e.Dom._testElement(G,W)){return G;}}return null;},getAncestorByClassName:function(W,G){W=e.Dom.get(W);if(!W){return null;}var X=function(Y){return e.Dom.hasClass(Y,G);};re
 turn e.Dom.getAncestorBy(W,X);},getAncestorByTagName:function(W,G){W=e.Dom.get(W);if(!W){return null;}var X=function(Y){return Y[c]&amp;&amp;Y[c].toUpperCase()==G.toUpperCase();};return e.Dom.getAncestorBy(W,X);},getPreviousSiblingBy:function(G,W){while(G){G=G.previousSibling;if(e.Dom._testElement(G,W)){return G;}}return null;},getPreviousSibling:function(G){G=e.Dom.get(G);if(!G){return null;}return e.Dom.getPreviousSiblingBy(G);},getNextSiblingBy:function(G,W){while(G){G=G.nextSibling;if(e.Dom._testElement(G,W)){return G;}}return null;},getNextSibling:function(G){G=e.Dom.get(G);if(!G){return null;}return e.Dom.getNextSiblingBy(G);},getFirstChildBy:function(G,X){var W=(e.Dom._testElement(G.firstChild,X))?G.firstChild:null;return W||e.Dom.getNextSiblingBy(G.firstChild,X);},getFirstChild:function(G,W){G=e.Dom.get(G);if(!G){return null;}return e.Dom.getFirstChildBy(G);},getLastChildBy:function(G,X){if(!G){return null;}var W=(e.Dom._testElement(G.lastChild,X))?G.lastChild:null;r
 eturn W||e.Dom.getPreviousSiblingBy(G.lastChild,X);},getLastChild:function(G){G=e.Dom.get(G);return e.Dom.getLastChildBy(G);},getChildrenBy:function(W,Y){var X=e.Dom.getFirstChildBy(W,Y),G=X?[X]:[];e.Dom.getNextSiblingBy(X,function(Z){if(!Y||Y(Z)){G[G.length]=Z;}return false;});return G;},getChildren:function(G){G=e.Dom.get(G);if(!G){}return e.Dom.getChildrenBy(G);},getDocumentScrollLeft:function(G){G=G||j;return Math.max(G[U].scrollLeft,G.body.scrollLeft);},getDocumentScrollTop:function(G){G=G||j;return Math.max(G[U].scrollTop,G.body.scrollTop);},insertBefore:function(W,G){W=e.Dom.get(W);G=e.Dom.get(G);if(!W||!G||!G[x]){return null;}return G[x].insertBefore(W,G);},insertAfter:function(W,G){W=e.Dom.get(W);G=e.Dom.get(G);if(!W||!G||!G[x]){return null;}if(G.nextSibling){return G[x].insertBefore(W,G.nextSibling);}else{return G[x].appendChild(W);}},getClientRegion:function(){var X=e.Dom.getDocumentScrollTop(),W=e.Dom.getDocumentScrollLeft(),Y=e.Dom.getViewportWidth()+W,G=e.Dom.g
 etViewportHeight()+X;return new e.Region(X,Y,G,W);},setAttribute:function(W,G,X){e.Dom.batch(W,e.Dom._setAttribute,{attr:G,val:X});},_setAttribute:function(X,W){var G=e.Dom._toCamel(W.attr),Y=W.val;if(X&amp;&amp;X.setAttribute){if(e.Dom.DOT_ATTRIBUTES[G]&amp;&amp;X.tagName&amp;&amp;X.tagName!=&quot;BUTTON&quot;){X[G]=Y;}else{G=e.Dom.CUSTOM_ATTRIBUTES[G]||G;X.setAttribute(G,Y);}}else{}},getAttribute:function(W,G){return e.Dom.batch(W,e.Dom._getAttribute,G);},_getAttribute:function(W,G){var X;G=e.Dom.CUSTOM_ATTRIBUTES[G]||G;if(e.Dom.DOT_ATTRIBUTES[G]){X=W[G];}else{if(W&amp;&amp;&quot;getAttribute&quot; in W){if(/^(?:href|src)$/.test(G)){X=W.getAttribute(G,2);}else{X=W.getAttribute(G);}}else{}}return X;},_toCamel:function(W){var X=B;function G(Y,Z){return Z.toUpperCase();}return X[W]||(X[W]=W.indexOf(&quot;-&quot;)===-1?W:W.replace(/-([a-z])/gi,G));},_getClassRegex:function(W){var G;if(W!==undefined){if(W.exec){G=W;}else{G=F[W];if(!G){W=W.replace(e.Dom._patterns.CLASS_RE_TOKENS
 ,&quot;\\$1&quot;);W=W.replace(/\s+/g,b);G=F[W]=new RegExp(R+W+J,t);}}}return G;},_patterns:{ROOT_TAG:/^body|html$/i,CLASS_RE_TOKENS:/([\.\(\)\^\$\*\+\?\|\[\]\{\}\\])/g},_testElement:function(G,W){return G&amp;&amp;G[K]==1&amp;&amp;(!W||W(G));},_calcBorders:function(X,Y){var W=parseInt(e.Dom[V](X,q),10)||0,G=parseInt(e.Dom[V](X,P),10)||0;if(g){if(m.test(X[c])){W=0;G=0;}}Y[0]+=G;Y[1]+=W;return Y;}};var r=e.Dom[V];if(L.opera){e.Dom[V]=function(W,G){var X=r(W,G);if(w.test(G)){X=e.Dom.Color.toRGB(X);}return X;};}if(L.webkit){e.Dom[V]=function(W,G){var X=r(W,G);if(X===&quot;rgba(0, 0, 0, 0)&quot;){X=&quot;transparent&quot;;}return X;};}if(L.ie&amp;&amp;L.ie&gt;=8){e.Dom.DOT_ATTRIBUTES.type=true;}})();YAHOO.util.Region=function(d,e,a,c){this.top=d;this.y=d;this[1]=d;this.right=e;this.bottom=a;this.left=c;this.x=c;this[0]=c;this.width=this.right-this.left;this.height=this.bottom-this.top;};YAHOO.util.Region.prototype.contains=function(a){return(a.left&gt;=this.left&amp;&amp;a.right
 &lt;=this.right&amp;&amp;a.top&gt;=this.top&amp;&amp;a.bottom&lt;=this.bottom);};YAHOO.util.Region.prototype.getArea=function(){return((this.bottom-this.top)*(this.right-this.left));};YAHOO.util.Region.prototype.intersect=function(f){var d=Math.max(this.top,f.top),e=Math.min(this.right,f.right),a=Math.min(this.bottom,f.bottom),c=Math.max(this.left,f.left);
+if(a&gt;=d&amp;&amp;e&gt;=c){return new YAHOO.util.Region(d,e,a,c);}else{return null;}};YAHOO.util.Region.prototype.union=function(f){var d=Math.min(this.top,f.top),e=Math.max(this.right,f.right),a=Math.max(this.bottom,f.bottom),c=Math.min(this.left,f.left);return new YAHOO.util.Region(d,e,a,c);};YAHOO.util.Region.prototype.toString=function(){return(&quot;Region {&quot;+&quot;top: &quot;+this.top+&quot;, right: &quot;+this.right+&quot;, bottom: &quot;+this.bottom+&quot;, left: &quot;+this.left+&quot;, height: &quot;+this.height+&quot;, width: &quot;+this.width+&quot;}&quot;);};YAHOO.util.Region.getRegion=function(e){var g=YAHOO.util.Dom.getXY(e),d=g[1],f=g[0]+e.offsetWidth,a=g[1]+e.offsetHeight,c=g[0];return new YAHOO.util.Region(d,f,a,c);};YAHOO.util.Point=function(a,b){if(YAHOO.lang.isArray(a)){b=a[1];a=a[0];}YAHOO.util.Point.superclass.constructor.call(this,b,a,b,a);};YAHOO.extend(YAHOO.util.Point,YAHOO.util.Region);(function(){var b=YAHOO.util,a=&quot;clientTop&quot;,f=
 &quot;clientLeft&quot;,j=&quot;parentNode&quot;,k=&quot;right&quot;,w=&quot;hasLayout&quot;,i=&quot;px&quot;,u=&quot;opacity&quot;,l=&quot;auto&quot;,d=&quot;borderLeftWidth&quot;,g=&quot;borderTopWidth&quot;,p=&quot;borderRightWidth&quot;,v=&quot;borderBottomWidth&quot;,s=&quot;visible&quot;,q=&quot;transparent&quot;,n=&quot;height&quot;,e=&quot;width&quot;,h=&quot;style&quot;,t=&quot;currentStyle&quot;,r=/^width|height$/,o=/^(\d[.\d]*)+(em|ex|px|gd|rem|vw|vh|vm|ch|mm|cm|in|pt|pc|deg|rad|ms|s|hz|khz|%){1}?/i,m={get:function(x,z){var y=&quot;&quot;,A=x[t][z];if(z===u){y=b.Dom.getStyle(x,u);}else{if(!A||(A.indexOf&amp;&amp;A.indexOf(i)&gt;-1)){y=A;}else{if(b.Dom.IE_COMPUTED[z]){y=b.Dom.IE_COMPUTED[z](x,z);}else{if(o.test(A)){y=b.Dom.IE.ComputedStyle.getPixel(x,z);}else{y=A;}}}}return y;},getOffset:function(z,E){var B=z[t][E],x=E.charAt(0).toUpperCase()+E.substr(1),C=&quot;offset&quot;+x,y=&quot;pixel&quot;+x,A=&quot;&quot;,D;if(B==l){D=z[C];if(D===undefined){A=0;}A=D;if(r.tes
 t(E)){z[h][E]=D;if(z[C]&gt;D){A=D-(z[C]-D);}z[h][E]=l;}}else{if(!z[h][y]&amp;&amp;!z[h][E]){z[h][E]=B;}A=z[h][y];}return A+i;},getBorderWidth:function(x,z){var y=null;if(!x[t][w]){x[h].zoom=1;}switch(z){case g:y=x[a];break;case v:y=x.offsetHeight-x.clientHeight-x[a];break;case d:y=x[f];break;case p:y=x.offsetWidth-x.clientWidth-x[f];break;}return y+i;},getPixel:function(y,x){var A=null,B=y[t][k],z=y[t][x];y[h][k]=z;A=y[h].pixelRight;y[h][k]=B;return A+i;},getMargin:function(y,x){var z;if(y[t][x]==l){z=0+i;}else{z=b.Dom.IE.ComputedStyle.getPixel(y,x);}return z;},getVisibility:function(y,x){var z;while((z=y[t])&amp;&amp;z[x]==&quot;inherit&quot;){y=y[j];}return(z)?z[x]:s;},getColor:function(y,x){return b.Dom.Color.toRGB(y[t][x])||q;},getBorderColor:function(y,x){var z=y[t],A=z[x]||z.color;return b.Dom.Color.toRGB(b.Dom.Color.toHex(A));}},c={};c.top=c.right=c.bottom=c.left=c[e]=c[n]=m.getOffset;c.color=m.getColor;c[g]=c[p]=c[v]=c[d]=m.getBorderWidth;c.marginTop=c.marginRight=c.
 marginBottom=c.marginLeft=m.getMargin;c.visibility=m.getVisibility;c.borderColor=c.borderTopColor=c.borderRightColor=c.borderBottomColor=c.borderLeftColor=m.getBorderColor;b.Dom.IE_COMPUTED=c;b.Dom.IE_ComputedStyle=m;})();(function(){var c=&quot;toString&quot;,a=parseInt,b=RegExp,d=YAHOO.util;d.Dom.Color={KEYWORDS:{black:&quot;000&quot;,silver:&quot;c0c0c0&quot;,gray:&quot;808080&quot;,white:&quot;fff&quot;,maroon:&quot;800000&quot;,red:&quot;f00&quot;,purple:&quot;800080&quot;,fuchsia:&quot;f0f&quot;,green:&quot;008000&quot;,lime:&quot;0f0&quot;,olive:&quot;808000&quot;,yellow:&quot;ff0&quot;,navy:&quot;000080&quot;,blue:&quot;00f&quot;,teal:&quot;008080&quot;,aqua:&quot;0ff&quot;},re_RGB:/^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i,re_hex:/^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i,re_hex3:/([0-9A-F])/gi,toRGB:function(e){if(!d.Dom.Color.re_RGB.test(e)){e=d.Dom.Color.toHex(e);}if(d.Dom.Color.re_hex.exec(e)){e=&quot;rgb(&quot;+[a(b.$1,16),a(b.$2,16),a(b.$3,16)].joi
 n(&quot;, &quot;)+&quot;)&quot;;}return e;},toHex:function(f){f=d.Dom.Color.KEYWORDS[f]||f;if(d.Dom.Color.re_RGB.exec(f)){f=[Number(b.$1).toString(16),Number(b.$2).toString(16),Number(b.$3).toString(16)];for(var e=0;e&lt;f.length;e++){if(f[e].length&lt;2){f[e]=&quot;0&quot;+f[e];}}f=f.join(&quot;&quot;);}if(f.length&lt;6){f=f.replace(d.Dom.Color.re_hex3,&quot;$1$1&quot;);}if(f!==&quot;transparent&quot;&amp;&amp;f.indexOf(&quot;#&quot;)&lt;0){f=&quot;#&quot;+f;}return f.toUpperCase();}};}());YAHOO.register(&quot;dom&quot;,YAHOO.util.Dom,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});YAHOO.util.CustomEvent=function(d,c,b,a,e){this.type=d;this.scope=c||window;this.silent=b;this.fireOnce=e;this.fired=false;this.firedWith=null;this.signature=a||YAHOO.util.CustomEvent.LIST;this.subscribers=[];if(!this.silent){}var f=&quot;_YUICEOnSubscribe&quot;;if(d!==f){this.subscribeEvent=new YAHOO.util.CustomEvent(f,this,true);}this.lastError=null;};YAHOO.util.CustomEvent.LIST=0;YAHOO.uti
 l.CustomEvent.FLAT=1;YAHOO.util.CustomEvent.prototype={subscribe:function(b,c,d){if(!b){throw new Error(&quot;Invalid callback for subscriber to '&quot;+this.type+&quot;'&quot;);}if(this.subscribeEvent){this.subscribeEvent.fire(b,c,d);}var a=new YAHOO.util.Subscriber(b,c,d);if(this.fireOnce&amp;&amp;this.fired){this.notify(a,this.firedWith);}else{this.subscribers.push(a);}},unsubscribe:function(d,f){if(!d){return this.unsubscribeAll();}var e=false;for(var b=0,a=this.subscribers.length;b&lt;a;++b){var c=this.subscribers[b];if(c&amp;&amp;c.contains(d,f)){this._delete(b);e=true;}}return e;},fire:function(){this.lastError=null;var h=[],a=this.subscribers.length;var d=[].slice.call(arguments,0),c=true,f,b=false;if(this.fireOnce){if(this.fired){return true;}else{this.firedWith=d;}}this.fired=true;if(!a&amp;&amp;this.silent){return true;}if(!this.silent){}var e=this.subscribers.slice();for(f=0;f&lt;a;++f){var g=e[f];if(!g||!g.fn){b=true;}else{c=this.notify(g,d);if(false===c){if(!th
 is.silent){}break;}}}return(c!==false);},notify:function(g,c){var b,i=null,f=g.getScope(this.scope),a=YAHOO.util.Event.throwErrors;if(!this.silent){}if(this.signature==YAHOO.util.CustomEvent.FLAT){if(c.length&gt;0){i=c[0];}try{b=g.fn.call(f,i,g.obj);}catch(h){this.lastError=h;if(a){throw h;}}}else{try{b=g.fn.call(f,this.type,c,g.obj);}catch(d){this.lastError=d;if(a){throw d;}}}return b;},unsubscribeAll:function(){var a=this.subscribers.length,b;for(b=a-1;b&gt;-1;b--){this._delete(b);}this.subscribers=[];return a;},_delete:function(a){var b=this.subscribers[a];if(b){delete b.fn;delete b.obj;}this.subscribers.splice(a,1);},toString:function(){return&quot;CustomEvent: &quot;+&quot;'&quot;+this.type+&quot;', &quot;+&quot;context: &quot;+this.scope;}};YAHOO.util.Subscriber=function(a,b,c){this.fn=a;this.obj=YAHOO.lang.isUndefined(b)?null:b;this.overrideContext=c;};YAHOO.util.Subscriber.prototype.getScope=function(a){if(this.overrideContext){if(this.overrideContext===true){return 
 this.obj;}else{return this.overrideContext;}}return a;};YAHOO.util.Subscriber.prototype.contains=function(a,b){if(b){return(this.fn==a&amp;&amp;this.obj==b);}else{return(this.fn==a);}};YAHOO.util.Subscriber.prototype.toString=function(){return&quot;Subscriber { obj: &quot;+this.obj+&quot;, overrideContext: &quot;+(this.overrideContext||&quot;no&quot;)+&quot; }&quot;;};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var g=false,h=[],j=[],a=0,e=[],b=0,c={63232:38,63233:40,63234:37,63235:39,63276:33,63277:34,25:9},d=YAHOO.env.ua.ie,f=&quot;focusin&quot;,i=&quot;focusout&quot;;return{POLL_RETRYS:500,POLL_INTERVAL:40,EL:0,TYPE:1,FN:2,WFN:3,UNLOAD_OBJ:3,ADJ_SCOPE:4,OBJ:5,OVERRIDE:6,CAPTURE:7,lastError:null,isSafari:YAHOO.env.ua.webkit,webkit:YAHOO.env.ua.webkit,isIE:d,_interval:null,_dri:null,_specialTypes:{focusin:(d?&quot;focusin&quot;:&quot;focus&quot;),focusout:(d?&quot;focusout&quot;:&quot;blur&quot;)},DOMReady:false,throwErrors:false,startInterval:function(){if(!this._inte
 rval){this._interval=YAHOO.lang.later(this.POLL_INTERVAL,this,this._tryPreloadAttach,null,true);}},onAvailable:function(q,m,o,p,n){var k=(YAHOO.lang.isString(q))?[q]:q;for(var l=0;l&lt;k.length;l=l+1){e.push({id:k[l],fn:m,obj:o,overrideContext:p,checkReady:n});}a=this.POLL_RETRYS;this.startInterval();},onContentReady:function(n,k,l,m){this.onAvailable(n,k,l,m,true);},onDOMReady:function(){this.DOMReadyEvent.subscribe.apply(this.DOMReadyEvent,arguments);},_addListener:function(m,k,v,p,t,y){if(!v||!v.call){return false;}if(this._isValidCollection(m)){var w=true;for(var q=0,s=m.length;q&lt;s;++q){w=this.on(m[q],k,v,p,t)&amp;&amp;w;}return w;}else{if(YAHOO.lang.isString(m)){var o=this.getEl(m);if(o){m=o;}else{this.onAvailable(m,function(){YAHOO.util.Event._addListener(m,k,v,p,t,y);});return true;}}}if(!m){return false;}if(&quot;unload&quot;==k&amp;&amp;p!==this){j[j.length]=[m,k,v,p,t];return true;}var l=m;if(t){if(t===true){l=p;}else{l=t;}}var n=function(z){return v.call(l,YAHO
 O.util.Event.getEvent(z,m),p);};var x=[m,k,v,n,l,p,t,y];var r=h.length;h[r]=x;try{this._simpleAdd(m,k,n,y);}catch(u){this.lastError=u;this.removeListener(m,k,v);return false;}return true;},_getType:function(k){return this._specialTypes[k]||k;},addListener:function(m,p,l,n,o){var k=((p==f||p==i)&amp;&amp;!YAHOO.env.ua.ie)?true:false;return this._addListener(m,this._getType(p),l,n,o,k);},addFocusListener:function(l,k,m,n){return this.on(l,f,k,m,n);},removeFocusListener:function(l,k){return this.removeListener(l,f,k);},addBlurListener:function(l,k,m,n){return this.on(l,i,k,m,n);},removeBlurListener:function(l,k){return this.removeListener(l,i,k);},removeListener:function(l,k,r){var m,p,u;k=this._getType(k);if(typeof l==&quot;string&quot;){l=this.getEl(l);}else{if(this._isValidCollection(l)){var s=true;for(m=l.length-1;m&gt;-1;m--){s=(this.removeListener(l[m],k,r)&amp;&amp;s);}return s;}}if(!r||!r.call){return this.purgeElement(l,false,k);}if(&quot;unload&quot;==k){for(m=j.lengt
 h-1;m&gt;-1;m--){u=j[m];if(u&amp;&amp;u[0]==l&amp;&amp;u[1]==k&amp;&amp;u[2]==r){j.splice(m,1);return true;}}return false;}var n=null;var o=arguments[3];if(&quot;undefined&quot;===typeof o){o=this._getCacheIndex(h,l,k,r);}if(o&gt;=0){n=h[o];}if(!l||!n){return false;}var t=n[this.CAPTURE]===true?true:false;try{this._simpleRemove(l,k,n[this.WFN],t);}catch(q){this.lastError=q;return false;}delete h[o][this.WFN];delete h[o][this.FN];h.splice(o,1);return true;},getTarget:function(m,l){var k=m.target||m.srcElement;return this.resolveTextNode(k);},resolveTextNode:function(l){try{if(l&amp;&amp;3==l.nodeType){return l.parentNode;}}catch(k){return null;}return l;},getPageX:function(l){var k=l.pageX;if(!k&amp;&amp;0!==k){k=l.clientX||0;if(this.isIE){k+=this._getScrollLeft();}}return k;},getPageY:function(k){var l=k.pageY;if(!l&amp;&amp;0!==l){l=k.clientY||0;if(this.isIE){l+=this._getScrollTop();}}return l;},getXY:function(k){return[this.getPageX(k),this.getPageY(k)];},getRelatedTarget:
 function(l){var k=l.relatedTarget;
+if(!k){if(l.type==&quot;mouseout&quot;){k=l.toElement;}else{if(l.type==&quot;mouseover&quot;){k=l.fromElement;}}}return this.resolveTextNode(k);},getTime:function(m){if(!m.time){var l=new Date().getTime();try{m.time=l;}catch(k){this.lastError=k;return l;}}return m.time;},stopEvent:function(k){this.stopPropagation(k);this.preventDefault(k);},stopPropagation:function(k){if(k.stopPropagation){k.stopPropagation();}else{k.cancelBubble=true;}},preventDefault:function(k){if(k.preventDefault){k.preventDefault();}else{k.returnValue=false;}},getEvent:function(m,k){var l=m||window.event;if(!l){var n=this.getEvent.caller;while(n){l=n.arguments[0];if(l&amp;&amp;Event==l.constructor){break;}n=n.caller;}}return l;},getCharCode:function(l){var k=l.keyCode||l.charCode||0;if(YAHOO.env.ua.webkit&amp;&amp;(k in c)){k=c[k];}return k;},_getCacheIndex:function(n,q,r,p){for(var o=0,m=n.length;o&lt;m;o=o+1){var k=n[o];if(k&amp;&amp;k[this.FN]==p&amp;&amp;k[this.EL]==q&amp;&amp;k[this.TYPE]==r){retur
 n o;}}return -1;},generateId:function(k){var l=k.id;if(!l){l=&quot;yuievtautoid-&quot;+b;++b;k.id=l;}return l;},_isValidCollection:function(l){try{return(l&amp;&amp;typeof l!==&quot;string&quot;&amp;&amp;l.length&amp;&amp;!l.tagName&amp;&amp;!l.alert&amp;&amp;typeof l[0]!==&quot;undefined&quot;);}catch(k){return false;}},elCache:{},getEl:function(k){return(typeof k===&quot;string&quot;)?document.getElementById(k):k;},clearCache:function(){},DOMReadyEvent:new YAHOO.util.CustomEvent(&quot;DOMReady&quot;,YAHOO,0,0,1),_load:function(l){if(!g){g=true;var k=YAHOO.util.Event;k._ready();k._tryPreloadAttach();}},_ready:function(l){var k=YAHOO.util.Event;if(!k.DOMReady){k.DOMReady=true;k.DOMReadyEvent.fire();k._simpleRemove(document,&quot;DOMContentLoaded&quot;,k._ready);}},_tryPreloadAttach:function(){if(e.length===0){a=0;if(this._interval){this._interval.cancel();this._interval=null;}return;}if(this.locked){return;}if(this.isIE){if(!this.DOMReady){this.startInterval();return;}}this.
 locked=true;var q=!g;if(!q){q=(a&gt;0&amp;&amp;e.length&gt;0);}var p=[];var r=function(t,u){var s=t;if(u.overrideContext){if(u.overrideContext===true){s=u.obj;}else{s=u.overrideContext;}}u.fn.call(s,u.obj);};var l,k,o,n,m=[];for(l=0,k=e.length;l&lt;k;l=l+1){o=e[l];if(o){n=this.getEl(o.id);if(n){if(o.checkReady){if(g||n.nextSibling||!q){m.push(o);e[l]=null;}}else{r(n,o);e[l]=null;}}else{p.push(o);}}}for(l=0,k=m.length;l&lt;k;l=l+1){o=m[l];r(this.getEl(o.id),o);}a--;if(q){for(l=e.length-1;l&gt;-1;l--){o=e[l];if(!o||!o.id){e.splice(l,1);}}this.startInterval();}else{if(this._interval){this._interval.cancel();this._interval=null;}}this.locked=false;},purgeElement:function(p,q,s){var n=(YAHOO.lang.isString(p))?this.getEl(p):p;var r=this.getListeners(n,s),o,k;if(r){for(o=r.length-1;o&gt;-1;o--){var m=r[o];this.removeListener(n,m.type,m.fn);}}if(q&amp;&amp;n&amp;&amp;n.childNodes){for(o=0,k=n.childNodes.length;o&lt;k;++o){this.purgeElement(n.childNodes[o],q,s);}}},getListeners:funct
 ion(n,k){var q=[],m;if(!k){m=[h,j];}else{if(k===&quot;unload&quot;){m=[j];}else{k=this._getType(k);m=[h];}}var s=(YAHOO.lang.isString(n))?this.getEl(n):n;for(var p=0;p&lt;m.length;p=p+1){var u=m[p];if(u){for(var r=0,t=u.length;r&lt;t;++r){var o=u[r];if(o&amp;&amp;o[this.EL]===s&amp;&amp;(!k||k===o[this.TYPE])){q.push({type:o[this.TYPE],fn:o[this.FN],obj:o[this.OBJ],adjust:o[this.OVERRIDE],scope:o[this.ADJ_SCOPE],index:r});}}}}return(q.length)?q:null;},_unload:function(s){var m=YAHOO.util.Event,p,o,n,r,q,t=j.slice(),k;for(p=0,r=j.length;p&lt;r;++p){n=t[p];if(n){try{k=window;if(n[m.ADJ_SCOPE]){if(n[m.ADJ_SCOPE]===true){k=n[m.UNLOAD_OBJ];}else{k=n[m.ADJ_SCOPE];}}n[m.FN].call(k,m.getEvent(s,n[m.EL]),n[m.UNLOAD_OBJ]);}catch(w){}t[p]=null;}}n=null;k=null;j=null;if(h){for(o=h.length-1;o&gt;-1;o--){n=h[o];if(n){try{m.removeListener(n[m.EL],n[m.TYPE],n[m.FN],o);}catch(v){}}}n=null;}try{m._simpleRemove(window,&quot;unload&quot;,m._unload);m._simpleRemove(window,&quot;load&quot;,m._loa
 d);}catch(u){}},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScroll:function(){var k=document.documentElement,l=document.body;if(k&amp;&amp;(k.scrollTop||k.scrollLeft)){return[k.scrollTop,k.scrollLeft];}else{if(l){return[l.scrollTop,l.scrollLeft];}else{return[0,0];}}},regCE:function(){},_simpleAdd:function(){if(window.addEventListener){return function(m,n,l,k){m.addEventListener(n,l,(k));};}else{if(window.attachEvent){return function(m,n,l,k){m.attachEvent(&quot;on&quot;+n,l);};}else{return function(){};}}}(),_simpleRemove:function(){if(window.removeEventListener){return function(m,n,l,k){m.removeEventListener(n,l,(k));};}else{if(window.detachEvent){return function(l,m,k){l.detachEvent(&quot;on&quot;+m,k);};}else{return function(){};}}}()};}();(function(){var a=YAHOO.util.Event;a.on=a.addListener;a.onFocus=a.addFocusListener;a.onBlur=a.addBlurListener;
+/*! DOMReady: based on work by: Dean Edwards/John Resig/Matthias Miller/Diego Perini */
+if(a.isIE){if(self!==self.top){document.onreadystatechange=function(){if(document.readyState==&quot;complete&quot;){document.onreadystatechange=null;a._ready();}};}else{YAHOO.util.Event.onDOMReady(YAHOO.util.Event._tryPreloadAttach,YAHOO.util.Event,true);var b=document.createElement(&quot;p&quot;);a._dri=setInterval(function(){try{b.doScroll(&quot;left&quot;);clearInterval(a._dri);a._dri=null;a._ready();b=null;}catch(c){}},a.POLL_INTERVAL);}}else{if(a.webkit&amp;&amp;a.webkit&lt;525){a._dri=setInterval(function(){var c=document.readyState;if(&quot;loaded&quot;==c||&quot;complete&quot;==c){clearInterval(a._dri);a._dri=null;a._ready();}},a.POLL_INTERVAL);}else{a._simpleAdd(document,&quot;DOMContentLoaded&quot;,a._ready);}}a._simpleAdd(window,&quot;load&quot;,a._load);a._simpleAdd(window,&quot;unload&quot;,a._unload);a._tryPreloadAttach();})();}YAHOO.util.EventProvider=function(){};YAHOO.util.EventProvider.prototype={__yui_events:null,__yui_subscribers:null,subscribe:function(a
 ,c,f,e){this.__yui_events=this.__yui_events||{};var d=this.__yui_events[a];if(d){d.subscribe(c,f,e);}else{this.__yui_subscribers=this.__yui_subscribers||{};var b=this.__yui_subscribers;if(!b[a]){b[a]=[];}b[a].push({fn:c,obj:f,overrideContext:e});}},unsubscribe:function(c,e,g){this.__yui_events=this.__yui_events||{};var a=this.__yui_events;if(c){var f=a[c];if(f){return f.unsubscribe(e,g);}}else{var b=true;for(var d in a){if(YAHOO.lang.hasOwnProperty(a,d)){b=b&amp;&amp;a[d].unsubscribe(e,g);
+}}return b;}return false;},unsubscribeAll:function(a){return this.unsubscribe(a);},createEvent:function(b,g){this.__yui_events=this.__yui_events||{};var e=g||{},d=this.__yui_events,f;if(d[b]){}else{f=new YAHOO.util.CustomEvent(b,e.scope||this,e.silent,YAHOO.util.CustomEvent.FLAT,e.fireOnce);d[b]=f;if(e.onSubscribeCallback){f.subscribeEvent.subscribe(e.onSubscribeCallback);}this.__yui_subscribers=this.__yui_subscribers||{};var a=this.__yui_subscribers[b];if(a){for(var c=0;c&lt;a.length;++c){f.subscribe(a[c].fn,a[c].obj,a[c].overrideContext);}}}return d[b];},fireEvent:function(b){this.__yui_events=this.__yui_events||{};var d=this.__yui_events[b];if(!d){return null;}var a=[];for(var c=1;c&lt;arguments.length;++c){a.push(arguments[c]);}return d.fire.apply(d,a);},hasEvent:function(a){if(this.__yui_events){if(this.__yui_events[a]){return true;}}return false;}};(function(){var a=YAHOO.util.Event,c=YAHOO.lang;YAHOO.util.KeyListener=function(d,i,e,f){if(!d){}else{if(!i){}else{if(!e){
 }}}if(!f){f=YAHOO.util.KeyListener.KEYDOWN;}var g=new YAHOO.util.CustomEvent(&quot;keyPressed&quot;);this.enabledEvent=new YAHOO.util.CustomEvent(&quot;enabled&quot;);this.disabledEvent=new YAHOO.util.CustomEvent(&quot;disabled&quot;);if(c.isString(d)){d=document.getElementById(d);}if(c.isFunction(e)){g.subscribe(e);}else{g.subscribe(e.fn,e.scope,e.correctScope);}function h(o,n){if(!i.shift){i.shift=false;}if(!i.alt){i.alt=false;}if(!i.ctrl){i.ctrl=false;}if(o.shiftKey==i.shift&amp;&amp;o.altKey==i.alt&amp;&amp;o.ctrlKey==i.ctrl){var j,m=i.keys,l;if(YAHOO.lang.isArray(m)){for(var k=0;k&lt;m.length;k++){j=m[k];l=a.getCharCode(o);if(j==l){g.fire(l,o);break;}}}else{l=a.getCharCode(o);if(m==l){g.fire(l,o);}}}}this.enable=function(){if(!this.enabled){a.on(d,f,h);this.enabledEvent.fire(i);}this.enabled=true;};this.disable=function(){if(this.enabled){a.removeListener(d,f,h);this.disabledEvent.fire(i);}this.enabled=false;};this.toString=function(){return&quot;KeyListener [&quot;+i.k
 eys+&quot;] &quot;+d.tagName+(d.id?&quot;[&quot;+d.id+&quot;]&quot;:&quot;&quot;);};};var b=YAHOO.util.KeyListener;b.KEYDOWN=&quot;keydown&quot;;b.KEYUP=&quot;keyup&quot;;b.KEY={ALT:18,BACK_SPACE:8,CAPS_LOCK:20,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,META:224,NUM_LOCK:144,PAGE_DOWN:34,PAGE_UP:33,PAUSE:19,PRINTSCREEN:44,RIGHT:39,SCROLL_LOCK:145,SHIFT:16,SPACE:32,TAB:9,UP:38};})();YAHOO.register(&quot;event&quot;,YAHOO.util.Event,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});YAHOO.register(&quot;yahoo-dom-event&quot;, YAHOO, {version: &quot;2.9.0&quot;, build: &quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiyahoodomeventjs"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/js/yui/yahoo-dom-event.js (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/yahoo-dom-event.js        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/js/yui/yahoo-dom-event.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,10 +0,0 @@
</span><del>-/*
-Copyright (c) 2007, Yahoo! Inc. All rights reserved.
-Code licensed under the BSD License:
-http://developer.yahoo.net/yui/license.txt
-version: 2.3.1
-*/
-if(typeof YAHOO==&quot;undefined&quot;){var YAHOO={};}YAHOO.namespace=function(){var A=arguments,E=null,C,B,D;for(C=0;C&lt;A.length;C=C+1){D=A[C].split(&quot;.&quot;);E=YAHOO;for(B=(D[0]==&quot;YAHOO&quot;)?1:0;B&lt;D.length;B=B+1){E[D[B]]=E[D[B]]||{};E=E[D[B]];}}return E;};YAHOO.log=function(D,A,C){var B=YAHOO.widget.Logger;if(B&amp;&amp;B.log){return B.log(D,A,C);}else{return false;}};YAHOO.register=function(A,E,D){var I=YAHOO.env.modules;if(!I[A]){I[A]={versions:[],builds:[]};}var B=I[A],H=D.version,G=D.build,F=YAHOO.env.listeners;B.name=A;B.version=H;B.build=G;B.versions.push(H);B.builds.push(G);B.mainClass=E;for(var C=0;C&lt;F.length;C=C+1){F[C](B);}if(E){E.VERSION=H;E.BUILD=G;}else{YAHOO.log(&quot;mainClass is undefined for module &quot;+A,&quot;warn&quot;);}};YAHOO.env=YAHOO.env||{modules:[],listeners:[]};YAHOO.env.getVersion=function(A){return YAHOO.env.modules[A]||null;};YAHOO.env.ua=function(){var C={ie:0,opera:0,gecko:0,webkit:0};var B=navigator.userAgent,A;if((/K
 HTML/).test(B)){C.webkit=1;}A=B.match(/AppleWebKit\/([^\s]*)/);if(A&amp;&amp;A[1]){C.webkit=parseFloat(A[1]);}if(!C.webkit){A=B.match(/Opera[\s\/]([^\s]*)/);if(A&amp;&amp;A[1]){C.opera=parseFloat(A[1]);}else{A=B.match(/MSIE\s([^;]*)/);if(A&amp;&amp;A[1]){C.ie=parseFloat(A[1]);}else{A=B.match(/Gecko\/([^\s]*)/);if(A){C.gecko=1;A=B.match(/rv:([^\s\)]*)/);if(A&amp;&amp;A[1]){C.gecko=parseFloat(A[1]);}}}}}return C;}();(function(){YAHOO.namespace(&quot;util&quot;,&quot;widget&quot;,&quot;example&quot;);if(&quot;undefined&quot;!==typeof YAHOO_config){var B=YAHOO_config.listener,A=YAHOO.env.listeners,D=true,C;if(B){for(C=0;C&lt;A.length;C=C+1){if(A[C]==B){D=false;break;}}if(D){A.push(B);}}}})();YAHOO.lang={isArray:function(B){if(B){var A=YAHOO.lang;return A.isNumber(B.length)&amp;&amp;A.isFunction(B.splice)&amp;&amp;!A.hasOwnProperty(B.length);}return false;},isBoolean:function(A){return typeof A===&quot;boolean&quot;;},isFunction:function(A){return typeof A===&quot;function&quot;;
 },isNull:function(A){return A===null;},isNumber:function(A){return typeof A===&quot;number&quot;&amp;&amp;isFinite(A);},isObject:function(A){return(A&amp;&amp;(typeof A===&quot;object&quot;||YAHOO.lang.isFunction(A)))||false;},isString:function(A){return typeof A===&quot;string&quot;;},isUndefined:function(A){return typeof A===&quot;undefined&quot;;},hasOwnProperty:function(A,B){if(Object.prototype.hasOwnProperty){return A.hasOwnProperty(B);}return !YAHOO.lang.isUndefined(A[B])&amp;&amp;A.constructor.prototype[B]!==A[B];},_IEEnumFix:function(C,B){if(YAHOO.env.ua.ie){var E=[&quot;toString&quot;,&quot;valueOf&quot;],A;for(A=0;A&lt;E.length;A=A+1){var F=E[A],D=B[F];if(YAHOO.lang.isFunction(D)&amp;&amp;D!=Object.prototype[F]){C[F]=D;}}}},extend:function(D,E,C){if(!E||!D){throw new Error(&quot;YAHOO.lang.extend failed, please check that all dependencies are included.&quot;);}var B=function(){};B.prototype=E.prototype;D.prototype=new B();D.prototype.constructor=D;D.superclass=E.pr
 ototype;if(E.prototype.constructor==Object.prototype.constructor){E.prototype.constructor=E;}if(C){for(var A in C){D.prototype[A]=C[A];}YAHOO.lang._IEEnumFix(D.prototype,C);}},augmentObject:function(E,D){if(!D||!E){throw new Error(&quot;Absorb failed, verify dependencies.&quot;);}var A=arguments,C,F,B=A[2];if(B&amp;&amp;B!==true){for(C=2;C&lt;A.length;C=C+1){E[A[C]]=D[A[C]];}}else{for(F in D){if(B||!E[F]){E[F]=D[F];}}YAHOO.lang._IEEnumFix(E,D);}},augmentProto:function(D,C){if(!C||!D){throw new Error(&quot;Augment failed, verify dependencies.&quot;);}var A=[D.prototype,C.prototype];for(var B=2;B&lt;arguments.length;B=B+1){A.push(arguments[B]);}YAHOO.lang.augmentObject.apply(this,A);},dump:function(A,G){var C=YAHOO.lang,D,F,I=[],J=&quot;{...}&quot;,B=&quot;f(){...}&quot;,H=&quot;, &quot;,E=&quot; =&gt; &quot;;if(!C.isObject(A)){return A+&quot;&quot;;}else{if(A instanceof Date||(&quot;nodeType&quot; in A&amp;&amp;&quot;tagName&quot; in A)){return A;}else{if(C.isFunction(A)){ret
 urn B;}}}G=(C.isNumber(G))?G:3;if(C.isArray(A)){I.push(&quot;[&quot;);for(D=0,F=A.length;D&lt;F;D=D+1){if(C.isObject(A[D])){I.push((G&gt;0)?C.dump(A[D],G-1):J);}else{I.push(A[D]);}I.push(H);}if(I.length&gt;1){I.pop();}I.push(&quot;]&quot;);}else{I.push(&quot;{&quot;);for(D in A){if(C.hasOwnProperty(A,D)){I.push(D+E);if(C.isObject(A[D])){I.push((G&gt;0)?C.dump(A[D],G-1):J);}else{I.push(A[D]);}I.push(H);}}if(I.length&gt;1){I.pop();}I.push(&quot;}&quot;);}return I.join(&quot;&quot;);},substitute:function(Q,B,J){var G,F,E,M,N,P,D=YAHOO.lang,L=[],C,H=&quot;dump&quot;,K=&quot; &quot;,A=&quot;{&quot;,O=&quot;}&quot;;for(;;){G=Q.lastIndexOf(A);if(G&lt;0){break;}F=Q.indexOf(O,G);if(G+1&gt;=F){break;}C=Q.substring(G+1,F);M=C;P=null;E=M.indexOf(K);if(E&gt;-1){P=M.substring(E+1);M=M.substring(0,E);}N=B[M];if(J){N=J(M,N,P);}if(D.isObject(N)){if(D.isArray(N)){N=D.dump(N,parseInt(P,10));}else{P=P||&quot;&quot;;var I=P.indexOf(H);if(I&gt;-1){P=P.substring(4);}if(N.toString===Object.prototyp
 e.toString||I&gt;-1){N=D.dump(N,parseInt(P,10));}else{N=N.toString();}}}else{if(!D.isString(N)&amp;&amp;!D.isNumber(N)){N=&quot;~-&quot;+L.length+&quot;-~&quot;;L[L.length]=C;}}Q=Q.substring(0,G)+N+Q.substring(F+1);}for(G=L.length-1;G&gt;=0;G=G-1){Q=Q.replace(new RegExp(&quot;~-&quot;+G+&quot;-~&quot;),&quot;{&quot;+L[G]+&quot;}&quot;,&quot;g&quot;);}return Q;},trim:function(A){try{return A.replace(/^\s+|\s+$/g,&quot;&quot;);}catch(B){return A;}},merge:function(){var C={},A=arguments,B;for(B=0;B&lt;A.length;B=B+1){YAHOO.lang.augmentObject(C,A[B],true);}return C;},isValue:function(B){var A=YAHOO.lang;return(A.isObject(B)||A.isString(B)||A.isNumber(B)||A.isBoolean(B));}};YAHOO.util.Lang=YAHOO.lang;YAHOO.lang.augment=YAHOO.lang.augmentProto;YAHOO.augment=YAHOO.lang.augmentProto;YAHOO.extend=YAHOO.lang.extend;YAHOO.register(&quot;yahoo&quot;,YAHOO,{version:&quot;2.3.1&quot;,build:&quot;541&quot;});(function(){var B=YAHOO.util,K,I,H=0,J={},F={};var C=YAHOO.env.ua.opera,L=YAHOO.en
 v.ua.webkit,A=YAHOO.env.ua.gecko,G=YAHOO.env.ua.ie;var E={HYPHEN:/(-[a-z])/i,ROOT_TAG:/^body|html$/i};var M=function(O){if(!E.HYPHEN.test(O)){return O;}if(J[O]){return J[O];}var P=O;while(E.HYPHEN.exec(P)){P=P.replace(RegExp.$1,RegExp.$1.substr(1).toUpperCase());}J[O]=P;return P;};var N=function(P){var O=F[P];if(!O){O=new RegExp(&quot;(?:^|\\s+)&quot;+P+&quot;(?:\\s+|$)&quot;);F[P]=O;}return O;};if(document.defaultView&amp;&amp;document.defaultView.getComputedStyle){K=function(O,R){var Q=null;if(R==&quot;float&quot;){R=&quot;cssFloat&quot;;}var P=document.defaultView.getComputedStyle(O,&quot;&quot;);if(P){Q=P[M(R)];}return O.style[R]||Q;};}else{if(document.documentElement.currentStyle&amp;&amp;G){K=function(O,Q){switch(M(Q)){case&quot;opacity&quot;:var S=100;try{S=O.filters[&quot;DXImageTransform.Microsoft.Alpha&quot;].opacity;}catch(R){try{S=O.filters(&quot;alpha&quot;).opacity;}catch(R){}}return S/100;case&quot;float&quot;:Q=&quot;styleFloat&quot;;default:var P=O.currentSt
 yle?O.currentStyle[Q]:null;return(O.style[Q]||P);}};}else{K=function(O,P){return O.style[P];};}}if(G){I=function(O,P,Q){switch(P){case&quot;opacity&quot;:if(YAHOO.lang.isString(O.style.filter)){O.style.filter=&quot;alpha(opacity=&quot;+Q*100+&quot;)&quot;;if(!O.currentStyle||!O.currentStyle.hasLayout){O.style.zoom=1;}}break;case&quot;float&quot;:P=&quot;styleFloat&quot;;default:O.style[P]=Q;}};}else{I=function(O,P,Q){if(P==&quot;float&quot;){P=&quot;cssFloat&quot;;}O.style[P]=Q;};}var D=function(O,P){return O&amp;&amp;O.nodeType==1&amp;&amp;(!P||P(O));};YAHOO.util.Dom={get:function(Q){if(Q&amp;&amp;(Q.tagName||Q.item)){return Q;}if(YAHOO.lang.isString(Q)||!Q){return document.getElementById(Q);}if(Q.length!==undefined){var R=[];for(var P=0,O=Q.length;P&lt;O;++P){R[R.length]=B.Dom.get(Q[P]);}return R;}return Q;},getStyle:function(O,Q){Q=M(Q);var P=function(R){return K(R,Q);};return B.Dom.batch(O,P,B.Dom,true);},setStyle:function(O,Q,R){Q=M(Q);var P=function(S){I(S,Q,R);};B.Dom
 .batch(O,P,B.Dom,true);},getXY:function(O){var P=function(R){if((R.parentNode===null||R.offsetParent===null||this.getStyle(R,&quot;display&quot;)==&quot;none&quot;)&amp;&amp;R!=document.body){return false;}var Q=null;var V=[];var S;var T=R.ownerDocument;if(R.getBoundingClientRect){S=R.getBoundingClientRect();return[S.left+B.Dom.getDocumentScrollLeft(R.ownerDocument),S.top+B.Dom.getDocumentScrollTop(R.ownerDocument)];}else{V=[R.offsetLeft,R.offsetTop];Q=R.offsetParent;var U=this.getStyle(R,&quot;position&quot;)==&quot;absolute&quot;;if(Q!=R){while(Q){V[0]+=Q.offsetLeft;V[1]+=Q.offsetTop;if(L&amp;&amp;!U&amp;&amp;this.getStyle(Q,&quot;position&quot;)==&quot;absolute&quot;){U=true;}Q=Q.offsetParent;}}if(L&amp;&amp;U){V[0]-=R.ownerDocument.body.offsetLeft;V[1]-=R.ownerDocument.body.offsetTop;}}Q=R.parentNode;while(Q.tagName&amp;&amp;!E.ROOT_TAG.test(Q.tagName)){if(B.Dom.getStyle(Q,&quot;display&quot;).search(/^inline|table-row.*$/i)){V[0]-=Q.scrollLeft;V[1]-=Q.scrollTop;}Q=Q.par
 entNode;}return V;};return B.Dom.batch(O,P,B.Dom,true);},getX:function(O){var P=function(Q){return B.Dom.getXY(Q)[0];};return B.Dom.batch(O,P,B.Dom,true);},getY:function(O){var P=function(Q){return B.Dom.getXY(Q)[1];};return B.Dom.batch(O,P,B.Dom,true);},setXY:function(O,R,Q){var P=function(U){var T=this.getStyle(U,&quot;position&quot;);if(T==&quot;static&quot;){this.setStyle(U,&quot;position&quot;,&quot;relative&quot;);T=&quot;relative&quot;;}var W=this.getXY(U);if(W===false){return false;}var V=[parseInt(this.getStyle(U,&quot;left&quot;),10),parseInt(this.getStyle(U,&quot;top&quot;),10)];if(isNaN(V[0])){V[0]=(T==&quot;relative&quot;)?0:U.offsetLeft;}if(isNaN(V[1])){V[1]=(T==&quot;relative&quot;)?0:U.offsetTop;}if(R[0]!==null){U.style.left=R[0]-W[0]+V[0]+&quot;px&quot;;}if(R[1]!==null){U.style.top=R[1]-W[1]+V[1]+&quot;px&quot;;}if(!Q){var S=this.getXY(U);if((R[0]!==null&amp;&amp;S[0]!=R[0])||(R[1]!==null&amp;&amp;S[1]!=R[1])){this.setXY(U,R,true);}}};B.Dom.batch(O,P,B.Dom,t
 rue);},setX:function(P,O){B.Dom.setXY(P,[O,null]);},setY:function(O,P){B.Dom.setXY(O,[null,P]);},getRegion:function(O){var P=function(Q){if((Q.parentNode===null||Q.offsetParent===null||this.getStyle(Q,&quot;display&quot;)==&quot;none&quot;)&amp;&amp;Q!=document.body){return false;}var R=B.Region.getRegion(Q);return R;};return B.Dom.batch(O,P,B.Dom,true);},getClientWidth:function(){return B.Dom.getViewportWidth();},getClientHeight:function(){return B.Dom.getViewportHeight();},getElementsByClassName:function(S,W,T,U){W=W||&quot;*&quot;;T=(T)?B.Dom.get(T):null||document;if(!T){return[];}var P=[],O=T.getElementsByTagName(W),V=N(S);for(var Q=0,R=O.length;Q&lt;R;++Q){if(V.test(O[Q].className)){P[P.length]=O[Q];if(U){U.call(O[Q],O[Q]);}}}return P;},hasClass:function(Q,P){var O=N(P);var R=function(S){return O.test(S.className);};return B.Dom.batch(Q,R,B.Dom,true);},addClass:function(P,O){var Q=function(R){if(this.hasClass(R,O)){return false;}R.className=YAHOO.lang.trim([R.className,
 O].join(&quot; &quot;));return true;};return B.Dom.batch(P,Q,B.Dom,true);},removeClass:function(Q,P){var O=N(P);var R=function(S){if(!this.hasClass(S,P)){return false;}var T=S.className;S.className=T.replace(O,&quot; &quot;);if(this.hasClass(S,P)){this.removeClass(S,P);}S.className=YAHOO.lang.trim(S.className);return true;};return B.Dom.batch(Q,R,B.Dom,true);},replaceClass:function(R,P,O){if(!O||P===O){return false;}var Q=N(P);var S=function(T){if(!this.hasClass(T,P)){this.addClass(T,O);return true;}T.className=T.className.replace(Q,&quot; &quot;+O+&quot; &quot;);if(this.hasClass(T,P)){this.replaceClass(T,P,O);}T.className=YAHOO.lang.trim(T.className);return true;};return B.Dom.batch(R,S,B.Dom,true);},generateId:function(O,Q){Q=Q||&quot;yui-gen&quot;;var P=function(R){if(R&amp;&amp;R.id){return R.id;}var S=Q+H++;if(R){R.id=S;}return S;};return B.Dom.batch(O,P,B.Dom,true)||P.apply(B.Dom,arguments);},isAncestor:function(P,Q){P=B.Dom.get(P);if(!P||!Q){return false;}var O=functi
 on(R){if(P.contains&amp;&amp;R.nodeType&amp;&amp;!L){return P.contains(R);}else{if(P.compareDocumentPosition&amp;&amp;R.nodeType){return !!(P.compareDocumentPosition(R)&amp;16);}else{if(R.nodeType){return !!this.getAncestorBy(R,function(S){return S==P;});}}}return false;};return B.Dom.batch(Q,O,B.Dom,true);},inDocument:function(O){var P=function(Q){if(L){while(Q=Q.parentNode){if(Q==document.documentElement){return true;}}return false;}return this.isAncestor(document.documentElement,Q);};return B.Dom.batch(O,P,B.Dom,true);},getElementsBy:function(V,P,Q,S){P=P||&quot;*&quot;;
-Q=(Q)?B.Dom.get(Q):null||document;if(!Q){return[];}var R=[],U=Q.getElementsByTagName(P);for(var T=0,O=U.length;T&lt;O;++T){if(V(U[T])){R[R.length]=U[T];if(S){S(U[T]);}}}return R;},batch:function(S,V,U,Q){S=(S&amp;&amp;(S.tagName||S.item))?S:B.Dom.get(S);if(!S||!V){return false;}var R=(Q)?U:window;if(S.tagName||S.length===undefined){return V.call(R,S,U);}var T=[];for(var P=0,O=S.length;P&lt;O;++P){T[T.length]=V.call(R,S[P],U);}return T;},getDocumentHeight:function(){var P=(document.compatMode!=&quot;CSS1Compat&quot;)?document.body.scrollHeight:document.documentElement.scrollHeight;var O=Math.max(P,B.Dom.getViewportHeight());return O;},getDocumentWidth:function(){var P=(document.compatMode!=&quot;CSS1Compat&quot;)?document.body.scrollWidth:document.documentElement.scrollWidth;var O=Math.max(P,B.Dom.getViewportWidth());return O;},getViewportHeight:function(){var O=self.innerHeight;var P=document.compatMode;if((P||G)&amp;&amp;!C){O=(P==&quot;CSS1Compat&quot;)?document.documentEl
 ement.clientHeight:document.body.clientHeight;}return O;},getViewportWidth:function(){var O=self.innerWidth;var P=document.compatMode;if(P||G){O=(P==&quot;CSS1Compat&quot;)?document.documentElement.clientWidth:document.body.clientWidth;}return O;},getAncestorBy:function(O,P){while(O=O.parentNode){if(D(O,P)){return O;}}return null;},getAncestorByClassName:function(P,O){P=B.Dom.get(P);if(!P){return null;}var Q=function(R){return B.Dom.hasClass(R,O);};return B.Dom.getAncestorBy(P,Q);},getAncestorByTagName:function(P,O){P=B.Dom.get(P);if(!P){return null;}var Q=function(R){return R.tagName&amp;&amp;R.tagName.toUpperCase()==O.toUpperCase();};return B.Dom.getAncestorBy(P,Q);},getPreviousSiblingBy:function(O,P){while(O){O=O.previousSibling;if(D(O,P)){return O;}}return null;},getPreviousSibling:function(O){O=B.Dom.get(O);if(!O){return null;}return B.Dom.getPreviousSiblingBy(O);},getNextSiblingBy:function(O,P){while(O){O=O.nextSibling;if(D(O,P)){return O;}}return null;},getNextSibling
 :function(O){O=B.Dom.get(O);if(!O){return null;}return B.Dom.getNextSiblingBy(O);},getFirstChildBy:function(O,Q){var P=(D(O.firstChild,Q))?O.firstChild:null;return P||B.Dom.getNextSiblingBy(O.firstChild,Q);},getFirstChild:function(O,P){O=B.Dom.get(O);if(!O){return null;}return B.Dom.getFirstChildBy(O);},getLastChildBy:function(O,Q){if(!O){return null;}var P=(D(O.lastChild,Q))?O.lastChild:null;return P||B.Dom.getPreviousSiblingBy(O.lastChild,Q);},getLastChild:function(O){O=B.Dom.get(O);return B.Dom.getLastChildBy(O);},getChildrenBy:function(P,R){var Q=B.Dom.getFirstChildBy(P,R);var O=Q?[Q]:[];B.Dom.getNextSiblingBy(Q,function(S){if(!R||R(S)){O[O.length]=S;}return false;});return O;},getChildren:function(O){O=B.Dom.get(O);if(!O){}return B.Dom.getChildrenBy(O);},getDocumentScrollLeft:function(O){O=O||document;return Math.max(O.documentElement.scrollLeft,O.body.scrollLeft);},getDocumentScrollTop:function(O){O=O||document;return Math.max(O.documentElement.scrollTop,O.body.scrollT
 op);},insertBefore:function(P,O){P=B.Dom.get(P);O=B.Dom.get(O);if(!P||!O||!O.parentNode){return null;}return O.parentNode.insertBefore(P,O);},insertAfter:function(P,O){P=B.Dom.get(P);O=B.Dom.get(O);if(!P||!O||!O.parentNode){return null;}if(O.nextSibling){return O.parentNode.insertBefore(P,O.nextSibling);}else{return O.parentNode.appendChild(P);}}};})();YAHOO.util.Region=function(C,D,A,B){this.top=C;this[1]=C;this.right=D;this.bottom=A;this.left=B;this[0]=B;};YAHOO.util.Region.prototype.contains=function(A){return(A.left&gt;=this.left&amp;&amp;A.right&lt;=this.right&amp;&amp;A.top&gt;=this.top&amp;&amp;A.bottom&lt;=this.bottom);};YAHOO.util.Region.prototype.getArea=function(){return((this.bottom-this.top)*(this.right-this.left));};YAHOO.util.Region.prototype.intersect=function(E){var C=Math.max(this.top,E.top);var D=Math.min(this.right,E.right);var A=Math.min(this.bottom,E.bottom);var B=Math.max(this.left,E.left);if(A&gt;=C&amp;&amp;D&gt;=B){return new YAHOO.util.Region(C,D,A
 ,B);}else{return null;}};YAHOO.util.Region.prototype.union=function(E){var C=Math.min(this.top,E.top);var D=Math.max(this.right,E.right);var A=Math.max(this.bottom,E.bottom);var B=Math.min(this.left,E.left);return new YAHOO.util.Region(C,D,A,B);};YAHOO.util.Region.prototype.toString=function(){return(&quot;Region {top: &quot;+this.top+&quot;, right: &quot;+this.right+&quot;, bottom: &quot;+this.bottom+&quot;, left: &quot;+this.left+&quot;}&quot;);};YAHOO.util.Region.getRegion=function(D){var F=YAHOO.util.Dom.getXY(D);var C=F[1];var E=F[0]+D.offsetWidth;var A=F[1]+D.offsetHeight;var B=F[0];return new YAHOO.util.Region(C,E,A,B);};YAHOO.util.Point=function(A,B){if(YAHOO.lang.isArray(A)){B=A[1];A=A[0];}this.x=this.right=this.left=this[0]=A;this.y=this.top=this.bottom=this[1]=B;};YAHOO.util.Point.prototype=new YAHOO.util.Region();YAHOO.register(&quot;dom&quot;,YAHOO.util.Dom,{version:&quot;2.3.1&quot;,build:&quot;541&quot;});YAHOO.util.CustomEvent=function(D,B,C,A){this.type=D;th
 is.scope=B||window;this.silent=C;this.signature=A||YAHOO.util.CustomEvent.LIST;this.subscribers=[];if(!this.silent){}var E=&quot;_YUICEOnSubscribe&quot;;if(D!==E){this.subscribeEvent=new YAHOO.util.CustomEvent(E,this,true);}this.lastError=null;};YAHOO.util.CustomEvent.LIST=0;YAHOO.util.CustomEvent.FLAT=1;YAHOO.util.CustomEvent.prototype={subscribe:function(B,C,A){if(!B){throw new Error(&quot;Invalid callback for subscriber to '&quot;+this.type+&quot;'&quot;);}if(this.subscribeEvent){this.subscribeEvent.fire(B,C,A);}this.subscribers.push(new YAHOO.util.Subscriber(B,C,A));},unsubscribe:function(D,F){if(!D){return this.unsubscribeAll();}var E=false;for(var B=0,A=this.subscribers.length;B&lt;A;++B){var C=this.subscribers[B];if(C&amp;&amp;C.contains(D,F)){this._delete(B);E=true;}}return E;},fire:function(){var E=this.subscribers.length;if(!E&amp;&amp;this.silent){return true;}var H=[],G=true,D,I=false;for(D=0;D&lt;arguments.length;++D){H.push(arguments[D]);}var A=H.length;if(!thi
 s.silent){}for(D=0;D&lt;E;++D){var L=this.subscribers[D];if(!L){I=true;}else{if(!this.silent){}var K=L.getScope(this.scope);if(this.signature==YAHOO.util.CustomEvent.FLAT){var B=null;if(H.length&gt;0){B=H[0];}try{G=L.fn.call(K,B,L.obj);}catch(F){this.lastError=F;}}else{try{G=L.fn.call(K,this.type,H,L.obj);}catch(F){this.lastError=F;}}if(false===G){if(!this.silent){}return false;}}}if(I){var J=[],C=this.subscribers;for(D=0,E=C.length;D&lt;E;D=D+1){J.push(C[D]);}this.subscribers=J;}return true;},unsubscribeAll:function(){for(var B=0,A=this.subscribers.length;B&lt;A;++B){this._delete(A-1-B);}this.subscribers=[];return B;},_delete:function(A){var B=this.subscribers[A];if(B){delete B.fn;delete B.obj;}this.subscribers[A]=null;},toString:function(){return&quot;CustomEvent: '&quot;+this.type+&quot;', scope: &quot;+this.scope;}};YAHOO.util.Subscriber=function(B,C,A){this.fn=B;this.obj=YAHOO.lang.isUndefined(C)?null:C;this.override=A;};YAHOO.util.Subscriber.prototype.getScope=function
 (A){if(this.override){if(this.override===true){return this.obj;}else{return this.override;}}return A;};YAHOO.util.Subscriber.prototype.contains=function(A,B){if(B){return(this.fn==A&amp;&amp;this.obj==B);}else{return(this.fn==A);}};YAHOO.util.Subscriber.prototype.toString=function(){return&quot;Subscriber { obj: &quot;+this.obj+&quot;, override: &quot;+(this.override||&quot;no&quot;)+&quot; }&quot;;};if(!YAHOO.util.Event){YAHOO.util.Event=function(){var H=false;var J=false;var I=[];var K=[];var G=[];var E=[];var C=0;var F=[];var B=[];var A=0;var D={63232:38,63233:40,63234:37,63235:39};return{POLL_RETRYS:4000,POLL_INTERVAL:10,EL:0,TYPE:1,FN:2,WFN:3,UNLOAD_OBJ:3,ADJ_SCOPE:4,OBJ:5,OVERRIDE:6,lastError:null,isSafari:YAHOO.env.ua.webkit,webkit:YAHOO.env.ua.webkit,isIE:YAHOO.env.ua.ie,_interval:null,startInterval:function(){if(!this._interval){var L=this;var M=function(){L._tryPreloadAttach();};this._interval=setInterval(M,this.POLL_INTERVAL);}},onAvailable:function(N,L,O,M){F.pus
 h({id:N,fn:L,obj:O,override:M,checkReady:false});C=this.POLL_RETRYS;this.startInterval();},onDOMReady:function(L,N,M){if(J){setTimeout(function(){var O=window;if(M){if(M===true){O=N;}else{O=M;}}L.call(O,&quot;DOMReady&quot;,[],N);},0);}else{this.DOMReadyEvent.subscribe(L,N,M);}},onContentReady:function(N,L,O,M){F.push({id:N,fn:L,obj:O,override:M,checkReady:true});C=this.POLL_RETRYS;this.startInterval();},addListener:function(N,L,W,R,M){if(!W||!W.call){return false;}if(this._isValidCollection(N)){var X=true;for(var S=0,U=N.length;S&lt;U;++S){X=this.on(N[S],L,W,R,M)&amp;&amp;X;}return X;}else{if(YAHOO.lang.isString(N)){var Q=this.getEl(N);if(Q){N=Q;}else{this.onAvailable(N,function(){YAHOO.util.Event.on(N,L,W,R,M);});return true;}}}if(!N){return false;}if(&quot;unload&quot;==L&amp;&amp;R!==this){K[K.length]=[N,L,W,R,M];return true;}var Z=N;if(M){if(M===true){Z=R;}else{Z=M;}}var O=function(a){return W.call(Z,YAHOO.util.Event.getEvent(a,N),R);};var Y=[N,L,W,O,Z,R,M];var T=I.leng
 th;I[T]=Y;if(this.useLegacyEvent(N,L)){var P=this.getLegacyIndex(N,L);if(P==-1||N!=G[P][0]){P=G.length;B[N.id+L]=P;G[P]=[N,L,N[&quot;on&quot;+L]];E[P]=[];N[&quot;on&quot;+L]=function(a){YAHOO.util.Event.fireLegacyEvent(YAHOO.util.Event.getEvent(a),P);};}E[P].push(Y);}else{try{this._simpleAdd(N,L,O,false);}catch(V){this.lastError=V;this.removeListener(N,L,W);return false;}}return true;},fireLegacyEvent:function(P,N){var R=true,L,T,S,U,Q;T=E[N];for(var M=0,O=T.length;M&lt;O;++M){S=T[M];if(S&amp;&amp;S[this.WFN]){U=S[this.ADJ_SCOPE];Q=S[this.WFN].call(U,P);R=(R&amp;&amp;Q);}}L=G[N];if(L&amp;&amp;L[2]){L[2](P);}return R;},getLegacyIndex:function(M,N){var L=this.generateId(M)+N;if(typeof B[L]==&quot;undefined&quot;){return -1;}else{return B[L];}},useLegacyEvent:function(M,N){if(this.webkit&amp;&amp;(&quot;click&quot;==N||&quot;dblclick&quot;==N)){var L=parseInt(this.webkit,10);if(!isNaN(L)&amp;&amp;L&lt;418){return true;}}return false;},removeListener:function(M,L,U){var P,S,W;if
 (typeof M==&quot;string&quot;){M=this.getEl(M);}else{if(this._isValidCollection(M)){var V=true;for(P=0,S=M.length;P&lt;S;++P){V=(this.removeListener(M[P],L,U)&amp;&amp;V);}return V;}}if(!U||!U.call){return this.purgeElement(M,false,L);}if(&quot;unload&quot;==L){for(P=0,S=K.length;P&lt;S;P++){W=K[P];if(W&amp;&amp;W[0]==M&amp;&amp;W[1]==L&amp;&amp;W[2]==U){K[P]=null;return true;}}return false;}var Q=null;var R=arguments[3];if(&quot;undefined&quot;===typeof R){R=this._getCacheIndex(M,L,U);}if(R&gt;=0){Q=I[R];}if(!M||!Q){return false;}if(this.useLegacyEvent(M,L)){var O=this.getLegacyIndex(M,L);var N=E[O];if(N){for(P=0,S=N.length;P&lt;S;++P){W=N[P];if(W&amp;&amp;W[this.EL]==M&amp;&amp;W[this.TYPE]==L&amp;&amp;W[this.FN]==U){N[P]=null;break;}}}}else{try{this._simpleRemove(M,L,Q[this.WFN],false);}catch(T){this.lastError=T;return false;}}delete I[R][this.WFN];delete I[R][this.FN];I[R]=null;return true;},getTarget:function(N,M){var L=N.target||N.srcElement;return this.resolveTextNode
 (L);},resolveTextNode:function(L){if(L&amp;&amp;3==L.nodeType){return L.parentNode;}else{return L;}},getPageX:function(M){var L=M.pageX;if(!L&amp;&amp;0!==L){L=M.clientX||0;if(this.isIE){L+=this._getScrollLeft();}}return L;},getPageY:function(L){var M=L.pageY;if(!M&amp;&amp;0!==M){M=L.clientY||0;if(this.isIE){M+=this._getScrollTop();}}return M;},getXY:function(L){return[this.getPageX(L),this.getPageY(L)];
-},getRelatedTarget:function(M){var L=M.relatedTarget;if(!L){if(M.type==&quot;mouseout&quot;){L=M.toElement;}else{if(M.type==&quot;mouseover&quot;){L=M.fromElement;}}}return this.resolveTextNode(L);},getTime:function(N){if(!N.time){var M=new Date().getTime();try{N.time=M;}catch(L){this.lastError=L;return M;}}return N.time;},stopEvent:function(L){this.stopPropagation(L);this.preventDefault(L);},stopPropagation:function(L){if(L.stopPropagation){L.stopPropagation();}else{L.cancelBubble=true;}},preventDefault:function(L){if(L.preventDefault){L.preventDefault();}else{L.returnValue=false;}},getEvent:function(Q,O){var P=Q||window.event;if(!P){var R=this.getEvent.caller;while(R){P=R.arguments[0];if(P&amp;&amp;Event==P.constructor){break;}R=R.caller;}}if(P&amp;&amp;this.isIE){try{var N=P.srcElement;if(N){var M=N.type;}}catch(L){P.target=O;}}return P;},getCharCode:function(M){var L=M.keyCode||M.charCode||0;if(YAHOO.env.ua.webkit&amp;&amp;(L in D)){L=D[L];}return L;},_getCacheIndex:func
 tion(P,Q,O){for(var N=0,M=I.length;N&lt;M;++N){var L=I[N];if(L&amp;&amp;L[this.FN]==O&amp;&amp;L[this.EL]==P&amp;&amp;L[this.TYPE]==Q){return N;}}return -1;},generateId:function(L){var M=L.id;if(!M){M=&quot;yuievtautoid-&quot;+A;++A;L.id=M;}return M;},_isValidCollection:function(M){try{return(typeof M!==&quot;string&quot;&amp;&amp;M.length&amp;&amp;!M.tagName&amp;&amp;!M.alert&amp;&amp;typeof M[0]!==&quot;undefined&quot;);}catch(L){return false;}},elCache:{},getEl:function(L){return(typeof L===&quot;string&quot;)?document.getElementById(L):L;},clearCache:function(){},DOMReadyEvent:new YAHOO.util.CustomEvent(&quot;DOMReady&quot;,this),_load:function(M){if(!H){H=true;var L=YAHOO.util.Event;L._ready();L._tryPreloadAttach();}},_ready:function(M){if(!J){J=true;var L=YAHOO.util.Event;L.DOMReadyEvent.fire();L._simpleRemove(document,&quot;DOMContentLoaded&quot;,L._ready);}},_tryPreloadAttach:function(){if(this.locked){return false;}if(this.isIE){if(!J){this.startInterval();return fa
 lse;}}this.locked=true;var Q=!H;if(!Q){Q=(C&gt;0);}var P=[];var R=function(T,U){var S=T;if(U.override){if(U.override===true){S=U.obj;}else{S=U.override;}}U.fn.call(S,U.obj);};var M,L,O,N;for(M=0,L=F.length;M&lt;L;++M){O=F[M];if(O&amp;&amp;!O.checkReady){N=this.getEl(O.id);if(N){R(N,O);F[M]=null;}else{P.push(O);}}}for(M=0,L=F.length;M&lt;L;++M){O=F[M];if(O&amp;&amp;O.checkReady){N=this.getEl(O.id);if(N){if(H||N.nextSibling){R(N,O);F[M]=null;}}else{P.push(O);}}}C=(P.length===0)?0:C-1;if(Q){this.startInterval();}else{clearInterval(this._interval);this._interval=null;}this.locked=false;return true;},purgeElement:function(O,P,R){var Q=this.getListeners(O,R),N,L;if(Q){for(N=0,L=Q.length;N&lt;L;++N){var M=Q[N];this.removeListener(O,M.type,M.fn,M.index);}}if(P&amp;&amp;O&amp;&amp;O.childNodes){for(N=0,L=O.childNodes.length;N&lt;L;++N){this.purgeElement(O.childNodes[N],P,R);}}},getListeners:function(N,L){var Q=[],M;if(!L){M=[I,K];}else{if(L==&quot;unload&quot;){M=[K];}else{M=[I];}}fo
 r(var P=0;P&lt;M.length;P=P+1){var T=M[P];if(T&amp;&amp;T.length&gt;0){for(var R=0,S=T.length;R&lt;S;++R){var O=T[R];if(O&amp;&amp;O[this.EL]===N&amp;&amp;(!L||L===O[this.TYPE])){Q.push({type:O[this.TYPE],fn:O[this.FN],obj:O[this.OBJ],adjust:O[this.OVERRIDE],scope:O[this.ADJ_SCOPE],index:R});}}}}return(Q.length)?Q:null;},_unload:function(S){var R=YAHOO.util.Event,P,O,M,L,N;for(P=0,L=K.length;P&lt;L;++P){M=K[P];if(M){var Q=window;if(M[R.ADJ_SCOPE]){if(M[R.ADJ_SCOPE]===true){Q=M[R.UNLOAD_OBJ];}else{Q=M[R.ADJ_SCOPE];}}M[R.FN].call(Q,R.getEvent(S,M[R.EL]),M[R.UNLOAD_OBJ]);K[P]=null;M=null;Q=null;}}K=null;if(I&amp;&amp;I.length&gt;0){O=I.length;while(O){N=O-1;M=I[N];if(M){R.removeListener(M[R.EL],M[R.TYPE],M[R.FN],N);}O=O-1;}M=null;R.clearCache();}for(P=0,L=G.length;P&lt;L;++P){G[P][0]=null;G[P]=null;}G=null;R._simpleRemove(window,&quot;unload&quot;,R._unload);},_getScrollLeft:function(){return this._getScroll()[1];},_getScrollTop:function(){return this._getScroll()[0];},_getScro
 ll:function(){var L=document.documentElement,M=document.body;if(L&amp;&amp;(L.scrollTop||L.scrollLeft)){return[L.scrollTop,L.scrollLeft];}else{if(M){return[M.scrollTop,M.scrollLeft];}else{return[0,0];}}},regCE:function(){},_simpleAdd:function(){if(window.addEventListener){return function(N,O,M,L){N.addEventListener(O,M,(L));};}else{if(window.attachEvent){return function(N,O,M,L){N.attachEvent(&quot;on&quot;+O,M);};}else{return function(){};}}}(),_simpleRemove:function(){if(window.removeEventListener){return function(N,O,M,L){N.removeEventListener(O,M,(L));};}else{if(window.detachEvent){return function(M,N,L){M.detachEvent(&quot;on&quot;+N,L);};}else{return function(){};}}}()};}();(function(){var D=YAHOO.util.Event;D.on=D.addListener;if(D.isIE){YAHOO.util.Event.onDOMReady(YAHOO.util.Event._tryPreloadAttach,YAHOO.util.Event,true);var B,E=document,A=E.body;if((&quot;undefined&quot;!==typeof YAHOO_config)&amp;&amp;YAHOO_config.injecting){B=document.createElement(&quot;script&quo
 t;);var C=E.getElementsByTagName(&quot;head&quot;)[0]||A;C.insertBefore(B,C.firstChild);}else{E.write(&quot;&lt;script id=\&quot;_yui_eu_dr\&quot; defer=\&quot;true\&quot; src=\&quot;//:\&quot;&gt;&lt;/script&gt;&quot;);B=document.getElementById(&quot;_yui_eu_dr&quot;);}if(B){B.onreadystatechange=function(){if(&quot;complete&quot;===this.readyState){this.parentNode.removeChild(this);YAHOO.util.Event._ready();}};}else{}B=null;}else{if(D.webkit){D._drwatch=setInterval(function(){var F=document.readyState;if(&quot;loaded&quot;==F||&quot;complete&quot;==F){clearInterval(D._drwatch);D._drwatch=null;D._ready();}},D.POLL_INTERVAL);}else{D._simpleAdd(document,&quot;DOMContentLoaded&quot;,D._ready);}}D._simpleAdd(window,&quot;load&quot;,D._load);D._simpleAdd(window,&quot;unload&quot;,D._unload);D._tryPreloadAttach();})();}YAHOO.util.EventProvider=function(){};YAHOO.util.EventProvider.prototype={__yui_events:null,__yui_subscribers:null,subscribe:function(A,C,F,E){this.__yui_events=thi
 s.__yui_events||{};var D=this.__yui_events[A];if(D){D.subscribe(C,F,E);}else{this.__yui_subscribers=this.__yui_subscribers||{};var B=this.__yui_subscribers;if(!B[A]){B[A]=[];}B[A].push({fn:C,obj:F,override:E});}},unsubscribe:function(C,E,G){this.__yui_events=this.__yui_events||{};var A=this.__yui_events;if(C){var F=A[C];if(F){return F.unsubscribe(E,G);}}else{var B=true;for(var D in A){if(YAHOO.lang.hasOwnProperty(A,D)){B=B&amp;&amp;A[D].unsubscribe(E,G);}}return B;}return false;},unsubscribeAll:function(A){return this.unsubscribe(A);},createEvent:function(G,D){this.__yui_events=this.__yui_events||{};
-var A=D||{};var I=this.__yui_events;if(I[G]){}else{var H=A.scope||this;var E=(A.silent);var B=new YAHOO.util.CustomEvent(G,H,E,YAHOO.util.CustomEvent.FLAT);I[G]=B;if(A.onSubscribeCallback){B.subscribeEvent.subscribe(A.onSubscribeCallback);}this.__yui_subscribers=this.__yui_subscribers||{};var F=this.__yui_subscribers[G];if(F){for(var C=0;C&lt;F.length;++C){B.subscribe(F[C].fn,F[C].obj,F[C].override);}}}return I[G];},fireEvent:function(E,D,A,C){this.__yui_events=this.__yui_events||{};var G=this.__yui_events[E];if(!G){return null;}var B=[];for(var F=1;F&lt;arguments.length;++F){B.push(arguments[F]);}return G.fire.apply(G,B);},hasEvent:function(A){if(this.__yui_events){if(this.__yui_events[A]){return true;}}return false;}};YAHOO.util.KeyListener=function(A,F,B,C){if(!A){}else{if(!F){}else{if(!B){}}}if(!C){C=YAHOO.util.KeyListener.KEYDOWN;}var D=new YAHOO.util.CustomEvent(&quot;keyPressed&quot;);this.enabledEvent=new YAHOO.util.CustomEvent(&quot;enabled&quot;);this.disabledEvent
 =new YAHOO.util.CustomEvent(&quot;disabled&quot;);if(typeof A==&quot;string&quot;){A=document.getElementById(A);}if(typeof B==&quot;function&quot;){D.subscribe(B);}else{D.subscribe(B.fn,B.scope,B.correctScope);}function E(K,J){if(!F.shift){F.shift=false;}if(!F.alt){F.alt=false;}if(!F.ctrl){F.ctrl=false;}if(K.shiftKey==F.shift&amp;&amp;K.altKey==F.alt&amp;&amp;K.ctrlKey==F.ctrl){var H;var G;if(F.keys instanceof Array){for(var I=0;I&lt;F.keys.length;I++){H=F.keys[I];if(H==K.charCode){D.fire(K.charCode,K);break;}else{if(H==K.keyCode){D.fire(K.keyCode,K);break;}}}}else{H=F.keys;if(H==K.charCode){D.fire(K.charCode,K);}else{if(H==K.keyCode){D.fire(K.keyCode,K);}}}}}this.enable=function(){if(!this.enabled){YAHOO.util.Event.addListener(A,C,E);this.enabledEvent.fire(F);}this.enabled=true;};this.disable=function(){if(this.enabled){YAHOO.util.Event.removeListener(A,C,E);this.disabledEvent.fire(F);}this.enabled=false;};this.toString=function(){return&quot;KeyListener [&quot;+F.keys+&quo
 t;] &quot;+A.tagName+(A.id?&quot;[&quot;+A.id+&quot;]&quot;:&quot;&quot;);};};YAHOO.util.KeyListener.KEYDOWN=&quot;keydown&quot;;YAHOO.util.KeyListener.KEYUP=&quot;keyup&quot;;YAHOO.register(&quot;event&quot;,YAHOO.util.Event,{version:&quot;2.3.1&quot;,build:&quot;541&quot;});YAHOO.register(&quot;yahoo-dom-event&quot;, YAHOO, {version: &quot;2.3.1&quot;, build: &quot;541&quot;});
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiyuiloaderyuiloaderminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/yuiloader/yuiloader-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/yuiloader/yuiloader-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/yuiloader/yuiloader-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,11 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+if(typeof YAHOO==&quot;undefined&quot;||!YAHOO){var YAHOO={};}YAHOO.namespace=function(){var b=arguments,g=null,e,c,f;for(e=0;e&lt;b.length;e=e+1){f=(&quot;&quot;+b[e]).split(&quot;.&quot;);g=YAHOO;for(c=(f[0]==&quot;YAHOO&quot;)?1:0;c&lt;f.length;c=c+1){g[f[c]]=g[f[c]]||{};g=g[f[c]];}}return g;};YAHOO.log=function(d,a,c){var b=YAHOO.widget.Logger;if(b&amp;&amp;b.log){return b.log(d,a,c);}else{return false;}};YAHOO.register=function(a,f,e){var k=YAHOO.env.modules,c,j,h,g,d;if(!k[a]){k[a]={versions:[],builds:[]};}c=k[a];j=e.version;h=e.build;g=YAHOO.env.listeners;c.name=a;c.version=j;c.build=h;c.versions.push(j);c.builds.push(h);c.mainClass=f;for(d=0;d&lt;g.length;d=d+1){g[d](c);}if(f){f.VERSION=j;f.BUILD=h;}else{YAHOO.log(&quot;mainClass is undefined for module &quot;+a,&quot;warn&quot;);}};YAHOO.env=YAHOO.env||{modules:[],listeners:[]};YAHOO.env.getVersion=function(a){return YAHOO.env.modules[a]||null;};YAHOO.env.parseUA=function(d){var e=function(i){var j=0;return parseFlo
 at(i.replace(/\./g,function(){return(j++==1)?&quot;&quot;:&quot;.&quot;;}));},h=navigator,g={ie:0,opera:0,gecko:0,webkit:0,chrome:0,mobile:null,air:0,ipad:0,iphone:0,ipod:0,ios:null,android:0,webos:0,caja:h&amp;&amp;h.cajaVersion,secure:false,os:null},c=d||(navigator&amp;&amp;navigator.userAgent),f=window&amp;&amp;window.location,b=f&amp;&amp;f.href,a;g.secure=b&amp;&amp;(b.toLowerCase().indexOf(&quot;https&quot;)===0);if(c){if((/windows|win32/i).test(c)){g.os=&quot;windows&quot;;}else{if((/macintosh/i).test(c)){g.os=&quot;macintosh&quot;;}else{if((/rhino/i).test(c)){g.os=&quot;rhino&quot;;}}}if((/KHTML/).test(c)){g.webkit=1;}a=c.match(/AppleWebKit\/([^\s]*)/);if(a&amp;&amp;a[1]){g.webkit=e(a[1]);if(/ Mobile\//.test(c)){g.mobile=&quot;Apple&quot;;a=c.match(/OS ([^\s]*)/);if(a&amp;&amp;a[1]){a=e(a[1].replace(&quot;_&quot;,&quot;.&quot;));}g.ios=a;g.ipad=g.ipod=g.iphone=0;a=c.match(/iPad|iPod|iPhone/);if(a&amp;&amp;a[0]){g[a[0].toLowerCase()]=g.ios;}}else{a=c.match(/NokiaN[^\/
 ]*|Android \d\.\d|webOS\/\d\.\d/);if(a){g.mobile=a[0];}if(/webOS/.test(c)){g.mobile=&quot;WebOS&quot;;a=c.match(/webOS\/([^\s]*);/);if(a&amp;&amp;a[1]){g.webos=e(a[1]);}}if(/ Android/.test(c)){g.mobile=&quot;Android&quot;;a=c.match(/Android ([^\s]*);/);if(a&amp;&amp;a[1]){g.android=e(a[1]);}}}a=c.match(/Chrome\/([^\s]*)/);if(a&amp;&amp;a[1]){g.chrome=e(a[1]);}else{a=c.match(/AdobeAIR\/([^\s]*)/);if(a){g.air=a[0];}}}if(!g.webkit){a=c.match(/Opera[\s\/]([^\s]*)/);if(a&amp;&amp;a[1]){g.opera=e(a[1]);a=c.match(/Version\/([^\s]*)/);if(a&amp;&amp;a[1]){g.opera=e(a[1]);}a=c.match(/Opera Mini[^;]*/);if(a){g.mobile=a[0];}}else{a=c.match(/MSIE\s([^;]*)/);if(a&amp;&amp;a[1]){g.ie=e(a[1]);}else{a=c.match(/Gecko\/([^\s]*)/);if(a){g.gecko=1;a=c.match(/rv:([^\s\)]*)/);if(a&amp;&amp;a[1]){g.gecko=e(a[1]);}}}}}}return g;};YAHOO.env.ua=YAHOO.env.parseUA();(function(){YAHOO.namespace(&quot;util&quot;,&quot;widget&quot;,&quot;example&quot;);if(&quot;undefined&quot;!==typeof YAHOO_config){var b=
 YAHOO_config.listener,a=YAHOO.env.listeners,d=true,c;if(b){for(c=0;c&lt;a.length;c++){if(a[c]==b){d=false;break;}}if(d){a.push(b);}}}})();YAHOO.lang=YAHOO.lang||{};(function(){var f=YAHOO.lang,a=Object.prototype,c=&quot;[object Array]&quot;,h=&quot;[object Function]&quot;,i=&quot;[object Object]&quot;,b=[],g={&quot;&amp;&quot;:&quot;&amp;amp;&quot;,&quot;&lt;&quot;:&quot;&amp;lt;&quot;,&quot;&gt;&quot;:&quot;&amp;gt;&quot;,'&quot;':&quot;&amp;quot;&quot;,&quot;'&quot;:&quot;&amp;#x27;&quot;,&quot;/&quot;:&quot;&amp;#x2F;&quot;,&quot;`&quot;:&quot;&amp;#x60;&quot;},d=[&quot;toString&quot;,&quot;valueOf&quot;],e={isArray:function(j){return a.toString.apply(j)===c;},isBoolean:function(j){return typeof j===&quot;boolean&quot;;},isFunction:function(j){return(typeof j===&quot;function&quot;)||a.toString.apply(j)===h;},isNull:function(j){return j===null;},isNumber:function(j){return typeof j===&quot;number&quot;&amp;&amp;isFinite(j);},isObject:function(j){return(j&amp;&amp;(typeof 
 j===&quot;object&quot;||f.isFunction(j)))||false;},isString:function(j){return typeof j===&quot;string&quot;;},isUndefined:function(j){return typeof j===&quot;undefined&quot;;},_IEEnumFix:(YAHOO.env.ua.ie)?function(l,k){var j,n,m;for(j=0;j&lt;d.length;j=j+1){n=d[j];m=k[n];if(f.isFunction(m)&amp;&amp;m!=a[n]){l[n]=m;}}}:function(){},escapeHTML:function(j){return j.replace(/[&amp;&lt;&gt;&quot;'\/`]/g,function(k){return g[k];});},extend:function(m,n,l){if(!n||!m){throw new Error(&quot;extend failed, please check that &quot;+&quot;all dependencies are included.&quot;);}var k=function(){},j;k.prototype=n.prototype;m.prototype=new k();m.prototype.constructor=m;m.superclass=n.prototype;if(n.prototype.constructor==a.constructor){n.prototype.constructor=n;}if(l){for(j in l){if(f.hasOwnProperty(l,j)){m.prototype[j]=l[j];}}f._IEEnumFix(m.prototype,l);}},augmentObject:function(n,m){if(!m||!n){throw new Error(&quot;Absorb failed, verify dependencies.&quot;);}var j=arguments,l,o,k=j[2];i
 f(k&amp;&amp;k!==true){for(l=2;l&lt;j.length;l=l+1){n[j[l]]=m[j[l]];}}else{for(o in m){if(k||!(o in n)){n[o]=m[o];}}f._IEEnumFix(n,m);}return n;},augmentProto:function(m,l){if(!l||!m){throw new Error(&quot;Augment failed, verify dependencies.&quot;);}var j=[m.prototype,l.prototype],k;for(k=2;k&lt;arguments.length;k=k+1){j.push(arguments[k]);}f.augmentObject.apply(this,j);return m;},dump:function(j,p){var l,n,r=[],t=&quot;{...}&quot;,k=&quot;f(){...}&quot;,q=&quot;, &quot;,m=&quot; =&gt; &quot;;if(!f.isObject(j)){return j+&quot;&quot;;}else{if(j instanceof Date||(&quot;nodeType&quot; in j&amp;&amp;&quot;tagName&quot; in j)){return j;}else{if(f.isFunction(j)){return k;}}}p=(f.isNumber(p))?p:3;if(f.isArray(j)){r.push(&quot;[&quot;);for(l=0,n=j.length;l&lt;n;l=l+1){if(f.isObject(j[l])){r.push((p&gt;0)?f.dump(j[l],p-1):t);}else{r.push(j[l]);}r.push(q);}if(r.length&gt;1){r.pop();}r.push(&quot;]&quot;);}else{r.push(&quot;{&quot;);for(l in j){if(f.hasOwnProperty(j,l)){r.push(l+m);if
 (f.isObject(j[l])){r.push((p&gt;0)?f.dump(j[l],p-1):t);}else{r.push(j[l]);}r.push(q);}}if(r.length&gt;1){r.pop();}r.push(&quot;}&quot;);}return r.join(&quot;&quot;);},substitute:function(x,y,E,l){var D,C,B,G,t,u,F=[],p,z=x.length,A=&quot;dump&quot;,r=&quot; &quot;,q=&quot;{&quot;,m=&quot;}&quot;,n,w;for(;;){D=x.lastIndexOf(q,z);if(D&lt;0){break;}C=x.indexOf(m,D);if(D+1&gt;C){break;}p=x.substring(D+1,C);G=p;u=null;B=G.indexOf(r);if(B&gt;-1){u=G.substring(B+1);G=G.substring(0,B);}t=y[G];if(E){t=E(G,t,u);}if(f.isObject(t)){if(f.isArray(t)){t=f.dump(t,parseInt(u,10));}else{u=u||&quot;&quot;;n=u.indexOf(A);if(n&gt;-1){u=u.substring(4);}w=t.toString();if(w===i||n&gt;-1){t=f.dump(t,parseInt(u,10));}else{t=w;}}}else{if(!f.isString(t)&amp;&amp;!f.isNumber(t)){t=&quot;~-&quot;+F.length+&quot;-~&quot;;F[F.length]=p;}}x=x.substring(0,D)+t+x.substring(C+1);if(l===false){z=D-1;}}for(D=F.length-1;D&gt;=0;D=D-1){x=x.replace(new RegExp(&quot;~-&quot;+D+&quot;-~&quot;),&quot;{&quot;+F[D]+&quo
 t;}&quot;,&quot;g&quot;);}return x;},trim:function(j){try{return j.replace(/^\s+|\s+$/g,&quot;&quot;);}catch(k){return j;
+}},merge:function(){var n={},k=arguments,j=k.length,m;for(m=0;m&lt;j;m=m+1){f.augmentObject(n,k[m],true);}return n;},later:function(t,k,u,n,p){t=t||0;k=k||{};var l=u,s=n,q,j;if(f.isString(u)){l=k[u];}if(!l){throw new TypeError(&quot;method undefined&quot;);}if(!f.isUndefined(n)&amp;&amp;!f.isArray(s)){s=[n];}q=function(){l.apply(k,s||b);};j=(p)?setInterval(q,t):setTimeout(q,t);return{interval:p,cancel:function(){if(this.interval){clearInterval(j);}else{clearTimeout(j);}}};},isValue:function(j){return(f.isObject(j)||f.isString(j)||f.isNumber(j)||f.isBoolean(j));}};f.hasOwnProperty=(a.hasOwnProperty)?function(j,k){return j&amp;&amp;j.hasOwnProperty&amp;&amp;j.hasOwnProperty(k);}:function(j,k){return !f.isUndefined(j[k])&amp;&amp;j.constructor.prototype[k]!==j[k];};e.augmentObject(f,e,true);YAHOO.util.Lang=f;f.augment=f.augmentProto;YAHOO.augment=f.augmentProto;YAHOO.extend=f.extend;})();YAHOO.register(&quot;yahoo&quot;,YAHOO,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
 YAHOO.util.Get=function(){var m={},k=0,r=0,l=false,n=YAHOO.env.ua,s=YAHOO.lang,q,d,e,i=function(x,t,y){var u=y||window,z=u.document,A=z.createElement(x),v;for(v in t){if(t.hasOwnProperty(v)){A.setAttribute(v,t[v]);}}return A;},h=function(u,v,t){var w={id:&quot;yui__dyn_&quot;+(r++),type:&quot;text/css&quot;,rel:&quot;stylesheet&quot;,href:u};if(t){s.augmentObject(w,t);}return i(&quot;link&quot;,w,v);},p=function(u,v,t){var w={id:&quot;yui__dyn_&quot;+(r++),type:&quot;text/javascript&quot;,src:u};if(t){s.augmentObject(w,t);}return i(&quot;script&quot;,w,v);},a=function(t,u){return{tId:t.tId,win:t.win,data:t.data,nodes:t.nodes,msg:u,purge:function(){d(this.tId);}};},b=function(t,w){var u=m[w],v=(s.isString(t))?u.win.document.getElementById(t):t;if(!v){q(w,&quot;target node not found: &quot;+t);}return v;},c=function(w){YAHOO.log(&quot;Finishing transaction &quot;+w);var u=m[w],v,t;u.finished=true;if(u.aborted){v=&quot;transaction &quot;+w+&quot; was aborted&quot;;q(w,v);return
 ;}if(u.onSuccess){t=u.scope||u.win;u.onSuccess.call(t,a(u));}},o=function(v){YAHOO.log(&quot;Timeout &quot;+v,&quot;info&quot;,&quot;get&quot;);var u=m[v],t;if(u.onTimeout){t=u.scope||u;u.onTimeout.call(t,a(u));}},f=function(v,A){YAHOO.log(&quot;_next: &quot;+v+&quot;, loaded: &quot;+A,&quot;info&quot;,&quot;Get&quot;);var u=m[v],D=u.win,C=D.document,B=C.getElementsByTagName(&quot;head&quot;)[0],x,y,t,E,z;if(u.timer){u.timer.cancel();}if(u.aborted){y=&quot;transaction &quot;+v+&quot; was aborted&quot;;q(v,y);return;}if(A){u.url.shift();if(u.varName){u.varName.shift();}}else{u.url=(s.isString(u.url))?[u.url]:u.url;if(u.varName){u.varName=(s.isString(u.varName))?[u.varName]:u.varName;}}if(u.url.length===0){if(u.type===&quot;script&quot;&amp;&amp;n.webkit&amp;&amp;n.webkit&lt;420&amp;&amp;!u.finalpass&amp;&amp;!u.varName){z=p(null,u.win,u.attributes);z.innerHTML='YAHOO.util.Get._finalize(&quot;'+v+'&quot;);';u.nodes.push(z);B.appendChild(z);}else{c(v);}return;}t=u.url[0];if(!t)
 {u.url.shift();YAHOO.log(&quot;skipping empty url&quot;);return f(v);}YAHOO.log(&quot;attempting to load &quot;+t,&quot;info&quot;,&quot;Get&quot;);if(u.timeout){u.timer=s.later(u.timeout,u,o,v);}if(u.type===&quot;script&quot;){x=p(t,D,u.attributes);}else{x=h(t,D,u.attributes);}e(u.type,x,v,t,D,u.url.length);u.nodes.push(x);if(u.insertBefore){E=b(u.insertBefore,v);if(E){E.parentNode.insertBefore(x,E);}}else{B.appendChild(x);}YAHOO.log(&quot;Appending node: &quot;+t,&quot;info&quot;,&quot;Get&quot;);if((n.webkit||n.gecko)&amp;&amp;u.type===&quot;css&quot;){f(v,t);}},j=function(){if(l){return;}l=true;var t,u;for(t in m){if(m.hasOwnProperty(t)){u=m[t];if(u.autopurge&amp;&amp;u.finished){d(u.tId);delete m[t];}}}l=false;},g=function(u,t,v){var x=&quot;q&quot;+(k++),w;v=v||{};if(k%YAHOO.util.Get.PURGE_THRESH===0){j();}m[x]=s.merge(v,{tId:x,type:u,url:t,finished:false,aborted:false,nodes:[]});w=m[x];w.win=w.win||window;w.scope=w.scope||w.win;w.autopurge=(&quot;autopurge&quot; in w)
 ?w.autopurge:(u===&quot;script&quot;)?true:false;w.attributes=w.attributes||{};w.attributes.charset=v.charset||w.attributes.charset||&quot;utf-8&quot;;s.later(0,w,f,x);return{tId:x};};e=function(H,z,x,u,D,E,G){var F=G||f,B,t,I,v,J,A,C,y;if(n.ie){z.onreadystatechange=function(){B=this.readyState;if(&quot;loaded&quot;===B||&quot;complete&quot;===B){YAHOO.log(x+&quot; onload &quot;+u,&quot;info&quot;,&quot;Get&quot;);z.onreadystatechange=null;F(x,u);}};}else{if(n.webkit){if(H===&quot;script&quot;){if(n.webkit&gt;=420){z.addEventListener(&quot;load&quot;,function(){YAHOO.log(x+&quot; DOM2 onload &quot;+u,&quot;info&quot;,&quot;Get&quot;);F(x,u);});}else{t=m[x];if(t.varName){v=YAHOO.util.Get.POLL_FREQ;YAHOO.log(&quot;Polling for &quot;+t.varName[0]);t.maxattempts=YAHOO.util.Get.TIMEOUT/v;t.attempts=0;t._cache=t.varName[0].split(&quot;.&quot;);t.timer=s.later(v,t,function(w){I=this._cache;A=I.length;J=this.win;for(C=0;C&lt;A;C=C+1){J=J[I[C]];if(!J){this.attempts++;if(this.attempts
 ++&gt;this.maxattempts){y=&quot;Over retry limit, giving up&quot;;t.timer.cancel();q(x,y);}else{YAHOO.log(I[C]+&quot; failed, retrying&quot;);}return;}}YAHOO.log(&quot;Safari poll complete&quot;);t.timer.cancel();F(x,u);},null,true);}else{s.later(YAHOO.util.Get.POLL_FREQ,null,F,[x,u]);}}}}else{z.onload=function(){YAHOO.log(x+&quot; onload &quot;+u,&quot;info&quot;,&quot;Get&quot;);F(x,u);};}}};q=function(w,v){YAHOO.log(&quot;get failure: &quot;+v,&quot;warn&quot;,&quot;Get&quot;);var u=m[w],t;if(u.onFailure){t=u.scope||u.win;u.onFailure.call(t,a(u,v));}};d=function(z){if(m[z]){var t=m[z],u=t.nodes,x=u.length,C=t.win.document,A=C.getElementsByTagName(&quot;head&quot;)[0],v,y,w,B;if(t.insertBefore){v=b(t.insertBefore,z);if(v){A=v.parentNode;}}for(y=0;y&lt;x;y=y+1){w=u[y];if(w.clearAttributes){w.clearAttributes();}else{for(B in w){if(w.hasOwnProperty(B)){delete w[B];}}}A.removeChild(w);}t.nodes=[];}};return{POLL_FREQ:10,PURGE_THRESH:20,TIMEOUT:2000,_finalize:function(t){YAHOO.l
 og(t+&quot; finalized &quot;,&quot;info&quot;,&quot;Get&quot;);s.later(0,null,c,t);},abort:function(u){var v=(s.isString(u))?u:u.tId,t=m[v];if(t){YAHOO.log(&quot;Aborting &quot;+v,&quot;info&quot;,&quot;Get&quot;);t.aborted=true;}},script:function(t,u){return g(&quot;script&quot;,t,u);},css:function(t,u){return g(&quot;css&quot;,t,u);}};}();YAHOO.register(&quot;get&quot;,YAHOO.util.Get,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});(function(){var Y=YAHOO,util=Y.util,lang=Y.lang,env=Y.env,PROV=&quot;_provides&quot;,SUPER=&quot;_supersedes&quot;,REQ=&quot;expanded&quot;,AFTER=&quot;_after&quot;,VERSION=&quot;2.9.0&quot;;var YUI={dupsAllowed:{&quot;yahoo&quot;:true,&quot;get&quot;:true},info:{&quot;root&quot;:VERSION+&quot;/build/&quot;,&quot;base&quot;:&quot;http://yui.yahooapis.com/&quot;+VERSION+&quot;/build/&quot;,&quot;comboBase&quot;:&quot;http://yui.yahooapis.com/combo?&quot;,&quot;skin&quot;:{&quot;defaultSkin&quot;:&quot;sam&quot;,&quot;base&quot;:&quot;assets/sk
 ins/&quot;,&quot;path&quot;:&quot;skin.css&quot;,&quot;after&quot;:[&quot;reset&quot;,&quot;fonts&quot;,&quot;grids&quot;,&quot;base&quot;],&quot;rollup&quot;:3},dupsAllowed:[&quot;yahoo&quot;,&quot;get&quot;],&quot;moduleInfo&quot;:{&quot;animation&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;animation/animation-min.js&quot;,&quot;requires&quot;:[&quot;dom&quot;,&quot;event&quot;]},&quot;autocomplete&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;autocomplete/autocomplete-min.js&quot;,&quot;requires&quot;:[&quot;dom&quot;,&quot;event&quot;,&quot;datasource&quot;],&quot;optional&quot;:[&quot;connection&quot;,&quot;animation&quot;],&quot;skinnable&quot;:true},&quot;base&quot;:{&quot;type&quot;:&quot;css&quot;,&quot;path&quot;:&quot;base/base-min.css&quot;,&quot;after&quot;:[&quot;reset&quot;,&quot;fonts&quot;,&quot;grids&quot;]},&quot;button&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;button/button-min.js&quot;,&quot;requires&
 quot;:[&quot;element&quot;],&quot;optional&quot;:[&quot;menu&quot;],&quot;skinnable&quot;:true},&quot;calendar&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;calendar/calendar-min.js&quot;,&quot;requires&quot;:[&quot;event&quot;,&quot;dom&quot;],supersedes:[&quot;datemath&quot;],&quot;skinnable&quot;:true},&quot;carousel&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;carousel/carousel-min.js&quot;,&quot;requires&quot;:[&quot;element&quot;],&quot;optional&quot;:[&quot;animation&quot;],&quot;skinnable&quot;:true},&quot;charts&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;charts/charts-min.js&quot;,&quot;requires&quot;:[&quot;element&quot;,&quot;json&quot;,&quot;datasource&quot;,&quot;swf&quot;]},&quot;colorpicker&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;colorpicker/colorpicker-min.js&quot;,&quot;requires&quot;:[&quot;slider&quot;,&quot;element&quot;],&quot;optional&quot;:[&quot;animation&quot;],&quot;skinnable&
 quot;:true},&quot;connection&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;connection/connection-min.js&quot;,&quot;requires&quot;:[&quot;event&quot;],&quot;supersedes&quot;:[&quot;connectioncore&quot;]},&quot;connectioncore&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;connection/connection_core-min.js&quot;,&quot;requires&quot;:[&quot;event&quot;],&quot;pkg&quot;:&quot;connection&quot;},&quot;container&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;container/container-min.js&quot;,&quot;requires&quot;:[&quot;dom&quot;,&quot;event&quot;],&quot;optional&quot;:[&quot;dragdrop&quot;,&quot;animation&quot;,&quot;connection&quot;],&quot;supersedes&quot;:[&quot;containercore&quot;],&quot;skinnable&quot;:true},&quot;containercore&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;container/container_core-min.js&quot;,&quot;requires&quot;:[&quot;dom&quot;,&quot;event&quot;],&quot;pkg&quot;:&quot;container&quot;},&quot;cookie&
 quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;cookie/cookie-min.js&quot;,&quot;requires&quot;:[&quot;yahoo&quot;]},&quot;datasource&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;datasource/datasource-min.js&quot;,&quot;requires&quot;:[&quot;event&quot;],&quot;optional&quot;:[&quot;connection&quot;]},&quot;datatable&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;datatable/datatable-min.js&quot;,&quot;requires&quot;:[&quot;element&quot;,&quot;datasource&quot;],&quot;optional&quot;:[&quot;calendar&quot;,&quot;dragdrop&quot;,&quot;paginator&quot;],&quot;skinnable&quot;:true},datemath:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;datemath/datemath-min.js&quot;,&quot;requires&quot;:[&quot;yahoo&quot;]},&quot;dom&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;dom/dom-min.js&quot;,&quot;requires&quot;:[&quot;yahoo&quot;]},&quot;dragdrop&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;dragdrop/dragd
 rop-min.js&quot;,&quot;requires&quot;:[&quot;dom&quot;,&quot;event&quot;]},&quot;editor&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;editor/editor-min.js&quot;,&quot;requires&quot;:[&quot;menu&quot;,&quot;element&quot;,&quot;button&quot;],&quot;optional&quot;:[&quot;animation&quot;,&quot;dragdrop&quot;],&quot;supersedes&quot;:[&quot;simpleeditor&quot;],&quot;skinnable&quot;:true},&quot;element&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;element/element-min.js&quot;,&quot;requires&quot;:[&quot;dom&quot;,&quot;event&quot;],&quot;optional&quot;:[&quot;event-mouseenter&quot;,&quot;event-delegate&quot;]},&quot;element-delegate&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;element-delegate/element-delegate-min.js&quot;,&quot;requires&quot;:[&quot;element&quot;]},&quot;event&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;event/event-min.js&quot;,&quot;requires&quot;:[&quot;yahoo&quot;]},&quot;event-simulate&quot;:{&q
 uot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;event-simulate/event-simulate-min.js&quot;,&quot;requires&quot;:[&quot;event&quot;]},&quot;event-delegate&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;event-delegate/event-delegate-min.js&quot;,&quot;requires&quot;:[&quot;event&quot;],&quot;optional&quot;:[&quot;selector&quot;]},&quot;event-mouseenter&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;event-mouseenter/event-mouseenter-min.js&quot;,&quot;requires&quot;:[&quot;dom&quot;,&quot;event&quot;]},&quot;fonts&quot;:{&quot;type&quot;:&quot;css&quot;,&quot;path&quot;:&quot;fonts/fonts-min.css&quot;},&quot;get&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;get/get-min.js&quot;,&quot;requires&quot;:[&quot;yahoo&quot;]},&quot;grids&quot;:{&quot;type&quot;:&quot;css&quot;,&quot;path&quot;:&quot;grids/grids-min.css&quot;,&quot;requires&quot;:[&quot;fonts&quot;],&quot;optional&quot;:[&quot;reset&quot;]},&quot;history&quot;:{&quot;t
 ype&quot;:&quot;js&quot;,&quot;path&quot;:&quot;history/history-min.js&quot;,&quot;requires&quot;:[&quot;event&quot;]},&quot;imagecropper&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;imagecropper/imagecropper-min.js&quot;,&quot;requires&quot;:[&quot;dragdrop&quot;,&quot;element&quot;,&quot;resize&quot;],&quot;skinnable&quot;:true},&quot;imageloader&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;imageloader/imageloader-min.js&quot;,&quot;requires&quot;:[&quot;event&quot;,&quot;dom&quot;]},&quot;json&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;json/json-min.js&quot;,&quot;requires&quot;:[&quot;yahoo&quot;]},&quot;layout&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;layout/layout-min.js&quot;,&quot;requires&quot;:[&quot;element&quot;],&quot;optional&quot;:[&quot;animation&quot;,&quot;dragdrop&quot;,&quot;resize&quot;,&quot;selector&quot;],&quot;skinnable&quot;:true},&quot;logger&quot;:{&quot;type&quot;:&quot;js&q
 uot;,&quot;path&quot;:&quot;logger/logger-min.js&quot;,&quot;requires&quot;:[&quot;event&quot;,&quot;dom&quot;],&quot;optional&quot;:[&quot;dragdrop&quot;],&quot;skinnable&quot;:true},&quot;menu&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;menu/menu-min.js&quot;,&quot;requires&quot;:[&quot;containercore&quot;],&quot;skinnable&quot;:true},&quot;paginator&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;paginator/paginator-min.js&quot;,&quot;requires&quot;:[&quot;element&quot;],&quot;skinnable&quot;:true},&quot;profiler&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;profiler/profiler-min.js&quot;,&quot;requires&quot;:[&quot;yahoo&quot;]},&quot;profilerviewer&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;profilerviewer/profilerviewer-min.js&quot;,&quot;requires&quot;:[&quot;profiler&quot;,&quot;yuiloader&quot;,&quot;element&quot;],&quot;skinnable&quot;:true},&quot;progressbar&quot;:{&quot;type&quot;:&quot;js&quot;,&qu
 ot;path&quot;:&quot;progressbar/progressbar-min.js&quot;,&quot;requires&quot;:[&quot;element&quot;],&quot;optional&quot;:[&quot;animation&quot;],&quot;skinnable&quot;:true},&quot;reset&quot;:{&quot;type&quot;:&quot;css&quot;,&quot;path&quot;:&quot;reset/reset-min.css&quot;},&quot;reset-fonts-grids&quot;:{&quot;type&quot;:&quot;css&quot;,&quot;path&quot;:&quot;reset-fonts-grids/reset-fonts-grids.css&quot;,&quot;supersedes&quot;:[&quot;reset&quot;,&quot;fonts&quot;,&quot;grids&quot;,&quot;reset-fonts&quot;],&quot;rollup&quot;:4},&quot;reset-fonts&quot;:{&quot;type&quot;:&quot;css&quot;,&quot;path&quot;:&quot;reset-fonts/reset-fonts.css&quot;,&quot;supersedes&quot;:[&quot;reset&quot;,&quot;fonts&quot;],&quot;rollup&quot;:2},&quot;resize&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;resize/resize-min.js&quot;,&quot;requires&quot;:[&quot;dragdrop&quot;,&quot;element&quot;],&quot;optional&quot;:[&quot;animation&quot;],&quot;skinnable&quot;:true},&quot;selector&quot
 ;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;selector/selector-min.js&quot;,&quot;requires&quot;:[&quot;yahoo&quot;,&quot;dom&quot;]},&quot;simpleeditor&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;editor/simpleeditor-min.js&quot;,&quot;requires&quot;:[&quot;element&quot;],&quot;optional&quot;:[&quot;containercore&quot;,&quot;menu&quot;,&quot;button&quot;,&quot;animation&quot;,&quot;dragdrop&quot;],&quot;skinnable&quot;:true,&quot;pkg&quot;:&quot;editor&quot;},&quot;slider&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;slider/slider-min.js&quot;,&quot;requires&quot;:[&quot;dragdrop&quot;],&quot;optional&quot;:[&quot;animation&quot;],&quot;skinnable&quot;:true},&quot;storage&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;storage/storage-min.js&quot;,&quot;requires&quot;:[&quot;yahoo&quot;,&quot;event&quot;,&quot;cookie&quot;],&quot;optional&quot;:[&quot;swfstore&quot;]},&quot;stylesheet&quot;:{&quot;type&quot;:&quot;
 js&quot;,&quot;path&quot;:&quot;stylesheet/stylesheet-min.js&quot;,&quot;requires&quot;:[&quot;yahoo&quot;]},&quot;swf&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;swf/swf-min.js&quot;,&quot;requires&quot;:[&quot;element&quot;],&quot;supersedes&quot;:[&quot;swfdetect&quot;]},&quot;swfdetect&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;swfdetect/swfdetect-min.js&quot;,&quot;requires&quot;:[&quot;yahoo&quot;]},&quot;swfstore&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;swfstore/swfstore-min.js&quot;,&quot;requires&quot;:[&quot;element&quot;,&quot;cookie&quot;,&quot;swf&quot;]},&quot;tabview&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;tabview/tabview-min.js&quot;,&quot;requires&quot;:[&quot;element&quot;],&quot;optional&quot;:[&quot;connection&quot;],&quot;skinnable&quot;:true},&quot;treeview&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;treeview/treeview-min.js&quot;,&quot;requires&quot;:[&quo
 t;event&quot;,&quot;dom&quot;],&quot;optional&quot;:[&quot;json&quot;,&quot;animation&quot;,&quot;calendar&quot;],&quot;skinnable&quot;:true},&quot;uploader&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;uploader/uploader-min.js&quot;,&quot;requires&quot;:[&quot;element&quot;]},&quot;utilities&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;utilities/utilities.js&quot;,&quot;supersedes&quot;:[&quot;yahoo&quot;,&quot;event&quot;,&quot;dragdrop&quot;,&quot;animation&quot;,&quot;dom&quot;,&quot;connection&quot;,&quot;element&quot;,&quot;yahoo-dom-event&quot;,&quot;get&quot;,&quot;yuiloader&quot;,&quot;yuiloader-dom-event&quot;],&quot;rollup&quot;:8},&quot;yahoo&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;yahoo/yahoo-min.js&quot;},&quot;yahoo-dom-event&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;yahoo-dom-event/yahoo-dom-event.js&quot;,&quot;supersedes&quot;:[&quot;yahoo&quot;,&quot;event&quot;,&quot;dom&quot;],&qu
 ot;rollup&quot;:3},&quot;yuiloader&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;yuiloader/yuiloader-min.js&quot;,&quot;supersedes&quot;:[&quot;yahoo&quot;,&quot;get&quot;]},&quot;yuiloader-dom-event&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;yuiloader-dom-event/yuiloader-dom-event.js&quot;,&quot;supersedes&quot;:[&quot;yahoo&quot;,&quot;dom&quot;,&quot;event&quot;,&quot;get&quot;,&quot;yuiloader&quot;,&quot;yahoo-dom-event&quot;],&quot;rollup&quot;:5},&quot;yuitest&quot;:{&quot;type&quot;:&quot;js&quot;,&quot;path&quot;:&quot;yuitest/yuitest-min.js&quot;,&quot;requires&quot;:[&quot;logger&quot;],&quot;optional&quot;:[&quot;event-simulate&quot;],&quot;skinnable&quot;:true}}},ObjectUtil:{appendArray:function(o,a){if(a){for(var i=0;
+i&lt;a.length;i=i+1){o[a[i]]=true;}}},keys:function(o,ordered){var a=[],i;for(i in o){if(lang.hasOwnProperty(o,i)){a.push(i);}}return a;}},ArrayUtil:{appendArray:function(a1,a2){Array.prototype.push.apply(a1,a2);},indexOf:function(a,val){for(var i=0;i&lt;a.length;i=i+1){if(a[i]===val){return i;}}return -1;},toObject:function(a){var o={};for(var i=0;i&lt;a.length;i=i+1){o[a[i]]=true;}return o;},uniq:function(a){return YUI.ObjectUtil.keys(YUI.ArrayUtil.toObject(a));}}};YAHOO.util.YUILoader=function(o){this._internalCallback=null;this._useYahooListener=false;this.onSuccess=null;this.onFailure=Y.log;this.onProgress=null;this.onTimeout=null;this.scope=this;this.data=null;this.insertBefore=null;this.charset=null;this.varName=null;this.base=YUI.info.base;this.comboBase=YUI.info.comboBase;this.combine=false;this.root=YUI.info.root;this.timeout=0;this.ignore=null;this.force=null;this.allowRollup=true;this.filter=null;this.required={};this.moduleInfo=lang.merge(YUI.info.moduleInfo);th
 is.rollups=null;this.loadOptional=false;this.sorted=[];this.loaded={};this.dirty=true;this.inserted={};var self=this;env.listeners.push(function(m){if(self._useYahooListener){self.loadNext(m.name);}});this.skin=lang.merge(YUI.info.skin);this._config(o);};Y.util.YUILoader.prototype={FILTERS:{RAW:{&quot;searchExp&quot;:&quot;-min\\.js&quot;,&quot;replaceStr&quot;:&quot;.js&quot;},DEBUG:{&quot;searchExp&quot;:&quot;-min\\.js&quot;,&quot;replaceStr&quot;:&quot;-debug.js&quot;}},SKIN_PREFIX:&quot;skin-&quot;,_config:function(o){if(o){for(var i in o){if(lang.hasOwnProperty(o,i)){if(i==&quot;require&quot;){this.require(o[i]);}else{this[i]=o[i];}}}}var f=this.filter;if(lang.isString(f)){f=f.toUpperCase();if(f===&quot;DEBUG&quot;){this.require(&quot;logger&quot;);}if(!Y.widget.LogWriter){Y.widget.LogWriter=function(){return Y;};}this.filter=this.FILTERS[f];}},addModule:function(o){if(!o||!o.name||!o.type||(!o.path&amp;&amp;!o.fullpath)){return false;}o.ext=(&quot;ext&quot; in o)?o.ex
 t:true;o.requires=o.requires||[];this.moduleInfo[o.name]=o;this.dirty=true;return true;},require:function(what){var a=(typeof what===&quot;string&quot;)?arguments:what;this.dirty=true;YUI.ObjectUtil.appendArray(this.required,a);},_addSkin:function(skin,mod){var name=this.formatSkin(skin),info=this.moduleInfo,sinf=this.skin,ext=info[mod]&amp;&amp;info[mod].ext;if(!info[name]){this.addModule({&quot;name&quot;:name,&quot;type&quot;:&quot;css&quot;,&quot;path&quot;:sinf.base+skin+&quot;/&quot;+sinf.path,&quot;after&quot;:sinf.after,&quot;rollup&quot;:sinf.rollup,&quot;ext&quot;:ext});}if(mod){name=this.formatSkin(skin,mod);if(!info[name]){var mdef=info[mod],pkg=mdef.pkg||mod;this.addModule({&quot;name&quot;:name,&quot;type&quot;:&quot;css&quot;,&quot;after&quot;:sinf.after,&quot;path&quot;:pkg+&quot;/&quot;+sinf.base+skin+&quot;/&quot;+mod+&quot;.css&quot;,&quot;ext&quot;:ext});}}return name;},getRequires:function(mod){if(!mod){return[];}if(!this.dirty&amp;&amp;mod.expanded){ret
 urn mod.expanded;}mod.requires=mod.requires||[];var i,d=[],r=mod.requires,o=mod.optional,info=this.moduleInfo,m;for(i=0;i&lt;r.length;i=i+1){d.push(r[i]);m=info[r[i]];YUI.ArrayUtil.appendArray(d,this.getRequires(m));}if(o&amp;&amp;this.loadOptional){for(i=0;i&lt;o.length;i=i+1){d.push(o[i]);YUI.ArrayUtil.appendArray(d,this.getRequires(info[o[i]]));}}mod.expanded=YUI.ArrayUtil.uniq(d);return mod.expanded;},getProvides:function(name,notMe){var addMe=!(notMe),ckey=(addMe)?PROV:SUPER,m=this.moduleInfo[name],o={};if(!m){return o;}if(m[ckey]){return m[ckey];}var s=m.supersedes,done={},me=this;var add=function(mm){if(!done[mm]){done[mm]=true;lang.augmentObject(o,me.getProvides(mm));}};if(s){for(var i=0;i&lt;s.length;i=i+1){add(s[i]);}}m[SUPER]=o;m[PROV]=lang.merge(o);m[PROV][name]=true;return m[ckey];},calculate:function(o){if(o||this.dirty){this._config(o);this._setup();this._explode();if(this.allowRollup){this._rollup();}this._reduce();this._sort();this.dirty=false;}},_setup:func
 tion(){var info=this.moduleInfo,name,i,j;for(name in info){if(lang.hasOwnProperty(info,name)){var m=info[name];if(m&amp;&amp;m.skinnable){var o=this.skin.overrides,smod;if(o&amp;&amp;o[name]){for(i=0;i&lt;o[name].length;i=i+1){smod=this._addSkin(o[name][i],name);}}else{smod=this._addSkin(this.skin.defaultSkin,name);}if(YUI.ArrayUtil.indexOf(m.requires,smod)==-1){m.requires.push(smod);}}}}var l=lang.merge(this.inserted);if(!this._sandbox){l=lang.merge(l,env.modules);}if(this.ignore){YUI.ObjectUtil.appendArray(l,this.ignore);}if(this.force){for(i=0;i&lt;this.force.length;i=i+1){if(this.force[i] in l){delete l[this.force[i]];}}}for(j in l){if(lang.hasOwnProperty(l,j)){lang.augmentObject(l,this.getProvides(j));}}this.loaded=l;},_explode:function(){var r=this.required,i,mod;for(i in r){if(lang.hasOwnProperty(r,i)){mod=this.moduleInfo[i];if(mod){var req=this.getRequires(mod);if(req){YUI.ObjectUtil.appendArray(r,req);}}}}},_skin:function(){},formatSkin:function(skin,mod){var s=this
 .SKIN_PREFIX+skin;if(mod){s=s+&quot;-&quot;+mod;}return s;},parseSkin:function(mod){if(mod.indexOf(this.SKIN_PREFIX)===0){var a=mod.split(&quot;-&quot;);return{skin:a[1],module:a[2]};}return null;},_rollup:function(){var i,j,m,s,rollups={},r=this.required,roll,info=this.moduleInfo;if(this.dirty||!this.rollups){for(i in info){if(lang.hasOwnProperty(info,i)){m=info[i];if(m&amp;&amp;m.rollup){rollups[i]=m;}}}this.rollups=rollups;}for(;;){var rolled=false;for(i in rollups){if(!r[i]&amp;&amp;!this.loaded[i]){m=info[i];s=m.supersedes;roll=false;if(!m.rollup){continue;}var skin=(m.ext)?false:this.parseSkin(i),c=0;if(skin){for(j in r){if(lang.hasOwnProperty(r,j)){if(i!==j&amp;&amp;this.parseSkin(j)){c++;roll=(c&gt;=m.rollup);if(roll){break;}}}}}else{for(j=0;j&lt;s.length;j=j+1){if(this.loaded[s[j]]&amp;&amp;(!YUI.dupsAllowed[s[j]])){roll=false;break;}else{if(r[s[j]]){c++;roll=(c&gt;=m.rollup);if(roll){break;}}}}}if(roll){r[i]=true;rolled=true;this.getRequires(m);}}}if(!rolled){break
 ;}}},_reduce:function(){var i,j,s,m,r=this.required;for(i in r){if(i in this.loaded){delete r[i];}else{var skinDef=this.parseSkin(i);if(skinDef){if(!skinDef.module){var skin_pre=this.SKIN_PREFIX+skinDef.skin;for(j in r){if(lang.hasOwnProperty(r,j)){m=this.moduleInfo[j];var ext=m&amp;&amp;m.ext;if(!ext&amp;&amp;j!==i&amp;&amp;j.indexOf(skin_pre)&gt;-1){delete r[j];}}}}}else{m=this.moduleInfo[i];s=m&amp;&amp;m.supersedes;if(s){for(j=0;j&lt;s.length;j=j+1){if(s[j] in r){delete r[s[j]];}}}}}}},_onFailure:function(msg){YAHOO.log(&quot;Failure&quot;,&quot;info&quot;,&quot;loader&quot;);
+var f=this.onFailure;if(f){f.call(this.scope,{msg:&quot;failure: &quot;+msg,data:this.data,success:false});}},_onTimeout:function(){YAHOO.log(&quot;Timeout&quot;,&quot;info&quot;,&quot;loader&quot;);var f=this.onTimeout;if(f){f.call(this.scope,{msg:&quot;timeout&quot;,data:this.data,success:false});}},_sort:function(){var s=[],info=this.moduleInfo,loaded=this.loaded,checkOptional=!this.loadOptional,me=this;var requires=function(aa,bb){var mm=info[aa];if(loaded[bb]||!mm){return false;}var ii,rr=mm.expanded,after=mm.after,other=info[bb],optional=mm.optional;if(rr&amp;&amp;YUI.ArrayUtil.indexOf(rr,bb)&gt;-1){return true;}if(after&amp;&amp;YUI.ArrayUtil.indexOf(after,bb)&gt;-1){return true;}if(checkOptional&amp;&amp;optional&amp;&amp;YUI.ArrayUtil.indexOf(optional,bb)&gt;-1){return true;}var ss=info[bb]&amp;&amp;info[bb].supersedes;if(ss){for(ii=0;ii&lt;ss.length;ii=ii+1){if(requires(aa,ss[ii])){return true;}}}if(mm.ext&amp;&amp;mm.type==&quot;css&quot;&amp;&amp;!other.ext&amp;&
 amp;other.type==&quot;css&quot;){return true;}return false;};for(var i in this.required){if(lang.hasOwnProperty(this.required,i)){s.push(i);}}var p=0;for(;;){var l=s.length,a,b,j,k,moved=false;for(j=p;j&lt;l;j=j+1){a=s[j];for(k=j+1;k&lt;l;k=k+1){if(requires(a,s[k])){b=s.splice(k,1);s.splice(j,0,b[0]);moved=true;break;}}if(moved){break;}else{p=p+1;}}if(!moved){break;}}this.sorted=s;},toString:function(){var o={type:&quot;YUILoader&quot;,base:this.base,filter:this.filter,required:this.required,loaded:this.loaded,inserted:this.inserted};lang.dump(o,1);},_combine:function(){this._combining=[];var self=this,s=this.sorted,len=s.length,js=this.comboBase,css=this.comboBase,target,startLen=js.length,i,m,type=this.loadType;YAHOO.log(&quot;type &quot;+type);for(i=0;i&lt;len;i=i+1){m=this.moduleInfo[s[i]];if(m&amp;&amp;!m.ext&amp;&amp;(!type||type===m.type)){target=this.root+m.path;target+=&quot;&amp;&quot;;if(m.type==&quot;js&quot;){js+=target;}else{css+=target;}this._combining.push(s[
 i]);}}if(this._combining.length){YAHOO.log(&quot;Attempting to combine: &quot;+this._combining,&quot;info&quot;,&quot;loader&quot;);var callback=function(o){var c=this._combining,len=c.length,i,m;for(i=0;i&lt;len;i=i+1){this.inserted[c[i]]=true;}this.loadNext(o.data);},loadScript=function(){if(js.length&gt;startLen){YAHOO.util.Get.script(self._filter(js),{data:self._loading,onSuccess:callback,onFailure:self._onFailure,onTimeout:self._onTimeout,insertBefore:self.insertBefore,charset:self.charset,timeout:self.timeout,scope:self});}else{this.loadNext();}};if(css.length&gt;startLen){YAHOO.util.Get.css(this._filter(css),{data:this._loading,onSuccess:loadScript,onFailure:this._onFailure,onTimeout:this._onTimeout,insertBefore:this.insertBefore,charset:this.charset,timeout:this.timeout,scope:self});}else{loadScript();}return;}else{this.loadNext(this._loading);}},insert:function(o,type){this.calculate(o);this._loading=true;this.loadType=type;if(this.combine){return this._combine();}i
 f(!type){var self=this;this._internalCallback=function(){self._internalCallback=null;self.insert(null,&quot;js&quot;);};this.insert(null,&quot;css&quot;);return;}this.loadNext();},sandbox:function(o,type){var self=this,success=function(o){var idx=o.argument[0],name=o.argument[2];self._scriptText[idx]=o.responseText;if(self.onProgress){self.onProgress.call(self.scope,{name:name,scriptText:o.responseText,xhrResponse:o,data:self.data});}self._loadCount++;if(self._loadCount&gt;=self._stopCount){var v=self.varName||&quot;YAHOO&quot;;var t=&quot;(function() {\n&quot;;var b=&quot;\nreturn &quot;+v+&quot;;\n})();&quot;;var ref=eval(t+self._scriptText.join(&quot;\n&quot;)+b);self._pushEvents(ref);if(ref){self.onSuccess.call(self.scope,{reference:ref,data:self.data});}else{self._onFailure.call(self.varName+&quot; reference failure&quot;);}}},failure=function(o){self.onFailure.call(self.scope,{msg:&quot;XHR failure&quot;,xhrResponse:o,data:self.data});};self._config(o);if(!self.onSucce
 ss){throw new Error(&quot;You must supply an onSuccess handler for your sandbox&quot;);}self._sandbox=true;if(!type||type!==&quot;js&quot;){self._internalCallback=function(){self._internalCallback=null;self.sandbox(null,&quot;js&quot;);};self.insert(null,&quot;css&quot;);return;}if(!util.Connect){var ld=new YAHOO.util.YUILoader();ld.insert({base:self.base,filter:self.filter,require:&quot;connection&quot;,insertBefore:self.insertBefore,charset:self.charset,onSuccess:function(){self.sandbox(null,&quot;js&quot;);},scope:self},&quot;js&quot;);return;}self._scriptText=[];self._loadCount=0;self._stopCount=self.sorted.length;self._xhr=[];self.calculate();var s=self.sorted,l=s.length,i,m,url;for(i=0;i&lt;l;i=i+1){m=self.moduleInfo[s[i]];if(!m){self._onFailure(&quot;undefined module &quot;+m);for(var j=0;j&lt;self._xhr.length;j=j+1){self._xhr[j].abort();}return;}if(m.type!==&quot;js&quot;){self._loadCount++;continue;}url=m.fullpath;url=(url)?self._filter(url):self._url(m.path);var xh
 rData={success:success,failure:failure,scope:self,argument:[i,url,s[i]]};self._xhr.push(util.Connect.asyncRequest(&quot;GET&quot;,url,xhrData));}},loadNext:function(mname){if(!this._loading){return;}var self=this,donext=function(o){self.loadNext(o.data);},successfn,s=this.sorted,len=s.length,i,fn,m,url;if(mname){if(mname!==this._loading){return;}this.inserted[mname]=true;if(this.onProgress){this.onProgress.call(this.scope,{name:mname,data:this.data});}}for(i=0;i&lt;len;i=i+1){if(s[i] in this.inserted){continue;}if(s[i]===this._loading){return;}m=this.moduleInfo[s[i]];if(!m){this.onFailure.call(this.scope,{msg:&quot;undefined module &quot;+m,data:this.data});return;}if(!this.loadType||this.loadType===m.type){successfn=donext;this._loading=s[i];fn=(m.type===&quot;css&quot;)?util.Get.css:util.Get.script;url=m.fullpath;url=(url)?this._filter(url):this._url(m.path);if(env.ua.webkit&amp;&amp;env.ua.webkit&lt;420&amp;&amp;m.type===&quot;js&quot;&amp;&amp;!m.varName){successfn=null;
 this._useYahooListener=true;}fn(url,{data:s[i],onSuccess:successfn,onFailure:this._onFailure,onTimeout:this._onTimeout,insertBefore:this.insertBefore,charset:this.charset,timeout:this.timeout,varName:m.varName,scope:self});return;}}this._loading=null;if(this._internalCallback){var f=this._internalCallback;this._internalCallback=null;f.call(this);}else{if(this.onSuccess){this._pushEvents();this.onSuccess.call(this.scope,{data:this.data});}}},_pushEvents:function(ref){var r=ref||YAHOO;if(r.util&amp;&amp;r.util.Event){r.util.Event._load();}},_filter:function(str){var f=this.filter;return(f)?str.replace(new RegExp(f.searchExp,&quot;g&quot;),f.replaceStr):str;
+},_url:function(path){return this._filter((this.base||&quot;&quot;)+path);}};})();YAHOO.register(&quot;yuiloader&quot;,YAHOO.util.YUILoader,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiyuitestyuitestminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/yuitest/yuitest-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/yuitest/yuitest-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/yuitest/yuitest-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,11 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+YAHOO.namespace(&quot;tool&quot;);(function(){var a=0;YAHOO.tool.TestCase=function(b){this._should={};for(var c in b){this[c]=b[c];}if(!YAHOO.lang.isString(this.name)){this.name=&quot;testCase&quot;+(a++);}};YAHOO.tool.TestCase.prototype={resume:function(b){YAHOO.tool.TestRunner.resume(b);},wait:function(d,c){var b=arguments;if(YAHOO.lang.isFunction(b[0])){throw new YAHOO.tool.TestCase.Wait(b[0],b[1]);}else{throw new YAHOO.tool.TestCase.Wait(function(){YAHOO.util.Assert.fail(&quot;Timeout: wait() called but resume() never called.&quot;);},(YAHOO.lang.isNumber(b[0])?b[0]:10000));}},setUp:function(){},tearDown:function(){}};YAHOO.tool.TestCase.Wait=function(c,b){this.segment=(YAHOO.lang.isFunction(c)?c:null);this.delay=(YAHOO.lang.isNumber(b)?b:0);};})();YAHOO.namespace(&quot;tool&quot;);YAHOO.tool.TestSuite=function(a){this.name=&quot;&quot;;this.items=[];if(YAHOO.lang.isString(a)){this.name=a;}else{if(YAHOO.lang.isObject(a)){YAHOO.lang.augmentObject(this,a,true);}}if(this.na
 me===&quot;&quot;){this.name=YAHOO.util.Dom.generateId(null,&quot;testSuite&quot;);}};YAHOO.tool.TestSuite.prototype={add:function(a){if(a instanceof YAHOO.tool.TestSuite||a instanceof YAHOO.tool.TestCase){this.items.push(a);}},setUp:function(){},tearDown:function(){}};YAHOO.namespace(&quot;tool&quot;);YAHOO.tool.TestRunner=(function(){function b(c){this.testObject=c;this.firstChild=null;this.lastChild=null;this.parent=null;this.next=null;this.results={passed:0,failed:0,total:0,ignored:0,duration:0};if(c instanceof YAHOO.tool.TestSuite){this.results.type=&quot;testsuite&quot;;this.results.name=c.name;}else{if(c instanceof YAHOO.tool.TestCase){this.results.type=&quot;testcase&quot;;this.results.name=c.name;}}}b.prototype={appendChild:function(c){var d=new b(c);if(this.firstChild===null){this.firstChild=this.lastChild=d;}else{this.lastChild.next=d;this.lastChild=d;}d.parent=this;return d;}};function a(){a.superclass.constructor.apply(this,arguments);this.masterSuite=new YAHOO.
 tool.TestSuite(&quot;yuitests&quot;+(new Date()).getTime());this._cur=null;this._root=null;this._running=false;this._lastResults=null;var d=[this.TEST_CASE_BEGIN_EVENT,this.TEST_CASE_COMPLETE_EVENT,this.TEST_SUITE_BEGIN_EVENT,this.TEST_SUITE_COMPLETE_EVENT,this.TEST_PASS_EVENT,this.TEST_FAIL_EVENT,this.TEST_IGNORE_EVENT,this.COMPLETE_EVENT,this.BEGIN_EVENT];for(var c=0;c&lt;d.length;c++){this.createEvent(d[c],{scope:this});}}YAHOO.lang.extend(a,YAHOO.util.EventProvider,{TEST_CASE_BEGIN_EVENT:&quot;testcasebegin&quot;,TEST_CASE_COMPLETE_EVENT:&quot;testcasecomplete&quot;,TEST_SUITE_BEGIN_EVENT:&quot;testsuitebegin&quot;,TEST_SUITE_COMPLETE_EVENT:&quot;testsuitecomplete&quot;,TEST_PASS_EVENT:&quot;pass&quot;,TEST_FAIL_EVENT:&quot;fail&quot;,TEST_IGNORE_EVENT:&quot;ignore&quot;,COMPLETE_EVENT:&quot;complete&quot;,BEGIN_EVENT:&quot;begin&quot;,getName:function(){return this.masterSuite.name;},setName:function(c){this.masterSuite.name=c;},isRunning:function(){return this._running
 ;},getResults:function(c){if(!this._running&amp;&amp;this._lastResults){if(YAHOO.lang.isFunction(c)){return c(this._lastResults);}else{return this._lastResults;}}else{return null;}},getCoverage:function(c){if(!this._running&amp;&amp;typeof _yuitest_coverage==&quot;object&quot;){if(YAHOO.lang.isFunction(c)){return c(_yuitest_coverage);}else{return _yuitest_coverage;}}else{return null;}},getName:function(){return this.masterSuite.name;},setName:function(c){this.masterSuite.name=c;},_addTestCaseToTestTree:function(c,d){var e=c.appendChild(d);for(var f in d){if(f.indexOf(&quot;test&quot;)===0&amp;&amp;YAHOO.lang.isFunction(d[f])){e.appendChild(f);}}},_addTestSuiteToTestTree:function(c,f){var e=c.appendChild(f);for(var d=0;d&lt;f.items.length;d++){if(f.items[d] instanceof YAHOO.tool.TestSuite){this._addTestSuiteToTestTree(e,f.items[d]);}else{if(f.items[d] instanceof YAHOO.tool.TestCase){this._addTestCaseToTestTree(e,f.items[d]);}}}},_buildTestTree:function(){this._root=new b(this
 .masterSuite);for(var c=0;c&lt;this.masterSuite.items.length;c++){if(this.masterSuite.items[c] instanceof YAHOO.tool.TestSuite){this._addTestSuiteToTestTree(this._root,this.masterSuite.items[c]);}else{if(this.masterSuite.items[c] instanceof YAHOO.tool.TestCase){this._addTestCaseToTestTree(this._root,this.masterSuite.items[c]);}}}},_handleTestObjectComplete:function(c){if(YAHOO.lang.isObject(c.testObject)){c.parent.results.passed+=c.results.passed;c.parent.results.failed+=c.results.failed;c.parent.results.total+=c.results.total;c.parent.results.ignored+=c.results.ignored;c.parent.results[c.testObject.name]=c.results;if(c.testObject instanceof YAHOO.tool.TestSuite){c.testObject.tearDown();c.results.duration=(new Date())-c._start;this.fireEvent(this.TEST_SUITE_COMPLETE_EVENT,{testSuite:c.testObject,results:c.results});}else{if(c.testObject instanceof YAHOO.tool.TestCase){c.results.duration=(new Date())-c._start;this.fireEvent(this.TEST_CASE_COMPLETE_EVENT,{testCase:c.testObject
 ,results:c.results});}}}},_next:function(){if(this._cur===null){this._cur=this._root;}else{if(this._cur.firstChild){this._cur=this._cur.firstChild;}else{if(this._cur.next){this._cur=this._cur.next;}else{while(this._cur&amp;&amp;!this._cur.next&amp;&amp;this._cur!==this._root){this._handleTestObjectComplete(this._cur);this._cur=this._cur.parent;}if(this._cur==this._root){this._cur.results.type=&quot;report&quot;;this._cur.results.timestamp=(new Date()).toLocaleString();this._cur.results.duration=(new Date())-this._cur._start;this._lastResults=this._cur.results;this._running=false;this.fireEvent(this.COMPLETE_EVENT,{results:this._lastResults});this._cur=null;}else{this._handleTestObjectComplete(this._cur);this._cur=this._cur.next;}}}}return this._cur;},_run:function(){var e=false;var d=this._next();if(d!==null){this._running=true;this._lastResult=null;var c=d.testObject;if(YAHOO.lang.isObject(c)){if(c instanceof YAHOO.tool.TestSuite){this.fireEvent(this.TEST_SUITE_BEGIN_EVENT,
 {testSuite:c});d._start=new Date();c.setUp();}else{if(c instanceof YAHOO.tool.TestCase){this.fireEvent(this.TEST_CASE_BEGIN_EVENT,{testCase:c});d._start=new Date();}}if(typeof setTimeout!=&quot;undefined&quot;){setTimeout(function(){YAHOO.tool.TestRunner._run();},0);}else{this._run();}}else{this._runTest(d);}}},_resumeTest:function(h){var c=this._cur;var i=c.testObject;
+var f=c.parent.testObject;if(f.__yui_wait){clearTimeout(f.__yui_wait);delete f.__yui_wait;}var l=(f._should.fail||{})[i];var d=(f._should.error||{})[i];var g=false;var j=null;try{h.apply(f);if(l){j=new YAHOO.util.ShouldFail();g=true;}else{if(d){j=new YAHOO.util.ShouldError();g=true;}}}catch(k){if(k instanceof YAHOO.util.AssertionError){if(!l){j=k;g=true;}}else{if(k instanceof YAHOO.tool.TestCase.Wait){if(YAHOO.lang.isFunction(k.segment)){if(YAHOO.lang.isNumber(k.delay)){if(typeof setTimeout!=&quot;undefined&quot;){f.__yui_wait=setTimeout(function(){YAHOO.tool.TestRunner._resumeTest(k.segment);},k.delay);}else{throw new Error(&quot;Asynchronous tests not supported in this environment.&quot;);}}}return;}else{if(!d){j=new YAHOO.util.UnexpectedError(k);g=true;}else{if(YAHOO.lang.isString(d)){if(k.message!=d){j=new YAHOO.util.UnexpectedError(k);g=true;}}else{if(YAHOO.lang.isFunction(d)){if(!(k instanceof d)){j=new YAHOO.util.UnexpectedError(k);g=true;}}else{if(YAHOO.lang.isObject
 (d)){if(!(k instanceof d.constructor)||k.message!=d.message){j=new YAHOO.util.UnexpectedError(k);g=true;}}}}}}}}if(g){this.fireEvent(this.TEST_FAIL_EVENT,{testCase:f,testName:i,error:j});}else{this.fireEvent(this.TEST_PASS_EVENT,{testCase:f,testName:i});}f.tearDown();var e=(new Date())-c._start;c.parent.results[i]={result:g?&quot;fail&quot;:&quot;pass&quot;,message:j?j.getMessage():&quot;Test passed&quot;,type:&quot;test&quot;,name:i,duration:e};if(g){c.parent.results.failed++;}else{c.parent.results.passed++;}c.parent.results.total++;if(typeof setTimeout!=&quot;undefined&quot;){setTimeout(function(){YAHOO.tool.TestRunner._run();},0);}else{this._run();}},_runTest:function(f){var c=f.testObject;var d=f.parent.testObject;var g=d[c];var e=(d._should.ignore||{})[c];if(e){f.parent.results[c]={result:&quot;ignore&quot;,message:&quot;Test ignored&quot;,type:&quot;test&quot;,name:c};f.parent.results.ignored++;f.parent.results.total++;this.fireEvent(this.TEST_IGNORE_EVENT,{testCase:d,
 testName:c});if(typeof setTimeout!=&quot;undefined&quot;){setTimeout(function(){YAHOO.tool.TestRunner._run();},0);}else{this._run();}}else{f._start=new Date();d.setUp();this._resumeTest(g);}},fireEvent:function(c,d){d=d||{};d.type=c;a.superclass.fireEvent.call(this,c,d);},add:function(c){this.masterSuite.add(c);},clear:function(){this.masterSuite=new YAHOO.tool.TestSuite(&quot;yuitests&quot;+(new Date()).getTime());},resume:function(c){this._resumeTest(c||function(){});},run:function(c){var d=YAHOO.tool.TestRunner;if(!c&amp;&amp;this.masterSuite.items.length==1&amp;&amp;this.masterSuite.items[0] instanceof YAHOO.tool.TestSuite){this.masterSuite=this.masterSuite.items[0];}d._buildTestTree();d._root._start=new Date();d.fireEvent(d.BEGIN_EVENT);d._run();}});return new a();})();YAHOO.namespace(&quot;util&quot;);YAHOO.util.Assert={_formatMessage:function(b,a){var c=b;if(YAHOO.lang.isString(b)&amp;&amp;b.length&gt;0){return YAHOO.lang.substitute(b,{message:a});}else{return a;}},fa
 il:function(a){throw new YAHOO.util.AssertionError(this._formatMessage(a,&quot;Test force-failed.&quot;));},areEqual:function(b,c,a){if(b!=c){throw new YAHOO.util.ComparisonFailure(this._formatMessage(a,&quot;Values should be equal.&quot;),b,c);}},areNotEqual:function(a,c,b){if(a==c){throw new YAHOO.util.UnexpectedValue(this._formatMessage(b,&quot;Values should not be equal.&quot;),a);}},areNotSame:function(a,c,b){if(a===c){throw new YAHOO.util.UnexpectedValue(this._formatMessage(b,&quot;Values should not be the same.&quot;),a);}},areSame:function(b,c,a){if(b!==c){throw new YAHOO.util.ComparisonFailure(this._formatMessage(a,&quot;Values should be the same.&quot;),b,c);}},isFalse:function(b,a){if(false!==b){throw new YAHOO.util.ComparisonFailure(this._formatMessage(a,&quot;Value should be false.&quot;),false,b);}},isTrue:function(b,a){if(true!==b){throw new YAHOO.util.ComparisonFailure(this._formatMessage(a,&quot;Value should be true.&quot;),true,b);}},isNaN:function(b,a){if(
 !isNaN(b)){throw new YAHOO.util.ComparisonFailure(this._formatMessage(a,&quot;Value should be NaN.&quot;),NaN,b);}},isNotNaN:function(b,a){if(isNaN(b)){throw new YAHOO.util.UnexpectedValue(this._formatMessage(a,&quot;Values should not be NaN.&quot;),NaN);}},isNotNull:function(b,a){if(YAHOO.lang.isNull(b)){throw new YAHOO.util.UnexpectedValue(this._formatMessage(a,&quot;Values should not be null.&quot;),null);}},isNotUndefined:function(b,a){if(YAHOO.lang.isUndefined(b)){throw new YAHOO.util.UnexpectedValue(this._formatMessage(a,&quot;Value should not be undefined.&quot;),undefined);}},isNull:function(b,a){if(!YAHOO.lang.isNull(b)){throw new YAHOO.util.ComparisonFailure(this._formatMessage(a,&quot;Value should be null.&quot;),null,b);}},isUndefined:function(b,a){if(!YAHOO.lang.isUndefined(b)){throw new YAHOO.util.ComparisonFailure(this._formatMessage(a,&quot;Value should be undefined.&quot;),undefined,b);}},isArray:function(b,a){if(!YAHOO.lang.isArray(b)){throw new YAHOO.util.
 UnexpectedValue(this._formatMessage(a,&quot;Value should be an array.&quot;),b);}},isBoolean:function(b,a){if(!YAHOO.lang.isBoolean(b)){throw new YAHOO.util.UnexpectedValue(this._formatMessage(a,&quot;Value should be a Boolean.&quot;),b);}},isFunction:function(b,a){if(!YAHOO.lang.isFunction(b)){throw new YAHOO.util.UnexpectedValue(this._formatMessage(a,&quot;Value should be a function.&quot;),b);}},isInstanceOf:function(b,c,a){if(!(c instanceof b)){throw new YAHOO.util.ComparisonFailure(this._formatMessage(a,&quot;Value isn't an instance of expected type.&quot;),b,c);}},isNumber:function(b,a){if(!YAHOO.lang.isNumber(b)){throw new YAHOO.util.UnexpectedValue(this._formatMessage(a,&quot;Value should be a number.&quot;),b);}},isObject:function(b,a){if(!YAHOO.lang.isObject(b)){throw new YAHOO.util.UnexpectedValue(this._formatMessage(a,&quot;Value should be an object.&quot;),b);}},isString:function(b,a){if(!YAHOO.lang.isString(b)){throw new YAHOO.util.UnexpectedValue(this._formatM
 essage(a,&quot;Value should be a string.&quot;),b);}},isTypeOf:function(b,c,a){if(typeof c!=b){throw new YAHOO.util.ComparisonFailure(this._formatMessage(a,&quot;Value should be of type &quot;+b+&quot;.&quot;),b,typeof c);}}};YAHOO.util.AssertionError=function(a){this.message=a;this.name=&quot;AssertionError&quot;;};YAHOO.lang.extend(YAHOO.util.AssertionError,Object,{getMessage:function(){return this.message;},toString:function(){return this.name+&quot;: &quot;+this.getMessage();
+}});YAHOO.util.ComparisonFailure=function(b,a,c){YAHOO.util.AssertionError.call(this,b);this.expected=a;this.actual=c;this.name=&quot;ComparisonFailure&quot;;};YAHOO.lang.extend(YAHOO.util.ComparisonFailure,YAHOO.util.AssertionError,{getMessage:function(){return this.message+&quot;\nExpected: &quot;+this.expected+&quot; (&quot;+(typeof this.expected)+&quot;)&quot;+&quot;\nActual:&quot;+this.actual+&quot; (&quot;+(typeof this.actual)+&quot;)&quot;;}});YAHOO.util.UnexpectedValue=function(b,a){YAHOO.util.AssertionError.call(this,b);this.unexpected=a;this.name=&quot;UnexpectedValue&quot;;};YAHOO.lang.extend(YAHOO.util.UnexpectedValue,YAHOO.util.AssertionError,{getMessage:function(){return this.message+&quot;\nUnexpected: &quot;+this.unexpected+&quot; (&quot;+(typeof this.unexpected)+&quot;) &quot;;}});YAHOO.util.ShouldFail=function(a){YAHOO.util.AssertionError.call(this,a||&quot;This test should fail but didn't.&quot;);this.name=&quot;ShouldFail&quot;;};YAHOO.lang.extend(YAHOO.u
 til.ShouldFail,YAHOO.util.AssertionError);YAHOO.util.ShouldError=function(a){YAHOO.util.AssertionError.call(this,a||&quot;This test should have thrown an error but didn't.&quot;);this.name=&quot;ShouldError&quot;;};YAHOO.lang.extend(YAHOO.util.ShouldError,YAHOO.util.AssertionError);YAHOO.util.UnexpectedError=function(a){YAHOO.util.AssertionError.call(this,&quot;Unexpected error: &quot;+a.message);this.cause=a;this.name=&quot;UnexpectedError&quot;;this.stack=a.stack;};YAHOO.lang.extend(YAHOO.util.UnexpectedError,YAHOO.util.AssertionError);YAHOO.util.ArrayAssert={contains:function(e,d,b){var c=false;var f=YAHOO.util.Assert;for(var a=0;a&lt;d.length&amp;&amp;!c;a++){if(d[a]===e){c=true;}}if(!c){f.fail(f._formatMessage(b,&quot;Value &quot;+e+&quot; (&quot;+(typeof e)+&quot;) not found in array [&quot;+d+&quot;].&quot;));}},containsItems:function(c,d,b){for(var a=0;a&lt;c.length;a++){this.contains(c[a],d,b);}},containsMatch:function(e,d,b){if(typeof e!=&quot;function&quot;){throw
  new TypeError(&quot;ArrayAssert.containsMatch(): First argument must be a function.&quot;);}var c=false;var f=YAHOO.util.Assert;for(var a=0;a&lt;d.length&amp;&amp;!c;a++){if(e(d[a])){c=true;}}if(!c){f.fail(f._formatMessage(b,&quot;No match found in array [&quot;+d+&quot;].&quot;));}},doesNotContain:function(e,d,b){var c=false;var f=YAHOO.util.Assert;for(var a=0;a&lt;d.length&amp;&amp;!c;a++){if(d[a]===e){c=true;}}if(c){f.fail(f._formatMessage(b,&quot;Value found in array [&quot;+d+&quot;].&quot;));}},doesNotContainItems:function(c,d,b){for(var a=0;a&lt;c.length;a++){this.doesNotContain(c[a],d,b);}},doesNotContainMatch:function(e,d,b){if(typeof e!=&quot;function&quot;){throw new TypeError(&quot;ArrayAssert.doesNotContainMatch(): First argument must be a function.&quot;);}var c=false;var f=YAHOO.util.Assert;for(var a=0;a&lt;d.length&amp;&amp;!c;a++){if(e(d[a])){c=true;}}if(c){f.fail(f._formatMessage(b,&quot;Value found in array [&quot;+d+&quot;].&quot;));}},indexOf:function(e
 ,d,a,c){for(var b=0;b&lt;d.length;b++){if(d[b]===e){YAHOO.util.Assert.areEqual(a,b,c||&quot;Value exists at index &quot;+b+&quot; but should be at index &quot;+a+&quot;.&quot;);return;}}var f=YAHOO.util.Assert;f.fail(f._formatMessage(c,&quot;Value doesn't exist in array [&quot;+d+&quot;].&quot;));},itemsAreEqual:function(d,f,c){var a=Math.max(d.length,f.length||0);var e=YAHOO.util.Assert;for(var b=0;b&lt;a;b++){e.areEqual(d[b],f[b],e._formatMessage(c,&quot;Values in position &quot;+b+&quot; are not equal.&quot;));}},itemsAreEquivalent:function(e,f,b,d){if(typeof b!=&quot;function&quot;){throw new TypeError(&quot;ArrayAssert.itemsAreEquivalent(): Third argument must be a function.&quot;);}var a=Math.max(e.length,f.length||0);for(var c=0;c&lt;a;c++){if(!b(e[c],f[c])){throw new YAHOO.util.ComparisonFailure(YAHOO.util.Assert._formatMessage(d,&quot;Values in position &quot;+c+&quot; are not equivalent.&quot;),e[c],f[c]);}}},isEmpty:function(c,a){if(c.length&gt;0){var b=YAHOO.util
 .Assert;b.fail(b._formatMessage(a,&quot;Array should be empty.&quot;));}},isNotEmpty:function(c,a){if(c.length===0){var b=YAHOO.util.Assert;b.fail(b._formatMessage(a,&quot;Array should not be empty.&quot;));}},itemsAreSame:function(d,f,c){var a=Math.max(d.length,f.length||0);var e=YAHOO.util.Assert;for(var b=0;b&lt;a;b++){e.areSame(d[b],f[b],e._formatMessage(c,&quot;Values in position &quot;+b+&quot; are not the same.&quot;));}},lastIndexOf:function(e,d,a,c){var f=YAHOO.util.Assert;for(var b=d.length;b&gt;=0;b--){if(d[b]===e){f.areEqual(a,b,f._formatMessage(c,&quot;Value exists at index &quot;+b+&quot; but should be at index &quot;+a+&quot;.&quot;));return;}}f.fail(f._formatMessage(c,&quot;Value doesn't exist in array.&quot;));}};YAHOO.namespace(&quot;util&quot;);YAHOO.util.ObjectAssert={propertiesAreEqual:function(d,g,c){var f=YAHOO.util.Assert;var b=[];for(var e in d){b.push(e);}for(var a=0;a&lt;b.length;a++){f.isNotUndefined(g[b[a]],f._formatMessage(c,&quot;Property '&quo
 t;+b[a]+&quot;' expected.&quot;));}},hasProperty:function(a,b,c){if(!(a in b)){var d=YAHOO.util.Assert;d.fail(d._formatMessage(c,&quot;Property '&quot;+a+&quot;' not found on object.&quot;));}},hasOwnProperty:function(a,b,c){if(!YAHOO.lang.hasOwnProperty(b,a)){var d=YAHOO.util.Assert;d.fail(d._formatMessage(c,&quot;Property '&quot;+a+&quot;' not found on object instance.&quot;));}}};YAHOO.util.DateAssert={datesAreEqual:function(b,d,a){if(b instanceof Date&amp;&amp;d instanceof Date){var c=YAHOO.util.Assert;c.areEqual(b.getFullYear(),d.getFullYear(),c._formatMessage(a,&quot;Years should be equal.&quot;));c.areEqual(b.getMonth(),d.getMonth(),c._formatMessage(a,&quot;Months should be equal.&quot;));c.areEqual(b.getDate(),d.getDate(),c._formatMessage(a,&quot;Day of month should be equal.&quot;));}else{throw new TypeError(&quot;DateAssert.datesAreEqual(): Expected and actual values must be Date objects.&quot;);}},timesAreEqual:function(b,d,a){if(b instanceof Date&amp;&amp;d insta
 nceof Date){var c=YAHOO.util.Assert;c.areEqual(b.getHours(),d.getHours(),c._formatMessage(a,&quot;Hours should be equal.&quot;));c.areEqual(b.getMinutes(),d.getMinutes(),c._formatMessage(a,&quot;Minutes should be equal.&quot;));c.areEqual(b.getSeconds(),d.getSeconds(),c._formatMessage(a,&quot;Seconds should be equal.&quot;));}else{throw new TypeError(&quot;DateAssert.timesAreEqual(): Expected and actual values must be Date objects.&quot;);}}};YAHOO.namespace(&quot;tool&quot;);YAHOO.tool.TestManager={TEST_PAGE_BEGIN_EVENT:&quot;testpagebegin&quot;,TEST_PAGE_COMPLETE_EVENT:&quot;testpagecomplete&quot;,TEST_MANAGER_BEGIN_EVENT:&quot;testmanagerbegin&quot;,TEST_MANAGER_COMPLETE_EVENT:&quot;testmanagercomplete&quot;,_curPage:null,_frame:null,_logger:null,_timeoutId:0,_pages:[],_results:null,_handleTestRunnerComplete:function(a){this.fireEvent(this.TEST_PAGE_COMPLETE_EVENT,{page:this._curPage,results:a.results});
+this._processResults(this._curPage,a.results);this._logger.clearTestRunner();if(this._pages.length){this._timeoutId=setTimeout(function(){YAHOO.tool.TestManager._run();},1000);}else{this.fireEvent(this.TEST_MANAGER_COMPLETE_EVENT,this._results);}},_processResults:function(c,a){var b=this._results;b.passed+=a.passed;b.failed+=a.failed;b.ignored+=a.ignored;b.total+=a.total;b.duration+=a.duration;if(a.failed){b.failedPages.push(c);}else{b.passedPages.push(c);}a.name=c;a.type=&quot;page&quot;;b[c]=a;},_run:function(){this._curPage=this._pages.shift();this.fireEvent(this.TEST_PAGE_BEGIN_EVENT,this._curPage);this._frame.location.replace(this._curPage);},load:function(){if(parent.YAHOO.tool.TestManager!==this){parent.YAHOO.tool.TestManager.load();}else{if(this._frame){var a=this._frame.YAHOO.tool.TestRunner;this._logger.setTestRunner(a);a.subscribe(a.COMPLETE_EVENT,this._handleTestRunnerComplete,this,true);a.run();}}},setPages:function(a){this._pages=a;},start:function(){if(!this._
 initialized){this.createEvent(this.TEST_PAGE_BEGIN_EVENT);this.createEvent(this.TEST_PAGE_COMPLETE_EVENT);this.createEvent(this.TEST_MANAGER_BEGIN_EVENT);this.createEvent(this.TEST_MANAGER_COMPLETE_EVENT);if(!this._frame){var a=document.createElement(&quot;iframe&quot;);a.style.visibility=&quot;hidden&quot;;a.style.position=&quot;absolute&quot;;document.body.appendChild(a);this._frame=a.contentWindow||a.contentDocument.parentWindow;}if(!this._logger){this._logger=new YAHOO.tool.TestLogger();}this._initialized=true;}this._results={passed:0,failed:0,ignored:0,total:0,type:&quot;report&quot;,name:&quot;YUI Test Results&quot;,duration:0,failedPages:[],passedPages:[]};this.fireEvent(this.TEST_MANAGER_BEGIN_EVENT,null);this._run();},stop:function(){clearTimeout(this._timeoutId);}};YAHOO.lang.augmentObject(YAHOO.tool.TestManager,YAHOO.util.EventProvider.prototype);YAHOO.namespace(&quot;tool&quot;);YAHOO.tool.TestLogger=function(b,a){YAHOO.tool.TestLogger.superclass.constructor.call
 (this,b,a);this.init();};YAHOO.lang.extend(YAHOO.tool.TestLogger,YAHOO.widget.LogReader,{footerEnabled:true,newestOnTop:false,formatMsg:function(b){var a=b.category;var c=this.html2Text(b.msg);return'&lt;pre&gt;&lt;p&gt;&lt;span class=&quot;'+a+'&quot;&gt;'+a.toUpperCase()+&quot;&lt;/span&gt; &quot;+c+&quot;&lt;/p&gt;&lt;/pre&gt;&quot;;},init:function(){if(YAHOO.tool.TestRunner){this.setTestRunner(YAHOO.tool.TestRunner);}this.hideSource(&quot;global&quot;);this.hideSource(&quot;LogReader&quot;);this.hideCategory(&quot;warn&quot;);this.hideCategory(&quot;window&quot;);this.hideCategory(&quot;time&quot;);this.clearConsole();},clearTestRunner:function(){if(this._runner){this._runner.unsubscribeAll();this._runner=null;}},setTestRunner:function(a){if(this._runner){this.clearTestRunner();}this._runner=a;a.subscribe(a.TEST_PASS_EVENT,this._handleTestRunnerEvent,this,true);a.subscribe(a.TEST_FAIL_EVENT,this._handleTestRunnerEvent,this,true);a.subscribe(a.TEST_IGNORE_EVENT,this._hand
 leTestRunnerEvent,this,true);a.subscribe(a.BEGIN_EVENT,this._handleTestRunnerEvent,this,true);a.subscribe(a.COMPLETE_EVENT,this._handleTestRunnerEvent,this,true);a.subscribe(a.TEST_SUITE_BEGIN_EVENT,this._handleTestRunnerEvent,this,true);a.subscribe(a.TEST_SUITE_COMPLETE_EVENT,this._handleTestRunnerEvent,this,true);a.subscribe(a.TEST_CASE_BEGIN_EVENT,this._handleTestRunnerEvent,this,true);a.subscribe(a.TEST_CASE_COMPLETE_EVENT,this._handleTestRunnerEvent,this,true);},_handleTestRunnerEvent:function(d){var a=YAHOO.tool.TestRunner;var c=&quot;&quot;;var b=&quot;&quot;;switch(d.type){case a.BEGIN_EVENT:c=&quot;Testing began at &quot;+(new Date()).toString()+&quot;.&quot;;b=&quot;info&quot;;break;case a.COMPLETE_EVENT:c=&quot;Testing completed at &quot;+(new Date()).toString()+&quot;.\nPassed:&quot;+d.results.passed+&quot; Failed:&quot;+d.results.failed+&quot; Total:&quot;+d.results.total;b=&quot;info&quot;;break;case a.TEST_FAIL_EVENT:c=d.testName+&quot;: &quot;+d.error.getMess
 age();b=&quot;fail&quot;;break;case a.TEST_IGNORE_EVENT:c=d.testName+&quot;: ignored.&quot;;b=&quot;ignore&quot;;break;case a.TEST_PASS_EVENT:c=d.testName+&quot;: passed.&quot;;b=&quot;pass&quot;;break;case a.TEST_SUITE_BEGIN_EVENT:c='Test suite &quot;'+d.testSuite.name+'&quot; started.';b=&quot;info&quot;;break;case a.TEST_SUITE_COMPLETE_EVENT:c='Test suite &quot;'+d.testSuite.name+'&quot; completed.\nPassed:'+d.results.passed+&quot; Failed:&quot;+d.results.failed+&quot; Total:&quot;+d.results.total;b=&quot;info&quot;;break;case a.TEST_CASE_BEGIN_EVENT:c='Test case &quot;'+d.testCase.name+'&quot; started.';b=&quot;info&quot;;break;case a.TEST_CASE_COMPLETE_EVENT:c='Test case &quot;'+d.testCase.name+'&quot; completed.\nPassed:'+d.results.passed+&quot; Failed:&quot;+d.results.failed+&quot; Total:&quot;+d.results.total;b=&quot;info&quot;;break;default:c=&quot;Unexpected event &quot;+d.type;c=&quot;info&quot;;}YAHOO.log(c,b,&quot;TestRunner&quot;);}});YAHOO.namespace(&quot;tool
 .TestFormat&quot;);(function(){YAHOO.tool.TestFormat.JSON=function(b){return YAHOO.lang.JSON.stringify(b);};function a(b){return b.replace(/[&quot;'&lt;&gt;&amp;]/g,function(d){switch(d){case&quot;&lt;&quot;:return&quot;&amp;lt;&quot;;case&quot;&gt;&quot;:return&quot;&amp;gt;&quot;;case'&quot;':return&quot;&amp;quot;&quot;;case&quot;'&quot;:return&quot;&amp;apos;&quot;;case&quot;&amp;&quot;:return&quot;&amp;amp;&quot;;}});}YAHOO.tool.TestFormat.XML=function(c){function b(f){var d=YAHOO.lang,e=&quot;&lt;&quot;+f.type+' name=&quot;'+a(f.name)+'&quot;';if(d.isNumber(f.duration)){e+=' duration=&quot;'+f.duration+'&quot;';}if(f.type==&quot;test&quot;){e+=' result=&quot;'+f.result+'&quot; message=&quot;'+a(f.message)+'&quot;&gt;';}else{e+=' passed=&quot;'+f.passed+'&quot; failed=&quot;'+f.failed+'&quot; ignored=&quot;'+f.ignored+'&quot; total=&quot;'+f.total+'&quot;&gt;';for(var g in f){if(d.hasOwnProperty(f,g)&amp;&amp;d.isObject(f[g])&amp;&amp;!d.isArray(f[g])){e+=b(f[g]);}}}e+=
 &quot;&lt;/&quot;+f.type+&quot;&gt;&quot;;return e;}return'&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;'+b(c);};YAHOO.tool.TestFormat.JUnitXML=function(b){function c(f){var d=YAHOO.lang,e=&quot;&quot;,g;switch(f.type){case&quot;test&quot;:if(f.result!=&quot;ignore&quot;){e='&lt;testcase name=&quot;'+a(f.name)+'&quot;&gt;';if(f.result==&quot;fail&quot;){e+='&lt;failure message=&quot;'+a(f.message)+'&quot;&gt;&lt;![CDATA['+f.message+&quot;]]&gt;&lt;/failure&gt;&quot;;}e+=&quot;&lt;/testcase&gt;&quot;;}break;case&quot;testcase&quot;:e='&lt;testsuite name=&quot;'+a(f.name)+'&quot; tests=&quot;'+f.total+'&quot; failures=&quot;'+f.failed+'&quot;&gt;';for(g in f){if(d.hasOwnProperty(f,g)&amp;&amp;d.isObject(f[g])&amp;&amp;!d.isArray(f[g])){e+=c(f[g]);}}e+=&quot;&lt;/testsuite&gt;&quot;;break;case&quot;testsuite&quot;:for(g in f){if(d.hasOwnProperty(f,g)&amp;&amp;d.isObject(f[g])&amp;&amp;!d.isArray(f[g])){e+=c(f[g]);}}break;case&quot;report&quot;:e=&quot;&lt;tes
 tsuites&gt;&quot;;for(g in f){if(d.hasOwnProperty(f,g)&amp;&amp;d.isObject(f[g])&amp;&amp;!d.isArray(f[g])){e+=c(f[g]);}}e+=&quot;&lt;/testsuites&gt;&quot;;}return e;}return'&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;'+c(b);
+};YAHOO.tool.TestFormat.TAP=function(c){var d=1;function b(f){var e=YAHOO.lang,g=&quot;&quot;;switch(f.type){case&quot;test&quot;:if(f.result!=&quot;ignore&quot;){g=&quot;ok &quot;+(d++)+&quot; - &quot;+f.name;if(f.result==&quot;fail&quot;){g=&quot;not &quot;+g+&quot; - &quot;+f.message;}g+=&quot;\n&quot;;}else{g=&quot;#Ignored test &quot;+f.name+&quot;\n&quot;;}break;case&quot;testcase&quot;:g=&quot;#Begin testcase &quot;+f.name+&quot;(&quot;+f.failed+&quot; failed of &quot;+f.total+&quot;)\n&quot;;for(prop in f){if(e.hasOwnProperty(f,prop)&amp;&amp;e.isObject(f[prop])&amp;&amp;!e.isArray(f[prop])){g+=b(f[prop]);}}g+=&quot;#End testcase &quot;+f.name+&quot;\n&quot;;break;case&quot;testsuite&quot;:g=&quot;#Begin testsuite &quot;+f.name+&quot;(&quot;+f.failed+&quot; failed of &quot;+f.total+&quot;)\n&quot;;for(prop in f){if(e.hasOwnProperty(f,prop)&amp;&amp;e.isObject(f[prop])&amp;&amp;!e.isArray(f[prop])){g+=b(f[prop]);}}g+=&quot;#End testsuite &quot;+f.name+&quot;\n&quot;;b
 reak;case&quot;report&quot;:for(prop in f){if(e.hasOwnProperty(f,prop)&amp;&amp;e.isObject(f[prop])&amp;&amp;!e.isArray(f[prop])){g+=b(f[prop]);}}}return g;}return&quot;1..&quot;+c.total+&quot;\n&quot;+b(c);};})();YAHOO.namespace(&quot;tool.CoverageFormat&quot;);YAHOO.tool.CoverageFormat.JSON=function(a){return YAHOO.lang.JSON.stringify(a);};YAHOO.tool.CoverageFormat.XdebugJSON=function(b){var a={},c;for(c in b){if(b.hasOwnProperty(c)){a[c]=b[c].lines;}}return YAHOO.lang.JSON.stringify(a);};YAHOO.namespace(&quot;tool&quot;);YAHOO.tool.TestReporter=function(a,b){this.url=a;this.format=b||YAHOO.tool.TestFormat.XML;this._fields=new Object();this._form=null;this._iframe=null;};YAHOO.tool.TestReporter.prototype={constructor:YAHOO.tool.TestReporter,_convertToISOString:function(a){function b(c){return c&lt;10?&quot;0&quot;+c:c;}return a.getUTCFullYear()+&quot;-&quot;+b(a.getUTCMonth()+1)+&quot;-&quot;+b(a.getUTCDate())+&quot;T&quot;+b(a.getUTCHours())+&quot;:&quot;+b(a.getUTCMinute
 s())+&quot;:&quot;+b(a.getUTCSeconds())+&quot;Z&quot;;},addField:function(a,b){this._fields[a]=b;},clearFields:function(){this._fields=new Object();},destroy:function(){if(this._form){this._form.parentNode.removeChild(this._form);this._form=null;}if(this._iframe){this._iframe.parentNode.removeChild(this._iframe);this._iframe=null;}this._fields=null;},report:function(a){if(!this._form){this._form=document.createElement(&quot;form&quot;);this._form.method=&quot;post&quot;;this._form.style.visibility=&quot;hidden&quot;;this._form.style.position=&quot;absolute&quot;;this._form.style.top=0;document.body.appendChild(this._form);if(YAHOO.env.ua.ie){this._iframe=document.createElement('&lt;iframe name=&quot;yuiTestTarget&quot; /&gt;');}else{this._iframe=document.createElement(&quot;iframe&quot;);this._iframe.name=&quot;yuiTestTarget&quot;;}this._iframe.src=&quot;javascript:false&quot;;this._iframe.style.visibility=&quot;hidden&quot;;this._iframe.style.position=&quot;absolute&quot;;t
 his._iframe.style.top=0;document.body.appendChild(this._iframe);this._form.target=&quot;yuiTestTarget&quot;;}this._form.action=this.url;while(this._form.hasChildNodes()){this._form.removeChild(this._form.lastChild);}this._fields.results=this.format(a);this._fields.useragent=navigator.userAgent;this._fields.timestamp=this._convertToISOString(new Date());for(var b in this._fields){if(YAHOO.lang.hasOwnProperty(this._fields,b)&amp;&amp;typeof this._fields[b]!=&quot;function&quot;){if(YAHOO.env.ua.ie){input=document.createElement('&lt;input name=&quot;'+b+'&quot; &gt;');}else{input=document.createElement(&quot;input&quot;);input.name=b;}input.type=&quot;hidden&quot;;input.value=this._fields[b];this._form.appendChild(input);}}delete this._fields.results;delete this._fields.useragent;delete this._fields.timestamp;if(arguments[1]!==false){this._form.submit();}}};YUITest={TestRunner:YAHOO.tool.TestRunner,ResultsFormat:YAHOO.tool.TestFormat,CoverageFormat:YAHOO.tool.CoverageFormat};YA
 HOO.register(&quot;yuitest&quot;,YAHOO.tool.TestRunner,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsyuiyuitestyuitest_coreminjs"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/js/yui/yuitest/yuitest_core-min.js (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/js/yui/yuitest/yuitest_core-min.js                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/js/yui/yuitest/yuitest_core-min.js        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,9 @@
</span><ins>+/*
+Copyright (c) 2011, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.com/yui/license.html
+version: 2.9.0
+*/
+YAHOO.namespace(&quot;tool&quot;);(function(){var a=0;YAHOO.tool.TestCase=function(b){this._should={};for(var c in b){this[c]=b[c];}if(!YAHOO.lang.isString(this.name)){this.name=&quot;testCase&quot;+(a++);}};YAHOO.tool.TestCase.prototype={resume:function(b){YAHOO.tool.TestRunner.resume(b);},wait:function(d,c){var b=arguments;if(YAHOO.lang.isFunction(b[0])){throw new YAHOO.tool.TestCase.Wait(b[0],b[1]);}else{throw new YAHOO.tool.TestCase.Wait(function(){YAHOO.util.Assert.fail(&quot;Timeout: wait() called but resume() never called.&quot;);},(YAHOO.lang.isNumber(b[0])?b[0]:10000));}},setUp:function(){},tearDown:function(){}};YAHOO.tool.TestCase.Wait=function(c,b){this.segment=(YAHOO.lang.isFunction(c)?c:null);this.delay=(YAHOO.lang.isNumber(b)?b:0);};})();YAHOO.namespace(&quot;tool&quot;);YAHOO.tool.TestSuite=function(a){this.name=&quot;&quot;;this.items=[];if(YAHOO.lang.isString(a)){this.name=a;}else{if(YAHOO.lang.isObject(a)){YAHOO.lang.augmentObject(this,a,true);}}if(this.na
 me===&quot;&quot;){this.name=YAHOO.util.Dom.generateId(null,&quot;testSuite&quot;);}};YAHOO.tool.TestSuite.prototype={add:function(a){if(a instanceof YAHOO.tool.TestSuite||a instanceof YAHOO.tool.TestCase){this.items.push(a);}},setUp:function(){},tearDown:function(){}};YAHOO.namespace(&quot;tool&quot;);YAHOO.tool.TestRunner=(function(){function b(c){this.testObject=c;this.firstChild=null;this.lastChild=null;this.parent=null;this.next=null;this.results={passed:0,failed:0,total:0,ignored:0,duration:0};if(c instanceof YAHOO.tool.TestSuite){this.results.type=&quot;testsuite&quot;;this.results.name=c.name;}else{if(c instanceof YAHOO.tool.TestCase){this.results.type=&quot;testcase&quot;;this.results.name=c.name;}}}b.prototype={appendChild:function(c){var d=new b(c);if(this.firstChild===null){this.firstChild=this.lastChild=d;}else{this.lastChild.next=d;this.lastChild=d;}d.parent=this;return d;}};function a(){a.superclass.constructor.apply(this,arguments);this.masterSuite=new YAHOO.
 tool.TestSuite(&quot;yuitests&quot;+(new Date()).getTime());this._cur=null;this._root=null;this._running=false;this._lastResults=null;var d=[this.TEST_CASE_BEGIN_EVENT,this.TEST_CASE_COMPLETE_EVENT,this.TEST_SUITE_BEGIN_EVENT,this.TEST_SUITE_COMPLETE_EVENT,this.TEST_PASS_EVENT,this.TEST_FAIL_EVENT,this.TEST_IGNORE_EVENT,this.COMPLETE_EVENT,this.BEGIN_EVENT];for(var c=0;c&lt;d.length;c++){this.createEvent(d[c],{scope:this});}}YAHOO.lang.extend(a,YAHOO.util.EventProvider,{TEST_CASE_BEGIN_EVENT:&quot;testcasebegin&quot;,TEST_CASE_COMPLETE_EVENT:&quot;testcasecomplete&quot;,TEST_SUITE_BEGIN_EVENT:&quot;testsuitebegin&quot;,TEST_SUITE_COMPLETE_EVENT:&quot;testsuitecomplete&quot;,TEST_PASS_EVENT:&quot;pass&quot;,TEST_FAIL_EVENT:&quot;fail&quot;,TEST_IGNORE_EVENT:&quot;ignore&quot;,COMPLETE_EVENT:&quot;complete&quot;,BEGIN_EVENT:&quot;begin&quot;,getName:function(){return this.masterSuite.name;},setName:function(c){this.masterSuite.name=c;},isRunning:function(){return this._running
 ;},getResults:function(c){if(!this._running&amp;&amp;this._lastResults){if(YAHOO.lang.isFunction(c)){return c(this._lastResults);}else{return this._lastResults;}}else{return null;}},getCoverage:function(c){if(!this._running&amp;&amp;typeof _yuitest_coverage==&quot;object&quot;){if(YAHOO.lang.isFunction(c)){return c(_yuitest_coverage);}else{return _yuitest_coverage;}}else{return null;}},getName:function(){return this.masterSuite.name;},setName:function(c){this.masterSuite.name=c;},_addTestCaseToTestTree:function(c,d){var e=c.appendChild(d);for(var f in d){if(f.indexOf(&quot;test&quot;)===0&amp;&amp;YAHOO.lang.isFunction(d[f])){e.appendChild(f);}}},_addTestSuiteToTestTree:function(c,f){var e=c.appendChild(f);for(var d=0;d&lt;f.items.length;d++){if(f.items[d] instanceof YAHOO.tool.TestSuite){this._addTestSuiteToTestTree(e,f.items[d]);}else{if(f.items[d] instanceof YAHOO.tool.TestCase){this._addTestCaseToTestTree(e,f.items[d]);}}}},_buildTestTree:function(){this._root=new b(this
 .masterSuite);for(var c=0;c&lt;this.masterSuite.items.length;c++){if(this.masterSuite.items[c] instanceof YAHOO.tool.TestSuite){this._addTestSuiteToTestTree(this._root,this.masterSuite.items[c]);}else{if(this.masterSuite.items[c] instanceof YAHOO.tool.TestCase){this._addTestCaseToTestTree(this._root,this.masterSuite.items[c]);}}}},_handleTestObjectComplete:function(c){if(YAHOO.lang.isObject(c.testObject)){c.parent.results.passed+=c.results.passed;c.parent.results.failed+=c.results.failed;c.parent.results.total+=c.results.total;c.parent.results.ignored+=c.results.ignored;c.parent.results[c.testObject.name]=c.results;if(c.testObject instanceof YAHOO.tool.TestSuite){c.testObject.tearDown();c.results.duration=(new Date())-c._start;this.fireEvent(this.TEST_SUITE_COMPLETE_EVENT,{testSuite:c.testObject,results:c.results});}else{if(c.testObject instanceof YAHOO.tool.TestCase){c.results.duration=(new Date())-c._start;this.fireEvent(this.TEST_CASE_COMPLETE_EVENT,{testCase:c.testObject
 ,results:c.results});}}}},_next:function(){if(this._cur===null){this._cur=this._root;}else{if(this._cur.firstChild){this._cur=this._cur.firstChild;}else{if(this._cur.next){this._cur=this._cur.next;}else{while(this._cur&amp;&amp;!this._cur.next&amp;&amp;this._cur!==this._root){this._handleTestObjectComplete(this._cur);this._cur=this._cur.parent;}if(this._cur==this._root){this._cur.results.type=&quot;report&quot;;this._cur.results.timestamp=(new Date()).toLocaleString();this._cur.results.duration=(new Date())-this._cur._start;this._lastResults=this._cur.results;this._running=false;this.fireEvent(this.COMPLETE_EVENT,{results:this._lastResults});this._cur=null;}else{this._handleTestObjectComplete(this._cur);this._cur=this._cur.next;}}}}return this._cur;},_run:function(){var e=false;var d=this._next();if(d!==null){this._running=true;this._lastResult=null;var c=d.testObject;if(YAHOO.lang.isObject(c)){if(c instanceof YAHOO.tool.TestSuite){this.fireEvent(this.TEST_SUITE_BEGIN_EVENT,
 {testSuite:c});d._start=new Date();c.setUp();}else{if(c instanceof YAHOO.tool.TestCase){this.fireEvent(this.TEST_CASE_BEGIN_EVENT,{testCase:c});d._start=new Date();}}if(typeof setTimeout!=&quot;undefined&quot;){setTimeout(function(){YAHOO.tool.TestRunner._run();},0);}else{this._run();}}else{this._runTest(d);}}},_resumeTest:function(h){var c=this._cur;var i=c.testObject;
+var f=c.parent.testObject;if(f.__yui_wait){clearTimeout(f.__yui_wait);delete f.__yui_wait;}var l=(f._should.fail||{})[i];var d=(f._should.error||{})[i];var g=false;var j=null;try{h.apply(f);if(l){j=new YAHOO.util.ShouldFail();g=true;}else{if(d){j=new YAHOO.util.ShouldError();g=true;}}}catch(k){if(k instanceof YAHOO.util.AssertionError){if(!l){j=k;g=true;}}else{if(k instanceof YAHOO.tool.TestCase.Wait){if(YAHOO.lang.isFunction(k.segment)){if(YAHOO.lang.isNumber(k.delay)){if(typeof setTimeout!=&quot;undefined&quot;){f.__yui_wait=setTimeout(function(){YAHOO.tool.TestRunner._resumeTest(k.segment);},k.delay);}else{throw new Error(&quot;Asynchronous tests not supported in this environment.&quot;);}}}return;}else{if(!d){j=new YAHOO.util.UnexpectedError(k);g=true;}else{if(YAHOO.lang.isString(d)){if(k.message!=d){j=new YAHOO.util.UnexpectedError(k);g=true;}}else{if(YAHOO.lang.isFunction(d)){if(!(k instanceof d)){j=new YAHOO.util.UnexpectedError(k);g=true;}}else{if(YAHOO.lang.isObject
 (d)){if(!(k instanceof d.constructor)||k.message!=d.message){j=new YAHOO.util.UnexpectedError(k);g=true;}}}}}}}}if(g){this.fireEvent(this.TEST_FAIL_EVENT,{testCase:f,testName:i,error:j});}else{this.fireEvent(this.TEST_PASS_EVENT,{testCase:f,testName:i});}f.tearDown();var e=(new Date())-c._start;c.parent.results[i]={result:g?&quot;fail&quot;:&quot;pass&quot;,message:j?j.getMessage():&quot;Test passed&quot;,type:&quot;test&quot;,name:i,duration:e};if(g){c.parent.results.failed++;}else{c.parent.results.passed++;}c.parent.results.total++;if(typeof setTimeout!=&quot;undefined&quot;){setTimeout(function(){YAHOO.tool.TestRunner._run();},0);}else{this._run();}},_runTest:function(f){var c=f.testObject;var d=f.parent.testObject;var g=d[c];var e=(d._should.ignore||{})[c];if(e){f.parent.results[c]={result:&quot;ignore&quot;,message:&quot;Test ignored&quot;,type:&quot;test&quot;,name:c};f.parent.results.ignored++;f.parent.results.total++;this.fireEvent(this.TEST_IGNORE_EVENT,{testCase:d,
 testName:c});if(typeof setTimeout!=&quot;undefined&quot;){setTimeout(function(){YAHOO.tool.TestRunner._run();},0);}else{this._run();}}else{f._start=new Date();d.setUp();this._resumeTest(g);}},fireEvent:function(c,d){d=d||{};d.type=c;a.superclass.fireEvent.call(this,c,d);},add:function(c){this.masterSuite.add(c);},clear:function(){this.masterSuite=new YAHOO.tool.TestSuite(&quot;yuitests&quot;+(new Date()).getTime());},resume:function(c){this._resumeTest(c||function(){});},run:function(c){var d=YAHOO.tool.TestRunner;if(!c&amp;&amp;this.masterSuite.items.length==1&amp;&amp;this.masterSuite.items[0] instanceof YAHOO.tool.TestSuite){this.masterSuite=this.masterSuite.items[0];}d._buildTestTree();d._root._start=new Date();d.fireEvent(d.BEGIN_EVENT);d._run();}});return new a();})();YAHOO.namespace(&quot;util&quot;);YAHOO.util.Assert={_formatMessage:function(b,a){var c=b;if(YAHOO.lang.isString(b)&amp;&amp;b.length&gt;0){return YAHOO.lang.substitute(b,{message:a});}else{return a;}},fa
 il:function(a){throw new YAHOO.util.AssertionError(this._formatMessage(a,&quot;Test force-failed.&quot;));},areEqual:function(b,c,a){if(b!=c){throw new YAHOO.util.ComparisonFailure(this._formatMessage(a,&quot;Values should be equal.&quot;),b,c);}},areNotEqual:function(a,c,b){if(a==c){throw new YAHOO.util.UnexpectedValue(this._formatMessage(b,&quot;Values should not be equal.&quot;),a);}},areNotSame:function(a,c,b){if(a===c){throw new YAHOO.util.UnexpectedValue(this._formatMessage(b,&quot;Values should not be the same.&quot;),a);}},areSame:function(b,c,a){if(b!==c){throw new YAHOO.util.ComparisonFailure(this._formatMessage(a,&quot;Values should be the same.&quot;),b,c);}},isFalse:function(b,a){if(false!==b){throw new YAHOO.util.ComparisonFailure(this._formatMessage(a,&quot;Value should be false.&quot;),false,b);}},isTrue:function(b,a){if(true!==b){throw new YAHOO.util.ComparisonFailure(this._formatMessage(a,&quot;Value should be true.&quot;),true,b);}},isNaN:function(b,a){if(
 !isNaN(b)){throw new YAHOO.util.ComparisonFailure(this._formatMessage(a,&quot;Value should be NaN.&quot;),NaN,b);}},isNotNaN:function(b,a){if(isNaN(b)){throw new YAHOO.util.UnexpectedValue(this._formatMessage(a,&quot;Values should not be NaN.&quot;),NaN);}},isNotNull:function(b,a){if(YAHOO.lang.isNull(b)){throw new YAHOO.util.UnexpectedValue(this._formatMessage(a,&quot;Values should not be null.&quot;),null);}},isNotUndefined:function(b,a){if(YAHOO.lang.isUndefined(b)){throw new YAHOO.util.UnexpectedValue(this._formatMessage(a,&quot;Value should not be undefined.&quot;),undefined);}},isNull:function(b,a){if(!YAHOO.lang.isNull(b)){throw new YAHOO.util.ComparisonFailure(this._formatMessage(a,&quot;Value should be null.&quot;),null,b);}},isUndefined:function(b,a){if(!YAHOO.lang.isUndefined(b)){throw new YAHOO.util.ComparisonFailure(this._formatMessage(a,&quot;Value should be undefined.&quot;),undefined,b);}},isArray:function(b,a){if(!YAHOO.lang.isArray(b)){throw new YAHOO.util.
 UnexpectedValue(this._formatMessage(a,&quot;Value should be an array.&quot;),b);}},isBoolean:function(b,a){if(!YAHOO.lang.isBoolean(b)){throw new YAHOO.util.UnexpectedValue(this._formatMessage(a,&quot;Value should be a Boolean.&quot;),b);}},isFunction:function(b,a){if(!YAHOO.lang.isFunction(b)){throw new YAHOO.util.UnexpectedValue(this._formatMessage(a,&quot;Value should be a function.&quot;),b);}},isInstanceOf:function(b,c,a){if(!(c instanceof b)){throw new YAHOO.util.ComparisonFailure(this._formatMessage(a,&quot;Value isn't an instance of expected type.&quot;),b,c);}},isNumber:function(b,a){if(!YAHOO.lang.isNumber(b)){throw new YAHOO.util.UnexpectedValue(this._formatMessage(a,&quot;Value should be a number.&quot;),b);}},isObject:function(b,a){if(!YAHOO.lang.isObject(b)){throw new YAHOO.util.UnexpectedValue(this._formatMessage(a,&quot;Value should be an object.&quot;),b);}},isString:function(b,a){if(!YAHOO.lang.isString(b)){throw new YAHOO.util.UnexpectedValue(this._formatM
 essage(a,&quot;Value should be a string.&quot;),b);}},isTypeOf:function(b,c,a){if(typeof c!=b){throw new YAHOO.util.ComparisonFailure(this._formatMessage(a,&quot;Value should be of type &quot;+b+&quot;.&quot;),b,typeof c);}}};YAHOO.util.AssertionError=function(a){this.message=a;this.name=&quot;AssertionError&quot;;};YAHOO.lang.extend(YAHOO.util.AssertionError,Object,{getMessage:function(){return this.message;},toString:function(){return this.name+&quot;: &quot;+this.getMessage();
+}});YAHOO.util.ComparisonFailure=function(b,a,c){YAHOO.util.AssertionError.call(this,b);this.expected=a;this.actual=c;this.name=&quot;ComparisonFailure&quot;;};YAHOO.lang.extend(YAHOO.util.ComparisonFailure,YAHOO.util.AssertionError,{getMessage:function(){return this.message+&quot;\nExpected: &quot;+this.expected+&quot; (&quot;+(typeof this.expected)+&quot;)&quot;+&quot;\nActual:&quot;+this.actual+&quot; (&quot;+(typeof this.actual)+&quot;)&quot;;}});YAHOO.util.UnexpectedValue=function(b,a){YAHOO.util.AssertionError.call(this,b);this.unexpected=a;this.name=&quot;UnexpectedValue&quot;;};YAHOO.lang.extend(YAHOO.util.UnexpectedValue,YAHOO.util.AssertionError,{getMessage:function(){return this.message+&quot;\nUnexpected: &quot;+this.unexpected+&quot; (&quot;+(typeof this.unexpected)+&quot;) &quot;;}});YAHOO.util.ShouldFail=function(a){YAHOO.util.AssertionError.call(this,a||&quot;This test should fail but didn't.&quot;);this.name=&quot;ShouldFail&quot;;};YAHOO.lang.extend(YAHOO.u
 til.ShouldFail,YAHOO.util.AssertionError);YAHOO.util.ShouldError=function(a){YAHOO.util.AssertionError.call(this,a||&quot;This test should have thrown an error but didn't.&quot;);this.name=&quot;ShouldError&quot;;};YAHOO.lang.extend(YAHOO.util.ShouldError,YAHOO.util.AssertionError);YAHOO.util.UnexpectedError=function(a){YAHOO.util.AssertionError.call(this,&quot;Unexpected error: &quot;+a.message);this.cause=a;this.name=&quot;UnexpectedError&quot;;this.stack=a.stack;};YAHOO.lang.extend(YAHOO.util.UnexpectedError,YAHOO.util.AssertionError);YAHOO.util.ArrayAssert={contains:function(e,d,b){var c=false;var f=YAHOO.util.Assert;for(var a=0;a&lt;d.length&amp;&amp;!c;a++){if(d[a]===e){c=true;}}if(!c){f.fail(f._formatMessage(b,&quot;Value &quot;+e+&quot; (&quot;+(typeof e)+&quot;) not found in array [&quot;+d+&quot;].&quot;));}},containsItems:function(c,d,b){for(var a=0;a&lt;c.length;a++){this.contains(c[a],d,b);}},containsMatch:function(e,d,b){if(typeof e!=&quot;function&quot;){throw
  new TypeError(&quot;ArrayAssert.containsMatch(): First argument must be a function.&quot;);}var c=false;var f=YAHOO.util.Assert;for(var a=0;a&lt;d.length&amp;&amp;!c;a++){if(e(d[a])){c=true;}}if(!c){f.fail(f._formatMessage(b,&quot;No match found in array [&quot;+d+&quot;].&quot;));}},doesNotContain:function(e,d,b){var c=false;var f=YAHOO.util.Assert;for(var a=0;a&lt;d.length&amp;&amp;!c;a++){if(d[a]===e){c=true;}}if(c){f.fail(f._formatMessage(b,&quot;Value found in array [&quot;+d+&quot;].&quot;));}},doesNotContainItems:function(c,d,b){for(var a=0;a&lt;c.length;a++){this.doesNotContain(c[a],d,b);}},doesNotContainMatch:function(e,d,b){if(typeof e!=&quot;function&quot;){throw new TypeError(&quot;ArrayAssert.doesNotContainMatch(): First argument must be a function.&quot;);}var c=false;var f=YAHOO.util.Assert;for(var a=0;a&lt;d.length&amp;&amp;!c;a++){if(e(d[a])){c=true;}}if(c){f.fail(f._formatMessage(b,&quot;Value found in array [&quot;+d+&quot;].&quot;));}},indexOf:function(e
 ,d,a,c){for(var b=0;b&lt;d.length;b++){if(d[b]===e){YAHOO.util.Assert.areEqual(a,b,c||&quot;Value exists at index &quot;+b+&quot; but should be at index &quot;+a+&quot;.&quot;);return;}}var f=YAHOO.util.Assert;f.fail(f._formatMessage(c,&quot;Value doesn't exist in array [&quot;+d+&quot;].&quot;));},itemsAreEqual:function(d,f,c){var a=Math.max(d.length,f.length||0);var e=YAHOO.util.Assert;for(var b=0;b&lt;a;b++){e.areEqual(d[b],f[b],e._formatMessage(c,&quot;Values in position &quot;+b+&quot; are not equal.&quot;));}},itemsAreEquivalent:function(e,f,b,d){if(typeof b!=&quot;function&quot;){throw new TypeError(&quot;ArrayAssert.itemsAreEquivalent(): Third argument must be a function.&quot;);}var a=Math.max(e.length,f.length||0);for(var c=0;c&lt;a;c++){if(!b(e[c],f[c])){throw new YAHOO.util.ComparisonFailure(YAHOO.util.Assert._formatMessage(d,&quot;Values in position &quot;+c+&quot; are not equivalent.&quot;),e[c],f[c]);}}},isEmpty:function(c,a){if(c.length&gt;0){var b=YAHOO.util
 .Assert;b.fail(b._formatMessage(a,&quot;Array should be empty.&quot;));}},isNotEmpty:function(c,a){if(c.length===0){var b=YAHOO.util.Assert;b.fail(b._formatMessage(a,&quot;Array should not be empty.&quot;));}},itemsAreSame:function(d,f,c){var a=Math.max(d.length,f.length||0);var e=YAHOO.util.Assert;for(var b=0;b&lt;a;b++){e.areSame(d[b],f[b],e._formatMessage(c,&quot;Values in position &quot;+b+&quot; are not the same.&quot;));}},lastIndexOf:function(e,d,a,c){var f=YAHOO.util.Assert;for(var b=d.length;b&gt;=0;b--){if(d[b]===e){f.areEqual(a,b,f._formatMessage(c,&quot;Value exists at index &quot;+b+&quot; but should be at index &quot;+a+&quot;.&quot;));return;}}f.fail(f._formatMessage(c,&quot;Value doesn't exist in array.&quot;));}};YAHOO.namespace(&quot;util&quot;);YAHOO.util.ObjectAssert={propertiesAreEqual:function(d,g,c){var f=YAHOO.util.Assert;var b=[];for(var e in d){b.push(e);}for(var a=0;a&lt;b.length;a++){f.isNotUndefined(g[b[a]],f._formatMessage(c,&quot;Property '&quo
 t;+b[a]+&quot;' expected.&quot;));}},hasProperty:function(a,b,c){if(!(a in b)){var d=YAHOO.util.Assert;d.fail(d._formatMessage(c,&quot;Property '&quot;+a+&quot;' not found on object.&quot;));}},hasOwnProperty:function(a,b,c){if(!YAHOO.lang.hasOwnProperty(b,a)){var d=YAHOO.util.Assert;d.fail(d._formatMessage(c,&quot;Property '&quot;+a+&quot;' not found on object instance.&quot;));}}};YAHOO.util.DateAssert={datesAreEqual:function(b,d,a){if(b instanceof Date&amp;&amp;d instanceof Date){var c=YAHOO.util.Assert;c.areEqual(b.getFullYear(),d.getFullYear(),c._formatMessage(a,&quot;Years should be equal.&quot;));c.areEqual(b.getMonth(),d.getMonth(),c._formatMessage(a,&quot;Months should be equal.&quot;));c.areEqual(b.getDate(),d.getDate(),c._formatMessage(a,&quot;Day of month should be equal.&quot;));}else{throw new TypeError(&quot;DateAssert.datesAreEqual(): Expected and actual values must be Date objects.&quot;);}},timesAreEqual:function(b,d,a){if(b instanceof Date&amp;&amp;d insta
 nceof Date){var c=YAHOO.util.Assert;c.areEqual(b.getHours(),d.getHours(),c._formatMessage(a,&quot;Hours should be equal.&quot;));c.areEqual(b.getMinutes(),d.getMinutes(),c._formatMessage(a,&quot;Minutes should be equal.&quot;));c.areEqual(b.getSeconds(),d.getSeconds(),c._formatMessage(a,&quot;Seconds should be equal.&quot;));}else{throw new TypeError(&quot;DateAssert.timesAreEqual(): Expected and actual values must be Date objects.&quot;);}}};YAHOO.register(&quot;yuitest_core&quot;,YAHOO.tool.TestRunner,{version:&quot;2.9.0&quot;,build:&quot;2800&quot;});
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgjsonrpccgi"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/jsonrpc.cgi (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/jsonrpc.cgi                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/jsonrpc.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,41 @@
</span><ins>+#!/usr/bin/env perl -wT
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla JSON Webservices Interface.
+#
+# The Initial Developer of the Original Code is the San Jose State
+# University Foundation. Portions created by the Initial Developer 
+# are Copyright (C) 2008 the Initial Developer. All Rights Reserved.
+#
+# Contributor(s): 
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+use strict;
+use lib qw(. lib);
+
+use Bugzilla;
+use Bugzilla::Constants;
+use Bugzilla::Error;
+use Bugzilla::WebService::Constants;
+BEGIN {
+    if (!Bugzilla-&gt;feature('jsonrpc')) {
+        ThrowCodeError('feature_disabled', { feature =&gt; 'jsonrpc' });
+    }
+}
+use Bugzilla::WebService::Server::JSONRPC;
+
+Bugzilla-&gt;usage_mode(USAGE_MODE_JSON);
+
+local @INC = (bz_locations()-&gt;{extensionsdir}, @INC);
+my $server = new Bugzilla::WebService::Server::JSONRPC;
+$server-&gt;dispatch(WS_DISPATCH)-&gt;handle();
</ins><span class="cx">Property changes on: trunk/Websites/bugs.webkit.org/jsonrpc.cgi
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkWebsitesbugswebkitorglong_listcgi"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/long_list.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/long_list.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/long_list.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,36 +0,0 @@
</span><del>-#!/usr/bin/env perl -wT
-# -*- Mode: perl; indent-tabs-mode: nil -*-
-#
-# The contents of this file are subject to the Mozilla Public
-# License Version 1.1 (the &quot;License&quot;); you may not use this file
-# except in compliance with the License. You may obtain a copy of
-# the License at http://www.mozilla.org/MPL/
-#
-# Software distributed under the License is distributed on an &quot;AS
-# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
-# implied. See the License for the specific language governing
-# rights and limitations under the License.
-#
-# The Original Code is the Bugzilla Bug Tracking System.
-#
-# The Initial Developer of the Original Code is Netscape Communications
-# Corporation. Portions created by Netscape are
-# Copyright (C) 1998 Netscape Communications Corporation. All
-# Rights Reserved.
-#
-# Contributor(s): Terry Weissman &lt;terry@mozilla.org&gt;
-#                 Gervase Markham &lt;gerv@gerv.net&gt;
-
-use strict;
-use lib qw(. lib);
-use Bugzilla;
-
-my $cgi = Bugzilla-&gt;cgi;
-
-# Convert comma/space separated elements into separate params
-my $buglist = $cgi-&gt;param('buglist') || $cgi-&gt;param('bug_id') || $cgi-&gt;param('id');
-my @ids = split (/[\s,]+/, $buglist);
-
-my $ids = join('', map { $_ = &quot;&amp;id=&quot; . $_ } @ids);
-
-print $cgi-&gt;redirect(&quot;show_bug.cgi?format=multiple$ids&quot;);
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgmigratepl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/migrate.pl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/migrate.pl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/migrate.pl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,110 @@
</span><ins>+#!/usr/bin/env perl -w
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is The Bugzilla Migration Tool.
+#
+# The Initial Developer of the Original Code is Lambda Research
+# Corporation. Portions created by the Initial Developer are Copyright
+# (C) 2009 the Initial Developer. All Rights Reserved.
+#
+# Contributor(s): 
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+use strict;
+use File::Basename;
+BEGIN { chdir dirname($0); }
+use lib qw(. lib);
+use Bugzilla;
+use Bugzilla::Migrate;
+
+use Getopt::Long;
+use Pod::Usage;
+
+my %switch;
+GetOptions(\%switch, 'help|h|?', 'from=s', 'verbose|v+', 'dry-run');
+
+# Print the help message if that switch was selected or if --from
+# wasn't specified.
+if (!$switch{'from'} or $switch{'help'}) {
+    pod2usage({-exitval =&gt; 1});
+}
+
+my $migrator = Bugzilla::Migrate-&gt;load($switch{'from'});
+$migrator-&gt;verbose($switch{'verbose'});
+$migrator-&gt;dry_run($switch{'dry-run'});
+$migrator-&gt;check_requirements();
+$migrator-&gt;do_migration();
+
+# Even if there's an error, we want to be sure that the serial values
+# get reset properly.
+END {
+    if ($migrator and $migrator-&gt;dry_run) {
+        my $dbh = Bugzilla-&gt;dbh;
+        if ($dbh-&gt;bz_in_transaction) {
+            $dbh-&gt;bz_rollback_transaction();
+        }
+        $migrator-&gt;reset_serial_values();
+    }
+}
+
+__END__
+
+=head1 NAME
+
+migrate.pl - A script to migrate from other bug-trackers to Bugzilla.
+
+=head1 SYNOPSIS
+
+ ./migrate.pl --from=&lt;tracker&gt; [--verbose] [--dry-run]
+
+ Migrates from another bug-tracker to Bugzilla. If you want
+ to upgrade Bugzilla, use checksetup.pl instead.
+
+ Always test this on a backup copy of your database before
+ running it on your live Bugzilla.
+
+=head1 OPTIONS
+
+=over
+
+=item B&lt;--from=tracker&gt;
+
+Specifies what bug-tracker you're migrating from. To see what values
+are valid, see the contents of the F&lt;Bugzilla/Migrate/&gt; directory.
+
+=item B&lt;--dry-run&gt;
+
+Don't modify the Bugzilla database at all, just test the import.
+Note that this could cause significant slowdown and other strange effects
+on a live Bugzilla, so only use it on a test instance.
+
+=item B&lt;--verbose&gt;
+
+If specified, this script will output extra debugging information
+to STDERR. Specify multiple times (up to three) for more information.
+
+=back
+
+=head1 DESCRIPTION
+
+This script copies data from another bug-tracker into Bugzilla. It migrates
+users, products, and bugs from the other bug-tracker into this Bugzilla,
+without removing any of the data currently in this Bugzilla.
+
+Note that you will need enough space in your temporary directory to hold
+the size of all attachments in your current bug-tracker.
+
+You may also need to increase the number of file handles a process is allowed
+to hold open (as the migrator will create a file handle for each attachment
+in your database). On Linux and simliar systems, you can do this as root
+by typing C&lt;ulimit -n 65535&gt; before running your script.
</ins><span class="cx">Property changes on: trunk/Websites/bugs.webkit.org/migrate.pl
</span><span class="cx">___________________________________________________________________
</span></span></pre></div>
<a id="svnexecutable"></a>
<div class="addfile"><h4>Added: svn:executable</h4></div>
<a id="trunkWebsitesbugswebkitorgmod_perlpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/mod_perl.pl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/mod_perl.pl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/mod_perl.pl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -15,44 +15,57 @@
</span><span class="cx"> #
</span><span class="cx"> # Contributor(s): Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
</span><span class="cx"> 
</span><del>-use lib qw(/var/www/html);
</del><ins>+use lib qw(/var/www/html); # WEBKIT_CHANGES
</ins><span class="cx"> package Bugzilla::ModPerl;
</span><del>-
</del><span class="cx"> use strict;
</span><ins>+use warnings;
</ins><span class="cx"> 
</span><ins>+# This sets up our libpath without having to specify it in the mod_perl
+# configuration.
+use File::Basename;
+use lib dirname(__FILE__);
+use Bugzilla::Constants ();
+use lib Bugzilla::Constants::bz_locations()-&gt;{'ext_libpath'};
+
</ins><span class="cx"> # If you have an Apache2::Status handler in your Apache configuration,
</span><del>-# you need to load Apache2::Status *here*, so that Apache::DBI can
-# report information to Apache2::Status.
</del><ins>+# you need to load Apache2::Status *here*, so that any later-loaded modules
+# can report information to Apache2::Status.
</ins><span class="cx"> #use Apache2::Status ();
</span><span class="cx"> 
</span><span class="cx"> # We don't want to import anything into the global scope during
</span><span class="cx"> # startup, so we always specify () after using any module in this
</span><span class="cx"> # file.
</span><span class="cx"> 
</span><ins>+use Apache2::Log ();
</ins><span class="cx"> use Apache2::ServerUtil;
</span><del>-use Apache2::SizeLimit;
</del><span class="cx"> use ModPerl::RegistryLoader ();
</span><del>-use CGI ();
-CGI-&gt;compile(qw(:cgi -no_xhtml -oldstyle_urls :private_tempfiles
-                :unique_headers SERVER_PUSH :push));
-use Template::Config ();
-Template::Config-&gt;preload();
</del><ins>+use File::Basename ();
</ins><span class="cx"> 
</span><ins>+# This loads most of our modules.
</ins><span class="cx"> use Bugzilla ();
</span><del>-use Bugzilla::Constants ();
</del><ins>+# Loading Bugzilla.pm doesn't load this, though, and we want it preloaded.
+use Bugzilla::BugMail ();
</ins><span class="cx"> use Bugzilla::CGI ();
</span><del>-use Bugzilla::Mailer ();
-use Bugzilla::Template ();
</del><ins>+use Bugzilla::Extension ();
+use Bugzilla::Install::Requirements ();
</ins><span class="cx"> use Bugzilla::Util ();
</span><ins>+use Bugzilla::RNG ();
</ins><span class="cx"> 
</span><del>-# For PerlChildInitHandler
-eval { require Math::Random::Secure };
</del><ins>+# Make warnings go to the virtual host's log and not the main
+# server log.
+BEGIN { *CORE::GLOBAL::warn = \&amp;Apache2::ServerRec::warn; }
</ins><span class="cx"> 
</span><ins>+# Pre-compile the CGI.pm methods that we're going to use.
+Bugzilla::CGI-&gt;compile(qw(:cgi :push));
+
+use Apache2::SizeLimit;
+# This means that every httpd child will die after processing
+# a CGI if it is taking up more than 45MB of RAM all by itself,
+# not counting RAM it is sharing with the other httpd processes.
</ins><span class="cx"> #if WEBKIT_CHANGES
</span><del>-# This means that every httpd child will die after processing
-# a CGI if it is taking up more than 700MB of RAM all by itself.
-# our children are normally about 400MB 
-$Apache2::SizeLimit::MAX_UNSHARED_SIZE = 700000;
</del><ins>+# bugs.webkit.org children are normally about 400MB.
+#Apache2::SizeLimit-&gt;set_max_unshared_size(45_000);
+Apache2::SizeLimit-&gt;set_max_unshared_size(700_000);
</ins><span class="cx"> #endif // WEBKIT_CHANGES
</span><span class="cx"> 
</span><span class="cx"> my $cgi_path = Bugzilla::Constants::bz_locations()-&gt;{'cgi_path'};
</span><span class="lines">@@ -61,41 +74,51 @@
</span><span class="cx"> my $server = Apache2::ServerUtil-&gt;server;
</span><span class="cx"> my $conf = &lt;&lt;EOT;
</span><span class="cx"> # Make sure each httpd child receives a different random seed (bug 476622).
</span><del>-# Math::Random::Secure has one srand that needs to be called for
</del><ins>+# Bugzilla::RNG has one srand that needs to be called for
</ins><span class="cx"> # every process, and Perl has another. (Various Perl modules still use
</span><del>-# the built-in rand(), even though we only use Math::Random::Secure in
-# Bugzilla itself, so we need to srand() both of them.) However, 
-# Math::Random::Secure may not be installed, so we call its srand in an
-# eval.
-PerlChildInitHandler &quot;sub { eval { Math::Random::Secure::srand() }; srand(); }&quot;
</del><ins>+# the built-in rand(), even though we never use it in Bugzilla itself,
+# so we need to srand() both of them.)
+PerlChildInitHandler &quot;sub { Bugzilla::RNG::srand(); srand(); }&quot;
</ins><span class="cx"> &lt;Directory &quot;$cgi_path&quot;&gt;
</span><span class="cx">     AddHandler perl-script .cgi
</span><span class="cx">     # No need to PerlModule these because they're already defined in mod_perl.pl
</span><span class="cx">     PerlResponseHandler Bugzilla::ModPerl::ResponseHandler
</span><del>-    PerlCleanupHandler  Bugzilla::ModPerl::CleanupHandler
-    PerlCleanupHandler  Apache2::SizeLimit
</del><ins>+    PerlCleanupHandler  Apache2::SizeLimit Bugzilla::ModPerl::CleanupHandler
</ins><span class="cx">     PerlOptions +ParseHeaders
</span><span class="cx">     Options +ExecCGI
</span><del>-    AllowOverride Limit
</del><ins>+    AllowOverride Limit FileInfo Indexes
</ins><span class="cx">     DirectoryIndex index.cgi index.html
</span><span class="cx"> &lt;/Directory&gt;
</span><span class="cx"> EOT
</span><span class="cx"> 
</span><span class="cx"> $server-&gt;add_config([split(&quot;\n&quot;, $conf)]);
</span><span class="cx"> 
</span><ins>+# Pre-load all extensions
+$Bugzilla::extension_packages = Bugzilla::Extension-&gt;load_all();
+
</ins><span class="cx"> # Have ModPerl::RegistryLoader pre-compile all CGI scripts.
</span><span class="cx"> my $rl = new ModPerl::RegistryLoader();
</span><span class="cx"> # If we try to do this in &quot;new&quot; it fails because it looks for a 
</span><span class="cx"> # Bugzilla/ModPerl/ResponseHandler.pm
</span><span class="cx"> $rl-&gt;{package} = 'Bugzilla::ModPerl::ResponseHandler';
</span><del>-# Note that $cgi_path will be wrong if somebody puts the libraries
-# in a different place than the CGIs.
</del><ins>+my $feature_files = Bugzilla::Install::Requirements::map_files_to_features();
+
+# Prevent &quot;use lib&quot; from doing anything when the .cgi files are compiled.
+# This is important to prevent the current directory from getting into
+# @INC and messing things up. (See bug 630750.)
+no warnings 'redefine';
+local *lib::import = sub {};
+use warnings;
+
</ins><span class="cx"> foreach my $file (glob &quot;$cgi_path/*.cgi&quot;) {
</span><ins>+    my $base_filename = File::Basename::basename($file);
+    if (my $feature = $feature_files-&gt;{$base_filename}) {
+        next if !Bugzilla-&gt;feature($feature);
+    }
</ins><span class="cx">     Bugzilla::Util::trick_taint($file);
</span><span class="cx">     $rl-&gt;handler($file, $file);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-
</del><span class="cx"> package Bugzilla::ModPerl::ResponseHandler;
</span><span class="cx"> use strict;
</span><span class="cx"> use base qw(ModPerl::Registry);
</span><span class="lines">@@ -108,6 +131,14 @@
</span><span class="cx">     # here explicitly or init_page's shutdownhtml code won't work right.
</span><span class="cx">     $0 = $ENV{'SCRIPT_FILENAME'};
</span><span class="cx"> 
</span><ins>+    # Prevent &quot;use lib&quot; from modifying @INC in the case where a .cgi file
+    # is being automatically recompiled by mod_perl when Apache is
+    # running. (This happens if a file changes while Apache is already
+    # running.)
+    no warnings 'redefine';
+    local *lib::import = sub {};
+    use warnings;
+
</ins><span class="cx">     Bugzilla::init_page();
</span><span class="cx">     return $class-&gt;SUPER::handler(@_);
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgpagecgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/page.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/page.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/page.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -34,7 +34,31 @@
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla;
</span><span class="cx"> use Bugzilla::Error;
</span><ins>+use Bugzilla::Hook;
+use Bugzilla::Search::Quicksearch;
</ins><span class="cx"> 
</span><ins>+###############
+# Subroutines #
+###############
+
+# For quicksearch.html.
+sub quicksearch_field_names {
+    my $fields = Bugzilla::Search::Quicksearch-&gt;FIELD_MAP;
+    my %fields_reverse;
+    # Put longer names before shorter names.
+    my @nicknames = sort { length($b) &lt;=&gt; length($a) } (keys %$fields);
+    foreach my $nickname (@nicknames) {
+        my $db_field = $fields-&gt;{$nickname};
+        $fields_reverse{$db_field} ||= [];
+        push(@{ $fields_reverse{$db_field} }, $nickname);
+    }
+    return \%fields_reverse;
+}
+
+###############
+# Main Script #
+###############
+
</ins><span class="cx"> Bugzilla-&gt;login();
</span><span class="cx"> 
</span><span class="cx"> my $cgi = Bugzilla-&gt;cgi;
</span><span class="lines">@@ -42,21 +66,31 @@
</span><span class="cx"> 
</span><span class="cx"> my $id = $cgi-&gt;param('id');
</span><span class="cx"> if ($id) {
</span><del>-    # Remove all dodgy chars, and split into name and ctype.
-    $id =~ s/[^\w\-\.]//g;
-    $id =~ /(.*)\.(.*)/;
</del><ins>+    # Be careful not to allow directory traversal.
+    if ($id =~ /\.\./) {
+        # two dots in a row is bad
+        ThrowCodeError(&quot;bad_page_cgi_id&quot;, { &quot;page_id&quot; =&gt; $id });
+    }
+    # Split into name and ctype.
+    $id =~ /^([\w\-\/\.]+)\.(\w+)$/;
</ins><span class="cx">     if (!$2) {
</span><span class="cx">         # if this regexp fails to match completely, something bad came in
</span><span class="cx">         ThrowCodeError(&quot;bad_page_cgi_id&quot;, { &quot;page_id&quot; =&gt; $id });
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    my %vars = ( 
+      quicksearch_field_names =&gt; \&amp;quicksearch_field_names,
+    );
+    Bugzilla::Hook::process('page_before_template', 
+                            { page_id =&gt; $id, vars =&gt; \%vars });
+
</ins><span class="cx">     my $format = $template-&gt;get_format(&quot;pages/$1&quot;, undef, $2);
</span><span class="cx">     
</span><span class="cx">     $cgi-&gt;param('id', $id);
</span><span class="cx"> 
</span><span class="cx">     print $cgi-&gt;header($format-&gt;{'ctype'});
</span><span class="cx"> 
</span><del>-    $template-&gt;process(&quot;$format-&gt;{'template'}&quot;)
</del><ins>+    $template-&gt;process(&quot;$format-&gt;{'template'}&quot;, \%vars)
</ins><span class="cx">       || ThrowTemplateError($template-&gt;error());
</span><span class="cx"> }
</span><span class="cx"> else {
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgpost_bugcgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/post_bug.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/post_bug.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/post_bug.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -55,42 +55,20 @@
</span><span class="cx"> ######################################################################
</span><span class="cx"> 
</span><span class="cx"> # redirect to enter_bug if no field is passed.
</span><del>-print $cgi-&gt;redirect(correct_urlbase() . 'enter_bug.cgi') unless $cgi-&gt;param();
</del><ins>+unless ($cgi-&gt;param()) {
+    print $cgi-&gt;redirect(correct_urlbase() . 'enter_bug.cgi');
+    exit;
+}
</ins><span class="cx"> 
</span><span class="cx"> # Detect if the user already used the same form to submit a bug
</span><span class="cx"> my $token = trim($cgi-&gt;param('token'));
</span><del>-if ($token) {
-    my ($creator_id, $date, $old_bug_id) = Bugzilla::Token::GetTokenData($token);
-    unless ($creator_id
-              &amp;&amp; ($creator_id == $user-&gt;id)
-              &amp;&amp; ($old_bug_id =~ &quot;^createbug:&quot;))
-    {
-        # The token is invalid.
-        ThrowUserError('token_does_not_exist');
-    }
</del><ins>+check_token_data($token, 'create_bug', 'index.cgi');
</ins><span class="cx"> 
</span><del>-    $old_bug_id =~ s/^createbug://;
-
-    if ($old_bug_id &amp;&amp; (!$cgi-&gt;param('ignore_token')
-                        || ($cgi-&gt;param('ignore_token') != $old_bug_id)))
-    {
-        $vars-&gt;{'bugid'} = $old_bug_id;
-        $vars-&gt;{'allow_override'} = defined $cgi-&gt;param('ignore_token') ? 0 : 1;
-
-        print $cgi-&gt;header();
-        $template-&gt;process(&quot;bug/create/confirm-create-dupe.html.tmpl&quot;, $vars)
-           || ThrowTemplateError($template-&gt;error());
-        exit;
-    }
-}    
-
</del><span class="cx"> # do a match on the fields if applicable
</span><del>-
-&amp;Bugzilla::User::match_field ($cgi, {
</del><ins>+Bugzilla::User::match_field ({
</ins><span class="cx">     'cc'            =&gt; { 'type' =&gt; 'multi'  },
</span><span class="cx">     'assigned_to'   =&gt; { 'type' =&gt; 'single' },
</span><span class="cx">     'qa_contact'    =&gt; { 'type' =&gt; 'single' },
</span><del>-    '^requestee_type-(\d+)$' =&gt; { 'type' =&gt; 'multi' },
</del><span class="cx"> });
</span><span class="cx"> 
</span><span class="cx"> if (defined $cgi-&gt;param('maketemplate')) {
</span><span class="lines">@@ -105,16 +83,6 @@
</span><span class="cx"> 
</span><span class="cx"> umask 0;
</span><span class="cx"> 
</span><del>-# get current time
-my $timestamp = $dbh-&gt;selectrow_array(q{SELECT NOW()});
-
-# Group Validation
-my @selected_groups;
-foreach my $group (grep(/^bit-\d+$/, $cgi-&gt;param())) {
-    $group =~ /^bit-(\d+)$/;
-    push(@selected_groups, $1);
-}
-
</del><span class="cx"> # The format of the initial comment can be structured by adding fields to the
</span><span class="cx"> # enter_bug template and then referencing them in the comment template.
</span><span class="cx"> my $comment;
</span><span class="lines">@@ -141,7 +109,7 @@
</span><span class="cx"> 
</span><span class="cx">     alias
</span><span class="cx">     blocked
</span><del>-    commentprivacy
</del><ins>+    comment_is_private
</ins><span class="cx">     bug_file_loc
</span><span class="cx">     bug_severity
</span><span class="cx">     bug_status
</span><span class="lines">@@ -162,23 +130,31 @@
</span><span class="cx"> foreach my $field (@bug_fields) {
</span><span class="cx">     $bug_params{$field} = $cgi-&gt;param($field);
</span><span class="cx"> }
</span><del>-$bug_params{'creation_ts'} = $timestamp;
-$bug_params{'cc'}          = [$cgi-&gt;param('cc')];
-$bug_params{'groups'}      = \@selected_groups;
-$bug_params{'comment'}     = $comment;
</del><ins>+foreach my $field (qw(cc groups)) {
+    next if !$cgi-&gt;should_set($field);
+    $bug_params{$field} = [$cgi-&gt;param($field)];
+}
+$bug_params{'comment'} = $comment;
</ins><span class="cx"> 
</span><span class="cx"> my @multi_selects = grep {$_-&gt;type == FIELD_TYPE_MULTI_SELECT &amp;&amp; $_-&gt;enter_bug}
</span><span class="cx">                          Bugzilla-&gt;active_custom_fields;
</span><span class="cx"> 
</span><span class="cx"> foreach my $field (@multi_selects) {
</span><ins>+    next if !$cgi-&gt;should_set($field-&gt;name);
</ins><span class="cx">     $bug_params{$field-&gt;name} = [$cgi-&gt;param($field-&gt;name)];
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> my $bug = Bugzilla::Bug-&gt;create(\%bug_params);
</span><span class="cx"> 
</span><del>-# Get the bug ID back.
</del><ins>+# Get the bug ID back and delete the token used to create this bug.
</ins><span class="cx"> my $id = $bug-&gt;bug_id;
</span><ins>+delete_token($token);
</ins><span class="cx"> 
</span><ins>+# We do this directly from the DB because $bug-&gt;creation_ts has the seconds
+# formatted out of it (which should be fixed some day).
+my $timestamp = $dbh-&gt;selectrow_array(
+    'SELECT creation_ts FROM bugs WHERE bug_id = ?', undef, $id);
+
</ins><span class="cx"> # Set Version cookie, but only if the user actually selected
</span><span class="cx"> # a version on the page.
</span><span class="cx"> if (defined $cgi-&gt;param('version')) {
</span><span class="lines">@@ -192,93 +168,78 @@
</span><span class="cx"> # after the bug is filed.
</span><span class="cx"> 
</span><span class="cx"> # Add an attachment if requested.
</span><del>-if (defined($cgi-&gt;upload('data')) || $cgi-&gt;param('attachurl')) {
-    $cgi-&gt;param('isprivate', $cgi-&gt;param('commentprivacy'));
-    my $attachment = Bugzilla::Attachment-&gt;insert_attachment_for_bug(!THROW_ERROR,
-                                                  $bug, $user, $timestamp, $vars);
</del><ins>+if (defined($cgi-&gt;upload('data')) || $cgi-&gt;param('attach_text')) {
+    $cgi-&gt;param('isprivate', $cgi-&gt;param('comment_is_private'));
</ins><span class="cx"> 
</span><ins>+    # Must be called before create() as it may alter $cgi-&gt;param('ispatch').
+    my $content_type = Bugzilla::Attachment::get_content_type();
+    my $attachment;
+
+    # If the attachment cannot be successfully added to the bug,
+    # we notify the user, but we don't interrupt the bug creation process.
+    my $error_mode_cache = Bugzilla-&gt;error_mode;
+    Bugzilla-&gt;error_mode(ERROR_MODE_DIE);
+    eval {
+        $attachment = Bugzilla::Attachment-&gt;create(
+            {bug           =&gt; $bug,
+             creation_ts   =&gt; $timestamp,
+             data          =&gt; scalar $cgi-&gt;param('attach_text') || $cgi-&gt;upload('data'),
+             description   =&gt; scalar $cgi-&gt;param('description'),
+             filename      =&gt; $cgi-&gt;param('attach_text') ? &quot;file_$id.txt&quot; : scalar $cgi-&gt;upload('data'),
+             ispatch       =&gt; scalar $cgi-&gt;param('ispatch'),
+             isprivate     =&gt; scalar $cgi-&gt;param('isprivate'),
+             mimetype      =&gt; $content_type,
+            });
+    };
+    Bugzilla-&gt;error_mode($error_mode_cache);
+
</ins><span class="cx">     if ($attachment) {
</span><del>-        # Update the comment to include the new attachment ID.
-        # This string is hardcoded here because Template::quoteUrls()
-        # expects to find this exact string.
-        my $new_comment = &quot;Created an attachment (id=&quot; . $attachment-&gt;id . &quot;)\n&quot; .
-                          $attachment-&gt;description . &quot;\n&quot;;
-        # We can use $bug-&gt;longdescs here because we are sure that the bug
-        # description is of type CMT_NORMAL. No need to include it if it's
-        # empty, though.
-        if ($bug-&gt;longdescs-&gt;[0]-&gt;{'body'} !~ /^\s+$/) {
-            $new_comment .= &quot;\n&quot; . $bug-&gt;longdescs-&gt;[0]-&gt;{'body'};
-        }
-        $bug-&gt;update_comment($bug-&gt;longdescs-&gt;[0]-&gt;{'id'}, $new_comment);
</del><ins>+        # Set attachment flags.
+        my ($flags, $new_flags) = Bugzilla::Flag-&gt;extract_flags_from_cgi(
+                                      $bug, $attachment, $vars, SKIP_REQUESTEE_ON_ERROR);
+        $attachment-&gt;set_flags($flags, $new_flags);
+        $attachment-&gt;update($timestamp);
+        my $comment = $bug-&gt;comments-&gt;[0];
+        $comment-&gt;set_all({ type =&gt; CMT_ATTACHMENT_CREATED, 
+                            extra_data =&gt; $attachment-&gt;id });
+        $comment-&gt;update();
</ins><span class="cx">     }
</span><span class="cx">     else {
</span><span class="cx">         $vars-&gt;{'message'} = 'attachment_creation_failed';
</span><span class="cx">     }
</span><del>-
-    # Determine if Patch Viewer is installed, for Diff link
-    eval {
-        require PatchReader;
-        $vars-&gt;{'patchviewerinstalled'} = 1;
-    };
</del><span class="cx"> }
</span><span class="cx"> 
</span><del>-# Add flags, if any. To avoid dying if something goes wrong
-# while processing flags, we will eval() flag validation.
-# This requires errors to die().
-# XXX: this can go away as soon as flag validation is able to
-#      fail without dying.
-my $error_mode_cache = Bugzilla-&gt;error_mode;
-Bugzilla-&gt;error_mode(ERROR_MODE_DIE);
-eval {
-    Bugzilla::Flag::validate($id, undef, SKIP_REQUESTEE_ON_ERROR);
-    Bugzilla::Flag-&gt;process($bug, undef, $timestamp, $vars);
-};
-Bugzilla-&gt;error_mode($error_mode_cache);
-if ($@) {
-    $vars-&gt;{'message'} = 'flag_creation_failed';
-    $vars-&gt;{'flag_creation_error'} = $@;
-}
</del><ins>+# Set bug flags.
+my ($flags, $new_flags) = Bugzilla::Flag-&gt;extract_flags_from_cgi($bug, undef, $vars,
+                                                             SKIP_REQUESTEE_ON_ERROR);
+$bug-&gt;set_flags($flags, $new_flags);
+$bug-&gt;update($timestamp);
</ins><span class="cx"> 
</span><del>-# Email everyone the details of the new bug 
-$vars-&gt;{'mailrecipients'} = {'changer' =&gt; $user-&gt;login};
-
</del><span class="cx"> $vars-&gt;{'id'} = $id;
</span><span class="cx"> $vars-&gt;{'bug'} = $bug;
</span><span class="cx"> 
</span><del>-Bugzilla::Hook::process(&quot;post_bug-after_creation&quot;, { vars =&gt; $vars });
</del><ins>+Bugzilla::Hook::process('post_bug_after_creation', { vars =&gt; $vars });
</ins><span class="cx"> 
</span><span class="cx"> ThrowCodeError(&quot;bug_error&quot;, { bug =&gt; $bug }) if $bug-&gt;error;
</span><span class="cx"> 
</span><del>-$vars-&gt;{'sentmail'} = [];
-
-push (@{$vars-&gt;{'sentmail'}}, { type =&gt; 'created',
-                                id =&gt; $id,
-                              });
-
-foreach my $i (@{$bug-&gt;dependson || []}, @{$bug-&gt;blocked || []}) {
-    push (@{$vars-&gt;{'sentmail'}}, { type =&gt; 'dep', id =&gt; $i, });
</del><ins>+my $recipients = { changer =&gt; $user };
+my $bug_sent = Bugzilla::BugMail::Send($id, $recipients);
+$bug_sent-&gt;{type} = 'created';
+$bug_sent-&gt;{id}   = $id;
+my @all_mail_results = ($bug_sent);
+foreach my $dep (@{$bug-&gt;dependson || []}, @{$bug-&gt;blocked || []}) {
+    my $dep_sent = Bugzilla::BugMail::Send($dep, $recipients);
+    $dep_sent-&gt;{type} = 'dep';
+    $dep_sent-&gt;{id}   = $dep;
+    push(@all_mail_results, $dep_sent);
</ins><span class="cx"> }
</span><ins>+$vars-&gt;{sentmail} = \@all_mail_results;
</ins><span class="cx"> 
</span><del>-my @bug_list;
-if ($cgi-&gt;cookie(&quot;BUGLIST&quot;)) {
-    @bug_list = split(/:/, $cgi-&gt;cookie(&quot;BUGLIST&quot;));
-}
-$vars-&gt;{'bug_list'} = \@bug_list;
-$vars-&gt;{'use_keywords'} = 1 if Bugzilla::Keyword::keyword_count();
</del><ins>+$format = $template-&gt;get_format(&quot;bug/create/created&quot;,
+                                 scalar($cgi-&gt;param('created-format')),
+                                 &quot;html&quot;);
+print $cgi-&gt;header();
+$template-&gt;process($format-&gt;{'template'}, $vars)
+    || ThrowTemplateError($template-&gt;error());
</ins><span class="cx"> 
</span><del>-if ($token) {
-    trick_taint($token);
-    $dbh-&gt;do('UPDATE tokens SET eventdata = ? WHERE token = ?', undef, 
-             (&quot;createbug:$id&quot;, $token));
-}
-
-if (Bugzilla-&gt;usage_mode == USAGE_MODE_EMAIL) {
-    Bugzilla::BugMail::Send($id, $vars-&gt;{'mailrecipients'});
-}
-else {
-    print $cgi-&gt;header();
-    $template-&gt;process(&quot;bug/create/created.html.tmpl&quot;, $vars)
-        || ThrowTemplateError($template-&gt;error());
-}
-
</del><span class="cx"> 1;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgprocess_bugcgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/process_bug.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/process_bug.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/process_bug.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -48,8 +48,6 @@
</span><span class="cx"> use Bugzilla;
</span><span class="cx"> use Bugzilla::Constants;
</span><span class="cx"> use Bugzilla::Bug;
</span><del>-use Bugzilla::BugMail;
-use Bugzilla::Mailer;
</del><span class="cx"> use Bugzilla::User;
</span><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> use Bugzilla::Error;
</span><span class="lines">@@ -61,6 +59,7 @@
</span><span class="cx"> use Bugzilla::Status;
</span><span class="cx"> use Bugzilla::Token;
</span><span class="cx"> 
</span><ins>+use List::MoreUtils qw(firstidx);
</ins><span class="cx"> use Storable qw(dclone);
</span><span class="cx"> 
</span><span class="cx"> my $user = Bugzilla-&gt;login(LOGIN_REQUIRED);
</span><span class="lines">@@ -69,26 +68,11 @@
</span><span class="cx"> my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx"> my $template = Bugzilla-&gt;template;
</span><span class="cx"> my $vars = {};
</span><del>-$vars-&gt;{'use_keywords'} = 1 if Bugzilla::Keyword::keyword_count();
</del><span class="cx"> 
</span><span class="cx"> ######################################################################
</span><span class="cx"> # Subroutines
</span><span class="cx"> ######################################################################
</span><span class="cx"> 
</span><del>-# Used to send email when an update is done.
-sub send_results {
-    my ($bug_id, $vars) = @_;
-    my $template = Bugzilla-&gt;template;
-    if (Bugzilla-&gt;usage_mode == USAGE_MODE_EMAIL) {
-         Bugzilla::BugMail::Send($bug_id, $vars-&gt;{'mailrecipients'});
-    }
-    else {
-        $template-&gt;process(&quot;bug/process/results.html.tmpl&quot;, $vars)
-            || ThrowTemplateError($template-&gt;error());
-    }
-    $vars-&gt;{'header_done'} = 1;
-}
-
</del><span class="cx"> # Tells us whether or not a field should be changed by process_bug.
</span><span class="cx"> sub should_set {
</span><span class="cx">     # check_defined is used for fields where there's another field
</span><span class="lines">@@ -112,23 +96,16 @@
</span><span class="cx"> # Create a list of objects for all bugs being modified in this request.
</span><span class="cx"> my @bug_objects;
</span><span class="cx"> if (defined $cgi-&gt;param('id')) {
</span><del>-  my $id = $cgi-&gt;param('id');
-  ValidateBugID($id);
-
-  # Store the validated, and detainted id back in the cgi data, as
-  # lots of later code will need it, and will obtain it from there
-  $cgi-&gt;param('id', $id);
-  push(@bug_objects, new Bugzilla::Bug($id));
</del><ins>+  my $bug = Bugzilla::Bug-&gt;check(scalar $cgi-&gt;param('id'));
+  $cgi-&gt;param('id', $bug-&gt;id);
+  push(@bug_objects, $bug);
</ins><span class="cx"> } else {
</span><del>-    my @ids;
</del><span class="cx">     foreach my $i ($cgi-&gt;param()) {
</span><span class="cx">         if ($i =~ /^id_([1-9][0-9]*)/) {
</span><span class="cx">             my $id = $1;
</span><del>-            ValidateBugID($id);
-            push(@ids, $id);
</del><ins>+            push(@bug_objects, Bugzilla::Bug-&gt;check($id));
</ins><span class="cx">         }
</span><span class="cx">     }
</span><del>-    @bug_objects = @{Bugzilla::Bug-&gt;new_from_list(\@ids)};
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> # Make sure there are bugs to process.
</span><span class="lines">@@ -150,51 +127,44 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> # do a match on the fields if applicable
</span><del>-
-# The order of these function calls is important, as Flag::validate
-# assumes User::match_field has ensured that the values
-# in the requestee fields are legitimate user email addresses.
-&amp;Bugzilla::User::match_field($cgi, {
</del><ins>+Bugzilla::User::match_field({
</ins><span class="cx">     'qa_contact'                =&gt; { 'type' =&gt; 'single' },
</span><span class="cx">     'newcc'                     =&gt; { 'type' =&gt; 'multi'  },
</span><span class="cx">     'masscc'                    =&gt; { 'type' =&gt; 'multi'  },
</span><span class="cx">     'assigned_to'               =&gt; { 'type' =&gt; 'single' },
</span><del>-    '^requestee(_type)?-(\d+)$' =&gt; { 'type' =&gt; 'multi'  },
</del><span class="cx"> });
</span><span class="cx"> 
</span><del>-# Validate flags in all cases. validate() should not detect any
-# reference to flags if $cgi-&gt;param('id') is undefined.
-Bugzilla::Flag::validate($cgi-&gt;param('id'));
-
</del><span class="cx"> print $cgi-&gt;header() unless Bugzilla-&gt;usage_mode == USAGE_MODE_EMAIL;
</span><span class="cx"> 
</span><span class="cx"> # Check for a mid-air collision. Currently this only works when updating
</span><span class="cx"> # an individual bug.
</span><del>-if (defined $cgi-&gt;param('delta_ts')
-    &amp;&amp; $cgi-&gt;param('delta_ts') ne $first_bug-&gt;delta_ts)
</del><ins>+if (defined $cgi-&gt;param('delta_ts'))
</ins><span class="cx"> {
</span><del>-    ($vars-&gt;{'operations'}) =
-        Bugzilla::Bug::GetBugActivity($first_bug-&gt;id, undef,
-                                      scalar $cgi-&gt;param('delta_ts'));
</del><ins>+    my $delta_ts_z = datetime_from($cgi-&gt;param('delta_ts'));
+    my $first_delta_tz_z =  datetime_from($first_bug-&gt;delta_ts);
+    if ($first_delta_tz_z ne $delta_ts_z) {
+        ($vars-&gt;{'operations'}) =
+            Bugzilla::Bug::GetBugActivity($first_bug-&gt;id, undef,
+                                          scalar $cgi-&gt;param('delta_ts'));
</ins><span class="cx"> 
</span><del>-    $vars-&gt;{'title_tag'} = &quot;mid_air&quot;;
</del><ins>+        $vars-&gt;{'title_tag'} = &quot;mid_air&quot;;
</ins><span class="cx">     
</span><del>-    ThrowCodeError('undefined_field', { field =&gt; 'longdesclength' })
-        if !defined $cgi-&gt;param('longdesclength');
</del><ins>+        ThrowCodeError('undefined_field', { field =&gt; 'longdesclength' })
+            if !defined $cgi-&gt;param('longdesclength');
</ins><span class="cx"> 
</span><del>-    $vars-&gt;{'start_at'} = $cgi-&gt;param('longdesclength');
-    # Always sort midair collision comments oldest to newest,
-    # regardless of the user's personal preference.
-    $vars-&gt;{'comments'} = Bugzilla::Bug::GetComments($first_bug-&gt;id,
-                                                     &quot;oldest_to_newest&quot;);
-    $vars-&gt;{'bug'} = $first_bug;
-    # The token contains the old delta_ts. We need a new one.
-    $cgi-&gt;param('token', issue_hash_token([$first_bug-&gt;id, $first_bug-&gt;delta_ts]));
-    
-    # Warn the user about the mid-air collision and ask them what to do.
-    $template-&gt;process(&quot;bug/process/midair.html.tmpl&quot;, $vars)
-      || ThrowTemplateError($template-&gt;error());
-    exit;
</del><ins>+        $vars-&gt;{'start_at'} = $cgi-&gt;param('longdesclength');
+        # Always sort midair collision comments oldest to newest,
+        # regardless of the user's personal preference.
+        $vars-&gt;{'comments'} = $first_bug-&gt;comments({ order =&gt; &quot;oldest_to_newest&quot; });
+        $vars-&gt;{'bug'} = $first_bug;
+
+        # The token contains the old delta_ts. We need a new one.
+        $cgi-&gt;param('token', issue_hash_token([$first_bug-&gt;id, $first_bug-&gt;delta_ts]));
+        # Warn the user about the mid-air collision and ask them what to do.
+        $template-&gt;process(&quot;bug/process/midair.html.tmpl&quot;, $vars)
+          || ThrowTemplateError($template-&gt;error());
+        exit;
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> # We couldn't do this check earlier as we first had to validate bug IDs
</span><span class="lines">@@ -215,30 +185,27 @@
</span><span class="cx"> 
</span><span class="cx"> $vars-&gt;{'title_tag'} = &quot;bug_processed&quot;;
</span><span class="cx"> 
</span><del>-# Set up the vars for navigational &lt;link&gt; elements
-my @bug_list;
-if ($cgi-&gt;cookie(&quot;BUGLIST&quot;)) {
-    @bug_list = split(/:/, $cgi-&gt;cookie(&quot;BUGLIST&quot;));
-    $vars-&gt;{'bug_list'} = \@bug_list;
-}
-
-my ($action, $next_bug);
</del><ins>+my $action;
</ins><span class="cx"> if (defined $cgi-&gt;param('id')) {
</span><del>-    $action = Bugzilla-&gt;user-&gt;settings-&gt;{'post_bug_submit_action'}-&gt;{'value'};
</del><ins>+    $action = $user-&gt;setting('post_bug_submit_action');
</ins><span class="cx"> 
</span><span class="cx">     if ($action eq 'next_bug') {
</span><del>-        my $cur = lsearch(\@bug_list, $cgi-&gt;param('id'));
</del><ins>+        my $bug_list_obj = $user-&gt;recent_search_for($first_bug);
+        my @bug_list = $bug_list_obj ? @{$bug_list_obj-&gt;bug_list} : ();
+        my $cur = firstidx { $_ eq $cgi-&gt;param('id') } @bug_list;
</ins><span class="cx">         if ($cur &gt;= 0 &amp;&amp; $cur &lt; $#bug_list) {
</span><del>-            $next_bug = $bug_list[$cur + 1];
-            # No need to check whether the user can see the bug or not.
-            # All we want is its ID. An error will be thrown later
-            # if the user cannot see it.
-            $vars-&gt;{'bug'} = {bug_id =&gt; $next_bug};
</del><ins>+            my $next_bug_id = $bug_list[$cur + 1];
+            detaint_natural($next_bug_id);
+            if ($next_bug_id and $user-&gt;can_see_bug($next_bug_id)) {
+                # We create an object here so that $bug-&gt;send_changes can use it
+                # when displaying the header.
+                $vars-&gt;{'bug'} = new Bugzilla::Bug($next_bug_id);
+            }
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx">     # Include both action = 'same_bug' and 'nothing'.
</span><span class="cx">     else {
</span><del>-        $vars-&gt;{'bug'} = {bug_id =&gt; $cgi-&gt;param('id')};
</del><ins>+        $vars-&gt;{'bug'} = $first_bug;
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> else {
</span><span class="lines">@@ -255,418 +222,192 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-# For security purposes, and because lots of other checks depend on it,
-# we set the product first before anything else.
-my $product_change; # Used only for strict_isolation checks, right now.
-if (should_set('product')) {
-    foreach my $b (@bug_objects) {
-        my $changed = $b-&gt;set_product(scalar $cgi-&gt;param('product'),
-            { component        =&gt; scalar $cgi-&gt;param('component'),
-              version          =&gt; scalar $cgi-&gt;param('version'),
-              target_milestone =&gt; scalar $cgi-&gt;param('target_milestone'),
-              change_confirmed =&gt; scalar $cgi-&gt;param('confirm_product_change'),
-              other_bugs =&gt; \@bug_objects,
-            });
-        $product_change ||= $changed;
-    }
-}
-        
-# strict_isolation checks mean that we should set the groups
-# immediately after changing the product.
-foreach my $b (@bug_objects) {
-    foreach my $group (@{$b-&gt;product_obj-&gt;groups_valid}) {
-        my $gid = $group-&gt;id;
-        if (should_set(&quot;bit-$gid&quot;, 1)) {
-            # Check ! first to avoid having to check defined below.
-            if (!$cgi-&gt;param(&quot;bit-$gid&quot;)) {
-                $b-&gt;remove_group($gid);
-            }
-            # &quot;== 1&quot; is important because mass-change uses -1 to mean
-            # &quot;don't change this restriction&quot;
-            elsif ($cgi-&gt;param(&quot;bit-$gid&quot;) == 1) {
-                $b-&gt;add_group($gid);
-            }
-        }
-    }
-}
-
-if ($cgi-&gt;param('id') &amp;&amp; (defined $cgi-&gt;param('dependson')
-                          || defined $cgi-&gt;param('blocked')) )
-{
-    $first_bug-&gt;set_dependencies(scalar $cgi-&gt;param('dependson'),
-                                 scalar $cgi-&gt;param('blocked'));
-}
-# Right now, you can't modify dependencies on a mass change.
-else {
-    $cgi-&gt;delete('dependson');
-    $cgi-&gt;delete('blocked');
-}
-
-my $any_keyword_changes;
-if (defined $cgi-&gt;param('keywords')) {
-    foreach my $b (@bug_objects) {
-        my $return =
-            $b-&gt;modify_keywords(scalar $cgi-&gt;param('keywords'),
-                                scalar $cgi-&gt;param('keywordaction'));
-        $any_keyword_changes ||= $return;
-    }
-}
-
</del><span class="cx"> # Component, target_milestone, and version are in here just in case
</span><span class="cx"> # the 'product' field wasn't defined in the CGI. It doesn't hurt to set
</span><span class="cx"> # them twice.
</span><span class="cx"> my @set_fields = qw(op_sys rep_platform priority bug_severity
</span><span class="cx">                     component target_milestone version
</span><span class="cx">                     bug_file_loc status_whiteboard short_desc
</span><del>-                    deadline remaining_time estimated_time);
</del><ins>+                    deadline remaining_time estimated_time
+                    work_time set_default_assignee set_default_qa_contact
+                    cclist_accessible reporter_accessible 
+                    product confirm_product_change
+                    bug_status resolution dup_id);
</ins><span class="cx"> push(@set_fields, 'assigned_to') if !$cgi-&gt;param('set_default_assignee');
</span><span class="cx"> push(@set_fields, 'qa_contact')  if !$cgi-&gt;param('set_default_qa_contact');
</span><del>-my @custom_fields = Bugzilla-&gt;active_custom_fields;
-
-my %methods = (
-    bug_severity =&gt; 'set_severity',
-    rep_platform =&gt; 'set_platform',
-    short_desc   =&gt; 'set_summary',
-    bug_file_loc =&gt; 'set_url',
</del><ins>+my %field_translation = (
+    bug_severity =&gt; 'severity',
+    rep_platform =&gt; 'platform',
+    short_desc   =&gt; 'summary',
+    bug_file_loc =&gt; 'url',
+    set_default_assignee   =&gt; 'reset_assigned_to',
+    set_default_qa_contact =&gt; 'reset_qa_contact',
+    confirm_product_change =&gt; 'product_change_confirmed',
</ins><span class="cx"> );
</span><del>-foreach my $b (@bug_objects) {
-    if (should_set('comment') || $cgi-&gt;param('work_time')) {
-        # Add a comment as needed to each bug. This is done early because
-        # there are lots of things that want to check if we added a comment.
-        $b-&gt;add_comment(scalar($cgi-&gt;param('comment')),
-            { isprivate =&gt; scalar $cgi-&gt;param('commentprivacy'),
-              work_time =&gt; scalar $cgi-&gt;param('work_time') });
-    }
-    foreach my $field_name (@set_fields) {
-        if (should_set($field_name)) {
-            my $method = $methods{$field_name};
-            $method ||= &quot;set_&quot; . $field_name;
-            $b-&gt;$method($cgi-&gt;param($field_name));
-        }
-    }
-    $b-&gt;reset_assigned_to if $cgi-&gt;param('set_default_assignee');
-    $b-&gt;reset_qa_contact  if $cgi-&gt;param('set_default_qa_contact');
</del><span class="cx"> 
</span><del>-    # And set custom fields.
-    foreach my $field (@custom_fields) {
-        my $fname = $field-&gt;name;
-        if (should_set($fname, 1)) {
-            $b-&gt;set_custom_field($field, [$cgi-&gt;param($fname)]);
-        }
</del><ins>+my %set_all_fields = ( other_bugs =&gt; \@bug_objects );
+foreach my $field_name (@set_fields) {
+    if (should_set($field_name, 1)) {
+        my $param_name = $field_translation{$field_name} || $field_name;
+        $set_all_fields{$param_name} = $cgi-&gt;param($field_name);
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-# Certain changes can only happen on individual bugs, never on mass-changes.
-if (defined $cgi-&gt;param('id')) {
-    # Since aliases are unique (like bug numbers), they can only be changed
-    # for one bug at a time.
-    if (Bugzilla-&gt;params-&gt;{&quot;usebugaliases&quot;} &amp;&amp; defined $cgi-&gt;param('alias')) {
-        $first_bug-&gt;set_alias($cgi-&gt;param('alias'));
</del><ins>+if (should_set('keywords')) {
+    my $action = $cgi-&gt;param('keywordaction') || '';
+    # Backward-compatibility for Bugzilla 3.x and older.
+    $action = 'remove' if $action eq 'delete';
+    $action = 'set'    if $action eq 'makeexact';
+    $set_all_fields{keywords}-&gt;{$action} = $cgi-&gt;param('keywords');
+}
+if (should_set('comment')) {
+    $set_all_fields{comment} = {
+        body       =&gt; scalar $cgi-&gt;param('comment'),
+        is_private =&gt; scalar $cgi-&gt;param('comment_is_private'),
+    };
+}
+if (should_set('see_also')) {
+    $set_all_fields{'see_also'}-&gt;{add} = 
+        [split(/[\s,]+/, $cgi-&gt;param('see_also'))];
+}
+if (should_set('remove_see_also')) {
+    $set_all_fields{'see_also'}-&gt;{remove} = [$cgi-&gt;param('remove_see_also')];
+}
+foreach my $dep_field (qw(dependson blocked)) {
+    if (should_set($dep_field)) {
+        if (my $dep_action = $cgi-&gt;param(&quot;${dep_field}_action&quot;)) {
+            $set_all_fields{$dep_field}-&gt;{$dep_action} =
+                [split(/\s,/, $cgi-&gt;param($dep_field))];
+        }
+        else {
+            $set_all_fields{$dep_field}-&gt;{set} = $cgi-&gt;param($dep_field);
+        }
</ins><span class="cx">     }
</span><del>-
-    # reporter_accessible and cclist_accessible--these are only set if
-    # the user can change them and they appear on the page.
-    if (should_set('cclist_accessible', 1)) {
-        $first_bug-&gt;set_cclist_accessible($cgi-&gt;param('cclist_accessible'))
-    }
-    if (should_set('reporter_accessible', 1)) {
-        $first_bug-&gt;set_reporter_accessible($cgi-&gt;param('reporter_accessible'))
-    }
-    
-    # You can only mark/unmark comments as private on single bugs. If
-    # you're not in the insider group, this code won't do anything.
-    foreach my $field (grep(/^defined_isprivate/, $cgi-&gt;param())) {
-        $field =~ /(\d+)$/;
-        my $comment_id = $1;
-        $first_bug-&gt;set_comment_is_private($comment_id,
-                                           $cgi-&gt;param(&quot;isprivate_$comment_id&quot;));
-    }
</del><span class="cx"> }
</span><del>-
-# We need to check the addresses involved in a CC change before we touch 
-# any bugs. What we'll do here is formulate the CC data into two arrays of
-# users involved in this CC change.  Then those arrays can be used later 
-# on for the actual change.
-my (@cc_add, @cc_remove);
</del><ins>+# Formulate the CC data into two arrays of users involved in this CC change.
</ins><span class="cx"> if (defined $cgi-&gt;param('newcc')
</span><del>-    || defined $cgi-&gt;param('addselfcc')
-    || defined $cgi-&gt;param('removecc')
-    || defined $cgi-&gt;param('masscc')) {
-        
</del><ins>+    or defined $cgi-&gt;param('addselfcc')
+    or defined $cgi-&gt;param('removecc')
+    or defined $cgi-&gt;param('masscc')) 
+{
+    my (@cc_add, @cc_remove);
</ins><span class="cx">     # If masscc is defined, then we came from buglist and need to either add or
</span><del>-    # remove cc's... otherwise, we came from bugform and may need to do both.
-    my ($cc_add, $cc_remove) = &quot;&quot;;
</del><ins>+    # remove cc's... otherwise, we came from show_bug and may need to do both.
</ins><span class="cx">     if (defined $cgi-&gt;param('masscc')) {
</span><span class="cx">         if ($cgi-&gt;param('ccaction') eq 'add') {
</span><del>-            $cc_add = join(' ',$cgi-&gt;param('masscc'));
</del><ins>+            @cc_add = $cgi-&gt;param('masscc');
</ins><span class="cx">         } elsif ($cgi-&gt;param('ccaction') eq 'remove') {
</span><del>-            $cc_remove = join(' ',$cgi-&gt;param('masscc'));
</del><ins>+            @cc_remove = $cgi-&gt;param('masscc');
</ins><span class="cx">         }
</span><span class="cx">     } else {
</span><del>-        $cc_add = join(' ',$cgi-&gt;param('newcc'));
-        # We came from bug_form which uses a select box to determine what cc's
</del><ins>+        @cc_add = $cgi-&gt;param('newcc');
+        push(@cc_add, Bugzilla-&gt;user) if $cgi-&gt;param('addselfcc');
+
+        # We came from show_bug which uses a select box to determine what cc's
</ins><span class="cx">         # need to be removed...
</span><del>-        if (defined $cgi-&gt;param('removecc') &amp;&amp; $cgi-&gt;param('cc')) {
-            $cc_remove = join (&quot;,&quot;, $cgi-&gt;param('cc'));
</del><ins>+        if ($cgi-&gt;param('removecc') &amp;&amp; $cgi-&gt;param('cc')) {
+            @cc_remove = $cgi-&gt;param('cc');
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    push(@cc_add, split(/[\s,]+/, $cc_add)) if $cc_add;
-    push(@cc_add, Bugzilla-&gt;user) if $cgi-&gt;param('addselfcc');
-
-    push(@cc_remove, split(/[\s,]+/, $cc_remove)) if $cc_remove;
</del><ins>+    $set_all_fields{cc} = { add =&gt; \@cc_add, remove =&gt; \@cc_remove };
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-foreach my $b (@bug_objects) {
-    $b-&gt;remove_cc($_) foreach @cc_remove;
-    $b-&gt;add_cc($_) foreach @cc_add;
-    # Theoretically you could move a product without ever specifying
-    # a new assignee or qa_contact, or adding/removing any CCs. So,
-    # we have to check that the current assignee, qa, and CCs are still
-    # valid if we've switched products, under strict_isolation. We can only
-    # do that here. There ought to be some better way to do this,
-    # architecturally, but I haven't come up with it.
-    if ($product_change) {
-        $b-&gt;_check_strict_isolation();
</del><ins>+# Fields that can only be set on one bug at a time.
+if (defined $cgi-&gt;param('id')) {
+    # Since aliases are unique (like bug numbers), they can only be changed
+    # for one bug at a time.
+    if (Bugzilla-&gt;params-&gt;{&quot;usebugaliases&quot;} &amp;&amp; defined $cgi-&gt;param('alias')) {
+        $set_all_fields{alias} = $cgi-&gt;param('alias');
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-my $move_action = $cgi-&gt;param('action') || '';
-if ($move_action eq Bugzilla-&gt;params-&gt;{'move-button-text'}) {
-    Bugzilla-&gt;params-&gt;{'move-enabled'} || ThrowUserError(&quot;move_bugs_disabled&quot;);
</del><ins>+my %is_private;
+foreach my $field (grep(/^defined_isprivate/, $cgi-&gt;param())) {
+    $field =~ /(\d+)$/;
+    my $comment_id = $1;
+    $is_private{$comment_id} = $cgi-&gt;param(&quot;isprivate_$comment_id&quot;);
+}
+$set_all_fields{comment_is_private} = \%is_private;
</ins><span class="cx"> 
</span><del>-    $user-&gt;is_mover || ThrowUserError(&quot;auth_failure&quot;, {action =&gt; 'move',
-                                                       object =&gt; 'bugs'});
</del><ins>+my @check_groups = $cgi-&gt;param('defined_groups');
+my @set_groups = $cgi-&gt;param('groups');
+my ($removed_groups) = diff_arrays(\@check_groups, \@set_groups);
+$set_all_fields{groups} = { add =&gt; \@set_groups, remove =&gt; $removed_groups };
</ins><span class="cx"> 
</span><del>-    $dbh-&gt;bz_start_transaction();
-
-    # First update all moved bugs.
-    foreach my $bug (@bug_objects) {
-        $bug-&gt;add_comment('', { type =&gt; CMT_MOVED_TO, extra_data =&gt; $user-&gt;login });
</del><ins>+my @custom_fields = Bugzilla-&gt;active_custom_fields;
+foreach my $field (@custom_fields) {
+    my $fname = $field-&gt;name;
+    if (should_set($fname, 1)) {
+        $set_all_fields{$fname} = [$cgi-&gt;param($fname)];
</ins><span class="cx">     }
</span><del>-    # Don't export the new status and resolution. We want the current ones.
-    local $Storable::forgive_me = 1;
-    my $bugs = dclone(\@bug_objects);
-
-    my $new_status = Bugzilla-&gt;params-&gt;{'duplicate_or_move_bug_status'};
-    foreach my $bug (@bug_objects) {
-        $bug-&gt;set_status($new_status, {resolution =&gt; 'MOVED', moving =&gt; 1});
-    }
-    $_-&gt;update() foreach @bug_objects;
-    $dbh-&gt;bz_commit_transaction();
-
-    # Now send emails.
-    foreach my $bug (@bug_objects) {
-        $vars-&gt;{'mailrecipients'} = { 'changer' =&gt; $user-&gt;login };
-        $vars-&gt;{'id'} = $bug-&gt;id;
-        $vars-&gt;{'type'} = &quot;move&quot;;
-        send_results($bug-&gt;id, $vars);
-    }
-    # Prepare and send all data about these bugs to the new database
-    my $to = Bugzilla-&gt;params-&gt;{'move-to-address'};
-    $to =~ s/@/\@/;
-    my $from = Bugzilla-&gt;params-&gt;{'moved-from-address'};
-    $from =~ s/@/\@/;
-    my $msg = &quot;To: $to\n&quot;;
-    $msg .= &quot;From: Bugzilla &lt;&quot; . $from . &quot;&gt;\n&quot;;
-    $msg .= &quot;Subject: Moving bug(s) &quot; . join(', ', map($_-&gt;id, @bug_objects))
-            . &quot;\n\n&quot;;
-
-    my @fieldlist = (Bugzilla::Bug-&gt;fields, 'group', 'long_desc',
-                     'attachment', 'attachmentdata');
-    my %displayfields;
-    foreach (@fieldlist) {
-        $displayfields{$_} = 1;
-    }
-
-    $template-&gt;process(&quot;bug/show.xml.tmpl&quot;, { bugs =&gt; $bugs,
-                                              displayfields =&gt; \%displayfields,
-                                            }, \$msg)
-      || ThrowTemplateError($template-&gt;error());
-
-    $msg .= &quot;\n&quot;;
-    MessageToMTA($msg);
-
-    # End the response page.
-    unless (Bugzilla-&gt;usage_mode == USAGE_MODE_EMAIL) {
-        $template-&gt;process(&quot;bug/navigate.html.tmpl&quot;, $vars)
-            || ThrowTemplateError($template-&gt;error());
-        $template-&gt;process(&quot;global/footer.html.tmpl&quot;, $vars)
-            || ThrowTemplateError($template-&gt;error());
-    }
-    exit;
</del><span class="cx"> }
</span><span class="cx"> 
</span><del>-
-# You cannot mark bugs as duplicates when changing several bugs at once
-# (because currently there is no way to check for duplicate loops in that
-# situation).
-if (!$cgi-&gt;param('id') &amp;&amp; $cgi-&gt;param('dup_id')) {
-    ThrowUserError('dupe_not_allowed');
-}
-
-# Set the status, resolution, and dupe_of (if needed). This has to be done
-# down here, because the validity of status changes depends on other fields,
-# such as Target Milestone.
</del><ins>+# We are going to alter the list of removed groups, so we keep a copy here.
+my @unchecked_groups = @$removed_groups;
</ins><span class="cx"> foreach my $b (@bug_objects) {
</span><del>-    if (should_set('bug_status')) {
-        $b-&gt;set_status(
-            scalar $cgi-&gt;param('bug_status'),
-            {resolution =&gt;  scalar $cgi-&gt;param('resolution'),
-                dupe_of =&gt; scalar $cgi-&gt;param('dup_id')}
-            );
</del><ins>+    # Don't blindly ask to remove unchecked groups available in the UI.
+    # A group can be already unchecked, and the user didn't try to remove it.
+    # In this case, we don't want remove_group() to complain.
+    my @remove_groups;
+    foreach my $g (@{$b-&gt;groups_in}) {
+        push(@remove_groups, $g-&gt;name) if grep { $_ eq $g-&gt;name } @unchecked_groups;
</ins><span class="cx">     }
</span><del>-    elsif (should_set('resolution')) {
-       $b-&gt;set_resolution(scalar $cgi-&gt;param('resolution'), 
-                          {dupe_of =&gt; scalar $cgi-&gt;param('dup_id')});
-    }
-    elsif (should_set('dup_id')) {
-        $b-&gt;set_dup_id(scalar $cgi-&gt;param('dup_id'));
-    }
</del><ins>+    local $set_all_fields{groups}-&gt;{remove} = \@remove_groups;
+    $b-&gt;set_all(\%set_all_fields);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+if (defined $cgi-&gt;param('id')) {
+    # Flags should be set AFTER the bug has been moved into another
+    # product/component. The structure of flags code doesn't currently
+    # allow them to be set using set_all.
+    my ($flags, $new_flags) = Bugzilla::Flag-&gt;extract_flags_from_cgi(
+        $first_bug, undef, $vars);
+    $first_bug-&gt;set_flags($flags, $new_flags);
+}
+
</ins><span class="cx"> ##############################
</span><span class="cx"> # Do Actual Database Updates #
</span><span class="cx"> ##############################
</span><span class="cx"> foreach my $bug (@bug_objects) {
</span><del>-    $dbh-&gt;bz_start_transaction();
</del><ins>+    my $changes = $bug-&gt;update();
</ins><span class="cx"> 
</span><del>-    my $timestamp = $dbh-&gt;selectrow_array(q{SELECT NOW()});
-    my $changes = $bug-&gt;update($timestamp);
-
-    my %notify_deps;
</del><span class="cx">     if ($changes-&gt;{'bug_status'}) {
</span><del>-        my ($old_status, $new_status) = @{ $changes-&gt;{'bug_status'} };
-        
-        # If this bug has changed from opened to closed or vice-versa,
-        # then all of the bugs we block need to be notified.
-        if (is_open_state($old_status) ne is_open_state($new_status)) {
-            $notify_deps{$_} = 1 foreach (@{$bug-&gt;blocked});
-        }
-        
</del><ins>+        my $new_status = $changes-&gt;{'bug_status'}-&gt;[1];
</ins><span class="cx">         # We may have zeroed the remaining time, if we moved into a closed
</span><span class="cx">         # status, so we should inform the user about that.
</span><span class="cx">         if (!is_open_state($new_status) &amp;&amp; $changes-&gt;{'remaining_time'}) {
</span><span class="cx">             $vars-&gt;{'message'} = &quot;remaining_time_zeroed&quot;
</span><del>-              if Bugzilla-&gt;user-&gt;in_group(Bugzilla-&gt;params-&gt;{'timetrackinggroup'});
</del><ins>+              if Bugzilla-&gt;user-&gt;is_timetracker;
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    # To get a list of all changed dependencies, convert the &quot;changes&quot; arrays
-    # into a long string, then collapse that string into unique numbers in
-    # a hash.
-    my $all_changed_deps = join(', ', @{ $changes-&gt;{'dependson'} || [] });
-    $all_changed_deps = join(', ', @{ $changes-&gt;{'blocked'} || [] },
-                                   $all_changed_deps);
-    my %changed_deps = map { $_ =&gt; 1 } split(', ', $all_changed_deps);
-    # When clearning one field (say, blocks) and filling in the other
-    # (say, dependson), an empty string can get into the hash and cause
-    # an error later.
-    delete $changed_deps{''};
-
-    # $msgs will store emails which have to be sent to voters, if any.
-    my $msgs;
-    if ($changes-&gt;{'product'}) {
-        # If some votes have been removed, RemoveVotes() returns
-        # a list of messages to send to voters.
-        # We delay the sending of these messages till tables are unlocked.
-        $msgs = RemoveVotes($bug-&gt;id, 0, 'votes_bug_moved');
-        CheckIfVotedConfirmed($bug-&gt;id, Bugzilla-&gt;user-&gt;id);
-    }
-
-    # Set and update flags.
-    Bugzilla::Flag-&gt;process($bug, undef, $timestamp, $vars);
-
-    $dbh-&gt;bz_commit_transaction();
-
-    ###############
-    # Send Emails #
-    ###############
-
-    # Now is a good time to send email to voters.
-    foreach my $msg (@$msgs) {
-        MessageToMTA($msg);
-    }
-
-    my $old_qa  = $changes-&gt;{'qa_contact'}  ? $changes-&gt;{'qa_contact'}-&gt;[0] : '';
-    my $old_own = $changes-&gt;{'assigned_to'} ? $changes-&gt;{'assigned_to'}-&gt;[0] : '';
-    my $old_cc  = $changes-&gt;{cc}            ? $changes-&gt;{cc}-&gt;[0] : '';
-    $vars-&gt;{'mailrecipients'} = {
-        cc        =&gt; [split(/[\s,]+/, $old_cc)],
-        owner     =&gt; $old_own,
-        qacontact =&gt; $old_qa,
-        changer   =&gt; Bugzilla-&gt;user-&gt;login };
-
-    $vars-&gt;{'id'} = $bug-&gt;id;
-    $vars-&gt;{'type'} = &quot;bug&quot;;
-    
-    # Let the user know the bug was changed and who did and didn't
-    # receive email about the change.
-    send_results($bug-&gt;id, $vars);

-    # If the bug was marked as a duplicate, we need to notify users on the
-    # other bug of any changes to that bug.
-    my $new_dup_id = $changes-&gt;{'dup_id'} ? $changes-&gt;{'dup_id'}-&gt;[1] : undef;
-    if ($new_dup_id) {
-        $vars-&gt;{'mailrecipients'} = { 'changer' =&gt; Bugzilla-&gt;user-&gt;login }; 
-
-        $vars-&gt;{'id'} = $new_dup_id;
-        $vars-&gt;{'type'} = &quot;dupe&quot;;
-        
-        # Let the user know a duplication notation was added to the 
-        # original bug.
-        send_results($new_dup_id, $vars);
-    }
-
-    my %all_dep_changes = (%notify_deps, %changed_deps);
-    foreach my $id (sort { $a &lt;=&gt; $b } (keys %all_dep_changes)) {
-        $vars-&gt;{'mailrecipients'} = { 'changer' =&gt; Bugzilla-&gt;user-&gt;login };
-        $vars-&gt;{'id'} = $id;
-        $vars-&gt;{'type'} = &quot;dep&quot;;
-
-        # Let the user (if he is able to see the bug) know we checked to
-        # see if we should email notice of this change to users with a 
-        # relationship to the dependent bug and who did and didn't 
-        # receive email about it.
-        send_results($id, $vars);
-    }
</del><ins>+    $bug-&gt;send_changes($changes, $vars);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-# Determine if Patch Viewer is installed, for Diff link
-# (NB: Duplicate code with show_bug.cgi.)
-eval {
-    require PatchReader;
-    $vars-&gt;{'patchviewerinstalled'} = 1;
-};
</del><ins>+# Delete the session token used for the mass-change.
+delete_token($token) unless $cgi-&gt;param('id');
</ins><span class="cx"> 
</span><span class="cx"> if (Bugzilla-&gt;usage_mode == USAGE_MODE_EMAIL) {
</span><span class="cx">     # Do nothing.
</span><span class="cx"> }
</span><del>-elsif ($action eq 'next_bug') {
-    if ($next_bug) {
-        if (detaint_natural($next_bug) &amp;&amp; Bugzilla-&gt;user-&gt;can_see_bug($next_bug)) {
-            my $bug = new Bugzilla::Bug($next_bug);
-            ThrowCodeError(&quot;bug_error&quot;, { bug =&gt; $bug }) if $bug-&gt;error;
-
-            $vars-&gt;{'bugs'} = [$bug];
-            $vars-&gt;{'nextbug'} = $bug-&gt;bug_id;
-
-            $template-&gt;process(&quot;bug/show.html.tmpl&quot;, $vars)
-              || ThrowTemplateError($template-&gt;error());
-
-            exit;
</del><ins>+elsif ($action eq 'next_bug' or $action eq 'same_bug') {
+    my $bug = $vars-&gt;{'bug'};
+    if ($bug and $user-&gt;can_see_bug($bug)) {
+        if ($action eq 'same_bug') {
+            # $bug-&gt;update() does not update the internal structure of
+            # the bug sufficiently to display the bug with the new values.
+            # (That is, if we just passed in the old Bug object, we'd get
+            # a lot of old values displayed.)
+            $bug = new Bugzilla::Bug($bug-&gt;id);
+            $vars-&gt;{'bug'} = $bug;
</ins><span class="cx">         }
</span><del>-    }
-} elsif ($action eq 'same_bug') {
-    if (Bugzilla-&gt;user-&gt;can_see_bug($cgi-&gt;param('id'))) {
-        my $bug = new Bugzilla::Bug($cgi-&gt;param('id'));
-        ThrowCodeError(&quot;bug_error&quot;, { bug =&gt; $bug }) if $bug-&gt;error;
-
</del><span class="cx">         $vars-&gt;{'bugs'} = [$bug];
</span><del>-
</del><ins>+        if ($action eq 'next_bug') {
+            $vars-&gt;{'nextbug'} = $bug-&gt;id;
+        }
</ins><span class="cx">         $template-&gt;process(&quot;bug/show.html.tmpl&quot;, $vars)
</span><span class="cx">           || ThrowTemplateError($template-&gt;error());
</span><del>-
</del><span class="cx">         exit;
</span><span class="cx">     }
</span><span class="cx"> } elsif ($action ne 'nothing') {
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgquerycgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/query.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/query.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/query.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -49,44 +49,6 @@
</span><span class="cx"> my $user = Bugzilla-&gt;login();
</span><span class="cx"> my $userid = $user-&gt;id;
</span><span class="cx"> 
</span><del>-# Backwards compatibility hack -- if there are any of the old QUERY_*
-# cookies around, and we are logged in, then move them into the database
-# and nuke the cookie. This is required for Bugzilla 2.8 and earlier.
-if ($userid) {
-    my @oldquerycookies;
-    foreach my $i ($cgi-&gt;cookie()) {
-        if ($i =~ /^QUERY_(.*)$/) {
-            push(@oldquerycookies, [$1, $i, $cgi-&gt;cookie($i)]);
-        }
-    }
-    if (defined $cgi-&gt;cookie('DEFAULTQUERY')) {
-        push(@oldquerycookies, [DEFAULT_QUERY_NAME, 'DEFAULTQUERY',
-                                $cgi-&gt;cookie('DEFAULTQUERY')]);
-    }
-    if (@oldquerycookies) {
-        foreach my $ref (@oldquerycookies) {
-            my ($name, $cookiename, $value) = (@$ref);
-            if ($value) {
-                # If the query name contains invalid characters, don't import.
-                $name =~ /[&lt;&gt;&amp;]/ &amp;&amp; next;
-                trick_taint($name);
-                $dbh-&gt;bz_start_transaction();
-                my $query = $dbh-&gt;selectrow_array(
-                    &quot;SELECT query FROM namedqueries &quot; .
-                     &quot;WHERE userid = ? AND name = ?&quot;,
-                     undef, ($userid, $name));
-                if (!$query) {
-                    $dbh-&gt;do(&quot;INSERT INTO namedqueries &quot; .
-                            &quot;(userid, name, query) VALUES &quot; .
-                            &quot;(?, ?, ?)&quot;, undef, ($userid, $name, $value));
-                }
-                $dbh-&gt;bz_commit_transaction();
-            }
-            $cgi-&gt;remove_cookie($cookiename);
-        }
-    }
-}
-
</del><span class="cx"> if ($cgi-&gt;param('nukedefaultquery')) {
</span><span class="cx">     if ($userid) {
</span><span class="cx">         $dbh-&gt;do(&quot;DELETE FROM namedqueries&quot; .
</span><span class="lines">@@ -96,6 +58,9 @@
</span><span class="cx">     $buffer = &quot;&quot;;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# We are done with changes committed to the DB.
+$dbh = Bugzilla-&gt;switch_to_shadow_db;
+
</ins><span class="cx"> my $userdefaultquery;
</span><span class="cx"> if ($userid) {
</span><span class="cx">     $userdefaultquery = $dbh-&gt;selectrow_array(
</span><span class="lines">@@ -110,64 +75,46 @@
</span><span class="cx"> # Items which are single-valued, the template should only reference [0]
</span><span class="cx"> # and ignore any multiple values.
</span><span class="cx"> sub PrefillForm {
</span><del>-    my ($buf) = (@_);
</del><ins>+    my ($buf) = @_;
</ins><span class="cx">     my $cgi = Bugzilla-&gt;cgi;
</span><span class="cx">     $buf = new Bugzilla::CGI($buf);
</span><span class="cx">     my $foundone = 0;
</span><span class="cx"> 
</span><del>-    # Nothing must be undef, otherwise the template complains.
-    foreach my $name (&quot;bug_status&quot;, &quot;resolution&quot;, &quot;assigned_to&quot;,
-                      &quot;rep_platform&quot;, &quot;priority&quot;, &quot;bug_severity&quot;,
-                      &quot;classification&quot;, &quot;product&quot;, &quot;reporter&quot;, &quot;op_sys&quot;,
-                      &quot;component&quot;, &quot;version&quot;, &quot;chfield&quot;, &quot;chfieldfrom&quot;,
-                      &quot;chfieldto&quot;, &quot;chfieldvalue&quot;, &quot;target_milestone&quot;,
-                      &quot;email&quot;, &quot;emailtype&quot;, &quot;emailreporter&quot;,
-                      &quot;emailassigned_to&quot;, &quot;emailcc&quot;, &quot;emailqa_contact&quot;,
-                      &quot;emaillongdesc&quot;, &quot;content&quot;,
-                      &quot;changedin&quot;, &quot;votes&quot;, &quot;short_desc&quot;, &quot;short_desc_type&quot;,
-                      &quot;long_desc&quot;, &quot;long_desc_type&quot;, &quot;bug_file_loc&quot;,
-                      &quot;bug_file_loc_type&quot;, &quot;status_whiteboard&quot;,
-                      &quot;status_whiteboard_type&quot;, &quot;bug_id&quot;,
-                      &quot;bugidtype&quot;, &quot;keywords&quot;, &quot;keywords_type&quot;,
-                      &quot;deadlinefrom&quot;, &quot;deadlineto&quot;,
-                      &quot;x_axis_field&quot;, &quot;y_axis_field&quot;, &quot;z_axis_field&quot;,
-                      &quot;chart_format&quot;, &quot;cumulate&quot;, &quot;x_labels_vertical&quot;,
-                      &quot;category&quot;, &quot;subcategory&quot;, &quot;name&quot;, &quot;newcategory&quot;,
-                      &quot;newsubcategory&quot;, &quot;public&quot;, &quot;frequency&quot;) 
-    {
-        $default{$name} = [];
</del><ins>+    # If there are old-style boolean charts in the URL (from an old saved
+    # search or from an old link on the web somewhere) then convert them
+    # to the new &quot;custom search&quot; format so that the form is populated
+    # properly.
+    my $any_boolean_charts = grep { /^field-?\d+/ } $buf-&gt;param();
+    if ($any_boolean_charts) {
+        my $search = new Bugzilla::Search(params =&gt; scalar $buf-&gt;Vars);
+        $search-&gt;boolean_charts_to_custom_search($buf);
</ins><span class="cx">     }
</span><del>- 
-    # we won't prefill the boolean chart data from this query if
-    # there are any being submitted via params
-    my $prefillcharts = (grep(/^field-/, $cgi-&gt;param)) ? 0 : 1;

</del><ins>+
+    # Query parameters that don't represent form fields on this page.
+    my @skip = qw(format query_format list_id columnlist);
+
</ins><span class="cx">     # Iterate over the URL parameters
</span><span class="cx">     foreach my $name ($buf-&gt;param()) {
</span><ins>+        next if grep { $_ eq $name } @skip;
+        $foundone = 1;
</ins><span class="cx">         my @values = $buf-&gt;param($name);
</span><del>-
-        # If the name begins with the string 'field', 'type', 'value', or
-        # 'negate', then it is part of the boolean charts. Because
-        # these are built different than the rest of the form, we need
-        # to store these as parameters. We also need to indicate that
-        # we found something so the default query isn't added in if
-        # all we have are boolean chart items.
-        if ($name =~ m/^(?:field|type|value|negate)/) {
-            $cgi-&gt;param(-name =&gt; $name, -value =&gt; $values[0]) if ($prefillcharts);
-            $foundone = 1;
</del><ins>+        
+        # If the name is a single letter followed by numbers, it's part
+        # of Custom Search. We store these as an array of hashes.
+        if ($name =~ /^([[:lower:]])(\d+)$/) {
+            $default{'custom_search'}-&gt;[$2]-&gt;{$1} = $values[0];
</ins><span class="cx">         }
</span><span class="cx">         # If the name ends in a number (which it does for the fields which
</span><span class="cx">         # are part of the email searching), we use the array
</span><span class="cx">         # positions to show the defaults for that number field.
</span><del>-        elsif ($name =~ m/^(.+)(\d)$/ &amp;&amp; defined($default{$1})) {
-            $foundone = 1;
</del><ins>+        elsif ($name =~ /^(\w+)(\d)$/) {
</ins><span class="cx">             $default{$1}-&gt;[$2] = $values[0];
</span><span class="cx">         }
</span><del>-        elsif (exists $default{$name}) {
-            $foundone = 1;
-            push (@{$default{$name}}, @values);
</del><ins>+        else {
+            push (@{ $default{$name} }, @values);
</ins><span class="cx">         }
</span><span class="cx">     }
</span><ins>+
</ins><span class="cx">     return $foundone;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -181,10 +128,6 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-if (!scalar(@{$default{'chfieldto'}}) || $default{'chfieldto'}-&gt;[0] eq &quot;&quot;) {
-    $default{'chfieldto'} = [&quot;Now&quot;];
-}
-
</del><span class="cx"> # if using groups for entry, then we don't want people to see products they 
</span><span class="cx"> # don't have access to. Remove them from the list.
</span><span class="cx"> my @selectable_products = sort {lc($a-&gt;name) cmp lc($b-&gt;name)} 
</span><span class="lines">@@ -196,6 +139,9 @@
</span><span class="cx"> my %versions;
</span><span class="cx"> my %milestones;
</span><span class="cx"> 
</span><ins>+# Exclude products with no components.
+@selectable_products = grep { scalar @{$_-&gt;components} } @selectable_products;
+
</ins><span class="cx"> foreach my $product (@selectable_products) {
</span><span class="cx">     $components{$_-&gt;name} = 1 foreach (@{$product-&gt;components});
</span><span class="cx">     $versions{$_-&gt;name}   = 1 foreach (@{$product-&gt;versions});
</span><span class="lines">@@ -222,13 +168,6 @@
</span><span class="cx">     $vars-&gt;{'target_milestone'} = \@milestones;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-$vars-&gt;{'have_keywords'} = Bugzilla::Keyword::keyword_count();
-
-my $legal_resolutions = get_legal_field_values('resolution');
-push(@$legal_resolutions, &quot;---&quot;); # Oy, what a hack.
-# Another hack - this array contains &quot;&quot; for some reason. See bug 106589.
-$vars-&gt;{'resolution'} = [grep ($_, @$legal_resolutions)];
-
</del><span class="cx"> my @chfields;
</span><span class="cx"> 
</span><span class="cx"> push @chfields, &quot;[Bug creation]&quot;;
</span><span class="lines">@@ -246,28 +185,28 @@
</span><span class="cx">     push @chfields, $val;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-if (Bugzilla-&gt;user-&gt;in_group(Bugzilla-&gt;params-&gt;{'timetrackinggroup'})) {
</del><ins>+if (Bugzilla-&gt;user-&gt;is_timetracker) {
</ins><span class="cx">     push @chfields, &quot;work_time&quot;;
</span><span class="cx"> } else {
</span><ins>+    @chfields = grep($_ ne &quot;deadline&quot;, @chfields);
</ins><span class="cx">     @chfields = grep($_ ne &quot;estimated_time&quot;, @chfields);
</span><span class="cx">     @chfields = grep($_ ne &quot;remaining_time&quot;, @chfields);
</span><span class="cx"> }
</span><span class="cx"> @chfields = (sort(@chfields));
</span><span class="cx"> $vars-&gt;{'chfield'} = \@chfields;
</span><del>-$vars-&gt;{'bug_status'} = get_legal_field_values('bug_status');
-$vars-&gt;{'rep_platform'} = get_legal_field_values('rep_platform');
-$vars-&gt;{'op_sys'} = get_legal_field_values('op_sys');
-$vars-&gt;{'priority'} = get_legal_field_values('priority');
-$vars-&gt;{'bug_severity'} = get_legal_field_values('bug_severity');
</del><ins>+$vars-&gt;{'bug_status'} = Bugzilla::Field-&gt;new({name =&gt; 'bug_status'})-&gt;legal_values;
+$vars-&gt;{'rep_platform'} = Bugzilla::Field-&gt;new({name =&gt; 'rep_platform'})-&gt;legal_values;
+$vars-&gt;{'op_sys'} = Bugzilla::Field-&gt;new({name =&gt; 'op_sys'})-&gt;legal_values;
+$vars-&gt;{'priority'} = Bugzilla::Field-&gt;new({name =&gt; 'priority'})-&gt;legal_values;
+$vars-&gt;{'bug_severity'} = Bugzilla::Field-&gt;new({name =&gt; 'bug_severity'})-&gt;legal_values;
+$vars-&gt;{'resolution'} = Bugzilla::Field-&gt;new({name =&gt; 'resolution'})-&gt;legal_values;
</ins><span class="cx"> 
</span><span class="cx"> # Boolean charts
</span><del>-my @fields = Bugzilla-&gt;get_fields({ obsolete =&gt; 0 });
</del><ins>+my @fields = @{ Bugzilla-&gt;fields({ obsolete =&gt; 0 }) };
</ins><span class="cx"> 
</span><span class="cx"> # If we're not in the time-tracking group, exclude time-tracking fields.
</span><del>-if (!Bugzilla-&gt;user-&gt;in_group(Bugzilla-&gt;params-&gt;{'timetrackinggroup'})) {
-    foreach my $tt_field (qw(estimated_time remaining_time work_time
-                             percentage_complete deadline))
-    {
</del><ins>+if (!Bugzilla-&gt;user-&gt;is_timetracker) {
+    foreach my $tt_field (TIMETRACKING_FIELDS) {
</ins><span class="cx">         @fields = grep($_-&gt;name ne $tt_field, @fields);
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="lines">@@ -276,43 +215,6 @@
</span><span class="cx"> unshift(@fields, { name =&gt; &quot;noop&quot;, description =&gt; &quot;---&quot; });
</span><span class="cx"> $vars-&gt;{'fields'} = \@fields;
</span><span class="cx"> 
</span><del>-# Creating new charts - if the cmd-add value is there, we define the field
-# value so the code sees it and creates the chart. It will attempt to select
-# &quot;xyzzy&quot; as the default, and fail. This is the correct behaviour.
-foreach my $cmd (grep(/^cmd-/, $cgi-&gt;param)) {
-    if ($cmd =~ /^cmd-add(\d+)-(\d+)-(\d+)$/) {
-        $cgi-&gt;param(-name =&gt; &quot;field$1-$2-$3&quot;, -value =&gt; &quot;xyzzy&quot;);
-    }
-}
-
-if (!$cgi-&gt;param('field0-0-0')) {
-    $cgi-&gt;param(-name =&gt; 'field0-0-0', -value =&gt; &quot;xyzzy&quot;);
-}
-
-# Create data structure of boolean chart info. It's an array of arrays of
-# arrays - with the inner arrays having three members - field, type and
-# value.
-my @charts;
-for (my $chart = 0; $cgi-&gt;param(&quot;field$chart-0-0&quot;); $chart++) {
-    my @rows;
-    for (my $row = 0; $cgi-&gt;param(&quot;field$chart-$row-0&quot;); $row++) {
-        my @cols;
-        for (my $col = 0; $cgi-&gt;param(&quot;field$chart-$row-$col&quot;); $col++) {
-            my $value = $cgi-&gt;param(&quot;value$chart-$row-$col&quot;);
-            if (!defined($value)) {
-                $value = '';
-            }
-            push(@cols, { field =&gt; $cgi-&gt;param(&quot;field$chart-$row-$col&quot;),
-                          type =&gt; $cgi-&gt;param(&quot;type$chart-$row-$col&quot;) || 'noop',
-                          value =&gt; $value });
-        }
-        push(@rows, \@cols);
-    }
-    push(@charts, {'rows' =&gt; \@rows, 'negate' =&gt; scalar($cgi-&gt;param(&quot;negate$chart&quot;)) });
-}
-
-$default{'charts'} = \@charts;
-
</del><span class="cx"> # Named queries
</span><span class="cx"> if ($userid) {
</span><span class="cx">      $vars-&gt;{'namedqueries'} = $dbh-&gt;selectcol_arrayref(
</span><span class="lines">@@ -343,7 +245,15 @@
</span><span class="cx">     $vars-&gt;{'category'} = Bugzilla::Chart::getVisibleSeries();
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+if ($cgi-&gt;param('format') &amp;&amp; $cgi-&gt;param('format') =~ /^report-(table|graph)$/) {
+    # Get legal custom fields for tabular and graphical reports.
+    my @custom_fields_for_reports =
+      grep { $_-&gt;type == FIELD_TYPE_SINGLE_SELECT } Bugzilla-&gt;active_custom_fields;
+    $vars-&gt;{'custom_fields'} = \@custom_fields_for_reports;
+}
+
</ins><span class="cx"> $vars-&gt;{'known_name'} = $cgi-&gt;param('known_name');
</span><ins>+$vars-&gt;{'columnlist'} = $cgi-&gt;param('columnlist');
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> # Add in the defaults.
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgquipscgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/quips.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/quips.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/quips.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -32,6 +32,7 @@
</span><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> use Bugzilla::Error;
</span><span class="cx"> use Bugzilla::User;
</span><ins>+use Bugzilla::Token;
</ins><span class="cx"> 
</span><span class="cx"> my $user = Bugzilla-&gt;login(LOGIN_REQUIRED);
</span><span class="cx"> 
</span><span class="lines">@@ -41,6 +42,7 @@
</span><span class="cx"> my $vars = {};
</span><span class="cx"> 
</span><span class="cx"> my $action = $cgi-&gt;param('action') || &quot;&quot;;
</span><ins>+my $token = $cgi-&gt;param('token');
</ins><span class="cx"> 
</span><span class="cx"> if ($action eq &quot;show&quot;) {
</span><span class="cx">     # Read in the entire quip list
</span><span class="lines">@@ -74,9 +76,10 @@
</span><span class="cx">     (Bugzilla-&gt;params-&gt;{'quip_list_entry_control'} eq &quot;closed&quot;) &amp;&amp;
</span><span class="cx">       ThrowUserError(&quot;no_new_quips&quot;);
</span><span class="cx"> 
</span><ins>+    check_hash_token($token, ['create-quips']);
</ins><span class="cx">     # Add the quip 
</span><span class="cx">     my $approved = (Bugzilla-&gt;params-&gt;{'quip_list_entry_control'} eq &quot;open&quot;)
</span><del>-                   || Bugzilla-&gt;user-&gt;in_group('admin') || 0;
</del><ins>+                   || $user-&gt;in_group('bz_quip_moderators') || 0;
</ins><span class="cx">     my $comment = $cgi-&gt;param(&quot;quip&quot;);
</span><span class="cx">     $comment || ThrowUserError(&quot;need_quip&quot;);
</span><span class="cx">     trick_taint($comment); # Used in a placeholder below
</span><span class="lines">@@ -88,11 +91,12 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> if ($action eq 'approve') {
</span><del>-    $user-&gt;in_group('admin')
-      || ThrowUserError(&quot;auth_failure&quot;, {group  =&gt; &quot;admin&quot;,
</del><ins>+    $user-&gt;in_group('bz_quip_moderators')
+      || ThrowUserError(&quot;auth_failure&quot;, {group  =&gt; &quot;bz_quip_moderators&quot;,
</ins><span class="cx">                                          action =&gt; &quot;approve&quot;,
</span><span class="cx">                                          object =&gt; &quot;quips&quot;});
</span><del>- 
</del><ins>+
+    check_hash_token($token, ['approve-quips']);
</ins><span class="cx">     # Read in the entire quip list
</span><span class="cx">     my $quipsref = $dbh-&gt;selectall_arrayref(&quot;SELECT quipid, approved FROM quips&quot;);
</span><span class="cx">     
</span><span class="lines">@@ -127,13 +131,14 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> if ($action eq &quot;delete&quot;) {
</span><del>-    Bugzilla-&gt;user-&gt;in_group(&quot;admin&quot;)
-      || ThrowUserError(&quot;auth_failure&quot;, {group  =&gt; &quot;admin&quot;,
</del><ins>+    $user-&gt;in_group('bz_quip_moderators')
+      || ThrowUserError(&quot;auth_failure&quot;, {group  =&gt; &quot;bz_quip_moderators&quot;,
</ins><span class="cx">                                          action =&gt; &quot;delete&quot;,
</span><span class="cx">                                          object =&gt; &quot;quips&quot;});
</span><span class="cx">     my $quipid = $cgi-&gt;param(&quot;quipid&quot;);
</span><span class="cx">     ThrowCodeError(&quot;need_quipid&quot;) unless $quipid =~ /(\d+)/; 
</span><span class="cx">     $quipid = $1;
</span><ins>+    check_hash_token($token, ['quips', $quipid]);
</ins><span class="cx"> 
</span><span class="cx">     ($vars-&gt;{'deleted_quip'}) = $dbh-&gt;selectrow_array(
</span><span class="cx">                                     &quot;SELECT quip FROM quips WHERE quipid = ?&quot;,
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgrelogincgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/relogin.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/relogin.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/relogin.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -37,13 +37,18 @@
</span><span class="cx"> my $template = Bugzilla-&gt;template;
</span><span class="cx"> my $cgi = Bugzilla-&gt;cgi;
</span><span class="cx"> 
</span><del>-my $action = $cgi-&gt;param('action') || 'logout';
</del><ins>+my $action = $cgi-&gt;param('action') || '';
</ins><span class="cx"> 
</span><span class="cx"> my $vars = {};
</span><span class="cx"> my $target;
</span><span class="cx"> 
</span><ins>+if (!$action) {
+    # redirect to index.cgi if no action is defined.
+    print $cgi-&gt;redirect(correct_urlbase() . 'index.cgi');
+    exit;
+}
</ins><span class="cx"> # prepare-sudo: Display the sudo information &amp; login page
</span><del>-if ($action eq 'prepare-sudo') {
</del><ins>+elsif ($action eq 'prepare-sudo') {
</ins><span class="cx">     # We must have a logged-in user to do this
</span><span class="cx">     # That user must be in the 'bz_sudoers' group
</span><span class="cx">     my $user = Bugzilla-&gt;login(LOGIN_REQUIRED);
</span><span class="lines">@@ -140,15 +145,16 @@
</span><span class="cx"> 
</span><span class="cx">     # If we have a reason passed in, keep it under 200 characters
</span><span class="cx">     my $reason = $cgi-&gt;param('reason') || '';
</span><del>-    $reason = substr($reason, $[, 200);
</del><ins>+    $reason = substr($reason, 0, 200);
</ins><span class="cx">     
</span><span class="cx">     # Calculate the session expiry time (T + 6 hours)
</span><del>-    my $time_string = time2str('%a, %d-%b-%Y %T %Z', time+(6*60*60), 'GMT');
</del><ins>+    my $time_string = time2str('%a, %d-%b-%Y %T %Z', time + MAX_SUDO_TOKEN_AGE, 'GMT');
</ins><span class="cx"> 
</span><span class="cx">     # For future sessions, store the unique ID of the target user
</span><ins>+    my $token = Bugzilla::Token::_create_token($user-&gt;id, 'sudo', $target_user-&gt;id);
</ins><span class="cx">     $cgi-&gt;send_cookie('-name'    =&gt; 'sudo',
</span><span class="cx">                       '-expires' =&gt; $time_string,
</span><del>-                      '-value'   =&gt; $target_user-&gt;id
</del><ins>+                      '-value'   =&gt; $token
</ins><span class="cx">     );
</span><span class="cx">     
</span><span class="cx">     # For the present, change the values of Bugzilla::user &amp; Bugzilla::sudoer
</span><span class="lines">@@ -158,9 +164,8 @@
</span><span class="cx"> 
</span><span class="cx">     # Go ahead and send out the message now
</span><span class="cx">     my $message;
</span><del>-    my $mail_template = Bugzilla-&gt;template_inner($target_user-&gt;settings-&gt;{'lang'}-&gt;{'value'});
</del><ins>+    my $mail_template = Bugzilla-&gt;template_inner($target_user-&gt;setting('lang'));
</ins><span class="cx">     $mail_template-&gt;process('email/sudo.txt.tmpl', { reason =&gt; $reason }, \$message);
</span><del>-    Bugzilla-&gt;template_inner(&quot;&quot;);
</del><span class="cx">     MessageToMTA($message);
</span><span class="cx"> 
</span><span class="cx">     $vars-&gt;{'message'} = 'sudo_started';
</span><span class="lines">@@ -170,6 +175,7 @@
</span><span class="cx"> # end-sudo: End the current sudo session (if one is in progress)
</span><span class="cx"> elsif ($action eq 'end-sudo') {
</span><span class="cx">     # Regardless of our state, delete the sudo cookie if it exists
</span><ins>+    my $token = $cgi-&gt;cookie('sudo');
</ins><span class="cx">     $cgi-&gt;remove_cookie('sudo');
</span><span class="cx"> 
</span><span class="cx">     # Are we in an sudo session?
</span><span class="lines">@@ -178,30 +184,18 @@
</span><span class="cx">     if (defined($sudoer)) {
</span><span class="cx">         Bugzilla-&gt;sudo_request($sudoer, undef);
</span><span class="cx">     }
</span><ins>+    # Now that the session is over, remove the token from the DB.
+    delete_token($token);
</ins><span class="cx"> 
</span><span class="cx">     # NOTE: If you want to log the end of an sudo session, so it here.
</span><span class="cx">     
</span><span class="cx">     $vars-&gt;{'message'} = 'sudo_ended';
</span><span class="cx">     $target = 'global/message.html.tmpl';
</span><span class="cx"> }
</span><del>-# Log out the currently logged-in user (this used to be the only thing this did)
-elsif ($action eq 'logout') {
-    # We don't want to remove a random logincookie from the db, so
-    # call Bugzilla-&gt;login(). If we're logged in after this, then
-    # the logincookie must be correct
-    Bugzilla-&gt;login(LOGIN_OPTIONAL);
-
-    $cgi-&gt;remove_cookie('sudo');
-
-    Bugzilla-&gt;logout();
-
-    $vars-&gt;{'message'} = &quot;logged_out&quot;;
-    $target = 'global/message.html.tmpl';
-}
</del><span class="cx"> # No valid action found
</span><span class="cx"> else {
</span><span class="cx">     Bugzilla-&gt;login(LOGIN_OPTIONAL);
</span><del>-    ThrowCodeError('unknown_action', {action =&gt; $action});
</del><ins>+    ThrowUserError('unknown_action', {action =&gt; $action});
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> # Display the template
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgreportcgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/report.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/report.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/report.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -29,11 +29,13 @@
</span><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> use Bugzilla::Error;
</span><span class="cx"> use Bugzilla::Field;
</span><ins>+use Bugzilla::Search;
</ins><span class="cx"> 
</span><ins>+use List::MoreUtils qw(uniq);
+
</ins><span class="cx"> my $cgi = Bugzilla-&gt;cgi;
</span><span class="cx"> my $template = Bugzilla-&gt;template;
</span><span class="cx"> my $vars = {};
</span><del>-my $buffer = $cgi-&gt;query_string();
</del><span class="cx"> 
</span><span class="cx"> # Go straight back to query.cgi if we are adding a boolean chart.
</span><span class="cx"> if (grep(/^cmd-/, $cgi-&gt;param())) {
</span><span class="lines">@@ -45,12 +47,7 @@
</span><span class="cx">     exit;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-use Bugzilla::Search;
-
</del><span class="cx"> Bugzilla-&gt;login();
</span><del>-
-my $dbh = Bugzilla-&gt;switch_to_shadow_db();
-
</del><span class="cx"> my $action = $cgi-&gt;param('action') || 'menu';
</span><span class="cx"> 
</span><span class="cx"> if ($action eq &quot;menu&quot;) {
</span><span class="lines">@@ -61,6 +58,9 @@
</span><span class="cx">     exit;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# Sanitize the URL, to make URLs shorter.
+$cgi-&gt;clean_search_url;
+
</ins><span class="cx"> my $col_field = $cgi-&gt;param('x_axis_field') || '';
</span><span class="cx"> my $row_field = $cgi-&gt;param('y_axis_field') || '';
</span><span class="cx"> my $tbl_field = $cgi-&gt;param('z_axis_field') || '';
</span><span class="lines">@@ -95,6 +95,10 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> else {
</span><ins>+    if (!Bugzilla-&gt;feature('graphical_reports')) {
+        ThrowCodeError('feature_disabled', { feature =&gt; 'graphical_reports' });
+    }
+
</ins><span class="cx">     if ($row_field &amp;&amp; !$col_field) {
</span><span class="cx">         # 1D *charts* should be displayed horizontally (with an col_field only)
</span><span class="cx">         $col_field = $row_field;
</span><span class="lines">@@ -102,50 +106,35 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-my %columns;
-$columns{'bug_severity'}     = &quot;bugs.bug_severity&quot;;        
-$columns{'priority'}         = &quot;bugs.priority&quot;;
-$columns{'rep_platform'}     = &quot;bugs.rep_platform&quot;;
-$columns{'assigned_to'}      = &quot;map_assigned_to.login_name&quot;;
-$columns{'reporter'}         = &quot;map_reporter.login_name&quot;;
-$columns{'qa_contact'}       = &quot;map_qa_contact.login_name&quot;;
-$columns{'bug_status'}       = &quot;bugs.bug_status&quot;;
-$columns{'resolution'}       = &quot;bugs.resolution&quot;;
-$columns{'component'}        = &quot;map_components.name&quot;;
-$columns{'product'}          = &quot;map_products.name&quot;;
-$columns{'classification'}   = &quot;map_classifications.name&quot;;
-$columns{'version'}          = &quot;bugs.version&quot;;
-$columns{'op_sys'}           = &quot;bugs.op_sys&quot;;
-$columns{'votes'}            = &quot;bugs.votes&quot;;
-$columns{'keywords'}         = &quot;bugs.keywords&quot;;
-$columns{'target_milestone'} = &quot;bugs.target_milestone&quot;;
-# One which means &quot;nothing&quot;. Any number would do, really. It just gets SELECTed
-# so that we always select 3 items in the query.
-$columns{''}                 = &quot;42217354&quot;;
</del><ins>+# Valid bug fields that can be reported on.
+my $valid_columns = Bugzilla::Search::REPORT_COLUMNS;
</ins><span class="cx"> 
</span><span class="cx"> # Validate the values in the axis fields or throw an error.
</span><span class="cx"> !$row_field 
</span><del>-  || ($columns{$row_field} &amp;&amp; trick_taint($row_field))
</del><ins>+  || ($valid_columns-&gt;{$row_field} &amp;&amp; trick_taint($row_field))
</ins><span class="cx">   || ThrowCodeError(&quot;report_axis_invalid&quot;, {fld =&gt; &quot;x&quot;, val =&gt; $row_field});
</span><span class="cx"> !$col_field 
</span><del>-  || ($columns{$col_field} &amp;&amp; trick_taint($col_field))
</del><ins>+  || ($valid_columns-&gt;{$col_field} &amp;&amp; trick_taint($col_field))
</ins><span class="cx">   || ThrowCodeError(&quot;report_axis_invalid&quot;, {fld =&gt; &quot;y&quot;, val =&gt; $col_field});
</span><span class="cx"> !$tbl_field 
</span><del>-  || ($columns{$tbl_field} &amp;&amp; trick_taint($tbl_field))
</del><ins>+  || ($valid_columns-&gt;{$tbl_field} &amp;&amp; trick_taint($tbl_field))
</ins><span class="cx">   || ThrowCodeError(&quot;report_axis_invalid&quot;, {fld =&gt; &quot;z&quot;, val =&gt; $tbl_field});
</span><span class="cx"> 
</span><del>-my @axis_fields = ($row_field, $col_field, $tbl_field);
-my @selectnames = map($columns{$_}, @axis_fields);
</del><ins>+my @axis_fields = grep { $_ } ($row_field, $col_field, $tbl_field);
</ins><span class="cx"> 
</span><span class="cx"> # Clone the params, so that Bugzilla::Search can modify them
</span><span class="cx"> my $params = new Bugzilla::CGI($cgi);
</span><del>-my $search = new Bugzilla::Search('fields' =&gt; \@selectnames, 
-                                  'params' =&gt; $params);
-my $query = $search-&gt;getSQL();
</del><ins>+my $search = new Bugzilla::Search(
+    fields =&gt; \@axis_fields, 
+    params =&gt; scalar $params-&gt;Vars,
+    allow_unlimited =&gt; 1,
+);
+my $query = $search-&gt;sql;
</ins><span class="cx"> 
</span><span class="cx"> $::SIG{TERM} = 'DEFAULT';
</span><span class="cx"> $::SIG{PIPE} = 'DEFAULT';
</span><span class="cx"> 
</span><ins>+my $dbh = Bugzilla-&gt;switch_to_shadow_db();
</ins><span class="cx"> my $results = $dbh-&gt;selectall_arrayref($query);
</span><span class="cx"> 
</span><span class="cx"> # We have a hash of hashes for the data itself, and a hash to hold the 
</span><span class="lines">@@ -163,23 +152,11 @@
</span><span class="cx"> my $tbl_isnumeric = 1;
</span><span class="cx"> 
</span><span class="cx"> foreach my $result (@$results) {
</span><del>-    my ($row, $col, $tbl) = @$result;
-
</del><span class="cx">     # handle empty dimension member names
</span><del>-    $row = ' ' if ($row eq '');
-    $col = ' ' if ($col eq '');
-    $tbl = ' ' if ($tbl eq '');
</del><ins>+    my $row = check_value($row_field, $result);
+    my $col = check_value($col_field, $result);
+    my $tbl = check_value($tbl_field, $result);
</ins><span class="cx"> 
</span><del>-    $row = &quot;&quot; if ($row eq $columns{''});
-    $col = &quot;&quot; if ($col eq $columns{''});
-    $tbl = &quot;&quot; if ($tbl eq $columns{''});
-    
-    # account for the fact that names may start with '_' or '.'.  Change this 
-    # so the template doesn't hide hash elements with those keys
-    $row =~ s/^([._])/ $1/;
-    $col =~ s/^([._])/ $1/;
-    $tbl =~ s/^([._])/ $1/;
-
</del><span class="cx">     $data{$tbl}{$col}{$row}++;
</span><span class="cx">     $names{&quot;col&quot;}{$col}++;
</span><span class="cx">     $names{&quot;row&quot;}{$row}++;
</span><span class="lines">@@ -190,9 +167,9 @@
</span><span class="cx">     $tbl_isnumeric &amp;&amp;= ($tbl =~ /^-?\d+(\.\d+)?$/o);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-my @col_names = @{get_names($names{&quot;col&quot;}, $col_isnumeric, $col_field)};
-my @row_names = @{get_names($names{&quot;row&quot;}, $row_isnumeric, $row_field)};
-my @tbl_names = @{get_names($names{&quot;tbl&quot;}, $tbl_isnumeric, $tbl_field)};
</del><ins>+my @col_names = get_names($names{&quot;col&quot;}, $col_isnumeric, $col_field);
+my @row_names = get_names($names{&quot;row&quot;}, $row_isnumeric, $row_field);
+my @tbl_names = get_names($names{&quot;tbl&quot;}, $tbl_isnumeric, $tbl_field);
</ins><span class="cx"> 
</span><span class="cx"> # The GD::Graph package requires a particular format of data, so once we've
</span><span class="cx"> # gathered everything into the hashes and made sure we know the size of the
</span><span class="lines">@@ -226,7 +203,7 @@
</span><span class="cx"> $vars-&gt;{'col_field'} = $col_field;
</span><span class="cx"> $vars-&gt;{'row_field'} = $row_field;
</span><span class="cx"> $vars-&gt;{'tbl_field'} = $tbl_field;
</span><del>-$vars-&gt;{'time'} = time();
</del><ins>+$vars-&gt;{'time'} = localtime(time());
</ins><span class="cx"> 
</span><span class="cx"> $vars-&gt;{'col_names'} = \@col_names;
</span><span class="cx"> $vars-&gt;{'row_names'} = \@row_names;
</span><span class="lines">@@ -272,10 +249,10 @@
</span><span class="cx">     # We need to keep track of the defined restrictions on each of the 
</span><span class="cx">     # axes, because buglistbase, below, throws them away. Without this, we
</span><span class="cx">     # get buglistlinks wrong if there is a restriction on an axis field.
</span><del>-    $vars-&gt;{'col_vals'} = join(&quot;&amp;&quot;, $buffer =~ /[&amp;?]($col_field=[^&amp;]+)/g);
-    $vars-&gt;{'row_vals'} = join(&quot;&amp;&quot;, $buffer =~ /[&amp;?]($row_field=[^&amp;]+)/g);
-    $vars-&gt;{'tbl_vals'} = join(&quot;&amp;&quot;, $buffer =~ /[&amp;?]($tbl_field=[^&amp;]+)/g);
-    
</del><ins>+    $vars-&gt;{'col_vals'} = get_field_restrictions($col_field);
+    $vars-&gt;{'row_vals'} = get_field_restrictions($row_field);
+    $vars-&gt;{'tbl_vals'} = get_field_restrictions($tbl_field);
+
</ins><span class="cx">     # We need a number of different variants of the base URL for different
</span><span class="cx">     # URLs in the HTML.
</span><span class="cx">     $vars-&gt;{'buglistbase'} = $cgi-&gt;canonicalise_query(
</span><span class="lines">@@ -295,7 +272,7 @@
</span><span class="cx">     $vars-&gt;{'data'} = \@image_data;
</span><span class="cx"> }
</span><span class="cx"> else {
</span><del>-    ThrowCodeError(&quot;unknown_action&quot;, {action =&gt; $cgi-&gt;param('action')});
</del><ins>+    ThrowUserError('unknown_action', {action =&gt; $action});
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> my $format = $template-&gt;get_format(&quot;reports/report&quot;, $formatparam,
</span><span class="lines">@@ -317,9 +294,9 @@
</span><span class="cx"> if ($cgi-&gt;param('debug')) {
</span><span class="cx">     require Data::Dumper;
</span><span class="cx">     print &quot;&lt;pre&gt;data hash:\n&quot;;
</span><del>-    print Data::Dumper::Dumper(%data) . &quot;\n\n&quot;;
</del><ins>+    print html_quote(Data::Dumper::Dumper(%data)) . &quot;\n\n&quot;;
</ins><span class="cx">     print &quot;data array:\n&quot;;
</span><del>-    print Data::Dumper::Dumper(@image_data) . &quot;\n\n&lt;/pre&gt;&quot;;
</del><ins>+    print html_quote(Data::Dumper::Dumper(@image_data)) . &quot;\n\n&lt;/pre&gt;&quot;;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> # All formats point to the same section of the documentation.
</span><span class="lines">@@ -330,42 +307,55 @@
</span><span class="cx"> $template-&gt;process(&quot;$format-&gt;{'template'}&quot;, $vars)
</span><span class="cx">   || ThrowTemplateError($template-&gt;error());
</span><span class="cx"> 
</span><del>-exit;
</del><span class="cx"> 
</span><del>-
</del><span class="cx"> sub get_names {
</span><del>-    my ($names, $isnumeric, $field) = @_;
-  
-    # These are all the fields we want to preserve the order of in reports.
-    my %fields = ('priority'     =&gt; get_legal_field_values('priority'),
-                  'bug_severity' =&gt; get_legal_field_values('bug_severity'),
-                  'rep_platform' =&gt; get_legal_field_values('rep_platform'),
-                  'op_sys'       =&gt; get_legal_field_values('op_sys'),
-                  'bug_status'   =&gt; get_legal_field_values('bug_status'),
-                  'resolution'   =&gt; [' ', @{get_legal_field_values('resolution')}]);
</del><ins>+    my ($names, $isnumeric, $field_name) = @_;
+    my ($field, @sorted);
+    # _realname fields aren't real Bugzilla::Field objects, but they are a
+    # valid axis, so we don't vailidate them as Bugzilla::Field objects.
+    $field = Bugzilla::Field-&gt;check($field_name) 
+        if ($field_name &amp;&amp; $field_name !~ /_realname$/);
</ins><span class="cx">     
</span><del>-    my $field_list = $fields{$field};
-    my @sorted;
-    
-    if ($field_list) {
-        my @unsorted = keys %{$names};
-        
-        # Extract the used fields from the field_list, in the order they 
-        # appear in the field_list. This lets us keep e.g. severities in
-        # the normal order.
-        #
-        # This is O(n^2) but it shouldn't matter for short lists.
-        @sorted = map {lsearch(\@unsorted, $_) == -1 ? () : $_} @{$field_list};
</del><ins>+    if ($field &amp;&amp; $field-&gt;is_select) {
+        foreach my $value (@{$field-&gt;legal_values}) {
+            push(@sorted, $value-&gt;name) if $names-&gt;{$value-&gt;name};
+        }
+        unshift(@sorted, ' ') if $field_name eq 'resolution';
+        @sorted = uniq @sorted;
</ins><span class="cx">     }  
</span><span class="cx">     elsif ($isnumeric) {
</span><span class="cx">         # It's not a field we are preserving the order of, so sort it 
</span><span class="cx">         # numerically...
</span><del>-        sub numerically { $a &lt;=&gt; $b }
-        @sorted = sort numerically keys(%{$names});
-    } else {
</del><ins>+        @sorted = sort { $a &lt;=&gt; $b } keys %$names;
+    }
+    else {
</ins><span class="cx">         # ...or alphabetically, as appropriate.
</span><del>-        @sorted = sort(keys(%{$names}));
</del><ins>+        @sorted = sort keys %$names;
</ins><span class="cx">     }
</span><del>-  
-    return \@sorted;
</del><ins>+    
+    return @sorted;
</ins><span class="cx"> }
</span><ins>+
+sub check_value {
+    my ($field, $result) = @_;
+
+    my $value;
+    if (!defined $field) {
+        $value = '';
+    }
+    elsif ($field eq '') {
+        $value = ' ';
+    }
+    else {
+        $value = shift @$result;
+        $value = ' ' if (!defined $value || $value eq '');
+    }
+    return $value;
+}
+
+sub get_field_restrictions {
+    my $field = shift;
+    my $cgi = Bugzilla-&gt;cgi;
+
+    return join('&amp;', map {&quot;$field=$_&quot;} $cgi-&gt;param($field));
+}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgreportscgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/reports.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/reports.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/reports.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -18,22 +18,15 @@
</span><span class="cx"> # Copyright (C) 1998 Netscape Communications Corporation. All
</span><span class="cx"> # Rights Reserved.
</span><span class="cx"> #
</span><del>-# Contributor(s): Harrison Page &lt;harrison@netscape.com&gt;,
-# Terry Weissman &lt;terry@mozilla.org&gt;,
-# Dawn Endico &lt;endico@mozilla.org&gt;
-# Bryce Nesbitt &lt;bryce@nextbus.COM&gt;,
-# Joe Robins &lt;jmrobins@tgix.com&gt;,
-# Gervase Markham &lt;gerv@gerv.net&gt; and Adam Spiers &lt;adam@spiers.net&gt;
-#    Added ability to chart any combination of resolutions/statuses.
-#    Derive the choice of resolutions/statuses from the -All- data file
-#    Removed hardcoded order of resolutions/statuses when reading from
-#    daily stats file, so now works independently of collectstats.pl
-#    version
-#    Added image caching by date and datasets
-# Myk Melez &lt;myk@mozilla.org&gt;:
-#    Implemented form field validation and reorganized code.
-# Frédéric Buclin &lt;LpSolit@gmail.com&gt;:
-#    Templatization.
</del><ins>+# Contributor(s): Harrison Page &lt;harrison@netscape.com&gt;
+#                 Terry Weissman &lt;terry@mozilla.org&gt;
+#                 Dawn Endico &lt;endico@mozilla.org&gt;
+#                 Bryce Nesbitt &lt;bryce@nextbus.com&gt;
+#                 Joe Robins &lt;jmrobins@tgix.com&gt;
+#                 Gervase Markham &lt;gerv@gerv.net&gt;
+#                 Adam Spiers &lt;adam@spiers.net&gt;
+#                 Myk Melez &lt;myk@mozilla.org&gt;
+#                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
</ins><span class="cx"> 
</span><span class="cx"> use strict;
</span><span class="cx"> 
</span><span class="lines">@@ -45,32 +38,28 @@
</span><span class="cx"> use Bugzilla::Error;
</span><span class="cx"> use Bugzilla::Status;
</span><span class="cx"> 
</span><del>-eval &quot;use GD&quot;;
-$@ &amp;&amp; ThrowCodeError(&quot;gd_not_installed&quot;);
-eval &quot;use Chart::Lines&quot;;
-$@ &amp;&amp; ThrowCodeError(&quot;chart_lines_not_installed&quot;);
</del><ins>+use File::Basename;
+use Digest::MD5 qw(md5_hex);
</ins><span class="cx"> 
</span><del>-my $dir       = bz_locations()-&gt;{'datadir'} . &quot;/mining&quot;;
-my $graph_url = 'graphs';
-my $graph_dir = bz_locations()-&gt;{'libpath'} . '/' .$graph_url;
-
</del><span class="cx"> # If we're using bug groups for products, we should apply those restrictions
</span><span class="cx"> # to viewing reports, as well.  Time to check the login in that case.
</span><span class="cx"> my $user = Bugzilla-&gt;login();
</span><del>-
-Bugzilla-&gt;switch_to_shadow_db();
-
</del><span class="cx"> my $cgi = Bugzilla-&gt;cgi;
</span><span class="cx"> my $template = Bugzilla-&gt;template;
</span><span class="cx"> my $vars = {};
</span><span class="cx"> 
</span><del>-# We only want those products that the user has permissions for.
-my @myproducts;
-push( @myproducts, &quot;-All-&quot;);
-# Extract product names from objects and add them to the list.
-push( @myproducts, map { $_-&gt;name } @{$user-&gt;get_selectable_products} );
</del><ins>+if (!Bugzilla-&gt;feature('old_charts')) {
+    ThrowCodeError('feature_disabled', { feature =&gt; 'old_charts' });
+}
</ins><span class="cx"> 
</span><del>-if (! defined $cgi-&gt;param('product')) {
</del><ins>+my $dir       = bz_locations()-&gt;{'datadir'} . &quot;/mining&quot;;
+my $graph_dir = bz_locations()-&gt;{'graphsdir'};
+my $graph_url = basename($graph_dir);
+my $product_name = $cgi-&gt;param('product') || '';
+
+Bugzilla-&gt;switch_to_shadow_db();
+
+if (!$product_name) {
</ins><span class="cx">     # Can we do bug charts?
</span><span class="cx">     (-d $dir &amp;&amp; -d $graph_dir) 
</span><span class="cx">       || ThrowCodeError('chart_dir_nonexistent',
</span><span class="lines">@@ -88,51 +77,61 @@
</span><span class="cx">         push(@datasets, $datasets);
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    # We only want those products that the user has permissions for.
+    my @myproducts = ('-All-');
+    # Extract product names from objects and add them to the list.
+    push( @myproducts, map { $_-&gt;name } @{$user-&gt;get_selectable_products} );
+
</ins><span class="cx">     $vars-&gt;{'datasets'} = \@datasets;
</span><span class="cx">     $vars-&gt;{'products'} = \@myproducts;
</span><span class="cx"> 
</span><span class="cx">     print $cgi-&gt;header();
</span><del>-
-    $template-&gt;process('reports/old-charts.html.tmpl', $vars)
-      || ThrowTemplateError($template-&gt;error());
-    exit;
</del><span class="cx"> }
</span><span class="cx"> else {
</span><del>-    my $product = $cgi-&gt;param('product');
-
</del><span class="cx">     # For security and correctness, validate the value of the &quot;product&quot; form variable.
</span><span class="cx">     # Valid values are those products for which the user has permissions which appear
</span><span class="cx">     # in the &quot;product&quot; drop-down menu on the report generation form.
</span><del>-    grep($_ eq $product, @myproducts)
-      || ThrowUserError(&quot;invalid_product_name&quot;, {product =&gt; $product});
</del><ins>+    my ($product) = grep { $_-&gt;name eq $product_name } @{$user-&gt;get_selectable_products};
+    ($product || $product_name eq '-All-')
+      || ThrowUserError('invalid_product_name', {product =&gt; $product_name});
</ins><span class="cx"> 
</span><del>-    # We've checked that the product exists, and that the user can see it
-    # This means that is OK to detaint
-    trick_taint($product);
</del><ins>+    # Product names can change over time. Their ID cannot; so use the ID
+    # to generate the filename.
+    my $prod_id = $product ? $product-&gt;id : 0;
</ins><span class="cx"> 
</span><del>-    defined($cgi-&gt;param('datasets')) || ThrowUserError('missing_datasets');
</del><ins>+    # Make sure there is something to plot.
+    my @datasets = $cgi-&gt;param('datasets');
+    scalar(@datasets) || ThrowUserError('missing_datasets');
</ins><span class="cx"> 
</span><del>-    my $datasets = join('', $cgi-&gt;param('datasets'));
</del><ins>+    if (grep { $_ !~ /^[A-Za-z0-9:_-]+$/ } @datasets) {
+        ThrowUserError('invalid_datasets', {'datasets' =&gt; \@datasets});
+    }
</ins><span class="cx"> 
</span><del>-    my $type = chart_image_type();
-    my $data_file = daily_stats_filename($product);
-    my $image_file = chart_image_name($data_file, $type, $datasets);
-    my $url_image = correct_urlbase() . &quot;$graph_url/$image_file&quot;;
</del><ins>+    # Filenames must not be guessable as they can point to products
+    # you are not allowed to see. Also, different projects can have
+    # the same product names.
+    my $key = Bugzilla-&gt;localconfig-&gt;{'site_wide_secret'};
+    my $project = bz_locations()-&gt;{'project'} || '';
+    my $image_file =  join(':', ($key, $project, $prod_id, @datasets));
+    # Wide characters cause md5_hex() to die.
+    if (Bugzilla-&gt;params-&gt;{'utf8'}) {
+        utf8::encode($image_file) if utf8::is_utf8($image_file);
+    }
+    $image_file = md5_hex($image_file) . '.png';
+    trick_taint($image_file);
</ins><span class="cx"> 
</span><span class="cx">     if (! -e &quot;$graph_dir/$image_file&quot;) {
</span><del>-        generate_chart(&quot;$dir/$data_file&quot;, &quot;$graph_dir/$image_file&quot;, $type,
-                       $product, $datasets);
</del><ins>+        generate_chart($dir, &quot;$graph_dir/$image_file&quot;, $product, \@datasets);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    $vars-&gt;{'url_image'} = $url_image;
</del><ins>+    $vars-&gt;{'url_image'} = &quot;$graph_url/$image_file&quot;;
</ins><span class="cx"> 
</span><span class="cx">     print $cgi-&gt;header(-Content_Disposition=&gt;'inline; filename=bugzilla_report.html');
</span><del>-
-    $template-&gt;process('reports/old-charts.html.tmpl', $vars)
-      || ThrowTemplateError($template-&gt;error());
-    exit;
</del><span class="cx"> }
</span><span class="cx"> 
</span><ins>+$template-&gt;process('reports/old-charts.html.tmpl', $vars)
+  || ThrowTemplateError($template-&gt;error());
+
</ins><span class="cx"> #####################
</span><span class="cx"> #    Subroutines    #
</span><span class="cx"> #####################
</span><span class="lines">@@ -141,9 +140,8 @@
</span><span class="cx">     my $dir = shift;
</span><span class="cx"> 
</span><span class="cx">     my @datasets;
</span><del>-    my $datafile = daily_stats_filename('-All-');
-    open(DATA, '&lt;', &quot;$dir/$datafile&quot;)
-      || ThrowCodeError('chart_file_open_fail', {filename =&gt; &quot;$dir/$datafile&quot;});
</del><ins>+    open(DATA, '&lt;', &quot;$dir/-All-&quot;)
+      || ThrowCodeError('chart_file_open_fail', {filename =&gt; &quot;$dir/-All-&quot;});
</ins><span class="cx"> 
</span><span class="cx">     while (&lt;DATA&gt;) {
</span><span class="cx">         if (/^# fields?: (.+)\s*$/) {
</span><span class="lines">@@ -155,47 +153,12 @@
</span><span class="cx">     return @datasets;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub daily_stats_filename {
-    my ($prodname) = @_;
-    $prodname =~ s/\//-/gs;
-    return $prodname;
-}
-
-sub chart_image_type {
-    # what chart type should we be generating?
-    my $testimg = Chart::Lines-&gt;new(2,2);
-    my $type = $testimg-&gt;can('gif') ? &quot;gif&quot; : &quot;png&quot;;
-
-    undef $testimg;
-    return $type;
-}
-
-sub chart_image_name {
-    my ($data_file, $type, $datasets) = @_;
-
-    # This routine generates a filename from the requested fields. The problem
-    # is that we have to check the safety of doing this. We can't just require
-    # that the fields exist, because what stats were collected could change
-    # over time (eg by changing the resolutions available)
-    # Instead, just require that each field name consists only of letters,
-    # numbers, underscores and hyphens.
-
-    if ($datasets !~ m/^[A-Za-z0-9:_-]+$/) {
-        ThrowUserError('invalid_datasets', {'datasets' =&gt; $datasets});
-    }
-
-    # Since we pass the tests, consider it OK
-    trick_taint($datasets);
-
-    # Cache charts by generating a unique filename based on what they
-    # show. Charts should be deleted by collectstats.pl nightly.
-    my $id = join (&quot;_&quot;, split (&quot;:&quot;, $datasets));
-
-    return &quot;${data_file}_${id}.$type&quot;;
-}
-
</del><span class="cx"> sub generate_chart {
</span><del>-    my ($data_file, $image_file, $type, $product, $datasets) = @_;
</del><ins>+    my ($dir, $image_file, $product, $datasets) = @_;
+    $product = $product ? $product-&gt;name : '-All-';
+    my $data_file = $product;
+    $data_file =~ s/\//-/gs;
+    $data_file = $dir . '/' . $data_file;
</ins><span class="cx"> 
</span><span class="cx">     if (! open FILE, $data_file) {
</span><span class="cx">         if ($product eq '-All-') {
</span><span class="lines">@@ -206,7 +169,7 @@
</span><span class="cx"> 
</span><span class="cx">     my @fields;
</span><span class="cx">     my @labels = qw(DATE);
</span><del>-    my %datasets = map { $_ =&gt; 1 } split /:/, $datasets;
</del><ins>+    my %datasets = map { $_ =&gt; 1 } @$datasets;
</ins><span class="cx"> 
</span><span class="cx">     my %data = ();
</span><span class="cx">     while (&lt;FILE&gt;) {
</span><span class="lines">@@ -280,5 +243,5 @@
</span><span class="cx">         );
</span><span class="cx">     
</span><span class="cx">     $img-&gt;set (%settings);
</span><del>-    $img-&gt;$type($image_file, [ @data{('DATE', @labels)} ]);
</del><ins>+    $img-&gt;png($image_file, [ @data{('DATE', @labels)} ]);
</ins><span class="cx"> }
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgrequestcgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/request.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/request.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/request.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -42,7 +42,8 @@
</span><span class="cx"> # Make sure the user is logged in.
</span><span class="cx"> my $user = Bugzilla-&gt;login();
</span><span class="cx"> my $cgi = Bugzilla-&gt;cgi;
</span><del>-my $dbh = Bugzilla-&gt;dbh;
</del><ins>+# Force the script to run against the shadow DB. We already validated credentials.
+Bugzilla-&gt;switch_to_shadow_db;
</ins><span class="cx"> my $template = Bugzilla-&gt;template;
</span><span class="cx"> my $action = $cgi-&gt;param('action') || '';
</span><span class="cx"> 
</span><span class="lines">@@ -62,23 +63,21 @@
</span><span class="cx">     $fields-&gt;{'requestee'}-&gt;{'type'} = 'single';
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-Bugzilla::User::match_field($cgi, $fields);
</del><ins>+Bugzilla::User::match_field($fields);
</ins><span class="cx"> 
</span><span class="cx"> if ($action eq 'queue') {
</span><span class="cx">     queue();
</span><span class="cx"> }
</span><span class="cx"> else {
</span><del>-    my $flagtypes = $dbh-&gt;selectcol_arrayref('SELECT DISTINCT(name) FROM flagtypes
-                                              ORDER BY name');
</del><ins>+    my $flagtypes = get_flag_types();
</ins><span class="cx">     my @types = ('all', @$flagtypes);
</span><span class="cx"> 
</span><span class="cx">     my $vars = {};
</span><del>-    $vars-&gt;{'products'} = $user-&gt;get_selectable_products;
</del><span class="cx">     $vars-&gt;{'types'} = \@types;
</span><span class="cx">     $vars-&gt;{'requests'} = {};
</span><span class="cx"> 
</span><span class="cx">     my %components;
</span><del>-    foreach my $prod (@{$vars-&gt;{'products'}}) {
</del><ins>+    foreach my $prod (@{$user-&gt;get_selectable_products}) {
</ins><span class="cx">         foreach my $comp (@{$prod-&gt;components}) {
</span><span class="cx">             $components{$comp-&gt;name} = 1;
</span><span class="cx">         }
</span><span class="lines">@@ -96,7 +95,6 @@
</span><span class="cx"> 
</span><span class="cx"> sub queue {
</span><span class="cx">     my $cgi = Bugzilla-&gt;cgi;
</span><del>-    # There are some user privilege checks to do. We do them against the main DB.
</del><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx">     my $template = Bugzilla-&gt;template;
</span><span class="cx">     my $user = Bugzilla-&gt;user;
</span><span class="lines">@@ -115,7 +113,7 @@
</span><span class="cx">                 products.name, components.name,
</span><span class="cx">                 flags.attach_id, attachments.description,
</span><span class="cx">                 requesters.realname, requesters.login_name,
</span><del>-                requestees.realname, requestees.login_name,
</del><ins>+                requestees.realname, requestees.login_name, COUNT(privs.group_id),
</ins><span class="cx">     &quot; . $dbh-&gt;sql_date_format('flags.modification_date', '%Y.%m.%d %H:%i') .
</span><span class="cx">     # Use the flags and flagtypes tables for information about the flags,
</span><span class="cx">     # the bugs and attachments tables for target info, the profiles tables
</span><span class="lines">@@ -142,7 +140,9 @@
</span><span class="cx">            LEFT JOIN bug_group_map AS bgmap
</span><span class="cx">                   ON bgmap.bug_id = bugs.bug_id
</span><span class="cx">                  AND bgmap.group_id NOT IN (&quot; .
</span><del>-                     join(', ', (-1, values(%{$user-&gt;groups}))) . &quot;)
</del><ins>+                     $user-&gt;groups_as_string . &quot;)
+           LEFT JOIN bug_group_map AS privs
+                  ON privs.bug_id = bugs.bug_id
</ins><span class="cx">            LEFT JOIN cc AS ccmap
</span><span class="cx">                   ON ccmap.who = $userid
</span><span class="cx">                  AND ccmap.bug_id = bugs.bug_id
</span><span class="lines">@@ -166,9 +166,7 @@
</span><span class="cx">     $query .= &quot; AND flags.status = '?' &quot; unless $status;
</span><span class="cx"> 
</span><span class="cx">     # The set of criteria by which we filter records to display in the queue.
</span><del>-    # We now move to the shadow DB to query the DB.
</del><span class="cx">     my @criteria = ();
</span><del>-    $dbh = Bugzilla-&gt;switch_to_shadow_db;
</del><span class="cx"> 
</span><span class="cx">     # A list of columns to exclude from the report because the report conditions
</span><span class="cx">     # limit the data being displayed to exact matches for those columns.
</span><span class="lines">@@ -210,7 +208,7 @@
</span><span class="cx">     
</span><span class="cx">     # Filter results by exact product or component.
</span><span class="cx">     if (defined $cgi-&gt;param('product') &amp;&amp; $cgi-&gt;param('product') ne &quot;&quot;) {
</span><del>-        my $product = Bugzilla::Product::check_product(scalar $cgi-&gt;param('product'));
</del><ins>+        my $product = Bugzilla::Product-&gt;check(scalar $cgi-&gt;param('product'));
</ins><span class="cx">         push(@criteria, &quot;bugs.product_id = &quot; . $product-&gt;id);
</span><span class="cx">         push(@excluded_columns, 'product') unless $cgi-&gt;param('do_union');
</span><span class="cx">         if (defined $cgi-&gt;param('component') &amp;&amp; $cgi-&gt;param('component') ne &quot;&quot;) {
</span><span class="lines">@@ -296,28 +294,24 @@
</span><span class="cx">           'attach_summary'  =&gt; $data[8] ,
</span><span class="cx">           'requester'       =&gt; ($data[9] ? &quot;$data[9] &lt;$data[10]&gt;&quot; : $data[10]) , 
</span><span class="cx">           'requestee'       =&gt; ($data[11] ? &quot;$data[11] &lt;$data[12]&gt;&quot; : $data[12]) , 
</span><del>-          'created'         =&gt; $data[13]
</del><ins>+          'restricted'      =&gt; $data[13] ? 1 : 0,
+          'created'         =&gt; $data[14]
</ins><span class="cx">         };
</span><span class="cx">         push(@requests, $request);
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # Get a list of request type names to use in the filter form.
</span><span class="cx">     my @types = (&quot;all&quot;);
</span><del>-    my $flagtypes = $dbh-&gt;selectcol_arrayref(
-                         &quot;SELECT DISTINCT(name) FROM flagtypes ORDER BY name&quot;);
</del><ins>+    my $flagtypes = get_flag_types();
</ins><span class="cx">     push(@types, @$flagtypes);
</span><span class="cx"> 
</span><del>-    # We move back to the main DB to get the list of products the user can see.
-    $dbh = Bugzilla-&gt;switch_to_main_db;
-
-    $vars-&gt;{'products'} = $user-&gt;get_selectable_products;
</del><span class="cx">     $vars-&gt;{'excluded_columns'} = \@excluded_columns;
</span><span class="cx">     $vars-&gt;{'group_field'} = $form_group;
</span><span class="cx">     $vars-&gt;{'requests'} = \@requests;
</span><span class="cx">     $vars-&gt;{'types'} = \@types;
</span><span class="cx"> 
</span><span class="cx">     my %components;
</span><del>-    foreach my $prod (@{$vars-&gt;{'products'}}) {
</del><ins>+    foreach my $prod (@{$user-&gt;get_selectable_products}) {
</ins><span class="cx">         foreach my $comp (@{$prod-&gt;components}) {
</span><span class="cx">             $components{$comp-&gt;name} = 1;
</span><span class="cx">         }
</span><span class="lines">@@ -338,8 +332,7 @@
</span><span class="cx">     return if !defined $status;
</span><span class="cx"> 
</span><span class="cx">     grep($status eq $_, qw(? +- + - all))
</span><del>-      || ThrowCodeError(&quot;flag_status_invalid&quot;,
-                        { status =&gt; $status });
</del><ins>+      || ThrowUserError(&quot;flag_status_invalid&quot;, { status =&gt; $status });
</ins><span class="cx">     trick_taint($status);
</span><span class="cx">     return $status;
</span><span class="cx"> }
</span><span class="lines">@@ -349,9 +342,19 @@
</span><span class="cx">     return if !defined $group;
</span><span class="cx"> 
</span><span class="cx">     grep($group eq $_, qw(requester requestee category type))
</span><del>-      || ThrowCodeError(&quot;request_queue_group_invalid&quot;, 
-                        { group =&gt; $group });
</del><ins>+      || ThrowUserError(&quot;request_queue_group_invalid&quot;, { group =&gt; $group });
</ins><span class="cx">     trick_taint($group);
</span><span class="cx">     return $group;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# Returns all flag types which have at least one flag of this type.
+# If a flag type is inactive but still has flags, we want it.
+sub get_flag_types {
+    my $dbh = Bugzilla-&gt;dbh;
+    my $flag_types = $dbh-&gt;selectcol_arrayref('SELECT DISTINCT name
+                                                 FROM flagtypes
+                                                WHERE flagtypes.id IN
+                                                      (SELECT DISTINCT type_id FROM flags)
+                                             ORDER BY name');
+    return $flag_types;
+}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgsanitycheckcgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/sanitycheck.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/sanitycheck.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/sanitycheck.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -31,9 +31,11 @@
</span><span class="cx"> use Bugzilla;
</span><span class="cx"> use Bugzilla::Bug;
</span><span class="cx"> use Bugzilla::Constants;
</span><del>-use Bugzilla::Util;
</del><span class="cx"> use Bugzilla::Error;
</span><ins>+use Bugzilla::Hook;
+use Bugzilla::Util;
</ins><span class="cx"> use Bugzilla::Status;
</span><ins>+use Bugzilla::Token;
</ins><span class="cx"> 
</span><span class="cx"> ###########################################################################
</span><span class="cx"> # General subs
</span><span class="lines">@@ -74,10 +76,19 @@
</span><span class="cx"> # take the user prefs into account rather than querying the web browser.
</span><span class="cx"> my $template;
</span><span class="cx"> if (Bugzilla-&gt;usage_mode == USAGE_MODE_CMDLINE) {
</span><del>-    $template = Bugzilla-&gt;template_inner($user-&gt;settings-&gt;{'lang'}-&gt;{'value'});
</del><ins>+    $template = Bugzilla-&gt;template_inner($user-&gt;setting('lang'));
</ins><span class="cx"> }
</span><span class="cx"> else {
</span><span class="cx">     $template = Bugzilla-&gt;template;
</span><ins>+
+    # Only check the token if we are running this script from the
+    # web browser and a parameter is passed to the script.
+    # XXX - Maybe these two parameters should be deleted once logged in?
+    $cgi-&gt;delete('GoAheadAndLogIn', 'Bugzilla_restrictlogin');
+    if (scalar($cgi-&gt;param())) {
+        my $token = $cgi-&gt;param('token');
+        check_hash_token($token, ['sanitycheck']);
+    }
</ins><span class="cx"> }
</span><span class="cx"> my $vars = {};
</span><span class="cx"> 
</span><span class="lines">@@ -87,7 +98,6 @@
</span><span class="cx"> # As this script can now alter the group_control_map table, we no longer
</span><span class="cx"> # let users with editbugs privs run it anymore.
</span><span class="cx"> $user-&gt;in_group(&quot;editcomponents&quot;)
</span><del>-  || ($user-&gt;in_group('editkeywords') &amp;&amp; $cgi-&gt;param('rebuildkeywordcache'))
</del><span class="cx">   || ThrowUserError(&quot;auth_failure&quot;, {group  =&gt; &quot;editcomponents&quot;,
</span><span class="cx">                                      action =&gt; &quot;run&quot;,
</span><span class="cx">                                      object =&gt; &quot;sanity_check&quot;});
</span><span class="lines">@@ -98,39 +108,6 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ###########################################################################
</span><del>-# Users with 'editkeywords' privs only can only check keywords.
-###########################################################################
-unless ($user-&gt;in_group('editcomponents')) {
-    check_votes_or_keywords('keywords');
-    Status('checks_completed');
-
-    $template-&gt;process('global/footer.html.tmpl', $vars)
-        || ThrowTemplateError($template-&gt;error());
-    exit;
-}
-
-###########################################################################
-# Fix vote cache
-###########################################################################
-
-if ($cgi-&gt;param('rebuildvotecache')) {
-    Status('vote_cache_rebuild_start');
-    $dbh-&gt;bz_start_transaction();
-    $dbh-&gt;do(q{UPDATE bugs SET votes = 0});
-    my $sth_update = $dbh-&gt;prepare(q{UPDATE bugs 
-                                        SET votes = ? 
-                                      WHERE bug_id = ?});
-    my $sth = $dbh-&gt;prepare(q{SELECT bug_id, SUM(vote_count)
-                                FROM votes }. $dbh-&gt;sql_group_by('bug_id'));
-    $sth-&gt;execute();
-    while (my ($id, $v) = $sth-&gt;fetchrow_array) {
-        $sth_update-&gt;execute($v, $id);
-    }
-    $dbh-&gt;bz_commit_transaction();
-    Status('vote_cache_rebuild_end');
-}
-
-###########################################################################
</del><span class="cx"> # Create missing group_control_map entries
</span><span class="cx"> ###########################################################################
</span><span class="cx"> 
</span><span class="lines">@@ -140,14 +117,10 @@
</span><span class="cx">     my $na    = CONTROLMAPNA;
</span><span class="cx">     my $shown = CONTROLMAPSHOWN;
</span><span class="cx">     my $insertsth = $dbh-&gt;prepare(
</span><del>-        qq{INSERT INTO group_control_map (
-                       group_id, product_id, entry,
-                       membercontrol, othercontrol, canedit
-                      )
-               VALUES (
-                       ?, ?, 0,
-                       $shown, $na, 0
-                      )});
</del><ins>+        qq{INSERT INTO group_control_map
+                       (group_id, product_id, membercontrol, othercontrol)
+                VALUES (?, ?, $shown, $na)});
+
</ins><span class="cx">     my $updatesth = $dbh-&gt;prepare(qq{UPDATE group_control_map
</span><span class="cx">                                         SET membercontrol = $shown
</span><span class="cx">                                       WHERE group_id   = ?
</span><span class="lines">@@ -223,6 +196,22 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ###########################################################################
</span><ins>+# Fix everconfirmed
+###########################################################################
+
+if ($cgi-&gt;param('repair_everconfirmed')) {
+    Status('everconfirmed_start');
+
+    my @confirmed_open_states = grep {$_ ne 'UNCONFIRMED'} BUG_STATE_OPEN;
+    my $confirmed_open_states = join(', ', map {$dbh-&gt;quote($_)} @confirmed_open_states);
+
+    $dbh-&gt;do(&quot;UPDATE bugs SET everconfirmed = 0 WHERE bug_status = 'UNCONFIRMED'&quot;);
+    $dbh-&gt;do(&quot;UPDATE bugs SET everconfirmed = 1 WHERE bug_status IN ($confirmed_open_states)&quot;);
+
+    Status('everconfirmed_end');
+}
+
+###########################################################################
</ins><span class="cx"> # Fix entries in Bugs full_text
</span><span class="cx"> ###########################################################################
</span><span class="cx"> 
</span><span class="lines">@@ -250,14 +239,14 @@
</span><span class="cx">     require Bugzilla::BugMail;
</span><span class="cx"> 
</span><span class="cx">     Status('send_bugmail_start');
</span><del>-    my $time = $dbh-&gt;sql_interval(30, 'MINUTE');
</del><ins>+    my $time = $dbh-&gt;sql_date_math('NOW()', '-', 30, 'MINUTE');
</ins><span class="cx"> 
</span><span class="cx">     my $list = $dbh-&gt;selectcol_arrayref(qq{
</span><span class="cx">                                         SELECT bug_id
</span><span class="cx">                                           FROM bugs 
</span><span class="cx">                                          WHERE (lastdiffed IS NULL
</span><span class="cx">                                                 OR lastdiffed &lt; delta_ts)
</span><del>-                                           AND delta_ts &lt; now() - $time
</del><ins>+                                           AND delta_ts &lt; $time
</ins><span class="cx">                                       ORDER BY bug_id});
</span><span class="cx"> 
</span><span class="cx">     Status('send_bugmail_status', {bug_count =&gt; scalar(@$list)});
</span><span class="lines">@@ -269,7 +258,7 @@
</span><span class="cx">     # and so choosing this user as being the last one having done a change
</span><span class="cx">     # for the bug may be problematic. So the best we can do at this point
</span><span class="cx">     # is to choose the currently logged in user for email notification.
</span><del>-    $vars-&gt;{'changer'} = Bugzilla-&gt;user-&gt;login;
</del><ins>+    $vars-&gt;{'changer'} = Bugzilla-&gt;user;
</ins><span class="cx"> 
</span><span class="cx">     foreach my $bugid (@$list) {
</span><span class="cx">         Bugzilla::BugMail::Send($bugid, $vars);
</span><span class="lines">@@ -293,17 +282,12 @@
</span><span class="cx"> 
</span><span class="cx">     $dbh-&gt;bz_start_transaction();
</span><span class="cx"> 
</span><del>-    # Include custom multi-select fields to the list.
-    my @multi_selects = Bugzilla-&gt;get_fields({custom =&gt; 1, type =&gt; FIELD_TYPE_MULTI_SELECT});
-    my @addl_fields = map { 'bug_' . $_-&gt;name . '/' } @multi_selects;
-
</del><span class="cx">     foreach my $pair ('attachments/', 'bug_group_map/', 'bugs_activity/',
</span><span class="cx">                       'bugs_fulltext/', 'cc/',
</span><span class="cx">                       'dependencies/blocked', 'dependencies/dependson',
</span><span class="cx">                       'duplicates/dupe', 'duplicates/dupe_of',
</span><del>-                      'flags/', 'keywords/', 'longdescs/', 'votes/',
-                      @addl_fields)
-    {
</del><ins>+                      'flags/', 'keywords/', 'longdescs/') {
+
</ins><span class="cx">         my ($table, $field) = split('/', $pair);
</span><span class="cx">         $field ||= &quot;bug_id&quot;;
</span><span class="cx"> 
</span><span class="lines">@@ -376,6 +360,15 @@
</span><span class="cx">     Status('whines_obsolete_target_deletion_end');
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+###########################################################################
+# Repair hook
+###########################################################################
+
+Bugzilla::Hook::process('sanitycheck_repair', { status =&gt; \&amp;Status });
+
+###########################################################################
+# Checks
+###########################################################################
</ins><span class="cx"> Status('checks_start');
</span><span class="cx"> 
</span><span class="cx"> ###########################################################################
</span><span class="lines">@@ -462,10 +455,6 @@
</span><span class="cx">            [&quot;flagexclusions&quot;, &quot;type_id&quot;],
</span><span class="cx">            [&quot;flaginclusions&quot;, &quot;type_id&quot;]);
</span><span class="cx"> 
</span><del>-# Include custom multi-select fields to the list.
-my @multi_selects = Bugzilla-&gt;get_fields({custom =&gt; 1, type =&gt; FIELD_TYPE_MULTI_SELECT});
-my @addl_fields = map { ['bug_' . $_-&gt;name, 'bug_id'] } @multi_selects;
-
</del><span class="cx"> CrossCheck(&quot;bugs&quot;, &quot;bug_id&quot;,
</span><span class="cx">            [&quot;bugs_activity&quot;, &quot;bug_id&quot;],
</span><span class="cx">            [&quot;bug_group_map&quot;, &quot;bug_id&quot;],
</span><span class="lines">@@ -476,11 +465,9 @@
</span><span class="cx">            [&quot;dependencies&quot;, &quot;blocked&quot;],
</span><span class="cx">            [&quot;dependencies&quot;, &quot;dependson&quot;],
</span><span class="cx">            ['flags', 'bug_id'],
</span><del>-           [&quot;votes&quot;, &quot;bug_id&quot;],
</del><span class="cx">            [&quot;keywords&quot;, &quot;bug_id&quot;],
</span><span class="cx">            [&quot;duplicates&quot;, &quot;dupe_of&quot;, &quot;dupe&quot;],
</span><del>-           [&quot;duplicates&quot;, &quot;dupe&quot;, &quot;dupe_of&quot;],
-           @addl_fields);
</del><ins>+           [&quot;duplicates&quot;, &quot;dupe&quot;, &quot;dupe_of&quot;]);
</ins><span class="cx"> 
</span><span class="cx"> CrossCheck(&quot;groups&quot;, &quot;id&quot;,
</span><span class="cx">            [&quot;bug_group_map&quot;, &quot;group_id&quot;],
</span><span class="lines">@@ -512,7 +499,6 @@
</span><span class="cx">            [&quot;bugs_activity&quot;, &quot;who&quot;, &quot;bug_id&quot;],
</span><span class="cx">            [&quot;cc&quot;, &quot;who&quot;, &quot;bug_id&quot;],
</span><span class="cx">            ['quips', 'userid'],
</span><del>-           [&quot;votes&quot;, &quot;who&quot;, &quot;bug_id&quot;],
</del><span class="cx">            [&quot;longdescs&quot;, &quot;who&quot;, &quot;bug_id&quot;],
</span><span class="cx">            [&quot;logincookies&quot;, &quot;userid&quot;],
</span><span class="cx">            [&quot;namedqueries&quot;, &quot;userid&quot;],
</span><span class="lines">@@ -669,75 +655,14 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ###########################################################################
</span><del>-# Perform vote/keyword cache checks
</del><ins>+# Perform keyword checks
</ins><span class="cx"> ###########################################################################
</span><span class="cx"> 
</span><del>-check_votes_or_keywords();
-
-sub check_votes_or_keywords {
-    my $check = shift || 'all';
-
</del><ins>+sub check_keywords {
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><del>-    my $sth = $dbh-&gt;prepare(q{SELECT bug_id, votes, keywords
-                                FROM bugs
-                               WHERE votes != 0 OR keywords != ''});
-    $sth-&gt;execute;
</del><ins>+    my $cgi = Bugzilla-&gt;cgi;
</ins><span class="cx"> 
</span><del>-    my %votes;
-    my %keyword;
-
-    while (my ($id, $v, $k) = $sth-&gt;fetchrow_array) {
-        if ($v != 0) {
-            $votes{$id} = $v;
-        }
-        if ($k) {
-            $keyword{$id} = $k;
-        }
-    }
-
-    # If we only want to check keywords, skip checks about votes.
-    _check_votes(\%votes) unless ($check eq 'keywords');
-    # If we only want to check votes, skip checks about keywords.
-    _check_keywords(\%keyword) unless ($check eq 'votes');
-}
-
-sub _check_votes {
-    my $votes = shift;
-
-    Status('vote_count_start');
-    my $dbh = Bugzilla-&gt;dbh;
-    my $sth = $dbh-&gt;prepare(q{SELECT bug_id, SUM(vote_count)
-                                FROM votes }.
-                                $dbh-&gt;sql_group_by('bug_id'));
-    $sth-&gt;execute;
-
-    my $offer_votecache_rebuild = 0;
-
-    while (my ($id, $v) = $sth-&gt;fetchrow_array) {
-        if ($v &lt;= 0) {
-            Status('vote_count_alert', {id =&gt; $id}, 'alert');
-        } else {
-            if (!defined $votes-&gt;{$id} || $votes-&gt;{$id} != $v) {
-                Status('vote_cache_alert', {id =&gt; $id}, 'alert');
-                $offer_votecache_rebuild = 1;
-            }
-            delete $votes-&gt;{$id};
-        }
-    }
-    foreach my $id (keys %$votes) {
-        Status('vote_cache_alert', {id =&gt; $id}, 'alert');
-        $offer_votecache_rebuild = 1;
-    }
-
-    Status('vote_cache_rebuild_fix') if $offer_votecache_rebuild;
-}
-
-sub _check_keywords {
-    my $keyword = shift;
-
</del><span class="cx">     Status('keyword_check_start');
</span><del>-    my $dbh = Bugzilla-&gt;dbh;
-    my $cgi = Bugzilla-&gt;cgi;
</del><span class="cx"> 
</span><span class="cx">     my %keywordids;
</span><span class="cx">     my $keywords = $dbh-&gt;selectall_arrayref(q{SELECT id, name
</span><span class="lines">@@ -770,79 +695,6 @@
</span><span class="cx">         $lastid = $id;
</span><span class="cx">         $lastk = $k;
</span><span class="cx">     }
</span><del>-
-    Status('keyword_cache_start');
-
-    if ($cgi-&gt;param('rebuildkeywordcache')) {
-        $dbh-&gt;bz_start_transaction();
-    }
-
-    my $query = q{SELECT keywords.bug_id, keyworddefs.name
-                    FROM keywords
-              INNER JOIN keyworddefs
-                      ON keyworddefs.id = keywords.keywordid
-              INNER JOIN bugs
-                      ON keywords.bug_id = bugs.bug_id
-                ORDER BY keywords.bug_id, keyworddefs.name};
-
-    $sth = $dbh-&gt;prepare($query);
-    $sth-&gt;execute;
-
-    my $lastb = 0;
-    my @list;
-    my %realk;
-    while (1) {
-        my ($b, $k) = $sth-&gt;fetchrow_array;
-        if (!defined $b || $b != $lastb) {
-            if (@list) {
-                $realk{$lastb} = join(', ', @list);
-            }
-            last unless $b;
-
-            $lastb = $b;
-            @list = ();
-        }
-        push(@list, $k);
-    }
-
-    my @badbugs = ();
-
-    foreach my $b (keys(%$keyword)) {
-        if (!exists $realk{$b} || $realk{$b} ne $keyword-&gt;{$b}) {
-            push(@badbugs, $b);
-        }
-    }
-    foreach my $b (keys(%realk)) {
-        if (!exists $keyword-&gt;{$b}) {
-            push(@badbugs, $b);
-        }
-    }
-    if (@badbugs) {
-        @badbugs = sort {$a &lt;=&gt; $b} @badbugs;
-
-        if ($cgi-&gt;param('rebuildkeywordcache')) {
-            my $sth_update = $dbh-&gt;prepare(q{UPDATE bugs
-                                                SET keywords = ?
-                                              WHERE bug_id = ?});
-
-            Status('keyword_cache_fixing');
-            foreach my $b (@badbugs) {
-                my $k = '';
-                if (exists($realk{$b})) {
-                    $k = $realk{$b};
-                }
-                $sth_update-&gt;execute($k, $b);
-            }
-            Status('keyword_cache_fixed');
-        } else {
-            Status('keyword_cache_alert', {badbugs =&gt; \@badbugs}, 'alert');
-            Status('keyword_cache_rebuild');
-        }
-    }
-
-    if ($cgi-&gt;param('rebuildkeywordcache')) {
-        $dbh-&gt;bz_commit_transaction();
-    }
</del><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ###########################################################################
</span><span class="lines">@@ -953,20 +805,14 @@
</span><span class="cx"> Status('bug_check_status_everconfirmed');
</span><span class="cx"> 
</span><span class="cx"> BugCheck(&quot;bugs WHERE bug_status = 'UNCONFIRMED' AND everconfirmed = 1&quot;,
</span><del>-         'bug_check_status_everconfirmed_error_text');
</del><ins>+         'bug_check_status_everconfirmed_error_text', 'repair_everconfirmed');
</ins><span class="cx"> 
</span><span class="cx"> my @confirmed_open_states = grep {$_ ne 'UNCONFIRMED'} BUG_STATE_OPEN;
</span><span class="cx"> my $confirmed_open_states = join(', ', map {$dbh-&gt;quote($_)} @confirmed_open_states);
</span><span class="cx"> 
</span><span class="cx"> BugCheck(&quot;bugs WHERE bug_status IN ($confirmed_open_states) AND everconfirmed = 0&quot;,
</span><del>-         'bug_check_status_everconfirmed_error_text2');
</del><ins>+         'bug_check_status_everconfirmed_error_text2', 'repair_everconfirmed');
</ins><span class="cx"> 
</span><del>-Status('bug_check_votes_everconfirmed');
-
-BugCheck(&quot;bugs INNER JOIN products ON bugs.product_id = products.id &quot; .
-         &quot;WHERE everconfirmed = 0 AND votestoconfirm &lt;= votes&quot;,
-         'bug_check_votes_everconfirmed_error_text');
-
</del><span class="cx"> ###########################################################################
</span><span class="cx"> # Control Values
</span><span class="cx"> ###########################################################################
</span><span class="lines">@@ -1021,12 +867,12 @@
</span><span class="cx"> 
</span><span class="cx"> Status('unsent_bugmail_check');
</span><span class="cx"> 
</span><del>-my $time = $dbh-&gt;sql_interval(30, 'MINUTE');
</del><ins>+my $time = $dbh-&gt;sql_date_math('NOW()', '-', 30, 'MINUTE');
</ins><span class="cx"> my $badbugs = $dbh-&gt;selectcol_arrayref(qq{
</span><span class="cx">                     SELECT bug_id 
</span><span class="cx">                       FROM bugs 
</span><span class="cx">                      WHERE (lastdiffed IS NULL OR lastdiffed &lt; delta_ts)
</span><del>-                       AND delta_ts &lt; now() - $time
</del><ins>+                       AND delta_ts &lt; $time
</ins><span class="cx">                   ORDER BY bug_id});
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -1060,6 +906,12 @@
</span><span class="cx"> Status('whines_obsolete_target_fix') if $display_repair_whines_link;
</span><span class="cx"> 
</span><span class="cx"> ###########################################################################
</span><ins>+# Check hook
+###########################################################################
+
+Bugzilla::Hook::process('sanitycheck_check', { status =&gt; \&amp;Status });
+
+###########################################################################
</ins><span class="cx"> # End
</span><span class="cx"> ###########################################################################
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgsanitycheckpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/sanitycheck.pl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/sanitycheck.pl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/sanitycheck.pl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -42,8 +42,6 @@
</span><span class="cx"> 
</span><span class="cx"> pod2usage({-verbose =&gt; 1, -exitval =&gt; 1}) if $help;
</span><span class="cx"> 
</span><del>-Bugzilla-&gt;usage_mode(USAGE_MODE_CMDLINE);
-
</del><span class="cx"> # Be sure a login name if given.
</span><span class="cx"> $login || ThrowUserError('invalid_username');
</span><span class="cx"> 
</span><span class="lines">@@ -113,4 +111,4 @@
</span><span class="cx"> 
</span><span class="cx"> This script provides a way of running a 'Sanity Check' on the database
</span><span class="cx"> via either a CLI or cron. It is equivalent to calling sanitycheck.cgi
</span><del>-via a web broswer.
</del><ins>+via a web browser.
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgsearch_plugincgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/search_plugin.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/search_plugin.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/search_plugin.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -20,14 +20,24 @@
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla;
</span><span class="cx"> use Bugzilla::Error;
</span><ins>+use Bugzilla::Constants;
</ins><span class="cx"> 
</span><span class="cx"> Bugzilla-&gt;login();
</span><span class="cx"> 
</span><span class="cx"> my $cgi = Bugzilla-&gt;cgi;
</span><span class="cx"> my $template = Bugzilla-&gt;template;
</span><ins>+my $vars = {};
</ins><span class="cx"> 
</span><span class="cx"> # Return the appropriate HTTP response headers.
</span><span class="cx"> print $cgi-&gt;header('application/xml');
</span><span class="cx"> 
</span><del>-$template-&gt;process(&quot;search/search-plugin.xml.tmpl&quot;)
</del><ins>+# Get the contents of favicon.ico
+my $filename = bz_locations()-&gt;{'libpath'} . &quot;/images/favicon.ico&quot;;
+if (open(IN, $filename)) {
+    local $/;
+    binmode IN;
+    $vars-&gt;{'favicon'} = &lt;IN&gt;;
+    close IN;
+}
+$template-&gt;process(&quot;search/search-plugin.xml.tmpl&quot;, $vars)
</ins><span class="cx">   || ThrowTemplateError($template-&gt;error());
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgshow_activitycgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/show_activity.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/show_activity.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/show_activity.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -43,17 +43,21 @@
</span><span class="cx"> 
</span><span class="cx"> # Make sure the bug ID is a positive integer representing an existing
</span><span class="cx"> # bug that the user is authorized to access.
</span><del>-my $bug_id = $cgi-&gt;param('id');
-ValidateBugID($bug_id);
</del><ins>+my $id = $cgi-&gt;param('id');
+my $bug = Bugzilla::Bug-&gt;check($id);
</ins><span class="cx"> 
</span><span class="cx"> ###############################################################################
</span><span class="cx"> # End Data/Security Validation
</span><span class="cx"> ###############################################################################
</span><span class="cx"> 
</span><ins>+# Run queries against the shadow DB. In the worst case, new changes are not
+# visible immediately due to replication lag.
+Bugzilla-&gt;switch_to_shadow_db;
+
</ins><span class="cx"> ($vars-&gt;{'operations'}, $vars-&gt;{'incomplete_data'}) = 
</span><del>-    Bugzilla::Bug::GetBugActivity($bug_id);
</del><ins>+    Bugzilla::Bug::GetBugActivity($bug-&gt;id);
</ins><span class="cx"> 
</span><del>-$vars-&gt;{'bug'} = new Bugzilla::Bug($bug_id);
</del><ins>+$vars-&gt;{'bug'} = $bug;
</ins><span class="cx"> 
</span><span class="cx"> print $cgi-&gt;header();
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgshow_bugcgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/show_bug.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/show_bug.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/show_bug.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -51,15 +51,20 @@
</span><span class="cx">     exit;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-my @bugs = ();
</del><ins>+my $format = $template-&gt;get_format(&quot;bug/show&quot;, scalar $cgi-&gt;param('format'), 
+                                   scalar $cgi-&gt;param('ctype'));
+
+my @bugs;
</ins><span class="cx"> my %marks;
</span><span class="cx"> 
</span><ins>+# If the user isn't logged in, we use data from the shadow DB. If he plans
+# to edit the bug(s), he will have to log in first, meaning that the data
+# will be reloaded anyway, from the main DB.
+Bugzilla-&gt;switch_to_shadow_db unless $user-&gt;id;
+
</ins><span class="cx"> if ($single) {
</span><span class="cx">     my $id = $cgi-&gt;param('id');
</span><del>-    # Its a bit silly to do the validation twice - that functionality should
-    # probably move into Bug.pm at some point
-    ValidateBugID($id);
-    push @bugs, new Bugzilla::Bug($id);
</del><ins>+    push @bugs, Bugzilla::Bug-&gt;check($id);
</ins><span class="cx">     if (defined $cgi-&gt;param('mark')) {
</span><span class="cx">         foreach my $range (split ',', $cgi-&gt;param('mark')) {
</span><span class="cx">             if ($range =~ /^(\d+)-(\d+)$/) {
</span><span class="lines">@@ -88,32 +93,19 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-# Determine if Patch Viewer is installed, for Diff link
-eval {
-  require PatchReader;
-  $vars-&gt;{'patchviewerinstalled'} = 1;
-};
</del><ins>+Bugzilla::Bug-&gt;preload(\@bugs);
</ins><span class="cx"> 
</span><span class="cx"> $vars-&gt;{'bugs'} = \@bugs;
</span><span class="cx"> $vars-&gt;{'marks'} = \%marks;
</span><del>-$vars-&gt;{'use_keywords'} = 1 if Bugzilla::Keyword::keyword_count();
</del><span class="cx"> 
</span><span class="cx"> my @bugids = map {$_-&gt;bug_id} grep {!$_-&gt;error} @bugs;
</span><span class="cx"> $vars-&gt;{'bugids'} = join(&quot;, &quot;, @bugids);
</span><span class="cx"> 
</span><del>-# Next bug in list (if there is one)
-my @bug_list;
-if ($cgi-&gt;cookie(&quot;BUGLIST&quot;)) {
-    @bug_list = split(/:/, $cgi-&gt;cookie(&quot;BUGLIST&quot;));
-}
-
-$vars-&gt;{'bug_list'} = \@bug_list;
-
</del><span class="cx"> # Work out which fields we are displaying (currently XML only.)
</span><span class="cx"> # If no explicit list is defined, we show all fields. We then exclude any
</span><span class="cx"> # on the exclusion list. This is so you can say e.g. &quot;Everything except 
</span><span class="cx"> # attachments&quot; without listing almost all the fields.
</span><del>-my @fieldlist = (Bugzilla::Bug-&gt;fields, 'group', 'long_desc', 
</del><ins>+my @fieldlist = (Bugzilla::Bug-&gt;fields, 'flag', 'group', 'long_desc',
</ins><span class="cx">                  'attachment', 'attachmentdata', 'token');
</span><span class="cx"> my %displayfields;
</span><span class="cx"> 
</span><span class="lines">@@ -121,7 +113,7 @@
</span><span class="cx">     @fieldlist = $cgi-&gt;param(&quot;field&quot;);
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-unless (Bugzilla-&gt;user-&gt;in_group(Bugzilla-&gt;params-&gt;{&quot;timetrackinggroup&quot;})) {
</del><ins>+unless (Bugzilla-&gt;user-&gt;is_timetracker) {
</ins><span class="cx">     @fieldlist = grep($_ !~ /(^deadline|_time)$/, @fieldlist);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgshowattachmentcgi"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/showattachment.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/showattachment.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/showattachment.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,40 +0,0 @@
</span><del>-#!/usr/bin/env perl -wT
-# -*- Mode: perl; indent-tabs-mode: nil -*-
-#
-# The contents of this file are subject to the Mozilla Public
-# License Version 1.1 (the &quot;License&quot;); you may not use this file
-# except in compliance with the License. You may obtain a copy of
-# the License at http://www.mozilla.org/MPL/
-#
-# Software distributed under the License is distributed on an &quot;AS
-# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
-# implied. See the License for the specific language governing
-# rights and limitations under the License.
-#
-# The Original Code is the Bugzilla Bug Tracking System.
-#
-# The Initial Developer of the Original Code is Netscape Communications
-# Corporation. Portions created by Netscape are
-# Copyright (C) 1998 Netscape Communications Corporation. All
-# Rights Reserved.
-#
-# Contributor(s): Terry Weissman &lt;terry@mozilla.org&gt;
-#                 Jacob Steenhagen &lt;jake@bugzilla.org&gt;
-
-use strict;
-
-use lib qw(. lib);
-
-use Bugzilla;
-use Bugzilla::Util;
-
-my $cgi = Bugzilla-&gt;cgi;
-
-my $id = $cgi-&gt;param('attach_id');
-detaint_natural($id) if defined $id;
-$id ||= &quot;&quot;;
-
-print $cgi-&gt;redirect(-location=&gt;&quot;attachment.cgi?id=$id&quot;,
-                     -status=&gt;'301 Permanent Redirect');
-
-exit;
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgshowdependencygraphcgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/showdependencygraph.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/showdependencygraph.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/showdependencygraph.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -29,6 +29,7 @@
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla;
</span><span class="cx"> use Bugzilla::Constants;
</span><ins>+use Bugzilla::Install::Filesystem;
</ins><span class="cx"> use Bugzilla::Util;
</span><span class="cx"> use Bugzilla::Error;
</span><span class="cx"> use Bugzilla::Bug;
</span><span class="lines">@@ -58,7 +59,7 @@
</span><span class="cx"> sub CreateImagemap {
</span><span class="cx">     my $mapfilename = shift;
</span><span class="cx">     my $map = &quot;&lt;map name=\&quot;imagemap\&quot;&gt;\n&quot;;
</span><del>-    my $default;
</del><ins>+    my $default = &quot;&quot;;
</ins><span class="cx"> 
</span><span class="cx">     open MAP, &quot;&lt;$mapfilename&quot;;
</span><span class="cx">     while(my $line = &lt;MAP&gt;) {
</span><span class="lines">@@ -89,32 +90,36 @@
</span><span class="cx">     my $key = &quot;$blocked,$dependson&quot;;
</span><span class="cx">     if (!exists $edgesdone{$key}) {
</span><span class="cx">         $edgesdone{$key} = 1;
</span><del>-        print $fh &quot;$blocked -&gt; $dependson\n&quot;;
</del><ins>+        print $fh &quot;$dependson -&gt; $blocked\n&quot;;
</ins><span class="cx">         $seen{$blocked} = 1;
</span><span class="cx">         $seen{$dependson} = 1;
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+ThrowCodeError(&quot;missing_bug_id&quot;) if !defined $cgi-&gt;param('id');
+
</ins><span class="cx"> # The list of valid directions. Some are not proposed in the dropdrown
</span><span class="cx"> # menu despite the fact that they are valid.
</span><span class="cx"> my @valid_rankdirs = ('LR', 'RL', 'TB', 'BT');
</span><span class="cx"> 
</span><span class="cx"> my $rankdir = $cgi-&gt;param('rankdir') || 'TB';
</span><span class="cx"> # Make sure the submitted 'rankdir' value is valid.
</span><del>-if (lsearch(\@valid_rankdirs, $rankdir) &lt; 0) {
</del><ins>+if (!grep { $_ eq $rankdir } @valid_rankdirs) {
</ins><span class="cx">     $rankdir = 'TB';
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> my $display = $cgi-&gt;param('display') || 'tree';
</span><span class="cx"> my $webdotdir = bz_locations()-&gt;{'webdotdir'};
</span><span class="cx"> 
</span><del>-if (!defined $cgi-&gt;param('id') &amp;&amp; $display ne 'doall') {
-    ThrowCodeError(&quot;missing_bug_id&quot;);
-}
-
</del><span class="cx"> my ($fh, $filename) = File::Temp::tempfile(&quot;XXXXXXXXXX&quot;,
</span><span class="cx">                                            SUFFIX =&gt; '.dot',
</span><del>-                                           DIR =&gt; $webdotdir);
</del><ins>+                                           DIR =&gt; $webdotdir,
+                                           UNLINK =&gt; 1);
+
+chmod Bugzilla::Install::Filesystem::CGI_WRITE, $filename
+    or warn install_string('chmod_failed', { path =&gt; $filename,
+                                             error =&gt; $! });
+
</ins><span class="cx"> my $urlbase = Bugzilla-&gt;params-&gt;{'urlbase'};
</span><span class="cx"> 
</span><span class="cx"> print $fh &quot;digraph G {&quot;;
</span><span class="lines">@@ -125,64 +130,54 @@
</span><span class="cx"> 
</span><span class="cx"> my %baselist;
</span><span class="cx"> 
</span><del>-if ($display eq 'doall') {
-    my $dependencies = $dbh-&gt;selectall_arrayref(
-                           &quot;SELECT blocked, dependson FROM dependencies&quot;);
</del><ins>+foreach my $i (split('[\s,]+', $cgi-&gt;param('id'))) {
+    my $bug = Bugzilla::Bug-&gt;check($i);
+    $baselist{$bug-&gt;id} = 1;
+}
</ins><span class="cx"> 
</span><del>-    foreach my $dependency (@$dependencies) {
-        my ($blocked, $dependson) = @$dependency;
-        AddLink($blocked, $dependson, $fh);
-    }
-} else {
-    foreach my $i (split('[\s,]+', $cgi-&gt;param('id'))) {
-        ValidateBugID($i);
-        $baselist{$i} = 1;
-    }
</del><ins>+my @stack = keys(%baselist);
</ins><span class="cx"> 
</span><del>-    my @stack = keys(%baselist);
</del><ins>+if ($display eq 'web') {
+    my $sth = $dbh-&gt;prepare(q{SELECT blocked, dependson
+                                FROM dependencies
+                               WHERE blocked = ? OR dependson = ?});
</ins><span class="cx"> 
</span><del>-    if ($display eq 'web') {
-        my $sth = $dbh-&gt;prepare(q{SELECT blocked, dependson
-                                    FROM dependencies
-                                   WHERE blocked = ? OR dependson = ?});
-
-        foreach my $id (@stack) {
-            my $dependencies = $dbh-&gt;selectall_arrayref($sth, undef, ($id, $id));
-            foreach my $dependency (@$dependencies) {
-                my ($blocked, $dependson) = @$dependency;
-                if ($blocked != $id &amp;&amp; !exists $seen{$blocked}) {
-                    push @stack, $blocked;
-                }
-                if ($dependson != $id &amp;&amp; !exists $seen{$dependson}) {
-                    push @stack, $dependson;
-                }
-                AddLink($blocked, $dependson, $fh);
</del><ins>+    foreach my $id (@stack) {
+        my $dependencies = $dbh-&gt;selectall_arrayref($sth, undef, ($id, $id));
+        foreach my $dependency (@$dependencies) {
+            my ($blocked, $dependson) = @$dependency;
+            if ($blocked != $id &amp;&amp; !exists $seen{$blocked}) {
+                push @stack, $blocked;
</ins><span class="cx">             }
</span><ins>+            if ($dependson != $id &amp;&amp; !exists $seen{$dependson}) {
+                push @stack, $dependson;
+            }
+            AddLink($blocked, $dependson, $fh);
</ins><span class="cx">         }
</span><span class="cx">     }
</span><del>-    # This is the default: a tree instead of a spider web.
-    else {
-        my @blocker_stack = @stack;
-        foreach my $id (@blocker_stack) {
-            my $blocker_ids = Bugzilla::Bug::EmitDependList('blocked', 'dependson', $id);
-            foreach my $blocker_id (@$blocker_ids) {
-                push(@blocker_stack, $blocker_id) unless $seen{$blocker_id};
-                AddLink($id, $blocker_id, $fh);
-            }
</del><ins>+}
+# This is the default: a tree instead of a spider web.
+else {
+    my @blocker_stack = @stack;
+    foreach my $id (@blocker_stack) {
+        my $blocker_ids = Bugzilla::Bug::EmitDependList('blocked', 'dependson', $id);
+        foreach my $blocker_id (@$blocker_ids) {
+            push(@blocker_stack, $blocker_id) unless $seen{$blocker_id};
+            AddLink($id, $blocker_id, $fh);
</ins><span class="cx">         }
</span><del>-        my @dependent_stack = @stack;
-        foreach my $id (@dependent_stack) {
-            my $dep_bug_ids = Bugzilla::Bug::EmitDependList('dependson', 'blocked', $id);
-            foreach my $dep_bug_id (@$dep_bug_ids) {
-                push(@dependent_stack, $dep_bug_id) unless $seen{$dep_bug_id};
-                AddLink($dep_bug_id, $id, $fh);
-            }
</del><ins>+    }
+    my @dependent_stack = @stack;
+    foreach my $id (@dependent_stack) {
+        my $dep_bug_ids = Bugzilla::Bug::EmitDependList('dependson', 'blocked', $id);
+        foreach my $dep_bug_id (@$dep_bug_ids) {
+            push(@dependent_stack, $dep_bug_id) unless $seen{$dep_bug_id};
+            AddLink($dep_bug_id, $id, $fh);
</ins><span class="cx">         }
</span><span class="cx">     }
</span><ins>+}
</ins><span class="cx"> 
</span><del>-    foreach my $k (keys(%baselist)) {
-        $seen{$k} = 1;
-    }
</del><ins>+foreach my $k (keys(%baselist)) {
+    $seen{$k} = 1;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> my $sth = $dbh-&gt;prepare(
</span><span class="lines">@@ -192,9 +187,6 @@
</span><span class="cx"> foreach my $k (keys(%seen)) {
</span><span class="cx">     # Retrieve bug information from the database
</span><span class="cx">     my ($stat, $resolution, $summary) = $dbh-&gt;selectrow_array($sth, undef, $k);
</span><del>-    $stat ||= 'NEW';
-    $resolution ||= '';
-    $summary ||= '';
</del><span class="cx"> 
</span><span class="cx">     # Resolution and summary are shown only if user can see the bug
</span><span class="cx">     if (!Bugzilla-&gt;user-&gt;can_see_bug($k)) {
</span><span class="lines">@@ -206,6 +198,10 @@
</span><span class="cx">     my @params;
</span><span class="cx"> 
</span><span class="cx">     if ($summary ne &quot;&quot; &amp;&amp; $cgi-&gt;param('showsummary')) {
</span><ins>+        # Wide characters cause GraphViz to die.
+        if (Bugzilla-&gt;params-&gt;{'utf8'}) {
+            utf8::encode($summary) if utf8::is_utf8($summary);
+        }
</ins><span class="cx">         $summary =~ s/([\\\&quot;])/\\$1/g;
</span><span class="cx">         push(@params, qq{label=&quot;$k\\n$summary&quot;});
</span><span class="cx">     }
</span><span class="lines">@@ -240,8 +236,6 @@
</span><span class="cx"> print $fh &quot;}\n&quot;;
</span><span class="cx"> close $fh;
</span><span class="cx"> 
</span><del>-chmod 0777, $filename;
-
</del><span class="cx"> my $webdotbase = Bugzilla-&gt;params-&gt;{'webdotbase'};
</span><span class="cx"> 
</span><span class="cx"> if ($webdotbase =~ /^https?:/) {
</span><span class="lines">@@ -259,15 +253,20 @@
</span><span class="cx">     my ($pngfh, $pngfilename) = File::Temp::tempfile(&quot;XXXXXXXXXX&quot;,
</span><span class="cx">                                                      SUFFIX =&gt; '.png',
</span><span class="cx">                                                      DIR =&gt; $webdotdir);
</span><ins>+
+    chmod Bugzilla::Install::Filesystem::WS_SERVE, $pngfilename
+        or warn install_string('chmod_failed', { path =&gt; $pngfilename,
+                                                 error =&gt; $! });
+
</ins><span class="cx">     binmode $pngfh;
</span><span class="cx">     open(DOT, &quot;\&quot;$webdotbase\&quot; -Tpng $filename|&quot;);
</span><span class="cx">     binmode DOT;
</span><span class="cx">     print $pngfh $_ while &lt;DOT&gt;;
</span><span class="cx">     close DOT;
</span><span class="cx">     close $pngfh;
</span><del>-    
</del><ins>+
</ins><span class="cx">     # On Windows $pngfilename will contain \ instead of /
</span><del>-    $pngfilename =~ s|\\|/|g if $^O eq 'MSWin32';
</del><ins>+    $pngfilename =~ s|\\|/|g if ON_WINDOWS;
</ins><span class="cx"> 
</span><span class="cx">     # Under mod_perl, pngfilename will have an absolute path, and we
</span><span class="cx">     # need to make that into a relative path.
</span><span class="lines">@@ -283,12 +282,18 @@
</span><span class="cx">     my ($mapfh, $mapfilename) = File::Temp::tempfile(&quot;XXXXXXXXXX&quot;,
</span><span class="cx">                                                      SUFFIX =&gt; '.map',
</span><span class="cx">                                                      DIR =&gt; $webdotdir);
</span><ins>+
+    chmod Bugzilla::Install::Filesystem::WS_SERVE, $mapfilename
+        or warn install_string('chmod_failed', { path =&gt; $mapfilename,
+                                                 error =&gt; $! });
+
</ins><span class="cx">     binmode $mapfh;
</span><span class="cx">     open(DOT, &quot;\&quot;$webdotbase\&quot; -Tismap $filename|&quot;);
</span><span class="cx">     binmode DOT;
</span><span class="cx">     print $mapfh $_ while &lt;DOT&gt;;
</span><span class="cx">     close DOT;
</span><span class="cx">     close $mapfh;
</span><ins>+
</ins><span class="cx">     $vars-&gt;{'image_map'} = CreateImagemap($mapfilename);
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgshowdependencytreecgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/showdependencytree.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/showdependencytree.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/showdependencytree.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -49,9 +49,8 @@
</span><span class="cx"> 
</span><span class="cx"> # Make sure the bug ID is a positive integer representing an existing
</span><span class="cx"> # bug that the user is authorized to access.
</span><del>-my $id = $cgi-&gt;param('id') || ThrowUserError('improper_bug_id_field_value');
-ValidateBugID($id);
-my $current_bug = new Bugzilla::Bug($id);
</del><ins>+my $bug = Bugzilla::Bug-&gt;check(scalar $cgi-&gt;param('id'));
+my $id = $bug-&gt;id;
</ins><span class="cx"> 
</span><span class="cx"> local our $hide_resolved = $cgi-&gt;param('hide_resolved') ? 1 : 0;
</span><span class="cx"> 
</span><span class="lines">@@ -67,7 +66,7 @@
</span><span class="cx"> 
</span><span class="cx"> # Generate the tree of bugs that this bug depends on and a list of IDs
</span><span class="cx"> # appearing in the tree.
</span><del>-my $dependson_tree = { $id =&gt; $current_bug };
</del><ins>+my $dependson_tree = { $id =&gt; $bug };
</ins><span class="cx"> my $dependson_ids = {};
</span><span class="cx"> GenerateTree($id, &quot;dependson&quot;, 1, $dependson_tree, $dependson_ids);
</span><span class="cx"> $vars-&gt;{'dependson_tree'} = $dependson_tree;
</span><span class="lines">@@ -75,7 +74,7 @@
</span><span class="cx"> 
</span><span class="cx"> # Generate the tree of bugs that this bug blocks and a list of IDs
</span><span class="cx"> # appearing in the tree.
</span><del>-my $blocked_tree = { $id =&gt; $current_bug };
</del><ins>+my $blocked_tree = { $id =&gt; $bug };
</ins><span class="cx"> my $blocked_ids = {};
</span><span class="cx"> GenerateTree($id, &quot;blocked&quot;, 1, $blocked_tree, $blocked_ids);
</span><span class="cx"> $vars-&gt;{'blocked_tree'} = $blocked_tree;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgsidebarcgi"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/sidebar.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/sidebar.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/sidebar.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,49 +0,0 @@
</span><del>-#!/usr/bin/env perl -wT
-# -*- Mode: perl; indent-tabs-mode: nil -*-
-#
-# The contents of this file are subject to the Mozilla Public
-# License Version 1.1 (the &quot;License&quot;); you may not use this file
-# except in compliance with the License. You may obtain a copy of
-# the License at http://www.mozilla.org/MPL/
-#
-# Software distributed under the License is distributed on an &quot;AS
-# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
-# implied. See the License for the specific language governing
-# rights and limitations under the License.
-#
-# The Original Code is the Bugzilla Bug Tracking System.
-#
-# Contributor(s): Jacob Steenhagen &lt;jake@bugzilla.org&gt;
-
-use strict;
-
-use lib qw(. lib);
-
-use Bugzilla;
-use Bugzilla::Error;
-
-Bugzilla-&gt;login();
-my $cgi = Bugzilla-&gt;cgi;
-my $template = Bugzilla-&gt;template;
-
-###############################################################################
-# Main Body Execution
-###############################################################################
-
-# This sidebar is currently for use with Mozilla based web browsers.
-# Internet Explorer 6 is supposed to have a similar feature, but it
-# most likely won't support XUL ;)  When that does come out, this
-# can be expanded to output normal HTML for IE.  Until then, I like
-# the way Scott's sidebar looks so I'm using that as the base for
-# this file.
-# http://bugzilla.mozilla.org/show_bug.cgi?id=37339
-
-my $useragent = $ENV{HTTP_USER_AGENT};
-if ($useragent =~ m:Mozilla/([1-9][0-9]*):i &amp;&amp; $1 &gt;= 5 &amp;&amp; $useragent !~ m/compatible/i) {
-    print $cgi-&gt;header(&quot;application/vnd.mozilla.xul+xml&quot;);
-    # Generate and return the XUL from the appropriate template.
-    $template-&gt;process(&quot;sidebar.xul.tmpl&quot;)
-      || ThrowTemplateError($template-&gt;error());
-} else {
-    ThrowUserError(&quot;sidebar_supports_mozilla_only&quot;);
-}
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscvsignore"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/.cvsignore (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/.cvsignore        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/.cvsignore        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1 +0,0 @@
</span><del>-custom
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinsREADME"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/skins/README (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/README                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/skins/README        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,20 @@
</span><ins>+There are three directories here, standard/, custom/, and contrib/.
+
+standard/ holds the standard stylesheets. These are used no matter
+what skin the user selects. If the user selects the &quot;Classic&quot; skin,
+then *only* the standard/ stylesheets are used.
+
+contrib/ holds &quot;skins&quot; that the user can select in their preferences.
+skins are in directories, and they contain files with the same names
+as the files in skins/standard/. Simply putting a new directory
+into the contrib/ directory adds a new skin as an option in users'
+preferences.
+
+custom/ allows you to locally override the standard/ and contrib/ CSS.
+If you put files into the custom/ directory with the same names as the CSS
+files in skins/standard/, you can override the standard/ and contrib/
+CSS. For example, if you want to override some CSS in
+skins/standard/global.css, then you should create a file called &quot;global.css&quot;
+in custom/ and put some CSS in it. The CSS you put into files in custom/ will
+be used *in addition* to the CSS in skins/standard/ or the CSS in
+skins/contrib/. It will apply to every skin.
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscontribDuskcvsignore"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/.cvsignore (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/.cvsignore        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/.cvsignore        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,17 +0,0 @@
</span><del>-IE-fixes.css
-admin.css
-attachment.css
-create_attachment.css
-dependency-tree.css
-duplicates.css
-editusers.css
-help.css
-index.css
-panel.css
-params.css
-release-notes.css
-show_bug.css
-show_multiple.css
-summarize-time.css
-voting.css
-yui
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscontribDuskIEfixescss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/IE-fixes.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/IE-fixes.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/IE-fixes.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +0,0 @@
</span><del>-/*
- * Custom rules for IE-fixes.css.
- * The rules you put here override rules in that stylesheet.
- */
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscontribDuskadmincss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/admin.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/admin.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/admin.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +0,0 @@
</span><del>-/*
- * Custom rules for admin.css.
- * The rules you put here override rules in that stylesheet.
- */
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscontribDuskcreate_attachmentcss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/create_attachment.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/create_attachment.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/create_attachment.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +0,0 @@
</span><del>-/*
- * Custom rules for create_attachment.css.
- * The rules you put here override rules in that stylesheet.
- */
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscontribDuskdependencytreecss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/dependency-tree.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/dependency-tree.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/dependency-tree.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +0,0 @@
</span><del>-/*
- * Custom rules for dependency-tree.css.
- * The rules you put here override rules in that stylesheet.
- */
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscontribDuskduplicatescss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/duplicates.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/duplicates.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/duplicates.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +0,0 @@
</span><del>-/*
- * Custom rules for duplicates.css.
- * The rules you put here override rules in that stylesheet.
- */
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscontribDuskedituserscss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/editusers.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/editusers.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/editusers.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +0,0 @@
</span><del>-/*
- * Custom rules for editusers.css.
- * The rules you put here override rules in that stylesheet.
- */
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscontribDuskglobalcss"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/global.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/global.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/global.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -34,50 +34,43 @@
</span><span class="cx">     -moz-border-radius-topright: 5px;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-#header .links {
</del><ins>+#header .links, #footer {
</ins><span class="cx">     background-color: #929bb1;
</span><del>-    color: #f1dbc7;
</del><ins>+    color: #ddd;
+}
+
+#header {
</ins><span class="cx">     -moz-border-radius-bottomleft: 5px;
</span><span class="cx">     -moz-border-radius-bottomright: 5px;
</span><span class="cx">     border: none;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-#header a {
</del><ins>+#header a, #footer a {
</ins><span class="cx">     color: white;
</span><ins>+    text-decoration: none;
</ins><span class="cx"> }
</span><ins>+#header a:hover, #footer a:hover {
+    text-decoration: underline;
+}
</ins><span class="cx"> 
</span><span class="cx"> /* body */
</span><span class="cx"> 
</span><span class="cx"> #bugzilla-body {
</span><span class="cx">     background: #f0f0f0;
</span><span class="cx">     color: black;
</span><del>-    margin-top: 10px;
-    margin-bottom: 10px;
</del><span class="cx">     border: 1px solid #747e93;
</span><span class="cx">     padding: 10px;
</span><span class="cx">     font-size: 10pt;
</span><span class="cx">     -moz-border-radius: 5px;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-a:link,
-a:link:hover {
-    color: #6169c0;
</del><ins>+a {
+    color: #6070cf;
</ins><span class="cx"> }
</span><del>-
-a:visited {
-    color: #3d4a68;
</del><ins>+a:hover {
+    color: #8090ef;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-a:link,
-a:visited {
-    text-decoration: none;
-}
-
-a:link:hover,
-a:visited:hover {
-    text-decoration: underline;
-}
-
</del><span class="cx"> hr {
</span><span class="cx">   border-color: #969696;
</span><span class="cx">   border-style: dashed;
</span><span class="lines">@@ -123,7 +116,9 @@
</span><span class="cx">     border-top: 1px solid #c8c8ba;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-/* comments */
</del><ins>+/************/
+/* Comments */
+/************/
</ins><span class="cx"> 
</span><span class="cx"> #comments th {
</span><span class="cx">     font-size: 9pt;
</span><span class="lines">@@ -155,26 +150,21 @@
</span><span class="cx">     font-size: 9pt;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-.bz_first_comment {
-}
-
-.bz_comment_head,
-.bz_first_comment_head {
</del><ins>+.bz_comment_head, .bz_first_comment_head {
</ins><span class="cx">     margin: 0; padding: 0;
</span><span class="cx">     background-color: transparent;
</span><span class="cx">     font-weight: bold;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+.bz_comment_user {
+    margin-left: 0;
+}
+
</ins><span class="cx"> .bz_comment.bz_private {
</span><span class="cx">     background-color: #f0e8e8;
</span><span class="cx">     border-color: #f8c8ba;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-.bz_comment_head i,
-.bz_first_comment_head i {
-    font-style: normal;
-}
-
</del><span class="cx"> .comment_rule {
</span><span class="cx">     display: none;
</span><span class="cx"> }
</span><span class="lines">@@ -182,18 +172,11 @@
</span><span class="cx"> /* footer */
</span><span class="cx"> 
</span><span class="cx"> #footer {
</span><del>-    background: #929bb1;
-    color: #f1dbc7;
</del><span class="cx">     border: 1px solid #747e93;
</span><span class="cx">     width: 100%;
</span><del>-    font-size: 9pt;
</del><span class="cx">     -moz-border-radius: 5px;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-#footer a {
-    color: white;
-}
-
</del><span class="cx"> #footer #links-actions,
</span><span class="cx"> #footer #links-edit,
</span><span class="cx"> #footer #links-saved,
</span><span class="lines">@@ -201,24 +184,15 @@
</span><span class="cx">     margin-top: 2ex;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-#footer .label {
-    font-weight: bold;
-    color: #dddddd;
-}
-
</del><span class="cx"> #footer .links {
</span><span class="cx">     border-spacing: 30px;
</span><del>-    padding-bottom: 2ex;
</del><ins>+    margin-bottom: 2ex;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> .separator {
</span><span class="cx">     color: #cccccc;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-#footer li.form {
-    background-color: transparent;
-}
-
</del><span class="cx"> /* tabs */
</span><span class="cx"> 
</span><span class="cx"> .tabbed .tabbody {
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscontribDuskhelpcss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/help.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/help.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/help.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +0,0 @@
</span><del>-/*
- * Custom rules for help.css.
- * The rules you put here override rules in that stylesheet.
- */
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscontribDuskindexcss"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/index.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/index.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/index.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -2,3 +2,8 @@
</span><span class="cx">  * Custom rules for index.css.
</span><span class="cx">  * The rules you put here override rules in that stylesheet.
</span><span class="cx">  */
</span><ins>+    
+    div#page-index .outro 
+    {
+        clear:both;
+    }
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscontribDuskpanelcss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/panel.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/panel.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/panel.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +0,0 @@
</span><del>-/*
- * Custom rules for panel.css.
- * The rules you put here override rules in that stylesheet.
- */
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscontribDuskparamscss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/params.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/params.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/params.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +0,0 @@
</span><del>-/*
- * Custom rules for params.css.
- * The rules you put here override rules in that stylesheet.
- */
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscontribDuskreleasenotescss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/release-notes.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/release-notes.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/release-notes.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +0,0 @@
</span><del>-/*
- * Custom rules for release-notes.css.
- * The rules you put here override rules in that stylesheet.
- */
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscontribDuskshow_bugcss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/show_bug.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/show_bug.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/show_bug.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +0,0 @@
</span><del>-/*
- * Custom rules for show_bug.css.
- * The rules you put here override rules in that stylesheet.
- */
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscontribDuskshow_multiplecss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/show_multiple.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/show_multiple.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/show_multiple.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +0,0 @@
</span><del>-/*
- * Custom rules for show_multiple.css.
- * The rules you put here override rules in that stylesheet.
- */
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscontribDusksummarizetimecss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/summarize-time.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/summarize-time.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/summarize-time.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +0,0 @@
</span><del>-/*
- * Custom rules for summarize-time.css.
- * The rules you put here override rules in that stylesheet.
- */
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscontribDuskvotingcss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/voting.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/voting.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/contrib/Dusk/voting.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +0,0 @@
</span><del>-/*
- * Custom rules for voting.css.
- * The rules you put here override rules in that stylesheet.
- */
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscustomIEfixescss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/custom/IE-fixes.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/custom/IE-fixes.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/custom/IE-fixes.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +0,0 @@
</span><del>-/*
- * Custom rules for IE-fixes.css.
- * The rules you put here override rules in that stylesheet.
- */
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscustomadmincss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/custom/admin.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/custom/admin.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/custom/admin.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +0,0 @@
</span><del>-/*
- * Custom rules for admin.css.
- * The rules you put here override rules in that stylesheet.
- */
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscustombuglistcss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/custom/buglist.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/custom/buglist.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/custom/buglist.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +0,0 @@
</span><del>-/*
- * Custom rules for buglist.css.
- * The rules you put here override rules in that stylesheet.
- */
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscustomcreate_attachmentcss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/custom/create_attachment.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/custom/create_attachment.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/custom/create_attachment.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +0,0 @@
</span><del>-/*
- * Custom rules for create_attachment.css.
- * The rules you put here override rules in that stylesheet.
- */
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscustomdependencytreecss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/custom/dependency-tree.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/custom/dependency-tree.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/custom/dependency-tree.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +0,0 @@
</span><del>-/*
- * Custom rules for dependency-tree.css.
- * The rules you put here override rules in that stylesheet.
- */
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscustomduplicatescss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/custom/duplicates.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/custom/duplicates.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/custom/duplicates.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +0,0 @@
</span><del>-/*
- * Custom rules for duplicates.css.
- * The rules you put here override rules in that stylesheet.
- */
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscustomedituserscss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/custom/editusers.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/custom/editusers.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/custom/editusers.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +0,0 @@
</span><del>-/*
- * Custom rules for editusers.css.
- * The rules you put here override rules in that stylesheet.
- */
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscustomhelpcss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/custom/help.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/custom/help.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/custom/help.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +0,0 @@
</span><del>-/*
- * Custom rules for help.css.
- * The rules you put here override rules in that stylesheet.
- */
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscustomopendarwingif"></a>
<div class="binary"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/custom/opendarwin.gif</h4>
<pre class="diff"><span>
<span class="cx">(Binary files differ)
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscustompanelcss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/custom/panel.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/custom/panel.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/custom/panel.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +0,0 @@
</span><del>-/*
- * Custom rules for panel.css.
- * The rules you put here override rules in that stylesheet.
- */
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscustomparamscss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/custom/params.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/custom/params.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/custom/params.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +0,0 @@
</span><del>-/*
- * Custom rules for params.css.
- * The rules you put here override rules in that stylesheet.
- */
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscustomreleasenotescss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/custom/release-notes.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/custom/release-notes.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/custom/release-notes.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +0,0 @@
</span><del>-/*
- * Custom rules for release-notes.css.
- * The rules you put here override rules in that stylesheet.
- */
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscustomshow_bugcss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/custom/show_bug.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/custom/show_bug.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/custom/show_bug.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +0,0 @@
</span><del>-/*
- * Custom rules for show_bug.css.
- * The rules you put here override rules in that stylesheet.
- */
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscustomshow_multiplecss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/custom/show_multiple.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/custom/show_multiple.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/custom/show_multiple.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +0,0 @@
</span><del>-/*
- * Custom rules for show_multiple.css.
- * The rules you put here override rules in that stylesheet.
- */
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscustomsummarizetimecss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/custom/summarize-time.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/custom/summarize-time.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/custom/summarize-time.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +0,0 @@
</span><del>-/*
- * Custom rules for summarize-time.css.
- * The rules you put here override rules in that stylesheet.
- */
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinscustomvotingcss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/custom/voting.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/custom/voting.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/custom/voting.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,4 +0,0 @@
</span><del>-/*
- * Custom rules for voting.css.
- * The rules you put here override rules in that stylesheet.
- */
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinsstandardIEfixescss"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/skins/standard/IE-fixes.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/standard/IE-fixes.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/standard/IE-fixes.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -13,11 +13,19 @@
</span><span class="cx">   * Contributor(s): Marc Schumann &lt;wurblzap@gmail.com&gt;
</span><span class="cx">   */
</span><span class="cx"> 
</span><del>-.bz_comment_text, .uneditable_textarea {
</del><ins>+.bz_comment_text, .uneditable_textarea, tbody.file pre {
</ins><span class="cx">      white-space: pre;
</span><span class="cx">      word-wrap: break-word;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+.component_table {
+    margin-top: .5em;
+}
+
+form#Create #comp_desc {
+    margin: .5em 1em;
+}
+
</ins><span class="cx"> #footer #useful-links li {
</span><span class="cx">     padding-bottom: 0.8ex;
</span><span class="cx"> }
</span><span class="lines">@@ -36,3 +44,20 @@
</span><span class="cx"> #footer .links {
</span><span class="cx">     display: inline;
</span><span class="cx"> }
</span><ins>+
+#bug_id_container, .search_field_grid, 
+.search_email_fields, ul.bug_changes li { 
+    zoom: 1;
+    display: inline;
+}
+
+#keyword_container .yui-ac-content {
+    _height: 30em; /* ie6 */
+}
+
+.bz_short_desc_column a, .bz_short_short_desc_column a {
+    /* color:inherit */
+    color: expression(this.parentNode.currentStyle['color']);
+}
+
+
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinsstandardadmincss"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/skins/standard/admin.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/standard/admin.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/standard/admin.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -113,3 +113,15 @@
</span><span class="cx">     text-align: center;
</span><span class="cx">     vertical-align: middle;
</span><span class="cx"> }
</span><ins>+
+#edit_custom_field tr {
+    vertical-align: top;
+}
+
+#edit_custom_field th {
+    text-align: right;
+}
+
+#edit_custom_field th.narrow_label {
+    white-space: normal;
+}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinsstandardattachmentcss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/skins/standard/attachment.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/standard/attachment.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/skins/standard/attachment.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,247 @@
</span><ins>+ /* The contents of this file are subject to the Mozilla Public
+  * License Version 1.1 (the &quot;License&quot;); you may not use this file
+  * except in compliance with the License. You may obtain a copy of
+  * the License at http://www.mozilla.org/MPL/
+  *
+  * Software distributed under the License is distributed on an &quot;AS
+  * IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  * implied. See the License for the specific language governing
+  * rights and limitations under the License.
+  *
+  * The Original Code is the Bugzilla Bug Tracking System.
+  *
+  * Contributor(s): Myk Melez &lt;myk@mozilla.org&gt;
+  *                 Joel Peshkin &lt;bugreport@peshkin.net&gt;
+  *                 Erik Stambaugh &lt;erik@dasbistro.com&gt;
+  *                 Marc Schumann &lt;wurblzap@gmail.com&gt;
+  *                 Guy Pyrzak &lt;guy.pyrzak@gmail.com&gt;
+  */
+
+table.attachment_entry th {
+    text-align: right;
+    vertical-align: baseline;
+    white-space: nowrap;
+}
+
+table.attachment_entry td {
+    text-align: left;
+    vertical-align: baseline;
+    padding-bottom: 5px;
+}
+
+table#flags th,
+table#flags td {
+    text-align: left;
+    vertical-align: baseline;
+    font-size: small;
+}
+
+/* Rules used to view patches in diff mode. */
+
+.file_head {
+  font-weight: bold;
+  font-size: 1em;
+  background-color: #c3c3c3;
+  border: 1px solid black;
+}
+
+.file_head a {
+  text-decoration: none;
+  font-family: monospace;
+  font-size: 1.1em;
+}
+
+.file_collapse {
+  display: none;
+}
+
+.section_head {
+  background-color: #f0f0f0;
+  border: 1px solid black;
+  text-align: left;
+}
+
+table.file_table {
+  table-layout: fixed;
+  width: 100%;
+  empty-cells: show;
+  border-spacing: 0px;
+  border-collapse: collapse;
+  /* draw border below last open context section in listing */
+  border-bottom: 1px solid black;
+}
+
+tbody.file pre {
+  display: inline;
+  font-size: 0.9em;
+}
+
+tbody.file pre:empty {
+  display: block;
+}
+
+.changed {
+  background-color: lightblue;
+}
+
+.added {
+  background-color: lightgreen;
+}
+
+.removed {
+  background-color: #FFCC99;
+}
+
+.num {
+  background-color: #ffe9ae;
+  text-align:right;
+  padding: 0 0.3em;
+  width: 3em;
+}
+
+table.attachment_info th {
+    text-align: right;
+    vertical-align: top;
+}
+
+table.attachment_info td {
+    text-align: left;
+    vertical-align: top;
+}
+
+/* Text displayed when the attachment is not viewable by the web browser */
+#noview {
+    text-align: left;
+    vertical-align: middle;
+}
+
+#attachment_attributes div {
+    padding-bottom: 0.4em;
+}
+
+#attachment_attributes label,
+#attachment_attributes span.label,
+#attachment_actions span.label
+{
+    font-weight: bold;
+}
+
+#attachment_attributes .block {
+    display: block;
+}
+
+#smallCommentFrame, #attachment_flags {
+    float: left;
+}
+
+#smallCommentFrame {
+    margin-right: 1.5em;
+}
+
+#attachment_comments_and_flags, #attachment_actions {
+    clear: both;
+    margin-bottom: 1ex;
+}
+
+#attachment_information_read_only .title {
+    font-weight: bold;
+    font-size: 1.5em;
+    padding: 0;
+    margin: 0;
+}
+
+#attachment_information_read_only .title #bz_edit {
+    font-size: 0.7em;
+}
+
+#attachment_information_read_only .details {
+    font-size: 90%;
+}
+
+#attachment_info.read #attachment_information_edit {
+    display: none;
+}
+
+#attachment_info.edit #attachment_information_read_only {
+    display: none;  
+}
+
+#attachment_info.edit #attachment_view_window {
+    float: left;
+    width: 80%;
+}
+
+#attachment_info.edit #attachment_information_edit {
+    width: 20%;
+}
+
+#attachment_info.edit #attachment_information_edit input.text,
+#attachment_info.edit #attachment_information_edit textarea {
+    width: 90%; 
+}
+
+#attachment_isobsolete {
+    padding-right: 1em;
+}
+
+#attachment_information_edit { 
+    float: left;
+}
+
+#smallCommentFrame textarea {
+    display: block;
+}
+
+textarea.bz_private {
+    border: 1px solid #F8C8BA;
+}
+
+#update {
+    clear: both; 
+    display: block;  
+}
+
+div#update_container {
+    clear: both; 
+    padding: 1.5em 0; 
+}
+
+#attachment_flags {
+    margin-bottom: 1em;
+}
+
+#attachment_flags p {
+    padding-bottom: 0;
+    margin-bottom: 0;
+}
+
+#editFrame, #viewDiffFrame, #viewFrame {
+    height: 400px; 
+    width: 95%;
+    margin-left: 2%;
+}
+
+.viewall_frame {
+    width: 75%;
+    height: 350px;
+}
+
+.details span.bz_private{
+  border-left: 1px solid darkred;
+  padding-left: 0.5em;
+}
+
+.no_javascript .bz_hide, .no_javascript .bz_edit {
+    display: none;
+}
+
+#hidden_obsolete_message {
+   text-align: left; 
+   width: 75%; 
+   margin: 0  auto; 
+   font-weight: bold
+}
+
+#description {
+    resize: vertical;
+}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinsstandardbuglistcss"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/skins/standard/buglist.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/standard/buglist.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/standard/buglist.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -17,7 +17,43 @@
</span><span class="cx">   *
</span><span class="cx">   * Contributor(s): Myk Melez &lt;myk@mozilla.org&gt;
</span><span class="cx">   */
</span><ins>+.bz_query_head {
+  text-align: center;
+}
</ins><span class="cx"> 
</span><ins>+.bz_query_timestamp {
+  font-weight: bold;
+}
+
+.search_description {
+  margin: .5em 0;
+  padding: 0;
+}
+.search_description li {
+  list-style-type: none;
+  display: inline;
+  margin-right: 2em;
+}
+
+.zero_results, .zero_result_links {
+  font-size: 120%;
+  font-weight: bold;
+}
+
+.bz_buglist_header th {
+  text-align: left;
+}
+
+.bz_sort_order_primary,
+.bz_sort_order_secondary {
+    display: inline-block;
+    padding-left: .2em;
+    text-decoration: none;
+}
+.bz_sort_order_primary   { color: black; }
+.bz_sort_order_secondary { color: #777;  }
+
+
</ins><span class="cx"> .bz_id_column {
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -44,14 +80,14 @@
</span><span class="cx"> 
</span><span class="cx"> /* we use a first-child class and not the pseudo-class because IE
</span><span class="cx">  * doesn't support it :-( */
</span><del>-tr.bz_secure td.first-child { 
</del><ins>+tr.bz_secure td.first-child, a.bz_secure { 
</ins><span class="cx">   background-image: url(&quot;../../images/padlock.png&quot;);
</span><span class="cx">   background-position: center left;
</span><span class="cx">   background-repeat: no-repeat;
</span><span class="cx">   background-color: inherit;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-th.first-child, td.first-child {
</del><ins>+th.first-child, td.first-child, a.bz_secure {
</ins><span class="cx">   padding-left: 20px;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -61,6 +97,33 @@
</span><span class="cx"> tr.bz_secure_mode_manual td.first-child {
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+td.bz_estimated_time_column,
+td.bz_remaining_time_column,
+td.bz_actual_time_column,
+td.bz_percentage_complete_column {
+    text-align: right;
+}
+
+td.bz_total_label {
+    font-weight: bold;
+}
+
+td.bz_total {
+    border-top-style: solid;
+    border-top-color: #929bb1;
+    border-top-width: 3px;
+    text-align: right;
+}
+
</ins><span class="cx"> #commit, #action {
</span><span class="cx">   margin-top: .25em;
</span><span class="cx"> }
</span><ins>+
+.bz_query_explain {
+    text-align: left;
+}
+
+.bz_short_desc_column a, .bz_short_short_desc_column a {
+    color: inherit;
+}
+
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinsstandardcreate_attachmentcss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/standard/create_attachment.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/standard/create_attachment.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/standard/create_attachment.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,36 +0,0 @@
</span><del>- /* The contents of this file are subject to the Mozilla Public
-  * License Version 1.1 (the &quot;License&quot;); you may not use this file
-  * except in compliance with the License. You may obtain a copy of
-  * the License at http://www.mozilla.org/MPL/
-  *
-  * Software distributed under the License is distributed on an &quot;AS
-  * IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
-  * implied. See the License for the specific language governing
-  * rights and limitations under the License.
-  *
-  * The Original Code is the Bugzilla Bug Tracking System.
-  *
-  * Contributor(s): Myk Melez &lt;myk@mozilla.org&gt;
-  *                 Joel Peshkin &lt;bugreport@peshkin.net&gt;
-  *                 Erik Stambaugh &lt;erik@dasbistro.com&gt;
-  *                 Marc Schumann &lt;wurblzap@gmail.com&gt;
-  */
-
-table.attachment_entry th {
-    text-align: right;
-    vertical-align: baseline;
-    white-space: nowrap;
-}
-
-table.attachment_entry td {
-    text-align: left;
-    vertical-align: baseline;
-    padding-bottom: 5px;
-}
-
-table#flags th,
-table#flags td {
-    text-align: left;
-    vertical-align: baseline;
-    font-size: small;
-}
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinsstandardduplicatescss"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/skins/standard/duplicates.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/standard/duplicates.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/standard/duplicates.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -10,25 +10,40 @@
</span><span class="cx">  * 
</span><span class="cx">  * The Original Code is the Bugzilla Bug Tracking System.
</span><span class="cx">  * 
</span><del>- * The Initial Developer of the Original Code is Netscape Communications
- * Corporation. Portions created by Netscape are
- * Copyright (C) 1998 Netscape Communications Corporation. All
- * Rights Reserved.
</del><ins>+ * The Initial Developer of the Original Code is Everything Solved, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
</ins><span class="cx">  * 
</span><del>- * Contributor(s): Myk Melez &lt;myk@mozilla.org&gt;
</del><ins>+ * Contributor(s):
+ *   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
</ins><span class="cx">  */
</span><span class="cx"> 
</span><del>-tree#results-tree {
-  margin-right: 0px;
-  border-right-width: 0px;
-  margin-left: 0px;
-  border-left-width: 0px;
</del><ins>+#duplicates_table {
+  border-collapse: collapse;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-treechildren:-moz-tree-cell-text(resolution-FIXED) { 
-  text-decoration: line-through;
</del><ins>+#duplicates_table .resolved {
+  background-color: #d9d9d9; 
+  color: black;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-treecol#id_column { width: 6em; }
-treecol#duplicate_count_column { width: 5em; }
-treecol#duplicate_delta_column { width: 5em; }
</del><ins>+#duplicates_table thead tr {
+  background-color: #ccc;
+  color: black;
+}
+
+#duplicates_table thead tr th {
+  vertical-align: middle;
+}
+
+#duplicates_table td, #duplicates_table th {
+  border: 1px solid black;
+  padding: .1em .25em;
+}
+
+#duplicates_table tbody td {
+  text-align: center;
+}
+#duplicates_table tbody td.short_desc {
+  text-align: left;
+}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinsstandardenter_bugcss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/skins/standard/enter_bug.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/standard/enter_bug.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/skins/standard/enter_bug.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,72 @@
</span><ins>+/* The contents of this file are subject to the Mozilla Public
+  * License Version 1.1 (the &quot;License&quot;); you may not use this file
+  * except in compliance with the License. You may obtain a copy of
+  * the License at http://www.mozilla.org/MPL/
+  *
+  * Software distributed under the License is distributed on an &quot;AS
+  * IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  * implied. See the License for the specific language governing
+  * rights and limitations under the License.
+  *
+  * The Original Code is the Bugzilla Bug Tracking System.
+  *
+  * The Initial Developer of the Original Code is Netscape Communications
+  * Corporation. Portions created by Netscape are Copyright (C) 1998
+  * Netscape Communications Corporation. All Rights Reserved.
+  *
+  * Contributor(s): Byron Jones &lt;bugzilla@glob.com.au&gt;
+  *                 Christian Reis &lt;kiko@async.com.br&gt;
+  *                 Vitaly Harisov &lt;vitaly@rathedg.com&gt;
+  *                 Svetlana Harisova &lt;light@rathedg.com&gt;
+  *                 Marc Schumann &lt;wurblzap@gmail.com&gt;
+  *                 Pascal Held &lt;paheld@gmail.com&gt;
+  *                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  */
+
+/* These are specified using the class instead of the id so that they
+   don't override the YUI CSS. */
+.enter_bug_form table {
+    border-spacing: 0;
+    border-width: 0;
+}
+.enter_bug_form td, .enter_bug_form th { padding: .25em; }
+.enter_bug_form th { text-align: right; }
+
+/* This makes the &quot;component&quot; column as small as possible (since it
+ * contains only fixed-width content) and the Reporter column
+ * as large as possible, which makes the form not jump around
+ * when the Component Description changes size. This works
+ * pretty well on all browsers except IE 8.
+ */
+#Create #field_container_component { width: 1px; }
+#Create #field_container_reporter  { width: 100%; }
+
+#Create .comment {
+    vertical-align: top;
+    overflow: auto;
+    color: green;
+}
+#Create #comp_desc_container td { padding: 0; }
+#Create #comp_desc { height: 11ex; }
+#Create #os_guess_note {
+    padding-top: 0;
+}
+#Create #os_guess_note div {
+    max-width: 35em;
+}
+
+/* Text inputs need to be a little shorter on enter_bug
+ * than the 100% that they are on show_bug.
+ */
+#Create .field_value .text_input { max-width: 50em; }
+
+/* The Possible Duplicates table on enter_bug. */
+#possible_duplicates th {
+    text-align: center; 
+    background: none;
+    border-collapse: collapse;
+}
+/* Make the Add Me to CC button never wrap. */
+#possible_duplicates .yui-dt-col-update_token { white-space: nowrap; }
+
+form#Create #possible_duplicates td { vertical-align: middle; }
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinsstandardglobalcss"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/skins/standard/global.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/standard/global.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/standard/global.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -20,6 +20,7 @@
</span><span class="cx">   *                 Vitaly Harisov &lt;vitaly@rathedg.com&gt;
</span><span class="cx">   *                 Svetlana Harisova &lt;light@rathedg.com&gt;
</span><span class="cx">   *                 Marc Schumann &lt;wurblzap@gmail.com&gt;
</span><ins>+  *                 Pascal Held &lt;paheld@gmail.com&gt;
</ins><span class="cx">   */
</span><span class="cx"> 
</span><span class="cx"> /* global (begin) */
</span><span class="lines">@@ -41,24 +42,36 @@
</span><span class="cx"> /* header (begin) */
</span><span class="cx">     #header {
</span><span class="cx">         margin-bottom: 1em;
</span><del>-        padding-bottom: 2px;
</del><span class="cx">     }
</span><span class="cx"> 
</span><del>-    #header form {
-        font-size: 85%;
</del><ins>+    #header form, #header form input,
+    #footer form, #footer form input
+    {
+        font-size: 95%;
</ins><span class="cx">         display: inline;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     #header .links {
</span><del>-        font-size: 85%;
-        border-left: 1px solid silver;
-        border-right: 1px solid silver;
-        border-bottom: 1px solid silver;
</del><ins>+        border-left: 1px solid #747E93;
+        border-right: 1px solid #747E93;
+        border-bottom: 1px solid #747E93;
</ins><span class="cx">         -moz-border-radius-bottomleft: 5px;
</span><span class="cx">         -moz-border-radius-bottomright: 5px;
</span><span class="cx">         padding: 0.5em;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    #lang_links_container {
+        float: right;
+    }
+    #lang_links_container .links {
+        border: none;
+        padding: .5em;
+    }
+
+    .lang_current {
+        font-weight: bold;
+    }
+
</ins><span class="cx">     #message {
</span><span class="cx">         border: 1px solid red;
</span><span class="cx">         margin: 0.3em 0em;
</span><span class="lines">@@ -66,6 +79,19 @@
</span><span class="cx">         color: green;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    form.mini_login input.bz_login  {
+        width: 10em;
+    }
+    form.mini_login input.bz_password {
+        width: 6em;
+    }
+    form.mini_login input.bz_remember {
+        margin: 0;
+    }
+    .bz_mini_login_help {
+        color: #777;
+    }
+
</ins><span class="cx"> /* header (end)   */
</span><span class="cx"> 
</span><span class="cx"> /* banner (begin) */
</span><span class="lines">@@ -116,46 +142,40 @@
</span><span class="cx"> 
</span><span class="cx"> /* titles (end) */
</span><span class="cx"> 
</span><del>-/* footer (begin) */
</del><ins>+/* footer (begin)
+ * See also the &quot;header&quot; section for styles that apply
+ * to both the header and footer. 
+ */
</ins><span class="cx">     #footer {
</span><span class="cx">         clear: both;
</span><del>-        margin-top: 5px;
</del><ins>+        margin-top: 1em;
</ins><span class="cx">         width: 100%;
</span><span class="cx">         background: #edf2f2;
</span><span class="cx">         border-top: 1px solid #ddd;
</span><span class="cx">         border-bottom: 1px solid #ddd;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    #footer form {
-        display: inline;
-    }
-
-    #footer .btn,
-    #footer .txt {
-        font-size: 80%;
-    }
-
</del><span class="cx">     #footer #useful-links {
</span><del>-        display: table;
</del><span class="cx">         padding-left: 1ex;
</span><span class="cx">         padding-right: 1ex;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    #footer #links-actions,
-    #footer #links-saved,
-    #footer #links-special {
-        display: table-row;
</del><ins>+    #footer ul {
</ins><span class="cx">         list-style-type: none;
</span><span class="cx">     }
</span><ins>+    #links-saved ul {
+        display: inline;
+    }
+    #links-saved th {
+        vertical-align: top;
+    }
</ins><span class="cx"> 
</span><span class="cx">     #footer .label {
</span><del>-        display: table-cell;
</del><span class="cx">         white-space: nowrap;
</span><span class="cx">         vertical-align: top;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     #footer .links {
</span><del>-        display: table-cell;
</del><span class="cx">         vertical-align: top;
</span><span class="cx">     }
</span><span class="cx"> /* footer (end) */
</span><span class="lines">@@ -193,27 +213,36 @@
</span><span class="cx"> /* tabs (end) */
</span><span class="cx"> 
</span><span class="cx"> /* generic (begin) */
</span><del>-    :link {
</del><ins>+    a {
</ins><span class="cx">         color: #039;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    :visited {
</del><ins>+    a:visited {
</ins><span class="cx">         color: #636;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    :link:hover, :visited:hover {
</del><ins>+    a:hover {
</ins><span class="cx">         color: #333;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    :link:active, :link:active {
</del><ins>+    a:active {
</ins><span class="cx">         color: #000;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     .clickable_area {
</span><span class="cx">         cursor: pointer;
</span><span class="cx">     }
</span><ins>+
+    textarea {
+        font-family: monospace;
+    }
</ins><span class="cx"> /* generic (end) */
</span><span class="cx"> 
</span><ins>+/* Links that control whether or not something is visible. */
+a.controller {
+    font-size: 115%;
+}
+
</ins><span class="cx"> div#docslinks {
</span><span class="cx">     float: right;
</span><span class="cx">     border: 1px solid black;
</span><span class="lines">@@ -225,6 +254,18 @@
</span><span class="cx">     margin: 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/**************************/
+/* Bug links and statuses */
+/**************************/
+
+.bz_bug_link {
+    /* Catch-all if you want common styles for all bug links */
+}
+
+.bz_bug_link .bz_status_UNCONFIRMED {
+    font-style: italic;
+}
+
</ins><span class="cx"> .bz_obsolete {
</span><span class="cx">     text-decoration: line-through;
</span><span class="cx"> }
</span><span class="lines">@@ -243,39 +284,82 @@
</span><span class="cx">     color: #a0a0a0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/************/
+/* Comments */
+/************/
+
+.bz_comment_table td {
+    vertical-align: top;
+}
+
</ins><span class="cx"> .bz_comment {
</span><span class="cx">     margin-bottom: 2em;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-/* The rules for these classes make international text wrap correctly,
-   even for languages like Japanese that have no spaces. */
-.bz_comment_text, .uneditable_textarea {
</del><ins>+/* tbody.file pre is for the Diff view of attachments. */
+.bz_comment_text, .uneditable_textarea, tbody.file pre {
</ins><span class="cx">      font-family: monospace;
</span><del>-    /* Note that these must all be on separate lines or they stop
-       working in Konqueror. */
-     white-space: pre-wrap;      /* CSS 3 &amp; 2.1 */
-     white-space: -moz-pre-wrap; /* Gecko */
-     white-space: -pre-wrap;     /* Opera 4-6 */
-     white-space: -o-pre-wrap;   /* Opera 7 */
</del><ins>+     white-space: pre-wrap;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> .bz_comment_text {
</span><span class="cx">      width: 50em;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-.bz_first_comment {
</del><ins>+.bz_comment_user, .bz_comment_time, .bz_comment_number, 
+.bz_private_checkbox, .bz_comment_actions
+{
+    margin: 0 .5em;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+.bz_comment_actions, .bz_comment_number, .bz_private_checkbox {
+    float: right;
+}
+
+.bz_collapse_expand_comments {
+    padding: 0;
+    margin: 0 0 0 1em;
+    list-style-type: none;
+}
+.bz_collapse_expand_comments li {
+    margin-bottom: .5em;
+}
+.bz_collapse_comment {
+    text-decoration: none;
+}
+
+.bz_private_checkbox input { 
+    margin: 0;
+    vertical-align: middle;
+}
+
</ins><span class="cx"> .bz_comment_head, .bz_first_comment_head {
</span><ins>+    padding-top: .1em;
+    padding-bottom: .1em;
+    padding-left: .5em;
</ins><span class="cx">     background-color: #e0e0e0;
</span><span class="cx"> }
</span><ins>+
+.bz_comment_user_images img {
+    vertical-align: bottom;
+}
+
</ins><span class="cx"> .bz_comment_hilite pre {
</span><span class="cx">     background-color: lightgreen;
</span><span class="cx">     margin: 0;
</span><span class="cx">     padding: 1em 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-span.quote {
</del><ins>+/** End Comments **/
+
+.bz_default_hidden, .bz_tui_hidden, .bz_hidden_field, .bz_hidden_option {
+    /* We have !important because we want elements with these classes to always
+     * be hidden, even if there is some CSS that overrides it (we use these
+     * classes inside JavaScript to hide things). */
+    display: none !important;
+}
+
+.bz_comment_text span.quote {
</ins><span class="cx">     color: #65379c;
</span><span class="cx">     /* Make quoted text not wrap. */
</span><span class="cx">     white-space: pre;
</span><span class="lines">@@ -291,10 +375,18 @@
</span><span class="cx">     min-width: 3em;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+input.requestee {
+    width: 15em;
+}
+
</ins><span class="cx"> #error_msg {
</span><span class="cx">     font-size: x-large;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+.warning {
+  color: red;
+}
+
</ins><span class="cx"> .throw_error {
</span><span class="cx">     background-color: #ff0000;
</span><span class="cx">     color: black;
</span><span class="lines">@@ -304,7 +396,7 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> dt {
</span><del>-    font-weight: bolder;
</del><ins>+    font-weight: bold;
</ins><span class="cx"> }
</span><span class="cx"> body &gt; dl &gt; dt {
</span><span class="cx">     border-top: dotted gray thin;
</span><span class="lines">@@ -317,10 +409,15 @@
</span><span class="cx">     white-space: normal !important;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/* Arrow buttons are buttons with only &amp;uarr;, &amp;darr;, &amp;larr; or &amp;rarr; on
+ * them. We want these to look a little less spidery. */
+.arrow_button {
+    font-size: 150%;
+}
+
</ins><span class="cx"> /* Style of the attachment table and time tracking table */
</span><span class="cx"> #attachment_table {
</span><span class="cx">     border-collapse: collapse;
</span><del>-    width: 40em;
</del><span class="cx">     border: 1px solid #333333;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -346,28 +443,6 @@
</span><span class="cx">     padding-left: 1em;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-table.attachment_info th {
-    text-align: right;
-    vertical-align: top;
-}
-
-table.attachment_info td {
-    text-align: left;
-    vertical-align: top;
-}
-
-/* Text displayed when the attachment is not viewable by the web browser */
-#noview {
-    text-align: left;
-    vertical-align: middle;
-}
-
-/* For bug fields */
-.uneditable_textarea {
-    width: 30em;
-    font-size: medium;
-}
-
</del><span class="cx"> div.user_match {
</span><span class="cx">     margin-bottom: 1em;
</span><span class="cx"> }
</span><span class="lines">@@ -390,21 +465,52 @@
</span><span class="cx">         display: none;
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    div.bz_query_buttons {
+        display: none;
+    }
+
</ins><span class="cx">     body {
</span><span class="cx">         background-image: none;
</span><span class="cx">         background-color: #fff;
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+/**************/
+/* Bug Fields */
+/**************/
+
</ins><span class="cx"> .field_label {
</span><span class="cx">     text-align: right;
</span><span class="cx">     vertical-align: top;
</span><span class="cx">     font-weight: bold;
</span><span class="cx"> }
</span><ins>+.field_help_link {
+    cursor: help;
+}
</ins><span class="cx"> .field_value, form#Create th, form#Create td {
</span><span class="cx">     vertical-align: top;
</span><span class="cx"> }
</span><ins>+.field_value .text_input {
+  width: 100%;
+  min-width: 25em;
+}
</ins><span class="cx"> 
</span><ins>+.uneditable_textarea {
+    width: 30em;
+    font-size: medium;
+}
+
+th.required:before {
+    content: &quot;* &quot;;
+}
+th.required:before, span.required_star {
+    color: red;
+}
+input.required, select.required, span.required_explanation {
+    background-color: #fff7cd;
+    color: #000;
+}
+
</ins><span class="cx"> .calendar_button {
</span><span class="cx">     background: transparent url(&quot;global/calendar.png&quot;) no-repeat;
</span><span class="cx">     width: 20px;
</span><span class="lines">@@ -420,15 +526,43 @@
</span><span class="cx">     border: 1px solid #404D6C;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-form#Create th {
-    text-align: right;
</del><ins>+.bug_urls {
+    margin: 0 0 1em 0;
+    padding: 0;
+    list-style-type: none;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-form#Create .comment {
-    vertical-align: top;
</del><ins>+/* custom styles for inline instances of autocomplete input fields */
+.yui-skin-sam .yui-ac-input { position:static !important; 
+                              vertical-align:middle !important; }
+.yui-skin-sam .yui-ac-container { left:0px !important; }
+.yui-skin-sam .yui-ac { display: inline-block; }
+#bugzilla-body .yui-ac-content {
+    max-height: 19em;
</ins><span class="cx">     overflow: auto;
</span><del>-    color: green;
-    margin: 0 0.5em;
-    padding: 0.3em;
-    height: 8ex;
</del><ins>+    overflow-x: hidden;
</ins><span class="cx"> }
</span><ins>+
+#keyword_container {
+    padding-top: .2em;
+}
+
+
+#keyword_container .yui-ac-content {
+    margin-left: -1px;
+}
+
+/*******************/
+/* Form Validation */
+/*******************/
+
+.validation_error_text {
+    font-size: 120%;
+    color: #B70000;
+    font-weight: bold;
+}
+
+.validation_error_field, input.validation_error_field {
+    border: 2px solid #B70000;
+    background-color: #FFEBEB;
+}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinsstandardhelpcss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/standard/help.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/standard/help.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/standard/help.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,41 +0,0 @@
</span><del>-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the &quot;License&quot;); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an &quot;AS IS&quot; basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is the Bugzilla Bug Tracking System.
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Gervase Markham &lt;gerv@gerv.net&gt;
- *
- * ***** END LICENSE BLOCK ***** */
-
-/* Help system */
-#helpDiv {
-    border-style: solid;
-    border-color: #F0A000;
-    background-color: white;
-    padding: 5px;
-    position: absolute;
-    z-index: 2;
-}
-
-#helpIframe {
-    overflow: hidden;
-    position: absolute;
-    z-index: 1;
-    display: none;
-}
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinsstandardindexfileabugpng"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/skins/standard/index/file-a-bug.png (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/standard/index/file-a-bug.png                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/skins/standard/index/file-a-bug.png        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,34 @@
</span><ins>+\x89PNG
+
++IHDR\x91\x91\xC3\xD8Z#tEXtSoftwareAdobe ImageReadyq\xC9e&lt;+pIDATx\xDA\xEC\x9D}P\xE7ÇŸ;\xEExUÞŒD&quot;B\xE4DMHp&amp;\x93\xA0\x89\xA6\x93\xCED\xC1\x82\x84\xA4H\xE9t2\xD5\xA7\x93i\xFBG\x9BI'3}IÓ™N\xC5h\x8D4\x92L@|A+I\xD5$\xA8D Í 
+ĨA9\x90\xB6\xCFs\xEC\xD1\xE5n\xF7^\xBCcw\x9Fg_\xE6\x99=\xEEfwo\xF7\xF9\xEC\xEFm\x9F\xE7V\xC7q\x81\xBC\x91 D uA\xA4\xD3\xE9|\xB2M8\xADT\xC8+\xEB1\x85A\xA44\xBD\xE05H\x9D\xF0\x906.x\xCD)        \x91m\xBD\xA0p\xF3\xE3_\x83\xD4'\xCFn\xA3\xFCr\xFC~@\xF2Dz,F\xBEJKK\xA3
+
+2M&amp;S\xD9vdd\xA4\xC9`0\x84C\xDF)\xA7\xFE\xFE\xFEÖ‘\x91\x91\xFE\xBE\xBE\xBE\xAE\x96\x96\x96\x8B\xC5\xC5\xC5\xCD\xF8\xED\xDC\xEE\xF1KL\xE3\xEE\xBA:o \xBA-[+))\x89\xAD\xA8\xA8x&amp;11q\x86&amp;\xBAM\xE5\xA6h|\xBC\xBF\xB7\xB7\xF7hsssU^^\xDEq\xFC\x96\x85\x87\xC9&quot;\x80\x89\x9B\x88l\xFA\xF1V'\x88\xB4\xEE\xEE\xEE\xCD\xF1\xF1\xF1\xF4z=X
+5&lt;&lt;|\xAA\xA9\xA9\xE9\xF5\xDC\xDCÜ“\xBCe\xB2\\x9D\xA4U\x9A\x92Õ“l\xCD@\xB6x'\xB7\x99+++\x8B\xE5bB\x87\xCA\xCA\xCAL\xB8o\xA3\xF9&gt;6
+\x92$Q\x88&amp;\xB9q&quot;\x9D \xEE!\x8F\xEB\xE8\xE8\xF8#\x9Cv\xF6D\x8C\xC2Þ½{W\xE3&gt;\x8E\xC5-\x9C\xEFs\x97\xB9rgB@\xDCÒ¶\x85\x85\x85\xADG\xC0n\xBCT]]]\x90\x9F\x9F\xFF;È»\xB81{\xB7\xE6ILdK\xDB        @\xA1\xA0\xAD\xAE\xBA\xD4Þê\xB1.\xCF_h\x83^Q\x89BC\x82Т\x8C\xF4XV\xCA\xCD^h\xFD\xDFHUUU\x85EEE_\xF0 \x8D\xD8Ûž@\xE4\xC7g`\xC1\xAD\xAD\xAD%\xA9\xA9\xA9oH\xED\xF8|\xCB%\xB4k_\x80C        Pk\x9F}\xAD\xC1M
+&amp;Ryyyveee\x89\xBF\xF9`\xDBc\x88\xF4&lt;@A\xFB\xF7\xEF\xCFZ\xB3fM\x95TF\xE0Ù‰\x88&gt;\x98^\xFD\xC3\xCFÑ¢\xF4d\xC9\xCC-((\xE8'\xF8\xA5\x99i\xCCS\x88 |:88X\x9C-\xB6\xA3\xBFl݃a\xF75\xC5|\xF9\xF9\xA1\xA8\xC8P\x82\x8C\xD0[j(8\x98\xD1\xED\xBEdv\xF8\xEC\xE5M\xEB\xD1\xD3Of\x89\xAE\x87=\xD0æ´´\xB4\xDD\xF8\xE5\x80\xC0\xAD\xB9\x91\x8E\x87(\xF4\xECÙ³\xCF-^\xBCx\xBB;xfÏŠF\xF1\xB13\xA0\xD7T\xAA{#t\xA5\xB3+ \x98\xA7\xBC\xFF\xEA\xEFˬ\xB1\x92\xBDFGG\xBB\x8CFc~Ù‡Û-6r\xA3wR\x95\xB6M&amp;\xD3\xB1/\xF3\xFEG'\xA6\x88\x98\xE6\xA28 \x90\xF0\xAE4u5#JMIDs\xE2 \xC2\xF5\xBD\xFDl0\x9A\x9B\x9B \x9DÕ\xF4NjC\x86, ̱\xFF\x90\xECl\x97 &quot;\xCDO\x9E\x83\xFC\x8D\x86)\xF5h\xEAm\xB11Qh\xEE\x9CY\x93}xwp\xBD\xBD\xBDZ\x86\x94\x94\x94R&quot;?1\x90\xF4Ϊ\xD3Ë—/_'H\x93\x9D\xDA\X\xF2\xDC\xD9x\xA9\x87Ëœ\xB26sF\x8A\x8C\x9B\xEC\xD7\xCFNm-\xCD\xD8 שo\xBE\xF9f\x91[\x96h\xB2B\xE1Lx\xC8\xCEl\x8A\xC3D\xC1Q\xDB| fJ\xFF\xC4a\x8A\x98V\xADZ\xB5\xDA]\
 x88\x84\xF7\xC8\xFC\xB1+39Ôƒ.\xB4MZ!\xA2\x98\xE8H 5\xFC\xD1\xFAg\xF47`\x8B&gt;\xC5\x89)***M*&amp;2HX&quot;\xBFÇ\xE7\x8Am\xEC\xB2\xC0Ü…\x86#\xBD^\x8F`\x986ÝŠE?\xF4\xF6Oz\xE2\xD2H\x88&quot;6(        R\xEBK\xBA3\x8B\xC5\xE2'U\x99\xB6)\xCCI\xE9DW\xD1\xD1&gt;d\x89\x8BLR\xEB\xBC\xD99gWt\xD1)\xE2M\x84\xBAt\xA5Ë¡\x8A\xEDl\xBC\x98W!\xD7\xE3\x90@jP\xC49\x85\xD0[K\xBC\xDDX&quot;\x90\xDEK\x82\xE0 \x82 \xB0\xA9Â\xC1I\x88\xBC4ErX\xA2\xEC\xA5\xA1\x85 \x92QPP5'\xB6\xAB\xE7\xA6\xE4-\x80Hf\xAD^\x91\x83[6u'6%)\xA0\xDD\xFB\xEB&quot;\xE7\x86h\xFA\xEBD\xA43hU\xB6\xA0\xE4\x{DBAA}\x88\x9CF\xD6Ó®\xFF\xEF\xE4\xF4W'\xEF\xF1\xA8U\xCFK@)\xF3\xB8\xE2\xD6%\xCB \xA9&gt;;n\xFDÔ—Q\xDB\xE5k\xEA&gt;\xA3+\x9D\x91\xA4\xBFw wh\xF2J\xFD\xC9 '\x91,\xB0~\xC2&quot;H\xDE\xD6r\xE6\xF8\xF3\xBE\xA9=\xD99\xC4&quot;q\xA4:\x80H\xA9&gt;\xE5\x90\xFAr\xF5\xFDr\x96N\xB8\xB6] \xCD\xD3\xF3\xBE\xD8(\xA3\x83\xB1\x8DÆ£] q\xCCL\xF8TÅš\x9B\xFAZ\xF5\x96\xC8m\x90Ò­\xC7\xC2H^\x8F'v\xFFWÕ£
 \xCBÒ­Ë{k\xA9\x86H\xF5㉄\xEE\x8Bcp\xE9Å¢\xD5\xC9\xEB.\xD4+w\x9F \x915ß¡\xD4&quot;Qu\x9F\xF2 \xDFH\xD6\xE5\x8E=\xB5Ú‚\x88\x93y\x8C\xB5\xF7ê‚W\x89\xAC\xBEcO\x8D\xB6,\x929;c}`7\xF9%3\xABEz\xB7F;\xC9\xA3pL\xC6DR U\xBE\xFB\x89\xDC\xD9\xF4\xC7(m1\x91\x8F\xBE\x9F+\xA4\xED\xBB\xD5\x92^g\x8C!\xF9\xD2R\x906&lt;\xFFc-dg\xF2E\x9C'K\xE6b\x90\xAE^\xBB\x8E\xFF\x92\xE1\xC0\x83LÑ­\xFA|\xBE\xCD\xE0\xE0@U7\xDC\xC5\xF7\xB1O}\x8D\xE6ÌŽC+\x9FX\xE6\xD3W\xF3qTo\xEC#k
+\xB4\xE7\xFD#\xD6\xE6\x8D~\xF7\xEBb\x94\xFAp\xA2\xB0Ü–\xC9;&lt;VK\x93%9\xD9cO\xA5,'\xB3\xA7\xE64\x9A\xAA\xFC\xB8\xE9\x8B8\xEDN\xB9e\xD6!\xB8         \x85n\xC0*\xAD\xE8\x99\xE8\xF9\x82\xA7\xF84\x98N\x91\xB2\xC0?w~D\xA5\xF2\x91%\x92\xB1\xD8(ryN&amp;zd\xD1|\xCAmM&quot;:\xF9\x9F\xF3\xA8\xF5\xDBN\x89\xE3f9\xB0F\xCAJ\xAB;v\x9Azwe6\xA3o\xBE\xEDP\xD5y\x967\xB0\x963\xD7\xE5\xC4;\xE0\xE0\xC7'\xD8\xCF\xF1Yug\x91\x95\x99!\x8DÖœCF1\x91\xCF\xD23-\xFE2\x9Bb&quot;\x99O&amp;Ò¦\x98-6\xCA}\x85p\xFE\xDDl\xA6o{(\xAD\x98\x99\x91\xE8\x85\xC2U(\x84\xE2:\xD1\xCD[}\xE8;&gt;\xA06\xC8V\xFF@}\xFB[\xBA8\xD5Ú¨\xD6|\x84j\x8F\x9CBW\xAFS        \x92~\x9FH\xD9:щ\xCF\xCFQ]\xAD&amp;4\xA3\xF6\xABß¹8ˬJ\x93\xC1W \xB7/\x91'\xE2\xEC\xFF\xB0\x81\xF9H\xCD1\x91\x81@J\xD6p\x8E\x9B\xB2)CP%b2&amp;\x82\x91\xFA2\x9A#VS|\xA5+Ö±\xD1Q\xE8g\xEBWS]'\xBAq\xABm\xFB\xD7Ajm\xF5\xC5Æ¥KRѲ%&amp;\xAA\x8D \xF9\xC7O\xEA?\x97\xACq,\xE5I\xF1\x91\xD3\xFFx\xE3Yl\x85\xE8~\xA0\xF1\xA0y\xB5w~\xE7\xC6XO_hpwp\x
 BDW} B&quot;z!R⾺ku\x8F_\x80b#H\xF9\xC0~D\x8E\xE3f8&amp;\x92\xBBl\xC3\xC1\xDCEVc&quot;e\xE3\xA1ؘ(\xB4\xE9k\xE9\xCE\xCEpr\xF0Ú–\xDDN\x8E\x9A\xF5yg
+\xC9z$+\xA5\x9B\x92\xA8\xB74%\xCE\xC2i~\x95 Q_l&lt;\xF6i\xD5\xD5j\xAB%&quot;㉜\x84X/6N\xFB\x94!\xCE\xEE5g\xEF
+\x86о\x83GÙ\x81`Ê\x9D \xD4g1Ň\xECL\xEB\xC7+\xC5F\x90\xD21'\xF3\x93\xD9|\\x95\xBBg\x9AÙ˜Ht\xA4\xA3˸\x98(\xF4\x9B_\xAE\xA3\x91\xBB\xE6!\xF4\xE7\xBF\xEF\xA2+%\xF3)D
+\x8Fl$\x8F
+\xCFH\xA3\xBFN\x94\x948 ]\xE9\xE8Q\xC7yf9\xB0;\x97GO|e\xFD!!\xF4\x8E)\xFA\xFEf/\xBA\xDC\xDECm`m\xA0\xFD
+&amp;\xF3\xCE&gt;\xACm\x84\xE8kw#&quot;N3\x815GQ`+)&gt;Hyw&amp;\xE3p&quot;m9\xA7\xF9C\x96w\xA6\x84o\x83\xDF\xEB}\xD9\xED/.v\xDA\xFC\xD2O\xA9f\x84\xDCD~\xE5\xAF\xEF\xA8\xE7&lt;\xCBX+?y1gi:Z\xB8`\xF5\xC6&amp;\xE9\xA1\xD0\xE5\x8E*\x8D\xF5)\xFE\x91O$ \xA5\xB8Nt\x9DÔ‰\x9C\xD9\xAC\x95\xBF&gt;H\x9D胚O\x89\xE0\xB1 &gt;\xF5g0\x9E\x88\xB1\xEC\x8C\xE3\xE4\xBD
+\xB5t\x9F\xB3\xCF\xF1\xC1i\xE3\x8AK\xA4\xDEK\x92\x9A+rÚŽ\x9B\xED\xC0)&gt;\xF5\x8CÔ‰~\xFB\xABB\xAAy!u\xA2\xBF\xBD\xB5Ïš$\xD0\xF5)\xFEcY(3=\x99z\xC3WU\x8F\xEE\xB6wk5\xC5\xD7)\x9A\xEA\xD67\x9C\xB1\xBEOs\x9D\xE8\xFBd&lt;Q\xB7\x86S|\x85g\xC0P\xFD\xF1Imek\x90\xE2k#\xD8\xD4\xD2q\xD3\xF54j\xBF
+)&gt;\x88IQUl|\xEA\x89eLdbnek\xB13\xEC,0\xCC;\xF3D \xE6\xEB\xE9\xBF:`\xF0\xA4\xFAAÕ»\xB3KW\xBA4\xCF\xD0\xF5\xBD\xE0μ\xD1\xDBÛ«\xC1\xB1\xEC\xCE@ \x80\x81\xA6G\x9E\xFE\xAE@rPrR\x82\xC3{\xE3\xE3\xE3\xFD\x9E@DÒ€q\xA3\xD18&amp;\xB6\xC2&quot;\x8D\xFB\xB4,\xB1CCC\xAD\x9EB4\xB6r\xE5\xCA\xCF\xC4V\x987w6\x9Ce\xC6J\xE9\xE3\xE1\xE1\xE1.w!\xB2Z!\xDCFq\xC1+:з(#\x85\xEA\xB1; \xE7\xCA\xCD^(\xFA\xFE\xEDÛ·\xBF\xE1\xD9\xE0\xDCvg\xB8Y\xEEܹsZ\x8CT\xA9\x81\xE8ךg}\xBF\xAE\xAE\xAE\x96x(O!mll\xAC\xDB\xE0 \x85\xAB\xC01j\x85\xC4\\x8E\x87\xFE\xBBq\xE3\xC6+\x9E@di4??\xFFvi\xA7\xEC?\x8C\x8F\x9Da        \xC4V,\xF4R\xD9s\xA2\x9F\xB5\xB5\xB5\xED \x9E\x89\x87\xC8\xC1\xA5IY&quot;\x8E_\xC1\xD2\xDA\xDAZ)\xB6\xE1\xB5\xD8\xEC=\xFDd\x9C}F\xF4\xF2\xA6\xF5V\xE3`\xAF\xD1\xD1Ñ®\xCC\xCC\xCC}&lt;Dn\xC7DB\x90F\x97,YRk6\x9BOK\xED@b \xA98[\xA1-xq\x8FO\xB68O B\xB6\xE0\x9Adw555\xAFH\x9B\xC8x\\xB5.l\xCBk%+        e\xD2\xD2\xD2ȃ\xD8\xCCK\xE4 \x9Dp\x88\x81N\xE70\xFD\xC77Ü‚\xB1[+IMM}C\xEA ]j\xEF\x
 B6\xDEq?\xA1+z\x87xH8B21\xA9\x89\x8D\xF2\xF2\xF2\xEC\xCA\xCAJRX\xA2        W%\xE4\xC6Dz\xBE\x90}\xF7\xF7\xF7o+ s\xFA\xF3\xF5\xA6\xFAcg\xACKJ]\xE0\x90\x99\xECI\\x97\xB3\xEC\x9ATUUUXTT\xF4\xFEw\xB7\xFBx\xC8\x88t\x8BD@
+\xC2 ms\x88^\x80\xAA\xAB\xAB Hf\xCEtO,\xB5r\xE3\xEA,'\x88\x8F\x8DC\xE1\xE1\xE1\x9B:;;\xFF\xA7\x9B=\x91L\x8CX \xA0a\xBE\xCFEkCÈž(7\xAE\xE3\x81##!Cp\x9B\xD9\xD0\xD0P`\xB1X\xAEq &amp;400p\xA8\xAC\xACÌ„\xFB6\x9A\xEFc#\xDF\xE7:WܸrgR\xAE\x8D\xEC\x808Õ \xEE\xEE\xEE\xCD\xF1\xF1\xF1\xF4z}8\\xCB\xF4\x89d`MMM\xAF\xE7\xE6\xE6\x9E\xE4]\x97\x85\xA2\xC7\xEC\xBC\x92rg\x9E@d\xC9\xD6\xFCm\xAD\xA4\xA4$\xB6\xA2\xA2\xE2\x99\xC4\xC4\xC4\x91\x91\x91y\xD05\xEA\x8F{z{{\x8F677W\xE5\xE5\xE5\xE7\xC1\xA4\xF1\xE3\xAE\\x987\xD9gn~\xFC\xD2\xC87CiiitAAA\xA6\xC9d\xCA!\xDB\xC6P\x99 X)\x85\x93\xA1Ö‘\x91\x91\xFE\xBE\xBE\xBE\xAE\x96\x96\x96\x8B\xC5\xC5\xC5\xCD&lt;4\xF7qϸ\xA0\xE4rj\x89\xAF \xBA8\xBD\xA0p\x81Th\x88xhF\xD1\xD4{a\xCDI\xF2%DbnN/x+R\x9Fl\xC0\xE1\xF1xR\xDBt@$f\x9D@\xEA\x87\xE9\xFEW\x96\x82\xBA/\xAB\x81&quot;\x90\xE2\xFA\x9F\x86\xE73\xA3 K\xE2\x9BIEND\xAEB`\x82
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinsstandardindexfrontpng"></a>
<div class="binary"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/standard/index/front.png</h4>
<pre class="diff"><span>
<span class="cx">(Binary files differ)
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinsstandardindexhelppng"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/skins/standard/index/help.png (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/standard/index/help.png                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/skins/standard/index/help.png        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,37 @@
</span><ins>+\x89PNG
+
++IHDR\x91\x91\xC3\xD8Z#tEXtSoftwareAdobe ImageReadyq\xC9e&lt;\xB1IDATx\xDA\xEC\x9DP\xD7\xC7wx\xFC\x91 \x8A\x82\x82&quot;\x8A\xA2\x89&amp;\xA2\xD8ØŠ\x8AZ\x933EId\x8A\xD3\xF8\xA7\x93'q\xA6\xEDĤ\x9DNk\xA7\x9A\xB1\xA1q\xD2\xC4Nb\xAABÔ¨@\x8C\xA2\x95AAHE\xA3DO\x85\x83\xBB\xE5\xFA\xDEv\x8FY`\xEEnv\xDF\xEE\xFB2\xBF\xB9;\xEEnwy\xEF\xC3\xEF\xCFÛ·o56\x9B+\xA8\xA8\x84HK\x9B\x80\x8ABD%\xB9t\xDC\x8DF\x8Cmjh\xB3!Ay 7+Ò‰t@\x8Ei9Ï©\xE4        \xB6n\xCEsA@\xE9D\x80\xC7톷\xE9AC\xA5l\x85\xE1y\x84\xEC!\xFB\xD8-\xD43        \x81HËÅ“5\xBC=\xAF\xA2\xA2\xA2\xB1\xB1\xB1        \xD8\xE5\xC4\xEAt:\xDAw\xD2\xC9b\xB1\xDC2\x99L7\xADVkkYYYiFFF%\xFAu'2+\xFBh\x87\xC9-\xA04\xDC\xD8\xE6DN\xC4+[^\xD3WTT\xA4EDD,F\xD0$\xD1n\x93\xB9+\xEA\xEEn5\x8DG+++ó’’’\x8E\xA3_u\xB10uq`\xB29\x9B\xB9\x91\xFDM\xD6\xEBxc\xAB\xAF\xAF_\x8B\xE0Ù¤\xD5j\xA9\xB7!\xD3K\x95\x96\x97\x97oOLL&lt;\xC9z\xA6.N\xA8s\xE8\x95z\x8D/\xE2v {\xBE\xE3\x8B,(???@\xB5\x8DJjkk+\xCA\xCAÊŠE};\x9A\xEDcON\x91\
 xC4 Q7N@\xA4\xE1\xE4=x㆚\x9A\x9AM\xB4Ù•\xA7G\x8F=Ø·o\xDFr\xD4\xC7!\xC8\xFC\x89Ë3\xE1LÆ\xB08|\xB5\xB6\xB6\xE6\x8C92\x95\xE5\xE6Kuuu[cbbr\xD1K\xE2\xB8I\xB7\xCB9 ß¦\xA6\xA67 \xC3\xE6\x81\xA2\xE9\xB6
+\x9C\x80\xBAk\xB7\xA0\xE2\xD2\xDA+2\x91\x9F\xAF7Ìœ&gt;        \xE2\xE3\xA2!y\xD1S\xCC\xEB\x81T\\\x9C\x96\x9C\x9C| =mg\x93\xEE\x87\xDC\xFC\xC8\x88z\xC2Xmm\xED+\x88\xCE\x8Ev\x8A\xA1\xF9\xFB\x87\x9FSpiC\xD6\xF3a\xC2iÇŽ\xCB^\xFD\xF5Z\xF4\xD2\xCC\xF1H.A\xA4ai}NN\xCE\xD4u\xEBÖ•8\xAA\xC0&gt;\xCE=!\xA3&quot;\xCF;my\xEDEH\x9C;\x83\xF7}\xAB\xD5zY\xAF\xD7/a\xC3Z\xD79 \x91=\x8C\xF9\x98\xCD\xE6hc        |;Ú¶s/}}\xAE\xD7\xEF&lt;&lt;&lt;`T\x80\xF8\xFB\xF9ˆ\x9E\xB4\xB7d\xA0\xF6 \xB4\x99:\xE0\xDE\xFD\xB6~\xEFa\x90\xB0g\xE2S}}\xFD\xA2\xDECO\xB0a\xAD\xDBY\x88ì¹Ï™3g\x92
+\x9ChlX0BF\x81\xCEÃ\xF6\x9C e\xED\xEC\x827\x9B\xFB\xC1\xE4$\xD6233\xE7\xEDÙ³\xA7\x81+k\xDD\xFFg\xC89\x88\xF0H\xB4?\xF2B\xFB\xF9\xBC\x86C\xC4\xF5&gt;S&amp;\x8D=\xED)t\xE7\xEE}\xB8\xD6\xD0\xD8+\xB4}\xB0s \x84\x86\xF6\xFB\xEC\x8D7\xFE\xF1Ö˜S$\n\xB4\x8D \xA1\xC4*\x9A S\xBB\x99I\xA2\xB9\xC5D\x8Fo\xEF\xBD\xC6\xA8\xC9ׂ\x83        \xE3\xC3z\xF5)\xD7)p\xB6\x8A-\xB0&lt;\xF8Æ\x82H\xB7r\xE5\xCAe|\xC5%&lt;Þ©]\xD1Æ‚\xA8\xD7\xC4j\xB27 Ò˜\xD0\xD1=\xFD\x88+늪\xBA~\xFD\xED\xE9\xE99\xB6\xB0\xB0p&amp; Q\xBF^7\x90'
+++]\xCA\xD1g&quot;\xBB\xF0\x81`WH\xE7j\x93\xA90C\xDC1&gt;\x80\xCEή13.\xBA\xDF\xE7\x9Ex\xE2        &lt;\x92}\xD6\x88\xB8\xE7ȼ\xFC\xFC\xFC\x9E\xEC\xFBL*\xD7 \x8F@PS\x80HV\xD0(hl\xBE\xCB&lt;?}\xF6&quot;\xEFg炃S \x8E&lt;\x91Ƕm\xDB&quot;\xF96V\xC9L\xF4\xF2\xF2o=΃hG\x90\xAC\xC7\xFC\xFDz \xB2;\x8A\xBE\xDE\xC8\xCB\xCB+\xDC\xD1\xF7\xE6Dqqq|_\xC0\xA75z6ì©£=\xA0ႨWs\x80\xE2\xE6E\x8E\xBE\xEF2\\x88\xFC\xFC|h.\xA4\x90PD1[\xAC\xCC\xF3fN;#a\xAEd\xF0yHT\x84\xC8\xC3\xC3\xFD)\xF1\x82&amp;\xD3S|\xA8\x84{&quot;ꉨ^\xD6CR\x8C\x84\xF4\xA4N莩'\xA2\x89\xCEh\xFBÓœH \xBDJ\xF2Dx\xBC$|LpO\xC9&gt;&amp;\xCCf \xDCll\xE9\xF9\xCC\xCD[\xD0\xEF\xAC\xD4\x89\xE9\x89HÖ¤\xA8p\x984q\xF3\xDCo\xD0m ]\xA9\xBF\xC9u\xEB\xC7\xDBPY}U\xA1`+KND\xDE8Q\xFC\xB4h\x98\xC5&lt;\xBAM?'\x863\x86\x95\xC1z\xA8㧾C@Õ©(\xC1ገ0\x85B\xD3\xDC9\xD3\xE0\xA7 gN6\x85p|)u)\xBC`^È€t\xA8\xA4\x8C\xF7Ziu\xA6\x84\xEA\xECg\x9CK\xE6        \xF2:\xAE\xE6UsgOc\xEC\xF2L\x87J\xCE(\xDE3\xE9\x84\xF2+W\x84&amp;G\x
 8D\x83\x97W'\x99\xE7q\xE0\xD3\xC7yEP\xC93Ù‹\x96\xF82\xAE\xF1\xBEt\xE3}\xE4R\xF1\xBD\xBA\xE6Y(-\xAB\x86O\xF7S\xA4W\xD2        \xE5GN \xE1[\x93\xB6\x8C\xB9\xCASnJ@9\xD98\x947m/O\xA6 \xB9ß‘Zá»–Ç\xB7\xB7d\xAFO\x95%@=\xC9\xF7\xD8\xF8\xDD\xE6\x97\xD1c\xB0l\xDA\xCD\xFE#D\xC2!\xB2Io\xB8\xFA\xCA^\xBFÆ+\x91\xBD\xEB\xC7s\xD2\xD7e&gt;\xD73#T6&amp;D2i\xC2H\x88 \xD2\xE6+\xAB\xC1G?B&gt;I\x91Ò¡\x95\xC9\xF3\x99\xD5.H\x86~e\xF2&lt;P\x82\x88Ή\xFD\x88HÕ¢\xA7g\xC3\xE4\xE8q\xF2ȉlRB$\xA1NMYD\xFCqf\xFArÒ£\x99\xC0p&amp;\xE5e\xC0\xA3\xFCa\x81a\x8C/?zyS\xA9/\xAB\x964\x9CIu        p\xD2\xC29\x8A\xACc\xFE\xA9/\xABVcN\x83r        \xA5\xAFc0\xEF\xA9\xE9ÄŽ         g\x8D y\xEBa|\xB8AQ\xA7\xE6c\x88Ô˜IU\xE4\x8F'hL\xC8Y1k;+\xD3L\xB1\xBB\x92\xC8K\x86\x86r\x9Fx\xB1\xDA++\xD0\xD1\xE7\xFC\xD6\xE33&amp;\xB9\xF7\x9B\x85\xF6\xE1hA9K')\xC2\xEE\xFE\xD7N\x8E}\x9B\x9C?9w\xEE&gt;\xE0}\xFF\x8BC\xDF\xC0\xE8\xA0\xC7 }\xD5x&lt;~\xF2\xD0x\xD8\xF0 \xF1\x92P&quot;\xCF\xE2\xE3E,\xC5\xD4\xDEϾ\x82\x92c\xE7
 \xFD\Ë\xB0\xF3\xFDO\x99\xD5V×¾\xBCr 2y\xF5 \x919Ñ\x9AD\xDB\xD6{:W8\xE4&quot;\xCF4\x98\x919=\xB6\xE1\x87fq&lt;Ч%p\xAA\xB4Ò­\xEF~\xF9+,\x98Ï„8\xF1J}=\x91\x97`i\x85\xE2+ŸX\xBB\xD9\xE5\x95\xDF :t O\xF2@B\x8E\xE3\xF3/O\x89G\x90f\xACQ\xC2IiR+l
+\xE8\xC0T\x81\xFD y!\xA1\xC7P\xF3\xDF\xD1!\xFA\xFF\xAA*\x9A
+&quot;!Cp\xFD!\xBFÄ­P\xF8\xC7\xED{\xA0\xBD\xDD&quot;\xF8Z\xEE\xDC&quot;\xBD^\x86\xA4:\x8B/u\xFC\xC6 \xB2\xF7]\xD1`\x80\x9A@C\x87\xC8Õ\x98j\xB9{H\xF1\xEB}\x92W \x97\xBF\xBF\xCE\80 pO\x8A
+P\xC48\xF1\xAB)\xA9\xDA\xD3&amp;)D2\x{3DA25B1}\xD93\xA7\xA0\x8E+\xED\xE9\\xBA\xF0v+\x82l(\xFE\xC3Ç£}\x89ß™*l\x94\x9B\xEC0+\x97\x969\xB83\x8F\x9AB\x99\xF0q&quot;\xA1\x97        \xACeIs\xAF'*D8Q\xB7\xA9 &quot;9\xE4DR\xE8\xE9\xF93\x99Ll\xE1ÄŸ\xC4\xF6!'R\x8F\xF0-(^IM\x86Ù³\xA6 \xC9\xF6q\x81@b{\xD25\x9D\xD0ÍœY\xB1\x8CJU\xD7^\x93\xAE=mR\xAD\x94\xA6@~&quot;qu7&gt;=\x86A$z\x9C9,\xFB\xBD\x8EBY\xBB\x8Cǯ\x86\xB6:SHS\xA7D\xC2\xF2\xC5         0\xBE\xDD9\xF2pI)\xB1m)\xC2\xFADdS\xB4\xFE\x97)\xB0p\xFE,I\x8F{\xA0\xB2 5\x92\xB6%])\xCDM\xADI_.9@\x8C\xFA\xAA\xB4\xD7=\xE4H\x93T*\i\xADX\x9C \xF9q`/\x84\x97\xE4#Y&quot;\xACcMj\xC5+\x8B\xE3\xC07d6\xB5[\x88\x86\x88\xC8\xE9\xB1bhÚ”        \x92É\xD3\xE0\xFCw5\xF2h\xA9.\xB2        _\x90RRUa=%\xFD\x8DF\xC8\xF9\xA0@\xA9\xB1\x96\xA07\xFF\xB4[1mG\x87Yx\xD5\xFD\xEE;,\xBB\x89q6\xA9\xEE\xEDAr\x89?܇\x8D\xAB\xB0\xBC¯\xE1\xCB\xE23\x8A\xFBÇ \xB7\xAAU\xD5\\x83w\xFFQ\xB7\xEF\xDCS\xE4\xDF'xÄš\xC64\xC7:W~\x99\xF1&lt;U5\xF5\x8A\xFE;\xE9\x8D\xEDE\xF66
 &lt;Eg\xEByDO\xAC\xC9=\xEDa+\x9Ak+\x8D\x8C\xB7\xC1\x86\x9F\xABM&quot;$\xD6\xEA\xF6&lt;Ǿ\xF9r \x8E\x92\xFF\x87H\xB7z,͇l
+i\xD5_2$\xA5\x98+iU\xDEZ\xC9\xF0\x95Xb\x9D\xF4\xBC\xD6\xF0\xA3꽱\xF0\xDB2\xD8\xC84\xB1:\x9F\x99d\xF2MʻQ\x93Z\x9D\x9D-\xAB\x86\xB4UI\xC2*\xB3\x96{P\x9Dz&quot;\xD5\xCE'\xBA\x8A:\xFF\xD2\xE5z\x98&gt;u\xA2\xDB\xDB8z\xB2\x9C\x8E؃\x8Ag6b\xE1\xA5\xF6\xDCU=
+\x87\xFB\x8F\x9C\xA6        Ï‰\xC8\xFE\xB9z\xFD\xBC\xB3+\xDF\xF5\x8A\xAC\xC3\xCC|\xCF\xD4\xDEA|\x88q\xE7EÕŸ\xF68z\xF2[hn1¦u\xA9`5\xE8\xE7/]\xBE\xCA\xD4Ü¢\xB0S\xF4n\xD4\xC2t\xA9\xFA*\xFCz\xCB;\x90\xF4\xF4l憿ӧF\xF5 2\xC3E\x94?\xED?|\x8A\x81\x88\x8A&amp;\xD6\xFC\xA5\xBA\xC9 _:Ř%\xDD=`\xA9\xA8@\xF0        X\x9B\xEA\x87\xFC\xA9\xA8'\xA2\x92&lt;'eN\xF1\xF3\x{146251}cz^_\xAC\xA6\xC9\xF4\x90&amp;\xD6J\xE7\xB9 `\xF1\xC29\xBC\xA5~iY\x9C9_+_\x9D(\xA3\xA95-\xF1\xFBkÞ“q\xB0y\xC3j\xF0E 9RÂœ8\xC6Rh\xDBsr\x99\xD3&amp;T&quot;\xE4DJ8y\xFD\xAB\xCCg\xE1\xCD72\x88+\xE6\xFE\xF2\xF6z\xE6Ѧ\x906\xB0I        \xE9JY\xF1\xC6\\x83\xC5É›\xA8'RaR\x84xy!!9\xD4\xE6\x8Di\xCAɈ\xD4vX1\xF4j\xE6s\xA2\x80\xB8x\xE1l(9\xAE\xD4d{8r&quot;B\xEE\xFCÓ¢D\xD9\xD6K\xBFX
+j\x97*=ÑŒiÑ¢m\xCB!\xC1\xA3\xA0\xF9\xB6\x91z&quot;5)&gt;.J\xD4\xED\x85\xD2p&amp;8\xB7&amp;\xCC|}\xBCEmĨ        cU]\xE3\xD3sg&quot;\x88\xE4\x95_i\x89瑩^\xBB%\xEA\xF6\x9Anߥ\x89\xB50\x8C\xC8        Ï­J5O\x89Qe\x89\xFA\xEC%Ѷ\xF5\x9Fs\x97h8^\xE2\x93g\xB8\xD3\xF1\xFD`\xC5\xDE\x89m \xE2\xCDÕ›X\xEF\xF9w\x91`R|\xEC&lt;TVÕ©\xBE\xB0\xC1Ùˆ\xB46Sd\xFF\xF6]\xB7A\xAACy^+\x9FÔ¿\x9FϨ'rw@\xC2\xDEG\x80\xD4\xF5\xF1BJ)}\xED\xDBP\xFC\xF59\xA7ƃ\xB0\xF7\xD9D\xB9\xC4WH8\xB4\xFDy\xE7^\xF8(\xF7$Î\xF3\x91\xF5j\xBE\xCBx\x9F\xD3g/Rx\x86&quot;%\xA9\xE9\xB6&gt;;p\x821*\x9AQQ\x88\xA8(DT\xA2\x81H[M\xE12\xB8\xD8\xC7|\xE1r\xAB\xBB\xAA\xAA\xAA\x81B\xA4N\x85\x82\xFA\xFD\xAE\xAB\xABë–«=Ú²e\xCBu\xBE/\xC4O\x9FD[Y\xE1\x9A\xD7\xFApgg\xE7Mg!b\xBC\xB2\x87\xF8{&amp;\x93\xE9&lt;\xDF\xFC|\xBDiK+T\x89}\xC6\xC8\xEC2\x8DgY6lN\x873\xEC\xC1\x9A\x9A\x9A\x8A\xF96\xF8\xC23 ik+T\xAB\xF4myy\xF9a\xA1\\x85\xE8\xE1\xC1\x83\x8F8\xDA\xF5F
+ c(U\xE1 e8JII\xA9p\xA2\xAE\xEC\xEC\xEC:\x8B\xC5R\xDA\xF7\xA0+Y\xCF\xD3VW\x90p\x9Fny\xEDE\xDE\xF7\xF1m\xB3\xBBX\x88\xFA\x85\xB4\x81J|\xFC\xEB\x85 \xFE\xCA\xF7f\xF2\xA2\xA7\xA3R\x86\xB0Sૼ\xBB\xBB\xBB[\xB7n\xDD\xFA&gt; oN\xA4\xE1\x9E@\xD5h4\xDC\xF7&lt;\x90\x8D@\xE6c6\x9B\xE8\xF5\xFA\xBE\x9DoÛ¹\x8A\x9C8N%_a\xE4\xC8!444\xBC\xF9zÚ†\x8B-\xA4^'\xDE\xF2D\xDD,}\xD6Ý»wo\xC2D::\x805i\xCBhO\xC2\xFE\xF0\x9B,\x87\xA1\xB2\xBE\x9A\xA8\x83\xE3\x89\xC0Od\x87\xCC\x99omm\xED+111;\x90}\xA6_Å¥+\xB4w\x870Gv\xBBv\xEDZ\xB2q\xE3\xC6\xCB\xE8%\xBE\xAF\xD7Cn(\xEB\xC5\xCD i8a\xCD\x95\xFCo \x86\xCD\x9ENQp\xE0J^^W_\xF1\xA8\xFA\xC2+V]\xE7\xE6\xE6\xAEHOO\xC7\xE3\x84\xED\x9C0\xE6D}A\xF2nmm\xCD9rd*\xEDe
+{\xA0\xBA\xBA\xBA\xAD(\xEA\xECc\xB2\xF2\x95\xF6\xCE\xE6D}\xF3#L\xA3\xD9\xDF\xDF\xFF5Ú²is+\xA0\xBC\xBC\xBC4  \xDB\xE7\xBCcCЗ('f\xFBkX\xE0\xF0LH_dA\xF9\xF9\xF9\xC9\x8B\xA5\xDAF\xA5\xB5\xB5\xB5eeeÅ¢\xBE\xCD\xF6\xB1'\xDB\xE7\x9A\xC1\xB8q&amp;\x9CqA\xB2\x97\xFEx8\xA8z\xD7\xD7ׯ\x8D\x88\x88ؤ\xD5j\xFD\xE9\xFF2yƒ\xC9\xE5\xE5\xE5\xDBO\xB2\xA1\xAB\x8BM\xA2\xD9yq\x91+9Q_\x90\xEC\xE6\xC51}EEE\x82iq@@@\xED\xF9\x87-\xA3\xD1x\xB4\xB2\xB22/))\xE98 N'\xA7\x8C\xEF,\x84        \x81\xA8o\xF9\xEF\xC1\xF0dÃWQQÑ‚\xD8\xD8\xD8\xBCmU\xACN\xA7\xA3^JZos\xCBd2Ý´Z\xAD\xADeee\xA5\x95,4VN\xDE\xD3\xCD\xF4\xB1 \xE2\x868-\xC7t\xB8\xA8d\xE8\x88XhB\xEFsa.]\xFB\xC5\xE5F\xE8%C6Î\xD984k%dT\x92\xCB\xC6\xE9+Q\xD6JÓ‰|`\x86Æ©d        \x93(\xD2\xD8\xE8=\xB9\xA9\x8A\xE6-T&quot;*\xE9\xF5?\xCA\xF7J\xAC\x8E!\xEFIEND\xAEB`\x82
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinsstandardindexnewaccountpng"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/skins/standard/index/new-account.png (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/standard/index/new-account.png                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/skins/standard/index/new-account.png        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,31 @@
</span><ins>+\x89PNG
+
++IHDR\x91\x91\xC3\xD8Z#tEXtSoftwareAdobe ImageReadyq\xC9e&lt;\x94IDATx\xDA\xEC\x9DTTU\xC7\xEF \xFFf`\xF8/\x82\x82        2+h\x82柰MÅ´\x95\xB4S\x92\xD1\xC6\xE6F\xBBuN[\xBBv:\xB9k\xFF\xDC\xF6h\xB6\xDBq];\x8A6K\xB3\x93Z\xF4WV\xB4 \xA1\xA0\xA5\xC2+\xF3O\xCA\x98\xBD\xBF\xE7{\xD3xo\x98a\xDE}o\xEE\xD7s\x9D70\xBC\xF7\xE6\xDE\xCF\xFB\xFE~\xF7\xDE\xF7Ge2\x99\x95=R\xD3*\xA0\xA2QI.w\xFE\x95Je\xEF\xFAT\xB4Je!\xBBs~\xE4\xEE\x80RñŠš·LE&amp;&lt;Px\xCBv\xE5\xEE \x807v}n4L+\x80\xA7\x97&gt;v\x99+v\xB9\x93\xFB(\xC1\xE1\xF2)O\\xBC\xE0uÏž=\xC9z\xBD&gt;1   B\xA7\xD3Eh4\x9Ap\xDAvÒ©\xAF\xAF\xAF\xAD\xB5\xB5\xD5\xA9\x8A\xD1h,7 \xC7\xF0\x8F{X\x90z\xD9\xC2\xC150*'\xE1\xC76r&quot;\x8F\xD2\xD2Ò…\xC9\xC9\xC99AAA\x8B\xD4j\xB5m:\xB2\x85\xA1*mll\xFC0%%e~\xDB\xC5B\xC5\x9BÂœ76B\xC4\xFD\x82 Y\x90WYY\xD9\xFC\xD4\xD4\xD4DZۤӦ\x91alhkii\xD9\xFE2~\xDBÉ–^Ö•\xAC\x868\x8B\xF1ExÕa\xDC\xC0\xF1\xC1e\^^^B{{\xFB\x95&quot;\xD4\xD5\xD5USRRb\xC0m̶\xB1;\xA
 F\x93$
+\x91\x99!\x80 L\x8D/**Z\xD2\xDF\xDF\x95V\xBD\xF2\x84s\xA6\xC7p\x87\xB2 yX\x89\xCF\xCDp\xE1Lņ0H\x9A}***\x96\xE2\xDCg+\xCD{\x94+a\x8A\xFD\xFC\xFC
+\xD8\xD0\xD6͆6\xD3hlj\xF8aL\x8B(m8\x80\xAE]\xEFDG&gt;:\x89\xAA\xAA\xEBQ\xE57g\x99\xF7Td(ez\x8A\x9D\x8E\xB22of^\xC5\xE4\xEB\xEB\x9Bs\xF9\xF2\xE5\xB6\xE0\xE0\xE0\xA7\xD9\x89\x82dKb\xADb!\xD3lÛ¶mZ~~\xFEb,\xBB\xF7Fo\xBD\xFB)m-\x99\xF5H\xDEJ\xAB0\xD5\xD5\xD5\xC6\xC7\xC7\xEFÆ‹\xD7y\xC3#\xEE\x9DA\xD3\xE0\xE2\xDD\xDD\xDD\xFD\x89\xA7\xA7g\xA2\xD0\xC6*\xB1\xEB&lt;\xF3\xFC\xD4ud\xA8\xDC5\x8B\xD1:\\xC4zn;v츽\xA0\xA0\xE0[v\xA0\x8F\xEFF\xB6@\xA4fÇ€|6DEEm\xDA\x84\xAE-\xAF\xEE\xF2so\xAD\xF8&quot;?_o\xDAR\xA8\xBB\xBButv\xA1\x9F[\xDBQwO\xAF\xC5\xEF 8\xBC=\xB9\xF1\xC1\xBFý\xB6r\xADV\xBB/v\xF0šM97\x95áž›\x9BYh+@\xBE\x9A\xF0        !\xC8OG\xE1!I\xBE:\xF8\xDFM\x8AE\x97._E\x8D\xCD\xEEa\x9B\xDB$\x8C\xFF?~|^FFF);\xA9Ê\x84\x9C\x88\x9B\xCAÐ9s\xA60..\xEE\xE9\xC1\xD4\xF2\xD3\xF4\xE0\xC6-!l\xE2\x84q @T\xE4\xABTw\xA6\x89q'N\x90#ݵ|\x81\x98e\xE3\xC56\xF4ˈ\xB6\x85\xA9Ezd\x91Gtt\xF4\xFDB;\xC4(2&lt;M g1v@ \xB9\xC5M\xADFSc'1i'\xE8        \xE5\xB5\xE0F\xAF\xBC\
 xF2J\xAC\xB5q#\xB5H8s{\xE7\x9DwR&lt;&lt;&lt;Â…i\xE8\xBEs
+\xF0\xF7E\xA1!\x81\x963.\xB4_\xDC\xDC\xD4L\xEF\xCC\xCD\xCD\xCD\xDC\xC3\xDE/Ò»^\xB6l\xD9bk\xA3Ø¢\xE9\xF5\xFA\xB9B+&lt;\xCA\xC6P\xB3 M \xA1G\xB7L\x8B\x87\x87\xFB+`%6D\x96e͉\xC4kuHH\xC8l\xA1\x96\x9D\xF8Ú¼\xE4\x87&lt;&lt;\xDD1\xD8\xF4d\xB9*d\\xFA_\xCB%\xB3A\xA4I\xD1\xC7Z|F\xA7\xD3\xCDb{\xEB\xEE\xE8\x97s\x90LÖœ\x88\x91\x97\x97W\x84P(\xE3\xC7M\x9D\x8F7\xBA1\xFFF\x8B\\x8B\xE7G\xFE~:s\x9BV\xF1R\xBE\x8A\x8A\x8A\x92\xD8\Ù¦p\xC6%T        CF\xA6\xAFuX\xBC\xD7j&lt;顬yk\xBD\xCC\xCB\xF5\xE7\xCE ~\xC6\xDF\xDF?p$\xE1LT\xDF+Ú€F\xE3\x85\xE8uk\xF2\xBFG3\xF3`\xD79\xD6 \xA5Pd_;\xD2\xEA\xA9\xEC\xEEQ'\xA2\xB2[Ô‰\xA8\xECgÔ‰\xA8\xA4gʬT-\xEE\xF2F \x9ALn\xFE\xF1&quot;\xEA\xEC\xEC\xA6\xC4Q'Vp\xA0JJ\x9C\x82\x92\xF4\xB1 &lt;ZÞ¸        _\xD1\xD9\xEF\x9B\xD1\xD9\xEF~@_\xD7|\x87.\xFF\xDCF\xAD9\xE6Z|\xD9*nJZr[:\x8A\x8B\x89\xB0Ù¡\xD8pY\xB5|\xD2'e\xAAf\xEAD\xAE\xE6D\xE0&lt;\xF7\xE6\x88\xECTUM=\xDA\xF0S\xD9:\x93\xBDs\x9F.\xE7D\xB3\xD3\x99\x93\xAF\xC4B\xD6h\x94\x9C\x8Bn\x8A\x89Doa
 Ü‰\x863;\xD1]\xD9 Ñ­\xB7\xCC\xB3d\xFC\xA1\xDCl\xF4\xD6\xC1O\xD0\xC7\xC7*h\xEF\xCCYw\xA6\xEE\xBBÛ€\xD2\xD3\x9DjP\x90?\xFA\x86\xC9U0\xB2/\x9C\xC9ĉ\xD2g\xEA\x9D'p\xBB\xE6\xF3?\xA1\xF2/\xABib\xAD\x86&quot;\xC2\xC73.$\x85\xF35a\x90&amp;\xE2}\xC8\xCEv\xB4k\xDA\xC3$\x83\xF9\xF7gK\xD68\xEB0Hr\xA8#{\xA5\xB6\x97`\x92\xCBÒ¬9(\xE7'R)\xBB \x84R\xD2\xEBIR\x88H\xAEo\x8DÊœ\x97*y\xA8X\x96\x95!\x8F\xF3d%\x83\x88`\xA5L\x8F\xB58\xEDS*\x81f\xCC\xD2+\xBA\x8B\xAFØœ\xEE|A\xD0q\x8AΉ\xD9;&quot;&quot;\x9F5\xA3\xC8k\xE8Ö“\xA6\x9Bb#Q\xDD\xD9&amp;B\xBB\xF8R\xE6D\x84^&quot;;\x89\xB8\x86\x9AJ\xEEeÕ’:\xA1$\xEEÌ­)\xF5JaE\xE6DS        t&quot;d&quot;\xB7\xBE$\xB1\xA6\x92\xBFk;»\x99Xwtt)2\x81%Uj\xFB        &amp;\xAF4\x9D\xBF@\xF0\xAF\xBC\xCCZ\x919\xD1u\x9D\xE8\xE2\xA5V\x9A\xC9IM?\xB4\x90\xB7O\xCD\xAE1\x9A+\x91\xF1L#Y9Zgj$lG+\x89\xA8\xED\xDD8\xA9嫪:b\xE9\xAB\xCA:\xA2\xEB
+I\xCE&gt;\xB5\xE1Xy\x95Í®u\xF4\xE3\x93\xB7\xE3\xB5\xC5Y\xE0olu&lt;f_|B\x91bO\x8F=u\xBA]\xBAÜŠ\xC6\x88~~\xFF\xFC\xCBo2ËŸ\xAFB,\xBCy{k\xAC\xAE\xFEf\xEB\x8E\x9En\xE48\xDB\xFC\xDBa\xB7\xF1m]#R\xB2=ظ\xFF\xD0\xE76\xA0\xF8\xDDSGo\xFALp\x9C\xE9&quot;\x86~\xF7\xD4s\xFF4d\x8B\xFE\xF1\xEFw\x89\xAF'\xBD+\x88\xB8&gt;?^\x89\xE6e$\xA1\x84\x9B\xA2\xF2\x9Bu\xCBqC4+\xECÇ @\x89\x8A 5\xBB@5\xF8ݽ\xAB\xB3\xAC\xBA\x90\xF1Lv\xA1\xA4t)r\x96\xAF\xD7wDy\xE6!\xD105/#\x99\xE6u \xBF\xD5`\xA57\x86\xCE\xCDf^E\xF3&amp; \xDE˯\xBB\xC4\xED\x995\x84!\xA4pC\x8EU(4p\xAES\xB8'u\xAA\xB2V\xF0si)\xF1\xB8L\xC5\xE0\xA5 \xBB\xDD\xE7^\xDAM\xEC\xF4 Y\xC9\xE4 ;u\xBA;\xD2\xF4\xF0\xFD+\xAC~\xE0\xE01
+C        S\xA3G\xE0~\x88\xA29\xD1(\xF5\xD9+\xE6\xD7\xE5\x86í~Ûh]I.s-&gt;RcS \xCA_\xBF\xC2j&gt;3\x81\xF3\xEC\xF8\xD7\xAB\xB9\x85H\xE6N\xC4\xE9\Ó\xE8\xD9v17\xB7Z\xBCh6\xF2\xB1\xC1\x95\xAC        zt\x87KO\xC8\xEC\x8E5\x97\xBCS4&lt;4\xFA\xFB\x96\xA3%\x8B0L\xB7\x8D&amp;\x98\x95g{\xBF\xB4\x9Cȳ\x9CI\x91\xE2\xEBi\xF17r\x9Bok\x86\xC2t\xFDLP\xE0s\x89S'3\xAF\xEAC\xD0@O\xD6SSwNp}\xB6n\x97\x863 \x86È¥\xC1\xB4\xE9\x89\xF5\xCC+Ó˜\xB8\xB7\xB5}\xE7\xDB B\xAA\xA9=\xC7tо\xEDFO
+CÖ¯d^9\xF8\x9E\xD8\xF4\xE1n%\xE1%C$?\xEEk\xCD1΀{[\xDB_(D\xBF\xCE^\xC8\\xDC\xE8\xE8\xED\xC1:a\xDD/l\xDA`\x88\x83\xF9\xCFf\xA2\xA0g'\x82\x8A\x9C;\xCB]\xB3Ä¢!\xF9\x82\x86~\xF1\xD9GЂ\xB9\xBFr\xD8\xF6`]\xDB_|\x9CY\xB7\x98;\xAD^q++g\xC2ND\xDEJ\x8C\x9F\x8C\xEE\xB8=}\xD8P\xF7\xC8+\xD1\xEA\xEC[QÉ\x8F\xD1\xC6\x87È™\x9E\xA5\xB7gX8\x9E\x98\xB0j#2ibM\xAE\xA0a\x9Fxt\xED\x88\xF2&amp;x\x94w.\xE8K \xD2{G+M-\xC3B\xBA\xC33sFˆ{tx[\xBF\xFF\xD3v\xF3#z\xCFF\xB3\x88ÑŒ\xFBp\xAEÜ¢\xA1\xE9\xC7!\xF0DO\x9A`׸@\xBBz\xC5B\xB4k\xEF\xFBt\x9C\x88\xC4\xFE,\xEC P\xE1f\x8EZ\x97\x90\xEE\xC0\xE1\xEF\xE4WF2Ú+'\xD60V\xF0\xE0*\xD9\xEC/ì«·\x9D#\xE5$Y\x91&quot;\xBA\xF89\xB8\xE7\xE3CR\xA3 \xA3\xF18\xAC\xC1&gt;\xD3.&gt;&quot;\xE3s\xC8U\x96\xC2}e&amp;\xD8gȱ\xE8\x8D?        \xB8\xE0e\xFD=w\xC86 \xDF\xD8w\xF9_J-\xEB\x9ChY\xD649j\x82l\xF7_\x9F0yÌž5\xE2L\xC9\xF6TÈrVfʾ\xE0;\x9C8U#\xEDØ‘\xB4\x89\xB5te\x99a\xAE\xAC\x92i\xF1$;\x90\xF9.\x92\xE6E\xAE\xD8\xC5\x88\xEEV\x80 \x99òa\x8E\xC4
 \x84\x94\xB3\xF8\xFDS@\h~\xE0Þ¥\xAE\xF9l\xA9쟄\xC7-8Z\xF0\x9D໹\N$EOtͪEH\xA9b\xBE\x9Bu*\xF1`\xA3sGVaS\x89.\xC4w#\xF8\x8EήW$-D\xCE-kW݆\x94\xAE\xCCyi\xCE\xB1v\x95\xDB\xED\xF9\xF8hQ\xE6\xFCT\xC5C\x94\xBDd\xF3]\xE5$\xD9\xF4β\xCFA\xAE o8XfȪ\x87&amp;'Êœ\x9F\x86\EÙ‹oq'rV\xD0NO\x9B\x86BC]&quot;\xF8\xAE\xD3bd3\x8D/\x8B\xC4:s\xFEL\xE4jZ4?\x8D&amp;ÖŽL\xA8\xD3g&amp;\xBAD\xF0\x9D\xE5\x92`\x9FX\xBB&quot;@\xFC\x83\x87&amp;\xD6:&quot;]Ur\xF9\xEED_\xBC\xA8c\x8EF\xBD\xCBB\x944m\x8A,\x9E\xAB&amp;\xBD]YÒ’\x9DPJ\xBE\xA3~Rb ru1\x92\xA2\xEF\xA8?\xC68=1\x96B\x84\x9D\xC8D\xB6\x91ΦDO\xA4%\x92\xD2Õ´\xF2\xC8\xD7\xD8L
+\xBD\xB1N\xC2w\]h\x89\xBEɪ\x9Aܣ/\x9C\xD2\xE3$W6Iy&quot;\xA5&gt;]\x99DQ'\xA29\x91}\xE1̇\xEC\xD0\xEE\xCF\xF6\x90bNt]\xABiQQ\x88\xA8d\xDEŧ\xF1\xCC)\xAA\xAA\xA9'\xBA\xAE\x89u\xA2\xAA\xEAzJ\x8F\x93rO\x89\xBB\xF8\xB4}\x9D\xD7ŧ9\x95\xBAv\xBDS\xB9]\xFC\xB1;\xFB}3\xA5\x87U=\xAE :\xD88
+]\xF8\xE9
+\xA5\x87U \xE1uA,D\xF5\xE7Σ\xA3\x9Dty\x80\xA0\xC6&quot;E?H\xF8\xAF\xAF\xEEE\x95\xB8\x976&gt;\xC85\xC3&gt;\x90\xCAN|M\xFC~\xFF\x80\x98#Ô\x88\xED\x9DQQ\x88\xA8(DT\xAEÑ”\xC9\xF4lC\xA5K7\x8A\xEB\xFFE!\xEA\xEA\xEA2ـΛֲ\xC2+bW\xAF^\xFD\xBF  \x81\x99&lt;Q\x88\xBA\xBB\xBB\x87 \xA7\xE8cGE*\x95|\x94&lt;=N\xF0\xE7k×®\x85\xB1\x86~[!\x82+\\xBCx\xF1\x84\xD0\xCA\xE6\xCEN\xA25\xAD\xE0PF1X×®]\xFB\xBF\xF4\xE0\xD2'\xE4Fb\xF5WWW\x97        m(+\xF3fZ\xDB
+\xD5]\xCB\xFE\xBC\xA5\xA5\xE5(~\xE9I8c \xBA\xF3\xCE;+{{{\xCF \x85\xB4Ë£\x92\xB7 \xAD\x81\xE8СC\x87\xC5\H&quot;\xFBA\x88}\xBD+++\xBB\x84V\xFA\xE4\xC6{hn\xA40\xAD[\xB3X\xB0Mq\xAB\xBC\xB0\xB0\xB0~4N\xEEݼyó¾\x81\xB6\xC1\x80\xB9,x|8\x952d\xC0)\x8AX(;}\xFA\xF4K\xD0\xCFb\x8DEP*\xFE$\xAAJ\xA5\xE2\xC3剋/v\xA3+QQQ\x9B\x84\xFE浶\xBC\xBA\x97\xB6\x82\xCC\x82\xC8&quot;$p!\xADV\xBB/v \x89ÏX\x80\xB5\xAF\x8E\xE8\xE8\xE8\xD7zzzj\xC4v`\xEB\xE6Gih\x93\xA9rq&quot;\xD0Î;c\xE1\xE1BÙˆ\x9C\x88y\x8Bn\xCC\xF2k\xB6m\xDB6-??\xFF\xB5Z\xED'\xB48}s\xF7\xBE\xC3\xE8\xADw?\xA5-#A\xC7Ò‘X+3uuu\x85\xF1\xF1\xF1\xBB\xF1\xE2u!\x88,\xB8&quot;.\xAC\xF9\xCD\xCA\xC9\xC9\xD9'\x848\xB8R\xA3\xF2\x9B\xB3ÄŸ\xECj\xE04\xD0\xEE\xFC\xAC+W\xAE\xBC\xFC4 \xC6L\xA3\x81\x88\xC9+/\xA9\xA2\xA2birr\xF2Vk Q\xC9[\xED\xED\xED\xC5~~~x\xB1S  [s&quot;~O+V\xA3\x95]3f\xCCx\xAF\xB8\xB8x\x8DP\x8F\x8DJ\xFE\xAA\xAD\xAD-\xC4mdê±–+!j\x98\x87\xA7qa\xCD\xDC\x97qyyy        \x98\xD8#&amp;*E
 \xF7\xC2jJJJ \xB8m\x83\xD96vg\xDB\e 7Ã…3&gt;H\x88+m\xEE,P^eee\xF3SSS\xD7h4\xE9\xF48\x96\x9F \xA2466n\x8D\x89\x89y\x83u\x9FN6\x89\xEE\xE7E&quot;Q\x88l͉\xC4\\x89s&amp;H\xBA=JKK\xE2\)'((hÍ—\xC8Wkkk)\x86\xE7Ô\x94\x94}\x90\xA6\xB0\xA1\x8B+\xFC'Ä¢\xB1\x80\x88\xEFJLn,L\x90|{\xEEÙ³'Y\xAF\xD7'D\xE8t\xBA\xECR\xF4L6        \xD5\xD7\xD7׆\xA11B\xDB\x8D\xC6r\x83\xC1p \xFD2#\xDF\xCB\xEB\xBE\xF7Ûœ9\xA2\xC1@\xA9x0\xB9\xB3\xAF\xF4\xB4[B# 7\x99:\xC0gD\xD7\xF1\xB9\xB1\xF7\x92!o\xE7\xB897\x95\xB5\x84\x8CJR\x99x\xEDdSزE\xEE\xDC14;\xA4\x92&amp;\x87IE\xEFKe\xAFh\xEEBE!\xA2\x92^\xFF`\xD3\xCE!\x92ÞŸ\xF2IIEND\xAEB`\x82
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinsstandardindexsearchpng"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/skins/standard/index/search.png (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/standard/index/search.png                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/skins/standard/index/search.png        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,38 @@
</span><ins>+\x89PNG
+
++IHDR\x91\x91\xC3\xD8Z#tEXtSoftwareAdobe ImageReadyq\xC9e&lt;~IDATx\xDA\xEC\x9D        XG\xC7k`\x90\xFB\x87G&lt;$\x8A1(M\xA211\xEAnT\xF0\xC8J&quot;\xC1+\x9A\xC4\xC4\xEC\xC6D\xB39\xD4d\xBF]׸\xABQ\xBFÕ¨\xD1=T4\x90H6qE\xCD#\x9E\xA0â \xC8\xE1\x81x\x80\xE0@8f\xEB=\xA4\x81\xBEf\xA6g\xBA\xA7\xA7\xFE|\xEF\x9Bf\xBA\xAB\xA6\xDFo\xDE{U}\xE9\x8CF#\xA2\xA2\xB2F.tPQ\x88\xA8\x97\x9E\xFDB\xA7\xD3ɱNݬ\xAA\x97\xD55 \xBB \xD2\xCB\xD4)\xCB\XÏ©\xD4X\xEB\xB9\xD5@\xE9e\x80Ç”M\xEBt\xA5\xA9R\x95x\xB150\xCFMfUt\xB2&quot;,n\x8Cé“’\x92\x82\xA2&quot;&quot;&quot;b!\xE4D\xE8\xF5z?\xEA?\xE5TUUu\xB6\xBE\xBE\xBE\xAA\xB2\xB2\xB2\xA4\xB0\xB0\xF0d\\\xDC        \xA4zƬ
+m2\x89\x91\xC7\x8F'6l!\x89\x89\x89\x91999s+\xC3#\x95\xEA\xD5\xD8\xD8XYQQ\x91\xB6mÛ¶g\xC0\xD8\xB0y1\x81\xC0UJ)ÒŠ3 2\xD59z\xA0\xC0\xE4\xE4䈲\xB2\xB2\xA5\xD0)\xEA\xC7\xFE\xE1\xCC\xCAÊš\x80\xFD\x8C\xCD\x9B\xE3c\xC1\xBA\xD6\x88t\xACz\xC7fff\x91%\xD4+\xDAPyy\xF9Z
+ L\xDELTr\xE1\xC9\\x88t\xAC\xBAV\xDE\xE9Ê•+\x9F\xD1Í®=\xD5\xD6\xD6\xE6mÚ´i\xF6qGl~\x8C\xCFE!Ò±\xE1\xE1\x98'2\xFD\xF2\xA4;\xA41\\xA4\xAD\xF0\xF5\xF5\x9DD\xCBU\x8Dßš\x9A\xAA\xD2\xD3\xD3\xE2\xE3\xE3\xA1\xF8\xAE\xC1VÇŒ\xE8\x8C|\xF3Db\x99\x86\xED\x90h\x99@\x97\xCA\xD0\xEE\xBD\xD9(\xE7\xD4\xF2\x9CJ\xF2\xF1\xF6D\xFB\xF7E\xC3b\xFA\xA3\xE1C\x90\xD7B \xA5\xA6\xA6N\x99:u\xEAa\xA4\x9FYsKfC\xA8T\xEEEEE\xAF\x87\x86\x86~\xCC\xD7p\xCE\xE9\xB4q\xF3N\x95\xFA\x81\x9A\xF8\xDC4L+++\xA5)))\xA3×­[W\x8A_\xD62SfCd\x8A@\x9E[\xB7n\x82\xC3\xDBN\xBEN\xAD\\x9B\x8E\xBE\xCA\xD8O\xBD\xE3`\xEA\xDC1-z\xEAÖ•\xF3\xFD\xEA\xEA\xEA\xDD8\xF3L\xC3O\xEF1 5\x9A\x91i(s&gt;\xB8\xE0\xFA\xDE\xDDݽ_\xBBFj \xE8\x83?\xAE\xE5\x8C&gt;~\xBE^\xC8\xD7Ç›&lt;R)\xAF\xBA\xBAzTU]\x83nß©F\x8D\x8D\x8D\xAD\xA2\xD2k\xC9\xE3јQ1\x9C\xCB;vlFtt\xF4v\xFC\xF4.+\xADI\x86Ò˜_^^^b\xBF~\xFD\x96p5e:\xD9\xEA\xF7\xF8\xA2\xDD:!\xF7n\xD4s*T\xE8z\xF9mt\xAD\xFCV+\x98\xBEX\xF6.gD\x82\xB4\xE6\xE6\xE6\x8B\x9
 F\xDE\xC1f0\xD5Fln\D\x86\xF4\xE1\xE1\xE1oquꟶ\x85\x85vA}zuC0@\xEC\xBD{\xD4\xD4c\xAE\xAE\xAE\xE8\xFE.\xC1(2&quot; yyz\xB4\xF8n\xCE\xFC\xE5$\xB3\xB4\xDB/\xA6\xD7w\xCB\xCDÍ&quot;4o\xE4&quot;07\xE4\xBAcÇŽá°’\xB6o\xC56\xB7.\x91\xC2ztAA\x81\xFE\xAD\xE6\xA8\xA9\xD7:\xB8\xE9\xD1}z\xB4d j[.\xF5\xEA\xD5k&quot;k\x97H;\x90\vo\xB8 &lt;x&quot;_b\xABSH \x88\xFE\xD4\xCB\]]P\xEF\xB0_bÄ®\xBD\xD9$@\xB4\xCD\xF9\xF8 Y\xBE|y/\xBE\xFDjB\xE9L\xEF\xEF\xEF\xC3ULCc-s\xB8#]:\xD1_\xB7\x83\x9A\xA7G\x87\xE6\xC0(\x8Dg\x94=bĈ\xE1R!j\xE9\xC0U\xBBJ\xABmt\x9F?rq\xD5a\xB0韣\xFEu\xE9\xC8\xEB_\x93BBB&quot;\xF9j&quot;=_=4y\xF2\xE4\+\xCB=]\xD0굿\xBF\xA2'\x8C8\xB6p\xB0@\x9E\x9E\xEE\xC8`\xA8#\xE9 \xE6\x90\xD8\xF2\xF5\xF5\x8D\xE0[\x9E7\x9D\xD5\xD7×»r-\xD06g
+M\x9FS9\x8E&lt;=\xDCy},&amp;\xDE####c\xA4\xAC\x80\x9E\xB7\xA6+u\x99\xD7\xF3\xF6\xF6\x8E1&quot;\xA9\xA2iDV\xF8\x91LO\xD5Ì\xCB\xD2HDe\xB5h$\xA2\xB2:\x9D\xD1HD\xA5\x86tF`R\xB7\xFBC\xC8hx \xBC\xCFu\xEBB\xE6_\xDA\xEA\xC2\xC5R2'Sv\xF5\xBAPXJ^;\xB2h$\x92\x9C\x91\xC3\xA1\x91\xBD9\x81\xE1R\xDF^\xCD\xFB\xAB`\x99\xB1O!\xD4ɼBt\xE8X\x81\xCA\xD1B\x91\x9E\xC6\xCB44\xBA\x81\xE1\x88\xAC\xC0\x83\xD7v\xEBvÚ±\xE7't\xE8\xE8\x89\xB4\xAA\xBE\xBD\xBB\x93\xE3\x93倇K\x90\x93\xF0 \xFBt,\xFAg\xEAn\x99J\xEC\x88,\xAC\x9DE\xB0[\xE0W\xA3c\xD1\xC8\xC7Ù¥\xBD  \xD3[)\xF1(7\xAF\xFDs\xCBnd\xA8\xAD\xD3n:s\x86H\xE8\x87R^~G\x9F\x8Evo;*\xB2\xEA\xF6vG\xB4\xFA\xCB\xED\xA8\xF4J\xB9*Gg.r4\xAEe\xEB\x8A\xD3\xD6\xFBs\x88\x95\xE6\xCCL \xA9\xD4V\xDF\xD3\x8C\xAC\x9Fll&gt;[\x93C\xF4\xB7gN\x92&lt;\xEA\xB2i:\xC5}\x90b\xA3#m\xF3}\xE9&lt;\x91+\x86\xEE];\xA2\xB7g\x99\xD0\xCD[\x95\xE4D\xCE\xFC\x82\x92~nÞªjUpj\x84#        \xA3\xEA\x83\xC2qd\xE9\xDEÕ¼\x978y *.+G\xA5e\xF2\xA66\xA3\xA25
 \xD2E^s\xFA\xE9\xC8it\xC0#\xA4
+ \xD8\xF9\x82b\xF2 \xF5\xF8#(v\xF0C\x92Û‚\xBE-]\xB5\x95\x94\x95\xABb{\xD1HÄ¡\x99\xD3\xE3HRФ~\x93i\xB1C\x8BK\xCBÑ—\x9Bv\xA2\x8C]\xD1\xF4)cQx\x9F\xEE\x92 i\xF2X\xB4h\xC9FUl/Z\xB51\x88
+R        \xFAv×hɊͨ\xA4\xF4\xBA\xD5\xEDÞ¼y\x87\xAC+\xF5\xEBLImC\x9B\xF4“\xAA\xA8\x8B\xE8^\xFC6\xF5ʳc\x86\x89~îž¡\xADZ\x97N \x92[{E \xFF\xB2\x81\xB4!\xA6QO&lt;bvM\xA5\xD2!\xBEv\xFE )ilÉŠM\xE8Ä© 6\xEBGI\xD9uÒ†\x90âž”\xA5MEÓ™V2\x9C\xFA\xF4\xE8\x90\xFE\xA2\xDF\xF7\xCB\xEF u\x8C\xAD\xFBm\xF0\x9D\x91\xCA\x9C\xC5Þ»\x87\x92#|9 \xD2\xC6I|R\xD2Øž\xFDGQV\xF6I\xBB\xF5\xE9Ü…\xCB(cg\x96h\xBF\x9Ez&quot;Z\x96\xF6,\xACß¼&lt;&lt;\xD0\xC3\xC2E\x87\xE6;\xB2\xECÞ·\xED\xB8Í’R\xE1\x91\xDF\xC3\xFA\xA2`kOc\xA75\x91u\xB1\xC4j!pf\x8D\xC1\xA0H\xFF6\xA7\xEF\xF5\JO\xA9\x9A\x88\xCE1\xBFd\xB1(\xC4wz\xB1\xE0|\x8E\x97\xEA\x81GO\xC1A\xFE8R\xE0B\xB9\xD7:\xD7I\xC1 \x8FRu6\xBF\xA7\xB6b\xF4`\xDF\xDF!}\xBF\xEF\x88c\xCEXkAB\xCE\x99\xE3H+O\x8F\x8CE\x857\xA7\xDEi\x82ZÆ\x87N\xA1\xE3'\xF3E\xD7  \xF5S\xEC;\xD8r\x90\xEF\xF4\x87\x82\xC0U\xDD\xD8{\xE2\xD2\xF1\xDC\xF3\xA2\xDF\xA2\xCD \xE3#Wf\x95\xB6k\xC5+\xC2\xD1\xAC\xE2f%Ú”\xB6\xB7\x93/\xD84\xED\xD7&quot;#\xB5\xEELÇ›\xB1v\xF0\xA
 A:8\xC8Od\xB7\xC4u\xEC\xE4;\x82\xEB&gt;\xB4?Z8\xEF\xC9q8\xFB\xB7\x895\xD7f\xED\xDBh\x8E\\x97EJT\xD6N?OÔ£kgQ\x88\x84\x96\x9F:\xE1i\x94&lt;\xEDY\xD1h&amp;E\x90\xDF{\xEB7\xCC\xE7Ú·u.\xBFX4\xBA)1W\xE4\xF4\xBB=\xC4F&amp;7H\xE2ÖŒ\xC4g\xD1\xE8'\x87Èž^\xE7\xBD5\x8Ds\xB4x\xB9\xF4\x9AU\xB5\x9D\xADj&quot;\xA7\x9FllN\xFC\xBA\r\x9Ds9H]\x96\xA6/)\xE9mÞœi\xEDÚ¬\xB9W+^XX\xBA-\x94\x9D'rlKC\xF7\xB0\xE3\xDA.\x84\x9D\xFCb\xFC\xD36/\xF8\xE3~\xF5x\xEB\xAA\xC5h;({Þ™\xE6\xD4o_0\xDC\x89-\xF3K8\xA6\xFF\xE7t \x8F\xACL\xCBD\x84\x87\xA2\xC7b\xA3\x88\x89\xA9Ó­\xDB6\xAA\xD2N_X\x9F\xCD\xF1tn\xB7LMM-Z\xBD!Cp\xB9\xFF\xFD\x94\x8B\xE6\xF2\xFA\xE1`.\xF9\xBCi\xD93\xE7/\x93e?\xFD\xEC\x820\xCB9\x8Fv\xFD7\xDB\xEC\xE2\xD7!w\xC0:~\xA01\x8A\x8Cx\xDCy\x9D\xBCz\xC3v\x9E\xE6fP\x84 1}\x86\xBB\xBBƹn\x88b\x82\x83\x80\x8A;\x8A\xCC\xF79}a-4\xFA&quot;\x8E{ \x94wY\x882\\xCE\xFE\xFB\x97\xDB%\xB5}4\xE7YG[\x80&gt;\xC1Q
+\x8A趟
+I\xDA{\xBE&lt;3\xD6~\xA0\xBE(D\xE1=\xBFãƒ9d\xAF\xBE\xFC&lt;
+\xC1N0nܼ-\xB9}\xF8\xFC\xE3\x8F6\xD7G;\xF7&quot;\xA7N -&lt;\x92\xBC\xA6\x88?\x9C~\xDFÙ™\xF3E\xA2\x9F\x89\xF8 q\xB6\xD0:\xE6-\\x8D\xC6&gt;5\xD4\xEC\x94\xEBK\xCB8 8Ú½3\x81T &quot;%$\xC3\xE8L \xF5{\xA0'\xEF\xFB)\x8E\x9E8':\x90f\xE1=ß–\xAEL\xFD\xCC\xD8Q1\xA2U\xA9\x9A\x88\x9E\x8B\xD1&quot;D&quot;\x98\xB4\xC6I\xD6($8\x83&lt;P\xF4;(\xE5 z.&gt;\xB6#9\xE7D\xBFg\xCA\xF4\xEB\xDCfSL~\xCCQ\xEA\xC0F\x89@\xE57n\x8B\xA64x/z\xE0\xE8ȉsv\xED\xB4\xFB\x84H\x82y\xA9\xF8\xAAbU        \x9D'bW'\xD3̤8\xD1\xE2VNy{y\xA0Y\xB8M1m\xCB\xD8'\xC3|\x99\x92i\xE42G\x8E\x9F\xADy\xC0\xA9\xBF}
+\xF2\x86\xFDm6\xEE\xB4\xF1\xE1;\xD3I=$\x85d\xE5\xC8qm%k&quot;\xED\xFC\xADZ\xFF\xB5\xE8\xF7\xEDÙ£3\xFAp\xEEt\xE4\xE5\xE5n\xB3~\xC0\xBA\xA1+hK4
+m\xDF'\xD3É‹t\xC6Z{b\xD8@I\xDF\x9C\xFB\xD1\xDC$2w#w ]º\xA5\x94w\xEEÚ—u\\x9E\xB6iMd\xBD^{e&lt;1\xECaÉŸ'\xFCn\xB9\x8E\xA3\&lt;(-^0K@\xB0[d\xE5\xBAtUl;z\xCA\xD6\xEB\xC9\xA0\xE1\x9B\xBD\xD4H/OG\xE0\xDB\xFA\xCD&gt;t\xF8\xF8Y\x8BÚ|0 %\xBC0\x92&lt;JÕ†M;\xF0\xA8R\xC6y+zÊ\xFDj\x95\xBA\xA0\xB9\xB3\xA7\x92&quot;@\x82ST|M4\x924#qÛ°\xBC9\xFA\xEE\xFB\x83\xB8\x8D2o        %/Aì ¡\xA2\xC8k3&amp;\xA0!\x83&quot;d\x9DY\x86\xF4fJqP\xB3@\xDA)b\xE6ph\xD7\xF4h\x89\xB8\xA8R+B\xB2\xEC\xC5wL\x80\xCC{\xC5\xEC`I\x9A\xC9*\xB4\xE2\x8B4\xD5mO\xA7Kgpj\xF3B;$\xB7\xE0
+j[\xBFÉ´]\xF4b\xE8\xD2#\x90\xA3\xE9\xF0\xF35i\xB8Ö²\xED\xBD&gt;è­ª$\x94\x8C\xC2\xA0\xCC\xFFG\xEB\xFF\xF5\x9D\xE8\xA9BHg\xEA\xA7(,\xB4 9\xB3\xB4c\xF0}\xB2\xAD\xF3\xD2\xE5\xABd\xBD\xB6\xD0é³—p\xFAÚ‹/\xDAq+\xD1\xC4\xB4h\xFE \x8BGC\\xFA|\xCDW$J\x94\x93ÆB1\x8F\xF4\xB3z\xFDm\xB2\x8F\x9DA\xFB\xF0z\xED \x8F
+&quot;\x91\x9Ak&quot;[\xB4\xFA\xE1y~\xFD\xC6-\xB4|\xF56\xF2@z(\xA21\xA9
+\xA2Ù¥\xE2+(\xFB\xE8\x90\xA2R\xB6\xB0V/@\x9F\xBC\xFF[YZ\xB6\xFA\x80\xDA
+nrǾ\xD1\xB4\xEF\xED\xE5\xD9\xF2\xDCMs\xD41\xB4&lt;W\x8B-\xAC\xD5
+Ч\x90 H5\xCBp\xC4\xC96\xE3n\x88lH#=)y\x8C\xB5\xCA
+k\xB8&quot;\xFE\x9B\xAF\xC6\xCB:Äž\xFF\xC9 \xC5D\xE5\x91\xC8&amp;-ZC\xEA\xCDK\xD9 :h C3@*\xAB]4Y\xA9at\xF7\xB8x3Ef\x80\xAEAi
+s\x8E\xD1\xD9\xF3㆓+\x96\xC9%\xE7\xD3%\xFF\xC0\xC3\xF7\xDB\xCEE\x82\xB3O\xB7\xB3\x84($'@\xF3p\xAA\xA91\xD0\xF0\xE2 \xA33[\xF4\xDE\xC2\xD5N \x90\xD1\xD9v{@pS\xD9*\x80\xFE\xAE\xFA\x9D\xDA\xE2۹(\x9A3k\x92m\xA2)L\x{31753F7}'(vp\xA4l\xEB\xFC\xEF\xFE\xA3h\xCD\xC6 TM\xD2~a\xED\x8D\xFA\xD3G)\xA8W\xCF\xFBeh\xE9\xAAT
+\x8F3\xD6Пehh \xF5\xBEL~T\xF5É‹\xD0\xE2\x8FfR\x80hMdy+d \x80&gt;[IR\xDF\xE8\xCC\xEA\x8D\xC1\x81 t
+\x91\xEFpV\x80 \xA2Rca-s(\x80&lt;\x93\xA42Y\xB2⮄T6/\xACeh\xC1,YZB\xB2\xB9USXS\x80hM$ @&gt;2\x93\x87pU\xFB=\xFB)@\xF6\x88E\x8AO4z\xE4`reV9z\xE7\xC3U\xA8\xB0\xA8\x8Cr\xE1 \x91\x82k Ê¥f\x80Vb\x80\xE8\xC1d\xF6)\x89F\x8F&quot;;@\xBF\x80.\xD1\xE4\x91z\xE7+\x99\xFA`%Ma \x91\x99\x81\xE8ј\xFE\xB2\x91\xE7/\x9Fo\xA6È™&quot;\xD1\xF8_?.+@\x81\xE8\xA1t\x88o1@\xBF\xFB`\xB95&amp;\x95\xA3\xF1\xCDl\\x8E\xA8a\x88F u\xC8\xEE3\xD6?f\x9F\xB2\xA0\xB7\xFF@R\xD3\xDF\xEEw\xA3Þy]+\xBFeQ[\xB0\xAC         G\xBF \xB6\xDAÌ¡&quot;h\xF1\xF2M\xCB\xD1\xA4\xC1\xC2Ú’\xC9ÆœS\xD0\xC6-\xBB\xD0K\x93\xC7H\xE8\xCF\xCB\xFEM\xBDEk\xA2\xD6Ú¸y'J\xFB\xF6\x88Bd\x9DV\xAEM'\x80\xF0\xA5\xA8\xDD{\xB3)@v+\xACx/\xFE. JÖ¡\x93h\xE2s#а\xA1P\x9F\xB0\xAE* Þ£r\x82\x9AH4pz\xA3\xA2錊BDEE!\xA2RDyyy\xB4\xAA\xA5jQMMM\xB69\xC1p\xAB\xC9\xCDÍ­\x91k\x81\xCE\xE9Õ¸\xCC\xF51D\x8D[\xB6l9ɵ@\xD4C}\xE8V\xD68@\ݽ{\xF7\xACT\x88H\xC2Ö°~\xFD\xFA\x8A\xFA\xFA\xFAv\x87 :\x80ni+\x8BÏ¿7n\xDC\x
 C8c\xD80JNgReee\xBB&lt;\xA7\xF6\x8CC\xB7\xB6F5\xE1\xB9\x9C\xFFß¿d(s &quot; 9r\xE4+\xAE\xBE4e,\xDD\xDA\xAETV]]}x\xF6\xEC\xD9Í\xA8\xA5.7n\VCCC)W\xDE|\x99\x82\xA4)A\x86y-y&lt;\xE7{/^\x84`R\xCF@\xD4.\xA5        \xA53X\xA86??\xFFo|ш\xD6G\xDA\xD1_\xFF8\x9B\xF3,d&quot;QQQ\x9B$\xD7D&amp;\xC1?GFFn\xA9\xAB\xAB\xE3\xBCGÓ»o\xBE\x88\xF6\xEFK=\xE0\xE0\xFC;\xBE\xB9\x94\x9B\x9B\xBB?\xD4O\xACRGz:\x88\xB0222~\xC7×\xBF~\xFA\xD9O\xE5\x98\xC3y\x88@|%\ 펎\x8EÞŽ\x9F\xDEcE\xA2vÒ±\xE5\xD0\xE9tm\xDFw\xC5\xD6\x9BWQQ\xD1ë¡¡\xA1\xF3u(\xE7t9\xD0 \x8EZ\xA4R\xF4\x81&gt;\x8C\xC4\xF8.\xA4i,%%e\xF4\xBAu\xEB\xA0&amp;\xAEeE\xA2\xE6(\xC3\xE6F&quot;\xC6Ü¡\x{DAAA}\xAAe\xBE\xBE\xBE\x93\x84:Xp\xA9\x8CL0гRU\x94\xC3b\xFA\x93ZV\xE8*,MMMU\xA9\xA9\xA9S\xA6N\x9Dz\xBF\xACa2R\x93\xA5\xE9X        @\xF2\xC4 \xAD\x89\xCAq\xA5\xA7\xA7'\xC4\xC7ÇŸ`\xAA\xE3Ú³\xB9Û‹od\xD9P\xF9\xF9\xF9\xBDy\xF5\xEAÕ¥tskO0\x80\x82\xC4T\xCB\xF8\x9Csn\xB5%\xCAd\xD21\xC0\xC1\x91\x90\xDEØ‚233\xEA\xEB
 \xEBK\x8CT\x9APyy\xF9\xDA\xE4\xE4\xE4\xEC\xDB`\xC6\xC7n\x8C\xCFu\xA2\xDCH\x84\xC8\x92\x8E        j 4ZVV\xB6\xB4\xB1\xB1\xB1\x92\xBA\xC11e0feeM`\xE0\xF1\xC5\xE6\xC1\xF8X\xC7\x905\xB1#\x92+\x92?\xB6\x90\xC4\xC4\xC4Èœ\x9C\x9C\xB9\xB8Cg\xA8[\xD4/\xF8\xD1WTT\xA4mÛ¶\xED\xF0\xB6\x813\xD1\xC7U.\x88\xC4
+k!\x99`ra\xD3'%%'$$DEDD\xC4º&quot;\xF4z\xBD\xAD8\x94 \x9DÅ¥GUeeeIaa\xE1ɸ\xB8\xB8Ì\xBD\x9E5\xFF\xD3Äš2J\x81H\xEA\xE8LJdbO\x98\xEA&amp;WD\xBDU\xE5\xE0\x8B)\x94,\x87&quot;kOb\x8FÞŒ\xACN餄D*\xBB\xCB\xC8\xF2\x93\xF1\xEC\xC60Wz\x99;\x87\xF8\xA6Æ©T\x93lÒ©\xE1\xBE\xF6T\x8E-Z\xB7PQ\x88\xA8\x94\xD7\xFF\xAF\xFB2 \xE8Ř\x98IEND\xAEB`\x82
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinsstandardindexcss"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/skins/standard/index.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/standard/index.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/standard/index.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -11,6 +11,7 @@
</span><span class="cx">   * The Original Code is the Bugzilla Bug Tracking System.
</span><span class="cx">   *
</span><span class="cx">   * Contributor(s): Vitaly Harisov &lt;vitaly@rathedg.com&gt;
</span><ins>+  *                 Guy Pyrzak &lt;guy.pyrzak@gmail.com&gt; 
</ins><span class="cx">   */
</span><span class="cx"> 
</span><span class="cx"> /* index page (begin) */
</span><span class="lines">@@ -18,68 +19,125 @@
</span><span class="cx">     #page-index
</span><span class="cx">     {
</span><span class="cx">         padding: 0.2em 0.2em 0.15em 0.2em;
</span><ins>+        max-width: 1000px;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    #page-index ul, #page-index li,
-    #page-index p, #page-index form p
-    {
-        margin: 0;
-        padding: 0;
</del><ins>+    /* By default these contain nothing, but these CSS rules make things
+       easier on customizers. */
+    .intro, .outro {
+        text-align: center;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    #page-index ul
</del><ins>+    /* Hide from NN4 */
+
+    #new_release
</ins><span class="cx">     {
</span><del>-        padding-bottom: 1em;
</del><ins>+        border: 2px solid red;
+        padding: 0.5em 1em;
+        margin: 1em;
+        font-weight: bold;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    #page-index li
</del><ins>+    #new_release .notice
</ins><span class="cx">     {
</span><del>-        list-style: none;
</del><ins>+        font-size: 80%;
+        font-weight: normal;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    #page-index p
</del><ins>+    #welcome-admin a
</ins><span class="cx">     {
</span><del>-        padding-bottom: 0.5em;
</del><ins>+        font-weight: bold;
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    /* Hide from NN4 */
-    div#page-index .intro
</del><ins>+    .bz_common_actions {
+        text-align: center;
+    }
+    .bz_common_actions ul {
+        list-style-type: none;
+        padding: 0;
+    }
+    .bz_common_actions ul li {
+        display: inline;
+        vertical-align: top;
+    }
+    .bz_common_actions ul li a {
+        display: inline-block;
+        height: 170px;
+        width: 145px;
+        margin: 0 2ex 2em 0;
+    }
+    .bz_common_actions ul li a span {
+        position: relative;
+        top: 90%;
+        font-weight: bold;
+    }
+    .bz_common_actions a,
+    .bz_common_actions a:visited,
+    .bz_common_actions a:hover {
+        text-decoration: none;
+    }
+    #enter_bug { background: url(index/file-a-bug.png)     no-repeat; }
+    #query     { background: url(index/search.png)  no-repeat; }
+    #account   { 
+      background: url(index/new-account.png) no-repeat; 
+      margin-right: 0;
+    }
+    
+    #quicksearchForm
</ins><span class="cx">     {
</span><del>-        width: 250px;
-        height: 200px;
-
-        margin-top: 2.3em;
-        margin-right: 2.3em;
-        float: right;
-        background: transparent no-repeat url(index/front.png);
</del><ins>+        clear: both;
+        text-align: center;
+        margin-bottom: 2em;
</ins><span class="cx">     }
</span><del>-
-    #page-index #report
</del><ins>+    
+    #quicksearchForm #quicksearch_main
</ins><span class="cx">     {
</span><del>-        padding-bottom: 1em;
</del><ins>+        width: 27em;
</ins><span class="cx">     }
</span><del>-
-    #page-index #sidebar
</del><ins>+    
+    #quicksearchForm
</ins><span class="cx">     {
</span><del>-        padding-top: 1em;
</del><ins>+        margin: 0;
+        padding: 0;
</ins><span class="cx">     }
</span><del>-
-    #new_release
</del><ins>+    
+    #page-index table{
+        border-collapse: collapse;
+        margin: auto;
+    }
+    
+    #welcome
</ins><span class="cx">     {
</span><del>-        border: 2px solid red;
-        padding: 0.5em 1em;
-        margin: 1em;
</del><ins>+        font-size: x-large;
</ins><span class="cx">         font-weight: bold;
</span><ins>+        text-align: center;
+        margin: 0 0 0.8em 0;
+        padding: 0;
</ins><span class="cx">     }
</span><del>-
-    #new_release .notice
</del><ins>+    
+    ul.additional_links 
</ins><span class="cx">     {
</span><del>-        font-size: 80%;
-        font-weight: normal;
</del><ins>+        list-style: none;
+        margin: 0;
+        padding: 0;
</ins><span class="cx">     }
</span><del>-
-    #welcome-admin a
</del><ins>+    
+    ul#quicksearch_links{
+        margin-bottom: 1em;
+    }
+    
+    ul.additional_links li
</ins><span class="cx">     {
</span><del>-        font-weight: bold;
</del><ins>+        display: inline;
</ins><span class="cx">     }
</span><ins>+    
+    ul.additional_links li.bz_default_hidden
+    {
+        display: none;
+    }
+    
+    input.quicksearch_help_text
+    {
+        color: #ccc;
+    }
</ins><span class="cx"> /* index page (end) */
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinsstandardpagecss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/skins/standard/page.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/standard/page.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/skins/standard/page.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,103 @@
</span><ins>+/* The contents of this file are subject to the Mozilla Public
+  * License Version 1.1 (the &quot;License&quot;); you may not use this file
+  * except in compliance with the License. You may obtain a copy of
+  * the License at http://www.mozilla.org/MPL/
+  *
+  * Software distributed under the License is distributed on an &quot;AS
+  * IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  * implied. See the License for the specific language governing
+  * rights and limitations under the License.
+  *
+  * The Initial Developer of the Original Code is Everything Solved.
+  * Portions created by Everything Solved are Copyright (C) 2006
+  * Everything Solved. All Rights Reserved.
+  *
+  * The Original Code is the Bugzilla Bug Tracking System.
+  *
+  * Contributor(s): Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  */
+
+/* This CSS is used by various informational pages in the
+   template/en/default/pages/ directory. */
+
+#bugzilla-body {
+    padding: 0 1em;
+}
+
+#bugzilla-body &gt; * {
+    /* People have an easier time reading narrower columns of text. */
+    max-width: 45em;
+}
+
+/*****************/
+/* Release Notes */
+/*****************/
+
+.req_new {
+    color: red;
+}
+
+.req_table {
+    border-collapse: collapse;
+}
+
+.req_table td, .req_table th {
+    border: 1px solid black;
+    padding: .25em;
+}
+
+/********************/
+/* QuickSearch Help */
+/********************/
+
+.qs_help li {
+   margin-top: 1ex;
+}
+
+.qs_fields th {
+    padding: 0 .25em;
+}
+.qs_fields th.field_nickname {
+    text-align: left;
+}
+.qs_fields td {
+    padding: .25em;
+    border-top: 1px solid gray;
+}
+.qs_fields .field_name {
+    width: 10em;
+}
+
+/***************/
+/* fields.html */
+/***************/
+
+table.field_value_explanation {
+  table-layout: fixed;
+  border-collapse: collapse;
+}
+
+.field_value_explanation thead h2 {
+  margin: 0;
+}
+
+.field_value_explanation .header_row td {
+  text-align: center;
+  font-size: 120%;
+  font-weight: bold;
+}
+
+.field_value_explanation tbody td {
+  border: 1px solid black;
+  padding: 1em;
+}
+
+.field_value_explanation dt,
+.field_descriptions dt
+{
+  margin-top: 1em;
+}
+
+.field_descriptions dt {
+  font-size: 120%;
+}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinsstandardpanelcss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/standard/panel.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/standard/panel.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/standard/panel.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,37 +0,0 @@
</span><del>-body
-  {
-    font-family:       sans-serif;
-    font-size:        10pt;
-    background-color:  white;
-  }
-
-ul
-  {
-    padding-left: 12px;
-  }
-
-radio
-  {
-    -moz-user-select: ignore;
-  }
-
-.text-link
-  {
-    margin-left:      3px;
-  }
-
-.text-link:hover
-  {
-    text-decoration:  underline;
-    cursor:           pointer;
-  }
-
-.descriptive-content
-  {
-    color:            #AAAAAA;
-  }
-
-.descriptive-content[focused=true]
-  {
-    color:            black;
-  }
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinsstandardreleasenotescss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/standard/release-notes.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/standard/release-notes.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/standard/release-notes.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,35 +0,0 @@
</span><del>-/* The contents of this file are subject to the Mozilla Public
-  * License Version 1.1 (the &quot;License&quot;); you may not use this file
-  * except in compliance with the License. You may obtain a copy of
-  * the License at http://www.mozilla.org/MPL/
-  *
-  * Software distributed under the License is distributed on an &quot;AS
-  * IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
-  * implied. See the License for the specific language governing
-  * rights and limitations under the License.
-  *
-  * The Initial Developer of the Original Code is Everything Solved.
-  * Portions created by Everything Solved are Copyright (C) 2006
-  * Everything Solved. All Rights Reserved.
-  *
-  * The Original Code is the Bugzilla Bug Tracking System.
-  *
-  * Contributor(s): Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
-  */
-
-#bugzilla-body {
-    padding: 0 1em;
-}
-
-.req_new {
-    color: red;
-}
-
-.req_table {
-    border-collapse: collapse;
-}
-
-.req_table td, .req_table th {
-    border: 1px solid black;
-    padding: .25em;
-}
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinsstandardreportscss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/skins/standard/reports.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/standard/reports.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/skins/standard/reports.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,92 @@
</span><ins>+/* The contents of this file are subject to the Mozilla Public
+  * License Version 1.1 (the &quot;License&quot;); you may not use this file
+  * except in compliance with the License. You may obtain a copy of
+  * the License at http://www.mozilla.org/MPL/
+  *
+  * Software distributed under the License is distributed on an &quot;AS
+  * IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  * implied. See the License for the specific language governing
+  * rights and limitations under the License.
+  *
+  * The Original Code is the Bugzilla Bug Tracking System.
+  *
+  * The Initial Developer of the Original Code is Everything Solved, 
+  * Inc. Portions created by the Initial Developer are Copyright (C)
+  * 2009 the Initial Developer. All Rights Reserved.
+  *
+  * Contributor(s): 
+  *   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  */
+
+/* describecomponents.cgi */
+
+#components_header_table {
+  margin-bottom: 1em;
+}
+
+.product_container {
+  width: 65%;
+}
+
+.product_name {
+  font-weight: bold;
+  font-size: 150%;
+  margin: 0;
+}
+
+.product_desc {
+  /* This is padding instead of margin because it looks better 
+   * with the scrollbar. */
+  padding: 0 2em;
+  font-style: italic;
+  max-height: 5em;
+  overflow: auto;
+}
+
+.instructions {
+  font-weight: bold;
+  font-size: 105%;
+  padding-right: 1em;
+}
+
+.components_header {
+  margin: 0;
+  font-size: 140%;
+  font-weight: bold;
+}
+
+.component_table {
+  margin-top: -1em;
+  margin-left: 2em;
+}
+
+.component_table thead th {
+  padding-right: 1em;
+  vertical-align: bottom;
+  text-align: left;
+}
+
+.component_table td {
+  border-bottom: 1px dotted gray;
+}
+
+.component_table td.component_assignee,
+.component_table td.component_qa_contact
+{
+  border: none;
+  padding-top: .5em;
+}
+
+.component_name {
+  font-size: 115%;
+  font-weight: bold;
+  padding-right: 1em;
+  vertical-align: middle;
+  min-width: 8em;
+}
+
+.component_description {
+  padding-bottom: .5em;
+  color: #333;
+}
+
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinsstandardsearch_formcss"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/skins/standard/search_form.css (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/standard/search_form.css                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/skins/standard/search_form.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,206 @@
</span><ins>+/* The contents of this file are subject to the Mozilla Public
+  * License Version 1.1 (the &quot;License&quot;); you may not use this file
+  * except in compliance with the License. You may obtain a copy of
+  * the License at http://www.mozilla.org/MPL/
+  *
+  * Software distributed under the License is distributed on an &quot;AS
+  * IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  * implied. See the License for the specific language governing
+  * rights and limitations under the License.
+  *
+  * The Original Code is the Bugzilla Bug Tracking System.
+  *
+  * The Initial Developer of the Original Code is Guy Pyrzak
+  * Portions created by the Initial Developer are Copyright (C) 2010 the
+  * Initial Developer. All Rights Reserved.
+  *
+  * Contributor(s): 
+  *           Guy Pyrzak &lt;guy.pyrzak@gmail.com&gt;
+  */
+
+#summary_field {
+  padding: 1em;
+  margin: 1em;
+  border: 1px solid black;
+  background-color: #eee;
+  white-space: nowrap;
+}
+
+#bug_id_container { 
+  display: inline-block;
+  vertical-align: middle;
+  padding-bottom: 1ex;
+}
+
+#bug_id_container input {
+  width: 9em;
+}
+
+.container_date_from, 
+.container_date_to {
+  width: 14em;
+  padding-bottom: 1ex;
+}
+.container_date_from input,
+.container_date_to input {
+  width: 8em;
+}
+
+#bug_id_container input {
+  width: 9em;
+}
+
+#bug_id_type{
+  width: inherit;
+}
+
+.search_field_grid {
+  margin-top: 1em;
+  display: inline-block;
+}
+
+.search_field_grid .field_help_link, 
+.history_query .field_help_link 
+{
+  display: block;
+  text-align: left;
+}
+
+#chart .section_help {
+  font-size: 0.8em; 
+  font-weight: normal
+}
+
+#bug_id_container .field_help {
+  font-size: 0.75em
+}
+
+.search_field_row {
+  white-space: nowrap;
+  margin-bottom: 0.5em;
+}
+
+.search_field_row .container_date_from, .search_field_row .container_date_to {
+  display: inline;
+}
+
+#summary_field.search_field_row {
+  display: block;
+}
+
+#summary_field.search_field_row input, 
+#summary_field.search_field_row select
+{
+  display: inline;
+  padding-bottom: 0;
+  vertical-align: middle;
+}
+
+.search_field_row .field_label, #field_label_short_desc  {
+  width: 14em;
+  display: inline-block;
+  line-height: 2em;
+  margin-right: 0.8em;
+}
+
+#field_label_short_desc {
+  text-align: right;
+}
+
+#summary_field.search_field_row {
+  width: inherit;
+}
+
+#keyword_container {
+  padding-bottom: 0;
+}
+
+.search_field_grid .field_label,
+.search_field_grid .field_label
+ {
+  display: block;
+  padding-bottom: 1ex;
+}
+
+.search_field_grid select {
+  width: 17em;
+  height: 15ex;
+}
+
+.search_field_grid, .search_field_row {
+  padding-left: 1.5em;
+}
+
+.search_email_fields {
+  display: inline-block;
+  width: 14.5em;
+  padding-left: 1.5em;
+}
+
+ul.bug_changes {
+  margin: 0;
+  padding: 0;
+}
+
+ul.bug_changes li {
+  display: inline-block;
+  width: 14.5em;
+  vertical-align: top;
+  padding-left: 1.5em;
+}
+
+ul.bug_changes select {
+  width: 15em;
+}
+
+ul.bug_changes li label {
+   display: block;
+}
+
+div.bz_section_title {
+  display: block;
+  margin-top: 2em;
+  font-size: 1.2em;
+}
+
+div.bz_section_title a {
+  font-weight: bold;    
+}
+
+div.bz_section_title span {
+  font-size: 0.75em;
+  margin-left: 1em;    
+}  
+
+#summary_field label {
+  font-weight: bold;
+}
+
+#queryform, #reportform {
+  margin-bottom: 2em;
+}
+
+#knob {
+  margin-top: 2em;
+}
+
+.hide_people_filter #people_filter_section, 
+.hide_history_filter #history_filter_section, 
+.hide_detailed_information #detailed_information_section 
+{
+  display: none;
+}
+
+.arrow {
+  display: inline;
+  width: 16px;
+  height: 16px;
+}
+
+.bz_search_section, ul.bz_search_section {
+  margin-top: 1em;
+}
+
+.bz_simple_search_form th {
+  text-align: right;
+}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinsstandardshow_bugcss"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/skins/standard/show_bug.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/standard/show_bug.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/standard/show_bug.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -7,14 +7,28 @@
</span><span class="cx">     font-weight: bold;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-.bz_column_spacer {
-    width: 2em;
</del><ins>+.bz_bug .edit_form {
+  width: 100%;
</ins><span class="cx"> }
</span><ins>+.bz_bug .edit_form table {
+  width: 100%;
+}
+.bz_bug #alias {
+    min-width: 0;
+    width: 10em;
+}
</ins><span class="cx"> 
</span><del>-.bz_default_hidden {
-    display: none;
</del><ins>+.flags_label {
+    text-align: left;
</ins><span class="cx"> }
</span><ins>+table#flags {
+    width: auto;
+}
</ins><span class="cx"> 
</span><ins>+.bz_column_spacer {
+    width: 0.5em;
+}
+
</ins><span class="cx"> .related_actions {
</span><span class="cx">     font-size: 0.85em; 
</span><span class="cx">     float: right;
</span><span class="lines">@@ -36,11 +50,30 @@
</span><span class="cx">     height: 1em;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-#duplicate_settings, #votes_container {
</del><ins>+#duplicate_settings {
</ins><span class="cx">     white-space: nowrap;
</span><del>-    
</del><span class="cx"> }
</span><span class="cx"> 
</span><ins>+#bz_big_form_parts td {
+    vertical-align: top;
+}
+
+.bz_group_visibility_section {
+    margin-left: 1em;
+}
+
+.bz_group_visibility_section .instructions {
+    font-style: italic;
+}
+
+#bz_restrict_group_visibility_help .instructions {
+    margin-top: 0;
+}
+
+#bz_enable_role_visibility_help {
+    margin-top: 1em;
+}
+
</ins><span class="cx"> .bz_time_tracking_table {
</span><span class="cx">     border-collapse: collapse;
</span><span class="cx"> }
</span><span class="lines">@@ -61,6 +94,9 @@
</span><span class="cx"> .bz_time_tracking_table .bz_summarize_time {
</span><span class="cx">     text-align: right;
</span><span class="cx"> }
</span><ins>+.bz_time_tracking_table #deadline {
+    width: 7em;
+}
</ins><span class="cx"> 
</span><span class="cx"> #summary tr td { 
</span><span class="cx">     vertical-align:top;
</span><span class="lines">@@ -70,6 +106,13 @@
</span><span class="cx">     margin-bottom: 3ex;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-#knob-buttons {
</del><ins>+.knob-buttons {
</ins><span class="cx">     float: right;
</span><span class="cx"> }
</span><ins>+
+.text_input, .bz_userfield, #keyword_container {
+    width: 100%;
+}
+.bz_bug .bz_alias_short_desc_container {
+    width: inherit;
+}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgskinsstandardvotingcss"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/skins/standard/voting.css (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/skins/standard/voting.css        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/skins/standard/voting.css        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,24 +0,0 @@
</span><del>-/* The contents of this file are subject to the Mozilla Public
-  * License Version 1.1 (the &quot;License&quot;); you may not use this file
-  * except in compliance with the License. You may obtain a copy of
-  * the License at http://www.mozilla.org/MPL/
-  *
-  * Software distributed under the License is distributed on an &quot;AS
-  * IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
-  * implied. See the License for the specific language governing
-  * rights and limitations under the License.
-  *
-  * The Original Code is the Bugzilla Bug Tracking System.
-  *
-  * Contributor(s): Gavin Shelley &lt;bugzilla@chimpychompy.org&gt;
-  */
-
-/* Highlight the row for the bug being voted on */
-tr.bz_bug_being_voted_on {
-    background-color: #e2e2e2;
-}
-
-tr.bz_bug_being_voted_on td {
-    border-style: solid none solid none;
-    border-width: thin;
-}
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgsummarize_timecgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/summarize_time.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/summarize_time.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/summarize_time.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -232,6 +232,20 @@
</span><span class="cx">     return $bugs;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+# Return 1st day of the month of the earliest activity date for a given list of bugs.
+sub get_earliest_activity_date {
+    my ($bugids) = @_;
+    my $dbh = Bugzilla-&gt;dbh;
+
+    my ($date) = $dbh-&gt;selectrow_array(
+        'SELECT ' . $dbh-&gt;sql_date_format('MIN(bug_when)', '%Y-%m-01')
+       . ' FROM longdescs
+          WHERE ' . $dbh-&gt;sql_in('bug_id', $bugids)
+                  . ' AND work_time &gt; 0');
+
+    return $date;
+}
+
</ins><span class="cx"> #
</span><span class="cx"> # Template code starts here
</span><span class="cx"> #
</span><span class="lines">@@ -245,13 +259,13 @@
</span><span class="cx"> 
</span><span class="cx"> Bugzilla-&gt;switch_to_shadow_db();
</span><span class="cx"> 
</span><del>-$user-&gt;in_group(Bugzilla-&gt;params-&gt;{&quot;timetrackinggroup&quot;})
</del><ins>+$user-&gt;is_timetracker
</ins><span class="cx">     || ThrowUserError(&quot;auth_failure&quot;, {group  =&gt; &quot;time-tracking&quot;,
</span><span class="cx">                                        action =&gt; &quot;access&quot;,
</span><span class="cx">                                        object =&gt; &quot;timetracking_summaries&quot;});
</span><span class="cx"> 
</span><del>-my @ids = split(&quot;,&quot;, $cgi-&gt;param('id'));
-map { ValidateBugID($_) } @ids;
</del><ins>+my @ids = split(&quot;,&quot;, $cgi-&gt;param('id') || '');
+@ids = map { Bugzilla::Bug-&gt;check($_)-&gt;id } @ids;
</ins><span class="cx"> scalar(@ids) || ThrowUserError('no_bugs_chosen', {action =&gt; 'view'});
</span><span class="cx"> 
</span><span class="cx"> my $group_by = $cgi-&gt;param('group_by') || &quot;number&quot;;
</span><span class="lines">@@ -279,17 +293,17 @@
</span><span class="cx">     $start_date = trim $cgi-&gt;param('start_date');
</span><span class="cx">     $end_date = trim $cgi-&gt;param('end_date');
</span><span class="cx"> 
</span><ins>+    foreach my $date ($start_date, $end_date) {
+        next unless $date;
+        validate_date($date)
+          || ThrowUserError('illegal_date', {date =&gt; $date, format =&gt; 'YYYY-MM-DD'});
+    }
</ins><span class="cx">     # Swap dates in case the user put an end_date before the start_date
</span><span class="cx">     if ($start_date &amp;&amp; $end_date &amp;&amp; 
</span><span class="cx">         str2time($start_date) &gt; str2time($end_date)) {
</span><span class="cx">         $vars-&gt;{'warn_swap_dates'} = 1;
</span><span class="cx">         ($start_date, $end_date) = ($end_date, $start_date);
</span><span class="cx">     }
</span><del>-    foreach my $date ($start_date, $end_date) {
-        next unless $date;
-        validate_date($date)
-          || ThrowUserError('illegal_date', {date =&gt; $date, format =&gt; 'YYYY-MM-DD'});
-    }
</del><span class="cx"> 
</span><span class="cx">     # Store dates in a session cookie so re-visiting the page
</span><span class="cx">     # for other bugs keeps them around.
</span><span class="lines">@@ -301,16 +315,14 @@
</span><span class="cx">     # Break dates apart into months if necessary; if not, we use the
</span><span class="cx">     # same @parts list to allow us to use a common codepath.
</span><span class="cx">     if ($monthly) {
</span><del>-        # unfortunately it's not too easy to guess a start date, since
-        # it depends on what bugs we're looking at. We risk bothering
-        # the user here. XXX: perhaps run a query to see what the
-        # earliest activity in longdescs for all bugs and use that as a
-        # start date.
-        $start_date || ThrowUserError(&quot;illegal_date&quot;, {'date' =&gt; $start_date});
-        # we can, however, provide a default end date. Note that this
-        # differs in semantics from the open-ended queries we use when
-        # start/end_date aren't provided -- and clock skews will make
-        # this evident!
</del><ins>+        # Calculate the earliest activity date if the user doesn't
+        # specify a start date.
+        if (!$start_date) {
+            $start_date = get_earliest_activity_date(\@bugs);
+        }
+        # Provide a default end date. Note that this differs in semantics
+        # from the open-ended queries we use when start/end_date aren't
+        # provided -- and clock skews will make this evident!
</ins><span class="cx">         @parts = split_by_month($start_date, 
</span><span class="cx">                                 $end_date || format_time(scalar localtime(time()), '%Y-%m-%d'));
</span><span class="cx">     } else {
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgt001compilet"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/t/001compile.t (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/t/001compile.t        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/t/001compile.t        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -13,11 +13,11 @@
</span><span class="cx"> # The Original Code are the Bugzilla Tests.
</span><span class="cx"> # 
</span><span class="cx"> # The Initial Developer of the Original Code is Zach Lipton
</span><del>-# Portions created by Zach Lipton are 
-# Copyright (C) 2001 Zach Lipton.  All
-# Rights Reserved.
</del><ins>+# Portions created by Zach Lipton are Copyright (C) 2001 Zach Lipton.
+# All Rights Reserved.
</ins><span class="cx"> # 
</span><span class="cx"> # Contributor(s): Zach Lipton &lt;zach@zachlipton.com&gt;
</span><ins>+#                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> #################
</span><span class="lines">@@ -25,92 +25,82 @@
</span><span class="cx"> ###Compilation###
</span><span class="cx"> 
</span><span class="cx"> use strict;
</span><ins>+use 5.008001;
+use lib qw(. lib t);
+use Config;
+use Support::Files;
+use Test::More tests =&gt; scalar(@Support::Files::testitems);
</ins><span class="cx"> 
</span><del>-use lib 't';
</del><ins>+BEGIN { 
+    use_ok('Bugzilla::Constants');
+    use_ok('Bugzilla::Install::Requirements');
+    use_ok('Bugzilla');
+}
</ins><span class="cx"> 
</span><del>-use Support::Files;
</del><ins>+sub compile_file {
+    my ($file) = @_;
</ins><span class="cx"> 
</span><del>-use Test::More tests =&gt; scalar(@Support::Files::testitems);
</del><ins>+    # Don't allow CPAN.pm to modify the global @INC, which the version
+    # shipped with Perl 5.8.8 does. (It gets loaded by 
+    # Bugzilla::Install::CPAN.)
+    local @INC = @INC;
</ins><span class="cx"> 
</span><del>-# Need this to get the available driver information
-use DBI;
-my @DBI_drivers = DBI-&gt;available_drivers;
</del><ins>+    if ($file =~ s/\.pm$//) {
+        $file =~ s{/}{::}g;
+        use_ok($file);
+        return;
+    }
</ins><span class="cx"> 
</span><del>-# Bugzilla requires Perl 5.8.1 now.  Checksetup will tell you this if you run it, but
-# it tests it in a polite/passive way that won't make it fail at compile time.  We'll
-# slip in a compile-time failure if it's missing here so a tinderbox on &lt; 5.8.1 won't
-# pass and mistakenly let people think Bugzilla works on any perl below 5.8.1.
-require 5.008001;
</del><ins>+    open(my $fh, $file);
+    my $bang = &lt;$fh&gt;;
+    close $fh;
</ins><span class="cx"> 
</span><del>-# Capture the TESTOUT from Test::More or Test::Builder for printing errors.
-# This will handle verbosity for us automatically.
-my $fh;
-{
-    local $^W = 0;  # Don't complain about non-existent filehandles
-    if (-e \*Test::More::TESTOUT) {
-        $fh = \*Test::More::TESTOUT;
-    } elsif (-e \*Test::Builder::TESTOUT) {
-        $fh = \*Test::Builder::TESTOUT;
-    } else {
-        $fh = \*STDOUT;
</del><ins>+    my $T = &quot;&quot;;
+    if ($bang =~ m/#!\S*perl\s+-.*T/) {
+        $T = &quot;T&quot;;
</ins><span class="cx">     }
</span><ins>+
+    my $libs = '';
+    if ($ENV{PERL5LIB}) {
+       $libs = join &quot; &quot;, map { &quot;-I\&quot;$_\&quot;&quot; } split /$Config{path_sep}/, $ENV{PERL5LIB};
+    }
+    my $perl = qq{&quot;$^X&quot;};
+    my $output = `$perl $libs -wc$T $file 2&gt;&amp;1`;
+    chomp($output);
+    my $return_val = $?;
+    $output =~ s/^\Q$file\E syntax OK$//ms;
+    diag($output) if $output;
+    ok(!$return_val, $file) or diag('--ERROR');
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> my @testitems = @Support::Files::testitems;
</span><del>-my $perlapp = &quot;\&quot;$^X\&quot;&quot;;
</del><ins>+my $file_features = map_files_to_features();
</ins><span class="cx"> 
</span><span class="cx"> # Test the scripts by compiling them
</span><del>-
</del><span class="cx"> foreach my $file (@testitems) {
</span><del>-    $file =~ s/\s.*$//; # nuke everything after the first space (#comment)
-    next if (!$file); # skip null entries
-
-    # Skip mod_perl.pl in all cases. It doesn't compile correctly from the command line.
-    if ($file eq 'mod_perl.pl') {
-        ok(1, &quot;Skipping mod_perl.pl&quot;);
-        next;
-    }
-
-    # Check that we have a DBI module to support the DB, if this is a database
-    # module (but not Schema)
-    if ($file =~ m#Bugzilla/DB/([^/]+)\.pm$# &amp;&amp; $file ne &quot;Bugzilla/DB/Schema.pm&quot;) {
-        if (!grep(lc($_) =~ /$1/i, @DBI_drivers)) {
-            ok(1,$file.&quot; - Skipping, as the DBD module not installed&quot;);
-            next;
</del><ins>+    # These were already compiled, above.
+    next if ($file eq 'Bugzilla.pm' 
+             or $file eq 'Bugzilla/Constants.pm'
+             or $file eq 'Bugzilla/Install/Requirements.pm');
+    SKIP: {
+        if ($file eq 'mod_perl.pl') {
+            skip 'mod_perl.pl cannot be compiled from the command line', 1;
</ins><span class="cx">         }
</span><del>-    }
</del><ins>+        my $feature = $file_features-&gt;{$file};
+        if ($feature and !Bugzilla-&gt;feature($feature)) {
+            skip &quot;$file: $feature not enabled&quot;, 1;
+        }
</ins><span class="cx"> 
</span><del>-    open (FILE,$file);
-    my $bang = &lt;FILE&gt;;
-    close (FILE);
-    my $T = &quot;&quot;;
-    if ($bang =~ m/#!\S*perl\s+-.*T/) {
-        $T = &quot;T&quot;;
-    }
-    my $command = &quot;$perlapp -c$T $file 2&gt;&amp;1&quot;;
-    my $loginfo=`$command`;
-    #print '@@'.$loginfo.'##';
-    if ($loginfo =~ /syntax ok$/im) {
-        # Special hack due to CPAN.pm on Windows with Cygwin installed throwing
-        # strings of the form &quot;Set up gcc environment - 3.4.4 (cygming special,
-        # gdc 0.12, using dmd 0.125)&quot;. See bug 416047 for details.
-        if ($^O =~ /MSWin32/i
-            &amp;&amp; grep($_ eq $file, 'install-module.pl', 'Bugzilla/Install/CPAN.pm'))
</del><ins>+        # Check that we have a DBI module to support the DB, if this 
+        # is a database module (but not Schema)
+        if ($file =~ m{Bugzilla/DB/([^/]+)\.pm$}
+            and $file ne &quot;Bugzilla/DB/Schema.pm&quot;) 
</ins><span class="cx">         {
</span><del>-            $loginfo =~ s/^Set up gcc environment.*?\n//;
</del><ins>+            my $module = lc($1);
+            my $dbd = DB_MODULE-&gt;{$module}-&gt;{dbd}-&gt;{module};
+            eval(&quot;use $dbd; 1&quot;) or skip &quot;$file: $dbd not installed&quot;, 1;
</ins><span class="cx">         }
</span><del>-        if ($loginfo ne &quot;$file syntax OK\n&quot;) {
-            ok(0,$file.&quot; --WARNING&quot;);
-            print $fh $loginfo;
-        }
-        else {
-            ok(1,$file);
-        }
</del><ins>+
+        compile_file($file);
</ins><span class="cx">     }
</span><del>-    else {
-        ok(0,$file.&quot; --ERROR&quot;);
-        print $fh $loginfo;
-    }
</del><span class="cx"> }      
</span><del>-
-exit 0;
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgt002goodperlt"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/t/002goodperl.t (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/t/002goodperl.t        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/t/002goodperl.t        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -66,7 +66,7 @@
</span><span class="cx">             next;
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if ($file_line1 =~ m#^\#\!/usr/bin/perl\s#) {
</del><ins>+        if ($file_line1 =~ m#^\#\!/usr/bin/env perl\s#) {
</ins><span class="cx">             if ($file_line1 =~ m#\s-$flags#) {
</span><span class="cx">                 ok(1,&quot;$file uses standard perl location and -$flags&quot;);
</span><span class="cx">             } else {
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgt004templatet"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/t/004template.t (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/t/004template.t        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/t/004template.t        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -38,8 +38,7 @@
</span><span class="cx"> 
</span><span class="cx"> use File::Spec;
</span><span class="cx"> use Template;
</span><del>-use Test::More tests =&gt; ( scalar(@referenced_files) * scalar(@languages)
-                        + $num_actual_files );
</del><ins>+use Test::More tests =&gt; ( scalar(@referenced_files) + $num_actual_files );
</ins><span class="cx"> 
</span><span class="cx"> # Capture the TESTOUT from Test::More or Test::Builder for printing errors.
</span><span class="cx"> # This will handle verbosity for us automatically.
</span><span class="lines">@@ -55,27 +54,17 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-# Checks whether one of the passed files exists
-sub existOnce {
-  foreach my $file (@_) {
-    return $file  if -e $file;
-  }
-  return 0;
-}
</del><ins>+# Check to make sure all templates that are referenced in Bugzilla
+# exist in the proper place in the English template directory.
+# All other languages may or may not include any template as Bugzilla will
+# fall back to English if necessary.
</ins><span class="cx"> 
</span><del>-# Check to make sure all templates that are referenced in
-# Bugzilla exist in the proper place.
-
-foreach my $lang (@languages) {
-    foreach my $file (@referenced_files) {
-        my @path = map(File::Spec-&gt;catfile($_, $file),
-                       split(':', $include_path{$lang} . &quot;:&quot; . $include_path{&quot;en&quot;}));
-        if (my $path = existOnce(@path)) {
-            ok(1, &quot;$path exists&quot;);
-        } else {
-            ok(0, &quot;$file cannot be located --ERROR&quot;);
-            print $fh &quot;Looked in:\n  &quot; . join(&quot;\n  &quot;, @path) . &quot;\n&quot;;
-        }
</del><ins>+foreach my $file (@referenced_files) {
+    my $path = File::Spec-&gt;catfile($english_default_include_path, $file);
+    if (-e $path) {
+        ok(1, &quot;$path exists&quot;);
+    } else {
+        ok(0, &quot;$path cannot be located --ERROR&quot;);
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -117,19 +106,17 @@
</span><span class="cx"> 
</span><span class="cx">     foreach my $file (@{$actual_files{$include_path}}) {
</span><span class="cx">         my $path = File::Spec-&gt;catfile($include_path, $file);
</span><del>-        if (-e $path) {
-            my ($data, $err) = $provider-&gt;fetch($file);
</del><span class="cx"> 
</span><del>-            if (!$err) {
-                ok(1, &quot;$file syntax ok&quot;);
-            }
-            else {
-                ok(0, &quot;$file has bad syntax --ERROR&quot;);
-                print $fh $data . &quot;\n&quot;;
-            }
</del><ins>+        # These are actual files, so there's no need to check for existence.
+
+        my ($data, $err) = $provider-&gt;fetch($file);
+
+        if (!$err) {
+            ok(1, &quot;$path syntax ok&quot;);
</ins><span class="cx">         }
</span><span class="cx">         else {
</span><del>-            ok(1, &quot;$path doesn't exist, skipping test&quot;);
</del><ins>+            ok(0, &quot;$path has bad syntax --ERROR&quot;);
+            print $fh $data . &quot;\n&quot;;
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgt005no_tabst"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/t/005no_tabs.t (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/t/005no_tabs.t        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/t/005no_tabs.t        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,55 +0,0 @@
</span><del>-# -*- Mode: perl; indent-tabs-mode: nil -*-
-#
-# The contents of this file are subject to the Mozilla Public
-# License Version 1.1 (the &quot;License&quot;); you may not use this file
-# except in compliance with the License. You may obtain a copy of
-# the License at http://www.mozilla.org/MPL/
-#
-# Software distributed under the License is distributed on an &quot;AS
-# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
-# implied. See the License for the specific language governing
-# rights and limitations under the License.
-#
-# The Original Code are the Bugzilla tests.
-#
-# The Initial Developer of the Original Code is Jacob Steenhagen.
-# Portions created by Jacob Steenhagen are
-# Copyright (C) 2001 Jacob Steenhagen. All
-# Rights Reserved.
-#
-# Contributor(s): Jacob Steenhagen &lt;jake@bugzilla.org&gt;
-#                 David D. Kilzer &lt;ddkilzer@kilzer.net&gt;
-#
-
-#################
-#Bugzilla Test 5#
-#####no_tabs#####
-
-use strict;
-
-use lib 't';
-
-use Support::Files;
-use Support::Templates;
-
-use File::Spec;
-use Test::More tests =&gt; (  scalar(@Support::Files::testitems)
-                         + $Support::Templates::num_actual_files);
-
-my @testitems = @Support::Files::testitems;
-for my $path (@Support::Templates::include_paths) {
-   push(@testitems, map(File::Spec-&gt;catfile($path, $_),
-                        Support::Templates::find_actual_files($path)));
-}
-
-foreach my $file (@testitems) {
-    open (FILE, &quot;$file&quot;);
-    if (grep /\t/, &lt;FILE&gt;) {
-        ok(0, &quot;$file contains tabs --WARNING&quot;);
-    } else {
-        ok(1, &quot;$file has no tabs&quot;);
-    }
-    close (FILE);
-}
-
-exit 0;
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgt005whitespacetfromrev173253trunkWebsitesbugswebkitorgt005no_tabst"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/t/005whitespace.t (from rev 173253, trunk/Websites/bugs.webkit.org/t/005no_tabs.t) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/t/005whitespace.t                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/t/005whitespace.t        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,82 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code are the Bugzilla tests.
+#
+# The Initial Developer of the Original Code is Jacob Steenhagen.
+# Portions created by Jacob Steenhagen are
+# Copyright (C) 2001 Jacob Steenhagen. All
+# Rights Reserved.
+#
+# Contributor(s): Jacob Steenhagen &lt;jake@bugzilla.org&gt;
+#                 David D. Kilzer &lt;ddkilzer@kilzer.net&gt;
+#                 Colin Ogilvie &lt;mozilla@colinogilvie.co.uk&gt;
+#                 Marc Schumann &lt;wurblzap@gmail.com&gt;
+#
+
+#################
+#Bugzilla Test 5#
+#####no_tabs#####
+
+use strict;
+
+use lib 't';
+
+use Support::Files;
+use Support::Templates;
+
+use File::Spec;
+use Test::More tests =&gt; (  scalar(@Support::Files::testitems)
+                         + $Support::Templates::num_actual_files) * 3;
+
+my @testitems = @Support::Files::testitems;
+for my $path (@Support::Templates::include_paths) {
+   push(@testitems, map(File::Spec-&gt;catfile($path, $_),
+                        Support::Templates::find_actual_files($path)));
+}
+
+my %results;
+
+foreach my $file (@testitems) {
+    open (FILE, &quot;$file&quot;);
+    my @contents = &lt;FILE&gt;;
+    if (grep /\t/, @contents) {
+        ok(0, &quot;$file contains tabs --WARNING&quot;);
+    } else {
+        ok(1, &quot;$file has no tabs&quot;);
+    }
+    close (FILE);
+}
+
+foreach my $file (@testitems) {
+    open (FILE, &quot;$file&quot;);
+    my @contents = &lt;FILE&gt;;
+    if (grep /\r/, @contents) {
+        ok(0, &quot;$file contains non-OS-conformant line endings --WARNING&quot;);
+    } else {
+        ok(1, &quot;All line endings of $file are OS conformant&quot;);
+    }
+    close (FILE);
+}
+
+foreach my $file (@testitems) {
+    open (FILE, &quot;$file&quot;);
+    my $first_line = &lt;FILE&gt;;
+    if ($first_line =~ /\xef\xbb\xbf/) {
+        ok(0, &quot;$file contains Byte Order Mark --WARNING&quot;);
+    } else {
+        ok(1, &quot;$file is free of a Byte Order Mark&quot;);
+    }
+    close (FILE);
+}
+
+exit 0;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgt007utilt"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/t/007util.t (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/t/007util.t        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/t/007util.t        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -13,52 +13,75 @@
</span><span class="cx"> # The Original Code are the Bugzilla Tests.
</span><span class="cx"> # 
</span><span class="cx"> # The Initial Developer of the Original Code is Zach Lipton
</span><del>-# Portions created by Zach Lipton are 
-# Copyright (C) 2002 Zach Lipton.  All
-# Rights Reserved.
</del><ins>+# Portions created by Zach Lipton are Copyright (C) 2002 Zach Lipton.
+# All Rights Reserved.
</ins><span class="cx"> # 
</span><span class="cx"> # Contributor(s): Zach Lipton &lt;zach@zachlipton.com&gt;
</span><ins>+#                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+#                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
</ins><span class="cx"> 
</span><del>-
</del><span class="cx"> #################
</span><span class="cx"> #Bugzilla Test 7#
</span><span class="cx"> #####Util.pm#####
</span><span class="cx"> 
</span><span class="cx"> use lib 't';
</span><span class="cx"> use Support::Files;
</span><ins>+use Test::More tests =&gt; 15;
</ins><span class="cx"> 
</span><span class="cx"> BEGIN { 
</span><del>-        use Test::More tests =&gt; 12;
-        use_ok(Bugzilla);
-        use_ok(Bugzilla::Util);
</del><ins>+    use_ok(Bugzilla);
+    use_ok(Bugzilla::Util);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-# We need to override Bugzilla-&gt;params so we can get an expected value when
-# Bugzilla::Util::format_time() calls ask for the 'timezone' parameter.
-# This will also prevent the tests from failing on site that do not have a
-# data/params file containing 'timezone' yet.
-Bugzilla-&gt;params-&gt;{'timezone'} = &quot;TEST&quot;;
</del><ins>+# We need to override user preferences so we can get an expected value when
+# Bugzilla::Util::format_time() calls ask for the 'timezone' user preference.
+Bugzilla-&gt;user-&gt;{'settings'}-&gt;{'timezone'}-&gt;{'value'} = &quot;local&quot;;
</ins><span class="cx"> 
</span><ins>+# We need to know the local timezone for the date chosen in our tests.
+# Below, tests are run against Nov. 24, 2002.
+my $tz = Bugzilla-&gt;local_timezone-&gt;short_name_for_datetime(DateTime-&gt;new(year =&gt; 2002, month =&gt; 11, day =&gt; 24));
+
</ins><span class="cx"> # we don't test the taint functions since that's going to take some more work.
</span><span class="cx"> # XXX: test taint functions
</span><span class="cx"> 
</span><span class="cx"> #html_quote():
</span><del>-is(html_quote(&quot;&lt;lala&amp;&gt;&quot;),&quot;&amp;lt;lala&amp;amp;&amp;gt;&quot;,'html_quote');
</del><ins>+is(html_quote(&quot;&lt;lala&amp;@&gt;&quot;),&quot;&amp;lt;lala&amp;amp;&amp;#64;&amp;gt;&quot;,'html_quote');
</ins><span class="cx"> 
</span><span class="cx"> #url_quote():
</span><span class="cx"> is(url_quote(&quot;&lt;lala&amp;&gt;gaa\&quot;'[]{\\&quot;),&quot;%3Clala%26%3Egaa%22%27%5B%5D%7B%5C&quot;,'url_quote');
</span><span class="cx"> 
</span><del>-#lsearch():
-my @list = ('apple','pear','plum','&lt;&quot;\\%');
-is(lsearch(\@list,'pear'),1,'lsearch 1');
-is(lsearch(\@list,'&lt;&quot;\\%'),3,'lsearch 2');
-is(lsearch(\@list,'kiwi'),-1,'lsearch 3 (missing item)');
-
</del><span class="cx"> #trim():
</span><span class="cx"> is(trim(&quot; fg&lt;*\$%&gt;+=~~ &quot;),'fg&lt;*$%&gt;+=~~','trim()');
</span><span class="cx"> 
</span><span class="cx"> #format_time();
</span><del>-is(format_time(&quot;2002.11.24 00:05&quot;),'2002-11-24 00:05 TEST','format_time(&quot;2002.11.24 00:05&quot;)');
-is(format_time(&quot;2002.11.24 00:05:56&quot;),'2002-11-24 00:05:56 TEST','format_time(&quot;2002.11.24 00:05:56&quot;)');
</del><ins>+is(format_time(&quot;2002.11.24 00:05&quot;), &quot;2002-11-24 00:05 $tz&quot;,'format_time(&quot;2002.11.24 00:05&quot;) is ' . format_time(&quot;2002.11.24 00:05&quot;));
+is(format_time(&quot;2002.11.24 00:05:56&quot;), &quot;2002-11-24 00:05:56 $tz&quot;,'format_time(&quot;2002.11.24 00:05:56&quot;)');
</ins><span class="cx"> is(format_time(&quot;2002.11.24 00:05:56&quot;, &quot;%Y-%m-%d %R&quot;), '2002-11-24 00:05', 'format_time(&quot;2002.11.24 00:05:56&quot;, &quot;%Y-%m-%d %R&quot;) (with no timezone)');
</span><del>-is(format_time(&quot;2002.11.24 00:05:56&quot;, &quot;%Y-%m-%d %R %Z&quot;), '2002-11-24 00:05 TEST', 'format_time(&quot;2002.11.24 00:05:56&quot;, &quot;%Y-%m-%d %R %Z&quot;) (with timezone)');
</del><ins>+is(format_time(&quot;2002.11.24 00:05:56&quot;, &quot;%Y-%m-%d %R %Z&quot;), &quot;2002-11-24 00:05 $tz&quot;, 'format_time(&quot;2002.11.24 00:05:56&quot;, &quot;%Y-%m-%d %R %Z&quot;) (with timezone)');
+
+# email_filter
+my %email_strings = (
+    'somebody@somewhere.com' =&gt; 'somebody',
+    'Somebody &lt;somebody@somewhere.com&gt;' =&gt; 'Somebody &lt;somebody&gt;',
+    'One Person &lt;one@person.com&gt;, Two Person &lt;two@person.com&gt;' 
+        =&gt; 'One Person &lt;one&gt;, Two Person &lt;two&gt;',
+    'This string contains somebody@somewhere.com and also this@that.com'
+        =&gt; 'This string contains somebody and also this',
+);
+foreach my $input (keys %email_strings) {
+    is(Bugzilla::Util::email_filter($input), $email_strings{$input}, 
+       &quot;email_filter('$input')&quot;);
+}
+
+# diff_arrays():
+my @old_array = qw(alpha beta alpha gamma gamma beta alpha delta epsilon gamma);
+my @new_array = qw(alpha alpha beta gamma epsilon delta beta delta);
+# The order is not relevant when comparing both arrays for matching items,
+# i.e. (foo bar) and (bar foo) are the same arrays (same items).
+# But when returning data, we try to respect the initial order.
+# We remove the leftmost items first, and return what's left. This means:
+# Removed (in this order): gamma alpha gamma.
+# Added (in this order): delta
+my ($removed, $added) = diff_arrays(\@old_array, \@new_array);
+is_deeply($removed, [qw(gamma alpha gamma)], 'diff_array(\@old, \@new) (check removal)');
+is_deeply($added, [qw(delta)], 'diff_array(\@old, \@new) (check addition)');
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgt008filtert"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/t/008filter.t (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/t/008filter.t        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/t/008filter.t        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -30,10 +30,11 @@
</span><span class="cx"> # Sample exploit code: '&gt;&quot;&gt;&lt;script&gt;alert('Oh dear...')&lt;/script&gt;
</span><span class="cx"> 
</span><span class="cx"> use strict;
</span><del>-use lib 't';
</del><ins>+use lib qw(. lib t);
</ins><span class="cx"> 
</span><span class="cx"> use vars qw(%safe);
</span><span class="cx"> 
</span><ins>+use Bugzilla::Constants;
</ins><span class="cx"> use Support::Templates;
</span><span class="cx"> use File::Spec;
</span><span class="cx"> use Test::More tests =&gt; $Support::Templates::num_actual_files;
</span><span class="lines">@@ -45,7 +46,7 @@
</span><span class="cx"> $/ = undef;
</span><span class="cx"> 
</span><span class="cx"> foreach my $path (@Support::Templates::include_paths) {
</span><del>-    $path =~ s|\\|/|g if $^O eq 'MSWin32';  # convert \ to / in path if on windows
</del><ins>+    $path =~ s|\\|/|g if ON_WINDOWS;  # convert \ to / in path if on windows
</ins><span class="cx">     $path =~ m|template/([^/]+)/([^/]+)|;
</span><span class="cx">     my $lang = $1;
</span><span class="cx">     my $flavor = $2;
</span><span class="lines">@@ -60,13 +61,9 @@
</span><span class="cx">     chdir $path; # relative path
</span><span class="cx">     
</span><span class="cx">     # We load a %safe list of acceptable exceptions.
</span><del>-    if (!-r &quot;filterexceptions.pl&quot;) {
-        ok(0, &quot;$path has templates but no filterexceptions.pl file. --ERROR&quot;);
-        next;
-    }
-    else {
</del><ins>+    if (-r &quot;filterexceptions.pl&quot;) {
</ins><span class="cx">         do &quot;filterexceptions.pl&quot;;
</span><del>-        if ($^O eq 'MSWin32') {
</del><ins>+        if (ON_WINDOWS) {
</ins><span class="cx">           # filterexceptions.pl uses / separated paths, while 
</span><span class="cx">           # find_actual_files returns \ separated ones on Windows.
</span><span class="cx">           # Here, we convert the filter exception hash to use \.
</span><span class="lines">@@ -85,17 +82,19 @@
</span><span class="cx">     # us to flag which members were not found, and report that as a warning, 
</span><span class="cx">     # thereby keeping the lists clean.
</span><span class="cx">     foreach my $file (keys %safe) {
</span><del>-        my $list = $safe{$file};
-        $safe{$file} = {};
-        foreach my $directive (@$list) {
-            $safe{$file}{$directive} = 0;    
</del><ins>+        if (ref $safe{$file} eq 'ARRAY') {
+            my $list = $safe{$file};
+            $safe{$file} = {};
+            foreach my $directive (@$list) {
+                $safe{$file}{$directive} = 0;    
+            }
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     foreach my $file (@testitems) {
</span><span class="cx">         # There are some files we don't check, because there is no need to
</span><span class="cx">         # filter their contents due to their content-type.
</span><del>-        if ($file =~ /\.(txt|png)\.tmpl$/) {
</del><ins>+        if ($file =~ /\.(pm|txt|png)\.tmpl$/) {
</ins><span class="cx">             ok(1, &quot;($lang/$flavor) $file is filter-safe&quot;);
</span><span class="cx">             next;
</span><span class="cx">         }
</span><span class="lines">@@ -109,7 +108,7 @@
</span><span class="cx"> 
</span><span class="cx">         # /g means we execute this loop for every match
</span><span class="cx">         # /s means we ignore linefeeds in the regexp matches
</span><del>-        while ($slurp =~ /\[%(.*?)%\]/gs) {
</del><ins>+        while ($slurp =~ /\[%(?:-|\+|~|=)?(.*?)(?:-|\+|~|=)?%\]/gs) {
</ins><span class="cx">             my $directive = $1;
</span><span class="cx"> 
</span><span class="cx">             my @lineno = ($` =~ m/\n/gs);
</span><span class="lines">@@ -154,11 +153,11 @@
</span><span class="cx">     my ($file, $directive) = @_;
</span><span class="cx"> 
</span><span class="cx">     # Comments
</span><del>-    return 1 if $directive =~ /^[+-]?#/;        
</del><ins>+    return 1 if $directive =~ /^#/;        
</ins><span class="cx"> 
</span><del>-    # Remove any leading/trailing + or - and whitespace.
-    $directive =~ s/^[+-]?\s*//;
-    $directive =~ s/\s*[+-]?$//;
</del><ins>+    # Remove any leading/trailing whitespace.
+    $directive =~ s/^\s*//;
+    $directive =~ s/\s*$//;
</ins><span class="cx"> 
</span><span class="cx">     # Empty directives are ok; they are usually line break helpers
</span><span class="cx">     return 1 if $directive eq '';
</span><span class="lines">@@ -211,7 +210,7 @@
</span><span class="cx">     return 1 if $directive =~ /^(time2str|url)\(/;
</span><span class="cx"> 
</span><span class="cx">     # Safe Template Toolkit virtual methods
</span><del>-    return 1 if $directive =~ /\.(length$|size$|push\(|delete\()/;
</del><ins>+    return 1 if $directive =~ /\.(length$|size$|push\(|unshift\(|delete\()/;
</ins><span class="cx"> 
</span><span class="cx">     # Special Template Toolkit loop variable
</span><span class="cx">     return 1 if $directive =~ /^loop\.(index|count)$/;
</span><span class="lines">@@ -222,10 +221,10 @@
</span><span class="cx">     # Things which are already filtered
</span><span class="cx">     # Note: If a single directive prints two things, and only one is 
</span><span class="cx">     # filtered, we may not catch that case.
</span><del>-    return 1 if $directive =~ /FILTER\ (html|csv|js|base64|url_quote|css_class_quote|
-                                        ics|quoteUrls|time|uri|xml|lower|html_light|
</del><ins>+    return 1 if $directive =~ /FILTER\ (html|csv|js|base64|css_class_quote|ics|
+                                        quoteUrls|time|uri|xml|lower|html_light|
</ins><span class="cx">                                         obsolete|inactive|closed|unitconvert|
</span><del>-                                        txt|none)\b/x;
</del><ins>+                                        txt|html_linebreak|none)\b/x;
</ins><span class="cx"> 
</span><span class="cx">     return 0;
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgt009bugwordst"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/t/009bugwords.t (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/t/009bugwords.t        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/t/009bugwords.t        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -68,7 +68,7 @@
</span><span class="cx">         my $lineno = scalar(@lineno) + 1;
</span><span class="cx">     
</span><span class="cx">         # &quot;a bug&quot;, &quot;bug&quot;, &quot;bugs&quot;
</span><del>-        if (grep /(a?[\s&gt;]bugs?[\s.:;,])/i, $text) {
</del><ins>+        if (grep /(a?[\s&gt;]bugs?[\s.:;,&lt;])/i, $text) {
</ins><span class="cx">             # Exclude variable assignment.
</span><span class="cx">             unless (grep /bugs =/, $text) {
</span><span class="cx">                 push(@errors, [$lineno, $text]);
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgt010dependenciest"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/t/010dependencies.t (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/t/010dependencies.t        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/t/010dependencies.t        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -21,15 +21,24 @@
</span><span class="cx"> ## dependencies ##
</span><span class="cx"> 
</span><span class="cx"> use strict;
</span><ins>+use lib qw(. lib t);
</ins><span class="cx"> 
</span><del>-use lib 't';
-
</del><span class="cx"> use Support::Files;
</span><span class="cx"> use Test::More qw(no_plan);
</span><span class="cx"> 
</span><span class="cx"> my %mods;
</span><span class="cx"> my %deps;
</span><span class="cx"> 
</span><ins>+use constant MODULE_REGEX =&gt; qr/
+    (?:(?:^\s*use)
+       |
+       (?:^require)
+    )\s+
+    ['&quot;]?
+    ([\w:\.\\]+)
+/x;
+use constant BASE_REGEX =&gt; qr/^use base qw\(([^\)]+)/;
+
</ins><span class="cx"> # Extract all Perl modules.
</span><span class="cx"> foreach my $file (@Support::Files::testitems) {
</span><span class="cx">   if ($file =~ /^(.*)\.pm$/) {
</span><span class="lines">@@ -58,18 +67,19 @@
</span><span class="cx">       if ($line =~ /^package\s+([^;]);/) {
</span><span class="cx">         $module = $1;
</span><span class="cx">       }
</span><del>-      elsif ($line =~ /^\s*(?:use|^require) *&quot;?(Bugzilla.*?)&quot;?(?:;|\s+qw[\(\{]|\s+\(\))/) {
-        my $used = $1;
-        $used =~ s#/#::#g;
-        $used =~ s#\.pm$##;
-        $used =~ s#\$module#[^:]+#;
-        $used =~ s#\${[^}]+}#[^:]+#;
-        $used =~ s#[&quot; ]##g;
-        my $exclude = &quot;&quot;;
-        if    ($used eq 'Bugzilla::Auth::Login::[^:]+' ) { $exclude = 'Bugzilla::Auth::Login::Stack'  }
-        elsif ($used eq 'Bugzilla::Auth::Verify::[^:]+') { $exclude = 'Bugzilla::Auth::Verify::Stack' }
-        elsif ($used eq 'Bugzilla::Config::[^:]+'      ) { $exclude = 'Bugzilla::Config::Common'      }
-        push(@use, grep(/^$used$/, grep(!/^$exclude$/, keys %mods)));
</del><ins>+      elsif ($line =~ BASE_REGEX or $line =~ MODULE_REGEX) {
+        my $used_string = $1;
+        # &quot;use base&quot; can have multiple modules
+        my @used_array = split(/\s+/, $used_string);
+        foreach my $used (@used_array) {
+            next if $used !~ /^Bugzilla/;
+            $used =~ s#/#::#g;
+            $used =~ s#\.pm$##;
+            $used =~ s#\$module#[^:]+#;
+            $used =~ s#\${[^}]+}#[^:]+#;
+            $used =~ s#[&quot; ]##g;
+            push(@use, grep(/^\Q$used\E$/, keys %mods));
+        }
</ins><span class="cx">       }
</span><span class="cx">     }
</span><span class="cx">     close (SOURCE);
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgt012throwablest"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/t/012throwables.t (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/t/012throwables.t        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/t/012throwables.t        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -28,9 +28,9 @@
</span><span class="cx"> ######Errors######
</span><span class="cx"> 
</span><span class="cx"> use strict;
</span><ins>+use lib qw(. lib t);
</ins><span class="cx"> 
</span><del>-use lib 't';
-
</del><ins>+use Bugzilla::Constants;
</ins><span class="cx"> use Bugzilla::WebService::Constants;
</span><span class="cx"> 
</span><span class="cx"> use File::Spec;
</span><span class="lines">@@ -60,7 +60,7 @@
</span><span class="cx">     foreach my $path (@{$actual_files{$include_path}}) {
</span><span class="cx">         my $file = File::Spec-&gt;catfile($include_path, $path);
</span><span class="cx">         $file =~ s/\s.*$//; # nuke everything after the first space
</span><del>-        $file =~ s|\\|/|g if $^O eq 'MSWin32';  # convert \ to / in path if on windows
</del><ins>+        $file =~ s|\\|/|g if ON_WINDOWS;  # convert \ to / in path if on windows
</ins><span class="cx">         $test_templates{$file} = () 
</span><span class="cx">             if $file =~ m#global/(code|user)-error\.html\.tmpl#;
</span><span class="cx">     }
</span><span class="lines">@@ -117,7 +117,7 @@
</span><span class="cx">                                         # Bugzilla/Error.pm)
</span><span class="cx">         $lineno++;
</span><span class="cx">         if ($line =~
</span><del>-/^[^#]*(Throw(Code|User)Error|error\s+=&gt;)\s*\(?\s*[&quot;'](.*?)['&quot;]/) {
</del><ins>+/^[^#]*\b(Throw(Code|User)Error|(user_)?error\s+=&gt;)\s*\(?\s*[&quot;'](.*?)['&quot;]/) {
</ins><span class="cx">             my $errtype;
</span><span class="cx">             # If it's a normal ThrowCode/UserError
</span><span class="cx">             if ($2) {
</span><span class="lines">@@ -125,9 +125,9 @@
</span><span class="cx">             }
</span><span class="cx">             # If it's an AUTH_ERROR tag
</span><span class="cx">             else {
</span><del>-                $errtype = 'code';
</del><ins>+                $errtype = $3 ? 'user' : 'code';
</ins><span class="cx">             }
</span><del>-            my $errtag = $3;
</del><ins>+            my $errtag = $4;
</ins><span class="cx">             push @{$Errors{$errtype}{$errtag}{used_in}{$file}}, $lineno;
</span><span class="cx">         }
</span><span class="cx">     }
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtSupportFilespm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/t/Support/Files.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/t/Support/Files.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/t/Support/Files.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -25,43 +25,15 @@
</span><span class="cx"> 
</span><span class="cx"> use File::Find;
</span><span class="cx"> 
</span><del>-# exclude_deps is a hash of arrays listing the files to be excluded
-# if a module is not available
-#
</del><span class="cx"> @additional_files = ();
</span><del>-%exclude_deps = (
-    'XML::Twig' =&gt; ['importxml.pl'],
-    'Net::LDAP' =&gt; ['Bugzilla/Auth/Verify/LDAP.pm'],
-    'Authen::Radius' =&gt; ['Bugzilla/Auth/Verify/RADIUS.pm'],
-    'Email::Reply' =&gt; ['email_in.pl'],
-    'Email::MIME::Attachment::Stripper' =&gt; ['email_in.pl']
-);
</del><span class="cx"> 
</span><del>-
</del><span class="cx"> @files = glob('*');
</span><span class="cx"> find(sub { push(@files, $File::Find::name) if $_ =~ /\.pm$/;}, 'Bugzilla');
</span><ins>+push(@files, 'extensions/create.pl');
</ins><span class="cx"> 
</span><del>-sub have_pkg {
-    my ($pkg) = @_;
-    my ($msg, $vnum, $vstr);
-    no strict 'refs';
-    eval { my $p; ($p = $pkg . &quot;.pm&quot;) =~ s!::!/!g; require $p; };
-    return !($@);
-}
-
-@exclude_files    = ();
-foreach $dep (keys(%exclude_deps)) {
-    if (!have_pkg($dep)) {
-        push @exclude_files, @{$exclude_deps{$dep}};
-    }
-}
-
</del><span class="cx"> sub isTestingFile {
</span><span class="cx">     my ($file) = @_;
</span><span class="cx">     my $exclude;
</span><del>-    foreach $exclude (@exclude_files) {
-        if ($file eq $exclude) { return undef; } # get rid of excluded files.
-    }
</del><span class="cx"> 
</span><span class="cx">     if ($file =~ /\.cgi$|\.pl$|\.pm$/) {
</span><span class="cx">         return 1;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtSupportTemplatespm"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/t/Support/Templates.pm (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/t/Support/Templates.pm        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/t/Support/Templates.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -29,11 +29,14 @@
</span><span class="cx"> use lib 't';
</span><span class="cx"> use base qw(Exporter);
</span><span class="cx"> @Support::Templates::EXPORT = 
</span><del>-         qw(@languages @include_paths %include_path @referenced_files 
-            %actual_files $num_actual_files);
-use vars qw(@languages @include_paths %include_path @referenced_files 
-            %actual_files $num_actual_files);
</del><ins>+         qw(@languages @include_paths $english_default_include_path
+         %include_path @referenced_files %actual_files $num_actual_files);
+use vars qw(@languages @include_paths $english_default_include_path
+            %include_path @referenced_files %actual_files $num_actual_files);
</ins><span class="cx"> 
</span><ins>+use Bugzilla;
+use Bugzilla::Constants;
+use Bugzilla::Install::Util qw(template_include_path);
</ins><span class="cx"> use Support::Files;
</span><span class="cx"> 
</span><span class="cx"> use File::Find;
</span><span class="lines">@@ -48,6 +51,10 @@
</span><span class="cx"> # All include paths
</span><span class="cx"> @include_paths = ();
</span><span class="cx"> 
</span><ins>+# English default include path
+$english_default_include_path =
+    File::Spec-&gt;catdir(bz_locations()-&gt;{'templatedir'}, 'en', 'default');
+
</ins><span class="cx"> # Files which are referenced in the cgi files
</span><span class="cx"> @referenced_files = ();
</span><span class="cx"> 
</span><span class="lines">@@ -57,31 +64,10 @@
</span><span class="cx"> # total number of actual_files
</span><span class="cx"> $num_actual_files = 0;
</span><span class="cx"> 
</span><del>-# Scan for the template available languages and include paths
-{
-    opendir(DIR, &quot;template&quot;) || die &quot;Can't open  'template': $!&quot;;
-    my @files = grep { /^[a-z-]+$/i } readdir(DIR);
-    closedir DIR;
</del><ins>+# Set the template available languages and include paths
+@languages = @{ Bugzilla-&gt;languages };
+@include_paths = @{ template_include_path({ language =&gt; Bugzilla-&gt;languages }) };
</ins><span class="cx"> 
</span><del>-    foreach my $langdir (@files) {
-        next if($langdir =~ /^CVS$/i);
-
-        my $path = File::Spec-&gt;catdir('template', $langdir, 'custom');
-        my @dirs = ();
-        push(@dirs, $path) if(-d $path);
-        $path = File::Spec-&gt;catdir('template', $langdir, 'extension');
-        push(@dirs, $path) if(-d $path);
-        $path = File::Spec-&gt;catdir('template', $langdir, 'default');
-        push(@dirs, $path) if(-d $path);
-
-        next if(scalar(@dirs) == 0);
-        push(@languages, $langdir);
-        push(@include_paths, @dirs);
-        $include_path{$langdir} = join(&quot;:&quot;,@dirs);
-    }
-}
-
-
</del><span class="cx"> my @files;
</span><span class="cx"> 
</span><span class="cx"> # Local subroutine used with File::Find
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplatecvsignore"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/template/.cvsignore (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/.cvsignore        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/.cvsignore        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,3 +0,0 @@
</span><del>-.htaccess
-de
-es
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateencvsignore"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/template/en/.cvsignore (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/.cvsignore        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/.cvsignore        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,2 +0,0 @@
</span><del>-.htaccess
-custom
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateencustomattachmentcontenttypeshtmltmpl"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/template/en/custom/attachment/content-types.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/custom/attachment/content-types.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/custom/attachment/content-types.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,31 +0,0 @@
</span><del>-[%# The contents of this file are subject to the Mozilla Public
-  # License Version 1.1 (the &quot;License&quot;); you may not use this file
-  # except in compliance with the License. You may obtain a copy of
-  # the License at http://www.mozilla.org/MPL/
-  #
-  # Software distributed under the License is distributed on an &quot;AS
-  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
-  # implied. See the License for the specific language governing
-  # rights and limitations under the License.
-  #
-  # The Original Code is the Bugzilla Bug Tracking System.
-  #
-  # The Initial Developer of the Original Code is Netscape Communications
-  # Corporation. Portions created by Netscape are
-  # Copyright (C) 1998 Netscape Communications Corporation. All
-  # Rights Reserved.
-  #
-  # Contributor(s): Myk Melez &lt;myk@mozilla.org&gt;
-  #%]
-
-          &lt;option value=&quot;text/plain&quot;&gt;plain text (text/plain)&lt;/option&gt;
-          &lt;option value=&quot;text/html&quot;&gt;HTML source (text/html)&lt;/option&gt;
-[%# if WEBKIT_CHANGES %]
-          &lt;option value=&quot;application/xhtml+xml&quot;&gt;XHTML source (application/xhtml+xml)&lt;/option&gt;
-          &lt;option value=&quot;image/svg+xml&quot;&gt;SVG image (image/svg+xml)&lt;/option&gt;
-[%# endif // WEBKIT_CHANGES %]
-          &lt;option value=&quot;application/xml&quot;&gt;XML source (application/xml)&lt;/option&gt;
-          &lt;option value=&quot;image/gif&quot;&gt;GIF image (image/gif)&lt;/option&gt;
-          &lt;option value=&quot;image/jpeg&quot;&gt;JPEG image (image/jpeg)&lt;/option&gt;
-          &lt;option value=&quot;image/png&quot;&gt;PNG image (image/png)&lt;/option&gt;
-          &lt;option value=&quot;application/octet-stream&quot;&gt;binary file (application/octet-stream)&lt;/option&gt;
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateencustomattachmentcreatehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/custom/attachment/create.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/custom/attachment/create.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/custom/attachment/create.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -26,20 +26,28 @@
</span><span class="cx"> [%# Define strings that will serve as the title and header of this page %]
</span><span class="cx"> [% title = BLOCK %]Create New Attachment for [% terms.Bug %] #[% bug.bug_id %][% END %]
</span><span class="cx"> [% header = BLOCK %]Create New Attachment for
</span><del>-  [%+ &quot;$terms.Bug $bug.bug_id&quot; FILTER bug_link(bug.bug_id) FILTER none %][% END %]
</del><ins>+  [%+ &quot;$terms.Bug $bug.bug_id&quot; FILTER bug_link(bug) FILTER none %][% END %]
</ins><span class="cx"> [% subheader = BLOCK %][% bug.short_desc FILTER html %][% END %]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/header.html.tmpl
</span><span class="cx">   title = title
</span><span class="cx">   header = header
</span><span class="cx">   subheader = subheader
</span><del>-  onload=&quot;setContentTypeDisabledState(document.entryform);&quot;
-  style_urls = [ 'skins/standard/create_attachment.css' ]
-  javascript_urls = [ &quot;js/attachment.js&quot; ]
</del><ins>+  style_urls = [ 'skins/standard/attachment.css' ]
+  yui = [ 'autocomplete' ]
+  javascript_urls = [ &quot;js/attachment.js&quot;, 'js/field.js', &quot;js/util.js&quot;, &quot;js/TUI.js&quot; ]
</ins><span class="cx">   doc_section = &quot;attachments.html&quot;
</span><span class="cx"> %]
</span><span class="cx"> 
</span><del>-&lt;form name=&quot;entryform&quot; method=&quot;post&quot; action=&quot;attachment.cgi&quot; enctype=&quot;multipart/form-data&quot;&gt;
</del><ins>+&lt;script type=&quot;text/javascript&quot;&gt;
+&lt;!--
+TUI_hide_default('attachment_text_field');
+--&gt;
+&lt;/script&gt;
+
+&lt;form name=&quot;entryform&quot; method=&quot;post&quot; action=&quot;attachment.cgi&quot;
+      enctype=&quot;multipart/form-data&quot;
+      onsubmit=&quot;return validateAttachmentForm(this)&quot;&gt;
</ins><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;bugid&quot; value=&quot;[% bug.bug_id %]&quot;&gt;
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;insert&quot;&gt;
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% token FILTER html %]&quot;&gt;
</span><span class="lines">@@ -54,8 +62,7 @@
</span><span class="cx">         &lt;em&gt;(optional) Check each existing attachment made obsolete by your new attachment.&lt;/em&gt;&lt;br&gt;
</span><span class="cx">         [% IF attachments.size %]
</span><span class="cx">           [% FOREACH attachment = attachments %]
</span><del>-            [% IF ((attachment.isprivate == 0) || (Param(&quot;insidergroup&quot;)
-              &amp;&amp; user.in_group(Param(&quot;insidergroup&quot;)))) %]
</del><ins>+            [% IF ((attachment.isprivate == 0) || user.is_insider) %]
</ins><span class="cx">               &lt;input type=&quot;checkbox&quot; id=&quot;[% attachment.id %]&quot;
</span><span class="cx">                    name=&quot;obsolete&quot; value=&quot;[% attachment.id %]&quot;&gt;
</span><span class="cx">               &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&amp;amp;action=edit&quot;&gt;[% attachment.id %]: [% attachment.description FILTER html %]&lt;/a&gt;&lt;br&gt;
</span><span class="lines">@@ -77,16 +84,17 @@
</span><span class="cx">           &lt;label for=&quot;takebug&quot;&gt;take [% terms.bug %]&lt;/label&gt;
</span><span class="cx">           [% bug_statuses = [] %]
</span><span class="cx">           [% FOREACH bug_status = bug.status.can_change_to %]
</span><del>-            [% NEXT IF bug_status.name == &quot;UNCONFIRMED&quot; &amp;&amp; !bug.product_obj.votes_to_confirm %]
</del><ins>+            [% NEXT IF bug_status.name == &quot;UNCONFIRMED&quot; 
+                       &amp;&amp; !bug.product_obj.allows_unconfirmed %]
</ins><span class="cx">             [% bug_statuses.push(bug_status) IF bug_status.is_open %]
</span><span class="cx">           [% END %]
</span><span class="cx">           [% IF bug_statuses.size %]
</span><span class="cx">             &lt;label for=&quot;takebug&quot;&gt;and set the [% terms.bug %] status to&lt;/label&gt;
</span><span class="cx">             &lt;select id=&quot;bug_status&quot; name=&quot;bug_status&quot;&gt;
</span><del>-              &lt;option value=&quot;[% bug.status.name FILTER html %]&quot;&gt;[% get_status(bug.status.name) FILTER html %] (current)&lt;/option&gt;
</del><ins>+              &lt;option value=&quot;[% bug.status.name FILTER html %]&quot;&gt;[% display_value(&quot;bug_status&quot;, bug.status.name) FILTER html %] (current)&lt;/option&gt;
</ins><span class="cx">               [% FOREACH bug_status = bug_statuses %]
</span><span class="cx">                 [% NEXT IF bug_status.id == bug.status.id %]
</span><del>-                &lt;option value=&quot;[% bug_status.name FILTER html %]&quot;&gt;[% get_status(bug_status.name) FILTER html %]&lt;/option&gt;
</del><ins>+                &lt;option value=&quot;[% bug_status.name FILTER html %]&quot;&gt;[% display_value(&quot;bug_status&quot;, bug_status.name) FILTER html %]&lt;/option&gt;
</ins><span class="cx">               [% END %]
</span><span class="cx">             &lt;/select&gt;
</span><span class="cx">           [% END %]
</span><span class="lines">@@ -107,17 +115,22 @@
</span><span class="cx">         %]
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><del>-    [% IF (Param(&quot;insidergroup&quot;) &amp;&amp; user.in_group(Param(&quot;insidergroup&quot;))) %]
</del><ins>+    [% IF user.is_insider %]
</ins><span class="cx">       &lt;tr&gt;
</span><span class="cx">         &lt;th&gt;Privacy:&lt;/th&gt;
</span><span class="cx">         &lt;td&gt;
</span><del>-          &lt;em&gt;If the attachment is private, check the box below.&lt;/em&gt;&lt;br&gt;
</del><span class="cx">           &lt;input type=&quot;checkbox&quot; name=&quot;isprivate&quot; id=&quot;isprivate&quot;
</span><span class="cx">           value=&quot;1&quot; onClick=&quot;updateCommentPrivacy(this)&quot;&gt;
</span><del>-        &lt;label for=&quot;isprivate&quot;&gt;Private&lt;/label&gt;
</del><ins>+          &lt;label for=&quot;isprivate&quot;&gt;
+            Make attachment and comment private (visible only to members of
+            the &lt;strong&gt;[% Param('insidergroup') FILTER html %]&lt;/strong&gt;
+            group)
+          &lt;/label&gt;
</ins><span class="cx">         &lt;/td&gt;
</span><span class="cx">       &lt;/tr&gt;
</span><span class="cx">     [% END %]
</span><ins>+
+    [% Hook.process('form_before_submit') %]
</ins><span class="cx"> [%# if WEBKIT_CHANGES %]
</span><span class="cx"> [% IF (bug.product == &quot;WebKit&quot; || bug.product == &quot;Security&quot;) %] 
</span><span class="cx">     &lt;tr id=&quot;legal&quot; style=&quot;visibility: collapse;&quot;&gt;
</span><span class="lines">@@ -136,6 +149,7 @@
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx"> [% END %]
</span><span class="cx"> [%# endif // WEBKIT_CHANGES %]
</span><ins>+
</ins><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th&gt;&amp;nbsp;&lt;/th&gt;
</span><span class="cx">       &lt;td&gt;&lt;input type=&quot;submit&quot; id=&quot;create&quot; value=&quot;Submit&quot;&gt;&lt;/td&gt;
</span><span class="lines">@@ -144,4 +158,6 @@
</span><span class="cx"> 
</span><span class="cx"> &lt;/form&gt;
</span><span class="cx"> 
</span><ins>+[% Hook.process('end') %]
+
</ins><span class="cx"> [% PROCESS global/footer.html.tmpl %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateencustomattachmentcreatedhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/custom/attachment/created.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/custom/attachment/created.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/custom/attachment/created.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -26,23 +26,9 @@
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="cx"> [% bug = bugs.0 %]
</span><del>-[% bodyclasses = ['bz_bug',
-                 &quot;bz_status_$bug.bug_status&quot;,
-                 &quot;bz_component_$bug.component&quot;,
-                 &quot;bz_bug_$bug.bug_id&quot;
-                 ]
-%]
-[% FOREACH group = bug.groups_in %]
-  [% bodyclasses.push(&quot;bz_group_$group.name&quot;) %]
-[% END %]
-
</del><ins>+[% PROCESS &quot;bug/show-header.html.tmpl&quot; %]
</ins><span class="cx"> [% PROCESS global/header.html.tmpl
</span><span class="cx">   title = &quot;Attachment $attachment.id added to $terms.Bug $attachment.bug_id&quot;
</span><del>-  bodyclasses = bodyclasses
-  javascript_urls = [ &quot;js/util.js&quot;, &quot;js/field.js&quot;,
-                      &quot;js/yui/yahoo-dom-event.js&quot;, &quot;js/yui/calendar.js&quot; ]
-  style_urls = [ &quot;skins/standard/yui/calendar.css&quot;, &quot;skins/standard/show_bug.css&quot; ]
-  doc_section = &quot;bug_page.html&quot;
</del><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> &lt;dl&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateencustomattachmentcreateformcontentshtmltmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/custom/attachment/createformcontents.html.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/custom/attachment/createformcontents.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/custom/attachment/createformcontents.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,112 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Netscape Communications
+  # Corporation. Portions created by Netscape are
+  # Copyright (C) 1998 Netscape Communications Corporation. All
+  # Rights Reserved.
+  #
+  # Contributor(s): Myk Melez &lt;myk@mozilla.org&gt;
+  #                 Joel Peshkin &lt;bugreport@peshkin.net&gt;
+  #                 Erik Stambaugh &lt;erik@dasbistro.com&gt;
+  #                 Marc Schumann &lt;wurblzap@gmail.com&gt;
+  #%]
+
+&lt;tr class=&quot;attachment_data&quot;&gt;
+  &lt;th&gt;&lt;label for=&quot;data&quot;&gt;File&lt;/label&gt;:&lt;/th&gt;
+  &lt;td&gt;
+    &lt;em&gt;Enter the path to the file on your computer&lt;/em&gt; (or
+    &lt;a id=&quot;attachment_data_controller&quot; href=&quot;javascript:TUI_toggle_class('attachment_text_field');
+                                             javascript:TUI_toggle_class('attachment_data')&quot;
+    &gt;paste text as attachment&lt;/a&gt;).&lt;br&gt;
+    &lt;input type=&quot;file&quot; id=&quot;data&quot; name=&quot;data&quot; size=&quot;50&quot; onchange=&quot;DataFieldHandler()&quot;&gt;
+  &lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr class=&quot;attachment_text_field&quot;&gt;
+  &lt;th&gt;&lt;label for=&quot;attach_text&quot;&gt;File&lt;/label&gt;:&lt;/th&gt;
+  &lt;td&gt;
+    &lt;em&gt;Paste the text to be added as an attachment&lt;/em&gt; (or
+    &lt;a id=&quot;attachment_text_field_controller&quot; href=&quot;javascript:TUI_toggle_class('attachment_text_field');
+                                                   javascript:TUI_toggle_class('attachment_data')&quot;
+    &gt;attach a file&lt;/a&gt;).&lt;br&gt;
+    &lt;textarea id=&quot;attach_text&quot; name=&quot;attach_text&quot; cols=&quot;80&quot; rows=&quot;15&quot;
+              onkeyup=&quot;TextFieldHandler()&quot; onblur=&quot;TextFieldHandler()&quot;&gt;&lt;/textarea&gt;
+  &lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+  &lt;th class=&quot;required&quot;&gt;&lt;label for=&quot;description&quot;&gt;Description&lt;/label&gt;:&lt;/th&gt;
+  &lt;td&gt;
+    &lt;em&gt;Describe the attachment briefly.&lt;/em&gt;&lt;br&gt;
+    &lt;input type=&quot;text&quot; id=&quot;description&quot; name=&quot;description&quot; class=&quot;required&quot;
+           size=&quot;60&quot; maxlength=&quot;200&quot;&gt;
+  &lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr[% ' class=&quot;expert_fields&quot;' UNLESS bug.id %]&gt;
+  &lt;th&gt;Content Type:&lt;/th&gt;
+  &lt;td&gt;
+    &lt;em&gt;If the attachment is a patch, check the box below.&lt;/em&gt;&lt;br&gt;
+    &lt;input type=&quot;checkbox&quot; id=&quot;ispatch&quot; name=&quot;ispatch&quot; value=&quot;1&quot;
+           onchange=&quot;setContentTypeDisabledState(this.form);&quot;&gt;
+    &lt;label for=&quot;ispatch&quot;&gt;patch&lt;/label&gt;&lt;br&gt;&lt;br&gt;
+    [%# Reset this whenever the page loads so that the JS state is up to date %]
+    &lt;script type=&quot;text/javascript&quot;&gt;
+      YAHOO.util.Event.onDOMReady(function() {
+          bz_fireEvent(document.getElementById('ispatch'), 'change');
+      });
+    &lt;/script&gt;
+
+    &lt;em&gt;Otherwise, choose a method for determining the content type.&lt;/em&gt;&lt;br&gt;
+    &lt;input type=&quot;radio&quot; id=&quot;autodetect&quot;
+           name=&quot;contenttypemethod&quot; value=&quot;autodetect&quot; checked=&quot;checked&quot;&gt;
+      &lt;label for=&quot;autodetect&quot;&gt;auto-detect&lt;/label&gt;&lt;br&gt;
+    &lt;input type=&quot;radio&quot; id=&quot;list&quot;
+           name=&quot;contenttypemethod&quot; value=&quot;list&quot;&gt;
+      &lt;label for=&quot;list&quot;&gt;select from list&lt;/label&gt;:
+      &lt;select name=&quot;contenttypeselection&quot; id=&quot;contenttypeselection&quot;
+              onchange=&quot;this.form.contenttypemethod[1].checked = true;&quot;&gt;
+        [% PROCESS content_types %]
+      &lt;/select&gt;&lt;br&gt;
+    &lt;input type=&quot;radio&quot; id=&quot;manual&quot;
+                 name=&quot;contenttypemethod&quot; value=&quot;manual&quot;&gt;
+      &lt;label for=&quot;manual&quot;&gt;enter manually&lt;/label&gt;:
+      &lt;input type=&quot;text&quot; name=&quot;contenttypeentry&quot; id=&quot;contenttypeentry&quot;
+             size=&quot;30&quot; maxlength=&quot;200&quot;
+             onchange=&quot;if (this.value) this.form.contenttypemethod[2].checked = true;&quot;&gt;
+  &lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr[% ' class=&quot;expert_fields&quot;' UNLESS bug.id %]&gt;
+  &lt;td&gt; &lt;/td&gt;
+  &lt;td&gt;
+    [% IF flag_types &amp;&amp; flag_types.size &gt; 0 %]
+      [% PROCESS &quot;flag/list.html.tmpl&quot; %]&lt;br&gt;
+    [% END %]
+  &lt;/td&gt;
+&lt;/tr&gt;
+
+[% BLOCK content_types %]
+[%# WEBKIT_CHANGES: Added XHTML source and SVG image. %]
+  [% mimetypes = [{type =&gt; &quot;text/plain&quot;, desc =&gt; &quot;plain text&quot;},
+                  {type =&gt; &quot;text/html&quot;,  desc =&gt; &quot;HTML source&quot;},
+                  {type =&gt; &quot;application/xhtml+xml&quot;, desc =&gt; &quot;XHTML source&quot;},
+                  {type =&gt; &quot;image/svg+xml&quot;, desc =&gt; &quot;SVG image&quot;},
+                  {type =&gt; &quot;application/xml&quot;, desc =&gt; &quot;XML source&quot;},
+                  {type =&gt; &quot;image/gif&quot;,  desc =&gt; &quot;GIF image&quot;},
+                  {type =&gt; &quot;image/jpeg&quot;, desc =&gt; &quot;JPEG image&quot;},
+                  {type =&gt; &quot;image/png&quot;,  desc =&gt; &quot;PNG image&quot;},
+                  {type =&gt; &quot;application/octet-stream&quot;, desc =&gt; &quot;binary file&quot;}]
+  %]
+  [% Hook.process(&quot;mimetypes&quot;, &quot;attachment/createformcontents.html.tmpl&quot;) %]
+
+  [% FOREACH m = mimetypes %]
+    &lt;option value=&quot;[% m.type FILTER html %]&quot;&gt;[% m.desc FILTER html %] ([% m.type FILTER html %])&lt;/option&gt;
+  [% END %]
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateencustomattachmentedithtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/custom/attachment/edit.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/custom/attachment/edit.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/custom/attachment/edit.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -17,6 +17,7 @@
</span><span class="cx">   #
</span><span class="cx">   # Contributor(s): Myk Melez &lt;myk@mozilla.org&gt;
</span><span class="cx">   #                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
</span><ins>+  #                 Guy Pyrzak &lt;guy.pyrzak@gmail.com&gt;
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="lines">@@ -29,168 +30,24 @@
</span><span class="cx">   Attachment [% attachment.id %] Details for
</span><span class="cx">   [%+ &quot;$terms.Bug ${attachment.bug_id}&quot; FILTER bug_link(attachment.bug_id) FILTER none %]
</span><span class="cx"> [% END %]
</span><del>-[% subheader = BLOCK %][% bugsummary FILTER html %][% END %]
</del><ins>+[% subheader = BLOCK %][% attachment.bug.short_desc FILTER html %][% END %]
</ins><span class="cx"> 
</span><span class="cx"> [% PROCESS global/header.html.tmpl
</span><span class="cx">   title = title
</span><span class="cx">   header = header
</span><span class="cx">   subheader = subheader
</span><span class="cx">   doc_section = &quot;attachments.html&quot;
</span><ins>+  javascript_urls = ['js/attachment.js', 'js/field.js']
+  style_urls = ['skins/standard/attachment.css']
+  yui = [ 'autocomplete' ]
+  bodyclasses = &quot;no_javascript&quot;
</ins><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> [%# No need to display the Diff button and iframe if the attachment is not a patch. %]
</span><del>-[% patchviewerinstalled = (patchviewerinstalled &amp;&amp; attachment.ispatch) %]
</del><ins>+[% use_patchviewer = (feature_enabled('patch_viewer') &amp;&amp; attachment.ispatch) %]
+[% can_edit = attachment.validate_can_edit %]
+[% editable_or_hide = can_edit ? &quot;&quot; : &quot; bz_hidden_option&quot; %]
</ins><span class="cx"> 
</span><del>-&lt;script type=&quot;text/javascript&quot;&gt;
-  &lt;!--
-  var prev_mode = 'raw';
-  var current_mode = 'raw';
-  var has_edited = 0;
-  var has_viewed_as_diff = 0;
-// if WEBKIT_CHANGES
-  var viewing_formatted_diff = false;
-// endif WEBKIT_CHANGES
-  function editAsComment()
-    {
-      switchToMode('edit');
-      has_edited = 1;
-    }
-  function undoEditAsComment()
-    {
-      switchToMode(prev_mode);
-    }
-  function redoEditAsComment()
-    {
-      switchToMode('edit');
-    }
-// if WEBKIT_CHANGES
-  function viewPrettyPatch()
-    {
-      viewing_formatted_diff = !viewing_formatted_diff;
-      var src = &quot;attachment.cgi?id=[% attachment.id %]&quot;;
-      var buttonText = &quot;View Formatted Diff&quot;;
-      if (viewing_formatted_diff)
-      {
-        src += &quot;&amp;action=prettypatch&quot;
-        buttonText = &quot;View Plain Diff&quot;;
-      }
-
-      document.getElementById('viewFrame').src = src;
-      document.getElementById('viewPrettyPatchButton').innerHTML = buttonText;
-    }
-// endif WEBKIT_CHANGES
-[% IF patchviewerinstalled %]
-  function viewDiff()
-    {
-      switchToMode('diff');
-
-      // If we have not viewed as diff before, set the view diff frame URL
-      if (!has_viewed_as_diff) {
-        var viewDiffFrame = document.getElementById('viewDiffFrame');
-        viewDiffFrame.src =
-            'attachment.cgi?id=[% attachment.id %]&amp;action=diff&amp;headers=0';
-        has_viewed_as_diff = 1;
-      }
-    }
-[% END %]
-  function viewRaw()
-    {
-      switchToMode('raw');
-    }
-
-  function switchToMode(mode)
-    {
-      if (mode == current_mode) {
-        alert('switched to same mode!  This should not happen.');
-        return;
-      }
-
-      // Switch out of current mode
-      if (current_mode == 'edit') {
-        hideElementById('editFrame');
-        hideElementById('undoEditButton');
-      } else if (current_mode == 'raw') {
-        hideElementById('viewFrame');
-[%# if WEBKIT_CHANGES %]
-        hideElementById('viewPrettyPatchButton');
-[%# endif // WEBKIT_CHANGES %]
-[% IF patchviewerinstalled %]
-        hideElementById('viewDiffButton');
-[% END %]
-        hideElementById(has_edited ? 'redoEditButton' : 'editButton');
-        hideElementById('smallCommentFrame');
-      } else if (current_mode == 'diff') {
-[% IF patchviewerinstalled %]
-        hideElementById('viewDiffFrame');
-[% END %]
-        hideElementById('viewRawButton');
-        hideElementById(has_edited ? 'redoEditButton' : 'editButton');
-        hideElementById('smallCommentFrame');
-      }
-
-      // Switch into new mode
-      if (mode == 'edit') {
-        showElementById('editFrame');
-        showElementById('undoEditButton');
-      } else if (mode == 'raw') {
-        showElementById('viewFrame');
-[%# if WEBKIT_CHANGES %]
-        showElementById('viewPrettyPatchButton');
-[%# endif // WEBKIT_CHANGES %]
-[% IF patchviewerinstalled %]
-        showElementById('viewDiffButton');
-[% END %]
-        showElementById(has_edited ? 'redoEditButton' : 'editButton');
-        showElementById('smallCommentFrame');
-      } else if (mode == 'diff') {
-[% IF patchviewerinstalled %]
-        showElementById('viewDiffFrame');
-[% END %]
-        showElementById('viewRawButton');
-        showElementById(has_edited ? 'redoEditButton' : 'editButton');
-        showElementById('smallCommentFrame');
-      }
-
-      prev_mode = current_mode;
-      current_mode = mode;
-    }
-
-  function hideElementById(id)
-  {
-    var elm = document.getElementById(id);
-    if (elm) {
-      elm.style.display = 'none';
-    }
-  }
-
-  function showElementById(id, val)
-  {
-    var elm = document.getElementById(id);
-    if (elm) {
-      if (!val) val = 'inline';
-      elm.style.display = val;
-    }
-  }
-
-  function normalizeComments()
-  {
-    // Remove the unused comment field from the document so its contents
-    // do not get transmitted back to the server.
-
-    var small = document.getElementById('smallCommentFrame');
-    var big = document.getElementById('editFrame');
-    if ( (small) &amp;&amp; (small.style.display == 'none') )
-    {
-      small.parentNode.removeChild(small);
-    }
-    if ( (big) &amp;&amp; (big.style.display == 'none') )
-    {
-      big.parentNode.removeChild(big);
-    }
-  }
-  //--&gt;
-&lt;/script&gt;
-
</del><span class="cx"> &lt;form method=&quot;post&quot; action=&quot;attachment.cgi&quot; onsubmit=&quot;normalizeComments();&quot;&gt;
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;id&quot; value=&quot;[% attachment.id %]&quot;&gt;
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;update&quot;&gt;
</span><span class="lines">@@ -200,65 +57,211 @@
</span><span class="cx">     &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% issue_hash_token([attachment.id, attachment.modification_time]) FILTER html %]&quot;&gt;
</span><span class="cx">   [% END %]
</span><span class="cx"> 
</span><del>-  &lt;table class=&quot;attachment_info&quot; width=&quot;100%&quot;&gt;
-
-    &lt;tr&gt;
-      &lt;td width=&quot;25%&quot;&gt;
-        &lt;small&gt;
-        &lt;b&gt;&lt;label for=&quot;description&quot;&gt;Description&lt;/label&gt;:&lt;/b&gt;&lt;br&gt;
</del><ins>+  &lt;div id=&quot;attachment_info&quot; class=&quot;attachment_info [% IF can_edit %] edit[% ELSE %] read[% END%]&quot;&gt;
+    &lt;div id=&quot;attachment_attributes&quot;&gt;
+      &lt;div id=&quot;attachment_information_read_only&quot; class=&quot;[% &quot;bz_private&quot; IF attachment.isprivate %]&quot;&gt;
+        &lt;div class=&quot;title&quot;&gt;
+          [% &quot;[patch]&quot; IF attachment.ispatch%] 
+          &lt;span class=&quot;[% &quot;bz_obsolete&quot; IF attachment.isobsolete %]&quot; title=&quot;[% &quot;obsolete&quot; IF attachment.isobsolete %]&quot;&gt;              
+            [% attachment.description FILTER html %]
+          &lt;/span&gt;
+          [% IF can_edit %]
+            &lt;span class=&quot;bz_edit&quot;&gt;(&lt;a href=&quot;javascript:toggle_attachment_details_visibility()&quot;&gt;edit details&lt;/a&gt;)&lt;/span&gt;
+          [% END %]
+        &lt;/div&gt;
+        &lt;div class=&quot;details&quot;&gt;
+          [% attachment.filename FILTER html %] ([% attachment.contenttype FILTER html %]),
+          [% IF attachment.datasize %]
+            [%+ attachment.datasize FILTER unitconvert %]
+          [% ELSE %]
+            &lt;em&gt;deleted&lt;/em&gt;
+          [% END %], created by [%+ INCLUDE global/user.html.tmpl who = attachment.attacher %]
+          [% IF attachment.isprivate %];
+            &lt;span class=&quot;bz_private&quot;&gt;only visible to &lt;strong&gt;[% Param('insidergroup') FILTER html %]&lt;/strong&gt; members&lt;/span&gt;
+          [% END %]
+        &lt;/div&gt;
+      &lt;/div&gt;
+      &lt;div id=&quot;attachment_information_edit&quot;&gt;
+        &lt;span class=&quot;bz_hide&quot;&gt;
+          (&lt;a href=&quot;javascript:toggle_attachment_details_visibility();&quot;&gt;hide&lt;/a&gt;)
+        &lt;/span&gt;
+        &lt;div id=&quot;attachment_description&quot;&gt;
+          &lt;label for=&quot;description&quot;&gt;Description:&lt;/label&gt;&amp;nbsp;
</ins><span class="cx">           [% INCLUDE global/textarea.html.tmpl
</span><span class="cx">             id             = 'description'
</span><span class="cx">             name           = 'description'
</span><span class="cx">             minrows        = 3
</span><span class="cx">             cols           = 25
</span><span class="cx">             wrap           = 'soft'
</span><ins>+            classes        = 'block' _ editable_or_hide
</ins><span class="cx">             defaultcontent = attachment.description
</span><del>-          %]&lt;br&gt;
</del><ins>+          %]          
+        &lt;/div&gt;
</ins><span class="cx"> 
</span><del>-        [% IF attachment.isurl %]
-            &lt;input type=&quot;hidden&quot; name=&quot;filename&quot;
-                   value=&quot;[% attachment.filename FILTER html %]&quot;&gt;
-            &lt;input type=&quot;hidden&quot; name=&quot;contenttypeentry&quot;
-                   value=&quot;[% attachment.contenttype FILTER html %]&quot;&gt;
-        [% ELSE %]
-          &lt;b&gt;&lt;label for=&quot;filename&quot;&gt;Filename&lt;/label&gt;:&lt;/b&gt;&lt;br&gt;
-            &lt;input type=&quot;text&quot; size=&quot;20&quot; id=&quot;filename&quot; name=&quot;filename&quot;
-                   value=&quot;[% attachment.filename FILTER html %]&quot;&gt;&lt;br&gt;
-          &lt;b&gt;Size:&lt;/b&gt;
-          [% IF attachment.datasize %]
-            [%+ attachment.datasize FILTER unitconvert %]
-          [% ELSE %]
-            &lt;em&gt;deleted&lt;/em&gt;
-          [% END %]&lt;br&gt;
</del><ins>+          &lt;div id=&quot;attachment_filename&quot;&gt;
+            &lt;label for=&quot;filename&quot;&gt;Filename:&lt;/label&gt;
+            &lt;input type=&quot;text&quot; size=&quot;20&quot;  class=&quot;text block[% editable_or_hide %]&quot;
+                   id=&quot;filename&quot; name=&quot;filename&quot;
+                   value=&quot;[% attachment.filename FILTER html %]&quot;&gt;     
+          &lt;/div&gt;
</ins><span class="cx"> 
</span><del>-          &lt;b&gt;&lt;label for=&quot;contenttypeentry&quot;&gt;MIME Type&lt;/label&gt;:&lt;/b&gt;&lt;br&gt;
-            &lt;input type=&quot;text&quot; size=&quot;20&quot;
</del><ins>+          &lt;div id=&quot;attachment_mimetype&quot;&gt;
+            &lt;label for=&quot;contenttypeentry&quot;&gt;MIME Type:&lt;/label&gt;
+            &lt;input type=&quot;text&quot; size=&quot;20&quot; class=&quot;text block[% editable_or_hide %]&quot;
</ins><span class="cx">                    id=&quot;contenttypeentry&quot; name=&quot;contenttypeentry&quot;
</span><del>-                   value=&quot;[% attachment.contenttype FILTER html %]&quot;&gt;&lt;br&gt;
</del><ins>+                   value=&quot;[% attachment.contenttype FILTER html %]&quot;&gt;                   
+          &lt;/div&gt;
+          
+          &lt;div id=&quot;attachment_creator&quot;&gt;
+            &lt;span class=&quot;label&quot;&gt;Creator:&lt;/span&gt;
+            [%+ INCLUDE global/user.html.tmpl who = attachment.attacher %]
+          &lt;/div&gt;
+          
+          &lt;div id=&quot;attachment_size&quot;&gt;
+            &lt;span class=&quot;label&quot;&gt;Size:&lt;/span&gt;
+            [% IF attachment.datasize %]
+              [%+ attachment.datasize FILTER unitconvert %]
+            [% ELSE %]
+              &lt;em&gt;deleted&lt;/em&gt;
+            [% END %]
+          &lt;/div&gt;
</ins><span class="cx"> 
</span><del>-          &lt;input type=&quot;checkbox&quot; id=&quot;ispatch&quot; name=&quot;ispatch&quot; value=&quot;1&quot;
-                 [%+ 'checked=&quot;checked&quot;' IF attachment.ispatch %]&gt;
-          &lt;label for=&quot;ispatch&quot;&gt;patch&lt;/label&gt;
-        [% END %]
-          &lt;input type=&quot;checkbox&quot; id=&quot;isobsolete&quot; name=&quot;isobsolete&quot; value=&quot;1&quot;
-                 [%+ 'checked=&quot;checked&quot;' IF attachment.isobsolete %]&gt;
-          &lt;label for=&quot;isobsolete&quot;&gt;obsolete&lt;/label&gt;
-          [% IF (Param(&quot;insidergroup&quot;) &amp;&amp; user.in_group(Param(&quot;insidergroup&quot;))) %]
-            &lt;input type=&quot;checkbox&quot; id=&quot;isprivate&quot; name=&quot;isprivate&quot; value=&quot;1&quot;
-                   [% &quot; checked&quot; IF attachment.isprivate %]&gt;
-            &lt;label for=&quot;isprivate&quot;&gt;private&lt;/label&gt;&lt;br&gt;
-          [% END %]
-          &lt;br&gt;
-        &lt;/small&gt;
</del><ins>+          &lt;div id=&quot;attachment_ispatch&quot;&gt;
+            &lt;input type=&quot;checkbox&quot; id=&quot;ispatch&quot; name=&quot;ispatch&quot; value=&quot;1&quot;
+                   [%+ 'checked=&quot;checked&quot;' IF attachment.ispatch %]&gt;
+                   &lt;label for=&quot;ispatch&quot;&gt;patch&lt;/label&gt;
+          &lt;/div&gt;
</ins><span class="cx"> 
</span><del>-        [% IF flag_types.size &gt; 0 %]
-          [% PROCESS &quot;flag/list.html.tmpl&quot; bug_id = attachment.bug_id
-                                           attach_id = attachment.id %]&lt;br&gt;
-        [% END %]
</del><ins>+        &lt;div class=&quot;readonly&quot;&gt;
+          &lt;div class=&quot;checkboxes&quot;&gt;
+            &lt;div id=&quot;attachment_isobsolete&quot;&gt;
+              &lt;input type=&quot;checkbox&quot; id=&quot;isobsolete&quot; name=&quot;isobsolete&quot; value=&quot;1&quot;                     
+                     [%+ 'checked=&quot;checked&quot;' IF attachment.isobsolete %]&gt;
+                &lt;label for=&quot;isobsolete&quot;&gt;obsolete&lt;/label&gt;
+            &lt;/div&gt;
</ins><span class="cx"> 
</span><ins>+            [% IF user.is_insider %]
+              &lt;div id=&quot;attachment_isprivate&quot;&gt;
+                &lt;input type=&quot;checkbox&quot; id=&quot;isprivate&quot; name=&quot;isprivate&quot; value=&quot;1&quot;
+                       [%+ 'checked=&quot;checked&quot;' IF attachment.isprivate %]&gt;
+                [% IF can_edit %]
+                  &lt;label for=&quot;isprivate&quot;&gt;private (only visible to
+                    &lt;strong&gt;[% Param('insidergroup') FILTER html %]&lt;/strong&gt;)
+                  &lt;/label&gt;
+                [% ELSE %]
+                  &lt;span class=&quot;label&quot;&gt;Is Private:&lt;/span&gt;
+                  [%+ attachment.isprivate ? &quot;yes&quot; : &quot;no&quot; %]
+                [% END %]
+              &lt;/div&gt;
+            [% END %]
+          &lt;/div&gt;
+        &lt;/div&gt;                    
+      &lt;/div&gt;
+
+      &lt;div id=&quot;attachment_view_window&quot;&gt;
+        [% IF !attachment.datasize %]
+          &lt;div&gt;&lt;b&gt;The content of this attachment has been deleted.&lt;/b&gt;&lt;/div&gt;
+        [% ELSIF !Param(&quot;allow_attachment_display&quot;) %]
+          &lt;div id=&quot;view_disabled&quot;&gt;
+            &lt;p&gt;&lt;b&gt;
+              The attachment is not viewable in your browser due to security
+              restrictions enabled by your [% terms.Bugzilla %] administrator.
+            &lt;/b&gt;&lt;/p&gt;
+            &lt;p&gt;&lt;b&gt;
+              In order to view the attachment, you first have to
+              &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&quot;&gt;download it&lt;/a&gt;.
+            &lt;/b&gt;&lt;/p&gt;
+          &lt;/div&gt;
+        [% ELSIF attachment.is_viewable %]
+          &lt;div&gt;
+            [% INCLUDE global/textarea.html.tmpl
+              id      = 'editFrame'
+              name    = 'comment'
+              classes   = 'bz_default_hidden'
+              minrows = 10
+              cols    = 80
+              wrap    = 'soft'
+              disabled = 'disabled'
+              defaultcontent = (attachment.contenttype.match('^text\/')) ?
+                                 attachment.data.replace('(.*\n|.+)', '&gt;$1') : undef
+            %]
+            [% IF attachment.contenttype == 'text/plain' AND is_safe_url(attachment.data) %]
+              &lt;p&gt;
+                &lt;a href=&quot;[% attachment.data FILTER html %]&quot;&gt;
+                  [% IF attachment.datasize &lt; 120 %]
+                    [% attachment.data FILTER html %]
+                  [% ELSE %]
+                    [% attachment.data FILTER truncate(80) FILTER html %]
+                    ...
+                    [% attachment.data.match('.*(.{20})$').0 FILTER html %]
+                  [% END %]
+                &lt;/a&gt;
+              &lt;/p&gt;
+            [% ELSIF attachment.contenttype == &quot;text/html&quot; %]
+              [%# For security reasons (clickjacking, embedded scripts), we never
+                # render HTML pages from here. The source code is displayed instead. %]
+              [% INCLUDE global/textarea.html.tmpl
+                 id      = 'viewFrame'
+                 minrows = 10
+                 cols    = 80
+                 defaultcontent = attachment.data
+                 readonly = 'readonly'
+              %]
+            [% ELSE %]
+              &lt;iframe id=&quot;viewFrame&quot; src=&quot;attachment.cgi?id=[% attachment.id %]&quot;&gt;
+                &lt;b&gt;You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
+                &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&quot;&gt;View the attachment on a separate page&lt;/a&gt;.&lt;/b&gt;
+              &lt;/iframe&gt;
+            [% END %]
+            &lt;script type=&quot;text/javascript&quot;&gt;
+              &lt;!--
+              var patchviewerinstalled = 0;
+              var attachment_id = [% attachment.id %];
+              if (typeof document.getElementById == &quot;function&quot;) {
+                [% IF use_patchviewer %]
+                  var patchviewerinstalled = 1;
+                  document.write('&lt;iframe id=&quot;viewDiffFrame&quot; class=&quot;bz_default_hidden&quot;&gt;&lt;\/iframe&gt;');
+                [% END %]
+                [% IF user.id %]
</ins><span class="cx"> [%# if WEBKIT_CHANGES %]
</span><del>-        [% IF attachment.ispatch %]
-        &lt;b&gt;&lt;small&gt;Bot Status:&lt;/small&gt;&lt;/b&gt;
</del><ins>+                  [% IF attachment.ispatch %]
+                  document.write('&lt;button type=&quot;button&quot; id=&quot;viewPrettyPatchButton&quot; onclick=&quot;viewPrettyPatch();&quot;&gt;View Formatt
+                  [% END %]
+[%# endif // WEBKIT_CHANGES %]
+                  document.write('&lt;button type=&quot;button&quot; id=&quot;editButton&quot; onclick=&quot;editAsComment(patchviewerinstalled);&quot;&gt;Edit Attachment As Comment&lt;\/button&gt;');
+                  document.write('&lt;button type=&quot;button&quot; id=&quot;undoEditButton&quot; onclick=&quot;undoEditAsComment(patchviewerinstalled);&quot; class=&quot;bz_default_hidden&quot;&gt;Undo Edit As Comment&lt;\/button&gt;');
+                  document.write('&lt;button type=&quot;button&quot; id=&quot;redoEditButton&quot; onclick=&quot;redoEditAsComment(patchviewerinstalled);&quot; class=&quot;bz_default_hidden&quot;&gt;Redo Edit As Comment&lt;\/button&gt;');
+                  var editFrame = document.getElementById('editFrame');
+                  if (editFrame) {
+                    editFrame.disabled = false;
+                  }
+                [% END %]
+                [% IF use_patchviewer %]
+                  document.write('&lt;button type=&quot;button&quot; id=&quot;viewDiffButton&quot; onclick=&quot;viewDiff(attachment_id, patchviewerinstalled);&quot;&gt;View Attachment As Diff&lt;\/button&gt;');
+                [% END %]
+                document.write('&lt;button type=&quot;button&quot; id=&quot;viewRawButton&quot; onclick=&quot;viewRaw(patchviewerinstalled);&quot; class=&quot;bz_default_hidden&quot;&gt;View Attachment As Raw&lt;\/button&gt;');
+              }
+              //--&gt;
+            &lt;/script&gt;
+          &lt;/div&gt;
+        [% ELSE %]
+          &lt;div id=&quot;noview&quot;&gt;
+            &lt;p&gt;&lt;b&gt;
+              Attachment is not viewable in your browser because its MIME type 
+              ([% attachment.contenttype FILTER html %]) is not one that your browser is 
+              able to display.
+            &lt;/b&gt;&lt;/p&gt;
+            &lt;p&gt;&lt;b&gt;
+              &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&quot;&gt;Download the attachment&lt;/a&gt;.
+            &lt;/b&gt;&lt;/p&gt;
+          &lt;/div&gt;
+        [% END %]
+      &lt;/div&gt;
+      &lt;div id=&quot;attachment_comments_and_flags&quot;&gt;
+        [% IF user.id %]
+[%# if WEBKIT_CHANGES %]
+            [% IF attachment.ispatch %]
+        Bot Status:
</ins><span class="cx"> 
</span><span class="cx">         &lt;div class=&quot;statusBubble&quot;&gt;
</span><span class="cx">           &lt;iframe src=&quot;https://webkit-queues.appspot.com/status-bubble/[% attachment.id %]&quot;
</span><span class="lines">@@ -266,120 +269,64 @@
</span><span class="cx">           &lt;/iframe&gt;
</span><span class="cx">         &lt;/div&gt;
</span><span class="cx">         &lt;br&gt;
</span><del>-        [% END %]
</del><ins>+            [% END %]
</ins><span class="cx"> [%# endif // WEBKIT_CHANGES %]
</span><del>-
-        &lt;div id=&quot;smallCommentFrame&quot;&gt;
-          &lt;b&gt;&lt;small&gt;&lt;label for=&quot;comment&quot;&gt;Comment&lt;/label&gt; (on the
-          [%+ terms.bug %]):&lt;/small&gt;&lt;/b&gt;&lt;br&gt;
</del><ins>+          &lt;div id=&quot;smallCommentFrame&quot; &gt;
+            &lt;label for=&quot;comment&quot;&gt;Comment (on the [% terms.bug %]):&lt;/label&gt;
+            [% classNames = 'block' %]
+            [% classNames = &quot;$classes bz_private&quot; IF attachment.isprivate %]
</ins><span class="cx">             [% INCLUDE global/textarea.html.tmpl
</span><span class="cx">               id      = 'comment'
</span><span class="cx">               name    = 'comment'
</span><del>-              minrows = 5
-              cols    = 25
</del><ins>+              minrows = 10
+              cols    = 80
</ins><span class="cx">               wrap    = 'soft'
</span><del>-            %]&lt;br&gt;
</del><ins>+              classes = classNames          
+            %]
+          &lt;/div&gt;
+        [% END %]             
+        &lt;div id=&quot;attachment_flags&quot;&gt;
+          [% IF attachment.flag_types.size &gt; 0 %]
+              [% PROCESS &quot;flag/list.html.tmpl&quot; flag_types = attachment.flag_types
+                                               read_only_flags = !can_edit
+              %]
+     
+          [% END %]
</ins><span class="cx">         &lt;/div&gt;
</span><span class="cx"> 
</span><del>-        &lt;input type=&quot;submit&quot; value=&quot;Submit&quot; id=&quot;update&quot;&gt;&lt;br&gt;&lt;br&gt;
-        &lt;strong&gt;Actions:&lt;/strong&gt;
-        &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&quot;&gt;View&lt;/a&gt;
-[%# if WEBKIT_CHANGES %]
-        [% IF attachment.ispatch %]
-         | &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&amp;amp;action=prettypatch&quot;&gt;Formatted Diff&lt;/a&gt;
-        [% END %]
-[%# endif // WEBKIT_CHANGES %]
-        [% IF attachment.ispatch &amp;&amp; patchviewerinstalled %]
-         | &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&amp;amp;action=diff&quot;&gt;Diff&lt;/a&gt;
-        [% END %]
-        [% IF Param(&quot;allow_attachment_deletion&quot;)
-              &amp;&amp; user.groups.admin
-              &amp;&amp; attachment.datasize &gt; 0 %]
-          | &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&amp;amp;action=delete&quot;&gt;Delete&lt;/a&gt;
-        [% END %]
-      &lt;/td&gt;
</del><ins>+        [% Hook.process('form_before_submit') %]
</ins><span class="cx"> 
</span><del>-      [% IF !attachment.datasize %]
-        &lt;td width=&quot;75%&quot;&gt;&lt;b&gt;The content of this attachment has been deleted.&lt;/b&gt;&lt;/td&gt;
-      [% ELSIF attachment.isurl %]
-        &lt;td width=&quot;75%&quot;&gt;
-          &lt;a href=&quot;[% attachment.data FILTER html %]&quot;&gt;
-            [% IF attachment.datasize &lt; 120 %]
-              [% attachment.data FILTER html %]
-            [% ELSE %]
-              [% attachment.data FILTER truncate(80) FILTER html %]
-              &amp;nbsp;...
-              [% attachment.data.match(&quot;.*(.{20})$&quot;).0 FILTER html %]
-            [% END %]
-          &lt;/a&gt;
-        &lt;/td&gt;
-      [% ELSIF !Param(&quot;allow_attachment_display&quot;) %]
-        &lt;td id=&quot;view_disabled&quot; width=&quot;50%&quot;&gt;
-          &lt;p&gt;&lt;b&gt;
-            The attachment is not viewable in your browser due to security
-            restrictions enabled by [% terms.Bugzilla %].
-          &lt;/b&gt;&lt;/p&gt;
-          &lt;p&gt;&lt;b&gt;
-            In order to view the attachment, you first have to
-            &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&quot;&gt;download it&lt;/a&gt;.
-          &lt;/b&gt;&lt;/p&gt;
-        &lt;/td&gt;
-      [% ELSIF attachment.is_viewable %]
-        &lt;td width=&quot;75%&quot;&gt;
-          [% INCLUDE global/textarea.html.tmpl
-            id      = 'editFrame'
-            name    = 'comment'
-            style   = 'height: 400px; width: 100%; display: none'
-            minrows = 10
-            cols    = 80
-            wrap    = 'soft'
-            defaultcontent = (attachment.contenttype.match('^text\/')) ?
-                               attachment.data.replace('(.*\n|.+)', '&gt;$1') : undef
-          %]
-          &lt;iframe id=&quot;viewFrame&quot; src=&quot;attachment.cgi?id=[% attachment.id %]&quot; style=&quot;height: 400px; width: 100%;&quot;&gt;
-            &lt;b&gt;You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
-            &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&quot;&gt;View the attachment on a separate page&lt;/a&gt;.&lt;/b&gt;
-          &lt;/iframe&gt;
-          &lt;script type=&quot;text/javascript&quot;&gt;
-            &lt;!--
-            if (typeof document.getElementById == &quot;function&quot;) {
-[% IF patchviewerinstalled %]
-              document.write('&lt;iframe id=&quot;viewDiffFrame&quot; style=&quot;height: 400px; width: 100%; display: none;&quot;&gt;&lt;\/iframe&gt;');
-[% END %]
</del><ins>+        [% IF user.id %]       
+          &lt;div id=&quot;update_container&quot;&gt;
+            &lt;input type=&quot;submit&quot; value=&quot;Submit&quot; id=&quot;update&quot;&gt;
+          &lt;/div&gt;
+        [% END %]        
+      &lt;/div&gt;        
+    &lt;/div&gt;
+  &lt;/div&gt;
+&lt;/form&gt;
+
+&lt;div id=&quot;attachment_actions&quot;&gt;
+  &lt;span class=&quot;label&quot;&gt;Actions:&lt;/span&gt;
+  &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&quot;&gt;View&lt;/a&gt;
</ins><span class="cx"> [%# if WEBKIT_CHANGES %]
</span><del>-[% IF attachment.ispatch %]
-              document.write('&lt;button type=&quot;button&quot; id=&quot;viewPrettyPatchButton&quot; onclick=&quot;viewPrettyPatch();&quot;&gt;View Formatted Diff&lt;\/button&gt;');
-[% END %]
</del><ins>+  [% IF attachment.ispatch %]
+    | &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&amp;amp;action=prettypatch&quot;&gt;Formatted Diff&lt;/a&gt;
+  [% END %]
</ins><span class="cx"> [%# endif // WEBKIT_CHANGES %]
</span><del>-              document.write('&lt;button type=&quot;button&quot; id=&quot;editButton&quot; onclick=&quot;editAsComment();&quot;&gt;Edit Attachment As Comment&lt;\/button&gt;');
-              document.write('&lt;button type=&quot;button&quot; id=&quot;undoEditButton&quot; onclick=&quot;undoEditAsComment();&quot; style=&quot;display: none;&quot;&gt;Undo Edit As Comment&lt;\/button&gt;');
-              document.write('&lt;button type=&quot;button&quot; id=&quot;redoEditButton&quot; onclick=&quot;redoEditAsComment();&quot; style=&quot;display: none;&quot;&gt;Redo Edit As Comment&lt;\/button&gt;');
-[% IF patchviewerinstalled %]
-              document.write('&lt;button type=&quot;button&quot; id=&quot;viewDiffButton&quot; onclick=&quot;viewDiff();&quot;&gt;View Attachment As Diff&lt;\/button&gt;');
-[% END %]
-              document.write('&lt;button type=&quot;button&quot; id=&quot;viewRawButton&quot; onclick=&quot;viewRaw();&quot; style=&quot;display: none;&quot;&gt;View Attachment As Raw&lt;\/button&gt;');
-            }
-            //--&gt;
-          &lt;/script&gt;
-        &lt;/td&gt;
-      [% ELSE %]
-        &lt;td id=&quot;noview&quot; width=&quot;50%&quot;&gt;
-          &lt;p&gt;&lt;b&gt;
-            Attachment is not viewable in your browser because its MIME type 
-            ([% attachment.contenttype FILTER html %]) is not one that your browser is 
-            able to display.
-          &lt;/b&gt;&lt;/p&gt;
-          &lt;p&gt;&lt;b&gt;
-            &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&quot;&gt;Download the attachment&lt;/a&gt;.
-          &lt;/b&gt;&lt;/p&gt;
-        &lt;/td&gt;
-      [% END %]
</del><ins>+  [% IF use_patchviewer %]
+    | &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&amp;amp;action=diff&quot;&gt;Diff&lt;/a&gt;
+  [% END %]
+  [% IF Param(&quot;allow_attachment_deletion&quot;)
+        &amp;&amp; user.in_group('admin')
+        &amp;&amp; attachment.datasize &gt; 0 %]
+    | &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&amp;amp;action=delete&quot;&gt;Delete&lt;/a&gt;
+  [% END %]
+  [% Hook.process('action') %]
+&lt;/div&gt;
</ins><span class="cx"> 
</span><del>-    &lt;/tr&gt;
-
-  &lt;/table&gt;
-
-  Attachments on this [% terms.Bug %]:
</del><ins>+&lt;div id=&quot;attachment_list&quot;&gt;
+  Attachments on [% &quot;$terms.bug ${attachment.bug_id}&quot; FILTER bug_link(attachment.bug_id) FILTER none %]:
</ins><span class="cx">   [% FOREACH a = attachments %]
</span><span class="cx">     [% IF a == attachment.id %]
</span><span class="cx">       [%+ a %]
</span><span class="lines">@@ -388,9 +335,15 @@
</span><span class="cx">     [% END %]
</span><span class="cx">     [% &quot; |&quot; UNLESS loop.last() %]
</span><span class="cx">   [% END %]
</span><ins>+&lt;/div&gt;
+[% IF can_edit %]
+  &lt;script type=&quot;text/javascript&quot;&gt;
+    &lt;!--
+      YAHOO.util.Dom.removeClass( document.body, &quot;no_javascript&quot; );
+      toggle_attachment_details_visibility( );
+    --&gt;
+  &lt;/script&gt;
+[% END %]
+[% Hook.process('end') %]
</ins><span class="cx"> 
</span><del>-&lt;/form&gt;
-
-&lt;br&gt;
-
</del><span class="cx"> [% PROCESS global/footer.html.tmpl %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateencustomattachmentlisthtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/custom/attachment/list.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/custom/attachment/list.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/custom/attachment/list.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -19,41 +19,46 @@
</span><span class="cx">   #                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
</span><span class="cx">   #%]
</span><span class="cx"> 
</span><ins>+[% RETURN UNLESS attachments.size || Param(&quot;maxattachmentsize&quot;) || Param(&quot;maxlocalattachment&quot;) %]
+
</ins><span class="cx"> &lt;script type=&quot;text/javascript&quot;&gt;
</span><del>-  &lt;!--
-  function toggle_display(link) {
</del><ins>+&lt;!--
+function toggle_display(link) {
</ins><span class="cx">     var table = document.getElementById(&quot;attachment_table&quot;);
</span><del>-    var rows = table.getElementsByTagName(&quot;tr&quot;);
-    var originalHeight = table.offsetHeight; // Store current height for scrolling
</del><ins>+    var view_all = document.getElementById(&quot;view_all&quot;);
+    var hide_obsolete_url_parameter = &quot;&amp;hide_obsolete=1&quot;;
+    // Store current height for scrolling later
+    var originalHeight = table.offsetHeight;
+    var rows = YAHOO.util.Dom.getElementsByClassName(
+        'bz_tr_obsolete', 'tr', table);
</ins><span class="cx"> 
</span><del>-    var toggle;
-    if (link.innerHTML == &quot;Show Obsolete&quot;) {
-      toggle = &quot;&quot;; // This should be 'table-row', but IE 6 doesn't understand it.
-      link.innerHTML = &quot;Hide Obsolete&quot;;
</del><ins>+    for (var i = 0; i &lt; rows.length; i++) {
+        bz_toggleClass(rows[i], 'bz_default_hidden');
</ins><span class="cx">     }
</span><ins>+
+    if (YAHOO.util.Dom.hasClass(rows[0], 'bz_default_hidden')) {
+        link.innerHTML = &quot;Show Obsolete&quot;;
+        view_all.href = view_all.href + hide_obsolete_url_parameter 
+    }
</ins><span class="cx">     else {
</span><del>-      toggle = &quot;none&quot;;
-      link.innerHTML = &quot;Show Obsolete&quot;;
</del><ins>+        link.innerHTML = &quot;Hide Obsolete&quot;;
+        view_all.href = view_all.href.replace(hide_obsolete_url_parameter,&quot;&quot;);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    for (var i = 0; i &lt; rows.length; i++) {
-      if (rows[i].className.match('bz_tr_obsolete'))
-        rows[i].style.display = toggle;
-    }
-
</del><span class="cx">     var newHeight = table.offsetHeight;
</span><ins>+    // This scrolling makes the window appear to not move at all.
</ins><span class="cx">     window.scrollBy(0, newHeight - originalHeight);
</span><span class="cx"> 
</span><span class="cx">     return false;
</span><del>-  }
-  //--&gt;
</del><ins>+}
+//--&gt;
</ins><span class="cx"> &lt;/script&gt;
</span><span class="cx"> 
</span><span class="cx"> &lt;br&gt;
</span><span class="cx"> &lt;table id=&quot;attachment_table&quot; cellspacing=&quot;0&quot; cellpadding=&quot;4&quot;&gt;
</span><del>-  &lt;tr&gt;
</del><ins>+  &lt;tr id=&quot;a0&quot;&gt;
</ins><span class="cx">     &lt;th colspan=&quot;[% show_attachment_flags ? 3 : 2 %]&quot; align=&quot;left&quot;&gt;
</span><del>-      &lt;a name=&quot;a0&quot; id=&quot;a0&quot;&gt;Attachments&lt;/a&gt;
</del><ins>+      Attachments
</ins><span class="cx">     &lt;/th&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -66,15 +71,19 @@
</span><span class="cx">       [% IF attachment.isobsolete %]
</span><span class="cx">         [% obsolete_attachments = obsolete_attachments + 1 %]
</span><span class="cx">       [% END %]
</span><del>-      &lt;tr class=&quot;[% &quot;bz_private&quot; IF attachment.isprivate %][%-%]
-                 [%+ &quot;bz_tr_obsolete&quot; IF attachment.isobsolete %]&quot;
</del><ins>+      &lt;tr id=&quot;a[% count %]&quot; class=&quot;[% &quot;bz_contenttype_&quot; _ attachment.contenttype
+                     FILTER css_class_quote %]
+                 [% &quot; bz_patch&quot; IF attachment.ispatch %]
+                 [% &quot; bz_private&quot; IF attachment.isprivate %]
+                 [% &quot; bz_tr_obsolete bz_default_hidden&quot; 
+                     IF attachment.isobsolete %]&quot;
</ins><span class="cx"> [%# if WEBKIT_CHANGES %]
</span><del>-          [% IF attachment.ispatch &amp;&amp; !attachment.isobsolete %] style=&quot;background-color: rgb(255,255,200);&quot; [% END %]
</del><ins>+                 [% IF attachment.ispatch &amp;&amp; !attachment.isobsolete %] style=&quot;background-color: rgb(255,255,200);&quot; [% END %]
</ins><span class="cx"> [%# endif // WEBKIT_CHANGES %]
</span><span class="cx">       &gt;
</span><span class="cx">         &lt;td valign=&quot;top&quot;&gt;
</span><span class="cx">           [% IF attachment.datasize %]
</span><del>-            &lt;a name=&quot;a[% count %]&quot; href=&quot;attachment.cgi?id=[% attachment.id %]&quot;
</del><ins>+            &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&quot;
</ins><span class="cx">                title=&quot;View the content of the attachment&quot;&gt;
</span><span class="cx">           [% END %]
</span><span class="cx">           &lt;b&gt;[% attachment.description FILTER html FILTER obsolete(attachment.isobsolete) %]&lt;/b&gt;
</span><span class="lines">@@ -85,8 +94,6 @@
</span><span class="cx">               ([% attachment.datasize FILTER unitconvert %],
</span><span class="cx">               [% IF attachment.ispatch %]
</span><span class="cx">                 patch)
</span><del>-              [% ELSIF attachment.isurl %]
-                url)
</del><span class="cx">               [% ELSE %]
</span><span class="cx">                 [%+ attachment.contenttype FILTER html %])
</span><span class="cx">               [% END %]
</span><span class="lines">@@ -99,10 +106,7 @@
</span><span class="cx">                title=&quot;Go to the comment associated with the attachment&quot;&gt;
</span><span class="cx">               [%- attachment.attached FILTER time %]&lt;/a&gt;,
</span><span class="cx"> 
</span><del>-            &lt;a href=&quot;mailto:[% attachment.attacher.email FILTER html %]&quot;
-               title=&quot;Write an email to the creator of the attachment&quot;&gt;
-              [% attachment.attacher.name || attachment.attacher.login FILTER html %]
-            &lt;/a&gt;
</del><ins>+            [% INCLUDE global/user.html.tmpl who = attachment.attacher %]
</ins><span class="cx">           &lt;/span&gt;
</span><span class="cx">         &lt;/td&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -118,11 +122,23 @@
</span><span class="cx"> [%# if WEBKIT_CHANGES %]
</span><span class="cx">                 [% IF flag.type.name != 'in-rietveld' %]
</span><span class="cx"> [%# endif // WEBKIT_CHANGES %]
</span><ins>+                [% IF user.id %]
+                  &lt;span title=&quot;[% flag.setter.identity FILTER html %]&quot;&gt;[% flag.setter.nick FILTER html %]&lt;/span&gt;:
+                [% ELSIF flag.setter.name %]
+                  &lt;span title=&quot;[% flag.setter.name FILTER html %]&quot;&gt;[% flag.setter.nick FILTER html %]&lt;/span&gt;:
+                [% ELSE %]
</ins><span class="cx">                   [% flag.setter.nick FILTER html %]:
</span><del>-                  [%+ flag.type.name FILTER html FILTER no_break %][% flag.status %]
-                  [%+ IF flag.status == &quot;?&quot; &amp;&amp; flag.requestee %]
</del><ins>+                [% END %]
+                [%+ flag.type.name FILTER html FILTER no_break %][% flag.status %]
+                [%+ IF flag.status == &quot;?&quot; &amp;&amp; flag.requestee %]
+                  [% IF user.id %]
+                    (&lt;span title=&quot;[% flag.requestee.identity FILTER html %]&quot;&gt;[% flag.requestee.nick FILTER html %]&lt;/span&gt;)
+                  [% ELSIF flag.requestee.name %]
+                    (&lt;span title=&quot;[% flag.requestee.name FILTER html %]&quot;&gt;[% flag.requestee.nick FILTER html %]&lt;/span&gt;)
+                  [% ELSE %]
</ins><span class="cx">                     ([% flag.requestee.nick FILTER html %])
</span><del>-                  [% END %]&lt;br&gt;
</del><ins>+                  [% END %]
+                [% END %]&lt;br&gt;
</ins><span class="cx"> [%# if WEBKIT_CHANGES %]
</span><span class="cx">                 [% END %]
</span><span class="cx"> [%# endif // WEBKIT_CHANGES %]
</span><span class="lines">@@ -133,7 +149,7 @@
</span><span class="cx"> 
</span><span class="cx">         &lt;td valign=&quot;top&quot;&gt;
</span><span class="cx"> [%# if WEBKIT_CHANGES %]
</span><del>-          [% IF attachment.ispatch %]
</del><ins>+          [% IF attachment.ispatch &amp;&amp; user.id %]
</ins><span class="cx">           &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&amp;amp;action=review&quot;&gt;Review Patch&lt;/a&gt; |
</span><span class="cx">           [% END %]
</span><span class="cx"> [%# endif // WEBKIT_CHANGES %]
</span><span class="lines">@@ -143,7 +159,7 @@
</span><span class="cx">             | &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&amp;amp;action=prettypatch&quot;&gt;Formatted Diff&lt;/a&gt;
</span><span class="cx">           [% END %]
</span><span class="cx"> [%# endif // WEBKIT_CHANGES %]
</span><del>-          [% IF attachment.ispatch &amp;&amp; patchviewerinstalled %]
</del><ins>+          [% IF attachment.ispatch &amp;&amp; feature_enabled('patch_viewer') %]
</ins><span class="cx">             | &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&amp;amp;action=diff&quot;&gt;Diff&lt;/a&gt;
</span><span class="cx">           [% END %]
</span><span class="cx">           [% Hook.process(&quot;action&quot;) %]
</span><span class="lines">@@ -151,7 +167,7 @@
</span><span class="cx">           [% IF attachment.ispatch %]
</span><span class="cx">             [% FOREACH flag = attachment.flags %]
</span><span class="cx">               [% IF flag.type.name == 'in-rietveld' &amp;&amp; flag.status == &quot;+&quot;  %]
</span><del>-                | &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&amp;amp;action=rietveldreview&amp;amp;GoAheadAndLogIn=1&quot;&gt;Rietveld Review&lt;/a&gt;
</del><ins>+                | &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&amp;amp;action=rietveldreview&amp;amp;GoAheadAndLogIn=1&quot;&gt;Rietve
</ins><span class="cx">               [% END %]
</span><span class="cx">             [% END %]
</span><span class="cx">           &lt;div class=&quot;statusBubble&quot;&gt;
</span><span class="lines">@@ -171,15 +187,20 @@
</span><span class="cx">       [% IF attachments.size %]
</span><span class="cx">         &lt;span class=&quot;bz_attach_view_hide&quot;&gt;
</span><span class="cx">           [% IF obsolete_attachments %]
</span><del>-            &lt;a href=&quot;#a0&quot; onClick=&quot;return toggle_display(this);&quot;&gt;Hide Obsolete&lt;/a&gt; ([% obsolete_attachments %])
</del><ins>+            &lt;a href=&quot;#a0&quot; onclick=&quot;return toggle_display(this);&quot;&gt;Show
+              Obsolete&lt;/a&gt; ([% obsolete_attachments %])
</ins><span class="cx">           [% END %]
</span><span class="cx">           [% IF Param(&quot;allow_attachment_display&quot;) %]
</span><del>-            &lt;a href=&quot;attachment.cgi?bugid=[% bugid %]&amp;amp;action=viewall&quot;&gt;View All&lt;/a&gt;
</del><ins>+            &lt;a id=&quot;view_all&quot; href=&quot;attachment.cgi?bugid=
+                  [%- bugid %]&amp;amp;action=viewall
+                  [%- &quot;&amp;amp;hide_obsolete=1&quot; IF obsolete_attachments %]&quot;&gt;View All&lt;/a&gt;
</ins><span class="cx">           [% END %]
</span><span class="cx">         &lt;/span&gt;
</span><span class="cx">       [% END %]
</span><del>-      &lt;a href=&quot;attachment.cgi?bugid=[% bugid %]&amp;amp;action=enter&quot;&gt;Add an attachment&lt;/a&gt;
-      (proposed patch, testcase, etc.)
</del><ins>+      [% IF Param(&quot;maxattachmentsize&quot;) || Param(&quot;maxlocalattachment&quot;) %]
+        &lt;a href=&quot;attachment.cgi?bugid=[% bugid %]&amp;amp;action=enter&quot;&gt;Add an attachment&lt;/a&gt;
+        (proposed patch, testcase, etc.)
+      [% END %]
</ins><span class="cx">     &lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> &lt;/table&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateencustombugedithtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/custom/bug/edit.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/custom/bug/edit.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/custom/bug/edit.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -40,7 +40,7 @@
</span><span class="cx">        */
</span><span class="cx">       [% IF user.settings.quote_replies.value != 'off' %]
</span><span class="cx">         document.write('[&lt;a href=&quot;#add_comment&quot; onclick=&quot;replyToComment(' + 
</span><del>-                       id + ',' + real_id + ');&quot;&gt;reply&lt;' + '/a&gt;]');
</del><ins>+                       id + ',' + real_id + '); return false;&quot;&gt;reply&lt;' + '/a&gt;]');
</ins><span class="cx">       [% END %]
</span><span class="cx">   }
</span><span class="cx"> 
</span><span class="lines">@@ -52,24 +52,15 @@
</span><span class="cx">         /* pre id=&quot;comment_name_N&quot; */
</span><span class="cx">         var text_elem = document.getElementById('comment_text_'+id);
</span><span class="cx">         var text = getText(text_elem);
</span><del>-
-        /* make sure we split on all newlines -- IE or Moz use \r and \n
-         * respectively.
-         */
-        text = text.split(/\r|\n/);
-
-        for (var i=0; i &lt; text.length; i++) {
-            replytext += &quot;&gt; &quot; + text[i] + &quot;\n&quot;; 
-        }
-
-        replytext = prefix + replytext + &quot;\n&quot;;
</del><ins>+        replytext = prefix + wrapReplyText(text);
</ins><span class="cx">       [% ELSIF user.settings.quote_replies.value == 'simple_reply' %]
</span><span class="cx">         replytext = prefix;
</span><span class="cx">       [% END %]
</span><span class="cx"> 
</span><del>-    [% IF Param(&quot;insidergroup&quot;) &amp;&amp; user.in_group(Param(&quot;insidergroup&quot;)) %]
</del><ins>+    [% IF user.is_insider %]
</ins><span class="cx">       if (document.getElementById('isprivate_' + real_id).checked) {
</span><span class="cx">           document.getElementById('newcommentprivacy').checked = 'checked';
</span><ins>+          updateCommentTagControl(document.getElementById('newcommentprivacy'), 'comment'); 
</ins><span class="cx">       }
</span><span class="cx">     [% END %]
</span><span class="cx"> 
</span><span class="lines">@@ -107,7 +98,7 @@
</span><span class="cx">       return text;
</span><span class="cx">   }
</span><span class="cx"> 
</span><del>-[% IF user.in_group(Param('timetrackinggroup')) %]
</del><ins>+[% IF user.is_timetracker %]
</ins><span class="cx">   var fRemainingTime = [% bug.remaining_time %]; // holds the original value
</span><span class="cx">   function adjustRemainingTime() {
</span><span class="cx">       // subtracts time spent from remaining time
</span><span class="lines">@@ -128,27 +119,28 @@
</span><span class="cx"> 
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><del>-  function updateCommentTagControl(checkbox, form) {
-      if (checkbox.checked) {
-          form.comment.className='bz_private';
-      } else {
-          form.comment.className='';
-      }
-  }
</del><ins>+  /* Index all classifications so we can keep track of the classification
+   * for the selected product, which could control field visibility.
+   */
+  var all_classifications = new Array([% bug.choices.product.size %]);
+  [%- FOREACH product = bug.choices.product %]
+      all_classifications['[% product.name FILTER js %]'] = '
+          [%- product.classification.name FILTER js %]';
+  [%- END %]
</ins><span class="cx"> 
</span><span class="cx">   //--&gt;
</span><span class="cx">   &lt;/script&gt;
</span><span class="cx"> 
</span><del>-&lt;form name=&quot;changeform&quot; method=&quot;post&quot; action=&quot;process_bug.cgi&quot;&gt;
</del><ins>+&lt;form name=&quot;changeform&quot; id=&quot;changeform&quot; method=&quot;post&quot; action=&quot;process_bug.cgi&quot;&gt;
</ins><span class="cx"> 
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;delta_ts&quot; value=&quot;[% bug.delta_ts %]&quot;&gt;
</span><del>-  &lt;input type=&quot;hidden&quot; name=&quot;longdesclength&quot; value=&quot;[% bug.longdescs.size %]&quot;&gt;
</del><ins>+  &lt;input type=&quot;hidden&quot; name=&quot;longdesclength&quot; value=&quot;[% bug.comments.size %]&quot;&gt;
</ins><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;id&quot; value=&quot;[% bug.bug_id %]&quot;&gt;
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% issue_hash_token([bug.id, bug.delta_ts]) FILTER html %]&quot;&gt;
</span><span class="cx"> 
</span><span class="cx">   [% PROCESS section_title %]
</span><span class="cx"> [%# if WEBKIT_CHANGES %]
</span><del>-  &lt;table id=&quot;bug_details&quot;&gt;
</del><ins>+  &lt;table id=&quot;bug_details&quot; class=&quot;edit_form&quot;&gt;
</ins><span class="cx"> [%# endif // WEBKIT_CHANGES %]
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       [%# 1st Column %]
</span><span class="lines">@@ -191,7 +183,9 @@
</span><span class="cx">          
</span><span class="cx">          [% PROCESS section_cclist %]
</span><span class="cx">          
</span><del>-         [% PROCESS section_spacer %] 
</del><ins>+         [% PROCESS section_spacer %]
+
+         [% PROCESS section_see_also %] 
</ins><span class="cx">          
</span><span class="cx">          [% PROCESS section_customfields %]
</span><span class="cx">          
</span><span class="lines">@@ -211,90 +205,43 @@
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">   &lt;/table&gt;
</span><span class="cx"> 
</span><del>-  
-  [% PROCESS section_restrict_visibility %]
-  [% IF user.in_group(Param('timetrackinggroup')) %]
-    &lt;br&gt;
-    [% PROCESS section_timetracking %]
-  [% END %]
-  
</del><ins>+  &lt;table id=&quot;bz_big_form_parts&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;&lt;tr&gt;
+  &lt;td&gt;
+    [% IF user.is_timetracker %]
+      [% PROCESS section_timetracking %]
+    [% END %]
</ins><span class="cx"> 
</span><del>-[%# *** Attachments *** %]
</del><ins>+    [%# *** Attachments *** %]
</ins><span class="cx"> 
</span><del>-  [% PROCESS attachment/list.html.tmpl
-             attachments = bug.attachments
-             bugid       = bug.bug_id
-             num_attachment_flag_types = bug.num_attachment_flag_types
-             show_attachment_flags = bug.show_attachment_flags
-   %]
</del><ins>+    [% PROCESS attachment/list.html.tmpl
+               attachments = bug.attachments
+               bugid       = bug.bug_id
+               num_attachment_flag_types = bug.num_attachment_flag_types
+               show_attachment_flags = bug.show_attachment_flags
+    %]
</ins><span class="cx"> 
</span><ins>+    [% IF user.settings.comment_box_position.value == 'before_comments' %]
+      [% PROCESS comment_box %]
+    [% END %]
+  &lt;/td&gt;
+  &lt;td&gt;
+    [% PROCESS section_restrict_visibility %]
+  &lt;/td&gt;
+  &lt;/tr&gt;&lt;/table&gt;
</ins><span class="cx"> 
</span><del>-[%# *** Comments Groups *** %]
</del><ins>+  [%# *** Additional Comments *** %]
+  &lt;div id=&quot;comments&quot;&gt;
+    [% PROCESS bug/comments.html.tmpl
+      comments = bug.comments
+      mode = user.id ? &quot;edit&quot; : &quot;show&quot;
+    %]
+  &lt;/div&gt;
</ins><span class="cx"> 
</span><del>-  &lt;br&gt;
-  &lt;table cellpadding=&quot;1&quot; cellspacing=&quot;1&quot;&gt;
-    &lt;tr&gt;
-      &lt;td id=&quot;comment_status_commit&quot;&gt;
-        &lt;!-- The table keeps the commit button aligned with the box. --&gt;
-        &lt;a name=&quot;add_comment&quot;&gt;&lt;/a&gt;
-        [% IF user.id %]
-        &lt;table&gt;&lt;tr&gt;&lt;td&gt;
-          &lt;label for=&quot;comment&quot; accesskey=&quot;c&quot;&gt;&lt;b&gt;Additional &lt;u&gt;C&lt;/u&gt;omments&lt;/b&gt;&lt;/label&gt;:
-          [% IF Param(&quot;insidergroup&quot;) &amp;&amp; user.in_group(Param(&quot;insidergroup&quot;)) %]
-            &lt;input type=&quot;checkbox&quot; name=&quot;commentprivacy&quot; value=&quot;1&quot;
-                   id=&quot;newcommentprivacy&quot;
-                   onClick=&quot;updateCommentTagControl(this, form)&quot;&gt;
-            &lt;label for=&quot;newcommentprivacy&quot;&gt;Private&lt;/label&gt;
-          [% END %]
-          &lt;br&gt;
-          [% INCLUDE global/textarea.html.tmpl
-                     name      = 'comment'
-                     id        = 'comment'
-                     minrows   = 10
-                     maxrows   = 25
-                     cols      = constants.COMMENT_COLS
-          %]
-          &lt;br&gt;
-          &lt;div id=&quot;knob-buttons&quot;&gt;
-            &lt;input type=&quot;submit&quot; value=&quot;Commit&quot; id=&quot;commit&quot;&gt;
-            [% IF bug.user.canmove %]
-              &lt;input type=&quot;submit&quot; name=&quot;action&quot; id=&quot;action&quot; value=&quot;[% Param(&quot;move-button-text&quot;) %]&quot;&gt;
-            [% END %]
-          &lt;/div&gt;
-          &lt;table class=&quot;status&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
-            &lt;tr&gt;
-              &lt;td class=&quot;field_label&quot;&gt;
-                &lt;b&gt;&lt;a href=&quot;page.cgi?id=fields.html#status&quot;&gt;Status&lt;/a&gt;&lt;/b&gt;:
-              &lt;/td&gt;
-              &lt;td&gt;
-                &lt;a name=&quot;bug_status_bottom&quot;&gt;&lt;/a&gt;
-                [% PROCESS bug/knob.html.tmpl %]
-              &lt;/td&gt;
-            &lt;/tr&gt;
-          &lt;/table&gt;
-        &lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
-        [% ELSE %]
-          &lt;fieldset&gt;
-            &lt;legend&gt;Note&lt;/legend&gt;
-            &lt;p&gt;
-              You need to
-              &lt;a href=&quot;[% IF Param('ssl') != 'never' %][% Param('sslbase') %][% END %]show_bug.cgi?id=[% bug.bug_id %]&amp;amp;GoAheadAndLogIn=1&quot;&gt;log in&lt;/a&gt;
-              before you can comment on or make changes to this [% terms.bug %].
-            &lt;/p&gt;
-          &lt;/fieldset&gt;
-        [% END %]
-        [%# *** Additional Comments *** %]
-        &lt;hr&gt;
-        &lt;div id=&quot;comments&quot;&gt;
-        [% PROCESS bug/comments.html.tmpl
-           comments = bug.longdescs
-           mode = user.id ? &quot;edit&quot; : &quot;show&quot;
-         %]
-        &lt;/div&gt;
-        
-      &lt;/td&gt;
-    &lt;/tr&gt;
-  &lt;/table&gt;
</del><ins>+  [% IF user.settings.comment_box_position.value == 'after_comments' %]
+    &lt;hr&gt;
+    [% PROCESS comment_box %]
+  [% END %]        
+
</ins><span class="cx"> &lt;/form&gt;
</span><span class="cx"> 
</span><span class="cx"> [%############################################################################%]
</span><span class="lines">@@ -303,17 +250,17 @@
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK section_title %]
</span><span class="cx">   [%# That's the main table, which contains all editable fields. %]
</span><del>-  &lt;div class=&quot;bz_alias_short_desc_container&quot;&gt;
-    
</del><ins>+  &lt;div class=&quot;bz_alias_short_desc_container edit_form&quot;&gt;
+      [% PROCESS commit_button id=&quot;_top&quot;%]
</ins><span class="cx">      &lt;a href=&quot;show_bug.cgi?id=[% bug.bug_id %]&quot;&gt;
</span><del>-        &lt;b&gt;[% terms.Bug %]&amp;nbsp;[% bug.bug_id FILTER html %]&lt;/b&gt;&lt;/a&gt; - 
-     &lt;span id=&quot;summary_alias_container&quot; class=&quot;bz_default_hidden&quot;&gt; 
</del><ins>+        [%-# %]&lt;b&gt;[% terms.Bug %]&amp;nbsp;[% bug.bug_id FILTER html %]&lt;/b&gt;
+     [%-# %]&lt;/a&gt; -&lt;span id=&quot;summary_alias_container&quot; class=&quot;bz_default_hidden&quot;&gt; 
</ins><span class="cx">       [% IF Param(&quot;usebugaliases&quot;) %]
</span><span class="cx">         [% IF bug.alias != &quot;&quot; %]
</span><span class="cx">           (&lt;span id=&quot;alias_nonedit_display&quot;&gt;[% bug.alias FILTER html %]&lt;/span&gt;) 
</span><span class="cx">         [% END %]
</span><span class="cx">       [% END %]
</span><del>-      &lt;span id=&quot;short_desc_nonedit_display&quot;&gt;[% bug.short_desc FILTER html %]&lt;/span&gt;
</del><ins>+      &lt;span id=&quot;short_desc_nonedit_display&quot;&gt;[% bug.short_desc FILTER quoteUrls(bug) %]&lt;/span&gt;
</ins><span class="cx">       [% IF bug.check_can_change_field('short_desc', 0, 1) || 
</span><span class="cx">             bug.check_can_change_field('alias', 0, 1)  %]
</span><span class="cx">         &lt;small class=&quot;editme&quot;&gt;(&lt;a href=&quot;#&quot; id=&quot;editme_action&quot;&gt;edit&lt;/a&gt;)&lt;/small&gt;
</span><span class="lines">@@ -375,23 +322,35 @@
</span><span class="cx">     [%#  PRODUCT  #%]
</span><span class="cx">     [%#############%]
</span><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;td class=&quot;field_label&quot;&gt;
-        &lt;label for=&quot;product&quot; accesskey=&quot;p&quot;&gt;&lt;b&gt;&lt;u&gt;P&lt;/u&gt;roduct&lt;/b&gt;&lt;/label&gt;:
-      &lt;/td&gt;
-      [% PROCESS select selname =&gt; &quot;product&quot; %]
</del><ins>+       [% INCLUDE bug/field.html.tmpl
+            bug = bug, field = bug_fields.product,
+            override_legal_values = bug.choices.product
+            desc_url = 'describecomponents.cgi', value = bug.product
+            editable = bug.check_can_change_field('product', 0, 1) %]
</ins><span class="cx">     &lt;/tr&gt;
</span><ins>+
+    [%# Classification is here so that it can be used in value controllers
+      # and visibility controllers. It comes after product because
+      # it uses some javascript that depends on the existence of the
+      # product field.
+      #%]
+    &lt;tr class=&quot;bz_default_hidden&quot;&gt;
+       [% INCLUDE bug/field.html.tmpl
+            bug = bug field = bug_fields.classification
+            override_legal_values = bug.choices.classification
+            value = bug.classification
+            editable = bug.check_can_change_field('product', 0, 1) %]
+    &lt;/tr&gt;
</ins><span class="cx">     [%###############%]    
</span><span class="cx">     [%#  Component  #%]
</span><span class="cx">     [%###############%]
</span><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;td class=&quot;field_label&quot;&gt;
-        &lt;label for=&quot;component&quot; accesskey=&quot;m&quot;&gt;
-          &lt;b&gt;&lt;a href=&quot;describecomponents.cgi?product=[% bug.product FILTER url_quote %]&quot;&gt;
-            Co&lt;u&gt;m&lt;/u&gt;ponent&lt;/a&gt;:
-          &lt;/b&gt;
-        &lt;/label&gt;
-      &lt;/td&gt;
-      [% PROCESS select selname =&gt; &quot;component&quot; %]
</del><ins>+      [% INCLUDE bug/field.html.tmpl
+          bug = bug, field = bug_fields.component, value = bug.component
+          override_legal_values = bug.choices.component
+          desc_url = &quot;describecomponents.cgi?product=$bug.product&quot;
+          editable = bug.check_can_change_field('component', 0, 1)
+      %]
</ins><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;td class=&quot;field_label&quot;&gt;
</span><span class="lines">@@ -411,11 +370,19 @@
</span><span class="cx">       &lt;td class=&quot;field_label&quot;&gt;
</span><span class="cx">         &lt;label for=&quot;rep_platform&quot; accesskey=&quot;h&quot;&gt;&lt;b&gt;Platform&lt;/b&gt;&lt;/label&gt;:
</span><span class="cx">       &lt;/td&gt;
</span><del>-      &lt;td&gt;
-       [% PROCESS select selname =&gt; &quot;rep_platform&quot; no_td=&gt; 1 %]
-       [%+ PROCESS select selname =&gt; &quot;op_sys&quot; no_td=&gt; 1 %]
</del><ins>+      &lt;td class=&quot;field_value&quot;&gt;
+       [% INCLUDE bug/field.html.tmpl
+            bug = bug, field = bug_fields.rep_platform,
+            no_tds = 1, value = bug.rep_platform
+            editable = bug.check_can_change_field('rep_platform', 0, 1) %]
+       [%+ INCLUDE bug/field.html.tmpl 
+            bug = bug, field = bug_fields.op_sys, 
+            no_tds = 1, value = bug.op_sys
+            editable = bug.check_can_change_field('op_sys', 0, 1) %]
</ins><span class="cx">        &lt;script type=&quot;text/javascript&quot;&gt;
</span><ins>+[%# if WEBKIT_CHANGES %]
</ins><span class="cx">          assignToDefaultOnChange(['product']);
</span><ins>+[%# endif // WEBKIT_CHANGES %]
</ins><span class="cx">        &lt;/script&gt;
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="lines">@@ -435,9 +402,9 @@
</span><span class="cx">     &lt;/td&gt;
</span><span class="cx">     &lt;td id=&quot;bz_field_status&quot;&gt;
</span><span class="cx">       &lt;span id=&quot;static_bug_status&quot;&gt;
</span><del>-        [% get_status(bug.bug_status) FILTER html %]
</del><ins>+        [% display_value(&quot;bug_status&quot;, bug.bug_status) FILTER html %]
</ins><span class="cx">         [% IF bug.resolution %]
</span><del>-          [%+ get_resolution(bug.resolution) FILTER html %]
</del><ins>+          [%+ display_value(&quot;resolution&quot;, bug.resolution) FILTER html %]
</ins><span class="cx">           [% IF bug.dup_id %]
</span><span class="cx">             of [% &quot;${terms.bug} ${bug.dup_id}&quot; FILTER bug_link(bug.dup_id) FILTER none %]
</span><span class="cx">           [% END %]
</span><span class="lines">@@ -458,7 +425,7 @@
</span><span class="cx"> [% BLOCK section_details2 %]
</span><span class="cx"> 
</span><span class="cx">  [%###############################################################%]
</span><del>- [%# Importance (priority, severity and votes) #%]
</del><ins>+ [%# Importance (priority and severity) #%]
</ins><span class="cx">  [%###############################################################%]
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;td class=&quot;field_label&quot;&gt;
</span><span class="lines">@@ -468,40 +435,29 @@
</span><span class="cx"> [%# endif // WEBKIT_CHANGES %]
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">       &lt;td&gt;
</span><del>-        [% PROCESS select selname =&gt; &quot;priority&quot; no_td=&gt;1 %] 
</del><ins>+       [% INCLUDE bug/field.html.tmpl
+            bug = bug, field = bug_fields.priority,
+            no_tds = 1, value = bug.priority
+            editable = bug.check_can_change_field('priority', 0, 1) %]
</ins><span class="cx"> [%# if WEBKIT_CHANGES %]
</span><del>-        [% PROCESS select selname =&gt; &quot;bug_severity&quot; no_td=&gt;1 accesskey =&gt; &quot;e&quot; %]
</del><ins>+       [%+ INCLUDE bug/field.html.tmpl
+            bug = bug, field = bug_fields.bug_severity,
+            no_tds = 1, value = bug.bug_severity
+            accesskey = 'e'
+            editable = bug.check_can_change_field('bug_severity', 0, 1) %]
</ins><span class="cx"> [%# endif // WEBKIT_CHANGES %]
</span><del>-        [% IF bug.use_votes %]
-          &lt;span id=&quot;votes_container&quot;&gt;
-          [% IF bug.votes %] 
-            with 
-            &lt;a href=&quot;votes.cgi?action=show_bug&amp;amp;bug_id=[% bug.bug_id %]&quot;&gt;
-              [% bug.votes %] 
-              [% IF bug.votes == 1 %]
-                vote
-              [% ELSE %]
-                votes
-              [% END %]&lt;/a&gt; 
-          [% END %]    
-          (&lt;a href=&quot;votes.cgi?action=show_user&amp;amp;bug_id=
-                  [% bug.bug_id %]#vote_[% bug.bug_id %]&quot;&gt;vote&lt;/a&gt;)
-          &lt;/span&gt;  
-        [% END %]
</del><ins>+        [% Hook.process('after_importance', 'bug/edit.html.tmpl') %]
</ins><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx"> 
</span><span class="cx">     [% IF Param(&quot;usetargetmilestone&quot;) &amp;&amp; bug.target_milestone %]
</span><span class="cx">       &lt;tr&gt;
</span><span class="cx">         &lt;td class=&quot;field_label&quot;&gt;
</span><del>-          &lt;label for=&quot;target_milestone&quot;&gt;&lt;b&gt;
-            [% IF bug.milestoneurl %]
-              &lt;a href=&quot;[% bug.milestoneurl FILTER html %]&quot;&gt;
-            [% END %]
</del><ins>+          &lt;label for=&quot;target_milestone&quot;&gt;
+              &lt;a href=&quot;page.cgi?id=fields.html#target_milestone&quot;&gt;
</ins><span class="cx"> [%# if WEBKIT_CHANGES %]
</span><del>-            &lt;u&gt;T&lt;/u&gt;arget&amp;nbsp;Milestone[% &quot;&lt;/a&gt;&quot; IF bug.milestoneurl %]
</del><ins>+            &lt;u&gt;T&lt;/u&gt;arget&amp;nbsp;Milestone&lt;/a&gt;&lt;/label&gt;:
</ins><span class="cx"> [%# endif // WEBKIT_CHANGES %]
</span><del>-          [%%]&lt;/b&gt;&lt;/label&gt;:
</del><span class="cx">         &lt;/td&gt;
</span><span class="cx"> [%# if WEBKIT_CHANGES %]
</span><span class="cx">         [% PROCESS select selname =&gt; &quot;target_milestone&quot; accesskey =&gt; &quot;t&quot; %]
</span><span class="lines">@@ -525,8 +481,12 @@
</span><span class="cx">         [% IF bug.check_can_change_field(&quot;assigned_to&quot;, 0, 1) %]
</span><span class="cx">           &lt;div id=&quot;bz_assignee_edit_container&quot; class=&quot;bz_default_hidden&quot;&gt;
</span><span class="cx">             &lt;span&gt;
</span><del>-              [% INCLUDE user_identity user=&gt; bug.assigned_to %]
</del><ins>+              [% INCLUDE global/user.html.tmpl who = bug.assigned_to %]
</ins><span class="cx">               (&lt;a href=&quot;#&quot; id=&quot;bz_assignee_edit_action&quot;&gt;edit&lt;/a&gt;)
</span><ins>+              [% IF bug.assigned_to.id != user.id %]
+                (&lt;a title=&quot;Reassign to yourself&quot; 
+                    href=&quot;#&quot; id=&quot;bz_assignee_take_action&quot;&gt;take&lt;/a&gt;)
+              [% END %]
</ins><span class="cx">             &lt;/span&gt;
</span><span class="cx">           &lt;/div&gt;
</span><span class="cx">           &lt;div id=&quot;bz_assignee_input&quot;&gt;
</span><span class="lines">@@ -534,6 +494,7 @@
</span><span class="cx">                  id =&gt; &quot;assigned_to&quot;
</span><span class="cx">                  name =&gt; &quot;assigned_to&quot;
</span><span class="cx">                  value =&gt; bug.assigned_to.login
</span><ins>+                 classes =&gt; [&quot;bz_userfield&quot;]
</ins><span class="cx">                  size =&gt; 30
</span><span class="cx">             %]
</span><span class="cx">             &lt;br&gt;
</span><span class="lines">@@ -546,10 +507,16 @@
</span><span class="cx">                              'bz_assignee_edit_action', 
</span><span class="cx">                              'assigned_to', 
</span><span class="cx">                              '[% bug.assigned_to.login FILTER js %]' );
</span><ins>+           hideEditableField('bz_assignee_edit_container',
+                             'bz_assignee_input',
+                             'bz_assignee_take_action',
+                             'assigned_to',
+                             '[% bug.assigned_to.login FILTER js %]',
+                             '[% user.login FILTER js %]' );
</ins><span class="cx">            initDefaultCheckbox('assignee');                  
</span><span class="cx">           &lt;/script&gt;
</span><span class="cx">         [% ELSE %]
</span><del>-          [% INCLUDE user_identity user =&gt; bug.assigned_to %]
</del><ins>+          [% INCLUDE global/user.html.tmpl who = bug.assigned_to %]
</ins><span class="cx">         [% END %]
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="lines">@@ -560,13 +527,12 @@
</span><span class="cx">         &lt;label for=&quot;qa_contact&quot; accesskey=&quot;q&quot;&gt;&lt;b&gt;&lt;u&gt;Q&lt;/u&gt;A Contact&lt;/b&gt;&lt;/label&gt;:
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">       &lt;td&gt;
</span><del>-
</del><span class="cx">         [% IF bug.check_can_change_field(&quot;qa_contact&quot;, 0, 1) %]
</span><span class="cx">           [% IF bug.qa_contact != &quot;&quot; %]
</span><span class="cx">            &lt;div id=&quot;bz_qa_contact_edit_container&quot; class=&quot;bz_default_hidden&quot;&gt;
</span><span class="cx">             &lt;span&gt;
</span><span class="cx">               &lt;span id=&quot;bz_qa_contact_edit_display&quot;&gt;
</span><del>-              [% INCLUDE user_identity user=&gt; bug.qa_contact %]&lt;/span&gt;
</del><ins>+              [% INCLUDE global/user.html.tmpl who = bug.qa_contact %]&lt;/span&gt;
</ins><span class="cx">               (&lt;a href=&quot;#&quot; id=&quot;bz_qa_contact_edit_action&quot;&gt;edit&lt;/a&gt;)
</span><span class="cx">             &lt;/span&gt;
</span><span class="cx">           &lt;/div&gt;
</span><span class="lines">@@ -577,6 +543,7 @@
</span><span class="cx">                 name =&gt; &quot;qa_contact&quot;
</span><span class="cx">                 value =&gt; bug.qa_contact.login
</span><span class="cx">                 size =&gt; 30
</span><ins>+                classes =&gt; [&quot;bz_userfield&quot;]
</ins><span class="cx">                 emptyok =&gt; 1
</span><span class="cx">             %]
</span><span class="cx">             &lt;br&gt;
</span><span class="lines">@@ -594,7 +561,7 @@
</span><span class="cx">             initDefaultCheckbox('qa_contact');
</span><span class="cx">           &lt;/script&gt;
</span><span class="cx">         [% ELSE %]
</span><del>-          [% INCLUDE user_identity user =&gt; bug.qa_contact %]
</del><ins>+          [% INCLUDE global/user.html.tmpl who = bug.qa_contact %]
</ins><span class="cx">         [% END %]
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="lines">@@ -605,23 +572,16 @@
</span><span class="cx"> [%# Block for URL Keyword and Whiteboard                                     #%]
</span><span class="cx"> [%############################################################################%]
</span><span class="cx"> [% BLOCK section_url_keyword_whiteboard %]
</span><del>-[%# *** URL Whiteboard Keywords *** %]
</del><span class="cx">   &lt;tr&gt;
</span><del>-    &lt;td class=&quot;field_label&quot;&gt;
-      &lt;label for=&quot;bug_file_loc&quot; accesskey=&quot;u&quot;&gt;&lt;b&gt;
-        [% IF bug.bug_file_loc 
-           AND NOT bug.bug_file_loc.match(&quot;^(javascript|data)&quot;) %]
-          &lt;a href=&quot;[% bug.bug_file_loc FILTER html %]&quot;&gt;&lt;u&gt;U&lt;/u&gt;RL&lt;/a&gt;
-        [% ELSE %]
-          &lt;u&gt;U&lt;/u&gt;RL
-        [% END %]
-      [%%]&lt;/b&gt;&lt;/label&gt;:
-    &lt;/td&gt;
</del><ins>+    [% INCLUDE &quot;bug/field-label.html.tmpl&quot;
+      field = bug_fields.bug_file_loc
+      editable = 1
+      accesskey = &quot;u&quot;
+    %]
</ins><span class="cx">     &lt;td&gt;
</span><span class="cx">       [% IF bug.check_can_change_field(&quot;bug_file_loc&quot;, 0, 1) %]
</span><span class="cx">         &lt;span id=&quot;bz_url_edit_container&quot; class=&quot;bz_default_hidden&quot;&gt; 
</span><del>-        [% IF bug.bug_file_loc 
-           AND NOT bug.bug_file_loc.match(&quot;^(javascript|data)&quot;) %]
</del><ins>+        [% IF is_safe_url(bug.bug_file_loc) %]
</ins><span class="cx">            &lt;a href=&quot;[% bug.bug_file_loc FILTER html %]&quot; target=&quot;_blank&quot;
</span><span class="cx">               title=&quot;[% bug.bug_file_loc FILTER html %]&quot;&gt;
</span><span class="cx">              [% bug.bug_file_loc FILTER truncate(40) FILTER html %]&lt;/a&gt;
</span><span class="lines">@@ -632,7 +592,8 @@
</span><span class="cx">       [% END %]
</span><span class="cx">       &lt;span id=&quot;bz_url_input_area&quot;&gt;
</span><span class="cx">         [% url_output =  PROCESS input no_td=1 inputname =&gt; &quot;bug_file_loc&quot; size =&gt; &quot;40&quot; colspan =&gt; 2 %]
</span><del>-        [% IF NOT bug.check_can_change_field(&quot;bug_file_loc&quot;, 0, 1)  %]
</del><ins>+        [% IF NOT bug.check_can_change_field(&quot;bug_file_loc&quot;, 0, 1)
+              AND is_safe_url(bug.bug_file_loc) %]
</ins><span class="cx">           &lt;a href=&quot;[% bug.bug_file_loc FILTER html %]&quot;&gt;[% url_output FILTER none %]&lt;/a&gt;
</span><span class="cx">         [% ELSE %]
</span><span class="cx">           [% url_output FILTER none %]
</span><span class="lines">@@ -665,8 +626,13 @@
</span><span class="cx">         &lt;label for=&quot;keywords&quot; accesskey=&quot;k&quot;&gt;
</span><span class="cx">           &lt;b&gt;&lt;a href=&quot;describekeywords.cgi&quot;&gt;&lt;u&gt;K&lt;/u&gt;eywords&lt;/a&gt;&lt;/b&gt;&lt;/label&gt;:
</span><span class="cx">       &lt;/td&gt;
</span><del>-      [% PROCESS input inputname =&gt; &quot;keywords&quot; size =&gt; 40 colspan =&gt; 2
-                       value =&gt; bug.keywords.join(', ') %]
</del><ins>+      &lt;td class=&quot;field_value&quot; colspan=&quot;2&quot;&gt;
+        [% INCLUDE bug/field.html.tmpl
+           bug = bug, field = bug_fields.keywords, value = bug.keywords
+           editable = bug.check_can_change_field(&quot;keywords&quot;, 0, 1),
+           no_tds = 1
+        %]
+      &lt;/td&gt;
</ins><span class="cx">     &lt;/tr&gt;
</span><span class="cx">   [% END %]
</span><span class="cx"> [% END %]
</span><span class="lines">@@ -676,15 +642,13 @@
</span><span class="cx"> [%############################################################################%]
</span><span class="cx"> [% BLOCK section_dependson_blocks %]
</span><span class="cx">   &lt;tr&gt;
</span><del>-[%# if WEBKIT_CHANGES %]
-    [% PROCESS dependencies accesskey = &quot;d&quot;
-               dep = { title =&gt; &quot;&lt;u&gt;D&lt;/u&gt;epends&amp;nbsp;on&quot;, fieldname =&gt; &quot;dependson&quot; } %]
-[%# endif // WEBKIT_CHANGES %]
</del><ins>+    [% INCLUDE dependencies 
+         field = bug_fields.dependson deps = bug.depends_on_obj %]
</ins><span class="cx">   &lt;/tr&gt;
</span><span class="cx">   
</span><span class="cx">   &lt;tr&gt;
</span><del>-    [% PROCESS dependencies accesskey = &quot;b&quot;
-               dep = { title =&gt; &quot;&lt;u&gt;B&lt;/u&gt;locks&quot;, fieldname =&gt; &quot;blocked&quot; } %]
</del><ins>+    [% INCLUDE dependencies 
+         field = bug_fields.blocked deps = bug.blocks_obj %]
</ins><span class="cx">   
</span><span class="cx">   &lt;tr&gt;
</span><span class="cx">     &lt;th&gt;&amp;nbsp;&lt;/th&gt;
</span><span class="lines">@@ -707,103 +671,93 @@
</span><span class="cx"> [% BLOCK section_restrict_visibility %]
</span><span class="cx">   [% RETURN UNLESS bug.groups.size %]
</span><span class="cx"> 
</span><del>-  [% inallgroups = 1 %]
-  [% inagroup = 0 %]
-  [% emitted_description = 0 %]
</del><ins>+  &lt;div class=&quot;bz_group_visibility_section&quot;&gt;
+    [% inallgroups = 1 %]
+    [% inagroup = 0 %]
+    [% emitted_description = 0 %]
</ins><span class="cx"> 
</span><del>-  [% FOREACH group = bug.groups %]
-    [% SET inallgroups = 0 IF NOT group.ingroup %]
-    [% SET inagroup = 1 IF group.ison %]
</del><ins>+    [% FOREACH group = bug.groups %]
+      [% SET inallgroups = 0 IF NOT group.ingroup %]
+      [% SET inagroup = 1 IF group.ison %]
</ins><span class="cx"> 
</span><del>-    [% NEXT IF group.mandatory %]
</del><ins>+      [% NEXT IF group.mandatory %]
</ins><span class="cx"> 
</span><del>-    [% IF NOT emitted_description %]
-      [% emitted_description = 1 %]
-      &lt;table&gt;
-        &lt;tr&gt;
-          &lt;td class=&quot;field_label&quot;&gt;
-            &lt;label id=&quot;bz_restrict_group_visibility_label&quot;&gt;&lt;b&gt;Restrict Group Visibility&lt;/b&gt;:&lt;/label&gt;
-          &lt;/td&gt;
-          &lt;td&gt;
-            &lt;div id=&quot;bz_restrict_group_visibility_help&quot;&gt;
-              &lt;b&gt;Only users in all of the selected groups can view this [% terms.bug %]:&lt;/b&gt;
-              &lt;br&gt;
-              &lt;small&gt;
-                (Unchecking all boxes makes this a more public [% terms.bug %].)
-              &lt;/small&gt;
-            &lt;/div&gt;
-    [% END %]
</del><ins>+      [% IF NOT emitted_description %]
+        [% emitted_description = 1 %]
+          &lt;div id=&quot;bz_restrict_group_visibility_help&quot;&gt;
+            &lt;b&gt;Only users in all of the selected groups can view this 
+              [%+ terms.bug %]:&lt;/b&gt;
+             &lt;p class=&quot;instructions&quot;&gt;
+               Unchecking all boxes makes this a more public [% terms.bug %].
+             &lt;/p&gt;
+          &lt;/div&gt;
+      [% END %]
</ins><span class="cx"> 
</span><del>-    [% IF group.ingroup %]
-      &lt;input type=&quot;hidden&quot; name=&quot;defined_bit-[% group.bit %]&quot; value=&quot;1&quot;&gt;
-    [% END %]
-    &lt;input type=&quot;checkbox&quot; value=&quot;1&quot; name=&quot;bit-[% group.bit %]&quot; id=&quot;bit-[% group.bit %]&quot;
-           [% ' checked=&quot;checked&quot;' IF group.ison %]
-           [% ' disabled=&quot;disabled&quot;' IF NOT group.ingroup %]&gt;
-    &lt;label for=&quot;bit-[% group.bit %]&quot;&gt;[% group.description FILTER html_light %]&lt;/label&gt;
-    &lt;br&gt;
-  [% END %]
</del><ins>+      [% IF group.ingroup %]
+        &lt;input type=&quot;hidden&quot; name=&quot;defined_groups&quot; 
+               value=&quot;[% group.name FILTER html %]&quot;&gt;
+      [% END %]
</ins><span class="cx"> 
</span><del>-  [% IF emitted_description %]
-    [% IF NOT inallgroups %]
-      &lt;b&gt;Only members of a group can change the visibility of [% terms.abug %] for that group.&lt;/b&gt;
</del><ins>+      &lt;input type=&quot;checkbox&quot; value=&quot;[% group.name FILTER html %]&quot;
+             name=&quot;groups&quot; id=&quot;group_[% group.bit %]&quot;
+             [% ' checked=&quot;checked&quot;' IF group.ison %]
+             [% ' disabled=&quot;disabled&quot;' IF NOT group.ingroup %]&gt;
+      &lt;label for=&quot;group_[% group.bit %]&quot;&gt;
+      [%- group.description FILTER html_light %]&lt;/label&gt;
</ins><span class="cx">       &lt;br&gt;
</span><span class="cx">     [% END %]
</span><del>-      &lt;/td&gt;
-    &lt;/tr&gt;
-    [% &quot;&lt;/table&gt;&quot; IF NOT inagroup %]
-  [% END %]
</del><span class="cx"> 
</span><del>-  [% IF inagroup %]
-    [% IF NOT emitted_description %]
-      [% emitted_description = 1 %]
-      &lt;table&gt;
</del><ins>+    [% IF emitted_description %]
+      [% IF NOT inallgroups %]
+        &lt;p class=&quot;instructions&quot;&gt;Only members of a group can change the 
+          visibility of [% terms.abug %] for that group.&lt;/p&gt;
+      [% END %]
</ins><span class="cx">     [% END %]
</span><del>-    &lt;tr&gt;
-      &lt;td class=&quot;field_label&quot;&gt;
-        &lt;label id=&quot;bz_enable_role_visibility_label&quot;&gt;&lt;b&gt;Enable Role Visibility&lt;/b&gt;:&lt;/label&gt;
-      &lt;/td&gt;
-      &lt;td&gt;
-        &lt;div id=&quot;bz_enable_role_visibility_help&quot;&gt;
-          &lt;b&gt;Users in the roles selected below can always view this [% terms.bug %]:&lt;/b&gt;
-          &lt;br&gt;
-          &lt;small&gt;
-            (The assignee
-            [% IF (Param('useqacontact')) %]
-               and QA contact
-            [% END %]
-            can always see [% terms.abug %], and this section does not take effect unless
-            the [% terms.bug %] is restricted to at least one group.)
-          &lt;/small&gt;
</del><ins>+
+    [% IF inagroup %]
+      &lt;div id=&quot;bz_enable_role_visibility_help&quot;&gt;
+        &lt;b&gt;Users in the roles selected below can always view 
+          this [% terms.bug %]:&lt;/b&gt;
+      &lt;/div&gt;
+      &lt;div id=&quot;bz_enable_role_visibility&quot;&gt;
+        &lt;div&gt;
+          [% user_can_edit_accessible = 
+            bug.check_can_change_field(&quot;reporter_accessible&quot;, 0, 1) 
+          %]
+          [% IF user_can_edit_accessible %]
+            &lt;input type=&quot;hidden&quot; name=&quot;defined_reporter_accessible&quot; value=&quot;1&quot;&gt;
+          [% END %]
+          &lt;input type=&quot;checkbox&quot; value=&quot;1&quot;
+                 name=&quot;reporter_accessible&quot; id=&quot;reporter_accessible&quot;
+                 [% &quot; checked&quot; IF bug.reporter_accessible %]
+                 [% &quot; disabled=\&quot;disabled\&quot;&quot; UNLESS user_can_edit_accessible %]&gt;
+          &lt;label for=&quot;reporter_accessible&quot;&gt;Reporter&lt;/label&gt;
</ins><span class="cx">         &lt;/div&gt;
</span><span class="cx">         &lt;div&gt;
</span><del>-          &lt;div&gt;
-            [% user_can_edit_accessible = bug.check_can_change_field(&quot;reporter_accessible&quot;, 0, 1) %]
-            [% IF user_can_edit_accessible %]
-              &lt;input type=&quot;hidden&quot; name=&quot;defined_reporter_accessible&quot; value=&quot;1&quot;&gt;
-            [% END %]
-            &lt;input type=&quot;checkbox&quot; value=&quot;1&quot;
-                   name=&quot;reporter_accessible&quot; id=&quot;reporter_accessible&quot;
-                   [% &quot; checked&quot; IF bug.reporter_accessible %]
-                   [% &quot; disabled=\&quot;disabled\&quot;&quot; UNLESS user_can_edit_accessible %]&gt;
-            &lt;label for=&quot;reporter_accessible&quot;&gt;Reporter&lt;/label&gt;
-          &lt;/div&gt;
-          &lt;div&gt;
-            [% user_can_edit_accessible = bug.check_can_change_field(&quot;cclist_accessible&quot;, 0, 1) %]
-            [% IF user_can_edit_accessible %]
-              &lt;input type=&quot;hidden&quot; name=&quot;defined_cclist_accessible&quot; value=&quot;1&quot;&gt;
-            [% END %]
-            &lt;input type=&quot;checkbox&quot; value=&quot;1&quot;
-                   name=&quot;cclist_accessible&quot; id=&quot;cclist_accessible&quot;
-                   [% &quot; checked&quot; IF bug.cclist_accessible %]
-                   [% &quot; disabled=\&quot;disabled\&quot;&quot; UNLESS user_can_edit_accessible %]&gt;
-            &lt;label for=&quot;cclist_accessible&quot;&gt;CC List&lt;/label&gt;
-          &lt;/div&gt;
</del><ins>+          [% user_can_edit_accessible = 
+            bug.check_can_change_field(&quot;cclist_accessible&quot;, 0, 1) 
+          %]
+          [% IF user_can_edit_accessible %]
+            &lt;input type=&quot;hidden&quot; name=&quot;defined_cclist_accessible&quot; value=&quot;1&quot;&gt;
+          [% END %]
+          &lt;input type=&quot;checkbox&quot; value=&quot;1&quot;
+                 name=&quot;cclist_accessible&quot; id=&quot;cclist_accessible&quot;
+                 [% &quot; checked&quot; IF bug.cclist_accessible %]
+                 [% &quot; disabled=\&quot;disabled\&quot;&quot; UNLESS user_can_edit_accessible %]&gt;
+          &lt;label for=&quot;cclist_accessible&quot;&gt;CC List&lt;/label&gt;
</ins><span class="cx">         &lt;/div&gt;
</span><del>-      &lt;/td&gt;
-    &lt;/tr&gt;
-  &lt;/table&gt;
-  [% END %]
</del><ins>+        &lt;p class=&quot;instructions&quot;&gt;
+          The assignee
+          [% IF (Param('useqacontact')) %]
+             and QA contact
+          [% END %]
+          can always see [% terms.abug %], and this section does not
+          take effect unless the [% terms.bug %] is restricted to at
+          least one group.
+        &lt;/p&gt;
+      &lt;/div&gt;
+    [% END %]
+  &lt;/div&gt; [%# bz_group_visibility_section %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [%############################################################################%]
</span><span class="lines">@@ -816,7 +770,7 @@
</span><span class="cx">       &lt;b&gt;Reported&lt;/b&gt;:
</span><span class="cx">     &lt;/td&gt;
</span><span class="cx">     &lt;td&gt;
</span><del>-     [% bug.creation_ts FILTER time %] by [% INCLUDE user_identity user =&gt; bug.reporter %]
</del><ins>+     [% bug.creation_ts FILTER time %] by [% INCLUDE global/user.html.tmpl who = bug.reporter %]
</ins><span class="cx">     &lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx">   
</span><span class="lines">@@ -836,11 +790,10 @@
</span><span class="cx"> [%# Block for CC LIST                                                        #%]
</span><span class="cx"> [%############################################################################%]
</span><span class="cx"> [% BLOCK section_cclist %]
</span><del>-  [% IF user.id %]
</del><span class="cx">     &lt;tr&gt;
</span><del>-        &lt;td class=&quot;field_label&quot;&gt;
-          &lt;label for=&quot;newcc&quot; accesskey=&quot;a&quot;&gt;&lt;b&gt;CC List&lt;/b&gt;:&lt;/label&gt;
-        &lt;/td&gt;
</del><ins>+      &lt;td class=&quot;field_label&quot;&gt;
+        &lt;label for=&quot;newcc&quot; accesskey=&quot;a&quot;&gt;&lt;b&gt;CC List&lt;/b&gt;:&lt;/label&gt;
+      &lt;/td&gt;
</ins><span class="cx">       &lt;td&gt;
</span><span class="cx">         [% IF user.id %]
</span><span class="cx">           [% IF NOT bug.cc || NOT bug.cc.contains(user.login) %]
</span><span class="lines">@@ -869,47 +822,76 @@
</span><span class="cx">             including you
</span><span class="cx">           [% END %]
</span><span class="cx">         [% END %]
</span><del>-        &lt;span id=&quot;cc_edit_area_showhide_container&quot; class=&quot;bz_default_hidden&quot;&gt;
-          (&lt;a href=&quot;#&quot; id=&quot;cc_edit_area_showhide&quot;&gt;edit&lt;/a&gt;)
-        &lt;/span&gt;
</del><ins>+        [% IF user.id || bug.cc.size %]
+          &lt;span id=&quot;cc_edit_area_showhide_container&quot; class=&quot;bz_default_hidden&quot;&gt;
+            (&lt;a href=&quot;#&quot; id=&quot;cc_edit_area_showhide&quot;&gt;[% IF user.id %]edit[% ELSE %]show[% END %]&lt;/a&gt;)
+          &lt;/span&gt;
+        [% END %]
</ins><span class="cx">         &lt;div id=&quot;cc_edit_area&quot;&gt;
</span><del>-          &lt;div&gt;
</del><ins>+          &lt;br&gt;
+          [% IF user.id %]
</ins><span class="cx">             &lt;div&gt;
</span><del>-              &lt;label for=&quot;cc&quot;&gt;
-                &lt;b&gt;Add&lt;/b&gt;
-              &lt;/label&gt;
</del><ins>+              &lt;div&gt;&lt;label for=&quot;cc&quot;&gt;&lt;b&gt;Add&lt;/b&gt;&lt;/label&gt;&lt;/div&gt;
+              [% INCLUDE global/userselect.html.tmpl
+                  id =&gt; &quot;newcc&quot;
+                  name =&gt; &quot;newcc&quot;
+                  value =&gt; &quot;&quot;
+                  size =&gt; 30
+                  classes =&gt; [&quot;bz_userfield&quot;]
+                  multiple =&gt; 5
+                %]
</ins><span class="cx">             &lt;/div&gt;
</span><del>-            [% INCLUDE global/userselect.html.tmpl
-                id =&gt; &quot;newcc&quot;
-                name =&gt; &quot;newcc&quot;
-                value =&gt; &quot;&quot;
-                size =&gt; 30
-                multiple =&gt; 5
-              %]
-          &lt;/div&gt;
-        [% IF bug.cc %]
-          &lt;select id=&quot;cc&quot; name=&quot;cc&quot; multiple=&quot;multiple&quot; size=&quot;5&quot;&gt;
-          [% FOREACH c = bug.cc %]
-            &lt;option value=&quot;[% c FILTER html %]&quot;&gt;[% c FILTER html %]&lt;/option&gt;
</del><span class="cx">           [% END %]
</span><del>-          &lt;/select&gt;
-          [% IF user.id %]
-            &lt;br&gt;
-            &lt;input type=&quot;checkbox&quot; id=&quot;removecc&quot; name=&quot;removecc&quot;&gt;
-            [%%]&lt;label for=&quot;removecc&quot;&gt;Remove selected CCs&lt;/label&gt;
-            &lt;br&gt;
</del><ins>+          [% IF bug.cc %]
+            &lt;select id=&quot;cc&quot; multiple=&quot;multiple&quot; size=&quot;5&quot;
+              [% IF bug.user.canedit %]name=&quot;cc&quot;[% END %]&gt;
+              [% FOREACH c = bug.cc %]
+                &lt;option value=&quot;[% c FILTER email FILTER html %]&quot;&gt;
+                  [% c FILTER email FILTER html %]&lt;/option&gt;
+              [% END %]
+            &lt;/select&gt;
+            [% IF user.id &amp;&amp; !bug.user.canedit %]
+              &lt;input type=&quot;hidden&quot; name=&quot;cc&quot; value=&quot;[% user.login FILTER email FILTER html %]&quot;&gt;
+            [% END %]
+            [% IF user.id AND (bug.user.canedit OR bug.cc.contains(user.login)) %]
+              &lt;br&gt;
+              &lt;input type=&quot;checkbox&quot; id=&quot;removecc&quot; name=&quot;removecc&quot;&gt;
+              &lt;label for=&quot;removecc&quot;&gt;
+                [% IF bug.user.canedit %]
+                  Remove selected CCs
+                [% ELSE %]
+                  Remove me from the CC list
+                [% END %]
+              &lt;/label&gt;
+              &lt;br&gt;
+            [% END %]
</ins><span class="cx">           [% END %]
</span><ins>+        &lt;/div&gt;
+        [% IF user.id || bug.cc.size %]
+          &lt;script type=&quot;text/javascript&quot;&gt;
+            hideEditableField( 'cc_edit_area_showhide_container', 
+                               'cc_edit_area', 
+                               'cc_edit_area_showhide', 
+                               '', 
+                               '');  
+          &lt;/script&gt;
</ins><span class="cx">         [% END %]
</span><del>-        &lt;/div&gt;
-        &lt;script type=&quot;text/javascript&quot;&gt;
-          hideEditableField( 'cc_edit_area_showhide_container', 
-                             'cc_edit_area', 
-                             'cc_edit_area_showhide', 
-                             '', 
-                             '');  
-        &lt;/script&gt;
</del><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><ins>+[% END %]
+
+[%############################################################################%]
+[%# Block for See Also                                                       #%]
+[%############################################################################%]
+[% BLOCK section_see_also %]
+  [% IF Param('use_see_also') || bug.see_also.size %]
+    &lt;tr&gt;
+      [% INCLUDE bug/field.html.tmpl 
+           field    = bug_fields.see_also
+           value    = bug.see_also
+           editable = bug.check_can_change_field('see_also', 0, 1)
+      %]
+    &lt;/tr&gt;
</ins><span class="cx">   [% END %]
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="lines">@@ -928,30 +910,18 @@
</span><span class="cx">   [% END %]
</span><span class="cx">   [% IF show_bug_flags %]
</span><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;td class=&quot;field_label&quot;&gt;
</del><ins>+      &lt;td class=&quot;field_label flags_label&quot;&gt;
</ins><span class="cx">         &lt;label&gt;&lt;b&gt;Flags:&lt;/b&gt;&lt;/label&gt;
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">       &lt;td&gt;&lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;td colspan=&quot;2&quot;&gt;
</span><del>-      [% IF user.id %]
</del><span class="cx">         [% IF bug.flag_types.size &gt; 0 %]
</span><span class="cx">           [% PROCESS &quot;flag/list.html.tmpl&quot; flag_no_header = 1
</span><span class="cx">                                            flag_types = bug.flag_types
</span><span class="cx">                                            any_flags_requesteeble = bug.any_flags_requesteeble %]
</span><span class="cx">         [% END %]
</span><del>-      [% ELSE %]
-        [% FOREACH type = bug.flag_types %]
-          [% FOREACH flag = type.flags %]
-              [% flag.setter.nick FILTER html %]:
-              [%+ type.name FILTER html FILTER no_break %][% flag.status %]
-              [%+ IF flag.requestee %]
-                ([% flag.requestee.nick FILTER html %])
-              [% END %]&lt;br&gt;
-          [% END %]
-        [% END %]
-      [% END %]         
</del><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">   [% END %]
</span><span class="lines">@@ -963,14 +933,19 @@
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK section_customfields %]
</span><span class="cx"> [%# *** Custom Fields *** %]
</span><del>-
</del><span class="cx">   [% USE Bugzilla %]
</span><span class="cx">   [% FOREACH field = Bugzilla.active_custom_fields %]
</span><span class="cx">     &lt;tr&gt;
</span><del>-      [% PROCESS bug/field.html.tmpl value=bug.${field.name}
</del><ins>+      [% PROCESS bug/field.html.tmpl value = bug.${field.name}
</ins><span class="cx">                                      editable = bug.check_can_change_field(field.name, 0, 1)
</span><span class="cx">                                      value_span = 2 %]
</span><span class="cx">     &lt;/tr&gt;
</span><ins>+    [% IF extra_field_item %]
+      &lt;tr&gt;
+        &lt;th class=&quot;field_label&quot;&gt;[% extra_field_item.header FILTER none %]&lt;/th&gt;
+        &lt;td&gt;[% extra_field_item.data FILTER none %]&lt;/td&gt;
+      &lt;/tr&gt;
+    [% END %]
</ins><span class="cx">   [% END %]
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="lines">@@ -993,37 +968,36 @@
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK dependencies %]
</span><span class="cx"> 
</span><del>-  &lt;th class=&quot;field_label&quot;&gt;
-    &lt;label for=&quot;[% dep.fieldname %]&quot;[% &quot; accesskey=\&quot;$accesskey\&quot;&quot; IF accesskey %]&gt;
-    [% dep.title %]&lt;/label&gt;:
-  &lt;/th&gt;
-  &lt;td&gt;    
-    &lt;span id=&quot;[% dep.fieldname %]_input_area&quot;&gt;
-      [% IF bug.check_can_change_field(dep.fieldname, 0, 1) %]
-        &lt;input name=&quot;[% dep.fieldname %]&quot; id=&quot;[% dep.fieldname %]&quot;
-               value=&quot;[% bug.${dep.fieldname}.join(', ') %]&quot;&gt;
</del><ins>+  [% INCLUDE &quot;bug/field-label.html.tmpl&quot; %]
+
+  &lt;td&gt;
+    &lt;span id=&quot;[% field.name FILTER html %]_input_area&quot;&gt;
+      [% IF bug.check_can_change_field(field.name, 0, 1) %]
+        &lt;input name=&quot;[% field.name FILTER html %]&quot; 
+               id=&quot;[% field.name FILTER html %]&quot; class=&quot;text_input&quot;
+               value=&quot;[% bug.${field.name}.join(', ') FILTER html %]&quot;&gt;
</ins><span class="cx">       [% END %]
</span><span class="cx">     &lt;/span&gt;
</span><span class="cx">     
</span><del>-    [% FOREACH depbug = bug.${dep.fieldname} %]
-      [% depbug FILTER bug_link(depbug) FILTER none %][% &quot; &quot; %]
</del><ins>+    [% FOREACH dep_bug = deps %]
+      [% dep_bug.id FILTER bug_link(dep_bug, use_alias =&gt; 1)
+                    FILTER none %][% &quot; &quot; %]
</ins><span class="cx">     [% END %]
</span><del>-    [% IF bug.check_can_change_field(dep.fieldname, 0, 1) %]
-      &lt;span id=&quot;[% dep.fieldname %]_edit_container&quot; class=&quot;edit_me bz_default_hidden&quot; &gt;
-        (&lt;a href=&quot;#&quot; id=&quot;[% dep.fieldname %]_edit_action&quot;&gt;edit&lt;/a&gt;)
</del><ins>+    [% IF bug.check_can_change_field(field.name, 0, 1) %]
+      &lt;span id=&quot;[% field.name FILTER html %]_edit_container&quot; 
+            class=&quot;edit_me bz_default_hidden&quot;&gt;
+        (&lt;a href=&quot;#&quot; id=&quot;[% field.name FILTER html %]_edit_action&quot;&gt;edit&lt;/a&gt;)
</ins><span class="cx">       &lt;/span&gt;
</span><span class="cx">       &lt;script type=&quot;text/javascript&quot;&gt;
</span><del>-        hideEditableField('[% dep.fieldname %]_edit_container', 
-                          '[% dep.fieldname %]_input_area', 
-                          '[% dep.fieldname %]_edit_action', 
-                          '[% dep.fieldname %]', 
-                          &quot;[% bug.${dep.fieldname}.join(', ') %]&quot;);
</del><ins>+        hideEditableField('[% field.name FILTER js %]_edit_container', 
+                          '[% field.name FILTER js %]_input_area', 
+                          '[% field.name FILTER js %]_edit_action', 
+                          '[% field.name FILTER js %]', 
+                          '[% bug.${field.name}.join(', ') FILTER js %]');
</ins><span class="cx">       &lt;/script&gt;
</span><span class="cx">     [% END %]
</span><span class="cx">   &lt;/td&gt;
</span><span class="cx">   
</span><del>-  [% accesskey = undef %]
-  
</del><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [%############################################################################%]
</span><span class="lines">@@ -1086,9 +1060,9 @@
</span><span class="cx">         [% PROCESS formattimeunit time_unit=bug.estimated_time - (bug.actual_time + bug.remaining_time) %]
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">        &lt;td&gt;
</span><del>-         &lt;input name=&quot;deadline&quot; id=&quot;deadline&quot; value=&quot;[% bug.deadline %]&quot;
-                size=&quot;10&quot; maxlength=&quot;10&quot;&gt;&lt;br /&gt;
-         &lt;small&gt;(YYYY-MM-DD)&lt;/small&gt;
</del><ins>+         [% INCLUDE bug/field.html.tmpl
+           field = bug_fields.deadline, value = bug.deadline, no_tds = 1
+           editable = bug.check_can_change_field('deadline', 0, 1) %]
</ins><span class="cx">       &lt;/td&gt;        
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     &lt;tr&gt;
</span><span class="lines">@@ -1102,28 +1076,91 @@
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [%############################################################################%]
</span><ins>+[%# Block for the Additional Comments box                                    #%]
+[%############################################################################%]
+
+[% BLOCK comment_box %]
+  &lt;div id=&quot;add_comment&quot; class=&quot;bz_section_additional_comments&quot;&gt;
+    [% IF user.id %]
+      &lt;label for=&quot;comment&quot; accesskey=&quot;c&quot;&gt;&lt;b&gt;Additional 
+        &lt;u&gt;C&lt;/u&gt;omments&lt;/b&gt;&lt;/label&gt;:
+
+      [% IF user.is_insider %]
+        &lt;input type=&quot;checkbox&quot; name=&quot;comment_is_private&quot; value=&quot;1&quot;
+               id=&quot;newcommentprivacy&quot;
+               onClick=&quot;updateCommentTagControl(this, 'comment')&quot;&gt;
+        &lt;label for=&quot;newcommentprivacy&quot;&gt;
+          Make comment private (visible only to members of the
+          &lt;strong&gt;[% Param('insidergroup') FILTER html %]&lt;/strong&gt; group)
+        &lt;/label&gt;
+      [% END %]
+
+      &lt;!-- This table keeps the submit button aligned with the box. --&gt;
+      &lt;table&gt;&lt;tr&gt;&lt;td&gt;
+        [% INCLUDE global/textarea.html.tmpl
+                   name      = 'comment'
+                   id        = 'comment'
+                   minrows   = 10
+                   maxrows   = 25
+                   cols      = constants.COMMENT_COLS
+        %]
+        [% Hook.process(&quot;after_comment_textarea&quot;, 'bug/edit.html.tmpl') %]
+        &lt;br&gt;
+        [% PROCESS commit_button id=&quot;&quot;%]
+
+        &lt;table id=&quot;bug_status_bottom&quot;
+               class=&quot;status&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
+          &lt;tr&gt;
+            &lt;td class=&quot;field_label&quot;&gt;
+              &lt;b&gt;&lt;a href=&quot;page.cgi?id=fields.html#status&quot;&gt;Status&lt;/a&gt;&lt;/b&gt;:
+            &lt;/td&gt;
+            &lt;td&gt;
+              [% PROCESS bug/knob.html.tmpl %]
+            &lt;/td&gt;
+          &lt;/tr&gt;
+        &lt;/table&gt;
+      &lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
+
+    [%# For logged-out users %]
+    [% ELSE %]
+      &lt;table&gt;
+        &lt;tr&gt;
+          &lt;td&gt;
+            &lt;fieldset&gt;
+              &lt;legend&gt;Note&lt;/legend&gt;
+              You need to
+              &lt;a href=&quot;show_bug.cgi?id=
+                      [%- bug.bug_id %]&amp;amp;GoAheadAndLogIn=1&quot;&gt;log in&lt;/a&gt;
+              before you can comment on or make changes to this [% terms.bug %].
+            &lt;/fieldset&gt;
+          &lt;/td&gt;
+        &lt;/tr&gt; 
+      &lt;/table&gt;
+    [% END %]
+  &lt;/div&gt;
+[% END %]
+
+[%############################################################################%]
</ins><span class="cx"> [%# Block for SELECT fields                                                  #%]
</span><span class="cx"> [%############################################################################%]
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK select %]
</span><del>-  [% IF NOT no_td %]
</del><span class="cx">   &lt;td&gt;
</span><del>-  [% END %]
-    [% IF bug.check_can_change_field(selname, 0, 1) AND bug.choices.${selname}.size &gt; 1 %]
</del><ins>+    [% IF bug.check_can_change_field(selname, 0, 1) 
+          AND bug.choices.${selname}.size &gt; 1 %]
</ins><span class="cx">       &lt;select id=&quot;[% selname %]&quot; name=&quot;[% selname %]&quot;&gt;
</span><span class="cx">         [% FOREACH x = bug.choices.${selname} %]
</span><del>-          &lt;option value=&quot;[% x FILTER html %]&quot;
-            [% &quot; selected&quot; IF x == bug.${selname} %]&gt;[% x FILTER html %]
</del><ins>+          [% NEXT IF NOT x.is_active AND x.name != bug.${selname} %]
+          &lt;option value=&quot;[% x.name FILTER html %]&quot;
+            [% &quot; selected&quot; IF x.name == bug.${selname} %]&gt;
+            [%- x.name FILTER html %]
</ins><span class="cx">           &lt;/option&gt;
</span><span class="cx">         [% END %]
</span><span class="cx">       &lt;/select&gt;
</span><span class="cx">     [% ELSE %]
</span><span class="cx">       [% bug.${selname} FILTER html %]
</span><span class="cx">     [% END %]
</span><del>-  [% IF NOT no_td %]
</del><span class="cx">   &lt;/td&gt;
</span><del>-  [% END %]
-  [% no_td = 0 %]
</del><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [%############################################################################%]
</span><span class="lines">@@ -1136,7 +1173,7 @@
</span><span class="cx">   [% END %]
</span><span class="cx">     [% val = value ? value : bug.$inputname %]
</span><span class="cx">     [% IF bug.check_can_change_field(inputname, 0, 1) %]
</span><del>-       &lt;input id=&quot;[% inputname %]&quot; name=&quot;[% inputname %]&quot;
</del><ins>+       &lt;input id=&quot;[% inputname %]&quot; name=&quot;[% inputname %]&quot; class=&quot;text_input&quot;
</ins><span class="cx">               value=&quot;[% val FILTER html %]&quot;[% &quot; size=\&quot;$size\&quot;&quot; IF size %]
</span><span class="cx">               [% &quot; maxlength=\&quot;$maxlength\&quot;&quot; IF maxlength %]
</span><span class="cx">               [% &quot; spellcheck=\&quot;$spellcheck\&quot;&quot; IF spellcheck %]&gt;
</span><span class="lines">@@ -1159,23 +1196,11 @@
</span><span class="cx">   [% value = undef %]
</span><span class="cx">   [% spellcheck = undef %]
</span><span class="cx"> [% END %]
</span><del>-
-[%############################################################################%]
-[%# Block for user identities. Wraps the information inside of an hCard.     #%]
-[%############################################################################%]
-
-[% BLOCK user_identity %]
-  &lt;span class=&quot;vcard&quot;&gt;
-    [% FILTER collapse %]
-      [% IF user.name %]
-        &lt;a class=&quot;email&quot; href=&quot;mailto:[% user.email FILTER html %]&quot; 
-           title=&quot;[% user.email FILTER html %]&quot;
-          &gt;&lt;span class=&quot;fn&quot;&gt;[% user.name FILTER html %]&lt;/span
-        &gt;&lt;/a&gt;
-      [% ELSE %]
-        &lt;a class=&quot;fn email&quot; href=&quot;mailto:[% user.email FILTER html %]&quot;&gt;
-          [% user.email FILTER html %]&lt;/a&gt;
-      [% END %]
-    [% END %]&lt;/span&gt;
</del><ins>+[% BLOCK commit_button %]
+  [% IF user.id %]
+    &lt;div class=&quot;knob-buttons&quot;&gt;
+      &lt;input type=&quot;submit&quot; value=&quot;Save Changes&quot; 
+             id=&quot;commit[% id FILTER css_class_quote %]&quot;&gt;
+    &lt;/div&gt;
+  [% END %]
</ins><span class="cx"> [% END %]
</span><del>-
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateencustombugfieldhtmltmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/custom/bug/field.html.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/custom/bug/field.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/custom/bug/field.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,258 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Netscape Communications
+  # Corporation. Portions created by Netscape are
+  # Copyright (C) 1998 Netscape Communications Corporation. All
+  # Rights Reserved.
+  #
+  # Contributor(s): Myk Melez &lt;myk@mozilla.org&gt;
+  #                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #                 Elliotte Martin &lt;elliotte_martin@yahoo.com&gt;
+  #                 Guy Pyrzak &lt;guy.pyrzak@gmail.com&gt;
+  #                 Reed Loden &lt;reed@reedloden.com&gt;
+  #%]
+
+[%# INTERFACE:
+  #   field: a Bugzilla::Field object
+  #   value: The value of the field for this bug.
+  #   override_legal_values (optional): The list of legal values, for select fields.
+  #   editable: Whether the field should be displayed as an editable
+  #             &lt;input&gt; or as just the plain text of its value.
+  #   allow_dont_change: display the --do_not_change-- option for select fields.
+  #   value_span: A colspan for the table cell containing
+  #               the field value.
+  #   no_tds: boolean; if true, don't display the label &lt;th&gt; or the 
+  #           wrapping &lt;td&gt; for the field.
+  #   bug (optional): The current Bugzilla::Bug being displayed, or a hash 
+  #                   with default field values being displayed on a page.
+  #   accesskey: set an accesskey attribute for this string
+  #%]
+
+[% SET hidden = 0 %]
+[% IF bug AND !field.is_visible_on_bug(bug) %]
+  [% SET hidden = 1 %]
+[% END %]
+
+[% IF NOT no_tds %]
+  [% PROCESS &quot;bug/field-label.html.tmpl&quot; %]
+  &lt;td class=&quot;field_value [% ' bz_hidden_field' IF hidden %]&quot;
+      id=&quot;field_container_[% field.name FILTER html %]&quot; 
+      [% &quot; colspan=\&quot;$value_span\&quot;&quot; FILTER none IF value_span %]&gt;
+[% END %]
+[% Hook.process('start_field_column') %]
+[% IF editable %]
+  [% SWITCH field.type %]
+    [% CASE constants.FIELD_TYPE_FREETEXT %]
+        &lt;input id=&quot;[% field.name FILTER html %]&quot; class=&quot;text_input&quot;
+               name=&quot;[% field.name FILTER html %]&quot;
+               value=&quot;[% value FILTER html %]&quot; size=&quot;40&quot;
+[% IF accesskey %]
+               accesskey=&quot;[% accesskey FILTER html %]&quot;
+[% END %]
+               maxlength=&quot;[% constants.MAX_FREETEXT_LENGTH FILTER none %]&quot;
+               [% ' aria-required=&quot;true&quot;' IF field.is_mandatory %]&gt;
+    [% CASE constants.FIELD_TYPE_DATETIME %]
+      &lt;input name=&quot;[% field.name FILTER html %]&quot; size=&quot;20&quot;
+             id=&quot;[% field.name FILTER html %]&quot;
+             value=&quot;[% value FILTER html %]&quot;
+             [% ' aria-required=&quot;true&quot;' IF field.is_mandatory %]
+             onchange=&quot;updateCalendarFromField(this)&quot;&gt;
+      &lt;button type=&quot;button&quot; class=&quot;calendar_button&quot;
+              id=&quot;button_calendar_[% field.name FILTER html %]&quot;
+              onclick=&quot;showCalendar('[% field.name FILTER js %]')&quot;&gt;
+        &lt;span&gt;Calendar&lt;/span&gt;
+      &lt;/button&gt;
+
+      &lt;div id=&quot;con_calendar_[% field.name FILTER html %]&quot;&gt;&lt;/div&gt;
+
+      &lt;script type=&quot;text/javascript&quot;&gt;
+        createCalendar('[% field.name FILTER js %]')
+      &lt;/script&gt;
+    [% CASE constants.FIELD_TYPE_BUG_ID %]
+        &lt;span id=&quot;[% field.name FILTER html %]_input_area&quot;&gt;
+          &lt;input name=&quot;[% field.name FILTER html %]&quot; id=&quot;[% field.name FILTER html %]&quot;
+                 value=&quot;[% value FILTER html %]&quot; size=&quot;7&quot;
+                 [% ' aria-required=&quot;true&quot;' IF field.is_mandatory %]&gt;
+
+        &lt;/span&gt;
+
+        [% IF value %]  
+          [% value FILTER bug_link(value, use_alias =&gt; 1) FILTER none %]
+        [% END %]
+        &lt;span id=&quot;[% field.name FILTER html %]_edit_container&quot; class=&quot;edit_me bz_default_hidden&quot;&gt;
+          (&lt;a href=&quot;#&quot; id=&quot;[% field.name FILTER html %]_edit_action&quot;&gt;edit&lt;/a&gt;)
+        &lt;/span&gt;
+        &lt;script type=&quot;text/javascript&quot;&gt;
+        hideEditableField('[% field.name FILTER js %]_edit_container',
+                          '[% field.name FILTER js %]_input_area',
+                          '[% field.name FILTER js %]_edit_action',
+                          '[% field.name FILTER js %]',
+                          &quot;[% value FILTER js %]&quot;);
+        &lt;/script&gt;
+    [% CASE [ constants.FIELD_TYPE_SINGLE_SELECT 
+              constants.FIELD_TYPE_MULTI_SELECT ] %]
+        &lt;select id=&quot;[% field.name FILTER html %]&quot; 
+                name=&quot;[% field.name FILTER html %]&quot; 
+                [% IF field.type == constants.FIELD_TYPE_MULTI_SELECT %]
+                    [% SET field_size = 5 %]
+                    [% IF field.legal_values.size &lt; 5 %]
+                        [% SET field_size = field.legal_values.size %]
+                    [% END %]
+                    size=&quot;[% field_size FILTER html %]&quot; multiple=&quot;multiple&quot;
+                    [% ' aria-required=&quot;true&quot;' IF field.is_mandatory %]
+                [% END %]
+                &gt;
+          [% IF allow_dont_change %]
+            &lt;option value=&quot;[% dontchange FILTER html %]&quot;
+                   [% ' selected=&quot;selected&quot;' IF value == dontchange %]&gt;
+              [% dontchange FILTER html %]
+            &lt;/option&gt;
+          [% END %]
+          [% IF override_legal_values %]
+            [% legal_values = override_legal_values %]
+          [% ELSE %]
+            [% legal_values = field.legal_values %]
+          [% END %]
+          [% FOREACH legal_value = legal_values %]
+            [% NEXT IF NOT legal_value.is_active AND NOT value.contains(legal_value.name).size %]
+            &lt;option value=&quot;[% legal_value.name FILTER html %]&quot;
+                    id=&quot;v[% legal_value.id FILTER html %]_
+                        [%- field.name FILTER html %]&quot;
+              [%# We always show selected values, even if they should be
+                # hidden %]
+              [% IF value.contains(legal_value.name).size %]
+                selected=&quot;selected&quot;
+              [% ELSIF bug AND !legal_value.is_visible_on_bug(bug) %]
+                class=&quot;bz_hidden_option&quot; disabled=&quot;disabled&quot;
+              [% END %]&gt;
+              [%- display_value(field.name, legal_value.name) FILTER html ~%]
+            &lt;/option&gt;
+          [% END %]
+        &lt;/select&gt;
+        [%# When you pass an empty multi-select in the web interface,
+          # it doesn't appear at all in the CGI object. Instead of
+          # forcing all users of process_bug to always specify every
+          # multi-select, we have this field defined if the multi-select
+          # field is defined, and then if this is passed but the multi-select
+          # isn't, we know that the multi-select was emptied.
+        %]
+        [% IF field.type == constants.FIELD_TYPE_MULTI_SELECT %]
+          &lt;input type=&quot;hidden&quot; name=&quot;defined_[% field.name FILTER html %]&quot;&gt;
+        [% END %]
+
+        &lt;script type=&quot;text/javascript&quot;&gt;
+        &lt;!--
+          initHidingOptionsForIE('[% field.name FILTER js %]');
+          [%+ INCLUDE &quot;bug/field-events.js.tmpl&quot;
+                      field = field, product = bug.product_obj %]
+        //--&gt;
+        &lt;/script&gt;
+
+     [% CASE constants.FIELD_TYPE_TEXTAREA %]
+       [% INCLUDE global/textarea.html.tmpl
+           id = field.name name = field.name minrows = 4 maxrows = 8
+           cols = 60 defaultcontent = value mandatory = field.is_mandatory %]
+     [% CASE constants.FIELD_TYPE_BUG_URLS %]
+       [% '&lt;ul class=&quot;bug_urls&quot;&gt;' IF value.size %]
+       [% FOREACH bug_url = value %]
+         &lt;li&gt;
+           [% PROCESS bug_url_link bug_url = bug_url %]
+           &lt;label&gt;&lt;input type=&quot;checkbox&quot; value=&quot;[% bug_url.name FILTER html %]&quot;
+                         name=&quot;remove_[% field.name FILTER html %]&quot;&gt;
+             Remove&lt;/label&gt;
+         &lt;/li&gt;
+       [% END %]
+       [% '&lt;/ul&gt;' IF value.size %]
+
+       [% IF Param('use_see_also') %]
+         &lt;span id=&quot;container_showhide_[% field.name FILTER html %]&quot;
+               class=&quot;bz_default_hidden&quot;&gt;
+           &lt;a href=&quot;#&quot; id=&quot;showhide_[% field.name FILTER html %]&quot;&gt;(add)&lt;/a&gt;
+         &lt;/span&gt;
+         &lt;div id=&quot;container_[% field.name FILTER html %]&quot;&gt;
+           &lt;label for=&quot;[% field.name FILTER html %]&quot;&gt;
+             &lt;strong&gt;Add [% terms.Bug %] URLs:&lt;/strong&gt;
+           &lt;/label&gt;&lt;br&gt;
+           &lt;input type=&quot;text&quot; id=&quot;[% field.name FILTER html %]&quot; size=&quot;40&quot;
+                  class=&quot;text_input&quot; name=&quot;[% field.name FILTER html %]&quot;&gt;
+         &lt;/div&gt;
+         &lt;script type=&quot;text/javascript&quot;&gt;
+             setupEditLink('[% field.name FILTER js %]');
+         &lt;/script&gt;
+       [% END %]
+     [% CASE constants.FIELD_TYPE_KEYWORDS %]
+       &lt;div id=&quot;keyword_container&quot;&gt;
+         &lt;input type=&quot;text&quot; id=&quot;[% field.name FILTER html %]&quot; size=&quot;40&quot;
+                class=&quot;text_input&quot; name=&quot;[% field.name FILTER html %]&quot;
+                value=&quot;[% value FILTER html %]&quot;&gt;
+         &lt;div id=&quot;keyword_autocomplete&quot;&gt;&lt;/div&gt;
+       &lt;/div&gt;
+       &lt;script type=&quot;text/javascript&quot; defer=&quot;defer&quot;&gt;
+         YAHOO.bugzilla.keyword_array = [
+           [%- FOREACH keyword = all_keywords %]
+             [%-# %]&quot;[% keyword.name FILTER js %]&quot;
+             [%- &quot;,&quot; IF NOT loop.last %][% END %]];
+         YAHOO.bugzilla.keywordAutocomplete.init('[% field.name FILTER js %]', 
+                                                 'keyword_autocomplete');
+       &lt;/script&gt;
+  [% END %]
+[% ELSE %]
+  [% SWITCH field.type %]
+    [% CASE constants.FIELD_TYPE_TEXTAREA %]
+      &lt;div class=&quot;uneditable_textarea&quot;&gt;[% value FILTER html %]&lt;/div&gt;
+    [% CASE constants.FIELD_TYPE_BUG_ID %]
+      [% IF value %]  
+          [% value FILTER bug_link(value, use_alias =&gt; 1) FILTER none %]
+      [% END %]
+    [% CASE [ constants.FIELD_TYPE_SINGLE_SELECT 
+              constants.FIELD_TYPE_MULTI_SELECT ] %]
+      [% FOREACH val = value %]
+        [% display_value(field.name, val) FILTER html %]
+        [% ', ' UNLESS loop.last() %]
+      [% END %]
+    [% CASE constants.FIELD_TYPE_BUG_URLS %]
+      [% '&lt;ul class=&quot;bug_urls&quot;&gt;' IF value.size %]
+        [% FOREACH bug_url = value %]
+          &lt;li&gt;
+            [% PROCESS bug_url_link bug_url = bug_url %]
+          &lt;/li&gt;
+        [% END %]
+      [% '&lt;/ul&gt;' IF value.size %]
+    [% CASE %]
+      [% value.join(', ') FILTER html %]
+  [% END %]
+[% END %]
+[% Hook.process('end_field_column') %]
+[% '&lt;/td&gt;' IF NOT no_tds %]
+
+[%# for reverse relationships, we show this pseudo-field after the main field %]
+[% IF bug.id &amp;&amp; field.is_relationship %]
+    [% extra_field_item = {} %]
+    [% extra_field_item.header = field.reverse_desc _ &quot;:&quot; FILTER html %]
+    [% extra_field_item.data = BLOCK %]
+        [% FOREACH depbug = bug.related_bugs(field) %]
+            [% depbug.id FILTER bug_link(depbug, use_alias =&gt; 1) FILTER none %][% &quot; &quot; %]
+        [% END %]
+    [% END %]
+[% ELSE %]
+    [% extra_field_item = '' %]
+[% END %]
+
+[% BLOCK bug_url_link %]
+  [% IF bug_url.isa('Bugzilla::BugUrl::Bugzilla::Local') %]
+    [% bug_url.target_bug_id FILTER bug_link(bug_url.target_bug_id, use_alias =&gt; 1) FILTER none %]
+  [% ELSE %]
+    &lt;a href=&quot;[% bug_url.name FILTER html %]&quot;&gt;
+      [% bug_url.name FILTER html %]&lt;/a&gt;
+  [% END %]
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateencustombugformat_commenttxttmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/custom/bug/format_comment.txt.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/custom/bug/format_comment.txt.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/custom/bug/format_comment.txt.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,60 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Marc Schumann.
+  # Portions created by Marc Schumann are Copyright (c) 2008 Marc Schumann.
+  # All rights reserved.
+  #
+  # Contributor(s): Marc Schumann &lt;wurblzap@gmail.com&gt;
+  #%]
+
+[%# NOTE: Everywhere you use this template, you must call 
+  # &quot;FILTER remove('^X')&quot; on the result. This is unfortunately the only way
+  # to preserve leading whitespace in comments.
+  #%]
+
+[%# INTERFACE:
+  #   comment: A Bugzilla::Comment object.
+  #   is_bugmail: boolean; True if this comment is going into a plain-text
+  #               bugmail.
+  #%]
+
+[%# Please don't use field-descs here. It can slow down Bugzilla. %]
+[% PROCESS 'global/variables.none.tmpl' %]
+
+[% SET comment_body = comment.body %]
+
+[% IF comment.type == constants.CMT_DUPE_OF %]
+X[% comment_body %]
+
+*** This [% terms.bug %] has been marked as a duplicate of [% terms.bug %] [%+ comment.extra_data %] ***
+[% ELSIF comment.type == constants.CMT_HAS_DUPE %]
+*** [% terms.Bug %] [%+ comment.extra_data %] has been marked as a duplicate of this [% terms.bug %]. ***
+[% ELSIF comment.type == constants.CMT_ATTACHMENT_CREATED %]
+Created attachment [% comment.extra_data %]
+[% IF is_bugmail %]
+  --&gt; [% urlbase _ &quot;attachment.cgi?id=&quot; _ comment.extra_data _ &quot;&amp;action=review&quot; %]
+[% END %]
+[%+ comment.attachment.description %]
+
+[%+ comment.body %]
+[% ELSIF comment.type == constants.CMT_ATTACHMENT_UPDATED %]
+Comment on attachment [% comment.extra_data %]
+[% IF is_bugmail %]
+  --&gt; [% urlbase _ &quot;attachment.cgi?id=&quot; _ comment.extra_data %]
+[% END %]
+[%+ comment.attachment.description %]
+
+[%+ comment.body %]
+[% ELSE %]
+X[% Hook.process('type') %]
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateencustombugnavigatehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/custom/bug/navigate.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/custom/bug/navigate.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/custom/bug/navigate.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -16,17 +16,20 @@
</span><span class="cx">   # Rights Reserved.
</span><span class="cx">   #
</span><span class="cx">   # Contributor(s): Gervase Markham &lt;gerv@gerv.net&gt;
</span><ins>+  #                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><ins>+[% RETURN IF !bug %]
+
</ins><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="cx"> [% IF bottom_navigator == 1 %]
</span><span class="cx">   &lt;ul class=&quot;related_actions&quot;&gt;
</span><span class="cx">     &lt;li&gt;&lt;a href=&quot;show_bug.cgi?format=multiple&amp;amp;id=
</span><del>-                [% bug.bug_id FILTER url_quote %]&quot;&gt;Format For Printing&lt;/a&gt;&lt;/li&gt;
</del><ins>+                [% bug.bug_id FILTER uri %]&quot;&gt;Format For Printing&lt;/a&gt;&lt;/li&gt;
</ins><span class="cx">     &lt;li&gt;&amp;nbsp;-&amp;nbsp;&lt;a href=&quot;show_bug.cgi?ctype=xml&amp;amp;id=
</span><del>-                        [% bug.bug_id  FILTER url_quote %]&quot;&gt;XML&lt;/a&gt;&lt;/li&gt;
</del><ins>+                        [% bug.bug_id  FILTER uri %]&quot;&gt;XML&lt;/a&gt;&lt;/li&gt;
</ins><span class="cx">     &lt;li&gt;&amp;nbsp;-&amp;nbsp;&lt;a href=&quot;enter_bug.cgi?cloned_bug_id=
</span><del>-                        [% bug.bug_id  FILTER url_quote %]&quot;&gt;Clone This 
</del><ins>+                        [% bug.bug_id  FILTER uri %]&quot;&gt;Clone This 
</ins><span class="cx">                         [% terms.Bug %]&lt;/a&gt;&lt;/li&gt;
</span><span class="cx">     [%# Links to more things users can do with this bug. %]
</span><span class="cx">     [% Hook.process(&quot;links&quot;) %]
</span><span class="lines">@@ -36,61 +39,63 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> &lt;div class=&quot;navigation&quot;&gt;
</span><del>-[% IF bug_list &amp;&amp; bug_list.size &gt; 0 %]
-  [% this_bug_idx = lsearch(bug_list, bug.bug_id) %]
</del><ins>+[% SET my_search = user.recent_search_for(bug) %]
+[% IF my_search %]
+  [% SET last_bug_list = my_search.bug_list %]
+  [% SET this_bug_idx = lsearch(last_bug_list, bug.id) %]
</ins><span class="cx">   &lt;b&gt;[% terms.Bug %] List:&lt;/b&gt;
</span><del>-  [% IF this_bug_idx != -1 %]
-    ([% this_bug_idx + 1 %] of [% bug_list.size %])
-  [% END %]
</del><span class="cx"> 
</span><del>-[% IF this_bug_idx != -1 %]
</del><ins>+  ([% this_bug_idx + 1 %] of [% last_bug_list.size %])
+
+  &lt;a href=&quot;show_bug.cgi?id=
+           [%- last_bug_list.first FILTER uri %]&amp;amp;list_id=
</ins><span class="cx"> [%# if WEBKIT_CHANGES %]
</span><del>-  &lt;a href=&quot;show_bug.cgi?id=[% bug_list.first %]&quot;&gt;|&amp;laquo; First&lt;/a&gt;
-  &lt;a href=&quot;show_bug.cgi?id=[% bug_list.last %]&quot;&gt;Last &amp;raquo;|&lt;/a&gt;
</del><ins>+           [%- my_search.id FILTER uri %]&quot;&gt;|&amp;laquo;&amp;nbsp;First&lt;/a&gt;
</ins><span class="cx"> [%# endif // WEBKIT_CHANGES %]
</span><del>-[% END %]
</del><ins>+  &lt;a href=&quot;show_bug.cgi?id=
+           [%- last_bug_list.last FILTER uri %]&amp;amp;list_id=
+[%# if WEBKIT_CHANGES %]
+           [%- my_search.id FILTER uri %]&quot;&gt;Last&amp;nbsp;&amp;raquo;|&lt;/a&gt;
+[%# endif // WEBKIT_CHANGES %]
</ins><span class="cx"> 
</span><del>-  [% IF bug.bug_id %]
-    [% IF this_bug_idx != -1 %]
-      [% IF this_bug_idx &gt; 0 %]
-        [% prev_bug = this_bug_idx - 1 %]
</del><ins>+  [% IF this_bug_idx &gt; 0 %]
+    [% prev_bug = this_bug_idx - 1 %]
+    &lt;a href=&quot;show_bug.cgi?id=
+             [%- last_bug_list.$prev_bug FILTER uri %]&amp;amp;list_id=
</ins><span class="cx"> [%# if WEBKIT_CHANGES %]
</span><del>-        &lt;a href=&quot;show_bug.cgi?id=[% bug_list.$prev_bug %]&quot;&gt;&amp;laquo; Prev&lt;/a&gt;
</del><ins>+             [%- my_search.id FILTER uri %]&quot;&gt;&amp;laquo;&amp;nbsp;Prev&lt;/a&gt;
</ins><span class="cx"> [%# endif // WEBKIT_CHANGES %]
</span><del>-      [% ELSE %]
</del><ins>+  [% ELSE %]
</ins><span class="cx"> [%# if WEBKIT_CHANGES %]
</span><del>-        &lt;i&gt;&lt;font color=&quot;#777777&quot;&gt;&amp;laquo; Prev&lt;/font&gt;&lt;/i&gt;
</del><ins>+    &lt;i&gt;&lt;font color=&quot;#777777&quot;&gt;&amp;laquo;&amp;nbsp;Prev&lt;/font&gt;&lt;/i&gt;
</ins><span class="cx"> [%# endif // WEBKIT_CHANGES %]
</span><del>-      [% END %]
</del><ins>+  [% END %]
</ins><span class="cx"> 
</span><del>-      [% IF this_bug_idx + 1 &lt; bug_list.size %]
-        [% next_bug = this_bug_idx + 1 %]
</del><ins>+  [% IF this_bug_idx + 1 &lt; last_bug_list.size %]
+    [% next_bug = this_bug_idx + 1 %]
+    &lt;a href=&quot;show_bug.cgi?id=
+             [%- last_bug_list.$next_bug FILTER uri %]&amp;amp;list_id=
</ins><span class="cx"> [%# if WEBKIT_CHANGES %]
</span><del>-        &lt;a href=&quot;show_bug.cgi?id=[% bug_list.$next_bug %]&quot;&gt;Next &amp;raquo;&lt;/a&gt;
</del><ins>+             [%- my_search.id FILTER uri %]&quot;&gt;Next&amp;nbsp;&amp;raquo;&lt;/a&gt;
</ins><span class="cx"> [%# endif // WEBKIT_CHANGES %]
</span><del>-      [% ELSE %]
</del><ins>+  [% ELSE %]
</ins><span class="cx"> [%# if WEBKIT_CHANGES %]
</span><del>-        &lt;i&gt;&lt;font color=&quot;#777777&quot;&gt;Next &amp;raquo;&lt;/font&gt;&lt;/i&gt;
</del><ins>+    &lt;i&gt;&lt;font color=&quot;#777777&quot;&gt;Next&amp;nbsp;&amp;raquo;&lt;/font&gt;&lt;/i&gt;
</ins><span class="cx"> [%# endif // WEBKIT_CHANGES %]
</span><del>-      [% END %]
-    [% ELSE %]
-      (This [% terms.bug %] is not in your last search results)
-    [% END %]
-  [% ELSE %]
-    &amp;nbsp;&amp;nbsp;
</del><span class="cx">   [% END %]
</span><span class="cx"> 
</span><del>-  &amp;nbsp;&amp;nbsp;&lt;a href=&quot;buglist.cgi?regetlastlist=1&quot;&gt;Show last search results&lt;/a&gt;
</del><ins>+  &amp;nbsp;&amp;nbsp;&lt;a href=&quot;buglist.cgi?regetlastlist=
+              [%- my_search.id FILTER uri %]&quot;&gt;Show last search results&lt;/a&gt;
</ins><span class="cx"> [% ELSE %]
</span><del>-  [%# Either !bug_list || bug_list.size &lt;= 0 %]
</del><span class="cx">   [%# With no list, don't show link to search results %]
</span><span class="cx"> [%# if WEBKIT_CHANGES %]
</span><del>-  &lt;i&gt;&lt;font color=&quot;#777777&quot;&gt;|&amp;laquo; First&lt;/font&gt;&lt;/i&gt;
-  &lt;i&gt;&lt;font color=&quot;#777777&quot;&gt;Last &amp;raquo;|&lt;/font&gt;&lt;/i&gt;
-  &lt;i&gt;&lt;font color=&quot;#777777&quot;&gt;&amp;laquo; Prev&lt;/font&gt;&lt;/i&gt;
-  &lt;i&gt;&lt;font color=&quot;#777777&quot;&gt;Next &amp;raquo;&lt;/font&gt;&lt;/i&gt;
</del><ins>+  &lt;i&gt;&lt;font color=&quot;#777777&quot;&gt;|&amp;laquo;&amp;nbsp;First&lt;/font&gt;&lt;/i&gt;
+  &lt;i&gt;&lt;font color=&quot;#777777&quot;&gt;Last&amp;nbsp;&amp;raquo;|&lt;/font&gt;&lt;/i&gt;
+  &lt;i&gt;&lt;font color=&quot;#777777&quot;&gt;&amp;laquo;&amp;nbsp;Prev&lt;/font&gt;&lt;/i&gt;
+  &lt;i&gt;&lt;font color=&quot;#777777&quot;&gt;Next&amp;nbsp;&amp;raquo;&lt;/font&gt;&lt;/i&gt;
</ins><span class="cx"> [%# endif // WEBKIT_CHANGES %]
</span><span class="cx">   &amp;nbsp;&amp;nbsp;
</span><del>-  &lt;i&gt;&lt;font color=&quot;#777777&quot;&gt;No search results available&lt;/font&gt;&lt;/i&gt;
</del><ins>+  &lt;i&gt;&lt;font color=&quot;#777777&quot;&gt;This [% terms.bug %] is not in your last
+    search results.&lt;/font&gt;&lt;/i&gt;
</ins><span class="cx"> [% END %]
</span><span class="cx"> &lt;/div&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateencustomflaglisthtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/custom/flag/list.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/custom/flag/list.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/custom/flag/list.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -18,59 +18,7 @@
</span><span class="cx">   # Contributor(s): Myk Melez &lt;myk@mozilla.org&gt;
</span><span class="cx">   #%]
</span><span class="cx"> 
</span><del>-&lt;script type=&quot;text/javascript&quot;&gt;
-&lt;!-- 
-  // Enables or disables a requestee field depending on whether or not
-  // the user is requesting the corresponding flag.
-  function toggleRequesteeField(flagField, no_focus)
-  {
-    // Convert the ID of the flag field into the ID of its corresponding
-    // requestee field and then use the ID to get the field.
-    var id = flagField.name.replace(/flag(_type)?-(\d+)/, &quot;requestee$1-$2&quot;);
-    var requesteeField = document.getElementById(id);
-    if (!requesteeField) return;
-    
-    // Enable or disable the requestee field based on the value
-    // of the flag field.
-    if (flagField.value == &quot;?&quot;) {
-        requesteeField.disabled = false;
-        if (!no_focus) requesteeField.focus();
-    } else                         
-        requesteeField.disabled = true;
-  }
-  
-  // Disables requestee fields when the window is loaded since they shouldn't
-  // be enabled until the user requests that flag type.
-  function disableRequesteeFields()
-  {
-    var inputElements = document.getElementsByTagName(&quot;input&quot;);
-    var selectElements = document.getElementsByTagName(&quot;select&quot;);
-    //You cannot update Node lists, so you must create an array to combine the NodeLists
-    var allElements = [];
-    for( var i=0; i &lt; inputElements.length; i++ ) {
-        allElements[allElements.length] = inputElements.item(i);
-    }
-    for( var i=0; i &lt; selectElements.length; i++ ) { //Combine inputs with selects
-        allElements[allElements.length] = selectElements.item(i);
-    }
-    var inputElement, id, flagField;
-    for ( var i=0 ; i&lt;allElements.length ; i++ )
-    {
-      inputElement = allElements[i];
-      if (inputElement.name.search(/^requestee(_type)?-(\d+)$/) != -1)
-      {
-        // Convert the ID of the requestee field into the ID of its corresponding
-        // flag field and then use the ID to get the field.
-        id = inputElement.name.replace(/requestee(_type)?-(\d+)/, &quot;flag$1-$2&quot;);
-        flagField = document.getElementById(id);
-        if (flagField &amp;&amp; flagField.value != &quot;?&quot;)
-            inputElement.disabled = true;
-      }
-    }
-  }
-  window.onload = disableRequesteeFields;
-// --&gt;
-&lt;/script&gt;
</del><ins>+[% IF user.id AND !read_only_flags %]
</ins><span class="cx"> 
</span><span class="cx"> [%# We list flags by looping twice over the flag types relevant for the bug.
</span><span class="cx">   # In the first loop, we display existing flags and then, for active types,
</span><span class="lines">@@ -82,6 +30,8 @@
</span><span class="cx"> 
</span><span class="cx"> [% DEFAULT flag_table_id = &quot;flags&quot; %]
</span><span class="cx"> 
</span><ins>+&lt;script src=&quot;[% 'js/flag.js' FILTER mtime %]&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
+
</ins><span class="cx"> &lt;table id=&quot;[% flag_table_id FILTER html %]&quot;&gt;
</span><span class="cx">   [% UNLESS flag_no_header %]
</span><span class="cx">     &lt;tr&gt;
</span><span class="lines">@@ -97,9 +47,9 @@
</span><span class="cx">   [% END %]
</span><span class="cx"> 
</span><span class="cx">   [%# Step 1: Display every flag type (except inactive types with no flags). %]
</span><del>-  [% FOREACH type = flag_types %]
-    
-    [%# Step 1a: Display existing flag(s). %]
</del><ins>+  [% FOREACH type = flag_types -%]
+
+    [%-# Step 1a: Display existing flag(s). %]
</ins><span class="cx">     [% FOREACH flag = type.flags %]
</span><span class="cx"> [%# if WEBKIT_CHANGES %]
</span><span class="cx">       [% IF type.name == 'in-rietveld' %]
</span><span class="lines">@@ -109,7 +59,7 @@
</span><span class="cx">       [% END %]
</span><span class="cx"> [%# endif // WEBKIT_CHANGES %]
</span><span class="cx">         &lt;td&gt;
</span><del>-          [% flag.setter.nick FILTER html %]:
</del><ins>+          &lt;span title=&quot;[% flag.setter.identity FILTER html %]&quot;&gt;[% flag.setter.nick FILTER html %]&lt;/span&gt;:
</ins><span class="cx">         &lt;/td&gt;
</span><span class="cx">         &lt;td&gt;
</span><span class="cx">           &lt;label title=&quot;[% type.description FILTER html %]&quot;
</span><span class="lines">@@ -120,9 +70,9 @@
</span><span class="cx">           &lt;select id=&quot;flag-[% flag.id %]&quot; name=&quot;flag-[% flag.id %]&quot; 
</span><span class="cx">                   title=&quot;[% type.description FILTER html %]&quot;
</span><span class="cx">                   onchange=&quot;toggleRequesteeField(this);&quot;
</span><del>-                  class=&quot;flag_select&quot;&gt;
</del><ins>+                  class=&quot;flag_select flag_type-[% type.id %]&quot;&gt;
</ins><span class="cx">             [%# Only display statuses the user is allowed to set. %]
</span><del>-            [% IF user.can_request_flag(type) %]
</del><ins>+            [% IF user.can_request_flag(type) || flag.setter_id == user.id %]
</ins><span class="cx">               &lt;option value=&quot;X&quot;&gt;&lt;/option&gt;
</span><span class="cx">             [% END %]
</span><span class="cx">             [% IF type.is_active %]
</span><span class="lines">@@ -144,6 +94,7 @@
</span><span class="cx">           &lt;td&gt;
</span><span class="cx">             [% IF (type.is_active &amp;&amp; type.is_requestable &amp;&amp; type.is_requesteeble) || flag.requestee %]
</span><span class="cx">               &lt;span style=&quot;white-space: nowrap;&quot;&gt;
</span><ins>+                [% SET flag_custom_list = [] %]
</ins><span class="cx">                 [% IF Param('usemenuforusers') %]
</span><span class="cx">                   [% flag_custom_list = flag.type.grant_list %]
</span><span class="cx">                   [% IF !(type.is_active &amp;&amp; type.is_requestable &amp;&amp; type.is_requesteeble) %]
</span><span class="lines">@@ -152,83 +103,27 @@
</span><span class="cx">                         nothing else. %]
</span><span class="cx">                     [% flag_custom_list = [flag.requestee] %]
</span><span class="cx">                   [% END %]
</span><del>-                  [% INCLUDE global/userselect.html.tmpl
-                             name     =&gt; &quot;requestee-$flag.id&quot;
-                             id       =&gt; &quot;requestee-$flag.id&quot;
-                             value    =&gt; flag.requestee.login
-                             multiple =&gt; 0
-                             emptyok  =&gt; 1
-                             custom_userlist =&gt; flag_custom_list
-                  %]
-                [% ELSE %]
-                  (&lt;input type=&quot;text&quot; size=&quot;30&quot; maxlength=&quot;255&quot;
-                          id=&quot;requestee-[% flag.id %]&quot; 
-                          name=&quot;requestee-[% flag.id %]&quot;
-                          [% IF flag.status == &quot;?&quot; &amp;&amp; flag.requestee %]
-                            value=&quot;[% flag.requestee.login FILTER html %]&quot;
-                          [% END %]&gt;)
</del><span class="cx">                 [% END %]
</span><ins>+                [% INCLUDE global/userselect.html.tmpl
+                           name     =&gt; &quot;requestee-$flag.id&quot;
+                           id       =&gt; &quot;requestee-$flag.id&quot;
+                           value    =&gt; flag.requestee.login
+                           multiple =&gt; 0
+                           emptyok  =&gt; 1
+                           classes =&gt; [&quot;requestee&quot;]
+                           custom_userlist =&gt; flag_custom_list
+                %]
</ins><span class="cx">               &lt;/span&gt;
</span><span class="cx">             [% END %]
</span><span class="cx">           &lt;/td&gt;
</span><span class="cx">         [% END %]
</span><span class="cx">       &lt;/tr&gt;
</span><del>-    [% END %]
-    
-    [%# Step 1b: Display UI for setting flag. %]
</del><ins>+    [% END -%]
+
+    [%-# Step 1b: Display UI for setting flag. %]
</ins><span class="cx">     [% IF (!type.flags || type.flags.size == 0) &amp;&amp; type.is_active %]
</span><del>-[%# if WEBKIT_CHANGES %]
-      [% IF type.name == 'in-rietveld' %]
-        &lt;tr style='display:none'&gt;
-      [% ELSE %]
-        &lt;tr&gt;
-      [% END %]
-[%# endif // WEBKIT_CHANGES %]
-        &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-        &lt;td&gt;
-          &lt;label title=&quot;[% type.description FILTER html %]&quot;
-                 for=&quot;flag_type-[% type.id %]&quot;&gt;
-            [%- type.name FILTER html FILTER no_break %]&lt;/label&gt;
-        &lt;/td&gt;
-        &lt;td&gt;
-          &lt;select id=&quot;flag_type-[% type.id %]&quot; name=&quot;flag_type-[% type.id %]&quot; 
-                  title=&quot;[% type.description FILTER html %]&quot;
-                  [% &quot; disabled=\&quot;disabled\&quot;&quot; UNLESS (type.is_requestable &amp;&amp; user.can_request_flag(type)) || user.can_set_flag(type) %]
-                  onchange=&quot;toggleRequesteeField(this);&quot;
-                  class=&quot;flag_select&quot;&gt;
-            &lt;option value=&quot;X&quot;&gt;&lt;/option&gt;
-            [% IF type.is_requestable &amp;&amp; user.can_request_flag(type) %]
-              &lt;option value=&quot;?&quot;&gt;?&lt;/option&gt;
-            [% END %]
-            [% IF user.can_set_flag(type) %]
-              &lt;option value=&quot;+&quot;&gt;+&lt;/option&gt;
-              &lt;option value=&quot;-&quot;&gt;-&lt;/option&gt;
-            [% END %]
-          &lt;/select&gt;
-        &lt;/td&gt;
-        [% IF any_flags_requesteeble %]
-          &lt;td&gt;
-            [% IF type.is_requestable &amp;&amp; type.is_requesteeble %]
-              &lt;span style=&quot;white-space: nowrap;&quot;&gt;
-                [% IF Param('usemenuforusers') %]
-                  [% INCLUDE global/userselect.html.tmpl
-                             name     =&gt; &quot;requestee_type-$type.id&quot;
-                             id       =&gt; &quot;requestee_type-$type.id&quot;
-                             multiple =&gt; type.is_multiplicable * 3
-                             emptyok  =&gt; !type.is_multiplicable
-                             value    =&gt; &quot;&quot;
-                             custom_userlist =&gt; type.grant_list
-                  %]
-                [% ELSE %]
-                  (&lt;input type=&quot;text&quot; size=&quot;30&quot; maxlength=&quot;255&quot;
-                          id=&quot;requestee_type-[% type.id %]&quot;
-                          name=&quot;requestee_type-[% type.id %]&quot;&gt;)
-                [% END %]
-              &lt;/span&gt;
-            [% END %]
-          &lt;/td&gt;
-        [% END %]
-      &lt;/tr&gt;
</del><ins>+
+      [% PROCESS flag_row first_cell_empty = 1 addl_text = &quot;&quot; %]
</ins><span class="cx">     [% END %]
</span><span class="cx">   [% END %]
</span><span class="cx"> 
</span><span class="lines">@@ -239,51 +134,95 @@
</span><span class="cx">         &lt;tr&gt;&lt;td colspan=&quot;3&quot;&gt;&lt;hr&gt;&lt;/td&gt;&lt;/tr&gt;
</span><span class="cx">         [% separator_displayed = 1 %]
</span><span class="cx">     [% END %]
</span><del>-    &lt;tr&gt;
-      &lt;td colspan=&quot;2&quot;&gt;
-        addl. &lt;label title=&quot;[% type.description FILTER html %]&quot;
-                     for=&quot;flag_type-[% type.id %]&quot;&gt;
-          [%- type.name FILTER html FILTER no_break %]&lt;/label&gt;
-      &lt;/td&gt;
-      &lt;td&gt;
-        &lt;select id=&quot;flag_type-[% type.id %]&quot; name=&quot;flag_type-[% type.id %]&quot; 
-                title=&quot;[% type.description FILTER html %]&quot;
-                [% &quot; disabled=\&quot;disabled\&quot;&quot; UNLESS (type.is_requestable &amp;&amp; user.can_request_flag(type)) || user.can_set_flag(type) %]
-                onchange=&quot;toggleRequesteeField(this);&quot;
-                class=&quot;flag_select&quot;&gt;
-          &lt;option value=&quot;X&quot;&gt;&lt;/option&gt;
-          [% IF type.is_requestable &amp;&amp; user.can_request_flag(type) %]
-            &lt;option value=&quot;?&quot;&gt;?&lt;/option&gt;
-          [% END %]
-          [% IF user.can_set_flag(type) %]
-            &lt;option value=&quot;+&quot;&gt;+&lt;/option&gt;
-            &lt;option value=&quot;-&quot;&gt;-&lt;/option&gt;
-          [% END %]
-        &lt;/select&gt;
-      &lt;/td&gt;
-      [% IF any_flags_requesteeble %]
-        &lt;td&gt;
-          [% IF type.is_requestable &amp;&amp; type.is_requesteeble %]
-            &lt;span style=&quot;white-space: nowrap;&quot;&gt;
-              [% IF Param('usemenuforusers') %]
-                [% INCLUDE global/userselect.html.tmpl
-                           name     =&gt; &quot;requestee_type-$type.id&quot;
-                           id       =&gt; &quot;requestee_type-$type.id&quot;
-                           multiple =&gt; type.is_multiplicable * 3
-                           emptyok  =&gt; !type.is_multiplicable
-                           value    =&gt; &quot;&quot;
-                           custom_userlist =&gt; type.grant_list
-                %]
-              [% ELSE %]
-                (&lt;input type=&quot;text&quot; size=&quot;30&quot; maxlength=&quot;255&quot;
-                        id=&quot;requestee_type-[% type.id %]&quot; 
-                        name=&quot;requestee_type-[% type.id %]&quot;&gt;)
-              [% END %]
-            &lt;/span&gt;
-          [% END %]
-        &lt;/td&gt;
</del><ins>+
+    [% PROCESS flag_row first_cell_empty = 0 addl_text = &quot;addl.&quot; %]
+  [% END %]
+&lt;/table&gt;
+
+[% ELSE %]
+  [%# The user is logged out. Display flags as read-only. %]
+  [% header_displayed = 0 %]
+  [% FOREACH type = flag_types %]
+    [% FOREACH flag = type.flags %]
+      [% IF !flag_no_header AND !header_displayed %]
+        &lt;p&gt;&lt;b&gt;Flags:&lt;/b&gt;&lt;/p&gt;
+        [% header_displayed = 1 %]
</ins><span class="cx">       [% END %]
</span><del>-    &lt;/tr&gt;
</del><ins>+      [% IF flag.setter.name %]
+        &lt;span title=&quot;[% flag.setter.name FILTER html %]&quot;&gt;[% flag.setter.nick FILTER html %]&lt;/span&gt;:
+      [% ELSE %]
+        [% flag.setter.nick FILTER html %]:
+      [% END %]
+      [%+ type.name FILTER html FILTER no_break %][% flag.status %]
+      [% IF flag.requestee %]
+        [% IF flag.requestee.name %]
+          (&lt;span title=&quot;[% flag.requestee.name FILTER html %]&quot;&gt;[% flag.requestee.nick FILTER html %]&lt;/span&gt;)
+        [% ELSE %]
+          ([% flag.requestee.nick FILTER html %])
+        [% END %]
+      [% END %]&lt;br&gt;
+    [% END %]
</ins><span class="cx">   [% END %]
</span><ins>+[% END %]
</ins><span class="cx"> 
</span><del>-&lt;/table&gt;
</del><ins>+[%# Display a table row for unset flags %]
+
+[% BLOCK flag_row %]
+[%# if WEBKIT_CHANGES %]
+  [% IF type.name == 'in-rietveld' %]
+  &lt;tr style='display:none'&gt;
+  [% ELSE %]
+  &lt;tr&gt;
+  [% END %]
+[%# endif // WEBKIT_CHANGES %]
+  [% IF first_cell_empty %]
+    &lt;td&gt;&amp;nbsp;&lt;/td&gt;
+    &lt;td&gt;
+  [% ELSE %]
+    &lt;td colspan=&quot;2&quot;&gt;
+  [% END %]
+
+      [% addl_text FILTER html %]
+      &lt;label title=&quot;[% type.description FILTER html %]&quot; for=&quot;flag_type-[% type.id %]&quot;&gt;
+        [%- type.name FILTER html FILTER no_break %]&lt;/label&gt;
+    &lt;/td&gt;
+    &lt;td&gt;
+      &lt;select id=&quot;flag_type-[% type.id %]&quot; name=&quot;flag_type-[% type.id %]&quot;
+              title=&quot;[% type.description FILTER html %]&quot;
+              [% &quot; disabled=\&quot;disabled\&quot;&quot; UNLESS (type.is_requestable &amp;&amp; user.can_request_flag(type)) || user.can_set_flag(type) %]
+              onchange=&quot;toggleRequesteeField(this);&quot;
+              class=&quot;flag_select flag_type-[% type.id %]&quot;&gt;
+        &lt;option value=&quot;X&quot;&gt;&lt;/option&gt;
+        [% IF type.is_requestable &amp;&amp; user.can_request_flag(type) %]
+          &lt;option value=&quot;?&quot;&gt;?&lt;/option&gt;
+        [% END %]
+        [% IF user.can_set_flag(type) %]
+          &lt;option value=&quot;+&quot;&gt;+&lt;/option&gt;
+          &lt;option value=&quot;-&quot;&gt;-&lt;/option&gt;
+        [% END %]
+      &lt;/select&gt;
+    &lt;/td&gt;
+    [% IF any_flags_requesteeble %]
+      &lt;td&gt;
+        [% IF type.is_requestable &amp;&amp; type.is_requesteeble %]
+          &lt;span style=&quot;white-space: nowrap;&quot;&gt;
+            [% SET grant_list = [] %]
+            [% IF Param('usemenuforusers') %]
+              [% grant_list = type.grant_list %]
+            [% END %]
+            [% INCLUDE  global/userselect.html.tmpl
+                        name     =&gt; &quot;requestee_type-$type.id&quot;
+                        id       =&gt; &quot;requestee_type-$type.id&quot;
+                        multiple =&gt; type.is_multiplicable * 3
+                        emptyok  =&gt; !type.is_multiplicable
+                        value    =&gt; &quot;&quot;
+                        custom_userlist =&gt; grant_list
+                        classes =&gt; [&quot;requestee&quot;]
+            %]            
+            
+          &lt;/span&gt;
+        [% END %]
+      &lt;/td&gt;
+    [% END %]
+  &lt;/tr&gt;
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateencustomglobalchooseproducthtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/custom/global/choose-product.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/custom/global/choose-product.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/custom/global/choose-product.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -31,15 +31,17 @@
</span><span class="cx"> 
</span><span class="cx"> [% IF target == &quot;enter_bug.cgi&quot; %]
</span><span class="cx">   [% title = &quot;Enter $terms.Bug&quot; %]
</span><del>-  [% subheader = BLOCK %]First, you must pick a product on which to enter [% terms.abug %]. [% END %]
</del><ins>+  [% h2 = BLOCK %]First, you must pick a product on which to enter [% terms.abug %]: [% END %]
</ins><span class="cx"> [% ELSIF target == &quot;describecomponents.cgi&quot; %]
</span><del>-  [% title = &quot;$terms.Bugzilla Component Descriptions&quot; %]
-  [% subheader = &quot;Please specify the product whose components you want described.&quot; %]
</del><ins>+  [% title = &quot;Browse&quot; %]
+  [% h2 = &quot;Select a product category to browse:&quot; %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% DEFAULT title = &quot;Choose a Product&quot; %]
</span><span class="cx"> [% PROCESS global/header.html.tmpl %]
</span><span class="cx"> 
</span><ins>+&lt;h2&gt;[% h2 FILTER html %]&lt;/h2&gt;
+
</ins><span class="cx"> &lt;table&gt;
</span><span class="cx"> 
</span><span class="cx"> [% FOREACH c = classifications %]
</span><span class="lines">@@ -53,9 +55,9 @@
</span><span class="cx">   [% FOREACH p = c.products %]
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th align=&quot;right&quot; valign=&quot;top&quot;&gt;
</span><del>-        &lt;a href=&quot;[% target %]?product=[% p.name FILTER url_quote -%]
-              [%- IF cloned_bug_id %]&amp;amp;cloned_bug_id=[% cloned_bug_id FILTER url_quote %][% END -%] 
-              [%- IF format %]&amp;amp;format=[% format FILTER url_quote %][% END %]&quot;&gt;
</del><ins>+        &lt;a href=&quot;[% target %]?product=[% p.name FILTER uri -%]
+              [%- IF cloned_bug_id %]&amp;amp;cloned_bug_id=[% cloned_bug_id FILTER uri %][% END -%] 
+              [%- IF format %]&amp;amp;format=[% format FILTER uri %][% END %]&quot;&gt;
</ins><span class="cx">         [% p.name FILTER html FILTER no_break %]&lt;/a&gt;:&amp;nbsp;
</span><span class="cx">       &lt;/th&gt;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateencustomglobalheaderhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/custom/global/header.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/custom/global/header.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/custom/global/header.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -46,8 +46,41 @@
</span><span class="cx">   header_addl_info = &quot;&quot;
</span><span class="cx">   onload = &quot;&quot;
</span><span class="cx">   style_urls = []
</span><ins>+  yui = []
</ins><span class="cx"> %]
</span><span class="cx"> 
</span><ins>+[% SET yui_css = {
+  autocomplete =&gt; 1,
+  calendar     =&gt; 1,
+  datatable    =&gt; 1,
+  button       =&gt; 1,
+} %]
+
+[%# Note: This is simple dependency resolution--you can't have dependencies
+  # that depend on each other. You have to specify all of a module's deps,
+  # if that module is going to be specified in &quot;yui&quot;.
+  #%]
+[% SET yui_deps = {
+  autocomplete =&gt; ['json', 'connection', 'datasource'],
+  datatable    =&gt; ['json', 'connection', 'datasource', 'element'],
+} %]
+
+[%# When using certain YUI modules, we need to process certain
+  # extra JS templates.
+  #%]
+[% SET yui_templates = {
+  datatable =&gt; ['global/value-descs.js.tmpl'],
+} %]
+
+[%# These are JS URLs that are *always* on the page and come before
+  # every other JS URL.
+  #%]
+[% SET starting_js_urls = [
+    &quot;js/yui/yahoo-dom-event/yahoo-dom-event.js&quot;,
+    &quot;js/yui/cookie/cookie-min.js&quot;,
+] %]
+
+
</ins><span class="cx"> [%# We should be able to set the default value of the header variable
</span><span class="cx">   # to the value of the title variable using the DEFAULT directive,
</span><span class="cx">   # but that doesn't work if a caller sets header to the empty string
</span><span class="lines">@@ -59,105 +92,48 @@
</span><span class="cx"> 
</span><span class="cx"> &lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;
</span><span class="cx">                       &quot;http://www.w3.org/TR/html4/loose.dtd&quot;&gt;
</span><del>-&lt;html&gt;
</del><ins>+&lt;html lang=&quot;en&quot;&gt;
</ins><span class="cx">   &lt;head&gt;
</span><ins>+    [% Hook.process(&quot;start&quot;) %]
</ins><span class="cx">     &lt;title&gt;[% title %]&lt;/title&gt;
</span><span class="cx"> 
</span><ins>+    [% IF Param('utf8') %]
+      &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;&gt;
+    [% END %]
+
</ins><span class="cx"> [%# Migration note: contents of the old Param 'headerhtml' would go here %]
</span><span class="cx"> 
</span><span class="cx">     [% PROCESS &quot;global/site-navigation.html.tmpl&quot; %]
</span><span class="cx"> 
</span><span class="cx">     [% PROCESS 'global/setting-descs.none.tmpl' %]
</span><span class="cx"> 
</span><del>-    [%# Set up the skin CSS cascade:
-      #  1. Standard Bugzilla stylesheet set (persistent)
-      #  2. Standard Bugzilla stylesheet set (selectable)
-      #  3. All third-party &quot;skin&quot; stylesheet sets (selectable)
-      #  4. Page-specific styles
-      #  5. Custom Bugzilla stylesheet set (persistent)
-      # &quot;Selectable&quot; skin file sets may be either preferred or alternate.
-      # Exactly one is preferred, determined by the &quot;skin&quot; user preference.
-      #%]
-    [% IF user.settings.skin.value != 'standard' %]
-      [% user_skin = user.settings.skin.value %]
-    [% END %]
-    [% style_urls.unshift('skins/standard/global.css') %]
</del><ins>+    [% SET yui = yui_resolve_deps(yui, yui_deps) %]
+    [% SET css_sets = css_files(style_urls, yui, yui_css) %]
</ins><span class="cx"> 
</span><span class="cx">     [%# CSS cascade, part 1: Standard Bugzilla stylesheet set (persistent).
</span><span class="cx">       # Always present.
</span><span class="cx">       #%]
</span><del>-    [% FOREACH style_url = style_urls %]
-      &lt;link href=&quot;[% style_url FILTER html %]&quot;
-            rel=&quot;stylesheet&quot;
-            type=&quot;text/css&quot;&gt;
</del><ins>+    [%# This allows people to switch back to the &quot;Classic&quot; skin if they
+      # are in another skin. 
+      #%]
+    &lt;link href=&quot;[% 'skins/standard/global.css' FILTER mtime FILTER html %]&quot;
+          rel=&quot;alternate stylesheet&quot; 
+          title=&quot;[% setting_descs.standard FILTER html %]&quot;&gt;
+    [% FOREACH style_url = css_sets.standard %]
+      [% PROCESS format_css_link css_set_name = 'standard' %]
</ins><span class="cx">     [% END %]
</span><del>-    &lt;!--[if IE]&gt;
-      [%# Internet Explorer treats [if IE] HTML comments as uncommented.
-        # Use it to import CSS fixes so that Bugzilla looks decent on IE, too.
-        #%]
-      &lt;link href=&quot;skins/standard/IE-fixes.css&quot;
-            rel=&quot;stylesheet&quot;
-            type=&quot;text/css&quot;&gt;
-    &lt;![endif]--&gt;
</del><span class="cx"> 
</span><del>-    [%# CSS cascade, part 2: Standard Bugzilla stylesheet set (selectable)
-      # Present if skin selection is enabled.
</del><ins>+    [%# CSS cascade, part 2 &amp; 3: Third-party stylesheet set (selected and
+      # selectable). All third-party skins are present as alternate
+      # stylesheets, even if they are not currently in use.
</ins><span class="cx">       #%]
</span><del>-    [% IF user.settings.skin.is_enabled %]
-      [% FOREACH style_url = style_urls %]
-        &lt;link href=&quot;[% style_url FILTER html %]&quot;
-              rel=&quot;[% 'alternate ' IF user_skin %]stylesheet&quot;
-              title=&quot;[% setting_descs.standard FILTER html %]&quot;
-              type=&quot;text/css&quot;&gt;
-      [% END %]
-      &lt;!--[if IE]&gt;
-        [%# Internet Explorer treats [if IE] HTML comments as uncommented.
-          # Use it to import CSS fixes so that Bugzilla looks decent on IE,
-          # too.
-          #%]
-        &lt;link href=&quot;skins/standard/IE-fixes.css&quot;
-              rel=&quot;[% 'alternate ' IF user_skin %]stylesheet&quot;
-              title=&quot;[% setting_descs.standard FILTER html %]&quot;
-              type=&quot;text/css&quot;&gt;
-      &lt;![endif]--&gt;
</del><ins>+    [% FOREACH style_url = css_sets.skin %]
+      [% PROCESS format_css_link css_set_name = user.settings.skin.value %]
</ins><span class="cx">     [% END %]
</span><span class="cx"> 
</span><del>-    [%# CSS cascade, part 3: Third-party stylesheet set (selectable).
-      # All third-party skins are present if skin selection is enabled.
-      # The admin-selected skin is always present.
-      #%]
-    [% FOREACH contrib_skin = user.settings.skin.legal_values %]
-      [% NEXT IF contrib_skin == 'standard' %]
-      [% NEXT UNLESS contrib_skin == user_skin
-                  OR user.settings.skin.is_enabled %]
-      [% contrib_skin = contrib_skin FILTER url_quote %]
-      [% IF contrib_skin.match('\.css$') %]
-        [%# 1st skin variant: single-file stylesheet %]
-        &lt;link href=&quot;[% &quot;skins/contrib/$contrib_skin&quot; %]&quot;
-              rel=&quot;[% 'alternate ' UNLESS contrib_skin == user_skin %]stylesheet&quot;
-              title=&quot;[% contrib_skin FILTER html %]&quot;
-              type=&quot;text/css&quot;&gt;
-      [% ELSE %]
-        [%# 2nd skin variant: stylesheet set %]
-        [% FOREACH style_url = style_urls %]
-          [% IF style_url.match('^skins/standard/') %]
-            &lt;link href=&quot;[% style_url.replace('^skins/standard/',
-                                             &quot;skins/contrib/$contrib_skin/&quot;) %]&quot;
-                  rel=&quot;[% 'alternate ' UNLESS contrib_skin == user_skin %]stylesheet&quot;
-                  title=&quot;[% contrib_skin FILTER html %]&quot;
-                  type=&quot;text/css&quot;&gt;
-          [% END %]
-        [% END %]
-        &lt;!--[if IE]&gt;
-          [%# Internet Explorer treats [if IE] HTML comments as uncommented.
-            # Use it to import CSS fixes so that Bugzilla looks decent on IE,
-            # too.
-            #%]
-          &lt;link href=&quot;skins/contrib/[% contrib_skin FILTER html %]/IE-fixes.css&quot;
-                rel=&quot;[% 'alternate ' UNLESS contrib_skin == user_skin %]stylesheet&quot;
-                title=&quot;[% contrib_skin FILTER html %]&quot;
-                type=&quot;text/css&quot;&gt;
-        &lt;![endif]--&gt;
</del><ins>+    [% FOREACH alternate_skin = css_sets.alternate.keys %]
+      [% FOREACH style_url = css_sets.alternate.$alternate_skin %]
+        [% PROCESS format_css_link css_set_name = alternate_skin %]
</ins><span class="cx">       [% END %]
</span><span class="cx">     [% END %]
</span><span class="cx"> 
</span><span class="lines">@@ -173,49 +149,95 @@
</span><span class="cx">       # Always present. Site administrators may override all other style
</span><span class="cx">       # definitions, including skins, using custom stylesheets.
</span><span class="cx">       #%]
</span><del>-    [% FOREACH style_url = style_urls %]
-      [% IF style_url.match('^skins/standard/') %]
-        &lt;link href=&quot;[% style_url.replace('^skins/standard/', &quot;skins/custom/&quot;)
-                       FILTER html %]&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot;&gt;
-      [% END %]
</del><ins>+    [% FOREACH style_url = css_sets.custom %]
+      [% PROCESS format_css_link css_set_name = 'standard' %]
</ins><span class="cx">     [% END %]
</span><del>-    &lt;!--[if IE]&gt;
-      [%# Internet Explorer treats [if IE] HTML comments as uncommented.
-        # Use it to import CSS fixes so that Bugzilla looks decent on IE, too.
-        #%]
-      &lt;link href=&quot;skins/custom/IE-fixes.css&quot;
-            rel=&quot;stylesheet&quot;
-            type=&quot;text/css&quot;&gt;
-    &lt;![endif]--&gt;
</del><span class="cx"> 
</span><ins>+    [%# YUI Scripts %]
+    [% FOREACH yui_name = yui %]
+      [% starting_js_urls.push(&quot;js/yui/$yui_name/${yui_name}-min.js&quot;) %]
+    [% END %]
+    [% starting_js_urls.push('js/global.js') %]
</ins><span class="cx"> 
</span><del>-    [% IF javascript %]
-      &lt;script type=&quot;text/javascript&quot;&gt;
-        [% javascript %]
-      &lt;/script&gt;
</del><ins>+    [% FOREACH javascript_url = starting_js_urls %]
+      [% PROCESS format_js_link %]
</ins><span class="cx">     [% END %]
</span><span class="cx"> 
</span><del>-    [% IF javascript_urls %]
-      [% FOREACH javascript_url = javascript_urls %]
-        &lt;script src=&quot;[% javascript_url FILTER html %]&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
-      [% END %]
-      [% IF javascript_urls.grep('yui/').size %]
-        &lt;script type=&quot;text/javascript&quot;&gt;
-          YAHOO.namespace('bugzilla');
-          if( YAHOO.env.ua.gecko )
-            YAHOO.util.Event._simpleRemove(window, &quot;unload&quot;, YAHOO.util.Event._unload);
-        &lt;/script&gt;
-      [% END %]
</del><ins>+    &lt;script type=&quot;text/javascript&quot;&gt;
+    &lt;!--
+        YAHOO.namespace('bugzilla');
+        YAHOO.util.Event.addListener = function (el, sType, fn, obj, overrideContext) {
+               if ( (&quot;onpagehide&quot; in window || YAHOO.env.ua.gecko) &amp;&amp; sType === &quot;unload&quot;) { sType = &quot;pagehide&quot;; };
+               var capture = ((sType == &quot;focusin&quot; || sType == &quot;focusout&quot;) &amp;&amp; !YAHOO.env.ua.ie) ? true : false;
+               return this._addListener(el, this._getType(sType), fn, obj, overrideContext, capture);
+         };
+        if ( &quot;onpagehide&quot; in window || YAHOO.env.ua.gecko) {
+            YAHOO.util.Event._simpleRemove(window, &quot;unload&quot;, 
+                                           YAHOO.util.Event._unload);
+        }
+        [%# The language selector needs javascript to set its cookie,
+          # so it is hidden in HTML/CSS by the &quot;bz_default_hidden&quot; class.
+          # If the browser can run javascript, it will then &quot;unhide&quot;
+          # the language selector using the following code.
+          #%]
+        function unhide_language_selector() { 
+            YAHOO.util.Dom.removeClass(
+                'lang_links_container', 'bz_default_hidden'
+            ); 
+        } 
+        YAHOO.util.Event.onDOMReady(unhide_language_selector);
+
+        [%# Make some Bugzilla information available to all scripts. 
+          # We don't import every parameter and constant because we
+          # don't want to add a lot of uncached JS to every page. 
+          #%]
+        var BUGZILLA = {
+            param: {
+                cookiepath: '[% Param('cookiepath') FILTER js %]',
+                maxusermatches: [% Param('maxusermatches') FILTER js %]
+            },
+            constant: {
+                COMMENT_COLS: [% constants.COMMENT_COLS FILTER js %]
+            },
+            string: {
+                [%# Please keep these in alphabetical order. %]
+
+                attach_desc_required:
+                    'You must enter a Description for this attachment.',
+                component_required:
+                    'You must select a Component for this [% terms.bug %].',
+                description_required:
+                    'You must enter a Description for this [% terms.bug %].',
+                short_desc_required:
+                    'You must enter a Summary for this [% terms.bug %].',
+                version_required:
+                    'You must select a Version for this [% terms.bug %].'
+            }
+        };
+
+        [% FOREACH yui_name = yui %]
+          [% FOREACH yui_template = yui_templates.$yui_name %]
+            [% INCLUDE $yui_template %]
+          [% END %]
+        [% END %]
+        [% IF javascript %]
+          [% javascript %]
+        [% END %]
+    // --&gt;
+    &lt;/script&gt;
+
+    [% FOREACH javascript_url = javascript_urls %]
+      [% PROCESS format_js_link %]
</ins><span class="cx">     [% END %]
</span><span class="cx"> 
</span><del>-[%# if WEBKIT_CHANGES %]
</del><ins>+[%# if WEBKIT_CHANGES #%]
</ins><span class="cx">     [%# this puts the live bookmark up on firefox for the RSS feed %]
</span><span class="cx">     [% IF rsslink %]
</span><span class="cx">        &lt;link rel=&quot;alternate&quot; 
</span><span class="cx">              type=&quot;application/rss+xml&quot; title=&quot;RSS 1.0&quot; 
</span><span class="cx">              href=&quot;[% rsslink FILTER html %]&quot;&gt;
</span><span class="cx">     [% END %]
</span><del>-[%# endif // WEBKIT_CHANGES %]
</del><ins>+[%# endif // WEBKIT_CHANGES #%]
</ins><span class="cx"> 
</span><span class="cx">     [%# Required for the 'Autodiscovery' feature in Firefox 2 and IE 7. %]
</span><span class="cx">     &lt;link rel=&quot;search&quot; type=&quot;application/opensearchdescription+xml&quot;
</span><span class="lines">@@ -232,40 +254,57 @@
</span><span class="cx">         class=&quot;[% urlbase.replace('^https?://','').replace('/$','').replace('[-~@:/.]+','-') %]
</span><span class="cx">                [% FOREACH class = bodyclasses %]
</span><span class="cx">                  [% ' ' %][% class FILTER css_class_quote %]
</span><del>-               [% END %]&quot;&gt;
</del><ins>+               [% END %] yui-skin-sam&quot;&gt;
</ins><span class="cx"> 
</span><span class="cx"> [%# Migration note: the following file corresponds to the old Param
</span><span class="cx">   # 'bannerhtml'
</span><span class="cx">   #%]
</span><span class="cx"> 
</span><del>-
</del><span class="cx"> &lt;div id=&quot;header&quot;&gt;
</span><span class="cx"> 
</span><ins>+[%# if WEBKIT_CHANGES #%]
</ins><span class="cx"> [%# INCLUDE global/banner.html.tmpl #%]
</span><ins>+[%# endif // WEBKIT_CHANGES #%]
</ins><span class="cx"> 
</span><span class="cx"> &lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot; id=&quot;titles&quot;&gt;
</span><span class="cx"> &lt;tr&gt;
</span><span class="cx">     &lt;td id=&quot;title&quot;&gt;
</span><del>-      &lt;p&gt;WebKit [% terms.Bugzilla %]
-[%# if WEBKIT_CHANGES %]
-      [%# &quot; &amp;ndash; $header&quot; IF header %]&lt;/p&gt;
-[%# endif // WEBKIT_CHANGES %]
</del><ins>+[%# if WEBKIT_CHANGES #%]
+      [%# &quot; &amp;ndash; $header&quot; IF header #%]&lt;/p&gt;
+[%# endif // WEBKIT_CHANGES #%]
</ins><span class="cx">     &lt;/td&gt;
</span><span class="cx"> 
</span><del>-[%# WEBKIT_CHANGES: Removed subheader and header_addl_info output %]
</del><ins>+[%# WEBKIT_CHANGES: Removed subheader and header_addl_info output #%]
</ins><span class="cx"> &lt;/tr&gt;
</span><span class="cx"> &lt;/table&gt;
</span><span class="cx"> 
</span><del>-[%# if WEBKIT_CHANGES %]
</del><ins>+&lt;table id=&quot;lang_links_container&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot;
+       class=&quot;bz_default_hidden&quot;&gt;&lt;tr&gt;&lt;td&gt;
+[% IF Bugzilla.languages.size &gt; 1 %]
+  &lt;ul class=&quot;links&quot;&gt;
+  [% FOREACH lang = Bugzilla.languages.sort %]
+    &lt;li&gt;[% IF NOT loop.first %]&lt;span class=&quot;separator&quot;&gt; | &lt;/span&gt;[% END %]
+    [% IF lang == current_language %]
+      &lt;span class=&quot;lang_current&quot;&gt;[% lang FILTER html FILTER upper %]&lt;/span&gt;
+    [% ELSE %]
+      &lt;a href=&quot;#&quot; onclick=&quot;set_language('[% lang FILTER none %]');&quot;&gt;
+       [%- lang FILTER html FILTER upper %]&lt;/a&gt;
+    [% END %]
+    &lt;/li&gt;
+  [% END %]
+  &lt;/ul&gt;
+[% END %]
+&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
+
+[%# if WEBKIT_CHANGES #%]
</ins><span class="cx">   [% IF header || subheader %]
</span><span class="cx">     &lt;div id=&quot;bug_title&quot;&gt;[% header %][% &quot;: $subheader&quot; IF subheader %]&lt;/div&gt;
</span><span class="cx">   [% END %]
</span><del>-[%# endif // WEBKIT_CHANGES %]
</del><ins>+[%# endif // WEBKIT_CHANGES #%]
</ins><span class="cx"> 
</span><span class="cx"> [% PROCESS &quot;global/common-links.html.tmpl&quot; qs_suffix = &quot;_top&quot; %]
</span><ins>+&lt;/div&gt; [%# header %]
</ins><span class="cx"> 
</span><del>-&lt;/div&gt;
-
</del><span class="cx"> &lt;div id=&quot;bugzilla-body&quot;&gt;
</span><span class="cx"> 
</span><span class="cx"> [% IF Param('announcehtml') %]
</span><span class="lines">@@ -275,3 +314,41 @@
</span><span class="cx"> [% IF message %]
</span><span class="cx"> &lt;div id=&quot;message&quot;&gt;[% message %]&lt;/div&gt;
</span><span class="cx"> [% END %]
</span><ins>+
+[% BLOCK format_css_link %]
+  [% IF style_url.match('/IE-fixes\.css') %]
+    &lt;!--[if lte IE 7]&gt;
+      [%# Internet Explorer treats [if IE] HTML comments as uncommented.
+        # We use it to import CSS fixes so that Bugzilla looks decent on IE 7
+        # and below.
+        #%]
+  [% END %]
+
+  [% IF css_set_name == 'standard'
+       OR css_set_name == user.settings.skin.value
+  %]
+    [% SET css_rel = 'stylesheet' %]
+    [% SET css_set_display_name = setting_descs.${user.settings.skin.value}
+                                  || user.settings.skin.value %]
+  [% ELSE %]
+    [% SET css_rel = 'alternate stylesheet' %]
+    [% SET css_set_display_name = setting_descs.$css_set_name || css_set_name %]
+  [% END %]
+
+  [% IF css_set_name == 'standard' %]
+    [% SET css_title_link = '' %]
+  [% ELSE %]
+    [% css_title_link = BLOCK ~%]
+      title=&quot;[% css_set_display_name FILTER html %]&quot;
+    [% END %]
+  [% END %]
+
+  &lt;link href=&quot;[% style_url FILTER html %]&quot; rel=&quot;[% css_rel FILTER none %]&quot;
+        type=&quot;text/css&quot; [% css_title_link FILTER none %]&gt;
+
+  [% '&lt;![endif]--&gt;' IF style_url.match('/IE-fixes\.css') %]
+[% END %]
+
+[% BLOCK format_js_link %]
+  &lt;script type=&quot;text/javascript&quot; src=&quot;[% javascript_url FILTER mtime FILTER html %]&quot;&gt;&lt;/script&gt;
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateencustomlistlisthtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/custom/list/list.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/custom/list/list.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/custom/list/list.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -28,54 +28,48 @@
</span><span class="cx"> [%# Template Initialization                                                  #%]
</span><span class="cx"> [%############################################################################%]
</span><span class="cx"> 
</span><del>-[% PROCESS global/variables.none.tmpl %]
</del><ins>+[% PROCESS &quot;global/field-descs.none.tmpl&quot; %]
</ins><span class="cx"> 
</span><span class="cx"> [% title = &quot;$terms.Bug List&quot; %]
</span><span class="cx"> [% IF searchname || defaultsavename %]
</span><span class="cx">   [% title = title _ &quot;: &quot; _ (searchname OR defaultsavename) FILTER html %]
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><del>-[% qorder = order FILTER url_quote IF order %]
</del><ins>+[% qorder = order FILTER uri IF order %]
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> [%############################################################################%]
</span><span class="cx"> [%# Page Header                                                              #%]
</span><span class="cx"> [%############################################################################%]
</span><span class="cx"> 
</span><del>-[%# if WEBKIT_CHANGES %]
</del><ins>+[%# if WEBKIT_CHANGES #%]
</ins><span class="cx"> [% PROCESS global/header.html.tmpl
</span><span class="cx">   title = title
</span><span class="cx">   style = style
</span><span class="cx">   rsslink = &quot;buglist.cgi?$urlquerypart&amp;title=$title&amp;ctype=rss&quot; 
</span><del>-  javascript_urls = [ &quot;js/util.js&quot;, &quot;js/field.js&quot;,
-                      &quot;js/yui/yahoo-dom-event.js&quot;, &quot;js/yui/calendar.js&quot; ]
-  style_urls = [ &quot;skins/standard/buglist.css&quot;, &quot;skins/standard/yui/calendar.css&quot; ]
</del><ins>+  yui = [ 'autocomplete', 'calendar' ]
+  javascript_urls = [ &quot;js/util.js&quot;, &quot;js/field.js&quot; ]
+  style_urls = [ &quot;skins/standard/buglist.css&quot; ]
</ins><span class="cx">   doc_section = &quot;query.html#list&quot;
</span><span class="cx"> %]
</span><del>-[%# endif // WEBKIT_CHANGES %]
</del><ins>+[%# endif // WEBKIT_CHANGES #%]
</ins><span class="cx"> 
</span><del>-&lt;div class=&quot;bz_query_head&quot; align=&quot;center&quot;&gt;
</del><ins>+&lt;div class=&quot;bz_query_head&quot;&gt;
</ins><span class="cx">   &lt;span class=&quot;bz_query_timestamp&quot;&gt;
</span><del>-    [% IF Param('timezone') %]
-      &lt;b&gt;[% time2str(&quot;%a %b %e %Y %T %Z&quot;, currenttime, Param('timezone')) %]&lt;/b&gt;&lt;br&gt;
-    [% ELSE %]
-      &lt;b&gt;[% time2str(&quot;%a %b %e %Y %T&quot;, currenttime) %]&lt;/b&gt;&lt;br&gt;
-    [% END %]
</del><ins>+    [% currenttime FILTER time('%a %b %e %Y %T %Z') FILTER html %]&lt;br&gt;
</ins><span class="cx">   &lt;/span&gt;
</span><span class="cx"> 
</span><span class="cx">   [% IF debug %]
</span><del>-    &lt;p class=&quot;bz_query_debug&quot;&gt;
-      [% FOREACH debugline = debugdata %]
-        [% debugline FILTER html %]&lt;br&gt;
-      [% END %]
-    &lt;/p&gt;
</del><span class="cx">     &lt;p class=&quot;bz_query&quot;&gt;[% query FILTER html %]&lt;/p&gt;
</span><ins>+    [% IF query_explain.defined %]
+      &lt;pre class=&quot;bz_query_explain&quot;&gt;[% query_explain FILTER html %]&lt;/pre&gt;
+    [% END %]
</ins><span class="cx">   [% END %]
</span><span class="cx"> 
</span><span class="cx">   [% IF user.settings.display_quips.value == 'on' %]
</span><span class="cx">     [% DEFAULT quip = &quot;$terms.Bugzilla would like to put a random quip here, but no one has entered any.&quot; %]
</span><span class="cx">     &lt;span class=&quot;bz_quip&quot;&gt;
</span><del>-      &lt;a href=&quot;quips.cgi&quot;&gt;&lt;i&gt;[% quip FILTER html %]&lt;/i&gt;&lt;/a&gt;
</del><ins>+      &lt;a href=&quot;quips.cgi&quot;&gt;&lt;em&gt;[% quip FILTER html %]&lt;/em&gt;&lt;/a&gt;
</ins><span class="cx">     &lt;/span&gt;
</span><span class="cx">   [% END %]
</span><span class="cx"> 
</span><span class="lines">@@ -88,6 +82,29 @@
</span><span class="cx">   &lt;/h2&gt;
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><ins>+[% SET shown_types = [
+  'notequals', 'regexp', 'notregexp', 'lessthan', 'lessthaneq', 
+  'greaterthan', 'greaterthaneq', 'changedbefore', 'changedafter', 
+  'changedfrom', 'changedto', 'changedby', 'notsubstring', 'nowords',
+  'nowordssubstr', 'notmatches',
+] %]
+&lt;ul class=&quot;search_description&quot;&gt;
+[% FOREACH desc_item = search_description %]
+  &lt;li&gt;
+    &lt;strong&gt;[% field_descs.${desc_item.field} FILTER html %]:&lt;/strong&gt;
+    [% IF shown_types.contains(desc_item.type) || debug %]
+      ([% search_descs.${desc_item.type} FILTER html %])
+    [% END %]
+    [% FOREACH val IN desc_item.value.split(',') %]
+      [%+ display_value(desc_item.field, val) FILTER html %][% ',' UNLESS loop.last %]
+    [% END %]
+    [% IF debug %]
+      (&lt;code&gt;[% desc_item.term FILTER html %]&lt;/code&gt;)
+   [% END %]
+  &lt;/li&gt;
+[% END %]
+&lt;/ul&gt;
+
</ins><span class="cx"> &lt;hr&gt;
</span><span class="cx"> 
</span><span class="cx"> [%############################################################################%]
</span><span class="lines">@@ -95,9 +112,7 @@
</span><span class="cx"> [%############################################################################%]
</span><span class="cx"> 
</span><span class="cx"> [% IF bugs.size &gt; 9 %]
</span><del>-  &lt;span class=&quot;bz_result_count&quot;&gt;
-    [% bugs.size %] [%+ terms.bugs %] found.
-  &lt;/span&gt;
</del><ins>+  [% PROCESS num_results %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [%############################################################################%]
</span><span class="lines">@@ -119,16 +134,20 @@
</span><span class="cx"> [%# Succeeding Status Line                                                   #%]
</span><span class="cx"> [%############################################################################%]
</span><span class="cx"> 
</span><del>-&lt;span class=&quot;bz_result_count&quot;&gt;
-  [% IF bugs.size == 0 %]
-    [% terms.zeroSearchResults %].
-  [% ELSIF bugs.size == 1 %]
-    One [% terms.bug %] found.
-  [% ELSE %]
-    [% bugs.size %] [%+ terms.bugs %] found.
-  [% END %]
-&lt;/span&gt;
</del><ins>+[% PROCESS num_results %]
</ins><span class="cx"> 
</span><ins>+[% IF bugs.size == 0 %]
+  &lt;ul class=&quot;zero_result_links&quot;&gt;
+    &lt;li&gt;[% PROCESS enter_bug_link %]&lt;/li&gt;
+    [% IF one_product.defined %]
+      &lt;li&gt;&lt;a href=&quot;enter_bug.cgi&quot;&gt;File a new [% terms.bug %] in a
+        different product&lt;/a&gt;&lt;/li&gt;
+    [% END %]
+    &lt;li&gt;&lt;a href=&quot;[% PROCESS edit_search_url %]&quot;&gt;Edit this search&lt;/a&gt;&lt;/li&gt;
+    &lt;li&gt;&lt;a href=&quot;query.cgi&quot;&gt;Start a new search&lt;/a&gt;&lt;/li&gt;
+  &lt;/ul&gt;
+[% END %]
+
</ins><span class="cx"> &lt;br&gt;
</span><span class="cx"> 
</span><span class="cx"> [%############################################################################%]
</span><span class="lines">@@ -165,11 +184,19 @@
</span><span class="cx">             &lt;input type=&quot;submit&quot; value=&quot;XML&quot; id=&quot;xml&quot;&gt;
</span><span class="cx">         &lt;/form&gt;
</span><span class="cx"> 
</span><del>-        [% IF user.in_group(Param('timetrackinggroup')) %]
</del><ins>+        [% IF user.is_timetracker %]
</ins><span class="cx">           &lt;form method=&quot;post&quot; action=&quot;summarize_time.cgi&quot;&gt;
</span><span class="cx">             &lt;input type=&quot;hidden&quot; name=&quot;id&quot; value=&quot;[% buglist_joined FILTER html %]&quot;&gt;
</span><span class="cx">             &lt;input type=&quot;submit&quot; id=&quot;timesummary&quot; value=&quot;Time Summary&quot;&gt;
</span><span class="cx">           &lt;/form&gt;
</span><ins>+          [% IF time_summary_limited %]
+            &lt;small&gt;
+              Time Summary will only include the [% terms.bugs %] shown above. In order to
+              to see a time summary for all [% terms.bugs %] found by the search, you can
+              &lt;a href=&quot;buglist.cgi?[% urlquerypart FILTER html %]
+                       [%- &quot;&amp;order=$qorder&quot; FILTER html IF order %]&amp;limit=0&quot;&gt;
+                Show all search results&lt;/a&gt;.&lt;/small&gt;
+          [% END %]
</ins><span class="cx">         [% END %]
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">       
</span><span class="lines">@@ -177,7 +204,7 @@
</span><span class="cx">       
</span><span class="cx">       &lt;td valign=&quot;middle&quot; class=&quot;bz_query_links&quot;&gt;
</span><span class="cx">         &lt;a href=&quot;buglist.cgi?
</span><del>-        [% urlquerypart FILTER html %]&amp;amp;ctype=csv&quot;&gt;CSV&lt;/a&gt; |
</del><ins>+        [% urlquerypart FILTER html %]&amp;amp;ctype=csv&amp;amp;human=1&quot;&gt;CSV&lt;/a&gt; |
</ins><span class="cx">         &lt;a href=&quot;buglist.cgi?
</span><span class="cx">         [% urlquerypart FILTER html %]&amp;amp;title=
</span><span class="cx"> [%# if WEBKIT_CHANGES %]
</span><span class="lines">@@ -187,7 +214,7 @@
</span><span class="cx">         [% urlquerypart FILTER html %]&amp;amp;ctype=ics&quot;&gt;iCalendar&lt;/a&gt; |
</span><span class="cx">         &lt;a href=&quot;colchange.cgi?
</span><span class="cx">         [% urlquerypart FILTER html %]&amp;amp;query_based_on=
</span><del>-          [% defaultsavename OR searchname FILTER url_quote %]&quot;&gt;Change&amp;nbsp;Columns&lt;/a&gt; |
</del><ins>+          [% defaultsavename OR searchname FILTER uri %]&quot;&gt;Change&amp;nbsp;Columns&lt;/a&gt; |
</ins><span class="cx"> 
</span><span class="cx">         [% IF bugs.size &gt; 1 &amp;&amp; caneditbugs &amp;&amp; !dotweak %]
</span><span class="cx">           &lt;a href=&quot;buglist.cgi?[% urlquerypart FILTER html %]
</span><span class="lines">@@ -196,7 +223,7 @@
</span><span class="cx">           |
</span><span class="cx">         [% END %]
</span><span class="cx"> 
</span><del>-        [% IF bugowners %]
</del><ins>+        [% IF bugowners &amp;&amp; user.id %]
</ins><span class="cx">           &lt;a href=&quot;mailto:
</span><span class="cx">             [% bugowners FILTER html %]&quot;&gt;Send&amp;nbsp;Mail&amp;nbsp;to&amp;nbsp;[% terms.Bug %]&amp;nbsp;Assignees&lt;/a&gt; |
</span><span class="cx">         [% END %]
</span><span class="lines">@@ -207,19 +234,15 @@
</span><span class="cx">     [% END %]
</span><span class="cx">     
</span><span class="cx">     &lt;td valign=&quot;middle&quot; class=&quot;bz_query_edit&quot;&gt;
</span><del>-      [% editqueryname = searchname OR defaultsavename OR '' %]
-      &lt;a href=&quot;query.cgi?[% urlquerypart FILTER html %]
-      [% IF editqueryname != '' %]&amp;amp;known_name=
-        [% editqueryname FILTER url_quote %]
-      [% END %]&quot;&gt;Edit&amp;nbsp;Search&lt;/a&gt;
</del><ins>+      &lt;a href=&quot;[% PROCESS edit_search_url %]&quot;&gt;Edit&amp;nbsp;Search&lt;/a&gt;
</ins><span class="cx">     &lt;/td&gt;
</span><span class="cx">       
</span><span class="cx">     [% IF searchtype == &quot;saved&quot; %]
</span><span class="cx">       &lt;td valign=&quot;middle&quot; nowrap=&quot;nowrap&quot; class=&quot;bz_query_forget&quot;&gt;
</span><span class="cx">         |
</span><span class="cx">         &lt;a href=&quot;buglist.cgi?cmdtype=dorem&amp;amp;remaction=forget&amp;amp;namedcmd=
</span><del>-                [% searchname FILTER url_quote %]&amp;amp;token=
-                [% issue_hash_token([search_id, searchname]) FILTER url_quote %]&quot;&gt;
</del><ins>+                [% searchname FILTER uri %]&amp;amp;token=
+                [% issue_hash_token([search_id, searchname]) FILTER uri %]&quot;&gt;
</ins><span class="cx">           Forget&amp;nbsp;Search&amp;nbsp;'[% searchname FILTER html %]'&lt;/a&gt;
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">     [% ELSE %]
</span><span class="lines">@@ -232,18 +255,18 @@
</span><span class="cx">                  value=&quot;[% urlquerypart FILTER html %][% &quot;&amp;order=$qorder&quot; FILTER html IF order %]&quot;&gt;
</span><span class="cx">           &lt;input type=&quot;hidden&quot; name=&quot;cmdtype&quot; value=&quot;doit&quot;&gt;
</span><span class="cx">           &lt;input type=&quot;hidden&quot; name=&quot;remtype&quot; value=&quot;asnamed&quot;&gt;
</span><ins>+          &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% issue_hash_token(['savedsearch']) FILTER html %]&quot;&gt;
</ins><span class="cx">           &lt;input type=&quot;text&quot; id=&quot;save_newqueryname&quot; name=&quot;newqueryname&quot; size=&quot;20&quot;
</span><del>-                 value=&quot;[% defaultsavename FILTER html %]&quot;&gt; 
</del><ins>+                 title=&quot;New query name&quot; value=&quot;[% defaultsavename FILTER html %]&quot;&gt; 
</ins><span class="cx">         &lt;/form&gt; 
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">     [% END %]  
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> &lt;/table&gt;
</span><span class="cx"> 
</span><del>-[% IF cgi.param('product').size == 1 &amp;&amp; cgi.param('product') != &quot;&quot; %]
</del><ins>+[% IF one_product.defined &amp;&amp; bugs.size %]
</ins><span class="cx">   &lt;p class=&quot;bz_query_single_product&quot;&gt;
</span><del>-    &lt;a href=&quot;enter_bug.cgi?product=[% cgi.param('product') FILTER url_quote %]&quot;&gt;File
-      a new [% terms.bug %] in the &quot;[% cgi.param('product') FILTER html %]&quot; product&lt;/a&gt;
</del><ins>+    [% PROCESS enter_bug_link %]
</ins><span class="cx">   &lt;/p&gt;
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="lines">@@ -252,3 +275,44 @@
</span><span class="cx"> [%############################################################################%]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/footer.html.tmpl %]
</span><ins>+
+[%##########%]
+[%# Blocks #%]
+[%##########%]
+
+[% BLOCK edit_search_url %]
+  [% editqueryname = searchname OR defaultsavename OR '' %]
+  query.cgi?[% urlquerypart FILTER html %]
+    [%- IF editqueryname != '' %]&amp;amp;known_name=
+      [%- editqueryname FILTER uri %]
+    [% END %]
+[% END %]
+
+[% BLOCK enter_bug_link %]
+  &lt;a href=&quot;enter_bug.cgi
+           [%- IF one_product.defined %]?product=
+             [%- one_product.name FILTER uri %][% END %]&quot;&gt;File
+    a new [% terms.bug %]
+   [% IF one_product.defined %]
+     in the &quot;[% one_product.name FILTER html %]&quot; product
+   [% END %]&lt;/a&gt;
+[% END %]
+
+[% BLOCK num_results %]
+  &lt;span class=&quot;bz_result_count&quot;&gt;
+    [% IF bugs.size == 0 %]
+      &lt;span class=&quot;zero_results&quot;&gt;[% terms.zeroSearchResults %].&lt;/span&gt;
+    [% ELSIF default_limited AND bugs.size &gt;= Param('default_search_limit') %]
+      This result was limited to [% Param('default_search_limit') FILTER html %]
+      [%+ terms.bugs %].
+      &lt;a href=&quot;buglist.cgi?[% urlquerypart FILTER html %]
+              [%- &quot;&amp;order=$qorder&quot; FILTER html IF order %]&amp;limit=0&quot;&gt;See
+        all search results for this query&lt;/a&gt;.
+      [% time_summary_limited = 1 %]
+    [% ELSIF bugs.size == 1 %]
+      One [% terms.bug %] found.
+    [% ELSE %]
+      [% bugs.size %] [%+ terms.bugs %] found.
+    [% END %]
+  &lt;/span&gt;
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateencustomrequestemailtxttmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/custom/request/email.txt.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/custom/request/email.txt.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/custom/request/email.txt.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -24,30 +24,34 @@
</span><span class="cx"> 
</span><span class="cx"> [% bugidsummary = bug.bug_id _ ': ' _ bug.short_desc %]
</span><span class="cx"> [% attidsummary = attachment.id _ ': ' _ attachment.description %]
</span><ins>+[% flagtype_name = flag ? flag.type.name : old_flag.type.name %]
</ins><span class="cx"> [% statuses = { '+' =&gt; &quot;granted&quot; , '-' =&gt; 'denied' , 'X' =&gt; &quot;canceled&quot; ,
</span><span class="cx">                 '?' =&gt; &quot;asked&quot; } %]
</span><span class="cx"> 
</span><span class="cx"> [% to_identity = &quot;&quot; %]
</span><span class="cx"> [% on_behalf_of = 0 %]
</span><del>-[% IF flag.status == '?' %]
</del><ins>+[% action = flag.status || 'X' %]
+
+[% IF flag &amp;&amp; flag.status == '?' %]
</ins><span class="cx">   [% subject_status = &quot;requested&quot; %]
</span><del>-  [% IF flag.setter.id == user.id %]
</del><ins>+  [% IF flag.setter_id == user.id %]
</ins><span class="cx">     [% to_identity = flag.requestee.identity _ &quot; for&quot; %]
</span><span class="cx">   [% ELSE %]
</span><span class="cx">     [% on_behalf_of = 1 %]
</span><span class="cx">     [% IF flag.requestee %][% to_identity = &quot; to &quot; _ flag.requestee.identity %][% END %]
</span><span class="cx">   [% END %]
</span><span class="cx"> [% ELSE %]
</span><del>-  [% IF flag.requester %]
-    [% to_identity = flag.requester.identity _ &quot;'s request for&quot; %]
</del><ins>+  [% IF old_flag &amp;&amp; old_flag.status == '?' %]
+    [% to_identity = old_flag.setter.identity _ &quot;'s request for&quot; %]
</ins><span class="cx">   [% END %]
</span><del>-  [% subject_status = statuses.${flag.status} %]
</del><ins>+  [% subject_status = statuses.$action %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> From: [% Param('mailfrom') %]
</span><span class="cx"> To: [% to %]
</span><del>-Subject: [% flag.type.name %] [%+ subject_status %]: [[% terms.Bug %] [%+ bug.bug_id %]] [% bug.short_desc %]
</del><ins>+Subject: [% flagtype_name %] [%+ subject_status %]: [[% terms.Bug %] [%+ bug.bug_id %]] [% bug.short_desc %]
</ins><span class="cx"> [%- IF attachment %] :
</span><del>-  [Attachment [% attachment.id %]] [% attachment.description %][% END %]
</del><ins>+  [Attachment [% attachment.id %]] [% attachment.description FILTER clean_text %][% END %]
+Date: [% date %]
</ins><span class="cx"> X-Bugzilla-Type: request
</span><span class="cx"> [%+ threadingmarker %]
</span><span class="cx"> 
</span><span class="lines">@@ -55,10 +59,10 @@
</span><span class="cx"> [%- FILTER bullet = wrap(80) -%]
</span><span class="cx"> 
</span><span class="cx"> [% IF on_behalf_of %]
</span><del>-[% user.identity %] has reassigned [% flag.setter.identity %]'s request for [% flag.type.name %]
</del><ins>+[% user.identity %] has reassigned [% flag.setter.identity %]'s request for [% flagtype_name %]
</ins><span class="cx"> [% to_identity %]:
</span><span class="cx"> [% ELSE %]
</span><del>-[% user.identity %] has [% statuses.${flag.status} %] [%+ to_identity %] [%+ flag.type.name %]:
</del><ins>+[% user.identity %] has [% statuses.$action %] [%+ to_identity %] [%+ flagtype_name %]:
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% terms.Bug %] [%+ bugidsummary %]
</span><span class="lines">@@ -69,12 +73,18 @@
</span><span class="cx"> [% FILTER bullet = wrap(80) %]
</span><span class="cx"> Attachment [% attidsummary %]
</span><span class="cx"> [%- END %]
</span><ins>+[%# if WEBKIT_CHANGES #%]
</ins><span class="cx"> [%+ urlbase %]attachment.cgi?id=[% attachment.id %]&amp;action=review
</span><ins>+[%# endif // WEBKIT_CHANGES #%]
</ins><span class="cx"> [%- END %]
</span><ins>+
+[%- Hook.process('after_summary') -%]
+
</ins><span class="cx"> [%- FILTER bullet = wrap(80) %]
</span><span class="cx"> 
</span><span class="cx"> [% USE Bugzilla %]
</span><del>-[% IF Bugzilla.cgi.param(&quot;comment&quot;) &amp;&amp; Bugzilla.cgi.param(&quot;comment&quot;).length &gt; 0 %]
</del><ins>+[%-# .defined is necessary to avoid a taint issue in Perl &lt; 5.10.1, see bug 509794. %]
+[% IF Bugzilla.cgi.param(&quot;comment&quot;).defined &amp;&amp; Bugzilla.cgi.param(&quot;comment&quot;).length &gt; 0 %]
</ins><span class="cx"> ------- Additional Comments from [% user.identity %]
</span><span class="cx"> [%+ Bugzilla.cgi.param(&quot;comment&quot;) %]
</span><span class="cx"> [% END %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateencustomrequestqueuehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/custom/request/queue.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/custom/request/queue.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/custom/request/queue.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -23,18 +23,43 @@
</span><span class="cx"> [% USE Bugzilla %]
</span><span class="cx"> [% cgi = Bugzilla.cgi %]
</span><span class="cx"> 
</span><del>-[% PROCESS &quot;global/js-products.html.tmpl&quot; %]
-
</del><span class="cx"> [% PROCESS global/header.html.tmpl
</span><span class="cx">   title=&quot;Request Queue&quot;
</span><span class="cx">   style = &quot;
</span><span class="cx">     table.requests th { text-align: left; }
</span><span class="cx">     table#filtering th { text-align: right; }
</span><span class="cx">   &quot;
</span><del>-  onload=&quot;var f = document.forms[0]; selectProduct(f.product, f.component, null, null, 'Any');&quot;
-  javascript_urls=[&quot;js/productform.js&quot;]
</del><ins>+  onload=&quot;var f = document.request_form; selectProduct(f.product, f.component, null, null, 'Any');&quot;
+  javascript_urls=[&quot;js/productform.js&quot;, &quot;js/field.js&quot;]
+  style_urls = ['skins/standard/buglist.css']
+  yui = ['autocomplete']
</ins><span class="cx"> %]
</span><span class="cx"> 
</span><ins>+&lt;script type=&quot;text/javascript&quot;&gt;
+  var useclassification = false; // No classification level in use
+  var first_load = true; // Is this the first time we load the page?
+  var last_sel = []; // Caches last selection
+  var cpts = new Array();
+  [% n = 1 %]
+  [% IF Param('useclassification') %]
+    [% FOREACH clas = user.get_selectable_classifications %]
+      [% FOREACH prod = user.get_selectable_products(clas.id) %]
+        [%+ PROCESS js_comp %]
+      [% END %]
+    [% END %]
+  [% ELSE %]
+    [% FOREACH prod = user.get_selectable_products %]
+      [%+ PROCESS js_comp %]
+    [% END %]
+  [% END %]
+&lt;/script&gt;
+
+[% BLOCK js_comp %]
+  cpts['[% n %]'] = [
+    [%- FOREACH comp = prod.components %]'[% comp.name FILTER js %]'[% &quot;, &quot; UNLESS loop.last %] [%- END -%]];
+  [% n = n+1 %]
+[% END %]
+
</ins><span class="cx"> &lt;p&gt;
</span><span class="cx"> When you are logged in, only requests made by you or addressed to you
</span><span class="cx"> are shown by default.  You can change the criteria using the form below.
</span><span class="lines">@@ -42,22 +67,44 @@
</span><span class="cx"> to some group are shown by default.
</span><span class="cx"> &lt;/p&gt;
</span><span class="cx"> 
</span><del>-&lt;form action=&quot;request.cgi&quot; method=&quot;get&quot;&gt;
</del><ins>+&lt;form id=&quot;request_form&quot; name=&quot;request_form&quot; action=&quot;request.cgi&quot; method=&quot;get&quot;&gt;
</ins><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;queue&quot;&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;table id=&quot;filtering&quot;&gt;
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th&gt;Requester:&lt;/th&gt;
</span><del>-      &lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;requester&quot; value=&quot;[% cgi.param('requester') FILTER html %]&quot; size=&quot;20&quot; 
-           title=&quot;Requester's email address&quot;&gt;&lt;/td&gt;
</del><ins>+      &lt;td&gt;
+        [% INCLUDE global/userselect.html.tmpl
+           id =&gt; &quot;requester&quot;
+           name =&gt; &quot;requester&quot;
+           value =&gt; cgi.param('requester')
+           size =&gt; 20
+           emptyok =&gt; 1
+           field_title =&gt; &quot;Requester's email address&quot;
+        %]
+      &lt;/td&gt;
</ins><span class="cx">       &lt;th&gt;Product:&lt;/th&gt;
</span><span class="cx">       &lt;td&gt;
</span><span class="cx">         &lt;select name=&quot;product&quot; onchange=&quot;selectProduct(this, this.form.component, null, null, 'Any');&quot;&gt;
</span><span class="cx">           &lt;option value=&quot;&quot;&gt;Any&lt;/option&gt;
</span><del>-          [% FOREACH prod = products %]
-            &lt;option value=&quot;[% prod.name FILTER html %]&quot;
-                    [% &quot;selected&quot; IF cgi.param('product') == prod.name %]&gt;
-              [% prod.name FILTER html %]&lt;/option&gt;
</del><ins>+          [% IF Param('useclassification') %]
+            [% FOREACH c = user.get_selectable_classifications %]
+              &lt;optgroup label=&quot;[% c.name FILTER html %]&quot;&gt;
+                [% FOREACH p = user.get_selectable_products(c.id) %]
+                  &lt;option value=&quot;[% p.name FILTER html %]&quot;
+                    [% &quot; selected&quot; IF cgi.param('product') == p.name %]&gt;
+                    [% p.name FILTER html %]
+                  &lt;/option&gt;
+                [% END %]
+              &lt;/optgroup&gt;
+            [% END %]
+          [% ELSE %]
+            [% FOREACH p = user.get_selectable_products %]
+              &lt;option value=&quot;[% p.name FILTER html %]&quot;
+                [% &quot; selected&quot; IF cgi.param('product') == p.name %]&gt;
+                [% p.name FILTER html %]
+              &lt;/option&gt;
+            [% END %]
</ins><span class="cx">           [% END %]
</span><span class="cx">         &lt;/select&gt;
</span><span class="cx">       &lt;/td&gt;
</span><span class="lines">@@ -83,8 +130,17 @@
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th&gt;Requestee:&lt;/th&gt;
</span><del>-      &lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;requestee&quot; value=&quot;[% cgi.param('requestee') FILTER html %]&quot; size=&quot;20&quot; 
-           title=&quot;Requestee's email address or &amp;quot;-&amp;quot; (hyphen) for requests with no requestee&quot;&gt;&lt;/td&gt;
</del><ins>+      &lt;td&gt;
+        [% INCLUDE global/userselect.html.tmpl
+           id =&gt; &quot;requestee&quot;
+           name =&gt; &quot;requestee&quot;
+           value =&gt; cgi.param('requestee')
+           size =&gt; 20
+           emptyok =&gt; 1
+           hyphenok =&gt; 1
+           field_title =&gt; &quot;Requestee's email address or \&quot;-\&quot; (hyphen) for requests with no requestee&quot;
+        %]
+      &lt;/td&gt;
</ins><span class="cx">       &lt;th&gt;Component:&lt;/th&gt;
</span><span class="cx">       &lt;td&gt;
</span><span class="cx">         &lt;select name=&quot;component&quot;&gt;
</span><span class="lines">@@ -136,28 +192,32 @@
</span><span class="cx">   &lt;/p&gt;
</span><span class="cx"> [% ELSE %]
</span><span class="cx">   [% FOREACH request = requests %]
</span><del>-    [% IF loop.first %] [% PROCESS start_new_table %] [% END %]
-    [% IF request.$group_field != group_value %]
</del><ins>+    [% IF request.$group_field != group_value || loop.first %]
</ins><span class="cx">       [% group_value = request.$group_field %]
</span><del>-      [% UNLESS loop.first %]
-        &lt;/table&gt;
-        [% PROCESS start_new_table %]
-      [% END %]
</del><ins>+      [% PROCESS display_buglist UNLESS loop.first %]
+      [% PROCESS start_new_table %]
</ins><span class="cx">     [% END %]
</span><ins>+    [% buglist.${request.bug_id} = 1 %]
</ins><span class="cx">     &lt;tr&gt;
</span><span class="cx">       [% FOREACH column = display_columns %]
</span><span class="cx">         [% NEXT IF column == group_field || excluded_columns.contains(column) %]
</span><del>-        &lt;td&gt;[% PROCESS &quot;display_$column&quot; %]&lt;/td&gt;
</del><ins>+        &lt;td&gt;
+          [% PROCESS &quot;display_$column&quot; %]
+          [% Hook.process('after_column') %]
+        &lt;/td&gt;
</ins><span class="cx">       [% END %]
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">   [% END %]
</span><del>-  &lt;/table&gt;
</del><ins>+  [% PROCESS display_buglist %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/footer.html.tmpl %]
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK start_new_table %]
</span><del>-  &lt;h3&gt;[% column_headers.$group_field %]: [% (request.$group_field || &quot;None&quot;) FILTER html %]&lt;/h3&gt;
</del><ins>+  [% buglist = {} %]
+
+  &lt;h3&gt;[% column_headers.$group_field %]: 
+    [%+ (request.$group_field || &quot;None&quot;) FILTER email FILTER html %]&lt;/h3&gt;
</ins><span class="cx">   &lt;table class=&quot;requests&quot; cellspacing=&quot;0&quot; cellpadding=&quot;4&quot; border=&quot;1&quot;&gt;
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       [% FOREACH column = display_columns %]
</span><span class="lines">@@ -176,15 +236,16 @@
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK display_bug %]
</span><del>-  &lt;a href=&quot;show_bug.cgi?id=[% request.bug_id %]&quot;&gt;
</del><ins>+  &lt;a href=&quot;show_bug.cgi?id=[% request.bug_id %]&quot;
+     [%- ' class=&quot;bz_secure&quot;' IF request.restricted %]&gt;
</ins><span class="cx">     [% request.bug_id %]: [%+ request.bug_summary FILTER html %]&lt;/a&gt;
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK display_attachment %]
</span><span class="cx">   [% IF request.attach_id %]
</span><del>-[%# if WEBKIT_CHANGES %]
</del><ins>+[%# if WEBKIT_CHANGES #%]
</ins><span class="cx">     &lt;a href=&quot;attachment.cgi?id=[% request.attach_id %]&amp;amp;action=review&quot;&gt;
</span><del>-[%# endif // WEBKIT_CHANGES %]
</del><ins>+[%# endif // WEBKIT_CHANGES #%]
</ins><span class="cx">       [% request.attach_id %]: [%+ request.attach_summary FILTER html %]&lt;/a&gt;
</span><span class="cx">   [% ELSE %]
</span><span class="cx">     N/A
</span><span class="lines">@@ -192,14 +253,21 @@
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK display_requestee %]
</span><del>-  [% request.requestee FILTER html %]
</del><ins>+  [% request.requestee FILTER email FILTER html %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK display_requester %]
</span><del>-  [% request.requester FILTER html %]
</del><ins>+  [% request.requester FILTER email FILTER html %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK display_created %]
</span><span class="cx">   [% request.created FILTER time %]
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><ins>+[% BLOCK display_buglist %]
+  &lt;/table&gt;
+  [% NEXT UNLESS buglist.keys.size %]
+  &lt;a href=&quot;buglist.cgi?bug_id=
+           [%- buglist.keys.nsort.join(&quot;,&quot;) FILTER html %]&quot;&gt;(view as
+  [%+ terms.bug %] list)&lt;/a&gt;
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultaccountauthloginsmallhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/account/auth/login-small.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/account/auth/login-small.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/account/auth/login-small.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -23,68 +23,106 @@
</span><span class="cx"> [%# Use the current script name. If an empty name is returned,
</span><span class="cx">   # then we are accessing the home page. %]
</span><span class="cx"> 
</span><del>-[% script_name = cgi.url(Relative =&gt; 1) %]
-[% IF !script_name %]
- [% script_name = &quot;index.cgi&quot; %]
</del><ins>+[% login_target = cgi.url(&quot;-relative&quot; =&gt; 1, &quot;-query&quot; =&gt; 1) %]
+[% IF !login_target OR login_target.match(&quot;^token.cgi&quot;) %]
+ [% login_target = &quot;index.cgi&quot; %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><del>-[%# If SSL is in use, use 'sslbase', else use 'urlbase'. %]
-[% IF Param(&quot;sslbase&quot;) != &quot;&quot; &amp;&amp; Param(&quot;ssl&quot;) != &quot;never&quot; %]
-  [% script_name = Param(&quot;sslbase&quot;) _ script_name %]
-[% ELSE %]
-  [% script_name = Param(&quot;urlbase&quot;) _ script_name %]
-[% END %]
</del><ins>+[% login_target = urlbase _ login_target %]
</ins><span class="cx"> 
</span><del>-&lt;form name=&quot;login&quot; action=&quot;[% script_name FILTER html %]&quot; method=&quot;POST&quot;&gt;
-  &lt;table id=&quot;login-small&quot;&gt;
-    &lt;tr&gt;
-      &lt;th align=&quot;right&quot;&gt;&lt;label for=&quot;Bugzilla_login&quot;&gt;Login:&lt;/label&gt;&lt;/th&gt;
-      &lt;td&gt;&lt;input size=&quot;20&quot; id=&quot;Bugzilla_login&quot; name=&quot;Bugzilla_login&quot;&gt;
-          [% Param('emailsuffix') FILTER html %]&lt;/td&gt;
-    &lt;/tr&gt;
-    &lt;tr&gt;
-      &lt;th align=&quot;right&quot;&gt;&lt;label for=&quot;Bugzilla_password&quot;&gt;Password:&lt;/label&gt;&lt;/th&gt;
-      &lt;td&gt;
-        &lt;input type=&quot;password&quot; size=&quot;20&quot; id=&quot;Bugzilla_password&quot; name=&quot;Bugzilla_password&quot;&gt;
-      &lt;/td&gt;
-    &lt;/tr&gt;
</del><ins>+&lt;li id=&quot;mini_login_container[% qs_suffix %]&quot;&gt;
+  &lt;span class=&quot;separator&quot;&gt;| &lt;/span&gt;
+  [% connector = &quot;?&quot; %]
+  [% IF cgi.request_method == &quot;GET&quot; AND cgi.query_string %]
+    [% connector = &quot;&amp;&quot; %]
+  [% END %]
+  [% script_name = login_target _ connector _ &quot;GoAheadAndLogIn=1&quot; %]
+  &lt;a id=&quot;login_link[% qs_suffix %]&quot; href=&quot;[% script_name FILTER html %]&quot;
+     onclick=&quot;return show_mini_login_form('[% qs_suffix %]')&quot;&gt;Log In&lt;/a&gt;
</ins><span class="cx"> 
</span><del>-    [% IF Param('rememberlogin') == 'defaulton' || 
-          Param('rememberlogin') == 'defaultoff' %]
-      &lt;tr&gt;
-        &lt;th&gt;&amp;nbsp;&lt;/th&gt;
-        &lt;td&gt;
-          &lt;input type=&quot;checkbox&quot; id=&quot;Bugzilla_remember&quot; name=&quot;Bugzilla_remember&quot; value=&quot;on&quot;
</del><ins>+  [% Hook.process('additional_methods') %]
+  
+  &lt;form action=&quot;[% login_target FILTER html %]&quot; method=&quot;POST&quot; 
+        class=&quot;mini_login bz_default_hidden&quot;
+        id=&quot;mini_login[% qs_suffix FILTER html %]&quot;
+        onsubmit=&quot;return check_mini_login_fields( '[% qs_suffix FILTER html %]' );&quot;
+  &gt;
+    &lt;input id=&quot;Bugzilla_login[% qs_suffix FILTER html %]&quot; 
+           class=&quot;bz_login&quot;
+           name=&quot;Bugzilla_login&quot;
+           title=&quot;Login&quot;
+           onfocus=&quot;mini_login_on_focus('[% qs_suffix FILTER js %]')&quot;
+    &gt;
+    &lt;input class=&quot;bz_password&quot; 
+           id=&quot;Bugzilla_password[% qs_suffix FILTER html %]&quot; 
+           name=&quot;Bugzilla_password&quot;
+           type=&quot;password&quot;
+           title=&quot;Password&quot;
+    &gt;
+    &lt;input class=&quot;bz_password bz_default_hidden bz_mini_login_help&quot; type=&quot;text&quot; 
+           id=&quot;Bugzilla_password_dummy[% qs_suffix %]&quot; value=&quot;password&quot;
+           title=&quot;Password&quot;
+           onfocus=&quot;mini_login_on_focus('[% qs_suffix FILTER js %]')&quot;
+    &gt;
+    [% IF Param('rememberlogin') == 'defaulton' ||
+          Param('rememberlogin') == 'defaultoff' 
+    %]
+      &lt;input type=&quot;checkbox&quot; id=&quot;Bugzilla_remember[% qs_suffix %]&quot; 
+             name=&quot;Bugzilla_remember&quot; value=&quot;on&quot; class=&quot;bz_remember&quot;
</ins><span class="cx">                  [%+ &quot;checked&quot; IF Param('rememberlogin') == &quot;defaulton&quot; %]&gt;
</span><del>-          &lt;label for=&quot;Bugzilla_remember&quot;&gt;Remember my Login&lt;/label&gt;
-        &lt;/td&gt;
-      &lt;/tr&gt;
</del><ins>+      &lt;label for=&quot;Bugzilla_remember[% qs_suffix %]&quot;&gt;Remember&lt;/label&gt;
</ins><span class="cx">     [% END %]
</span><del>-
-    [% IF Param('loginnetmask') &lt; 32 %]
-      &lt;tr&gt;
-        &lt;th&gt;&amp;nbsp;&lt;/th&gt;
-        &lt;td&gt;
-          &lt;input type=&quot;checkbox&quot; id=&quot;Bugzilla_restrictlogin&quot; name=&quot;Bugzilla_restrictlogin&quot;
-                 checked=&quot;checked&quot;&gt;
-          &lt;label for=&quot;Bugzilla_restrictlogin&quot;&gt;Restrict this session to this IP address
-          (using this option improves security)&lt;/label&gt;
-        &lt;/td&gt;
-      &lt;/tr&gt;
-    [% END %]
-
-    &lt;tr&gt;
-      &lt;td&gt;&lt;input type=&quot;submit&quot; name=&quot;GoAheadAndLogIn&quot; value=&quot;Login&quot;
-                 id=&quot;log_in&quot;&gt;&lt;/td&gt;
-
-      [%# For now, password change requests only apply to the DB
-        # verification method #%]
-
-      [% IF user.authorizer.can_change_password %]
-        &lt;td&gt;[ &lt;a href=&quot;index.cgi?GoAheadAndLogIn=1#forgot&quot;&gt;Forgot my Password&lt;/a&gt; ]&lt;/td&gt;
-      [% END %]
-    &lt;/tr&gt;
-  &lt;/table&gt;
-
-&lt;/form&gt;
-
</del><ins>+    &lt;input type=&quot;submit&quot; name=&quot;GoAheadAndLogIn&quot; value=&quot;Log in&quot; 
+            id=&quot;log_in[% qs_suffix %]&quot;&gt;
+    &lt;script type=&quot;text/javascript&quot;&gt;
+      mini_login_constants = {
+          &quot;login&quot; : &quot;login&quot;,
+          &quot;warning&quot; : &quot;You must set the login and password before logging in.&quot;
+      };
+      [%# We need this event to fire after autocomplete, because it does
+        # something different depending on whether or not there's already
+        # data in the login and password box.
+        # However, autocomplete happens at all sorts of different times in
+        # different browsers (before or after onDOMReady, before or after
+        # window.onload, in almost all combinations you can imagine).
+        # The only good solution I found is to time the event 200 
+        # milliseconds after window.onload for WebKit (doing it immediately 
+        # at onload works in Chrome but not in Safari, but I can't detect 
+        # them separately using YUI), and right after onDOMReady in Gecko. 
+        # The WebKit solution is also fairly guaranteed to work on any 
+        # browser (it's just strange, since the fields only populate 200 ms
+        # after the page loads), so it's the default. IE doesn't even
+        # recognize our forms as login forms, so I made it use the Gecko
+        # method also (since it's nicer visually). Opera never autocompletes
+        # forms without user interaction, so it also uses the Gecko method.
+        #%]
+      if (YAHOO.env.ua.gecko || YAHOO.env.ua.ie || YAHOO.env.ua.opera) {
+          YAHOO.util.Event.onDOMReady(function() {
+              init_mini_login_form('[% qs_suffix FILTER html %]');
+          });
+      }
+      else {
+          YAHOO.util.Event.on(window, 'load', function () {
+              window.setTimeout(function() {
+                  init_mini_login_form('[% qs_suffix FILTER html %]');
+              }, 200);
+          });
+    }
+    &lt;/script&gt;
+    &lt;a href=&quot;#&quot; onclick=&quot;return hide_mini_login_form('[% qs_suffix %]')&quot;&gt;[x]&lt;/a&gt;
+  &lt;/form&gt;
+&lt;/li&gt;
+&lt;li id=&quot;forgot_container[% qs_suffix %]&quot;&gt;
+  &lt;span class=&quot;separator&quot;&gt;| &lt;/span&gt;
+  &lt;a id=&quot;forgot_link[% qs_suffix %]&quot; href=&quot;[% script_name FILTER html %]#forgot&quot;
+     onclick=&quot;return show_forgot_form('[% qs_suffix %]')&quot;&gt;Forgot Password&lt;/a&gt;
+  &lt;form action=&quot;token.cgi&quot; method=&quot;post&quot; id=&quot;forgot_form[% qs_suffix %]&quot;
+        class=&quot;mini_forgot bz_default_hidden&quot;&gt;
+    &lt;label for=&quot;login[% qs_suffix FILTER html %]&quot;&gt;Login:&lt;/label&gt;
+    &lt;input type=&quot;text&quot; name=&quot;loginname&quot; size=&quot;20&quot; id=&quot;login[% qs_suffix FILTER html %]&quot;&gt;
+    &lt;input id=&quot;forgot_button[% qs_suffix %]&quot; value=&quot;Reset Password&quot; 
+           type=&quot;submit&quot;&gt;
+    &lt;input type=&quot;hidden&quot; name=&quot;a&quot; value=&quot;reqpw&quot;&gt;
+    &lt;a href=&quot;#&quot; onclick=&quot;return hide_forgot_form('[% qs_suffix %]')&quot;&gt;[x]&lt;/a&gt;
+  &lt;/form&gt;
+&lt;/li&gt;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultaccountauthloginhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/account/auth/login.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/account/auth/login.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/account/auth/login.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -69,17 +69,15 @@
</span><span class="cx">       &lt;/tr&gt;
</span><span class="cx">     [% END %]
</span><span class="cx"> 
</span><del>-    [% IF Param('loginnetmask') &lt; 32 %]
-      &lt;tr&gt;
-        &lt;th&gt;&amp;nbsp;&lt;/th&gt;
-        &lt;td&gt;
-          &lt;input type=&quot;checkbox&quot; id=&quot;Bugzilla_restrictlogin&quot; name=&quot;Bugzilla_restrictlogin&quot;
-                 checked=&quot;checked&quot;&gt;
-          &lt;label for=&quot;Bugzilla_restrictlogin&quot;&gt;Restrict this session to this IP address
-          (using this option improves security)&lt;/label&gt;
-        &lt;/td&gt;
-      &lt;/tr&gt;
-    [% END %]
</del><ins>+    &lt;tr&gt;
+      &lt;th&gt;&amp;nbsp;&lt;/th&gt;
+      &lt;td&gt;
+        &lt;input type=&quot;checkbox&quot; id=&quot;Bugzilla_restrictlogin&quot; name=&quot;Bugzilla_restrictlogin&quot;
+               checked=&quot;checked&quot;&gt;
+        &lt;label for=&quot;Bugzilla_restrictlogin&quot;&gt;Restrict this session to this IP address
+        (using this option improves security)&lt;/label&gt;
+      &lt;/td&gt;
+    &lt;/tr&gt;
</ins><span class="cx">   &lt;/table&gt;
</span><span class="cx"> 
</span><span class="cx">   [% PROCESS &quot;global/hidden-fields.html.tmpl&quot;
</span><span class="lines">@@ -93,6 +91,8 @@
</span><span class="cx">   &lt;/p&gt;
</span><span class="cx"> &lt;/form&gt;
</span><span class="cx"> 
</span><ins>+[% Hook.process('additional_methods') %]
+
</ins><span class="cx"> [%# Allow the user to create a new account, or request a token to change
</span><span class="cx">   # their password, assuming that our auth method allows that.
</span><span class="cx">   #%]
</span><span class="lines">@@ -109,14 +109,13 @@
</span><span class="cx">   [% IF user.authorizer.can_change_password %]
</span><span class="cx">     &lt;hr&gt;
</span><span class="cx"> 
</span><del>-    &lt;a name=&quot;forgot&quot;&gt;&lt;/a&gt;
-    &lt;form method=&quot;get&quot; action=&quot;token.cgi&quot;&gt;
</del><ins>+    &lt;form id=&quot;forgot&quot; method=&quot;get&quot; action=&quot;token.cgi&quot;&gt;
</ins><span class="cx">       &lt;input type=&quot;hidden&quot; name=&quot;a&quot; value=&quot;reqpw&quot;&gt;
</span><span class="cx">       If you have an account, but have forgotten your password,
</span><span class="cx">       enter your login name below and submit a request
</span><span class="cx">       to change your password.&lt;br&gt;
</span><span class="cx">       &lt;input size=&quot;35&quot; name=&quot;loginname&quot;&gt;
</span><del>-      &lt;input type=&quot;submit&quot; id=&quot;request&quot; value=&quot;Submit Request&quot;&gt;
</del><ins>+      &lt;input type=&quot;submit&quot; id=&quot;request&quot; value=&quot;Reset Password&quot;&gt;
</ins><span class="cx">     &lt;/form&gt;
</span><span class="cx">   [% END %]
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultaccountcanceltokentxttmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/account/cancel-token.txt.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/account/cancel-token.txt.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/account/cancel-token.txt.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -37,7 +37,7 @@
</span><span class="cx">             Token: [% token %]
</span><span class="cx">        Token Type: [% tokentype %]
</span><span class="cx">              User: [% emailaddress %]
</span><del>-       Issue Date: [% issuedate %]
</del><ins>+       Issue Date: [% issuedate FILTER time(&quot;%Y-%m-%d %H:%M:%S %Z&quot;, timezone) %]
</ins><span class="cx">        Event Data: [% eventdata %]
</span><span class="cx"> Canceled Because: [% PROCESS cancelactionmessage %]
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultaccountcreatehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/account/create.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/account/create.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/account/create.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -40,7 +40,7 @@
</span><span class="cx"> [% IF Param('emailsuffix') == '' %]
</span><span class="cx">   a legitimate email address.
</span><span class="cx"> [% ELSE %]
</span><del>-  an accountname which when combined with [% Param('emailsuffix') %]
</del><ins>+  an account name which when combined with [% Param('emailsuffix') %]
</ins><span class="cx">   corresponds to an address where you receive email.
</span><span class="cx"> [% END %]
</span><span class="cx">   You will receive an email at this address to confirm the creation of your
</span><span class="lines">@@ -73,6 +73,7 @@
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">   &lt;/table&gt;
</span><span class="cx">   &lt;br&gt;
</span><ins>+  &lt;input type=&quot;hidden&quot; id=&quot;token&quot; name=&quot;token&quot; value=&quot;[% issue_hash_token(['create_account']) FILTER html %]&quot;&gt;
</ins><span class="cx">   &lt;input type=&quot;submit&quot; id=&quot;send&quot; value=&quot;Send&quot;&gt;
</span><span class="cx"> &lt;/form&gt;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultaccountemailchangenewtxttmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/account/email/change-new.txt.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/account/email/change-new.txt.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/account/email/change-new.txt.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -20,7 +20,6 @@
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="cx"> 
</span><del>-[% expiration_ts = token_ts + (max_token_age * 86400) %]
</del><span class="cx"> From: [% Param('mailfrom') %]
</span><span class="cx"> To: [% emailaddress %]
</span><span class="cx"> Subject: [% terms.Bugzilla %] Change Email Address Request
</span><span class="lines">@@ -31,12 +30,12 @@
</span><span class="cx"> 
</span><span class="cx"> To confirm the change, visit the following link:
</span><span class="cx"> 
</span><del>-[%+ urlbase %]token.cgi?t=[% token FILTER url_quote %]&amp;a=cfmem
</del><ins>+[%+ urlbase %]token.cgi?t=[% token FILTER uri %]&amp;a=cfmem
</ins><span class="cx"> 
</span><span class="cx"> If you are not the person who made this request, or you wish to cancel
</span><span class="cx"> this request, visit the following link:
</span><span class="cx"> 
</span><del>-[%+ urlbase %]token.cgi?t=[% token FILTER url_quote %]&amp;a=cxlem
</del><ins>+[%+ urlbase %]token.cgi?t=[% token FILTER uri %]&amp;a=cxlem
</ins><span class="cx"> 
</span><del>-If you do nothing, the request will lapse after [%+ max_token_age %] days
-(on [%+ time2str(&quot;%B %o, %Y at %H:%M %Z&quot;, expiration_ts) %]).
</del><ins>+If you do nothing, the request will lapse after [% constants.MAX_TOKEN_AGE %] days
+(on [% expiration_ts FILTER time(&quot;%B %e, %Y at %H:%M %Z&quot;) %]).
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultaccountemailchangeoldtxttmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/account/email/change-old.txt.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/account/email/change-old.txt.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/account/email/change-old.txt.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -25,7 +25,6 @@
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="cx"> 
</span><del>-[% expiration_ts = token_ts + (max_token_age * 86400) %]
</del><span class="cx"> From: [% Param('mailfrom') %]
</span><span class="cx"> To: [% emailaddress %]
</span><span class="cx"> Subject: [% terms.Bugzilla %] Change Email Address Request
</span><span class="lines">@@ -40,8 +39,8 @@
</span><span class="cx"> If you are not the person who made this request, or you wish to cancel
</span><span class="cx"> this request, visit the following link:
</span><span class="cx"> 
</span><del>-[%+ urlbase %]token.cgi?t=[% token FILTER url_quote %]&amp;a=cxlem
</del><ins>+[%+ urlbase %]token.cgi?t=[% token FILTER uri %]&amp;a=cxlem
</ins><span class="cx"> 
</span><span class="cx"> If you do nothing, and [%+ newemailaddress %] confirms this request,
</span><del>-the change will be made permanent after [%+ max_token_age %] days
-(on [%+ time2str(&quot;%B %o, %Y at %H:%M %Z&quot;, expiration_ts) %]).
</del><ins>+the change will be made permanent after [% constants.MAX_TOKEN_AGE %] days
+(on [% expiration_ts FILTER time(&quot;%B %e, %Y at %H:%M %Z&quot;) %]).
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultaccountemailconfirmnewhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/account/email/confirm-new.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/account/email/confirm-new.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/account/email/confirm-new.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -16,7 +16,7 @@
</span><span class="cx"> [%# INTERFACE:
</span><span class="cx">   # token: string. The token to be used in the user account creation.
</span><span class="cx">   # email: email address of the user account.
</span><del>-  # date: creation date of the token.
</del><ins>+  # expiration_ts: expiration date of the token.
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [% title = BLOCK %]Create a new user account for '[% email FILTER html %]'[% END %]
</span><span class="lines">@@ -24,12 +24,11 @@
</span><span class="cx">            title = title
</span><span class="cx">            onload = &quot;document.forms['confirm_account_form'].realname.focus();&quot; %]
</span><span class="cx"> 
</span><del>-[% expiration_ts = date + (constants.MAX_TOKEN_AGE * 86400) %]
-&lt;div&gt;
</del><ins>+&lt;p&gt;
</ins><span class="cx">   To create your account, you must enter a password in the form below.
</span><span class="cx">   Your email address and Real Name (if provided) will be shown with
</span><span class="cx">   changes you make.
</span><del>-&lt;/div&gt;
</del><ins>+&lt;/p&gt;
</ins><span class="cx"> 
</span><span class="cx"> &lt;form id=&quot;confirm_account_form&quot; method=&quot;post&quot; action=&quot;token.cgi&quot;&gt;
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;t&quot; value=&quot;[% token FILTER html %]&quot;&gt;
</span><span class="lines">@@ -45,7 +44,10 @@
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th align=&quot;right&quot;&gt;&lt;label for=&quot;passwd1&quot;&gt;Type your password&lt;/label&gt;:&lt;/th&gt;
</span><del>-      &lt;td&gt;&lt;input type=&quot;password&quot; id=&quot;passwd1&quot; name=&quot;passwd1&quot; value=&quot;&quot;&gt;&lt;/td&gt;
</del><ins>+      &lt;td&gt;
+        &lt;input type=&quot;password&quot; id=&quot;passwd1&quot; name=&quot;passwd1&quot; value=&quot;&quot;&gt;
+        (minimum [% constants.USER_PASSWORD_MIN_LENGTH FILTER none %] characters)
+      &lt;/td&gt;
</ins><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th align=&quot;right&quot;&gt;&lt;label for=&quot;passwd2&quot;&gt;Confirm your password&lt;/label&gt;:&lt;/th&gt;
</span><span class="lines">@@ -53,14 +55,14 @@
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th align=&quot;right&quot;&gt;&amp;nbsp;&lt;/th&gt;
</span><del>-      &lt;td&gt;&lt;input type=&quot;submit&quot; id=&quot;confirm&quot; value=&quot;Send&quot;&gt;&lt;/td&gt;
</del><ins>+      &lt;td&gt;&lt;input type=&quot;submit&quot; id=&quot;confirm&quot; value=&quot;Create&quot;&gt;&lt;/td&gt;
</ins><span class="cx">     &lt;/tr&gt;
</span><span class="cx">   &lt;/table&gt;
</span><span class="cx"> &lt;/form&gt;
</span><span class="cx"> 
</span><span class="cx"> &lt;p&gt;
</span><span class="cx">   This account will not be created if this form is not completed by
</span><del>-  &lt;u&gt;[%+ time2str(&quot;%B %o, %Y at %H:%M %Z&quot;, expiration_ts) %]&lt;/u&gt;.
</del><ins>+  &lt;u&gt;[% expiration_ts FILTER time(&quot;%B %e, %Y at %H:%M %Z&quot;) %]&lt;/u&gt;.
</ins><span class="cx"> &lt;/p&gt;
</span><span class="cx"> 
</span><span class="cx"> &lt;p&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultaccountemailrequestnewtxttmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/account/email/request-new.txt.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/account/email/request-new.txt.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/account/email/request-new.txt.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -15,13 +15,12 @@
</span><span class="cx"> 
</span><span class="cx"> [%# INTERFACE:
</span><span class="cx">   # token: random string used to authenticate the transaction.
</span><del>-  # token_ts: creation date of the token.
</del><ins>+  # expiration_ts: expiration date of the token.
</ins><span class="cx">   # email: email address of the new account.
</span><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="cx"> 
</span><del>-[% expiration_ts = token_ts + (constants.MAX_TOKEN_AGE * 86400) %]
</del><span class="cx"> From: [% Param('mailfrom') %]
</span><span class="cx"> To: [% email %]
</span><span class="cx"> Subject: [% terms.Bugzilla %]: confirm account creation
</span><span class="lines">@@ -31,11 +30,11 @@
</span><span class="cx"> using your email address ([% email %]).
</span><span class="cx"> 
</span><span class="cx"> To continue creating an account using this email address, visit the 
</span><del>-following link by [%+ time2str(&quot;%B %o, %Y at %H:%M %Z&quot;, expiration_ts) %]:
</del><ins>+following link by [% expiration_ts FILTER time(&quot;%B %e, %Y at %H:%M %Z&quot;) %]:
</ins><span class="cx"> 
</span><del>-[%+ urlbase %]token.cgi?t=[% token FILTER url_quote %]&amp;a=request_new_account
</del><ins>+[%+ urlbase %]token.cgi?t=[% token FILTER uri %]&amp;a=request_new_account
</ins><span class="cx"> 
</span><del>-If you did not receive this email before [%+ time2str(&quot;%B %o, %Y at %H:%M %Z&quot;, expiration_ts) %] or
</del><ins>+If you did not receive this email before [% expiration_ts FILTER time(&quot;%B %e, %Y at %H:%M %Z&quot;) %] or
</ins><span class="cx"> you wish to create an account using a different email address you can begin
</span><span class="cx"> again by going to:
</span><span class="cx"> 
</span><span class="lines">@@ -51,7 +50,7 @@
</span><span class="cx"> If you do not wish to create an account, or if this request was made in
</span><span class="cx"> error you can do nothing or visit the following link:
</span><span class="cx"> 
</span><del>-[%+ urlbase %]token.cgi?t=[% token FILTER url_quote %]&amp;a=cancel_new_account
</del><ins>+[%+ urlbase %]token.cgi?t=[% token FILTER uri %]&amp;a=cancel_new_account
</ins><span class="cx"> 
</span><span class="cx"> If the above links do not work, or you have any other issues regarding
</span><span class="cx"> your account, please contact administration at [% Param('maintainer') %].
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultaccountpasswordforgottenpasswordtxttmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/account/password/forgotten-password.txt.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/account/password/forgotten-password.txt.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/account/password/forgotten-password.txt.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -20,7 +20,6 @@
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="cx"> 
</span><del>-[% expiration_ts = token_ts + (max_token_age * 86400) %]
</del><span class="cx"> From: [% Param('mailfrom') %]
</span><span class="cx"> To: [% emailaddress %]
</span><span class="cx"> Subject:  [% terms.Bugzilla %] Change Password Request
</span><span class="lines">@@ -29,13 +28,13 @@
</span><span class="cx"> You have (or someone impersonating you has) requested to change your 
</span><span class="cx"> [%+ terms.Bugzilla %] password. To complete the change, visit the following link:
</span><span class="cx"> 
</span><del>-[%+ urlbase %]token.cgi?t=[% token FILTER url_quote %]&amp;a=cfmpw
</del><ins>+[%+ urlbase %]token.cgi?t=[% token FILTER uri %]&amp;a=cfmpw
</ins><span class="cx"> 
</span><span class="cx"> If you are not the person who made this request, or you wish to cancel
</span><span class="cx"> this request, visit the following link:
</span><span class="cx"> 
</span><del>-[%+ urlbase %]token.cgi?t=[% token FILTER url_quote %]&amp;a=cxlpw
</del><ins>+[%+ urlbase %]token.cgi?t=[% token FILTER uri %]&amp;a=cxlpw
</ins><span class="cx"> 
</span><del>-If you do nothing, the request will lapse after [%+ max_token_age +%] days (at 
-precisely [%+ time2str(&quot;%H:%M on the %o of %B, %Y&quot;, expiration_ts) -%]) or when you 
</del><ins>+If you do nothing, the request will lapse after [% constants.MAX_TOKEN_AGE %] days
+(on [% expiration_ts FILTER time(&quot;%B %e, %Y at %H:%M %Z&quot;, timezone) %]) or when you
</ins><span class="cx"> log in successfully.
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultaccountpasswordsetforgottenpasswordhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/account/password/set-forgotten-password.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/account/password/set-forgotten-password.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/account/password/set-forgotten-password.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -32,14 +32,15 @@
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th align=&quot;right&quot;&gt;New Password:&lt;/th&gt;
</span><span class="cx">       &lt;td&gt;
</span><del>-        &lt;input type=&quot;password&quot; name=&quot;password&quot; size=&quot;16&quot; maxlength=&quot;16&quot;&gt;
</del><ins>+        &lt;input type=&quot;password&quot; name=&quot;password&quot;&gt;
+        (minimum [% constants.USER_PASSWORD_MIN_LENGTH FILTER none %] characters)
</ins><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th align=&quot;right&quot;&gt;New Password Again:&lt;/th&gt;
</span><span class="cx">       &lt;td&gt;
</span><del>-        &lt;input type=&quot;password&quot; name=&quot;matchpassword&quot; size=&quot;16&quot; maxlength=&quot;16&quot;&gt;
</del><ins>+        &lt;input type=&quot;password&quot; name=&quot;matchpassword&quot;&gt;
</ins><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultaccountprefsaccounthtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/account/prefs/account.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/account/prefs/account.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/account/prefs/account.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -33,9 +33,8 @@
</span><span class="cx">   &lt;tr&gt;
</span><span class="cx">     &lt;th align=&quot;right&quot;&gt;Password:&lt;/th&gt;
</span><span class="cx">     &lt;td&gt;
</span><del>-      &lt;input type=&quot;hidden&quot; name=&quot;Bugzilla_login&quot; 
-             value=&quot;[% user.login FILTER html %]&quot;&gt;
-      &lt;input type=&quot;password&quot; name=&quot;Bugzilla_password&quot;&gt;
</del><ins>+      &lt;input type=&quot;hidden&quot; name=&quot;old_login&quot; value=&quot;[% user.login FILTER html %]&quot;&gt;
+      &lt;input type=&quot;password&quot; name=&quot;old_password&quot;&gt;
</ins><span class="cx">     &lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;              
</span><span class="cx">   &lt;tr&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultaccountprefsemailhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/account/prefs/email.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/account/prefs/email.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/account/prefs/email.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -31,14 +31,10 @@
</span><span class="cx">   #               below), keyed by reasonname (e.g. comments; again, see
</span><span class="cx">   #               below). The value is a boolean - true if the user is
</span><span class="cx">   #               receiving mail for that reason when in that role.
</span><del>-  # Also references the 'supportwatchers' Param.
</del><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="cx"> 
</span><del>-[% useqacontact = Param('useqacontact') %]
-[% usevotes = Param('usevotes') %]
-
</del><span class="cx"> &lt;p&gt;
</span><span class="cx">   If you don't like getting a notification for &quot;trivial&quot;
</span><span class="cx">   changes to [% terms.bugs %], you can use the settings below to
</span><span class="lines">@@ -81,8 +77,8 @@
</span><span class="cx">       [% prefname = &quot;email-$constants.REL_ANY-$constants.EVT_FLAG_REQUESTED&quot; %]
</span><span class="cx">       &lt;input type=&quot;checkbox&quot; name=&quot;[% prefname %]&quot; id=&quot;[% prefname %]&quot; 
</span><span class="cx">         value=&quot;1&quot;
</span><del>-        [% &quot; checked&quot; IF 
-                  mail.${constants.REL_ANY}.${constants.EVT_FLAG_REQUESTED} %]&gt;
</del><ins>+        [% &quot; checked&quot;
+           IF user.mail_settings.${constants.REL_ANY}.${constants.EVT_FLAG_REQUESTED} %]&gt;
</ins><span class="cx">       &lt;label for=&quot;[% prefname %]&quot;&gt;Email me when someone asks me to set a flag&lt;/label&gt;
</span><span class="cx">       &lt;br&gt;
</span><span class="cx">     &lt;/td&gt;
</span><span class="lines">@@ -93,8 +89,8 @@
</span><span class="cx">       [% prefname = &quot;email-$constants.REL_ANY-$constants.EVT_REQUESTED_FLAG&quot; %]
</span><span class="cx">       &lt;input type=&quot;checkbox&quot; name=&quot;[% prefname %]&quot; id=&quot;[% prefname %]&quot; 
</span><span class="cx">         value=&quot;1&quot;
</span><del>-        [% &quot; checked&quot; IF 
-                  mail.${constants.REL_ANY}.${constants.EVT_REQUESTED_FLAG} %]&gt;
</del><ins>+        [% &quot; checked&quot;
+           IF user.mail_settings.${constants.REL_ANY}.${constants.EVT_REQUESTED_FLAG} %]&gt;
</ins><span class="cx">       &lt;label for=&quot;[% prefname %]&quot;&gt;Email me when someone sets a flag I asked for&lt;/label&gt;
</span><span class="cx">       &lt;br&gt;
</span><span class="cx">     &lt;/td&gt;
</span><span class="lines">@@ -119,6 +115,8 @@
</span><span class="cx"> [% events = [
</span><span class="cx">     { id = constants.EVT_ADDED_REMOVED,
</span><span class="cx">       description = &quot;I'm added to or removed from this capacity&quot; },
</span><ins>+    { id = constants.EVT_BUG_CREATED,
+      description = &quot;A new $terms.bug is created&quot; },
</ins><span class="cx">     { id = constants.EVT_OPENED_CLOSED,
</span><span class="cx">       description = &quot;The $terms.bug is resolved or reopened&quot; },
</span><span class="cx">     { id = constants.EVT_PROJ_MANAGEMENT,
</span><span class="lines">@@ -149,21 +147,28 @@
</span><span class="cx"> [% relationships = [
</span><span class="cx">     { id = constants.REL_ASSIGNEE,
</span><span class="cx">       description = &quot;Assignee&quot; },
</span><del>-    { id = constants.REL_QA,
-      description = &quot;QA Contact&quot; },
</del><span class="cx">     { id = constants.REL_REPORTER,
</span><span class="cx">       description = &quot;Reporter&quot; },
</span><span class="cx">     { id = constants.REL_CC,
</span><span class="cx">       description = &quot;CCed&quot; },
</span><del>-    { id = constants.REL_VOTER,
-      description = &quot;Voter&quot; },
</del><span class="cx"> ] %]
</span><span class="cx"> 
</span><ins>+[% IF Param('useqacontact') %]
+  [% relationships.push({ id = constants.REL_QA, 
+                          description = &quot;QA Contact&quot; }) %]
+[% END %]
+
+
+[%# This is up here so that the &quot;relationships&quot; hook can modify it. %]
+[% no_added_removed = [constants.REL_REPORTER] %]
+
+[% Hook.process('relationships') %]
+
+[% num_columns = relationships.size %]
+
</ins><span class="cx"> &lt;table class=&quot;bz_emailprefs&quot; border=&quot;1&quot;&gt;
</span><span class="cx">   &lt;tr&gt;
</span><del>-    &lt;td colspan=&quot;[% (useqacontact AND usevotes) ? '5' : 
-                     ((useqacontact OR usevotes) ? '4' : '3') %]&quot; 
-        align=&quot;center&quot; width=&quot;50%&quot;&gt;
</del><ins>+    &lt;td colspan=&quot;[% num_columns FILTER html %]&quot; align=&quot;center&quot; width=&quot;50%&quot;&gt;
</ins><span class="cx">       &lt;b&gt;When my relationship to this [% terms.bug %] is:&lt;/b&gt;
</span><span class="cx">     &lt;/td&gt;
</span><span class="cx">     &lt;td rowspan=&quot;2&quot; width=&quot;40%&quot;&gt;
</span><span class="lines">@@ -173,8 +178,6 @@
</span><span class="cx"> 
</span><span class="cx">   &lt;tr&gt;
</span><span class="cx">     [% FOREACH relationship = relationships %]
</span><del>-      [% NEXT IF (relationship.id == constants.REL_QA AND NOT useqacontact) OR
-                 (relationship.id == constants.REL_VOTER AND NOT usevotes) %]
</del><span class="cx">       &lt;th align=&quot;center&quot; width=&quot;9%&quot;&gt;
</span><span class="cx">         [% relationship.description FILTER html %]
</span><span class="cx">       &lt;/th&gt;
</span><span class="lines">@@ -185,18 +188,16 @@
</span><span class="cx">     [% count = loop.count() %]
</span><span class="cx">     &lt;tr class=&quot;bz_row_[% count % 2 == 1 ? &quot;odd&quot; : &quot;even&quot; %]&quot;&gt;
</span><span class="cx">       [% FOREACH relationship = relationships %]
</span><del>-      [% NEXT IF (relationship.id == constants.REL_QA AND NOT useqacontact) OR
-                 (relationship.id == constants.REL_VOTER AND NOT usevotes) %]
</del><span class="cx">         &lt;td align=&quot;center&quot;&gt;
</span><span class="cx">           &lt;input type=&quot;checkbox&quot; 
</span><span class="cx">             name=&quot;email-[% relationship.id %]-[% event.id %]&quot;
</span><span class="cx">             value=&quot;1&quot;
</span><span class="cx">             [%# The combinations don't always make sense; disable a couple %]
</span><span class="cx">             [% IF event.id == constants.EVT_ADDED_REMOVED AND 
</span><del>-                 (relationship.id == constants.REL_REPORTER OR
-                  relationship.id == constants.REL_VOTER) %]
</del><ins>+                  no_added_removed.contains(relationship.id) 
+            %]
</ins><span class="cx">                disabled
</span><del>-            [% ELSIF mail.${relationship.id}.${event.id} %]
</del><ins>+            [% ELSIF user.mail_settings.${relationship.id}.${event.id} %]
</ins><span class="cx">                checked
</span><span class="cx">             [% END %]&gt;
</span><span class="cx">         &lt;/td&gt;
</span><span class="lines">@@ -208,8 +209,7 @@
</span><span class="cx">   [% END %]
</span><span class="cx">   
</span><span class="cx">   &lt;tr&gt;
</span><del>-    &lt;td colspan=&quot;[% (useqacontact AND usevotes) ? '5' : 
-                     ((useqacontact OR usevotes) ? '4' : '3') %]&quot; 
</del><ins>+    &lt;td colspan=&quot;[% num_columns FILTER html %]&quot; 
</ins><span class="cx">         align=&quot;center&quot; width=&quot;50%&quot;&gt;
</span><span class="cx">       &amp;nbsp;
</span><span class="cx">     &lt;/td&gt;
</span><span class="lines">@@ -222,13 +222,11 @@
</span><span class="cx">     [% count = loop.count() %]
</span><span class="cx">     &lt;tr class=&quot;bz_row_[% count % 2 == 1 ? &quot;odd&quot; : &quot;even&quot; %]&quot;&gt;
</span><span class="cx">       [% FOREACH relationship = relationships %]
</span><del>-        [% NEXT IF (relationship.id == constants.REL_QA AND NOT useqacontact) OR
-                   (relationship.id == constants.REL_VOTER AND NOT usevotes) %]
</del><span class="cx">         &lt;td align=&quot;center&quot;&gt;
</span><span class="cx">           &lt;input type=&quot;checkbox&quot; 
</span><span class="cx">             name=&quot;neg-email-[% relationship.id %]-[% event.id %]&quot;
</span><span class="cx">             value=&quot;1&quot;
</span><del>-            [% &quot; checked&quot; IF NOT mail.${relationship.id}.${event.id} %]&gt;
</del><ins>+            [% &quot; checked&quot; IF NOT user.mail_settings.${relationship.id}.${event.id} %]&gt;
</ins><span class="cx">         &lt;/td&gt;
</span><span class="cx">       [% END %]
</span><span class="cx">       &lt;td&gt;
</span><span class="lines">@@ -239,30 +237,6 @@
</span><span class="cx">   
</span><span class="cx"> &lt;/table&gt;
</span><span class="cx"> 
</span><del>-[%# Add hidden form fields for fields not used %]
-[% FOREACH event = events %]  
-  [% FOREACH relationship = relationships %]
-    [% IF (relationship.id == constants.REL_QA AND NOT useqacontact) OR
-          (relationship.id == constants.REL_VOTER AND NOT usevotes) %]
-      &lt;input type=&quot;hidden&quot; 
-        name=&quot;email-[% relationship.id %]-[% event.id %]&quot;
-        value=&quot;[% mail.${relationship.id}.${event.id} ? &quot;1&quot; : &quot;0&quot; %]&quot;&gt;
-    [% END %]
-  [% END %]
-[% END %]
-
-[% FOREACH event = neg_events %]  
-  [% FOREACH relationship = relationships %]
-    [% IF (relationship.id == constants.REL_QA AND NOT useqacontact) OR
-          (relationship.id == constants.REL_VOTER AND NOT usevotes) %]
-      &lt;input type=&quot;hidden&quot; 
-        name=&quot;neg-email-[% relationship.id %]-[% event.id %]&quot;
-        value=&quot;[% mail.${relationship.id}.${event.id} ? &quot;0&quot; : &quot;1&quot; %]&quot;&gt;
-    [% END %]
-  [% END %]
-[% END %]
-
-[% IF Param('supportwatchers') %]
</del><span class="cx"> &lt;hr&gt;
</span><span class="cx"> &lt;b&gt;User Watching&lt;/b&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -290,11 +264,17 @@
</span><span class="cx"> [% END %]
</span><span class="cx"> &lt;/p&gt;
</span><span class="cx"> 
</span><del>-&lt;p&gt;&lt;a name=&quot;new_watched_by_you&quot; id=&quot;new_watched_by_you&quot;&gt;Add users to my watch list (comma separated list)&lt;/a&gt;:
-  &lt;input size=&quot;60&quot; name=&quot;new_watchedusers&quot; value=&quot;&quot;&gt;
</del><ins>+&lt;p id=&quot;new_watched_by_you&quot;&gt;Add users to my watch list (comma separated list):
+  [% INCLUDE global/userselect.html.tmpl
+     id =&gt; &quot;new_watchedusers&quot;
+     name =&gt; &quot;new_watchedusers&quot;
+     value =&gt; &quot;&quot;
+     size =&gt; 60
+     multiple =&gt; 5
+  %]
</ins><span class="cx"> &lt;/p&gt;            
</span><span class="cx"> 
</span><del>-&lt;p&gt;&lt;a name=&quot;watching_you&quot; id=&quot;watching_you&quot;&gt;Users watching you&lt;/a&gt;:&lt;br&gt;
</del><ins>+&lt;p id=&quot;watching_you&quot;&gt;Users watching you:&lt;br&gt;
</ins><span class="cx">   [% IF watchers.size %]
</span><span class="cx">     [% FOREACH watcher = watchers %]
</span><span class="cx">       [% watcher FILTER html %] &lt;br&gt;
</span><span class="lines">@@ -304,8 +284,6 @@
</span><span class="cx">   [% END %]
</span><span class="cx"> &lt;/p&gt;
</span><span class="cx"> 
</span><del>-[% END %]
-
</del><span class="cx"> &lt;hr&gt;
</span><span class="cx"> 
</span><span class="cx"> &lt;br&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultaccountprefspermissionshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/account/prefs/permissions.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/account/prefs/permissions.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/account/prefs/permissions.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -65,7 +65,7 @@
</span><span class="cx">         There are no permission bits set on your account.
</span><span class="cx">       [% END %]
</span><span class="cx"> 
</span><del>-      [% IF user.groups.editusers %]
</del><ins>+      [% IF user.in_group('editusers') %]
</ins><span class="cx">         &lt;br&gt;
</span><span class="cx">         You have editusers privileges.  You can turn on and off
</span><span class="cx">         all permissions for all users.
</span><span class="lines">@@ -83,7 +83,7 @@
</span><span class="cx">           &lt;/table&gt;
</span><span class="cx">       [% END %]
</span><span class="cx"> 
</span><del>-      [% IF user.groups.bz_sudoers %]
</del><ins>+      [% IF user.in_group('bz_sudoers') %]
</ins><span class="cx">         &lt;br&gt;
</span><span class="cx">         You are a member of the &lt;b&gt;bz_sudoers&lt;/b&gt; group, so you can 
</span><span class="cx">         &lt;a href=&quot;relogin.cgi?action=prepare-sudo&quot;&gt;impersonate someone else&lt;/a&gt;.
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultaccountprefsprefshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/account/prefs/prefs.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/account/prefs/prefs.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/account/prefs/prefs.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -40,8 +40,9 @@
</span><span class="cx">    title = &quot;User Preferences&quot;
</span><span class="cx">    subheader = filtered_login
</span><span class="cx">    style_urls = ['skins/standard/admin.css']
</span><del>-   javascript_urls = ['js/util.js']
</del><ins>+   javascript_urls = ['js/util.js', 'js/field.js']
</ins><span class="cx">    doc_section = &quot;userpreferences.html&quot;
</span><ins>+   yui = ['autocomplete']
</ins><span class="cx">  %]
</span><span class="cx"> 
</span><span class="cx"> [% tabs = [{ name =&gt; &quot;settings&quot;, label =&gt; &quot;General Preferences&quot;,
</span><span class="lines">@@ -50,11 +51,13 @@
</span><span class="cx">               link =&gt; &quot;userprefs.cgi?tab=email&quot;, saveable =&gt; &quot;1&quot; },
</span><span class="cx">             { name =&gt; &quot;saved-searches&quot;, label =&gt; &quot;Saved Searches&quot;, 
</span><span class="cx">               link =&gt; &quot;userprefs.cgi?tab=saved-searches&quot;, saveable =&gt; &quot;1&quot; },
</span><del>-            { name =&gt; &quot;account&quot;, label =&gt; &quot;Name and Password&quot;,
</del><ins>+            { name =&gt; &quot;account&quot;, label =&gt; &quot;Account Information&quot;,
</ins><span class="cx">               link =&gt; &quot;userprefs.cgi?tab=account&quot;, saveable =&gt; &quot;1&quot; },
</span><span class="cx">             { name =&gt; &quot;permissions&quot;, label =&gt; &quot;Permissions&quot;, 
</span><span class="cx">               link =&gt; &quot;userprefs.cgi?tab=permissions&quot;, saveable =&gt; &quot;0&quot; } ] %]
</span><span class="cx"> 
</span><ins>+[% Hook.process('tabs') %]
+
</ins><span class="cx"> [% FOREACH tab IN tabs %]
</span><span class="cx">   [% IF tab.name == current_tab_name %]
</span><span class="cx">     [% current_tab = tab %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultaccountprefssavedsearcheshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/account/prefs/saved-searches.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/account/prefs/saved-searches.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/account/prefs/saved-searches.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -31,9 +31,9 @@
</span><span class="cx">       var checkbox = document.getElementById(group.name.replace(/share_(\d+)/, &quot;force_$1&quot;));
</span><span class="cx"> 
</span><span class="cx">       if (bz_isValueInArray(bless_groups, group.value)) {
</span><del>-        checkbox.disabled = false;
</del><ins>+        YAHOO.util.Dom.removeClass(checkbox.parentNode, &quot;bz_default_hidden&quot;);
</ins><span class="cx">       } else {
</span><del>-        checkbox.disabled = true;
</del><ins>+        YAHOO.util.Dom.addClass(checkbox.parentNode, &quot;bz_default_hidden&quot;);
</ins><span class="cx">         checkbox.checked = false;
</span><span class="cx">       }
</span><span class="cx">     } //--&gt;
</span><span class="lines">@@ -71,7 +71,7 @@
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;td&gt;My [% terms.Bugs %]&lt;/td&gt;
</span><span class="cx">       &lt;td&gt;
</span><del>-        [% filtered_username = user.login FILTER url_quote %]
</del><ins>+        [% filtered_username = user.login FILTER uri %]
</ins><span class="cx">         &lt;a href=&quot;[% Param('mybugstemplate').replace('%userid%', filtered_username) %]&quot;&gt;Run&lt;/a&gt;
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">       &lt;td&gt;
</span><span class="lines">@@ -96,19 +96,20 @@
</span><span class="cx">       &lt;tr&gt;
</span><span class="cx">         &lt;td&gt;[% q.name FILTER html %]&lt;/td&gt;
</span><span class="cx">         &lt;td&gt;
</span><del>-          &lt;a href=&quot;buglist.cgi?cmdtype=runnamed&amp;amp;namedcmd=[% q.name FILTER url_quote %]&quot;&gt;Run&lt;/a&gt;
</del><ins>+          &lt;a href=&quot;buglist.cgi?cmdtype=dorem&amp;amp;remaction=run&amp;amp;namedcmd=[% q.name FILTER uri %]
+                   [% IF q.shared_with_group.id %]&amp;amp;sharer_id=[% user.id FILTER uri %][% END %]&quot;&gt;Run&lt;/a&gt;
</ins><span class="cx">         &lt;/td&gt;
</span><span class="cx">         &lt;td&gt;
</span><span class="cx">           &lt;a href=&quot;query.cgi?[% q.edit_link FILTER html %]&amp;amp;known_name=
</span><del>-                   [% q.name FILTER url_quote %]&quot;&gt;Edit&lt;/a&gt;
</del><ins>+                   [% q.name FILTER uri %]&quot;&gt;Edit&lt;/a&gt;
</ins><span class="cx">         &lt;/td&gt;
</span><span class="cx">         &lt;td&gt;
</span><span class="cx">           [% IF q.used_in_whine %]
</span><span class="cx">             Remove from &lt;a href=&quot;editwhines.cgi&quot;&gt;whining&lt;/a&gt; first
</span><span class="cx">           [% ELSE %]
</span><span class="cx">             &lt;a href=&quot;buglist.cgi?cmdtype=dorem&amp;amp;remaction=forget&amp;amp;namedcmd=
</span><del>-                     [% q.name FILTER url_quote %]&amp;amp;token=
-                     [% issue_hash_token([q.id, q.name]) FILTER url_quote %]&quot;&gt;Forget&lt;/a&gt;
</del><ins>+                     [% q.name FILTER uri %]&amp;amp;token=
+                     [% issue_hash_token([q.id, q.name]) FILTER uri %]&quot;&gt;Forget&lt;/a&gt;
</ins><span class="cx">           [% END %]
</span><span class="cx">         &lt;/td&gt;
</span><span class="cx">         &lt;td align=&quot;center&quot;&gt;
</span><span class="lines">@@ -131,12 +132,12 @@
</span><span class="cx">               [% END %]
</span><span class="cx">             &lt;/select&gt;
</span><span class="cx">             [% IF user.can_bless %]
</span><del>-              &lt;input type=&quot;checkbox&quot; id=&quot;force_[% q.id FILTER html %]&quot;
-                     name=&quot;force_[% q.id FILTER html %]&quot; value=&quot;1&quot;
-                     [% &quot; disabled&quot;
-                        IF !bless_group_ids.grep(&quot;^$q.shared_with_group.id\$&quot;).0
-                     %]&gt;
-              &lt;label for=&quot;force_[% q.id FILTER html %]&quot;&gt;Add to footer&lt;/label&gt;
</del><ins>+              &lt;span [% IF !bless_group_ids.grep(&quot;^$q.shared_with_group.id\$&quot;).0
+                     %]class=&quot;bz_default_hidden&quot;[% END %]&gt;
+                &lt;input type=&quot;checkbox&quot; id=&quot;force_[% q.id FILTER html %]&quot;
+                       name=&quot;force_[% q.id FILTER html %]&quot; value=&quot;1&quot;&gt;
+                &lt;label for=&quot;force_[% q.id FILTER html %]&quot;&gt;Add to footer&lt;/label&gt;
+              &lt;/span&gt;
</ins><span class="cx">             [% END %]
</span><span class="cx">             [% IF q.shared_with_users %]
</span><span class="cx">               (shared with [% q.shared_with_users FILTER html %]
</span><span class="lines">@@ -154,9 +155,9 @@
</span><span class="cx"> [% END %]
</span><span class="cx"> &lt;/blockquote&gt;
</span><span class="cx"> 
</span><del>-&lt;p&gt;You may use these searches saved and shared by others:&lt;/p&gt;
</del><ins>+[% IF user.queries_available.size %]
+  &lt;p&gt;You may use these searches saved and shared by others:&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;blockquote&gt;
</del><span class="cx">   &lt;table border=&quot;1&quot; cellpadding=&quot;3&quot;&gt;  
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th&gt;
</span><span class="lines">@@ -179,21 +180,19 @@
</span><span class="cx">         Footer
</span><span class="cx">       &lt;/th&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><del>-    [% found_shared_query = 0 %]
</del><span class="cx">     [% FOREACH q = user.queries_available %]
</span><del>-      [% found_shared_query = 1 %]
</del><span class="cx">       &lt;tr&gt;
</span><span class="cx">         &lt;td&gt;[% q.name FILTER html %]&lt;/td&gt;
</span><span class="cx">         &lt;td&gt;[% q.user.identity FILTER html %]&lt;/td&gt;
</span><span class="cx">         &lt;td&gt;[% q.shared_with_group.name FILTER html %]&lt;/td&gt;
</span><span class="cx">         &lt;td&gt;
</span><span class="cx">           &lt;a href=&quot;buglist.cgi?cmdtype=dorem&amp;amp;remaction=run&amp;amp;namedcmd=
</span><del>-                   [% q.name FILTER url_quote %]&amp;amp;sharer_id=
-                   [% q.user.id FILTER url_quote %]&quot;&gt;Run&lt;/a&gt;
</del><ins>+                   [% q.name FILTER uri %]&amp;amp;sharer_id=
+                   [% q.user.id FILTER uri %]&quot;&gt;Run&lt;/a&gt;
</ins><span class="cx">         &lt;/td&gt;
</span><span class="cx">         &lt;td&gt;
</span><span class="cx">           &lt;a href=&quot;query.cgi?[% q.edit_link FILTER html %]&amp;amp;known_name=
</span><del>-                   [% q.name FILTER url_quote %]&quot;&gt;Edit&lt;/a&gt;
</del><ins>+                   [% q.name FILTER uri %]&quot;&gt;Edit&lt;/a&gt;
</ins><span class="cx">         &lt;/td&gt;
</span><span class="cx">         &lt;td align=&quot;center&quot;&gt;
</span><span class="cx">           &lt;input type=&quot;checkbox&quot; 
</span><span class="lines">@@ -204,12 +203,7 @@
</span><span class="cx">         &lt;/td&gt;
</span><span class="cx">       &lt;/tr&gt;
</span><span class="cx">     [% END %]
</span><del>-    [% IF !found_shared_query %]
-      &lt;tr&gt;
-        &lt;td colspan=&quot;6&quot; style=&quot;text-align: center&quot;&gt;
-          &amp;lt;None&amp;gt;
-        &lt;/td&gt;
-      &lt;/tr&gt;
-    [% END %]
</del><span class="cx">   &lt;/table&gt;
</span><del>-&lt;/blockquote&gt;
</del><ins>+[% ELSE %]
+  &lt;p&gt;No searches are shared with you by other users.&lt;/p&gt;
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultaccountprofileactivityhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/account/profile-activity.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/account/profile-activity.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/account/profile-activity.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -56,6 +56,7 @@
</span><span class="cx">    }
</span><span class="cx">    {name               =&gt; 'what'
</span><span class="cx">     heading            =&gt; 'What'
</span><ins>+    content_use_field  =&gt; 1
</ins><span class="cx">    }
</span><span class="cx">    {name               =&gt; 'removed'
</span><span class="cx">     heading            =&gt; 'Removed'
</span><span class="lines">@@ -72,9 +73,9 @@
</span><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> &lt;p&gt;&lt;a href=&quot;editusers.cgi?action=edit&amp;amp;userid=
</span><del>-  [%- otheruser.id FILTER url_quote %]&quot;
</del><ins>+  [%- otheruser.id FILTER uri %]&quot;
</ins><span class="cx">   title=&quot;Edit user '[% otheruser.login FILTER html %]'&quot;&gt;Edit this user&lt;/a&gt; or
</span><del>-  &lt;a title=&quot;Search For Users&quot; href=&quot;editusers.cgi&quot;&gt;find other accounts&lt;/a&gt;
</del><ins>+  &lt;a title=&quot;Search For Users&quot; href=&quot;editusers.cgi&quot;&gt;search for other accounts&lt;/a&gt;
</ins><span class="cx">   [% IF listselectionvalues.matchtype != 'exact' %]
</span><span class="cx">     or go &lt;a title=&quot;Return to the user list&quot;
</span><span class="cx">        href=&quot;editusers.cgi?action=list[% INCLUDE listselectionurlparams %]&quot;&gt;back
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminadminhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/admin.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/admin.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/admin.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -26,7 +26,7 @@
</span><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> &lt;div&gt;
</span><del>-  This page is only accessible to empowered users. You can access administrive pages
</del><ins>+  This page is only accessible to empowered users. You can access administrative pages
</ins><span class="cx">   from here (based on your privileges), letting you configure different aspects of
</span><span class="cx">   this installation. Note: some sections may not be accessible to you and are marked
</span><span class="cx">   using a lighter color.
</span><span class="lines">@@ -36,59 +36,62 @@
</span><span class="cx">   &lt;tr&gt;
</span><span class="cx">     &lt;td class=&quot;admin_links&quot;&gt;
</span><span class="cx">       &lt;dl&gt;
</span><del>-        [% class = user.groups.tweakparams ? &quot;&quot; : &quot;forbidden&quot; %]
-        &lt;dt class=&quot;[% class %]&quot;&gt;&lt;a href=&quot;editparams.cgi&quot;&gt;Parameters&lt;/a&gt;&lt;/dt&gt;
</del><ins>+        [% class = user.in_group('tweakparams') ? &quot;&quot; : &quot;forbidden&quot; %]
+        &lt;dt id=&quot;parameters&quot; class=&quot;[% class %]&quot;&gt;&lt;a href=&quot;editparams.cgi&quot;&gt;Parameters&lt;/a&gt;&lt;/dt&gt;
</ins><span class="cx">         &lt;dd class=&quot;[% class %]&quot;&gt;Set core parameters of the installation. That's the
</span><span class="cx">         place where you specify the URL to access this installation, determine how
</span><span class="cx">         users authenticate, choose which [% terms.bug %] fields to display, select
</span><span class="cx">         the mail transfer agent to send email notifications, choose which group of
</span><span class="cx">         users can use charts and share queries, and much more.&lt;/dd&gt;
</span><span class="cx"> 
</span><del>-        &lt;dt class=&quot;[% class %]&quot;&gt;&lt;a href=&quot;editsettings.cgi&quot;&gt;Default Preferences&lt;/a&gt;&lt;/dt&gt;
</del><ins>+        &lt;dt id=&quot;preferences&quot; class=&quot;[% class %]&quot;&gt;&lt;a href=&quot;editsettings.cgi&quot;&gt;Default Preferences&lt;/a&gt;&lt;/dt&gt;
</ins><span class="cx">         &lt;dd class=&quot;[% class %]&quot;&gt;Set the default user preferences. These are the values
</span><span class="cx">         which will be used by default for all users. Users will be able to edit their
</span><span class="cx">         own preferences from the &lt;a href=&quot;userprefs.cgi?tab=settings&quot;&gt;Preferences&lt;/a&gt;.&lt;/dd&gt;
</span><span class="cx"> 
</span><del>-        [% class = user.groups.editcomponents ? &quot;&quot; : &quot;forbidden&quot; %]
-        &lt;dt class=&quot;[% class %]&quot;&gt;&lt;a href=&quot;sanitycheck.cgi&quot;&gt;Sanity Check&lt;/a&gt;&lt;/dt&gt;
</del><ins>+        [% class = user.in_group('editcomponents') ? &quot;&quot; : &quot;forbidden&quot; %]
+        &lt;dt id=&quot;sanitycheck&quot; class=&quot;[% class %]&quot;&gt;&lt;a href=&quot;sanitycheck.cgi&quot;&gt;Sanity Check&lt;/a&gt;&lt;/dt&gt;
</ins><span class="cx">         &lt;dd class=&quot;[% class %]&quot;&gt;Run sanity checks to locate problems in your database.
</span><span class="cx">         This may take several tens of minutes depending on the size of your installation.
</span><span class="cx">         You can also automate this check by running &lt;tt&gt;sanitycheck.pl&lt;/tt&gt; from a cron job.
</span><span class="cx">         A notification will be sent per email to the specified user if errors are detected.&lt;/dd&gt;
</span><span class="cx"> 
</span><del>-        [% class = (user.groups.editusers || user.can_bless) ? &quot;&quot; : &quot;forbidden&quot; %]
-        &lt;dt class=&quot;[% class %]&quot;&gt;&lt;a href=&quot;editusers.cgi&quot;&gt;Users&lt;/a&gt;&lt;/dt&gt;
</del><ins>+        [% class = (user.in_group('editusers') || user.can_bless) ? &quot;&quot; : &quot;forbidden&quot; %]
+        &lt;dt id=&quot;users&quot; class=&quot;[% class %]&quot;&gt;&lt;a href=&quot;editusers.cgi&quot;&gt;Users&lt;/a&gt;&lt;/dt&gt;
</ins><span class="cx">         &lt;dd class=&quot;[% class %]&quot;&gt;Create new user accounts or edit existing ones. You can
</span><span class="cx">         also add and remove users from groups (also known as &quot;user privileges&quot;).&lt;/dd&gt;
</span><span class="cx"> 
</span><del>-        [% class = (Param('useclassification') &amp;&amp; user.groups.editclassifications) ? &quot;&quot; : &quot;forbidden&quot; %]
-        &lt;dt class=&quot;[% class %]&quot;&gt;&lt;a href=&quot;editclassifications.cgi&quot;&gt;Classifications&lt;/a&gt;&lt;/dt&gt;
</del><ins>+        [% class = (Param('useclassification') &amp;&amp; user.in_group('editclassifications')) ? &quot;&quot; : &quot;forbidden&quot; %]
+        &lt;dt id=&quot;classifications&quot; class=&quot;[% class %]&quot;&gt;&lt;a href=&quot;editclassifications.cgi&quot;&gt;Classifications&lt;/a&gt;&lt;/dt&gt;
</ins><span class="cx">         &lt;dd class=&quot;[% class %]&quot;&gt;If your installation has to manage many products at once,
</span><span class="cx">         it's a good idea to group these products into distinct categories. This lets users
</span><span class="cx">         find information more easily when doing searches or when filing new [% terms.bugs %].&lt;/dd&gt;
</span><span class="cx"> 
</span><del>-        [% class = (user.groups.editcomponents
</del><ins>+        [% class = (user.in_group('editcomponents')
</ins><span class="cx">                     || user.get_products_by_permission(&quot;editcomponents&quot;).size) ? &quot;&quot; : &quot;forbidden&quot; %]
</span><del>-        &lt;dt class=&quot;[% class %]&quot;&gt;&lt;a href=&quot;editproducts.cgi&quot;&gt;Products&lt;/a&gt;&lt;/dt&gt;
</del><ins>+        &lt;dt id=&quot;products&quot; class=&quot;[% class %]&quot;&gt;&lt;a href=&quot;editproducts.cgi&quot;&gt;Products&lt;/a&gt;&lt;/dt&gt;
</ins><span class="cx">         &lt;dd class=&quot;[% class %]&quot;&gt;Edit all aspects of products, including group restrictions
</span><span class="cx">         which let you define who can access [% terms.bugs %] being in these products. You
</span><span class="cx">         can also edit some specific attributes of products such as
</span><span class="cx">         &lt;a href=&quot;editcomponents.cgi&quot;&gt;components&lt;/a&gt;, &lt;a href=&quot;editversions.cgi&quot;&gt;versions&lt;/a&gt;
</span><span class="cx">         and &lt;a href=&quot;editmilestones.cgi&quot;&gt;milestones&lt;/a&gt; directly.&lt;/dd&gt;
</span><span class="cx"> 
</span><del>-        [% class = user.groups.editcomponents ? &quot;&quot; : &quot;forbidden&quot; %]
-        &lt;dt class=&quot;[% class %]&quot;&gt;&lt;a href=&quot;editflagtypes.cgi&quot;&gt;Flags&lt;/a&gt;&lt;/dt&gt;
</del><ins>+        [% class = (user.in_group('editcomponents')
+                   || user.get_products_by_permission('editcomponents').size) ? &quot;&quot; : &quot;forbidden&quot; %]
+        &lt;dt id=&quot;flags&quot; class=&quot;[% class %]&quot;&gt;&lt;a href=&quot;editflagtypes.cgi&quot;&gt;Flags&lt;/a&gt;&lt;/dt&gt;
</ins><span class="cx">         &lt;dd class=&quot;[% class %]&quot;&gt;A flag is a custom 4-states attribute of [% terms.bugs %]
</span><span class="cx">         and/or attachments. These states are: granted, denied, requested and undefined.
</span><span class="cx">         You can set as many flags as desired per [% terms.bug %], and define which users
</span><span class="cx">         are allowed to edit them.&lt;/dd&gt;
</span><ins>+
+        [% Hook.process('end_links_left') %]
</ins><span class="cx">       &lt;/dl&gt;
</span><span class="cx">     &lt;/td&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;td class=&quot;admin_links&quot;&gt;
</span><span class="cx">       &lt;dl&gt;
</span><del>-        [% class = user.groups.admin ? &quot;&quot; : &quot;forbidden&quot; %]
-        &lt;dt class=&quot;[% class %]&quot;&gt;&lt;a href=&quot;editfields.cgi&quot;&gt;Custom Fields&lt;/a&gt;&lt;/dt&gt;
</del><ins>+        [% class = user.in_group('admin') ? &quot;&quot; : &quot;forbidden&quot; %]
+        &lt;dt id=&quot;custom_fields&quot; class=&quot;[% class %]&quot;&gt;&lt;a href=&quot;editfields.cgi&quot;&gt;Custom Fields&lt;/a&gt;&lt;/dt&gt;
</ins><span class="cx">         &lt;dd class=&quot;[% class %]&quot;&gt;[% terms.Bugzilla %] lets you define fields which are
</span><span class="cx">         not implemented by default, based on your local and specific requirements.
</span><span class="cx">         These fields can then be used as any other field, meaning that you can set
</span><span class="lines">@@ -97,32 +100,34 @@
</span><span class="cx">         interface more complex and harder to use. Be sure you have investigated other ways
</span><span class="cx">         to satisfy your needs before doing this.&lt;/dd&gt;
</span><span class="cx"> 
</span><del>-        &lt;dt class=&quot;[% class %]&quot;&gt;&lt;a href=&quot;editvalues.cgi&quot;&gt;Field Values&lt;/a&gt;&lt;/dt&gt;
</del><ins>+        &lt;dt id=&quot;field_values&quot; class=&quot;[% class %]&quot;&gt;&lt;a href=&quot;editvalues.cgi&quot;&gt;Field Values&lt;/a&gt;&lt;/dt&gt;
</ins><span class="cx">         &lt;dd class=&quot;[% class %]&quot;&gt;Define legal values for fields whose values must belong
</span><span class="cx">         to some given list. This is also the place where you define legal values for some
</span><span class="cx">         types of custom fields.&lt;/dd&gt;
</span><span class="cx"> 
</span><del>-        &lt;dt class=&quot;[% class %]&quot;&gt;&lt;a href=&quot;editworkflow.cgi&quot;&gt;[%terms.Bug %] Status Workflow&lt;/a&gt;&lt;/dt&gt;
</del><ins>+        &lt;dt id=&quot;status_workflow&quot; class=&quot;[% class %]&quot;&gt;&lt;a href=&quot;editworkflow.cgi&quot;&gt;[%terms.Bug %] Status Workflow&lt;/a&gt;&lt;/dt&gt;
</ins><span class="cx">         &lt;dd class=&quot;[% class %]&quot;&gt;Customize your workflow and choose initial [% terms.bug %]
</span><span class="cx">         statuses available on [% terms.bug %] creation and allowed [% terms.bug %] status
</span><span class="cx">         transitions when editing existing [% terms.bugs %].&lt;/dd&gt;
</span><span class="cx"> 
</span><del>-        [% class = user.groups.creategroups ? &quot;&quot; : &quot;forbidden&quot; %]
-        &lt;dt class=&quot;[% class %]&quot;&gt;&lt;a href=&quot;editgroups.cgi&quot;&gt;Groups&lt;/a&gt;&lt;/dt&gt;
</del><ins>+        [% class = user.in_group('creategroups') ? &quot;&quot; : &quot;forbidden&quot; %]
+        &lt;dt id=&quot;groups&quot; class=&quot;[% class %]&quot;&gt;&lt;a href=&quot;editgroups.cgi&quot;&gt;Groups&lt;/a&gt;&lt;/dt&gt;
</ins><span class="cx">         &lt;dd class=&quot;[% class %]&quot;&gt;Define groups which will be used in the installation.
</span><span class="cx">         They can either be used to define new user privileges or to restrict the access
</span><span class="cx">         to some [% terms.bugs %].&lt;/dd&gt;
</span><span class="cx"> 
</span><del>-        [% class = user.groups.editkeywords ? &quot;&quot; : &quot;forbidden&quot; %]
-        &lt;dt class=&quot;[% class %]&quot;&gt;&lt;a href=&quot;editkeywords.cgi&quot;&gt;Keywords&lt;/a&gt;&lt;/dt&gt;
</del><ins>+        [% class = user.in_group('editkeywords') ? &quot;&quot; : &quot;forbidden&quot; %]
+        &lt;dt id=&quot;keywords&quot; class=&quot;[% class %]&quot;&gt;&lt;a href=&quot;editkeywords.cgi&quot;&gt;Keywords&lt;/a&gt;&lt;/dt&gt;
</ins><span class="cx">         &lt;dd class=&quot;[% class %]&quot;&gt;Set keywords to be used with [% terms.bugs %]. Keywords
</span><span class="cx">         are an easy way to &quot;tag&quot; [% terms.bugs %] to let you find them more easily later.&lt;/dd&gt;
</span><span class="cx"> 
</span><del>-        [% class = user.groups.bz_canusewhines ? &quot;&quot; : &quot;forbidden&quot; %]
-        &lt;dt class=&quot;[% class %]&quot;&gt;&lt;a href=&quot;editwhines.cgi&quot;&gt;Whining&lt;/a&gt;&lt;/dt&gt;
</del><ins>+        [% class = user.in_group('bz_canusewhines') ? &quot;&quot; : &quot;forbidden&quot; %]
+        &lt;dt id=&quot;whining&quot; class=&quot;[% class %]&quot;&gt;&lt;a href=&quot;editwhines.cgi&quot;&gt;Whining&lt;/a&gt;&lt;/dt&gt;
</ins><span class="cx">         &lt;dd class=&quot;[% class %]&quot;&gt;Set queries which will be run at some specified date
</span><span class="cx">         and time, and get the result of these queries directly per email. This is a
</span><span class="cx">         good way to create reminders and to keep track of the activity in your installation.&lt;/dd&gt;
</span><ins>+
+        [% Hook.process('end_links_right') %]
</ins><span class="cx">       &lt;/dl&gt;
</span><span class="cx">     &lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminclassificationsaddhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/classifications/add.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/classifications/add.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/classifications/add.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -24,26 +24,9 @@
</span><span class="cx"> 
</span><span class="cx"> &lt;form method=post action=&quot;editclassifications.cgi&quot;&gt;
</span><span class="cx">   &lt;table border=0 cellpadding=4 cellspacing=0&gt;
</span><del>-    &lt;tr&gt;
-      &lt;th align=&quot;right&quot;&gt;Classification:&lt;/th&gt;
-      &lt;td&gt;&lt;input size=64 maxlength=64 name=&quot;classification&quot;&gt;&lt;/td&gt;
-    &lt;/tr&gt;
-    &lt;tr&gt;
-      &lt;th align=&quot;right&quot;&gt;Description:&lt;/th&gt;
-      &lt;td&gt;
-        [% INCLUDE global/textarea.html.tmpl
-          name    = 'description'
-          minrows = 4
-          cols    = 64
-          wrap    = 'virtual'
-        %]
-      &lt;/td&gt;
-    &lt;/tr&gt;
-    &lt;tr&gt;
-      &lt;th align=&quot;right&quot;&gt;&lt;label for=&quot;sortkey&quot;&gt;Sortkey:&lt;/label&gt;&lt;/th&gt;
-      &lt;td&gt;&lt;input id=&quot;sortkey&quot; size=&quot;20&quot; maxlength=&quot;20&quot; name=&quot;sortkey&quot; 
-                 value=&quot;&quot;&gt;&lt;/td&gt;
-    &lt;/tr&gt;
</del><ins>+
+    [% PROCESS &quot;admin/classifications/edit-common.html.tmpl&quot; %]
+
</ins><span class="cx">   &lt;/table&gt;
</span><span class="cx">   &lt;hr&gt;
</span><span class="cx">   &lt;input type=submit value=&quot;Add&quot;&gt;
</span><span class="lines">@@ -51,7 +34,6 @@
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% token FILTER html %]&quot;&gt;
</span><span class="cx"> &lt;/FORM&gt;
</span><span class="cx"> 
</span><del>-&lt;p&gt;Back to the &lt;a href=&quot;./&quot;&gt;main [% terms.bugs %] page&lt;/a&gt;
-or &lt;a href=&quot;editclassifications.cgi&quot;&gt; edit&lt;/a&gt; more classifications.
</del><ins>+[% PROCESS admin/classifications/footer.html.tmpl %] 
</ins><span class="cx"> 
</span><span class="cx"> [% PROCESS global/footer.html.tmpl %] 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminclassificationsdelhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/classifications/del.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/classifications/del.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/classifications/del.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -58,7 +58,6 @@
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% token FILTER html %]&quot;&gt;
</span><span class="cx"> &lt;/form&gt;
</span><span class="cx"> 
</span><del>-&lt;p&gt;Back to the &lt;a href=&quot;./&quot;&gt;main [% terms.bugs %] page&lt;/a&gt;
-or &lt;a href=&quot;editclassifications.cgi&quot;&gt; edit&lt;/a&gt; more classifications.&lt;/p&gt;
</del><ins>+[% PROCESS admin/classifications/footer.html.tmpl %] 
</ins><span class="cx"> 
</span><span class="cx"> [% PROCESS global/footer.html.tmpl %] 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminclassificationseditcommonhtmltmplfromrev173253trunkWebsitesbugswebkitorgtemplateendefaultreportsduplicatessimplehtmltmpl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/template/en/default/admin/classifications/edit-common.html.tmpl (from rev 173253, trunk/Websites/bugs.webkit.org/template/en/default/reports/duplicates-simple.html.tmpl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/classifications/edit-common.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/classifications/edit-common.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,47 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Netscape Communications
+  # Corporation. Portions created by Netscape are
+  # Copyright (C) 1998 Netscape Communications Corporation. All
+  # Rights Reserved.
+  #
+  # Contributor(s): Tiago Rodrigues de Mello &lt;timello@linux.vnet.ibm.com&gt;
+  #%]
+
+[%# INTERFACE:
+  # classification: Bugzilla::Classifiation object.
+  #%]
+
+&lt;tr&gt;
+  &lt;th align=&quot;right&quot;&gt;Classification:&lt;/th&gt;
+  &lt;td&gt;&lt;input size=64 maxlength=64 name=&quot;classification&quot; 
+             value=&quot;[% classification.name FILTER html %]&quot;&gt;&lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+  &lt;th align=&quot;right&quot;&gt;Description:&lt;/th&gt;
+  &lt;td&gt;
+    [% INCLUDE global/textarea.html.tmpl
+      name           = 'description'
+      minrows        = 4
+      cols           = 64
+      defaultcontent = classification.description
+    %]
+  &lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+  &lt;th align=&quot;right&quot;&gt;&lt;label for=&quot;sortkey&quot;&gt;Sortkey:&lt;/label&gt;&lt;/th&gt;
+  &lt;td&gt;&lt;input id=&quot;sortkey&quot; size=&quot;20&quot; maxlength=&quot;20&quot; name=&quot;sortkey&quot;
+             value=&quot;[%- classification.sortkey FILTER html %]&quot;&gt;&lt;/td&gt;
+&lt;/tr&gt;
+
+[% Hook.process('rows') %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminclassificationsedithtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/classifications/edit.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/classifications/edit.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/classifications/edit.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -24,30 +24,12 @@
</span><span class="cx"> 
</span><span class="cx"> &lt;form method=post action=&quot;editclassifications.cgi&quot;&gt;
</span><span class="cx">   &lt;table  border=0 cellpadding=4 cellspacing=0&gt;
</span><del>-    &lt;tr&gt;
-      &lt;th align=&quot;right&quot;&gt;Classification:&lt;/th&gt;
-      &lt;td&gt;&lt;input size=64 maxlength=64 name=&quot;classification&quot; 
-                 value=&quot;[% classification.name FILTER html %]&quot;&gt;&lt;/td&gt;
-    &lt;/tr&gt;
-    &lt;tr&gt;
-      &lt;th align=&quot;right&quot;&gt;Description:&lt;/th&gt;
-      &lt;td&gt;
-        [% INCLUDE global/textarea.html.tmpl
-          name           = 'description'
-          minrows        = 4
-          cols           = 64
-          defaultcontent = classification.description
-        %]
-      &lt;/td&gt;
-    &lt;/tr&gt;
-    &lt;tr&gt;
-      &lt;th align=&quot;right&quot;&gt;&lt;label for=&quot;sortkey&quot;&gt;Sortkey:&lt;/label&gt;&lt;/th&gt;
-      &lt;td&gt;&lt;input id=&quot;sortkey&quot; size=&quot;20&quot; maxlength=&quot;20&quot; name=&quot;sortkey&quot; value=&quot;
-      [%- classification.sortkey FILTER html %]&quot;&gt;&lt;/td&gt;
-    &lt;/tr&gt;
</del><ins>+
+    [% PROCESS &quot;admin/classifications/edit-common.html.tmpl&quot; %]
+
</ins><span class="cx">     &lt;tr valign=top&gt;
</span><span class="cx">       &lt;th align=&quot;right&quot;&gt;
</span><del>-        &lt;a href=&quot;editproducts.cgi?classification=[% classification.name FILTER url_quote %]&quot;&gt;
</del><ins>+        &lt;a href=&quot;editproducts.cgi?classification=[% classification.name FILTER uri %]&quot;&gt;
</ins><span class="cx">         Edit Products&lt;/a&gt;:
</span><span class="cx">       &lt;/th&gt;
</span><span class="cx">       &lt;td&gt;
</span><span class="lines">@@ -80,7 +62,6 @@
</span><span class="cx">   &lt;input type=submit value=&quot;Update&quot;&gt;
</span><span class="cx"> &lt;/form&gt;
</span><span class="cx"> 
</span><del>-&lt;p&gt;Back to the &lt;a href=&quot;./&quot;&gt;main [% terms.bugs %] page&lt;/a&gt;
-or &lt;a href=&quot;editclassifications.cgi&quot;&gt; edit&lt;/a&gt; more classifications.
</del><ins>+[% PROCESS admin/classifications/footer.html.tmpl %] 
</ins><span class="cx"> 
</span><span class="cx"> [% PROCESS global/footer.html.tmpl %] 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminclassificationsfooterhtmltmplfromrev173253trunkWebsitesbugswebkitorgtemplateendefaultattachmentdifffooterhtmltmpl"></a>
<div class="copfile"><h4>Copied: trunk/Websites/bugs.webkit.org/template/en/default/admin/classifications/footer.html.tmpl (from rev 173253, trunk/Websites/bugs.webkit.org/template/en/default/attachment/diff-footer.html.tmpl) (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/classifications/footer.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/classifications/footer.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,24 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Netscape Communications
+  # Corporation. Portions created by Netscape are
+  # Copyright (C) 1998 Netscape Communications Corporation. All
+  # Rights Reserved.
+  #
+  # Contributor(s): Nitish Bezzala &lt;nbezzala@yahoo.com&gt;
+  #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+&lt;p&gt;Back to the &lt;a href=&quot;./&quot;&gt;main [% terms.bugs %] page&lt;/a&gt;
+or &lt;a href=&quot;editclassifications.cgi&quot;&gt; edit&lt;/a&gt; more classifications.&lt;/p&gt;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminclassificationsreclassifyhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/classifications/reclassify.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/classifications/reclassify.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/classifications/reclassify.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -84,8 +84,7 @@
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% token FILTER html %]&quot;&gt;
</span><span class="cx"> &lt;/form&gt;
</span><span class="cx"> 
</span><del>-&lt;p&gt;Back to the &lt;a href=&quot;./&quot;&gt;main [% terms.bugs %] page&lt;/a&gt;,
-or &lt;a href=&quot;editclassifications.cgi&quot;&gt; edit&lt;/a&gt; more classifications.
</del><ins>+[% PROCESS admin/classifications/footer.html.tmpl %]
</ins><span class="cx"> 
</span><span class="cx"> [% PROCESS global/footer.html.tmpl %]
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminclassificationsselecthtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/classifications/select.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/classifications/select.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/classifications/select.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -33,7 +33,7 @@
</span><span class="cx"> 
</span><span class="cx">   [% FOREACH cl = classifications %]
</span><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;td valign=&quot;top&quot;&gt;&lt;a href=&quot;editclassifications.cgi?action=edit&amp;amp;classification=[% cl.name FILTER url_quote %]&quot;&gt;&lt;b&gt;[% cl.name FILTER html %]&lt;/b&gt;&lt;/a&gt;&lt;/td&gt;
</del><ins>+      &lt;td valign=&quot;top&quot;&gt;&lt;a href=&quot;editclassifications.cgi?action=edit&amp;amp;classification=[% cl.name FILTER uri %]&quot;&gt;&lt;b&gt;[% cl.name FILTER html %]&lt;/b&gt;&lt;/a&gt;&lt;/td&gt;
</ins><span class="cx">       &lt;td valign=&quot;top&quot;&gt; 
</span><span class="cx">       [% IF cl.description %]
</span><span class="cx">         [% cl.description FILTER html_light %]
</span><span class="lines">@@ -45,14 +45,14 @@
</span><span class="cx">       [% IF (cl.id == 1) %]
</span><span class="cx">         &lt;td valign=&quot;top&quot;&gt;[% cl.product_count FILTER html %]&lt;/td&gt;
</span><span class="cx">       [% ELSE %]
</span><del>-        &lt;td valign=&quot;top&quot;&gt;&lt;a href=&quot;editclassifications.cgi?action=reclassify&amp;amp;classification=[% cl.name FILTER url_quote %]&quot;&gt;reclassify ([% cl.product_count FILTER html %])&lt;/a&gt;&lt;/td&gt;
</del><ins>+        &lt;td valign=&quot;top&quot;&gt;&lt;a href=&quot;editclassifications.cgi?action=reclassify&amp;amp;classification=[% cl.name FILTER uri %]&quot;&gt;reclassify ([% cl.product_count FILTER html %])&lt;/a&gt;&lt;/td&gt;
</ins><span class="cx">       [% END %]
</span><span class="cx"> 
</span><span class="cx">       [%# don't allow user to delete the default id. %]
</span><span class="cx">       [% IF (cl.id == 1) %]
</span><span class="cx">         &lt;td valign=&quot;top&quot;&gt;&amp;nbsp;&lt;/td&gt;
</span><span class="cx">       [% ELSE %]
</span><del>-        &lt;td valign=&quot;top&quot;&gt;&lt;a href=&quot;editclassifications.cgi?action=del&amp;amp;classification=[% cl.name FILTER url_quote %]&quot;&gt;delete&lt;/a&gt;&lt;/td&gt;
</del><ins>+        &lt;td valign=&quot;top&quot;&gt;&lt;a href=&quot;editclassifications.cgi?action=del&amp;amp;classification=[% cl.name FILTER uri %]&quot;&gt;delete&lt;/a&gt;&lt;/td&gt;
</ins><span class="cx">       [% END %]
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">   [% END %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadmincomponentsconfirmdeletehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/components/confirm-delete.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/components/confirm-delete.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/components/confirm-delete.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -82,16 +82,16 @@
</span><span class="cx"> 
</span><span class="cx"> &lt;/tr&gt;
</span><span class="cx"> &lt;tr&gt;
</span><del>-  &lt;TD VALIGN=&quot;top&quot;&gt;Closed for [% terms.bugs %]:&lt;/TD&gt;
-  &lt;TD VALIGN=&quot;top&quot;&gt;[% IF product.disallow_new %]Yes[% ELSE %]No[% END %]&lt;/td&gt;
</del><ins>+  &lt;TD VALIGN=&quot;top&quot;&gt;Open for [% terms.bugs %]:&lt;/TD&gt;
+  &lt;TD VALIGN=&quot;top&quot;&gt;[% IF product.is_active &amp;&amp; comp.isactive %]Yes[% ELSE %]No[% END %]&lt;/td&gt;
</ins><span class="cx"> &lt;/tr&gt;
</span><span class="cx"> &lt;tr&gt;
</span><span class="cx">   &lt;td valign=&quot;top&quot;&gt;[% terms.Bugs %]:&lt;/td&gt;
</span><span class="cx">   &lt;td valign=&quot;top&quot;&gt;
</span><span class="cx"> [% IF comp.bug_count %]
</span><span class="cx">   &lt;a title=&quot;List of [% terms.bugs %] for component '[% comp.name FILTER html %]'&quot;
</span><del>-     href=&quot;buglist.cgi?component=[% comp.name FILTER url_quote %]&amp;amp;product=
-          [%- product.name FILTER url_quote %]&quot;&gt;[% comp.bug_count %]&lt;/a&gt;
</del><ins>+     href=&quot;buglist.cgi?component=[% comp.name FILTER uri %]&amp;amp;product=
+          [%- product.name FILTER uri %]&quot;&gt;[% comp.bug_count %]&lt;/a&gt;
</ins><span class="cx"> [% ELSE %]
</span><span class="cx">   None
</span><span class="cx"> [% END %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadmincomponentscreatehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/components/create.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/components/create.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/components/create.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -26,70 +26,16 @@
</span><span class="cx">   
</span><span class="cx"> [% title = BLOCK %]Add component to the [% product.name FILTER html %] product[% END %]
</span><span class="cx"> [% PROCESS global/header.html.tmpl
</span><ins>+  yui = [ 'autocomplete' ]
+  javascript_urls = [ &quot;js/field.js&quot; ]
</ins><span class="cx">   title = title
</span><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> &lt;form method=&quot;post&quot; action=&quot;editcomponents.cgi&quot;&gt;
</span><span class="cx">   &lt;table border=&quot;0&quot; cellpadding=&quot;4&quot; cellspacing=&quot;0&quot;&gt;
</span><del>-    &lt;tr&gt;
-      &lt;th align=&quot;right&quot;&gt;Component:&lt;/th&gt;
-      &lt;td&gt;&lt;input size=&quot;64&quot; maxlength=&quot;64&quot; name=&quot;component&quot; value=&quot;&quot;&gt;&lt;/td&gt;
-    &lt;/tr&gt;
-    &lt;tr&gt;
-      &lt;th align=&quot;right&quot;&gt;Description:&lt;/th&gt;
-      &lt;td&gt;
-        [% INCLUDE global/textarea.html.tmpl
-          name    = 'description'
-          minrows = 4
-          cols    = 64
-          wrap    = 'virtual'
-        %]
-      &lt;/td&gt;
-    &lt;/tr&gt;
-    &lt;tr&gt;
-      &lt;th align=&quot;right&quot;&gt;&lt;label for=&quot;initialowner&quot;&gt;Default Assignee:&lt;/label&gt;&lt;/th&gt;
-      &lt;td&gt;
-        [% INCLUDE global/userselect.html.tmpl
-           name =&gt; &quot;initialowner&quot;
-           id =&gt; &quot;initialowner&quot;
-           value =&gt; &quot;&quot;
-           size =&gt; 64
-         %]
-      &lt;/td&gt;
-    &lt;/tr&gt;
-[% IF Param('useqacontact') %]
-    &lt;tr&gt;
-      &lt;th align=&quot;right&quot;&gt;
-        &lt;label for=&quot;initialqacontact&quot;&gt;Default QA Contact:&lt;/label&gt;&lt;/th&gt;
-      &lt;td&gt;
-        [% INCLUDE global/userselect.html.tmpl
-           name =&gt; &quot;initialqacontact&quot;
-           id =&gt; &quot;initialqacontact&quot;
-           value =&gt; &quot;&quot;
-           size =&gt; 64
-           emptyok =&gt; 1
-         %]
-      &lt;/td&gt;
-    &lt;/tr&gt;
-[% END %]
-    &lt;tr&gt;
-      &lt;th align=&quot;right&quot;&gt;
-        &lt;label for=&quot;initialcc&quot;&gt;Default CC List:&lt;/label&gt;
-      &lt;/th&gt;
-      &lt;td&gt;
-        [% INCLUDE global/userselect.html.tmpl
-           name =&gt; &quot;initialcc&quot;
-           id =&gt; &quot;initialcc&quot;
-           value =&gt; &quot;&quot;
-           size =&gt; 64
-           multiple =&gt; 5
-        %]
-        &lt;br&gt;
-        [% IF !Param(&quot;usemenuforusers&quot;) %]
-          &lt;em&gt;Enter user names for the CC list as a comma-separated list.&lt;/em&gt;
-        [% END %]
-      &lt;/td&gt;
-    &lt;/tr&gt;
</del><ins>+
+    [% PROCESS &quot;admin/components/edit-common.html.tmpl&quot; %]
+    
</ins><span class="cx">   &lt;/table&gt;
</span><span class="cx">   &lt;hr&gt;
</span><span class="cx">   &lt;input type=&quot;submit&quot; id=&quot;create&quot; value=&quot;Add&quot;&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadmincomponentseditcommonhtmltmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/admin/components/edit-common.html.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/components/edit-common.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/components/edit-common.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,85 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Netscape Communications
+  # Corporation. Portions created by Netscape are
+  # Copyright (C) 1998 Netscape Communications Corporation. All
+  # Rights Reserved.
+  #
+  # Contributor(s): Tiago Rodrigues de Mello &lt;timello@linux.vnet.ibm.com&gt;
+  #%]
+
+[%# INTERFACE:
+  # comp: object; Bugzilla::Component object.
+  #%]
+
+&lt;tr&gt;
+  &lt;th class=&quot;field_label&quot;&gt;&lt;label for=&quot;component&quot;&gt;Component:&lt;/label&gt;&lt;/th&gt;
+  &lt;td&gt;&lt;input size=&quot;64&quot; maxlength=&quot;64&quot; name=&quot;component&quot; id=&quot;component&quot;
+             value=&quot;[%- comp.name FILTER html %]&quot;&gt;&lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+  &lt;th class=&quot;field_label&quot;&gt;&lt;label for=&quot;[% desc_name FILTER html %]&quot;&gt;Component Description:&lt;/label&gt;&lt;/th&gt;
+  &lt;td&gt;
+    [% INCLUDE global/textarea.html.tmpl
+      name           = 'description'
+      id             = 'description'
+      minrows        = 4
+      cols           = 64
+      wrap           = 'virtual'
+      defaultcontent = comp.description
+    %]
+  &lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+  &lt;th class=&quot;field_label&quot;&gt;&lt;label for=&quot;initialowner&quot;&gt;Default Assignee:&lt;/label&gt;&lt;/th&gt;
+  &lt;td&gt;
+    [% INCLUDE global/userselect.html.tmpl
+       name =&gt; &quot;initialowner&quot;
+       id =&gt; &quot;initialowner&quot;
+       value =&gt; comp.default_assignee.login
+       size =&gt; 64
+     %]
+  &lt;/td&gt;
+&lt;/tr&gt;
+[% IF Param('useqacontact') %]
+  &lt;tr&gt;
+    &lt;th class=&quot;field_label&quot;&gt;&lt;label for=&quot;initialqacontact&quot;&gt;Default QA contact:&lt;/label&gt;&lt;/th&gt;
+    &lt;td&gt;
+      [% INCLUDE global/userselect.html.tmpl
+         name =&gt; &quot;initialqacontact&quot;
+         id =&gt; &quot;initialqacontact&quot;
+         value =&gt; comp.default_qa_contact.login
+         size =&gt; 64
+         emptyok =&gt; 1
+       %]
+    &lt;/td&gt;
+  &lt;/tr&gt;
+[% END %]
+&lt;tr&gt;
+  &lt;th class=&quot;field_label&quot;&gt;&lt;label for=&quot;initialcc&quot;&gt;Default CC List:&lt;/label&gt;&lt;/th&gt;
+  &lt;td&gt;
+    [% INCLUDE global/userselect.html.tmpl
+       name     =&gt; &quot;initialcc&quot;
+       id       =&gt; &quot;initialcc&quot;
+       value    =&gt; initial_cc_names
+       size     =&gt; 64
+       multiple =&gt; 5
+    %]
+    &lt;br&gt;
+    [% IF !Param(&quot;usemenuforusers&quot;) %]
+      &lt;em&gt;Enter user names for the CC list as a comma-separated list.&lt;/em&gt;
+    [% END %]
+  &lt;/td&gt;
+&lt;/tr&gt;
+
+[% Hook.process('rows') %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadmincomponentsedithtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/components/edit.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/components/edit.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/components/edit.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -33,81 +33,28 @@
</span><span class="cx"> [% END %]
</span><span class="cx"> [% PROCESS global/header.html.tmpl
</span><span class="cx">   title = title
</span><ins>+  yui = [ 'autocomplete' ]
+  javascript_urls = [ &quot;js/field.js&quot; ]
</ins><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> &lt;form method=&quot;post&quot; action=&quot;editcomponents.cgi&quot;&gt;
</span><span class="cx">   &lt;table border=&quot;0&quot; cellpadding=&quot;4&quot; cellspacing=&quot;0&quot;&gt;
</span><span class="cx"> 
</span><ins>+    [% PROCESS &quot;admin/components/edit-common.html.tmpl&quot; %]
+
</ins><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;td valign=&quot;top&quot;&gt;Component:&lt;/td&gt;
-      &lt;td&gt;&lt;input size=&quot;64&quot; maxlength=&quot;64&quot; name=&quot;component&quot; value=&quot;
-      [%- comp.name FILTER html %]&quot;&gt;&lt;/td&gt;
</del><ins>+      &lt;th class=&quot;field_label&quot;&gt;&lt;label for=&quot;isactive&quot;&gt;Enabled For [% terms.Bugs %]:&lt;/label&gt;&lt;/th&gt;
+      &lt;td&gt;&lt;input id=&quot;isactive&quot; name=&quot;isactive&quot; type=&quot;checkbox&quot; value=&quot;1&quot; 
+                 [% 'checked=&quot;checked&quot;' IF comp.isactive %]&gt;&lt;/td&gt;
</ins><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;td valign=&quot;top&quot;&gt;Component Description:&lt;/td&gt;
</del><ins>+      &lt;th class=&quot;field_label&quot;&gt;[% terms.Bugs %]:&lt;/th&gt;
</ins><span class="cx">       &lt;td&gt;
</span><del>-        [% INCLUDE global/textarea.html.tmpl
-          name           = 'description'
-          minrows        = 4
-          cols           = 64
-          wrap           = 'virtual'
-          defaultcontent = comp.description
-        %]
-      &lt;/td&gt;
-    &lt;/tr&gt;
-    &lt;tr&gt;
-      &lt;td valign=&quot;top&quot;&gt;&lt;label for=&quot;initialowner&quot;&gt;Default Assignee:&lt;/label&gt;&lt;/td&gt;
-      &lt;td&gt;
-        [% INCLUDE global/userselect.html.tmpl
-           name =&gt; &quot;initialowner&quot;
-           id =&gt; &quot;initialowner&quot;
-           value =&gt; comp.default_assignee.login
-           size =&gt; 64
-         %]
-      &lt;/td&gt;
-  
-[% IF Param('useqacontact') %]
-    &lt;/tr&gt;
-    &lt;tr&gt;
-      &lt;td valign=&quot;top&quot;&gt;&lt;label for=&quot;initialqacontact&quot;&gt;Default QA contact:&lt;/label&gt;&lt;/td&gt;
-      &lt;td&gt;
-        [% INCLUDE global/userselect.html.tmpl
-           name =&gt; &quot;initialqacontact&quot;
-           id =&gt; &quot;initialqacontact&quot;
-           value =&gt; comp.default_qa_contact.login
-           size =&gt; 64
-           emptyok =&gt; 1
-         %]
-      &lt;/td&gt;
-[% END %]
-  
-    &lt;/tr&gt;
-    &lt;tr&gt;
-      &lt;td valign=&quot;top&quot;&gt;
-        &lt;label for=&quot;initialcc&quot;&gt;Default CC List:&lt;/label&gt;
-      &lt;/td&gt;
-      &lt;td&gt;
-        [% INCLUDE global/userselect.html.tmpl
-           name     =&gt; &quot;initialcc&quot;
-           id       =&gt; &quot;initialcc&quot;
-           value    =&gt; initial_cc_names
-           size     =&gt; 64
-           multiple =&gt; 5
-        %]
-        &lt;br&gt;
-        [% IF !Param(&quot;usemenuforusers&quot;) %]
-          &lt;em&gt;Enter user names for the CC list as a comma-separated list.&lt;/em&gt;
-        [% END %]
-      &lt;/td&gt;
-    &lt;/tr&gt;
-    &lt;tr&gt;
-      &lt;td&gt;[% terms.Bugs %]:&lt;/td&gt;
-      &lt;td&gt;
</del><span class="cx"> [% IF comp.bug_count &gt; 0 %]
</span><span class="cx">         &lt;a title=&quot;[% terms.Bugs %] in component '[% comp.name FILTER html %]'&quot;
</span><span class="cx">            href=&quot;buglist.cgi?component=
</span><del>-                [%- comp.name FILTER url_quote %]&amp;amp;product=
-                [%- product.name FILTER url_quote %]&quot;&gt;[% comp.bug_count %]&lt;/a&gt;
</del><ins>+                [%- comp.name FILTER uri %]&amp;amp;product=
+                [%- product.name FILTER uri %]&quot;&gt;[% comp.bug_count %]&lt;/a&gt;
</ins><span class="cx"> [% ELSE %]
</span><span class="cx">         None
</span><span class="cx"> [% END %]
</span><span class="lines">@@ -122,8 +69,8 @@
</span><span class="cx">    &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% token FILTER html %]&quot;&gt;
</span><span class="cx">    &lt;input type=&quot;submit&quot; value=&quot;Save Changes&quot; id=&quot;update&quot;&gt; or &lt;a 
</span><span class="cx">         href=&quot;editcomponents.cgi?action=del&amp;amp;product=
</span><del>-        [%- product.name FILTER url_quote %]&amp;amp;component=
-        [%- comp.name FILTER url_quote %]&quot;&gt;Delete&lt;/a&gt; this component.
</del><ins>+        [%- product.name FILTER uri %]&amp;amp;component=
+        [%- comp.name FILTER uri %]&quot;&gt;Delete&lt;/a&gt; this component.
</ins><span class="cx"> 
</span><span class="cx"> &lt;/form&gt;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadmincomponentsfooterhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/components/footer.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/components/footer.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/components/footer.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -33,7 +33,7 @@
</span><span class="cx">   component &lt;a 
</span><span class="cx">   title=&quot;Edit Component '[% comp.name FILTER html %]'&quot;
</span><span class="cx">   href=&quot;editcomponents.cgi?action=edit&amp;amp;product=
</span><del>-  [%- product.name FILTER url_quote %]&amp;amp;component=[% comp.name FILTER url_quote %]&quot;&gt;
</del><ins>+  [%- product.name FILTER uri %]&amp;amp;component=[% comp.name FILTER uri %]&quot;&gt;
</ins><span class="cx">    '[% comp.name FILTER html %]'&lt;/a&gt; 
</span><span class="cx">   or edit
</span><span class="cx"> [% END %]
</span><span class="lines">@@ -42,13 +42,13 @@
</span><span class="cx"> other components of product &lt;a 
</span><span class="cx">   title=&quot;Choose a component from product '[% product.name FILTER html %]' to edit&quot;
</span><span class="cx">   href=&quot;editcomponents.cgi?product=
</span><del>-  [%- product.name FILTER url_quote %]&quot;&gt;'[% product.name FILTER html %]'&lt;/a&gt;, 
</del><ins>+  [%- product.name FILTER uri %]&quot;&gt;'[% product.name FILTER html %]'&lt;/a&gt;, 
</ins><span class="cx">   or edit 
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> product &lt;a 
</span><span class="cx">   title=&quot;Edit Product '[% product.name FILTER html %]'&quot;
</span><span class="cx">   href=&quot;editproducts.cgi?action=edit&amp;amp;product=
</span><del>-  [%- product.name FILTER url_quote %]&quot;&gt;'[% product.name FILTER html %]'&lt;/a&gt;.
</del><ins>+  [%- product.name FILTER uri %]&quot;&gt;'[% product.name FILTER html %]'&lt;/a&gt;.
</ins><span class="cx"> 
</span><span class="cx"> &lt;/p&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadmincomponentslisthtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/components/list.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/components/list.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/components/list.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -34,11 +34,11 @@
</span><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> [% edit_contentlink = BLOCK %]editcomponents.cgi?action=edit&amp;amp;product=
</span><del>-  [%- product.name FILTER url_quote %]&amp;amp;component=%%name%%[% END %]
</del><ins>+  [%- product.name FILTER uri %]&amp;amp;component=%%name%%[% END %]
</ins><span class="cx"> [% delete_contentlink = BLOCK %]editcomponents.cgi?action=del&amp;amp;product=
</span><del>-  [%- product.name FILTER url_quote %]&amp;amp;component=%%name%%[% END %]
</del><ins>+  [%- product.name FILTER uri %]&amp;amp;component=%%name%%[% END %]
</ins><span class="cx"> [% bug_count_contentlink = BLOCK %]buglist.cgi?component=%%name%%&amp;amp;product=
</span><del>-  [%- product.name FILTER url_quote %][% END %]
</del><ins>+  [%- product.name FILTER uri %][% END %]
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> [% columns = [
</span><span class="lines">@@ -56,6 +56,11 @@
</span><span class="cx">        name =&gt; &quot;initialowner&quot;
</span><span class="cx">        heading =&gt; &quot;Default Assignee&quot;
</span><span class="cx">      },
</span><ins>+     {
+       name =&gt; &quot;isactive&quot;
+       heading =&gt; &quot;Active&quot;
+       yesno_field =&gt; 1
+     },
</ins><span class="cx">    ]
</span><span class="cx"> %]
</span><span class="cx"> 
</span><span class="lines">@@ -86,38 +91,37 @@
</span><span class="cx">    }) %]
</span><span class="cx"> 
</span><span class="cx"> [%# Overrides the initialowner and the initialqacontact with right values %]
</span><del>-[% overrides.initialowner = [] %]
-[% overrides.initialqacontact = [] %]
</del><ins>+[% overrides.initialowner = {} %]
+[% overrides.initialqacontact = {} %]
</ins><span class="cx"> 
</span><del>-[% FOREACH component = product.components %]
-  [% overrides.initialowner.push({
-       match_value =&gt; component.name
-       match_field =&gt; 'name'
</del><ins>+[%# &quot;component&quot; is a reserved word in Template Toolkit. %]
+[% FOREACH my_component = product.components %]
+  [% overrides.initialowner.name.${my_component.name} = {
</ins><span class="cx">        override_content =&gt; 1
</span><del>-       content =&gt; component.default_assignee.login
-     })
</del><ins>+       content =&gt; my_component.default_assignee.login
+     }
</ins><span class="cx">   %]
</span><del>-  [% overrides.initialqacontact.push({
-       match_value =&gt; component.name
-       match_field =&gt; 'name'
</del><ins>+  [% overrides.initialqacontact.name.${my_component.name} = {
</ins><span class="cx">        override_content =&gt; 1
</span><del>-       content =&gt; component.default_qa_contact.login
-     })
</del><ins>+       content =&gt; my_component.default_qa_contact.login
+     }
</ins><span class="cx">   %]
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><ins>+[% Hook.process('before_table') %]
+
</ins><span class="cx"> [% PROCESS admin/table.html.tmpl
</span><span class="cx">      columns = columns
</span><span class="cx">      data = product.components
</span><span class="cx">      overrides = overrides
</span><span class="cx"> %]
</span><span class="cx"> 
</span><del>-&lt;p&gt;&lt;a href=&quot;editcomponents.cgi?action=add&amp;amp;product=[% product.name FILTER url_quote %]&quot;&gt;Add&lt;/a&gt;
</del><ins>+&lt;p&gt;&lt;a href=&quot;editcomponents.cgi?action=add&amp;amp;product=[% product.name FILTER uri %]&quot;&gt;Add&lt;/a&gt;
</ins><span class="cx">     a new component to product '[% product.name FILTER html %]'&lt;/p&gt;
</span><span class="cx"> 
</span><span class="cx"> [% IF ! showbugcounts %]
</span><span class="cx"> 
</span><del>-  &lt;p&gt;&lt;a href=&quot;editcomponents.cgi?product=[% product.name FILTER url_quote %]&amp;amp;showbugcounts=1&quot;&gt;
</del><ins>+  &lt;p&gt;&lt;a href=&quot;editcomponents.cgi?product=[% product.name FILTER uri %]&amp;amp;showbugcounts=1&quot;&gt;
</ins><span class="cx">       Redisplay table with [% terms.bug %] counts (slower)&lt;/a&gt;&lt;/p&gt;
</span><span class="cx"> 
</span><span class="cx"> [% END %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadmincustom_fieldscfjsjstmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/admin/custom_fields/cf-js.js.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/custom_fields/cf-js.js.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/custom_fields/cf-js.js.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,77 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is NASA.
+  # Portions created by NASA are Copyright (C) 2008 
+  # San Jose State University Foundation. All Rights Reserved.
+  #
+  # Contributor(s): Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+// Disable a checkbox based on the state of another one.
+function toggleCheckbox(this_checkbox, other_checkbox_id) {
+    var other_checkbox = document.getElementById(other_checkbox_id);
+    other_checkbox.disabled = !this_checkbox.checked;
+}
+
+var select_values = new Array();
+[% USE Bugzilla %]
+[% FOREACH sel_field = Bugzilla.fields({ is_select =&gt; 1 }) %]
+  select_values[[% sel_field.id FILTER js %]] = [
+  [% FOREACH legal_value = sel_field.legal_values %]
+    [%# Prefix components with the name of their product so that admins
+        know which component we're talking about. #%]
+    [% IF sel_field.name == 'component' %]
+      [% SET value_name = display_value('product', legal_value.product.name) _ ': '
+                          _ display_value(sel_field.name, legal_value.name) %]
+    [% ELSE %]
+      [% SET value_name = display_value(sel_field.name, legal_value.name) %]
+    [% END %]
+    [[% legal_value.id FILTER js %], '[% value_name FILTER js %]'][% ',' UNLESS loop.last %]
+  [% END %]
+  ];
+[% END %]
+
+function onChangeType(type_field) {
+    var value_field = document.getElementById('value_field_id');
+    if (type_field.value == [% constants.FIELD_TYPE_SINGLE_SELECT %]
+        || type_field.value == [% constants.FIELD_TYPE_MULTI_SELECT %])
+    {
+        value_field.disabled = false;
+    }
+    else {
+        value_field.disabled = true;
+    }
+
+   var reverse_desc = document.getElementById('reverse_desc');
+   if (type_field.value == [% constants.FIELD_TYPE_BUG_ID %])
+   {
+       reverse_desc.disabled = false;
+   }
+   else {
+       reverse_desc.disabled = true;
+       reverse_desc.value = '';
+   }
+}
+
+function onChangeVisibilityField() {
+    var vis_field = document.getElementById('visibility_field_id');
+    var vis_value = document.getElementById('visibility_values');
+
+    if (vis_field.value) {
+        var values = select_values[vis_field.value];
+        bz_populateSelectFromArray(vis_value, values);
+    }
+    else {
+        bz_clearOptions(vis_value);
+    }
+}
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadmincustom_fieldscreatehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/custom_fields/create.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/custom_fields/create.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/custom_fields/create.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -19,20 +19,21 @@
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS &quot;global/field-descs.none.tmpl&quot; %]
</span><span class="cx"> 
</span><ins>+[% javascript = BLOCK %]
+  [% INCLUDE &quot;admin/custom_fields/cf-js.js.tmpl&quot; %]
+[% END %]
+
</ins><span class="cx"> [% PROCESS global/header.html.tmpl
</span><span class="cx">            title = &quot;Add a new Custom Field&quot;
</span><span class="cx">            onload = &quot;document.getElementById('new_bugmail').disabled = true;&quot;
</span><ins>+           javascript_urls = [ 'js/util.js' ]
</ins><span class="cx">            doc_section = &quot;custom-fields.html#add-custom-fields&quot;
</span><ins>+           style_urls = ['skins/standard/admin.css']
</ins><span class="cx"> %]
</span><span class="cx"> 
</span><ins>+[%# set initial editability of fields such as Reverse Relationship Description %]
</ins><span class="cx"> &lt;script type=&quot;text/javascript&quot;&gt;
</span><del>-  &lt;!--
-  // Disable a checkbox based on the state of another one.
-  function toggleCheckbox(this_checkbox, other_checkbox_id) {
-    var other_checkbox = document.getElementById(other_checkbox_id);
-    other_checkbox.disabled = !this_checkbox.checked;
-  }
-  //--&gt;
</del><ins>+YAHOO.util.Event.onDOMReady(function() {onChangeType(document.getElementById('type'))});
</ins><span class="cx"> &lt;/script&gt;
</span><span class="cx"> 
</span><span class="cx"> &lt;p&gt;
</span><span class="lines">@@ -53,14 +54,14 @@
</span><span class="cx"> &lt;/ul&gt;
</span><span class="cx"> 
</span><span class="cx"> &lt;form id=&quot;add_field&quot; action=&quot;editfields.cgi&quot; method=&quot;GET&quot;&gt;
</span><del>-  &lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;5&quot;&gt;
</del><ins>+  &lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;5&quot; id=&quot;edit_custom_field&quot;&gt;
</ins><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;th align=&quot;right&quot;&gt;&lt;label for=&quot;name&quot;&gt;Name:&lt;/label&gt;&lt;/th&gt;
</del><ins>+      &lt;th class=&quot;narrow_label&quot;&gt;&lt;label for=&quot;name&quot;&gt;Name:&lt;/label&gt;&lt;/th&gt;
</ins><span class="cx">       &lt;td&gt;
</span><span class="cx">         &lt;input type=&quot;text&quot; id=&quot;name&quot; name=&quot;name&quot; value=&quot;cf_&quot; size=&quot;40&quot; maxlength=&quot;64&quot;&gt;
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx"> 
</span><del>-      &lt;th align=&quot;right&quot;&gt;
</del><ins>+      &lt;th&gt;
</ins><span class="cx">         &lt;label for=&quot;enter_bug&quot;&gt;Can be set on [% terms.bug %] creation:&lt;/label&gt;
</span><span class="cx">       &lt;/th&gt;
</span><span class="cx">       &lt;td&gt;
</span><span class="lines">@@ -69,18 +70,18 @@
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;th align=&quot;right&quot;&gt;&lt;label for=&quot;desc&quot;&gt;Description:&lt;/label&gt;&lt;/th&gt;
</del><ins>+      &lt;th class=&quot;narrow_label&quot;&gt;&lt;label for=&quot;desc&quot;&gt;Description:&lt;/label&gt;&lt;/th&gt;
</ins><span class="cx">       &lt;td&gt;&lt;input type=&quot;text&quot; id=&quot;desc&quot; name=&quot;desc&quot; value=&quot;&quot; size=&quot;40&quot;&gt;&lt;/td&gt;
</span><span class="cx"> 
</span><del>-      &lt;th align=&quot;right&quot;&gt;
</del><ins>+      &lt;th&gt;
</ins><span class="cx">         &lt;label for=&quot;new_bugmail&quot;&gt;Displayed in [% terms.bug %]mail for new [% terms.bugs %]:&lt;/label&gt;
</span><span class="cx">       &lt;/th&gt;
</span><span class="cx">       &lt;td&gt;&lt;input type=&quot;checkbox&quot; id=&quot;new_bugmail&quot; name=&quot;new_bugmail&quot; value=&quot;1&quot;&gt;&lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;th align=&quot;right&quot;&gt;&lt;label for=&quot;type&quot;&gt;Type:&lt;/label&gt;&lt;/th&gt;
</del><ins>+      &lt;th class=&quot;narrow_label&quot;&gt;&lt;label for=&quot;type&quot;&gt;Type:&lt;/label&gt;&lt;/th&gt;
</ins><span class="cx">       &lt;td&gt;
</span><del>-        &lt;select id=&quot;type&quot; name=&quot;type&quot;&gt;
</del><ins>+        &lt;select id=&quot;type&quot; name=&quot;type&quot; onchange=&quot;onChangeType(this)&quot;&gt;
</ins><span class="cx">           [% FOREACH type = field_types.keys %]
</span><span class="cx">             [% NEXT IF type == constants.FIELD_TYPE_UNKNOWN %]
</span><span class="cx">             &lt;option value=&quot;[% type FILTER html %]&quot;&gt;[% field_types.$type FILTER html %]&lt;/option&gt;
</span><span class="lines">@@ -88,18 +89,78 @@
</span><span class="cx">         &lt;/select&gt;
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx"> 
</span><del>-      &lt;th align=&quot;right&quot;&gt;&lt;label for=&quot;obsolete&quot;&gt;Is obsolete:&lt;/label&gt;&lt;/th&gt;
</del><ins>+      &lt;th&gt;&lt;label for=&quot;obsolete&quot;&gt;Is obsolete:&lt;/label&gt;&lt;/th&gt;
</ins><span class="cx">       &lt;td&gt;&lt;input type=&quot;checkbox&quot; id=&quot;obsolete&quot; name=&quot;obsolete&quot; value=&quot;1&quot;&gt;&lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;th align=&quot;right&quot;&gt;&lt;label for=&quot;sortkey&quot;&gt;Sortkey:&lt;/label&gt;&lt;/th&gt;
</del><ins>+      &lt;th class=&quot;narrow_label&quot;&gt;&lt;label for=&quot;sortkey&quot;&gt;Sortkey:&lt;/label&gt;&lt;/th&gt;
</ins><span class="cx">       &lt;td&gt;
</span><span class="cx">         &lt;input type=&quot;text&quot; id=&quot;sortkey&quot; name=&quot;sortkey&quot; size=&quot;6&quot; maxlength=&quot;6&quot;&gt;
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx"> 
</span><del>-      &lt;th&gt;&amp;nbsp;&lt;/th&gt;
-      &lt;td&gt;&amp;nbsp;&lt;/td&gt;
</del><ins>+      &lt;th align=&quot;right&quot;&gt;&lt;label for=&quot;is_mandatory&quot;&gt;Is mandatory:&lt;/label&gt;&lt;/th&gt;
+      &lt;td&gt;&lt;input type=&quot;checkbox&quot; id=&quot;is_mandatory&quot; name=&quot;is_mandatory&quot; value=&quot;1&quot;&gt;&lt;/td&gt;
</ins><span class="cx">     &lt;/tr&gt;
</span><ins>+
+    &lt;tr&gt;
+      &lt;th class=&quot;narrow_label&quot;&gt;
+        &lt;label for=&quot;reverse_desc&quot;&gt;Reverse Relationship Description:&lt;/label&gt;
+      &lt;/th&gt;
+      &lt;td&gt;
+        &lt;input type=&quot;text&quot; id=&quot;reverse_desc&quot; name=&quot;reverse_desc&quot; value=&quot;&quot; size=&quot;40&quot; disabled=&quot;disabled&quot;&gt;
+        &lt;br/&gt;
+        Use this label for the list of [% terms.bugs %] that link to
+        [%+ terms.abug %] with this 
+        [%+ field_types.${constants.FIELD_TYPE_BUG_ID} FILTER html %]
+        field. For example, if the description is &quot;Is a duplicate of&quot;,
+        the reverse description would be &quot;Duplicates of this [% terms.bug %]&quot;.
+        Leave blank to disable the list for this field.
+      &lt;/td&gt;
+      &lt;th&gt;
+        &lt;label for=&quot;visibility_field_id&quot;&gt;Field only appears when:&lt;/label&gt;
+      &lt;/th&gt;
+      &lt;td&gt;
+        &lt;select name=&quot;visibility_field_id&quot; id=&quot;visibility_field_id&quot;
+                onchange=&quot;onChangeVisibilityField()&quot;&gt;
+          &lt;option&gt;&lt;/option&gt;
+          [% FOREACH sel_field = Bugzilla.fields({ is_select =&gt; 1 }) %]
+            &lt;option value=&quot;[% sel_field.id FILTER html %]&quot;&gt;
+              [% sel_field.description FILTER html %]
+              ([% sel_field.name FILTER html %])
+            &lt;/option&gt;
+          [% END %]
+        &lt;/select&gt;
+        &lt;label for=&quot;visibility_values&quot;&gt;
+          &lt;strong&gt;is set to any of:&lt;/strong&gt;
+        &lt;/label&gt;
+        &lt;select multiple=&quot;multiple&quot; size=&quot;5&quot; name=&quot;visibility_values&quot;
+                id=&quot;visibility_values&quot; class=&quot;field_value&quot;&gt;
+          &lt;option value=&quot;&quot;&gt;&lt;/option&gt;
+        &lt;/select&gt;
+      &lt;/td&gt;
+    &lt;/tr&gt;
+
+    &lt;tr&gt;
+      &lt;td colspan=&quot;2&quot;&gt;&amp;nbsp;&lt;/td&gt;
+      &lt;th&gt;
+        &lt;label for=&quot;value_field_id&quot;&gt;
+          Field that controls the values&lt;br&gt;
+          that appear in this field:
+        &lt;/label&gt;
+      &lt;/th&gt;
+
+      &lt;td&gt;
+        &lt;select disabled=&quot;disabled&quot; name=&quot;value_field_id&quot; id=&quot;value_field_id&quot;&gt;
+          &lt;option&gt;&lt;/option&gt;
+          [% FOREACH sel_field = Bugzilla.fields({ is_select =&gt; 1 }) %]
+            &lt;option value=&quot;[% sel_field.id FILTER html %]&quot;&gt;
+              [% sel_field.description FILTER html %]
+              ([% sel_field.name FILTER html %])
+            &lt;/option&gt;
+          [% END %]
+        &lt;/select&gt;
+      &lt;/td&gt;
+    &lt;/tr&gt;
</ins><span class="cx">   &lt;/table&gt;
</span><span class="cx">   &lt;p&gt;
</span><span class="cx">     &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;new&quot;&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadmincustom_fieldsedithtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/custom_fields/edit.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/custom_fields/edit.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/custom_fields/edit.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -14,7 +14,7 @@
</span><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [%# INTERFACE:
</span><del>-  # none
</del><ins>+  # field: Bugzila::Field; the current field being edited
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS &quot;global/field-descs.none.tmpl&quot; %]
</span><span class="lines">@@ -23,34 +23,30 @@
</span><span class="cx">   Edit the Custom Field '[% field.name FILTER html %]' ([% field.description FILTER html %])
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><ins>+[% javascript = BLOCK %]
+  [% INCLUDE &quot;admin/custom_fields/cf-js.js.tmpl&quot; %]
+[% END %]
+
</ins><span class="cx"> [% PROCESS global/header.html.tmpl
</span><span class="cx">            title = title
</span><span class="cx">            onload = &quot;toggleCheckbox(document.getElementById('enter_bug'), 'new_bugmail');&quot;
</span><ins>+           javascript_urls = [ 'js/util.js' ]
</ins><span class="cx">            doc_section = &quot;custom-fields.html#edit-custom-fields&quot;
</span><ins>+           style_urls = ['skins/standard/admin.css']
</ins><span class="cx"> %]
</span><span class="cx"> 
</span><del>-&lt;script type=&quot;text/javascript&quot;&gt;
-  &lt;!--
-  // Disable a checkbox based on the state of another one.
-  function toggleCheckbox(this_checkbox, other_checkbox_id) {
-    var other_checkbox = document.getElementById(other_checkbox_id);
-    other_checkbox.disabled = !this_checkbox.checked;
-  }
-  //--&gt;
-&lt;/script&gt;
-
</del><span class="cx"> &lt;p&gt;
</span><span class="cx">   Descriptions are a very short string describing the field and will be used as
</span><span class="cx">   the label for this field in the user interface.
</span><span class="cx"> &lt;/p&gt;
</span><span class="cx"> 
</span><span class="cx"> &lt;form id=&quot;edit_field&quot; action=&quot;editfields.cgi&quot; method=&quot;GET&quot;&gt;
</span><del>-  &lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;5&quot;&gt;
</del><ins>+  &lt;table border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;5&quot; id=&quot;edit_custom_field&quot;&gt;
</ins><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;th align=&quot;right&quot;&gt;Name:&lt;/th&gt;
</del><ins>+      &lt;th class=&quot;narrow_label&quot;&gt;Name:&lt;/th&gt;
</ins><span class="cx">       &lt;td&gt;[% field.name FILTER html %]&lt;/td&gt;
</span><span class="cx"> 
</span><del>-      &lt;th align=&quot;right&quot;&gt;
</del><ins>+      &lt;th&gt;
</ins><span class="cx">         &lt;label for=&quot;enter_bug&quot;&gt;Can be set on [% terms.bug %] creation:&lt;/label&gt;
</span><span class="cx">       &lt;/th&gt;
</span><span class="cx">       &lt;td&gt;&lt;input type=&quot;checkbox&quot; id=&quot;enter_bug&quot; name=&quot;enter_bug&quot; value=&quot;1&quot;
</span><span class="lines">@@ -58,42 +54,116 @@
</span><span class="cx">                  onchange=&quot;toggleCheckbox(this, 'new_bugmail');&quot;&gt;&lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;th align=&quot;right&quot;&gt;&lt;label for=&quot;desc&quot;&gt;Description:&lt;/label&gt;&lt;/th&gt;
</del><ins>+      &lt;th class=&quot;narrow_label&quot;&gt;&lt;label for=&quot;desc&quot;&gt;Description:&lt;/label&gt;&lt;/th&gt;
</ins><span class="cx">       &lt;td&gt;&lt;input type=&quot;text&quot; id=&quot;desc&quot; name=&quot;desc&quot; size=&quot;40&quot;
</span><span class="cx">                  value=&quot;[% field.description FILTER html %]&quot;&gt;&lt;/td&gt;
</span><span class="cx"> 
</span><del>-      &lt;th align=&quot;right&quot;&gt;
</del><ins>+      &lt;th&gt;
</ins><span class="cx">         &lt;label for=&quot;new_bugmail&quot;&gt;Displayed in [% terms.bug %]mail for new [% terms.bugs %]:&lt;/label&gt;
</span><span class="cx">       &lt;/th&gt;
</span><span class="cx">       &lt;td&gt;&lt;input type=&quot;checkbox&quot; id=&quot;new_bugmail&quot; name=&quot;new_bugmail&quot; value=&quot;1&quot;
</span><span class="cx">                  [%- &quot; checked&quot; IF field.mailhead %]&gt;&lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;th align=&quot;right&quot;&gt;Type:&lt;/th&gt;
</del><ins>+      &lt;th class=&quot;narrow_label&quot;&gt;Type:&lt;/th&gt;
</ins><span class="cx">       &lt;td&gt;[% field_types.${field.type} FILTER html %]&lt;/td&gt;
</span><span class="cx"> 
</span><del>-      &lt;th align=&quot;right&quot;&gt;&lt;label for=&quot;obsolete&quot;&gt;Is obsolete:&lt;/label&gt;&lt;/th&gt;
</del><ins>+      &lt;th&gt;&lt;label for=&quot;obsolete&quot;&gt;Is obsolete:&lt;/label&gt;&lt;/th&gt;
</ins><span class="cx">       &lt;td&gt;&lt;input type=&quot;checkbox&quot; id=&quot;obsolete&quot; name=&quot;obsolete&quot; value=&quot;1&quot;
</span><span class="cx">                  [%- &quot; checked&quot; IF field.obsolete %]&gt;&lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;th align=&quot;right&quot;&gt;&lt;label for=&quot;sortkey&quot;&gt;Sortkey:&lt;/label&gt;&lt;/th&gt;
</del><ins>+      &lt;th class=&quot;narrow_label&quot;&gt;&lt;label for=&quot;sortkey&quot;&gt;Sortkey:&lt;/label&gt;&lt;/th&gt;
</ins><span class="cx">       &lt;td&gt;
</span><span class="cx">         &lt;input type=&quot;text&quot; id=&quot;sortkey&quot; name=&quot;sortkey&quot; size=&quot;6&quot; maxlength=&quot;6&quot;
</span><span class="cx">                value=&quot;[% field.sortkey FILTER html %]&quot;&gt;
</span><span class="cx">       &lt;/td&gt;
</span><del>-
-      &lt;th&gt;&amp;nbsp;&lt;/th&gt;
-      &lt;td&gt;&amp;nbsp;&lt;/td&gt;
</del><ins>+      &lt;th align=&quot;right&quot;&gt;&lt;label for=&quot;is_mandatory&quot;&gt;Is mandatory:&lt;/label&gt;&lt;/th&gt;
+      &lt;td&gt;&lt;input type=&quot;checkbox&quot; id=&quot;is_mandatory&quot; name=&quot;is_mandatory&quot; value=&quot;1&quot;
+                 [%- ' checked=&quot;checked&quot;' IF field.is_mandatory %]&gt;&lt;/td&gt;
</ins><span class="cx">     &lt;/tr&gt;
</span><del>-    [% IF field.type == constants.FIELD_TYPE_SINGLE_SELECT
-          || field.type == constants.FIELD_TYPE_MULTI_SELECT %]
</del><ins>+    &lt;tr&gt;
+      [% IF field.type == constants.FIELD_TYPE_BUG_ID %]
+        &lt;th class=&quot;narrow_label&quot;&gt;
+          &lt;label for=&quot;reverse_desc&quot;&gt;Reverse Relationship Description:&lt;/label&gt;
+        &lt;/th&gt;
+        &lt;td&gt;
+          &lt;input type=&quot;text&quot; id=&quot;reverse_desc&quot; name=&quot;reverse_desc&quot; size=&quot;40&quot;
+                 value=&quot;[% field.reverse_desc FILTER html %]&quot;&gt;
+          &lt;br/&gt;
+          Use this label for the list of [% terms.bugs %] that link to
+          [%+ terms.abug %] with this 
+          [%+ field_types.${constants.FIELD_TYPE_BUG_ID} FILTER html %] field.
+          For example, if the description is &quot;Is a duplicate of&quot;,
+          the reverse description would be &quot;Duplicates of this [% terms.bug %]&quot;.
+          Leave blank to disable the list for this field.
+        &lt;/td&gt;
+      [% ELSE %]
+        &lt;td colspan=&quot;2&quot;&gt;&amp;nbsp;&lt;/td&gt;
+      [% END %]
+      &lt;th&gt;
+        &lt;label for=&quot;visibility_field_id&quot;&gt;Field only appears when:&lt;/label&gt;
+      &lt;/th&gt;
+      &lt;td&gt;
+        &lt;select name=&quot;visibility_field_id&quot; id=&quot;visibility_field_id&quot;
+                onchange=&quot;onChangeVisibilityField()&quot;&gt;
+          &lt;option&gt;&lt;/option&gt;
+          [% FOREACH sel_field = Bugzilla.fields({ is_select =&gt; 1 }) %]
+            [% NEXT IF sel_field.id == field.id %]
+            &lt;option value=&quot;[% sel_field.id FILTER html %]&quot;
+             [% ' selected=&quot;selected&quot;' 
+                IF sel_field.id == field.visibility_field.id %]&gt;
+              [% sel_field.description FILTER html %]
+              ([% sel_field.name FILTER html %])
+            &lt;/option&gt;
+          [% END %]
+        &lt;/select&gt;
+        &lt;label for=&quot;visibility_values&quot;&gt;
+          &lt;strong&gt;is set to any of:&lt;/strong&gt;
+        &lt;/label&gt;
+        &lt;select multiple=&quot;multiple&quot; size=&quot;5&quot; name=&quot;visibility_values&quot; 
+                id=&quot;visibility_values&quot; class=&quot;field_value&quot;&gt;
+          [% FOREACH value = field.visibility_field.legal_values %]
+            &lt;option value=&quot;[% value.id FILTER html %]&quot;
+              [% &quot; selected&quot; IF field.visibility_values.contains(value) %]&gt;
+              [% IF field.visibility_field.name == 'component' %]
+                [% display_value('product', value.product.name) FILTER html %]:
+              [% END %]
+              [%+ display_value(field.visibility_field.name, value.name) FILTER html %]
+            &lt;/option&gt;
+          [% END %]   
+        &lt;/select&gt;
+      &lt;/td&gt;
+    &lt;/tr&gt;
+    [% IF field.is_select %]
</ins><span class="cx">       &lt;tr&gt;
</span><span class="cx">         &lt;th&gt;&amp;nbsp;&lt;/th&gt;
</span><del>-        &lt;td colspan=&quot;3&quot;&gt;
-          &lt;a href=&quot;editvalues.cgi?field=[% field.name FILTER url_quote %]&quot;&gt;Edit
</del><ins>+        &lt;td&gt;
+          &lt;a href=&quot;editvalues.cgi?field=[% field.name FILTER uri %]&quot;&gt;Edit
</ins><span class="cx">             legal values for this field&lt;/a&gt;.
</span><span class="cx">         &lt;/td&gt;
</span><ins>+
+        &lt;th&gt;
+          &lt;label for=&quot;value_field_id&quot;&gt;
+            Field that controls the values&lt;br&gt;
+            that appear in this field:
+          &lt;/label&gt;
+        &lt;/th&gt;
+
+        &lt;td&gt;
+          &lt;select name=&quot;value_field_id&quot; id=&quot;value_field_id&quot;&gt;
+            &lt;option&gt;&lt;/option&gt;
+            [% FOREACH sel_field = Bugzilla.fields({ is_select =&gt; 1 }) %]
+              [% NEXT IF sel_field.id == field.id %]
+              &lt;option value=&quot;[% sel_field.id FILTER html %]&quot;
+               [% ' selected=&quot;selected&quot;' 
+                  IF sel_field.id == field.value_field.id %]&gt;
+                [% sel_field.description FILTER html %]
+                ([% sel_field.name FILTER html %])
+              &lt;/option&gt;
+            [% END %]
+          &lt;/select&gt;
+        &lt;/td&gt;
</ins><span class="cx">       &lt;/tr&gt;
</span><span class="cx">     [% END %]
</span><span class="cx">   &lt;/table&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadmincustom_fieldslisthtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/custom_fields/list.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/custom_fields/list.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/custom_fields/list.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -57,6 +57,10 @@
</span><span class="cx">        heading =&gt; &quot;Is Obsolete&quot;
</span><span class="cx">      },
</span><span class="cx">      {
</span><ins>+       name =&gt; &quot;is_mandatory&quot;
+       heading =&gt; &quot;Is Mandatory&quot;
+     },
+     {
</ins><span class="cx">        name =&gt; &quot;action&quot;
</span><span class="cx">        heading =&gt; &quot;Action&quot;
</span><span class="cx">        content =&gt; &quot;&quot;
</span><span class="lines">@@ -65,30 +69,28 @@
</span><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> [% USE Bugzilla %]
</span><del>-[% custom_fields = Bugzilla.get_fields({ custom =&gt; 1 }) %]
</del><ins>+[% custom_fields = Bugzilla.fields({ custom =&gt; 1 }) %]
</ins><span class="cx"> 
</span><span class="cx"> [%# We want to display the type name of fields, not their type ID. %]
</span><del>-[% overrides.type = [] %]
</del><ins>+[% overrides.type = {} %]
</ins><span class="cx"> 
</span><span class="cx"> [% FOREACH field_type = field_types.keys %]
</span><del>-  [% overrides.type.push({
-       match_value =&gt; field_type
-       match_field =&gt; 'type'
</del><ins>+  [% overrides.type.type.$field_type = {
</ins><span class="cx">        override_content =&gt; 1
</span><del>-       content =&gt; field_types.${field_type}
-    })
</del><ins>+       content =&gt; field_types.$field_type
+    }
</ins><span class="cx">   %]
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-[% overrides.action = [ {
-     match_value =&gt; 1
-     match_field =&gt; 'obsolete'
-     override_content =&gt; 1
-     content =&gt; &quot;Delete&quot;
-     override_contentlink =&gt; 1
-     contentlink =&gt; delete_contentlink
-   } ]
</del><ins>+[% overrides.action.obsolete = {
+     &quot;1&quot; =&gt; {
+       override_content =&gt; 1
+       content =&gt; &quot;Delete&quot;
+       override_contentlink =&gt; 1
+       contentlink =&gt; delete_contentlink
+     }
+   }
</ins><span class="cx"> %] 
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS admin/table.html.tmpl
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminfieldvaluesconfirmdeletehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/fieldvalues/confirm-delete.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/fieldvalues/confirm-delete.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/fieldvalues/confirm-delete.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -14,18 +14,14 @@
</span><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [%# INTERFACE:
</span><del>-  # value: string; The field value being deleted.
-  # bug_count: number; The number of bugs that have this field value.
-  # value_count: number; The number of values left for this field, including
-  #              this value.
</del><ins>+  # value: Bugzilla::Field::Choice; The field value being deleted.
+  # value_count: number; The number of values available for this field.
</ins><span class="cx">   # field: object; the field the value is being deleted from.
</span><del>-  # param_name: string; The name of the parameter (defaultxxx) associated
-  #             with the field.
</del><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [% title = BLOCK %]
</span><del>-  Delete Value '[% value FILTER html %]' from the '[% field.description FILTER html %]'
-  ([% field.name FILTER html %]) field
</del><ins>+  Delete Value '[% value.name FILTER html %]' from the 
+  '[% field.description FILTER html %]' ([% field.name FILTER html %]) field
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/header.html.tmpl
</span><span class="lines">@@ -44,15 +40,18 @@
</span><span class="cx"> &lt;/tr&gt;
</span><span class="cx"> &lt;tr&gt;
</span><span class="cx">   &lt;td valign=&quot;top&quot;&gt;Field Value:&lt;/td&gt;
</span><del>-  &lt;td valign=&quot;top&quot;&gt;[% value FILTER html %]&lt;/td&gt;
</del><ins>+  &lt;td valign=&quot;top&quot;&gt;[% value.name FILTER html %]&lt;/td&gt;
</ins><span class="cx"> &lt;/tr&gt;
</span><span class="cx"> &lt;tr&gt;
</span><span class="cx">   &lt;td valign=&quot;top&quot;&gt;[% terms.Bugs %]:&lt;/td&gt;
</span><span class="cx">   &lt;td valign=&quot;top&quot;&gt;
</span><del>-[% IF bug_count %]
-  &lt;a title=&quot;List of [% terms.bugs %] where '[% field.description FILTER html %]' is '
-            [% value FILTER html %]'&quot;
-     href=&quot;buglist.cgi?[% field.name FILTER url_quote %]=[%- value FILTER url_quote %]&quot;&gt;[% bug_count FILTER html %]&lt;/a&gt;
</del><ins>+[% IF value.bug_count %]
+  &lt;a title=&quot;List of [% terms.bugs %] where '
+            [%- field.description FILTER html %]' is '
+            [%- value.name FILTER html %]'&quot;
+     href=&quot;buglist.cgi?[% field.name FILTER uri %]=
+           [%- value.name FILTER uri %]&quot;&gt;
+   [%- value.bug_count FILTER html %]&lt;/a&gt;
</ins><span class="cx"> [% ELSE %]
</span><span class="cx">   None
</span><span class="cx"> [% END %]
</span><span class="lines">@@ -62,45 +61,83 @@
</span><span class="cx"> 
</span><span class="cx"> &lt;h2&gt;Confirmation&lt;/h2&gt;
</span><span class="cx"> 
</span><del>-[% IF (param_name.defined &amp;&amp; Param(param_name) == value) || bug_count || (value_count == 1) %]
</del><ins>+[% IF value.is_default || value.bug_count || (value_count == 1)
+      || value.controls_visibility_of_fields.size
+      || value.controlled_values_array.size 
+%]
</ins><span class="cx"> 
</span><del>-  &lt;p&gt;Sorry, but the '[% value FILTER html %]' value cannot be deleted
-  from the '[% field.description FILTER html %]' field for the following reason(s):&lt;/p&gt;
</del><ins>+  &lt;p&gt;Sorry, but the '[% value.name FILTER html %]' value cannot be deleted
+    from the '[% field.description FILTER html %]' field for the following 
+    reason(s):&lt;/p&gt;
</ins><span class="cx"> 
</span><span class="cx">   &lt;ul class=&quot;warningmessages&quot;&gt;
</span><del>-    [% IF param_name.defined &amp;&amp; Param(param_name) == value %]
-      &lt;li&gt;'[% value FILTER html %]' is the default value for
-          the '[% field.description FILTER html %]' field.
-          [% IF user.groups.tweakparams %]
-            You first have to &lt;a href=&quot;editparams.cgi?section=bugfields#
-            [%- param_name FILTER url_quote %]&quot;&gt;change the default value&lt;/a&gt; for
-            this field before you can delete this value.
-          [% END %]
</del><ins>+    [% IF value.is_default %]
+      &lt;li&gt;'[% value.name FILTER html %]' is the default value for
+        the '[% field.description FILTER html %]' field.
+        [% IF user.in_group('tweakparams') %]
+          You first have to &lt;a href=&quot;editparams.cgi?section=bugfields&quot;&gt;change
+          the default value&lt;/a&gt; for this field before you can delete
+          this value.
+        [% END %]
+      &lt;/li&gt;
</ins><span class="cx">     [% END %]
</span><span class="cx"> 
</span><del>-    [% IF bug_count %]
-      &lt;li&gt;There
-          [% IF bug_count &gt; 1 %] 
-            are [% bug_count FILTER html %] [%+ terms.bugs %] 
-          [% ELSE %]
-            is 1 [% terms.bug %] 
-          [% END %]
-          with this field value. You must change the field value on
-          &lt;a title=&quot;List of [% terms.bugs %] where '[% field.description FILTER html %]' is '[% value FILTER html %]'&quot;
-             href=&quot;buglist.cgi?[% field.name FILTER url_quote %]=[% value FILTER url_quote %]&quot;&gt;
-            [% IF bug_count &gt; 1 %]
</del><ins>+    [% IF value.bug_count %]
+      &lt;li&gt;
+        [% IF value.bug_count &gt; 1 %]
+          There are [% value.bug_count FILTER html %] [%+ terms.bugs %] 
+          with this field value.
+        [% ELSE %]
+          There is 1 [% terms.bug %] with this field value.
+        [% END %]
+        You must change the field value on
+          &lt;a title=&quot;List of [% terms.bugs %] where '
+                    [%- field.description FILTER html %]' is '
+                    [%- value.name FILTER html %]'&quot;
+             href=&quot;buglist.cgi?[% field.name FILTER uri %]=
+                   [%- value.name FILTER uri %]&quot;&gt;
+            [% IF value.bug_count &gt; 1 %]
</ins><span class="cx">               those [% terms.bugs %] 
</span><span class="cx">             [% ELSE %]
</span><span class="cx">               that [% terms.bug %]
</span><span class="cx">             [% END %]
</span><span class="cx">           &lt;/a&gt;
</span><span class="cx">           to another value before you can delete this value.
</span><ins>+      &lt;/li&gt;
</ins><span class="cx">     [% END %]
</span><span class="cx"> 
</span><span class="cx">     [% IF value_count == 1 %]
</span><del>-      &lt;li&gt;'[% value FILTER html %]' is the last value for
-          '[%- field.description FILTER html %]', and so it can not be deleted.
</del><ins>+      &lt;li&gt;'[% value.name FILTER html %]' is the last value for
+        '[%- field.description FILTER html %]', and so it can not be deleted.
+      &lt;/li&gt;
</ins><span class="cx">     [% END %]
</span><ins>+
+    [% IF value.controls_visibility_of_fields.size %]
+      &lt;li&gt;This value controls the visibility of the following fields:&lt;br&gt;
+        [% FOREACH field = value.controls_visibility_of_fields %]
+          &lt;a href=&quot;editfields.cgi?action=edit&amp;name=
+                   [%- field.name FILTER uri %]&quot;&gt;
+            [%- field.description FILTER html %] 
+            ([% field.name FILTER html %])&lt;/a&gt;&lt;br&gt;
+        [% END %]
+      &lt;/li&gt;
+    [% END %]
+
+    [% IF value.controlled_values_array.size %]
+      &lt;li&gt;This value controls the visibility of the following values in
+        other fields:&lt;br&gt;
+       [% FOREACH field_name = value.controlled_values.keys %]
+         [% FOREACH controlled = value.controlled_values.${field_name} %]
+           &lt;a href=&quot;editvalues.cgi?action=edit&amp;field=
+                    [%- controlled.field.name FILTER uri %]&amp;value=
+                    [%- controlled.name FILTER uri %]&quot;&gt;
+             [% controlled.field.description FILTER html %]
+             ([% controlled.field.name FILTER html %]):
+             [%+ controlled.name FILTER html %]&lt;/a&gt;&lt;br&gt;
+         [% END %]
+       [% END %]
+      &lt;/li&gt;
+    [% END %]
</ins><span class="cx">   &lt;/ul&gt;
</span><span class="cx"> 
</span><span class="cx"> [% ELSE %]
</span><span class="lines">@@ -111,7 +148,7 @@
</span><span class="cx">     &lt;input type=&quot;submit&quot; value=&quot;Yes, delete&quot; id=&quot;delete&quot;&gt;
</span><span class="cx">     &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;delete&quot;&gt;
</span><span class="cx">     &lt;input type=&quot;hidden&quot; name=&quot;field&quot; value=&quot;[% field.name FILTER html %]&quot;&gt;
</span><del>-    &lt;input type=&quot;hidden&quot; name=&quot;value&quot; value=&quot;[% value FILTER html %]&quot;&gt;
</del><ins>+    &lt;input type=&quot;hidden&quot; name=&quot;value&quot; value=&quot;[% value.name FILTER html %]&quot;&gt;
</ins><span class="cx">     &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% token FILTER html %]&quot;&gt;
</span><span class="cx">   &lt;/form&gt;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminfieldvaluescreatehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/fieldvalues/create.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/fieldvalues/create.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/fieldvalues/create.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -26,26 +26,29 @@
</span><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> &lt;p&gt;
</span><del>-  This page allows you to add a new value for the '[% field.description FILTER html %]' field.
</del><ins>+  This page allows you to add a new value for the 
+  '[% field.description FILTER html %]' field.
</ins><span class="cx"> &lt;/p&gt;
</span><span class="cx"> 
</span><span class="cx"> &lt;form method=&quot;post&quot; action=&quot;editvalues.cgi&quot;&gt;
</span><span class="cx">   &lt;table border=&quot;0&quot; cellpadding=&quot;4&quot; cellspacing=&quot;0&quot;&gt;
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th align=&quot;right&quot;&gt;&lt;label for=&quot;value&quot;&gt;Value:&lt;/label&gt;&lt;/th&gt;
</span><del>-      &lt;td&gt;&lt;input id=&quot;value&quot; size=&quot;30&quot; maxlength=&quot;60&quot; name=&quot;value&quot;
-                 value=&quot;&quot;&gt;&lt;/td&gt;
</del><ins>+      &lt;td&gt;
+        &lt;input id=&quot;value&quot; name=&quot;value&quot; size=&quot;30&quot;
+               maxlength=&quot;[% constants.MAX_FIELD_VALUE_SIZE FILTER none %]&quot;&gt;
+      &lt;/td&gt;
</ins><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th align=&quot;right&quot;&gt;&lt;label for=&quot;sortkey&quot;&gt;Sortkey:&lt;/label&gt;&lt;/th&gt;
</span><del>-      &lt;td&gt;&lt;input id=&quot;sortkey&quot; size=&quot;10&quot; maxlength=&quot;20&quot; name=&quot;sortkey&quot;
-                 value=&quot;&quot;&gt;&lt;/td&gt;
</del><ins>+      &lt;td&gt;&lt;input id=&quot;sortkey&quot; name=&quot;sortkey&quot; size=&quot;6&quot; maxlength=&quot;6&quot;&gt;&lt;/td&gt;
</ins><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     [% IF field.name == &quot;bug_status&quot; %]
</span><span class="cx">       &lt;tr&gt;
</span><span class="cx">         &lt;th align=&quot;right&quot;&gt;&lt;label for=&quot;is_open&quot;&gt;Status Type:&lt;/label&gt;&lt;/th&gt;
</span><span class="cx">         &lt;td&gt;
</span><del>-          &lt;input type=&quot;radio&quot; id=&quot;open_status&quot; name=&quot;is_open&quot; value=&quot;1&quot; checked=&quot;checked&quot;&gt;
</del><ins>+          &lt;input type=&quot;radio&quot; id=&quot;open_status&quot; name=&quot;is_open&quot; value=&quot;1&quot; 
+                 checked=&quot;checked&quot;&gt;
</ins><span class="cx">           &lt;label for=&quot;open_status&quot;&gt;Open&lt;/label&gt;&lt;br&gt;
</span><span class="cx">           &lt;input type=&quot;radio&quot; id=&quot;closed_status&quot; name=&quot;is_open&quot; value=&quot;0&quot;&gt;
</span><span class="cx">           &lt;label for=&quot;closed_status&quot;&gt;Closed (requires a Resolution)&lt;/label&gt;
</span><span class="lines">@@ -59,6 +62,30 @@
</span><span class="cx">         &lt;/td&gt;
</span><span class="cx">       &lt;/tr&gt;
</span><span class="cx">     [% END %]
</span><ins>+    [% IF field.value_field %]
+      &lt;tr&gt;
+        &lt;th align=&quot;right&quot;&gt;
+          &lt;label for=&quot;visibility_value_id&quot;&gt;Only appears when 
+           [%+ field.value_field.description FILTER html %] is set to:
+          &lt;/label&gt;
+        &lt;/th&gt;
+        &lt;td&gt;
+          &lt;select name=&quot;visibility_value_id&quot; id=&quot;visibility_value_id&quot;&gt;
+            &lt;option&gt;&lt;/option&gt;
+            [% FOREACH field_value = field.value_field.legal_values %]
+              [% NEXT IF field_value.name == '' %]
+              &lt;option value=&quot;[% field_value.id FILTER none %]&quot;&gt;
+                [% IF field.value_field.name == 'component' %]
+                  [% field_value.product.name FILTER html %]:
+                [% END %]
+                [%- field_value.name FILTER html -%]
+              &lt;/option&gt;
+            [% END %]
+          &lt;/select&gt;
+          &lt;small&gt;(Leave unset to have this value always appear.)&lt;/small&gt;
+        &lt;/td&gt;
+      &lt;/tr&gt;
+    [% END %]
</ins><span class="cx">   &lt;/table&gt;
</span><span class="cx">   &lt;input type=&quot;submit&quot; id=&quot;create&quot; value=&quot;Add&quot;&gt;
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;new&quot;&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminfieldvaluesedithtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/fieldvalues/edit.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/fieldvalues/edit.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/fieldvalues/edit.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -14,16 +14,15 @@
</span><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [%# INTERFACE:
</span><del>-  # value: string; The field value we are editing.
-  # sortkey: number; Sortkey of the field value we are editing.
-  # field: object; The field this value belongs to.
</del><ins>+  # value: Bugzilla::Field::Choice; The field value we are editing.
+  # field: Bugzilla::Field; The field this value belongs to.
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="cx"> 
</span><span class="cx"> [% title = BLOCK %]
</span><del>-  Edit Value '[% value FILTER html %]' for the '[% field.description FILTER html %]'
-  ([% field.name FILTER html %]) field
</del><ins>+  Edit Value '[% value.name FILTER html %]' for the 
+  '[% field.description FILTER html %]' ([% field.name FILTER html %]) field
</ins><span class="cx"> [% END %]
</span><span class="cx"> [% PROCESS global/header.html.tmpl
</span><span class="cx">   title = title
</span><span class="lines">@@ -33,32 +32,76 @@
</span><span class="cx">   &lt;table border=&quot;0&quot; cellpadding=&quot;4&quot; cellspacing=&quot;0&quot;&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;th valign=&quot;top&quot;&gt;&lt;label for=&quot;value&quot;&gt;Field Value:&lt;/label&gt;&lt;/th&gt;
</del><ins>+      &lt;th valign=&quot;top&quot; align=&quot;right&quot;&gt;
+        &lt;label for=&quot;value_new&quot;&gt;Field Value:&lt;/label&gt;
+      &lt;/th&gt;
</ins><span class="cx">       &lt;td&gt;
</span><del>-        [% IF is_static %]
-          &lt;input type=&quot;hidden&quot; name=&quot;value&quot; value=&quot;[% value FILTER html %]&quot;&gt;
-          [% value FILTER html %]
</del><ins>+        [% IF value.is_static %]
+          &lt;input type=&quot;hidden&quot; name=&quot;value_new&quot; id=&quot;value_new&quot;
+                 value=&quot;[% value.name FILTER html %]&quot;&gt;
+            [%- value.name FILTER html %]
</ins><span class="cx">         [% ELSE %]
</span><del>-          &lt;input id=&quot;value&quot; size=&quot;20&quot; maxlength=&quot;60&quot; name=&quot;value&quot; value=&quot;
-          [%- value FILTER html %]&quot;&gt;
</del><ins>+          &lt;input id=&quot;value_new&quot; name=&quot;value_new&quot; size=&quot;20&quot;
+                 maxlength=&quot;[% constants.MAX_FIELD_VALUE_SIZE FILTER none %]&quot;
+                 value=&quot;[% value.name FILTER html %]&quot;&gt;
</ins><span class="cx">         [% END %]
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th align=&quot;right&quot;&gt;&lt;label for=&quot;sortkey&quot;&gt;Sortkey:&lt;/label&gt;&lt;/th&gt;
</span><del>-      &lt;td&gt;&lt;input id=&quot;sortkey&quot; size=&quot;20&quot; maxlength=&quot;20&quot; name=&quot;sortkey&quot; value=&quot;
-      [%- sortkey FILTER html %]&quot;&gt;&lt;/td&gt;
</del><ins>+      &lt;td&gt;&lt;input id=&quot;sortkey&quot; size=&quot;6&quot; maxlength=&quot;6&quot; name=&quot;sortkey&quot; 
+                 value=&quot;[%- value.sortkey FILTER html %]&quot;&gt;&lt;/td&gt;
</ins><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     [% IF field.name == &quot;bug_status&quot; %]
</span><span class="cx">       &lt;tr&gt;
</span><span class="cx">         &lt;th align=&quot;right&quot;&gt;&lt;label for=&quot;is_open&quot;&gt;Status Type:&lt;/label&gt;&lt;/th&gt;
</span><del>-        &lt;td&gt;[% IF is_open %]Open[% ELSE %]Closed[% END %]&lt;/td&gt;
</del><ins>+        &lt;td&gt;[% IF value.is_open %]Open[% ELSE %]Closed[% END %]&lt;/td&gt;
</ins><span class="cx">       &lt;/tr&gt;
</span><span class="cx">     [% END %]
</span><ins>+    [% IF field.value_field %]
+      &lt;tr&gt;
+        &lt;th align=&quot;right&quot;&gt;
+          &lt;label for=&quot;visibility_value_id&quot;&gt;Only appears when
+           [%+ field.value_field.description FILTER html %] is set to:
+          &lt;/label&gt;
+        &lt;/th&gt;
+        &lt;td&gt;
+          &lt;select name=&quot;visibility_value_id&quot; id=&quot;visibility_value_id&quot;&gt;
+            &lt;option&gt;&lt;/option&gt;
+            [% FOREACH field_value = field.value_field.legal_values %]
+              [% NEXT IF field_value.name == '' %]
+              &lt;option value=&quot;[% field_value.id FILTER none %]&quot;
+               [% ' selected=&quot;selected&quot;' 
+                  IF field_value.id == value.visibility_value.id %]&gt;
+                [% IF field.value_field.name == 'component' %]
+                  [% field_value.product.name FILTER html %]:
+                [% END %]
+                [% field_value.name FILTER html -%]
+              &lt;/option&gt;
+            [% END %]
+          &lt;/select&gt;
+          &lt;small&gt;(Leave unset to have this value always appear.)&lt;/small&gt;
+        &lt;/td&gt;
+      &lt;/tr&gt;
+    [% END %]
+    &lt;tr&gt;
+      &lt;th align=&quot;right&quot;&gt;&lt;label for=&quot;is_active&quot;&gt;Enabled for [% terms.bugs %]:&lt;/label&gt;&lt;/th&gt;
+      &lt;td&gt;&lt;input id=&quot;is_active&quot; name=&quot;is_active&quot; type=&quot;checkbox&quot; value=&quot;1&quot; 
+           [%+ 'checked=&quot;checked&quot;' IF value.is_active %]
+           [%+ 'disabled=&quot;disabled&quot;' IF value.is_default OR value.is_static %]&gt;
+           [% IF value.is_default %]
+             This value is selected as default in the parameters for this field. It cannot be disabled.
+           [% ELSIF value.is_static %]
+             This value is non-deletable and cannot be disabled.
+           [% END %]
+           [% IF !(value.is_default OR value.is_static) %]
+             &lt;input id=&quot;defined_is_active&quot; name=&quot;defined_is_active&quot;
+                    type=&quot;hidden&quot; value=&quot;1&quot;&gt;
+           [% END %]
+      &lt;/td&gt;
+    &lt;/tr&gt;
</ins><span class="cx">   &lt;/table&gt;
</span><del>-
-  &lt;input type=&quot;hidden&quot; name=&quot;valueold&quot; value=&quot;[% value FILTER html %]&quot;&gt;
-  &lt;input type=&quot;hidden&quot; name=&quot;sortkeyold&quot; value=&quot;[% sortkey FILTER html %]&quot;&gt;
</del><ins>+  &lt;input type=&quot;hidden&quot; name=&quot;value&quot; value=&quot;[% value.name FILTER html %]&quot;&gt;
</ins><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;update&quot;&gt;
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;field&quot; value=&quot;[% field.name FILTER html %]&quot;&gt;
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% token FILTER html %]&quot;&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminfieldvaluesfooterhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/fieldvalues/footer.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/fieldvalues/footer.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/fieldvalues/footer.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -32,22 +32,23 @@
</span><span class="cx"> [% UNLESS no_add_link %]
</span><span class="cx">   &lt;a title=&quot;Add a value for the '[% field.description FILTER html %]' field.&quot;
</span><span class="cx">      href=&quot;editvalues.cgi?action=add&amp;amp;field=
</span><del>-          [%- field.name FILTER url_quote %]&quot;&gt;Add&lt;/a&gt; a value.
</del><ins>+          [%- field.name FILTER uri %]&quot;&gt;Add&lt;/a&gt; a value.
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><del>-[% IF value &amp;&amp; !no_edit_link %]
</del><ins>+[% IF value.defined &amp;&amp; !no_edit_link %]
</ins><span class="cx">   Edit value &lt;a 
</span><del>-  title=&quot;Edit value '[% value FILTER html %]' for the '
</del><ins>+  title=&quot;Edit value '[% value.name FILTER html %]' for the '
</ins><span class="cx">          [%- field.name FILTER html %]' field&quot;
</span><span class="cx">   href=&quot;editvalues.cgi?action=edit&amp;amp;field=
</span><del>-        [%- field.name FILTER url_quote %]&amp;amp;value=[% value FILTER url_quote %]&quot;&gt;
-        '[% value FILTER html %]'&lt;/a&gt;.
</del><ins>+        [%- field.name FILTER uri %]&amp;amp;value=
+        [%- value.name FILTER uri %]&quot;&gt;
+        '[% value.name FILTER html %]'&lt;/a&gt;.
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% UNLESS no_edit_other_link %]
</span><span class="cx">   Edit other values for the &lt;a 
</span><span class="cx">   href=&quot;editvalues.cgi?field=
</span><del>-        [%- field.name FILTER url_quote %]&quot;&gt;'[% field.description FILTER html %]'&lt;/a&gt; field.
</del><ins>+        [%- field.name FILTER uri %]&quot;&gt;'[% field.description FILTER html %]'&lt;/a&gt; field.
</ins><span class="cx"> 
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminfieldvalueslisthtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/fieldvalues/list.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/fieldvalues/list.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/fieldvalues/list.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -35,9 +35,9 @@
</span><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> [% edit_contentlink = BLOCK %]editvalues.cgi?action=edit&amp;amp;field=
</span><del>-  [%- field.name FILTER url_quote %]&amp;amp;value=%%name%%[% END %]
</del><ins>+  [%- field.name FILTER uri %]&amp;amp;value=%%name%%[% END %]
</ins><span class="cx"> [% delete_contentlink = BLOCK %]editvalues.cgi?action=del&amp;amp;field=
</span><del>-  [%- field.name FILTER url_quote %]&amp;amp;value=%%name%%[% END %]
</del><ins>+  [%- field.name FILTER uri %]&amp;amp;value=%%name%%[% END %]
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> [% columns = [
</span><span class="lines">@@ -51,6 +51,11 @@
</span><span class="cx">        heading =&gt; &quot;Sortkey&quot;
</span><span class="cx">      },
</span><span class="cx">      {
</span><ins>+       name =&gt; &quot;isactive&quot;
+       heading =&gt; &quot;Enabled for $terms.bugs&quot;
+       yesno_field =&gt; 1
+     },
+     {
</ins><span class="cx">        name =&gt; &quot;action&quot;
</span><span class="cx">        heading =&gt; &quot;Action&quot;
</span><span class="cx">        content =&gt; &quot;Delete&quot;
</span><span class="lines">@@ -58,34 +63,27 @@
</span><span class="cx">      } ]
</span><span class="cx"> %]
</span><span class="cx"> 
</span><del>-[% IF default.defined %]
-  [% overrides.action = [ {
-       match_value =&gt; &quot;$default&quot;
-       match_field =&gt; 'name'
-       override_content =&gt; 1
-       content =&gt; &quot;(Default value)&quot;
-       override_contentlink =&gt; 1
-       contentlink =&gt; undef
-     } ]
-  %]
-[% END %]
</del><span class="cx"> 
</span><del>-[% IF static.size %]
-  [% UNLESS overrides.action.size %]
-    [% overrides.action = [] %]
-  [% END %]
-
-  [% FOREACH static_value = static %]
-    [% overrides.action.push({
-         match_value =&gt; &quot;$static_value&quot;
-         match_field =&gt; 'name'
</del><ins>+[% SET overrides.action = {} %]
+[% FOREACH check_value = values %]
+  [% IF check_value.is_static %]
+    [% overrides.action.name.${check_value.name} = {
</ins><span class="cx">          override_content =&gt; 1
</span><span class="cx">          content =&gt; &quot;(Non-deletable value)&quot;
</span><span class="cx">          override_contentlink =&gt; 1
</span><span class="cx">          contentlink =&gt; undef
</span><del>-       })
</del><ins>+       }
</ins><span class="cx">     %]
</span><ins>+  [% ELSIF check_value.is_default %]
+    [% overrides.action.name.${check_value.name} = {
+         override_content =&gt; 1
+         content =&gt; &quot;(Default value)&quot;
+         override_contentlink =&gt; 1
+         contentlink =&gt; undef
+       }
+    %]
</ins><span class="cx">   [% END %]
</span><ins>+
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS admin/table.html.tmpl
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminflagtypeedithtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/flag-type/edit.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/flag-type/edit.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/flag-type/edit.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -17,26 +17,22 @@
</span><span class="cx">   #
</span><span class="cx">   # Contributor(s): Myk Melez &lt;myk@mozilla.org&gt;
</span><span class="cx">   #                 Mark Bickford &lt;markhb@maine.rr.com&gt;
</span><ins>+  #                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS &quot;global/js-products.html.tmpl&quot; %]
</span><span class="cx"> 
</span><del>-[% IF type.target_type == &quot;bug&quot; %]
-  [% title = BLOCK %]Create Flag Type for [% terms.Bugs %][% END %]
-  [% typeLabelLowerPlural = BLOCK %][% terms.bugs %][% END %]
-  [% typeLabelLowerSingular = BLOCK %][% terms.bug %][% END %]
</del><ins>+[% IF action == &quot;insert&quot; %]
+  [% title = BLOCK %]
+    Create Flag Type for [% type.target_type == &quot;bug&quot; ? terms.Bugs : &quot;Attachments&quot; %]
+    [% IF type.id %]
+      Based on [% type.name FILTER html %]
+    [% END %]
+  [% END %]
+  [% doc_section = &quot;flags-overview.html#flags-create&quot; %]
</ins><span class="cx"> [% ELSE %]
</span><del>-  [% title = &quot;Create Flag Type for Attachments&quot; %]
-  [% typeLabelLowerPlural = BLOCK %]attachments[% END %]
-  [% typeLabelLowerSingular = BLOCK %]attachment[% END %]
-[% END %]
-
-[% doc_section = &quot;flags-overview.html#flags-create&quot; %]
-[% IF last_action == &quot;copy&quot; %]
-  [% title = BLOCK %]Create Flag Type Based on [% type.name FILTER html %][% END %]
-[% ELSIF last_action == &quot;edit&quot; %]
</del><span class="cx">   [% title = BLOCK %]Edit Flag Type [% type.name FILTER html %][% END %]
</span><span class="cx">   [% doc_section = &quot;flags-overview.html#flags-edit&quot; %]
</span><span class="cx"> [% END %]
</span><span class="lines">@@ -47,21 +43,24 @@
</span><span class="cx">     table#form th { text-align: right; vertical-align: baseline; white-space: nowrap; }
</span><span class="cx">     table#form td { text-align: left; vertical-align: baseline; }
</span><span class="cx">   &quot;
</span><del>-  onload=&quot;var f = document.forms[0]; selectProduct(f.product, f.component, null, null, '__Any__');&quot;
</del><ins>+  onload=&quot;var f = document.forms['flagtype_properties'];
+          selectProduct(f.product, f.component, null, null, '__Any__');&quot;
</ins><span class="cx">   javascript_urls=[&quot;js/productform.js&quot;]
</span><span class="cx">   doc_section = doc_section
</span><span class="cx"> %]
</span><span class="cx"> 
</span><del>-&lt;form method=&quot;post&quot; action=&quot;editflagtypes.cgi&quot;&gt;
-  &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;[% action %]&quot;&gt;
</del><ins>+&lt;form id=&quot;flagtype_properties&quot; method=&quot;post&quot; action=&quot;editflagtypes.cgi&quot;&gt;
+  &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;[% action FILTER html %]&quot;&gt;
+  &lt;input type=&quot;hidden&quot; name=&quot;can_fully_edit&quot; value=&quot;[% can_fully_edit FILTER html %]&quot;&gt;
</ins><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;id&quot; value=&quot;[% type.id %]&quot;&gt;
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% token FILTER html %]&quot;&gt;
</span><del>-  &lt;input type=&quot;hidden&quot; name=&quot;target_type&quot; value=&quot;[% type.target_type %]&quot;&gt;
-  [% FOREACH category = type.inclusions %]
-    &lt;input type=&quot;hidden&quot; name=&quot;inclusions&quot; value=&quot;[% category.value FILTER html %]&quot;&gt;
</del><ins>+  &lt;input type=&quot;hidden&quot; name=&quot;target_type&quot; value=&quot;[% type.target_type FILTER html %]&quot;&gt;
+  &lt;input type=&quot;hidden&quot; name=&quot;check_clusions&quot; value=&quot;[% check_clusions FILTER none %]&quot;&gt;
+  [% FOREACH category = inclusions.values %]
+    &lt;input type=&quot;hidden&quot; name=&quot;inclusions&quot; value=&quot;[% category FILTER html %]&quot;&gt;
</ins><span class="cx">   [% END %]
</span><del>-  [% FOREACH category = type.exclusions %]
-    &lt;input type=&quot;hidden&quot; name=&quot;exclusions&quot; value=&quot;[% category.value FILTER html %]&quot;&gt;
</del><ins>+  [% FOREACH category = exclusions.values %]
+    &lt;input type=&quot;hidden&quot; name=&quot;exclusions&quot; value=&quot;[% category FILTER html %]&quot;&gt;
</ins><span class="cx">   [% END %]
</span><span class="cx"> 
</span><span class="cx">   [%# Add a hidden button at the top of the form so that the user pressing &quot;return&quot;
</span><span class="lines">@@ -72,21 +71,22 @@
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th&gt;Name:&lt;/th&gt;
</span><span class="cx">       &lt;td&gt;
</span><del>-        a short name identifying this type&lt;br&gt;
-        &lt;input type=&quot;text&quot; name=&quot;name&quot; value=&quot;[% type.name FILTER html %]&quot;
-               size=&quot;50&quot; maxlength=&quot;50&quot;&gt;
</del><ins>+        a short name identifying this type.&lt;br&gt;
+        &lt;input type=&quot;text&quot; name=&quot;name&quot; value=&quot;[% type.name FILTER html %]&quot; size=&quot;50&quot;
+               maxlength=&quot;50&quot; [%- ' disabled=&quot;disabled&quot;' UNLESS can_fully_edit %]&gt;
</ins><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th&gt;Description:&lt;/th&gt;
</span><span class="cx">       &lt;td&gt;
</span><del>-        a comprehensive description of this type&lt;br&gt;
</del><ins>+        a comprehensive description of this type.&lt;br&gt;
</ins><span class="cx">         [% INCLUDE global/textarea.html.tmpl
</span><span class="cx">           name           = 'description'
</span><span class="cx">           minrows        = 4
</span><span class="cx">           cols           = 80
</span><span class="cx">           defaultcontent = type.description
</span><ins>+          disabled       = !can_fully_edit
</ins><span class="cx">         %]
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="lines">@@ -95,9 +95,15 @@
</span><span class="cx">       &lt;th&gt;Category:&lt;/th&gt;
</span><span class="cx"> 
</span><span class="cx">       &lt;td&gt;
</span><del>-        the products/components to which [% typeLabelLowerPlural %] must
-        (inclusions) or must not (exclusions) belong in order for users
-        to be able to set flags of this type for them
</del><ins>+        the products/components to which [% type.target_type == &quot;bug&quot; ? terms.bugs : &quot;attachments&quot; %]
+        must (inclusions) or must not (exclusions) belong in order for users
+        to be able to set flags of this type for them.
+        [% UNLESS can_fully_edit %]
+          &lt;p class=&quot;warning&quot;&gt;This flagtype also applies to some products you are not allowed
+          to edit (and so which are not displayed in the lists below). Your limited privileges
+          means you are only allowed to add and remove this flagtype to/from products you can
+          edit, but not to edit other properties of the flagtype.&lt;/p&gt;
+        [% END %]
</ins><span class="cx">         &lt;table&gt;
</span><span class="cx">           &lt;tr&gt;
</span><span class="cx">             &lt;td style=&quot;vertical-align: top;&quot;&gt;
</span><span class="lines">@@ -105,31 +111,31 @@
</span><span class="cx">               &lt;select name=&quot;product&quot; onchange=&quot;selectProduct(this, this.form.component, null, null, '__Any__');&quot;&gt;
</span><span class="cx">                 &lt;option value=&quot;&quot;&gt;__Any__&lt;/option&gt;
</span><span class="cx">                 [% FOREACH prod = products %]
</span><del>-                  &lt;option value=&quot;[% prod.name FILTER html %]&quot; 
-                          [% &quot;selected&quot; IF type.product.name == prod.name %]&gt;
-                          [% prod.name FILTER html %]&lt;/option&gt;
</del><ins>+                  &lt;option value=&quot;[% prod.name FILTER html %]&quot;&gt;[% prod.name FILTER html %]&lt;/option&gt;
</ins><span class="cx">                 [% END %]
</span><span class="cx">               &lt;/select&gt;&lt;br&gt;
</span><span class="cx">               &lt;select name=&quot;component&quot;&gt;
</span><span class="cx">                 &lt;option value=&quot;&quot;&gt;__Any__&lt;/option&gt;
</span><span class="cx">                 [% FOREACH comp = components %]
</span><del>-                  &lt;option value=&quot;[% comp FILTER html %]&quot; 
-                          [% &quot;selected&quot; IF type.component.name == comp %]&gt;
-                          [% comp FILTER html %]&lt;/option&gt;
</del><ins>+                  &lt;option value=&quot;[% comp FILTER html %]&quot;&gt;[% comp FILTER html %]&lt;/option&gt;
</ins><span class="cx">                 [% END %]
</span><span class="cx">               &lt;/select&gt;&lt;br&gt;
</span><del>-              &lt;input type=&quot;submit&quot; name=&quot;categoryAction-include&quot; value=&quot;Include&quot;&gt;
-              &lt;input type=&quot;submit&quot; name=&quot;categoryAction-exclude&quot; value=&quot;Exclude&quot;&gt;
</del><ins>+              &lt;input type=&quot;submit&quot; id=&quot;categoryAction-include&quot; 
+                                   name=&quot;categoryAction-include&quot; value=&quot;Include&quot;&gt;
+              &lt;input type=&quot;submit&quot; id=&quot;categoryAction-exclude&quot;
+                                   name=&quot;categoryAction-exclude&quot; value=&quot;Exclude&quot;&gt;
</ins><span class="cx">             &lt;/td&gt;
</span><span class="cx">             &lt;td style=&quot;vertical-align: top;&quot;&gt;
</span><span class="cx">               &lt;b&gt;Inclusions:&lt;/b&gt;&lt;br&gt;
</span><del>-              [% PROCESS &quot;global/select-menu.html.tmpl&quot; name=&quot;inclusion_to_remove&quot; multiple=&quot;1&quot; size=&quot;7&quot; options=type.inclusions %]&lt;br&gt;
-              &lt;input type=&quot;submit&quot; name=&quot;categoryAction-removeInclusion&quot; value=&quot;Remove Inclusion&quot;&gt;
</del><ins>+              [% PROCESS category_select name=&quot;inclusion_to_remove&quot; categories = inclusions %]&lt;br&gt;
+              &lt;input type=&quot;submit&quot; id=&quot;categoryAction-removeInclusion&quot; 
+                     name=&quot;categoryAction-removeInclusion&quot; value=&quot;Remove Inclusion&quot;&gt;
</ins><span class="cx">             &lt;/td&gt;
</span><span class="cx">             &lt;td style=&quot;vertical-align: top;&quot;&gt;
</span><span class="cx">               &lt;b&gt;Exclusions:&lt;/b&gt;&lt;br&gt;
</span><del>-              [% PROCESS &quot;global/select-menu.html.tmpl&quot; name=&quot;exclusion_to_remove&quot; multiple=&quot;1&quot; size=&quot;7&quot; options=type.exclusions %]&lt;br&gt;
-              &lt;input type=&quot;submit&quot; name=&quot;categoryAction-removeExclusion&quot; value=&quot;Remove Exclusion&quot;&gt;
</del><ins>+              [% PROCESS category_select name=&quot;exclusion_to_remove&quot; categories = exclusions %]&lt;br&gt;
+              &lt;input type=&quot;submit&quot; id=&quot;categoryAction-removeExclusion&quot; 
+                     name=&quot;categoryAction-removeExclusion&quot; value=&quot;Remove Exclusion&quot;&gt;
</ins><span class="cx">             &lt;/td&gt;
</span><span class="cx">           &lt;/tr&gt;
</span><span class="cx">         &lt;/table&gt;
</span><span class="lines">@@ -139,11 +145,12 @@
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th&gt;Sort Key:&lt;/th&gt;
</span><span class="cx">       &lt;td&gt;
</span><del>-        a number between 1 and 32767 by which this type will be sorted
-        when displayed to users in a list; ignore if you don't care
-        what order the types appear in or if you want them to appear
-        in alphabetical order&lt;br&gt;
-        &lt;input type=&quot;text&quot; name=&quot;sortkey&quot; value=&quot;[% type.sortkey || 1 %]&quot; size=&quot;5&quot; maxlength=&quot;5&quot;&gt;
</del><ins>+        a number between 1 and [% constants.MAX_SMALLINT FILTER none %] by which
+        this type will be sorted when displayed to users in a list; ignore if you
+        don't care what order the types appear in or if you want them to appear
+        in alphabetical order.&lt;br&gt;
+        &lt;input type=&quot;text&quot; name=&quot;sortkey&quot; value=&quot;[% type.sortkey || 1 %]&quot; size=&quot;5&quot; maxlength=&quot;5&quot;
+               [%- ' disabled=&quot;disabled&quot;' UNLESS can_fully_edit %]&gt;
</ins><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -151,6 +158,7 @@
</span><span class="cx">       &lt;th&gt;&amp;nbsp;&lt;/th&gt;
</span><span class="cx">       &lt;td&gt;
</span><span class="cx">         &lt;input type=&quot;checkbox&quot; id=&quot;is_active&quot; name=&quot;is_active&quot;
</span><ins>+               [%- ' disabled=&quot;disabled&quot;' UNLESS can_fully_edit %]
</ins><span class="cx">                [% &quot; checked&quot; IF type.is_active || !type.is_active.defined %]&gt;
</span><span class="cx">         &lt;label for=&quot;is_active&quot;&gt;active (flags of this type appear in the UI and can be set)&lt;/label&gt;
</span><span class="cx">       &lt;/td&gt;
</span><span class="lines">@@ -160,6 +168,7 @@
</span><span class="cx">       &lt;th&gt;&amp;nbsp;&lt;/th&gt;
</span><span class="cx">       &lt;td&gt;
</span><span class="cx">         &lt;input type=&quot;checkbox&quot; id=&quot;is_requestable&quot; name=&quot;is_requestable&quot;
</span><ins>+               [%- ' disabled=&quot;disabled&quot;' UNLESS can_fully_edit %]
</ins><span class="cx">                [% &quot; checked&quot; IF type.is_requestable || !type.is_requestable.defined %]&gt;
</span><span class="cx">         &lt;label for=&quot;is_requestable&quot;&gt;requestable (users can ask for flags of this type to be set)&lt;/label&gt;
</span><span class="cx">       &lt;/td&gt;
</span><span class="lines">@@ -176,7 +185,8 @@
</span><span class="cx">           &lt;kbd&gt;[% Param('emailsuffix') %]&lt;/kbd&gt; will &lt;em&gt;not&lt;/em&gt; be appended
</span><span class="cx">           to these addresses, so you should add it explicitly if so desired.
</span><span class="cx">         [% END %]&lt;br&gt;
</span><del>-        &lt;input type=&quot;text&quot; name=&quot;cc_list&quot; value=&quot;[% type.cc_list FILTER html %]&quot; size=&quot;80&quot; maxlength=&quot;200&quot;&gt;
</del><ins>+        &lt;input type=&quot;text&quot; name=&quot;cc_list&quot; value=&quot;[% type.cc_list FILTER html %]&quot; size=&quot;80&quot;
+               maxlength=&quot;200&quot; [%- ' disabled=&quot;disabled&quot;' UNLESS can_fully_edit %]&gt;
</ins><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -184,6 +194,7 @@
</span><span class="cx">       &lt;th&gt;&amp;nbsp;&lt;/th&gt;
</span><span class="cx">       &lt;td&gt;
</span><span class="cx">         &lt;input type=&quot;checkbox&quot; id=&quot;is_requesteeble&quot; name=&quot;is_requesteeble&quot;
</span><ins>+               [%- ' disabled=&quot;disabled&quot;' UNLESS can_fully_edit %]
</ins><span class="cx">                [% &quot; checked&quot; IF type.is_requesteeble || !type.is_requesteeble.defined %]&gt;
</span><span class="cx">         &lt;label for=&quot;is_requesteeble&quot;&gt;specifically requestable (users can ask specific other users
</span><span class="cx">           to set flags of this type as opposed to just asking the wind)&lt;/label&gt;
</span><span class="lines">@@ -194,9 +205,10 @@
</span><span class="cx">       &lt;th&gt;&amp;nbsp;&lt;/th&gt;
</span><span class="cx">       &lt;td&gt;
</span><span class="cx">         &lt;input type=&quot;checkbox&quot; id=&quot;is_multiplicable&quot; name=&quot;is_multiplicable&quot;
</span><ins>+               [%- ' disabled=&quot;disabled&quot;' UNLESS can_fully_edit %]
</ins><span class="cx">                [% &quot; checked&quot; IF type.is_multiplicable || !type.is_multiplicable.defined %]&gt;
</span><span class="cx">         &lt;label for=&quot;is_multiplicable&quot;&gt;multiplicable (multiple flags of this type can be set on
</span><del>-          the same [% typeLabelLowerSingular %])&lt;/label&gt;
</del><ins>+          the same [% type.target_type == &quot;bug&quot; ? terms.bug : &quot;attachment&quot; %])&lt;/label&gt;
</ins><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -204,8 +216,8 @@
</span><span class="cx">       &lt;th&gt;Grant Group:&lt;/th&gt;
</span><span class="cx">       &lt;td&gt;
</span><span class="cx">         the group allowed to grant/deny flags of this type
</span><del>-        (to allow all users to grant/deny these flags, select no group)&lt;br&gt;
-        [% PROCESS select selname = &quot;grant_group&quot; %]
</del><ins>+        (to allow all users to grant/deny these flags, select no group).&lt;br&gt;
+        [% PROCESS group_select selname = &quot;grant_group&quot; %]
</ins><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -213,19 +225,16 @@
</span><span class="cx">       &lt;th&gt;Request Group:&lt;/th&gt;
</span><span class="cx">       &lt;td&gt;
</span><span class="cx">         if flags of this type are requestable, the group allowed to request them
</span><del>-        (to allow all users to request these flags, select no group)&lt;br&gt;
</del><ins>+        (to allow all users to request these flags, select no group).&lt;br&gt;
</ins><span class="cx">         Note that the request group alone has no effect if the grant group is not defined!&lt;br&gt;
</span><del>-        [% PROCESS select selname = &quot;request_group&quot; %]
</del><ins>+        [% PROCESS group_select selname = &quot;request_group&quot; %]
</ins><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;th&gt;&lt;/th&gt;
</del><ins>+      &lt;th&gt;&amp;nbsp;&lt;/th&gt;
</ins><span class="cx">       &lt;td&gt;
</span><del>-        &lt;input type=&quot;submit&quot; id=&quot;save&quot; value=&quot;
-          [%- IF (last_action == &quot;enter&quot; || last_action == &quot;copy&quot;) %]Create
-          [%- ELSE %]Save Changes
-          [%- END %]&quot;&gt;
</del><ins>+        &lt;input type=&quot;submit&quot; id=&quot;save&quot; value=&quot;[% action == &quot;insert&quot; ? &quot;Create&quot; : &quot;Save Changes&quot; %]&quot;&gt;
</ins><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -240,14 +249,33 @@
</span><span class="cx"> [%# Block for SELECT fields                                                  #%]
</span><span class="cx"> [%############################################################################%]
</span><span class="cx"> 
</span><del>-[% BLOCK select %]
-  &lt;select name=&quot;[% selname %]&quot; id=&quot;[% selname %]&quot;&gt;
</del><ins>+[% BLOCK group_select %]
+  &lt;select name=&quot;[% selname %]&quot; id=&quot;[% selname %]&quot; [%- ' disabled=&quot;disabled&quot;' UNLESS can_fully_edit %]&gt;
</ins><span class="cx">     &lt;option value=&quot;&quot;&gt;(no group)&lt;/option&gt;
</span><ins>+    [% group_found = 0 %]
</ins><span class="cx">     [% FOREACH group = groups %]
</span><span class="cx">       &lt;option value=&quot;[% group.name FILTER html %]&quot;
</span><del>-        [% &quot; selected&quot; IF (type.${selname} &amp;&amp; type.${selname}.name == group.name) %]&gt;
-      [%- group.name FILTER html %]
</del><ins>+        [% IF type.${selname} &amp;&amp; type.${selname}.name == group.name %]
+          [% ' selected=&quot;selected&quot;' %]
+          [% group_found = 1 %]
+        [% END %]&gt;
+        [%- group.name FILTER html ~%]
</ins><span class="cx">       &lt;/option&gt;
</span><span class="cx">     [% END %]
</span><ins>+    [% IF !group_found &amp;&amp; type.${selname}.name %]
+      &lt;option value=&quot;[% type.${selname}.name FILTER html %]&quot; selected=&quot;selected&quot;&gt;
+        [%- type.${selname}.name FILTER html ~%]
+      &lt;/option&gt;
+    [% END %]
</ins><span class="cx">   &lt;/select&gt;
</span><span class="cx"> [% END %]
</span><ins>+
+[% BLOCK category_select %]
+  &lt;select name=&quot;[% name FILTER html %]&quot; multiple=&quot;multiple&quot; size=&quot;7&quot;&gt;
+    [% FOREACH option = categories.keys.sort %]
+      &lt;option value=&quot;[% categories.$option FILTER html %]&quot;&gt;
+        [% option FILTER html %]
+      &lt;/option&gt;
+    [% END %]
+  &lt;/select&gt;
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminflagtypelisthtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/flag-type/list.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/flag-type/list.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/flag-type/list.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -16,6 +16,7 @@
</span><span class="cx">   # Rights Reserved.
</span><span class="cx">   #
</span><span class="cx">   # Contributor(s): Myk Melez &lt;myk@mozilla.org&gt;
</span><ins>+  #                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="lines">@@ -30,7 +31,7 @@
</span><span class="cx">     .inactive { color: #787878; }
</span><span class="cx">     .multiplicable { display: block; }
</span><span class="cx">   &quot;
</span><del>-  onload=&quot;var f = document.forms[0]; selectProduct(f.product, f.component, null, null, '__All__');&quot;
</del><ins>+  onload=&quot;var f = document.flagtype_form; selectProduct(f.product, f.component, null, null, '__All__');&quot;
</ins><span class="cx">   javascript_urls=[&quot;js/productform.js&quot;]
</span><span class="cx">   doc_section = &quot;flags-overview.html#flag-types&quot;
</span><span class="cx"> %]
</span><span class="lines">@@ -55,7 +56,7 @@
</span><span class="cx">   which are available to at least one component of the product are shown.
</span><span class="cx"> &lt;/p&gt;
</span><span class="cx"> 
</span><del>-&lt;form action=&quot;editflagtypes.cgi&quot; method=&quot;get&quot;&gt;
</del><ins>+&lt;form id=&quot;flagtype_form&quot; name=&quot;flagtype_form&quot; action=&quot;editflagtypes.cgi&quot; method=&quot;get&quot;&gt;
</ins><span class="cx">   &lt;table&gt;
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th&gt;&lt;label for=&quot;product&quot;&gt;Product:&lt;/label&gt;&lt;/th&gt;
</span><span class="lines">@@ -80,6 +81,11 @@
</span><span class="cx">           [% END %]
</span><span class="cx">         &lt;/select&gt;
</span><span class="cx">       &lt;/td&gt;
</span><ins>+      &lt;td&gt;
+        &lt;input type=&quot;checkbox&quot; id=&quot;show_flag_counts&quot; name=&quot;show_flag_counts&quot; value=&quot;1&quot;
+               [%+ 'checked=&quot;checked&quot;' IF show_flag_counts %]&gt;
+        &lt;label for=&quot;show_flag_counts&quot;&gt;Show flag counts&lt;/label&gt;
+      &lt;/td&gt;
</ins><span class="cx">       &lt;td&gt;&lt;input type=&quot;submit&quot; id=&quot;submit&quot; value=&quot;Filter&quot;&gt;&lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">   &lt;/table&gt;
</span><span class="lines">@@ -114,6 +120,11 @@
</span><span class="cx">       &lt;th&gt;Properties&lt;/th&gt;
</span><span class="cx">       &lt;th&gt;Grant group&lt;/th&gt;
</span><span class="cx">       &lt;th&gt;Request group&lt;/th&gt;
</span><ins>+      [% IF show_flag_counts %]
+        &lt;th&gt;Flags&lt;/th&gt;
+        [%# Note to translators: translate the strings in quotes only. %]
+        [% state_desc = {granted = 'granted' denied = 'denied' pending = 'pending'} %]
+      [% END %]
</ins><span class="cx">       &lt;th&gt;Actions&lt;/th&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -136,6 +147,21 @@
</span><span class="cx">         &lt;/td&gt;
</span><span class="cx">         &lt;td&gt;[% IF type.grant_group %][% type.grant_group.name FILTER html %][% END %]&lt;/td&gt;
</span><span class="cx">         &lt;td&gt;[% IF type.request_group %][% type.request_group.name FILTER html %][% END %]&lt;/td&gt;
</span><ins>+        [% IF show_flag_counts %]
+          &lt;td&gt;
+            [% FOREACH state = ['granted', 'pending', 'denied'] %]
+              [% bug_list = bug_lists.${type.id}.$state || [] %]
+              [% IF bug_list.size %]
+                &lt;a href=&quot;buglist.cgi?bug_id=[% bug_list.unique.nsort.join(&quot;,&quot;) FILTER html %]&quot;&gt;
+                  [% bug_list.size FILTER html %] [%+ state_desc.$state FILTER html %]
+                &lt;/a&gt;
+                &lt;br&gt;
+              [% ELSE %]
+                0 [% state_desc.$state FILTER html %]&lt;br&gt;
+              [% END %]
+            [% END %]
+          &lt;/td&gt;
+        [% END %]
</ins><span class="cx">         &lt;td&gt;
</span><span class="cx">           &lt;a href=&quot;editflagtypes.cgi?action=copy&amp;amp;id=[% type.id %]&quot;&gt;Copy&lt;/a&gt;
</span><span class="cx">           | &lt;a href=&quot;editflagtypes.cgi?action=confirmdelete&amp;amp;id=[% type.id %]&quot;&gt;Delete&lt;/a&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadmingroupsconfirmremovehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/groups/confirm-remove.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/groups/confirm-remove.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/groups/confirm-remove.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -59,7 +59,7 @@
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;remove_regexp&quot;&gt;
</span><span class="cx">   
</span><span class="cx">   &lt;input name=&quot;token&quot; type=&quot;hidden&quot; value=&quot;[% token FILTER html %]&quot;&gt;
</span><del>-  &lt;input name=&quot;confirm&quot; type=&quot;submit&quot; value=&quot;Confirm&quot;&gt;
</del><ins>+  &lt;input id=&quot;confirm&quot; name=&quot;confirm&quot; type=&quot;submit&quot; value=&quot;Confirm&quot;&gt;
</ins><span class="cx">   &lt;p&gt;Or &lt;a href=&quot;editgroups.cgi&quot;&gt;return to the Edit Groups page&lt;/a&gt;.&lt;/p&gt;
</span><span class="cx"> &lt;/form&gt;
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadmingroupsdeletehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/groups/delete.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/groups/delete.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/groups/delete.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -19,18 +19,14 @@
</span><span class="cx">   #                 Joel Peshkin &lt;bugreport@peshkin.net&gt;
</span><span class="cx">   #                 Jacob Steenhagen &lt;jake@bugzilla.org&gt;
</span><span class="cx">   #                 Vlad Dascalu &lt;jocuri@softhome.net&gt;
</span><ins>+  #                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [%# INTERFACE:
</span><del>-  # gid: number. The group ID.
-  # name: string. The name of the group.
-  # description: string. The description of the group.
-  # hasusers: boolean int. True if the group includes users in it.
-  # hasbugs: boolean int. True if the group includes bugs in it.
-  # hasproduct: boolean int. True if the group is binded to a product.
-  # hasflags: boolean int. True if the group is used by a flag type.
-  # shared_queries: int. Number of saved searches being shared with this group.
-  # buglist: string. The list of bugs included in this group.
</del><ins>+  # group: A Bugzilla::Group object representing the group that is
+  #        about to be deleted.
+  # shared_queries: int; The number of queries being shared with this
+  #                 group.
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -46,51 +42,107 @@
</span><span class="cx">     &lt;th&gt;Description&lt;/th&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx">   &lt;tr&gt;
</span><del>-    &lt;td&gt;[% gid FILTER html %]&lt;/td&gt;
-    &lt;td&gt;[% name FILTER html %]&lt;/td&gt;
-    &lt;td&gt;[% description FILTER html_light %]&lt;/td&gt;
</del><ins>+    &lt;td&gt;[% group.id FILTER html %]&lt;/td&gt;
+    &lt;td&gt;[% group.name FILTER html %]&lt;/td&gt;
+    &lt;td&gt;[% group.description FILTER html_light %]&lt;/td&gt;
</ins><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> &lt;/table&gt;
</span><span class="cx"> 
</span><span class="cx"> &lt;form method=&quot;post&quot; action=&quot;editgroups.cgi&quot;&gt;
</span><del>-  [% IF hasusers %]
-    &lt;p&gt;&lt;b&gt;One or more users belong to this group. You cannot delete
-    this group while there are users in it.&lt;/b&gt;
</del><ins>+  [% IF group.members_non_inherited.size %]
+    &lt;p&gt;&lt;b&gt;[% group.members_non_inherited.size FILTER html %] users belong
+      directly to this group. You cannot delete this group while there are
+      users in it.&lt;/b&gt;
</ins><span class="cx"> 
</span><del>-    &lt;br&gt;&lt;a href=&quot;editusers.cgi?action=list&amp;groupid=[% gid FILTER html %]&amp;grouprestrict=1&quot;&gt;Show
-    me which users&lt;/a&gt; - &lt;input type=&quot;checkbox&quot; name=&quot;removeusers&quot;&gt;Remove
-    all users from this group for me.&lt;/p&gt;
</del><ins>+    &lt;br&gt;&lt;a href=&quot;editusers.cgi?action=list&amp;amp;groupid=
+                 [%- group.id FILTER uri %]&amp;amp;grouprestrict=1&quot;&gt;Show
+    me which users&lt;/a&gt; - &lt;label&gt;&lt;input type=&quot;checkbox&quot; name=&quot;removeusers&quot;&gt;Remove
+    all users from this group for me.&lt;/label&gt;&lt;/p&gt;
</ins><span class="cx">   [% END %]
</span><span class="cx"> 
</span><del>-  [% IF hasbugs %]
-    &lt;p&gt;&lt;b&gt;One or more [% terms.bug %] reports are visible only to this group.
-    You cannot delete this group while any [% terms.bugs %] are using it.&lt;/b&gt;
</del><ins>+  [% IF group.granted_by_direct(constants.GROUP_MEMBERSHIP).size %]
+    &lt;p&gt;&lt;b&gt;Members of this group inherit membership in the following groups:&lt;/b&gt;&lt;/p&gt;
+    &lt;ul&gt;
+      [% FOREACH grantor = group.granted_by_direct(constants.GROUP_MEMBERSHIP) %]
+        &lt;li&gt;[% grantor.name FILTER html %]&lt;/li&gt;
+      [% END %]
+    &lt;/ul&gt;
+  [% END %]
</ins><span class="cx"> 
</span><del>-    &lt;br&gt;&lt;a href=&quot;buglist.cgi?bug_id=[% buglist FILTER html %]&quot;&gt;Show me
-    which [% terms.bugs %]&lt;/a&gt; - &lt;input type=&quot;checkbox&quot; name=&quot;removebugs&quot;&gt;Remove
-    all [% terms.bugs %] from this group restriction for me.&lt;/p&gt;
</del><ins>+  [% IF group.bugs.size %]
+    &lt;p&gt;&lt;b&gt;[% group.bugs.size FILTER html %] [%+ terms.bug %] reports are
+     visible only to this group. You cannot delete this group while any 
+     [%+ terms.bugs %] are using it.&lt;/b&gt;
</ins><span class="cx"> 
</span><ins>+    &lt;br&gt;&lt;a href=&quot;buglist.cgi?field0-0-0=bug_group&amp;amp;type0-0-0=equals&amp;amp;value0-0-0=
+                 [%- group.name FILTER uri %]&quot;&gt;Show me
+    which [% terms.bugs %]&lt;/a&gt; - 
+    &lt;label&gt;&lt;input type=&quot;checkbox&quot; name=&quot;removebugs&quot;&gt;Remove
+    all [% terms.bugs %] from this group restriction for me.&lt;/label&gt;&lt;/p&gt;
+
</ins><span class="cx">     &lt;p&gt;&lt;b&gt;NOTE:&lt;/b&gt; It's quite possible to make confidential [% terms.bugs %]
</span><span class="cx">     public by checking this box.  It is &lt;B&gt;strongly&lt;/B&gt; suggested
</span><span class="cx">     that you review the [% terms.bugs %] in this group before checking
</span><span class="cx">     the box.&lt;/p&gt;
</span><span class="cx">   [% END %]
</span><span class="cx"> 
</span><del>-  [% IF hasproduct %]
-    &lt;p&gt;&lt;b&gt;This group is tied to the &lt;U&gt;[% name FILTER html %]&lt;/U&gt; product.
-    You cannot delete this group while it is tied to a product.&lt;/b&gt;
</del><ins>+  [% IF group.products.size %]
+    &lt;p&gt;&lt;b&gt;This group is tied to the following products:&lt;/b&gt;&lt;/p&gt;
+    [% SET any_hidden = 0 %]
+    &lt;ul&gt;
+      [% FOREACH data = group.products %]
</ins><span class="cx"> 
</span><del>-    &lt;br&gt;&lt;input type=&quot;checkbox&quot; name=&quot;unbind&quot;&gt;Delete this group anyway,
-    and make the product &lt;U&gt;[% name FILTER html %]&lt;/U&gt; publicly visible.&lt;/p&gt;
</del><ins>+        [% SET active = [] %]
+        [% FOREACH control = data.controls.keys.sort %]
+          [% NEXT IF !data.controls.$control %]
+          [% IF control == 'othercontrol' OR control == 'membercontrol' %]
+            [% SWITCH data.controls.$control %]
+              [% CASE constants.CONTROLMAPMANDATORY %]
+                [% SET type = &quot;Mandatory&quot; %]
+              [% CASE constants.CONTROLMAPSHOWN %]
+                [% SET type = &quot;Shown&quot; %]
+              [% CASE constants.CONTROLMAPDEFAULT %]
+                [% SET type = &quot;Default&quot; %]
+            [% END %]
+            [% active.push(&quot;$control: $type&quot;) %]
+          [% ELSE %]
+            [% active.push(control) %]
+          [% END %]
+        [% END %]
+
+        [% SET hidden = 0 %]
+        [% IF data.controls.othercontrol == constants.CONTROLMAPMANDATORY
+              AND data.controls.membercontrol == constants.CONTROLMAPMANDATORY
+              AND data.controls.entry 
+        %]
+          [% SET hidden = 1 %]
+        [% END %]
+
+        &lt;li&gt;&lt;a href=&quot;editproducts.cgi?action=editgroupcontrols&amp;amp;product=
+                    [%- data.product.name FILTER uri %]&quot;&gt;
+          [%- data.product.name FILTER html %]&lt;/a&gt;
+          ([% active.join(', ') FILTER html %])
+          [% IF hidden %]
+            &lt;strong&gt;WARNING: This product is currently hidden.
+            Deleting this group will make this product publicly visible.
+            &lt;/strong&gt;
+          [% END %]&lt;/li&gt;
+      [% END %]
+    &lt;/ul&gt;
+
+    &lt;p&gt;&lt;label&gt;&lt;input type=&quot;checkbox&quot; name=&quot;unbind&quot;&gt;Delete this group anyway,
+      and remove these controls.&lt;/label&gt;&lt;/p&gt;
</ins><span class="cx">   [% END %]
</span><span class="cx">   
</span><del>-  [% IF hasflags %]
</del><ins>+  [% IF group.flag_types.size %]
</ins><span class="cx">     &lt;p&gt;&lt;b&gt;This group restricts who can make changes to flags of certain types.
</span><span class="cx">     You cannot delete this group while there are flag types using it.&lt;/b&gt;
</span><span class="cx"> 
</span><del>-    &lt;br&gt;&lt;a href=&quot;editflagtypes.cgi?action=list&amp;group=[% gid FILTER html %]&quot;&gt;Show
-    me which types&lt;/a&gt; - &lt;input type=&quot;checkbox&quot; name=&quot;removeflags&quot;&gt;Remove all
-    flag types from this group for me.&lt;/p&gt;
</del><ins>+    &lt;br&gt;&lt;a href=&quot;editflagtypes.cgi?action=list&amp;amp;group=
+                 [%- group.id FILTER uri %]&quot;&gt;Show
+    me which types&lt;/a&gt; - 
+    &lt;label&gt;&lt;input type=&quot;checkbox&quot; name=&quot;removeflags&quot;&gt;Remove all
+    flag types from this group for me.&lt;/label&gt;&lt;/p&gt;
</ins><span class="cx">   [% END %]
</span><span class="cx"> 
</span><span class="cx">   [% IF shared_queries %]
</span><span class="lines">@@ -115,7 +167,9 @@
</span><span class="cx">   &lt;h2&gt;Confirmation&lt;/h2&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;p&gt;Do you really want to delete this group?&lt;/p&gt;
</span><del>-  [% IF (hasusers || hasbugs || hasproduct || hasflags) %]
</del><ins>+  [% IF group.users.size || group.bugs.size || group.products.size 
+        || group.flags.size
+  %]
</ins><span class="cx">     &lt;p&gt;&lt;b&gt;You must check all of the above boxes or correct the
</span><span class="cx">           indicated problems first before you can proceed.&lt;/b&gt;&lt;/p&gt;
</span><span class="cx">   [% END %]
</span><span class="lines">@@ -123,7 +177,7 @@
</span><span class="cx">   &lt;p&gt;
</span><span class="cx">     &lt;input type=&quot;submit&quot; id=&quot;delete&quot; value=&quot;Yes, delete&quot;&gt;
</span><span class="cx">     &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;delete&quot;&gt;
</span><del>-    &lt;input type=&quot;hidden&quot; name=&quot;group&quot; value=&quot;[% gid FILTER html %]&quot;&gt;
</del><ins>+    &lt;input type=&quot;hidden&quot; name=&quot;group&quot; value=&quot;[% group.id FILTER html %]&quot;&gt;
</ins><span class="cx">     &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% token FILTER html %]&quot;&gt;
</span><span class="cx">   &lt;/p&gt;
</span><span class="cx"> &lt;/form&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadmingroupsedithtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/groups/edit.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/groups/edit.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/groups/edit.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -184,7 +184,7 @@
</span><span class="cx">     &lt;/table&gt;
</span><span class="cx">   [% END %]
</span><span class="cx"> 
</span><del>-  &lt;input type=&quot;submit&quot; value=&quot;Update Group&quot;&gt;
</del><ins>+  &lt;input type=&quot;submit&quot; id=&quot;update-group&quot; value=&quot;Update Group&quot;&gt;
</ins><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% token FILTER html %]&quot;&gt;
</span><span class="cx"> &lt;/form&gt;
</span><span class="cx">   
</span><span class="lines">@@ -197,10 +197,10 @@
</span><span class="cx"> &lt;table&gt;&lt;tr&gt;&lt;td&gt;
</span><span class="cx"> &lt;form method=&quot;post&quot; action=&quot;editgroups.cgi&quot;&gt;
</span><span class="cx">   &lt;fieldset&gt;
</span><del>-    &lt;legend&gt;Remove all explict memberships from users whose login names
</del><ins>+    &lt;legend&gt;Remove all explicit memberships from users whose login names
</ins><span class="cx">       match the following regular expression:&lt;/legend&gt;
</span><span class="cx">     &lt;input type=&quot;text&quot; size=&quot;20&quot; name=&quot;regexp&quot;&gt;
</span><del>-    &lt;input type=&quot;submit&quot; value=&quot;Remove Memberships&quot;&gt;
</del><ins>+    &lt;input type=&quot;submit&quot; id=&quot;remove-membership&quot; value=&quot;Remove Memberships&quot;&gt;
</ins><span class="cx"> 
</span><span class="cx">     &lt;p&gt;If you leave the field blank, all explicit memberships in 
</span><span class="cx">       this group will be removed.&lt;/p&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadmingroupslisthtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/groups/list.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/groups/list.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/groups/list.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -66,68 +66,60 @@
</span><span class="cx">   ]
</span><span class="cx"> %]
</span><span class="cx"> 
</span><del>-[% overrides.is_active_bug_group = [ {
-     match_value =&gt; &quot;0&quot;
-     match_field =&gt; 'is_active_bug_group'
-     override_content =&gt; 1
-     content =&gt; &quot;&amp;nbsp;&quot;
-   },
-   {
-     match_value =&gt; &quot;1&quot;
-     match_field =&gt; 'is_active_bug_group'
-     override_content =&gt; 1
-     content =&gt; &quot;X&quot;
-   }]
-   overrides.userregexp = [ {
-     match_value =&gt; &quot;&quot;
-     match_field =&gt; 'userregexp'
-     override_content =&gt; 1
-     content =&gt; &quot;&amp;nbsp;&quot;
-   }]
-   overrides.action = [ {
-     match_value =&gt; Param(&quot;chartgroup&quot;)
-     match_field =&gt; 'name'
-     override_content =&gt; 1
-     content =&gt; &quot;(used as the 'chartgroup')&quot;
-   },
-   {
-     match_value =&gt; Param(&quot;insidergroup&quot;)
-     match_field =&gt; 'name'
-     override_content =&gt; 1
-     content =&gt; &quot;(used as the 'insidergroup')&quot;
-   },
-   {
-     match_value =&gt; Param(&quot;timetrackinggroup&quot;)
-     match_field =&gt; 'name'
-     override_content =&gt; 1
-     content =&gt; &quot;(used as the 'timetrackinggroup')&quot;
-   },
-   {
-     match_value =&gt; Param(&quot;querysharegroup&quot;)
-     match_field =&gt; 'name'
-     override_content =&gt; 1
-     content =&gt; &quot;(used as the 'querysharegroup')&quot;
-   },
-   {
-     match_value =&gt; &quot;1&quot;
-     match_field =&gt; 'isbuggroup'
-     override_content =&gt; 1
-     content =&gt; &quot;Delete&quot;
-     override_contentlink =&gt; 1
-     contentlink =&gt; del_contentlink
-   }]
-   overrides.type = [ {
-     match_value =&gt; &quot;0&quot;
-     match_field =&gt; 'isbuggroup'
-     override_content =&gt; 1
-     content =&gt; &quot;system&quot;
-   },
-   {
-     match_value =&gt; &quot;1&quot;
-     match_field =&gt; 'isbuggroup'
-     override_content =&gt; 1
-     content =&gt; &quot;user&quot;
-   }]
</del><ins>+[% overrides.is_active_bug_group = {
+     'is_active_bug_group' =&gt; {
+       &quot;0&quot; =&gt; {
+          override_content =&gt; 1
+          content =&gt; &quot;&amp;nbsp;&quot;
+       }
+       &quot;1&quot; =&gt; {
+          override_content =&gt; 1
+          content =&gt; &quot;X&quot;
+       }
+     }
+   }
+
+   overrides.userregexp = {
+     'userregexp' =&gt; {
+       &quot;&quot; =&gt; {
+         override_content =&gt; 1
+         content =&gt; &quot;&amp;nbsp;&quot;
+       }
+     }
+   } 
+%]
+
+[% FOREACH group IN [&quot;chartgroup&quot;, &quot;insidergroup&quot;, &quot;timetrackinggroup&quot;, &quot;querysharegroup&quot;] %]
+  [% special_group = Param(group) %]
+
+  [% IF special_group %]
+    [% overrides.action.name.$special_group = {
+         override_content =&gt; 1
+         content =&gt; &quot;(used as the '$group')&quot;
+       }
+    %]
+  [% END %]
+[% END %]
+
+[% overrides.action.isbuggroup = {
+     &quot;1&quot; =&gt; {
+         override_content =&gt; 1
+         content =&gt; &quot;Delete&quot;
+         override_contentlink =&gt; 1
+         contentlink =&gt; del_contentlink
+     }
+   }
+
+   overrides.type.isbuggroup = {
+     &quot;0&quot; =&gt; {
+         override_content =&gt; 1
+         content =&gt; &quot;system&quot;
+     }
+     &quot;1&quot; =&gt; {
+         override_content =&gt; 1
+         content =&gt; &quot;user&quot;
+     }
+   }
</ins><span class="cx"> %] 
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS admin/table.html.tmpl
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminkeywordsedithtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/keywords/edit.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/keywords/edit.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/keywords/edit.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -53,7 +53,7 @@
</span><span class="cx">       &lt;th align=&quot;right&quot;&gt;[% terms.Bugs %]:&lt;/th&gt;
</span><span class="cx">       &lt;td&gt;
</span><span class="cx">         [% IF keyword.bug_count &gt; 0 %]
</span><del>-          &lt;a href=&quot;buglist.cgi?keywords=[% keyword.name FILTER url_quote %]&quot;&gt;
</del><ins>+          &lt;a href=&quot;buglist.cgi?keywords=[% keyword.name FILTER uri %]&quot;&gt;
</ins><span class="cx">             [% keyword.bug_count FILTER html %]&lt;/a&gt;
</span><span class="cx">         [% ELSE %]
</span><span class="cx">           none
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminmilestonesconfirmdeletehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/milestones/confirm-delete.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/milestones/confirm-delete.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/milestones/confirm-delete.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -52,8 +52,8 @@
</span><span class="cx"> [% IF milestone.bug_count %]
</span><span class="cx">   &lt;a title=&quot;List of [% terms.bugs %] targetted at milestone '
</span><span class="cx">            [% milestone.name FILTER html %]'&quot;
</span><del>-     href=&quot;buglist.cgi?target_milestone=[% milestone.name FILTER url_quote %]&amp;amp;product=
-          [%- product.name FILTER url_quote %]&quot;&gt;
</del><ins>+     href=&quot;buglist.cgi?target_milestone=[% milestone.name FILTER uri %]&amp;amp;product=
+          [%- product.name FILTER uri %]&quot;&gt;
</ins><span class="cx">           [% milestone.bug_count FILTER none %]&lt;/a&gt;
</span><span class="cx"> [% ELSE %]
</span><span class="cx">   None
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminmilestonesedithtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/milestones/edit.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/milestones/edit.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/milestones/edit.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -38,16 +38,20 @@
</span><span class="cx">   &lt;table border=&quot;0&quot; cellpadding=&quot;4&quot; cellspacing=&quot;0&quot;&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;th valign=&quot;top&quot;&gt;&lt;label for=&quot;milestone&quot;&gt;Milestone:&lt;/label&gt;&lt;/th&gt;
</del><ins>+      &lt;th class=&quot;field_label&quot;&gt;&lt;label for=&quot;milestone&quot;&gt;Milestone:&lt;/label&gt;&lt;/th&gt;
</ins><span class="cx">       &lt;td&gt;&lt;input id=&quot;milestone&quot; size=&quot;20&quot; maxlength=&quot;20&quot; name=&quot;milestone&quot; value=&quot;
</span><span class="cx">       [%- milestone.name FILTER html %]&quot;&gt;&lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;th align=&quot;right&quot;&gt;&lt;label for=&quot;sortkey&quot;&gt;Sortkey:&lt;/label&gt;&lt;/th&gt;
</del><ins>+      &lt;th class=&quot;field_label&quot;&gt;&lt;label for=&quot;sortkey&quot;&gt;Sortkey:&lt;/label&gt;&lt;/th&gt;
</ins><span class="cx">       &lt;td&gt;&lt;input id=&quot;sortkey&quot; size=&quot;20&quot; maxlength=&quot;20&quot; name=&quot;sortkey&quot; value=&quot;
</span><span class="cx">       [%- milestone.sortkey FILTER html %]&quot;&gt;&lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><del>-
</del><ins>+    &lt;tr&gt;
+      &lt;th class=&quot;field_label&quot;&gt;&lt;label for=&quot;isactive&quot;&gt;Enabled For [% terms.Bugs %]:&lt;/label&gt;&lt;/th&gt;
+      &lt;td&gt;&lt;input id=&quot;isactive&quot; name=&quot;isactive&quot; type=&quot;checkbox&quot; value=&quot;1&quot;
+                 [% 'checked=&quot;checked&quot;' IF milestone.isactive %]&gt;&lt;/td&gt;
+    &lt;/tr&gt;
</ins><span class="cx">   &lt;/table&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;milestoneold&quot; value=&quot;[% milestone.name FILTER html %]&quot;&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminmilestonesfooterhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/milestones/footer.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/milestones/footer.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/milestones/footer.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -40,7 +40,7 @@
</span><span class="cx"> [% UNLESS no_add_milestone_link %]
</span><span class="cx">   &lt;a title=&quot;Add a milestone to product '[% product.name FILTER html %]'&quot;
</span><span class="cx">      href=&quot;editmilestones.cgi?action=add&amp;amp;product=
</span><del>-          [%- product.name FILTER url_quote %]&quot;&gt;Add&lt;/a&gt; a milestone. 
</del><ins>+          [%- product.name FILTER uri %]&quot;&gt;Add&lt;/a&gt; a milestone. 
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% IF milestone.name &amp;&amp; !no_edit_milestone_link %]
</span><span class="lines">@@ -48,20 +48,20 @@
</span><span class="cx">   title=&quot;Edit Milestone '[% milestone.name FILTER html %]' of product '
</span><span class="cx">          [%- product.name FILTER html %]'&quot;
</span><span class="cx">   href=&quot;editmilestones.cgi?action=edit&amp;amp;product=
</span><del>-        [%- product.name FILTER url_quote %]&amp;amp;milestone=
-        [%- milestone.name FILTER url_quote %]&quot;&gt;
</del><ins>+        [%- product.name FILTER uri %]&amp;amp;milestone=
+        [%- milestone.name FILTER uri %]&quot;&gt;
</ins><span class="cx">         '[% milestone.name FILTER html %]'&lt;/a&gt;.
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% UNLESS no_edit_other_milestones_link %]
</span><span class="cx">   Edit other milestones of product &lt;a 
</span><span class="cx">   href=&quot;editmilestones.cgi?product=
</span><del>-        [%- product.name FILTER url_quote %]&quot;&gt;'[% product.name FILTER html %]'&lt;/a&gt;.
</del><ins>+        [%- product.name FILTER uri %]&quot;&gt;'[% product.name FILTER html %]'&lt;/a&gt;.
</ins><span class="cx"> 
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx">   Edit product &lt;a 
</span><span class="cx">   href=&quot;editproducts.cgi?action=edit&amp;amp;product=
</span><del>-        [%- product.name FILTER url_quote %]&quot;&gt;'[% product.name FILTER html %]'&lt;/a&gt;.
</del><ins>+        [%- product.name FILTER uri %]&quot;&gt;'[% product.name FILTER html %]'&lt;/a&gt;.
</ins><span class="cx"> 
</span><span class="cx"> &lt;/p&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminmilestoneslisthtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/milestones/list.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/milestones/list.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/milestones/list.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -37,11 +37,11 @@
</span><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> [% edit_contentlink = BLOCK %]editmilestones.cgi?action=edit&amp;amp;product=
</span><del>-  [%- product.name FILTER url_quote %]&amp;amp;milestone=%%name%%[% END %]
</del><ins>+  [%- product.name FILTER uri %]&amp;amp;milestone=%%name%%[% END %]
</ins><span class="cx"> [% delete_contentlink = BLOCK %]editmilestones.cgi?action=del&amp;amp;product=
</span><del>-  [%- product.name FILTER url_quote %]&amp;amp;milestone=%%name%%[% END %]
</del><ins>+  [%- product.name FILTER uri %]&amp;amp;milestone=%%name%%[% END %]
</ins><span class="cx"> [% bug_count_contentlink = BLOCK %]buglist.cgi?target_milestone=%%name%%&amp;amp;product=
</span><del>-  [%- product.name FILTER url_quote %][% END %]
</del><ins>+  [%- product.name FILTER uri %][% END %]
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> [% columns = [
</span><span class="lines">@@ -53,6 +53,11 @@
</span><span class="cx">      { 
</span><span class="cx">        name =&gt; &quot;sortkey&quot;
</span><span class="cx">        heading =&gt; &quot;Sortkey&quot;
</span><ins>+     },
+     {
+       name =&gt; &quot;isactive&quot;
+       heading =&gt; &quot;Active&quot;
+       yesno_field =&gt; 1
</ins><span class="cx">      }
</span><span class="cx">    ]
</span><span class="cx"> %]
</span><span class="lines">@@ -77,18 +82,17 @@
</span><span class="cx">      })
</span><span class="cx"> %]
</span><span class="cx"> 
</span><del>-[%# We want to override the usual 'Delete' link for the default
-    milestone %]
-[% overrides.action = [ {
-     match_value =&gt; product.default_milestone
-     match_field =&gt; 'name'
</del><ins>+[%# We want to override the usual 'Delete' link for the default milestone %]
+[% overrides.action.name.${product.default_milestone} = {
</ins><span class="cx">      override_content =&gt; 1
</span><span class="cx">      content =&gt; &quot;(Default milestone)&quot;
</span><span class="cx">      override_contentlink =&gt; 1
</span><span class="cx">      contentlink =&gt; undef
</span><del>-   } ]
</del><ins>+   } 
</ins><span class="cx"> %] 
</span><span class="cx"> 
</span><ins>+[% Hook.process('before_table') %]
+
</ins><span class="cx"> [% PROCESS admin/table.html.tmpl
</span><span class="cx">      columns = columns
</span><span class="cx">      data = product.milestones
</span><span class="lines">@@ -97,7 +101,7 @@
</span><span class="cx"> 
</span><span class="cx"> [% IF ! showbugcounts %]
</span><span class="cx"> 
</span><del>-  &lt;p&gt;&lt;a href=&quot;editmilestones.cgi?product=[% product.name FILTER url_quote %]&amp;amp;showbugcounts=1&quot;&gt;
</del><ins>+  &lt;p&gt;&lt;a href=&quot;editmilestones.cgi?product=[% product.name FILTER uri %]&amp;amp;showbugcounts=1&quot;&gt;
</ins><span class="cx">       Redisplay table with [% terms.bug %] counts (slower)&lt;/a&gt;&lt;/p&gt;
</span><span class="cx"> 
</span><span class="cx"> [% END %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminparamsadminhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/params/admin.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/params/admin.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/params/admin.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -37,9 +37,5 @@
</span><span class="cx">                        &quot;$terms.Bugzilla will issue a warning in case you'd run into inconsistencies &quot; _
</span><span class="cx">                        &quot;when you're about to do so, but such deletions remain kinda scary. &quot; _
</span><span class="cx">                        &quot;So, you have to turn on this option before any such deletions &quot; _
</span><del>-                       &quot;will ever happen.&quot;,
-
-  supportwatchers =&gt; &quot;Support one user watching (ie getting copies of all related &quot; _
-                     &quot;email about) another's ${terms.bugs}. Useful for people going on &quot; _
-                     &quot;vacation, and QA folks watching particular developers' ${terms.bugs}.&quot; }
</del><ins>+                       &quot;will ever happen.&quot; }
</ins><span class="cx"> %]
</span><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminparamsadvancedhtmltmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/admin/params/advanced.html.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/params/advanced.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/params/advanced.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,81 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Netscape Communications
+  # Corporation. Portions created by Netscape are
+  # Copyright (C) 1998 Netscape Communications Corporation. All
+  # Rights Reserved.
+  #
+  # Contributor(s): Dave Miller &lt;justdave@bugzilla.org&gt;
+  #                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
+  #%]
+
+[% 
+   title = &quot;Advanced&quot;
+   desc = &quot;Settings for advanced configurations.&quot;
+%]
+
+[% sts_desc = BLOCK %]
+  Enables the sending of the 
+  &lt;a href=&quot;http://en.wikipedia.org/wiki/Strict_Transport_Security&quot;&gt;Strict-Transport-Security&lt;/a&gt;
+  header along with HTTP responses on SSL connections. This adds greater
+  security to your SSL connections by forcing the browser to always
+  access your domain over SSL and never accept an invalid certificate. 
+  However, it should only be used if you have the &lt;code&gt;ssl_redirect&lt;/code&gt;
+  parameter turned on, [% terms.Bugzilla %] is the only thing running
+  on its domain (i.e., your &lt;code&gt;urlbase&lt;/code&gt; is something like
+  &lt;code&gt;http://bugzilla.example.com/&lt;/code&gt;), and you never plan to disable
+  the &lt;code&gt;ssl_redirect&lt;/code&gt; parameter.
+  &lt;ul&gt;
+    &lt;li&gt;
+      off - Don't send the Strict-Transport-Security header with requests.
+    &lt;/li&gt;
+    &lt;li&gt;
+      this_domain_only - Send the Strict-Transport-Security header with all
+      requests, but only support it for the current domain.
+    &lt;/li&gt;
+    &lt;li&gt;
+      include_subdomains - Send the Strict-Transport-Security header along
+      with the &lt;code&gt;includeSubDomains&lt;/code&gt; flag, which will apply the
+      security change to all subdomains. This is especially useful when
+      combined with an &lt;code&gt;attachment_base&lt;/code&gt; that exists as (a)
+      subdomain(s) under the main [% terms.Bugzilla %] domain.
+    &lt;/li&gt;
+  &lt;/ul&gt;
+[% END %]
+
+[% param_descs = {
+  cookiedomain =&gt; 
+    &quot;If your website is at 'www.foo.com', setting this to&quot;
+    _ &quot; '.foo.com' will also allow 'bar.foo.com' to access&quot;
+    _ &quot; $terms.Bugzilla cookies. This is useful if you have more than&quot;
+    _ &quot; one hostname pointing at the same web server, and you&quot;
+    _ &quot; want them to share the $terms.Bugzilla cookie.&quot;,
+
+  inbound_proxies =&gt;
+    &quot;When inbound traffic to $terms.Bugzilla goes through a proxy,&quot;
+    _ &quot; $terms.Bugzilla thinks that the IP address of every single&quot;
+    _ &quot; user is the IP address of the proxy. If you enter a comma-separated&quot;
+    _ &quot; list of IPs in this parameter, then $terms.Bugzilla will trust any&quot;
+    _ &quot; &lt;code&gt;X-Forwarded-For&lt;/code&gt; header sent from those IPs,&quot;
+    _ &quot; and use the value of that header as the end user's IP address.&quot;,
+
+  proxy_url =&gt; 
+    &quot;$terms.Bugzilla may have to access the web to get notifications about&quot;
+    _ &quot; new releases (see the &lt;tt&gt;upgrade_notification&lt;/tt&gt; parameter).&quot;
+    _ &quot; If your $terms.Bugzilla server is behind a proxy, it may be&quot;
+    _ &quot; necessary to enter its URL if the web server cannot access the&quot;
+    _ &quot; HTTP_PROXY environment variable. If you have to authenticate,&quot;
+    _ &quot; use the &lt;code&gt;http://user:pass@proxy_url/&lt;/code&gt; syntax.&quot;,
+
+  strict_transport_security =&gt; sts_desc,
+} %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminparamsattachmenthtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/params/attachment.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/params/attachment.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/params/attachment.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -45,7 +45,7 @@
</span><span class="cx">     _ &quot; That is, a different domain name that resolves to this exact&quot;
</span><span class="cx">     _ &quot; same $terms.Bugzilla installation.&lt;/p&gt;&quot;
</span><span class="cx">     _ &quot;&lt;p&gt;Note that if you have set the&quot;
</span><del>-    _ &quot; &lt;a href=\&quot;editparams.cgi?section=core#cookiedomain\&quot;&gt;&lt;tt&gt;cookiedomain&lt;/tt&gt;&quot;
</del><ins>+    _ &quot; &lt;a href=\&quot;editparams.cgi?section=advanced#cookiedomain_desc\&quot;&gt;&lt;tt&gt;cookiedomain&lt;/tt&gt;&quot;
</ins><span class="cx">     _&quot; parameter&lt;/a&gt;, you should set &lt;tt&gt;attachment_base&lt;/tt&gt; to use a&quot;
</span><span class="cx">     _ &quot; domain that would &lt;em&gt;not&lt;/em&gt; be matched by&quot;
</span><span class="cx">     _ &quot; &lt;tt&gt;cookiedomain&lt;/tt&gt;.&lt;/p&gt;&quot;
</span><span class="lines">@@ -60,27 +60,16 @@
</span><span class="cx">   allow_attachment_deletion =&gt; &quot;If this option is on, administrators will be able to delete &quot; _
</span><span class="cx">                                &quot;the content of attachments.&quot;,
</span><span class="cx"> 
</span><del>-  allow_attach_url =&gt; &quot;If this option is on, it will be possible to &quot; _
-                      &quot;specify a URL when creating an attachment and &quot; _
-                      &quot;treat the URL itself as if it were an attachment.&quot;,
</del><ins>+  maxattachmentsize =&gt; &quot;The maximum size (in kilobytes) of attachments to be stored &quot; _
+                       &quot;in the database. If a file larger than this size is attached &quot; _
+                       &quot;to ${terms.abug}, $terms.Bugzilla will look at the &quot; _
+                       &quot;&lt;a href='#maxlocalattachment'&gt;&lt;tt&gt;maxlocalattachment&lt;/tt&gt; parameter&lt;/a&gt; &quot; _
+                       &quot;to determine if the file can be stored locally on the web server. &quot; _
+                       &quot;If the file size exceeds both limits, then the attachment is rejected. &quot; _
+                       &quot;Settings both parameters to 0 will prevent attaching files to ${terms.bugs}.&quot;,
</ins><span class="cx"> 
</span><del>-  maxpatchsize =&gt; &quot;The maximum size (in kilobytes) of patches. $terms.Bugzilla will not &quot; _
-                  &quot;accept patches greater than this number of kilobytes in size. &quot; _
-                  &quot;To accept patches of any size (subject to the limitations of &quot; _
-                  &quot;your server software), set this value to zero.&quot;,
-
-  maxattachmentsize =&gt; &quot;The maximum size (in kilobytes) of non-patch attachments. &quot; _
-                       &quot;$terms.Bugzilla will not accept attachments greater than this number &quot; _
-                       &quot;of kilobytes in size. To accept attachments of any size &quot; _
-                       &quot;(subject to the limitations of your server software), set this &quot; _
-                       &quot;value to zero.&quot;,
-
-  maxlocalattachment =&gt; &quot;The maximum size (in megabytes) of attachments identified by &quot; _
-                        &quot;the user as 'Big Files' to be stored locally on the webserver. &quot; _
-                        &quot;If set to zero, attachments will never be kept on the local &quot; _
-                        &quot;filesystem.&quot;,
-
-  convert_uncompressed_images =&gt; &quot;If this option is on, attachments with content type image/bmp &quot; _
-                                 &quot;will be converted to image/png and compressed before uploading to &quot; _
-                                 &quot;the database to conserve disk space.&quot; }
</del><ins>+  maxlocalattachment =&gt; &quot;The maximum size (in megabytes) of attachments to be stored &quot; _
+                        &quot;locally on the web server. If set to a value lower than the &quot; _
+                        &quot;&lt;a href='#maxattachmentsize'&gt;&lt;tt&gt;maxattachmentsize&lt;/tt&gt; parameter&lt;/a&gt;, &quot; _
+                        &quot;attachments will never be kept on the local filesystem.&quot; }
</ins><span class="cx"> %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminparamsauthhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/params/auth.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/params/auth.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/params/auth.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -70,8 +70,8 @@
</span><span class="cx">                           &lt;dt&gt;RADIUS&lt;/dt&gt;
</span><span class="cx">                           &lt;dd&gt;
</span><span class="cx">                             RADIUS authentication using a RADIUS server.
</span><del>-                            This method is experimental; please see the
-                            $terms.Bugzilla documentation for more information.
</del><ins>+                            Please see the $terms.Bugzilla documentation for
+                            more information.
</ins><span class="cx">                             Using this method requires
</span><span class="cx">                             &lt;a href=\&quot;?section=radius\&quot;&gt;additional
</span><span class="cx">                             parameters&lt;/a&gt; to be set.
</span><span class="lines">@@ -103,11 +103,6 @@
</span><span class="cx">                       &lt;/li&gt;
</span><span class="cx">                     &lt;/ul&gt;&quot;,
</span><span class="cx"> 
</span><del>-  loginnetmask =&gt; &quot;The number of bits for the netmask used if a user chooses to &quot; _
-                  &quot;allow a login to be valid for more than a single IP. Setting &quot; _
-                  &quot;this to 32 disables this feature.&lt;br&gt; &quot; _
-                  &quot;Note that enabling this may decrease the security of your system.&quot;,
-
</del><span class="cx">   requirelogin =&gt; &quot;If this option is set, all access to the system beyond the &quot; _
</span><span class="cx">                   &quot;front page will require a login. No anonymous users will &quot; _
</span><span class="cx">                   &quot;be permitted.&quot;,
</span><span class="lines">@@ -125,10 +120,22 @@
</span><span class="cx">                  &quot;the &lt;tt&gt;emailregexp&lt;/tt&gt; param to only allow local usernames, &quot; _
</span><span class="cx">                  &quot;but you want the mail to be delivered to username@my.local.hostname.&quot;,
</span><span class="cx"> 
</span><del>-  createemailregexp =&gt; &quot;This defines the regexp to use for email addresses that are &quot; _
</del><ins>+  createemailregexp =&gt; &quot;This defines the (case-insensitive) regexp to use for email addresses that are &quot; _
</ins><span class="cx">                        &quot;permitted to self-register using a 'New Account' feature. The &quot; _
</span><span class="cx">                        &quot;default (.*) permits any account matching the emailregexp &quot; _
</span><span class="cx">                        &quot;to be created. If this parameter is left blank, no users &quot; _
</span><span class="cx">                        &quot;will be permitted to create their own accounts and all accounts &quot; _
</span><del>-                       &quot;will have to be created by an administrator.&quot; }
</del><ins>+                       &quot;will have to be created by an administrator.&quot;,
+
+  password_complexity =&gt;
+    &quot;Set the complexity required for passwords. In all cases must the passwords &quot; _
+    &quot;be at least ${constants.USER_PASSWORD_MIN_LENGTH} characters long.&quot; _
+    &quot;&lt;ul&gt;&lt;li&gt;no_constraints - No complexity required.&lt;/li&gt;&quot; _
+    &quot;&lt;li&gt;mixed_letters - Passwords must contain at least one UPPER and one lower &quot; _
+    &quot;case letter.&lt;/li&gt;&quot; _
+    &quot;&lt;li&gt;letters_numbers - Passwords must contain at least one UPPER and one &quot; _
+    &quot;lower case letter and a number.&lt;/li&gt;&quot; _
+    &quot;&lt;li&gt;letters_numbers_specialchars - Passwords must contain at least one &quot; _
+    &quot;UPPER or one lower case letter, a number and a special character.&lt;/li&gt;&lt;/ul&gt;&quot;
+  }
</ins><span class="cx"> %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminparamsbugchangehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/params/bugchange.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/params/bugchange.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/params/bugchange.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -23,6 +23,10 @@
</span><span class="cx">    desc = &quot;Set up $terms.bug change policies&quot;
</span><span class="cx"> %]
</span><span class="cx"> 
</span><ins>+[% PROCESS &quot;global/field-descs.none.tmpl&quot; %]
+
+[% accept_status = display_value('bug_status', 'IN_PROGRESS') FILTER html %]
+
</ins><span class="cx"> [% param_descs = {
</span><span class="cx">   duplicate_or_move_bug_status =&gt; &quot;When $terms.abug is marked as a duplicate of another one &quot; _
</span><span class="cx">                                   &quot;or is moved to another installation, use this $terms.bug status.&quot;
</span><span class="lines">@@ -37,18 +41,14 @@
</span><span class="cx">                                  &quot;If off, then all $terms.bugs initially have the default &quot; _
</span><span class="cx">                                  &quot;milestone for the product being filed in.&quot;,
</span><span class="cx"> 
</span><del>-  musthavemilestoneonaccept =&gt; &quot;If you are using Target Milestone, do you want to require that &quot; _
-                               &quot;the milestone be set in order for a user to ACCEPT a ${terms.bug}?&quot;,
</del><ins>+  musthavemilestoneonaccept =&gt; 
+    &quot;If you are using ${field_descs.target_milestone}, do you want to require&quot;
+    _ &quot; that the milestone be set in order for a user to set&quot;
+    _ &quot;  ${terms.abug}'s status to ${accept_status}?&quot;,
</ins><span class="cx"> 
</span><del>-  commentonclearresolution =&gt; &quot;If this option is on, the user needs to enter a short comment if &quot; _
-                              &quot;the ${terms.bug}'s resolution is cleared.&quot;,
-
</del><span class="cx">   commentonchange_resolution =&gt; &quot;If this option is on, the user needs to enter a short &quot; _
</span><span class="cx">                                 &quot;comment if the resolution of the $terms.bug changes.&quot;,
</span><span class="cx"> 
</span><del>-  commentonreassignbycomponent =&gt; &quot;If this option is on, the user needs to enter a short comment if &quot; _
-                                  &quot;the $terms.bug is reassigned by component.&quot;,
-
</del><span class="cx">   commentonduplicate =&gt; &quot;If this option is on, the user needs to enter a short comment &quot; _
</span><span class="cx">                         &quot;if the $terms.bug is marked as duplicate.&quot;,
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminparamsbugfieldshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/params/bugfields.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/params/bugfields.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/params/bugfields.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -28,23 +28,21 @@
</span><span class="cx">                        &quot;specific classification. But you must have 'editclassification' &quot; _
</span><span class="cx">                        &quot;permissions enabled in order to edit classifications.&quot;,
</span><span class="cx"> 
</span><del>-  showallproducts =&gt; &quot;If this is on and useclassification is set, $terms.Bugzilla will add a &quot; _
-                     &quot;'All' link in the 'New $terms.Bug' page to list all available products.&quot;,
-
</del><span class="cx">   usetargetmilestone =&gt; &quot;Do you wish to use the Target Milestone field?&quot;,
</span><span class="cx"> 
</span><span class="cx">   useqacontact =&gt; &quot;Do you wish to use the QA Contact field?&quot;,
</span><span class="cx"> 
</span><span class="cx">   usestatuswhiteboard =&gt; &quot;Do you wish to use the Status Whiteboard field?&quot;,
</span><span class="cx"> 
</span><del>-  usevotes =&gt; &quot;Do you wish to allow users to vote for ${terms.bugs}? Note that in order &quot; _
-              &quot;for this to be effective, you will have to change the maximum &quot; _
-              &quot;votes allowed in a product to be non-zero in &quot; _
-              &quot;&lt;a href=\&quot;editproducts.cgi\&quot;&gt;the product edit page&lt;/a&gt;.&quot;,
-
</del><span class="cx">   usebugaliases =&gt; &quot;Do you wish to use $terms.bug aliases, which allow you to assign &quot; _
</span><span class="cx">                    &quot;$terms.bugs an easy-to-remember name by which you can refer to them?&quot;,
</span><span class="cx"> 
</span><ins>+  use_see_also =&gt; 
+    &quot;Do you wish to use the See Also field? It allows you refer to&quot;
+    _ &quot; $terms.bugs in other installations. Even if you disable this field,&quot;
+    _ &quot; $terms.bug relationships (URLs) already set on $terms.bugs will&quot;
+    _ &quot; still appear and can be removed.&quot;,
+
</ins><span class="cx">   defaultpriority =&gt; &quot;This is the priority that newly entered $terms.bugs are set to.&quot;,
</span><span class="cx"> 
</span><span class="cx">   defaultseverity =&gt; &quot;This is the severity that newly entered $terms.bugs are set to.&quot;,
</span><span class="lines">@@ -60,4 +58,4 @@
</span><span class="cx">                   &quot;You can leave this empty: &quot; _
</span><span class="cx">                   &quot;$terms.Bugzilla will then use the operating system that the browser &quot; _
</span><span class="cx">                   &quot;reports to be running on as the default.&quot; }
</span><del>-%]
</del><span class="cx">\ No newline at end of file
</span><ins>+%]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminparamsbugmovehtmltmpl"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/template/en/default/admin/params/bugmove.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/params/bugmove.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/params/bugmove.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,49 +0,0 @@
</span><del>-[%# The contents of this file are subject to the Mozilla Public
-  # License Version 1.1 (the &quot;License&quot;); you may not use this file
-  # except in compliance with the License. You may obtain a copy of
-  # the License at http://www.mozilla.org/MPL/
-  #
-  # Software distributed under the License is distributed on an &quot;AS
-  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
-  # implied. See the License for the specific language governing
-  # rights and limitations under the License.
-  #
-  # The Original Code is the Bugzilla Bug Tracking System.
-  #
-  # The Initial Developer of the Original Code is Netscape Communications
-  # Corporation. Portions created by Netscape are
-  # Copyright (C) 1998 Netscape Communications Corporation. All
-  # Rights Reserved.
-  #
-  # Contributor(s): Dave Miller &lt;justdave@bugzilla.org&gt;
-  #                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
-  #%]
-[%
-   title = &quot;$terms.Bug Moving&quot;
-   desc = &quot;Set up parameters to move $terms.bugs to/from another installation&quot;
-%]
-
-[% param_descs = {
-  &quot;move-enabled&quot; =&gt; &quot;If this is on, $terms.Bugzilla will allow certain people &quot; _
-                    &quot;to move $terms.bugs to the defined database.&quot;,
-
-  &quot;move-button-text&quot; =&gt; &quot;The text written on the Move button. Explain where the $terms.bug is &quot; _
-                        &quot;being moved to.&quot;,
-
-  &quot;move-to-url&quot; =&gt; &quot;The URL of the database we allow some of our $terms.bugs to be moved to.&quot;,
-
-  &quot;move-to-address&quot; =&gt; &quot;To move ${terms.bugs}, an email is sent to the target database. This is &quot; _
-                       &quot;the email address that database uses to listen for incoming ${terms.bugs}.&quot;,
-
-  &quot;moved-from-address&quot; =&gt; &quot;To move ${terms.bugs}, an email is sent to the target database. This is &quot; _
-                          &quot;the email address from which this mail, and error messages are sent.&quot;,
-
-  movers =&gt; &quot;A list of people with permission to move $terms.bugs and reopen moved &quot; _
-            &quot;${terms.bugs} (in case the move operation fails).&quot;,
-
-  &quot;moved-default-product&quot; =&gt; &quot;$terms.Bugs moved from other databases to here are assigned &quot; _
-                             &quot;to this product.&quot;,
-
-  &quot;moved-default-component&quot; =&gt; &quot;$terms.Bugs moved from other databases to here are assigned &quot; _
-                               &quot;to this component.&quot; }
-%]
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminparamscommonhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/params/common.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/params/common.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/params/common.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -22,11 +22,13 @@
</span><span class="cx">   # panel: hash representing the current panel.
</span><span class="cx">   #%]
</span><span class="cx"> 
</span><ins>+[% PROCESS &quot;global/field-descs.none.tmpl&quot; %]
+
</ins><span class="cx"> [% sortlist_separator = '---' %]
</span><span class="cx"> 
</span><span class="cx"> &lt;dl&gt;
</span><span class="cx">   [% FOREACH param = panel.param_list %]
</span><del>-    &lt;dt&gt;&lt;a name=&quot;[% param.name FILTER html %]&quot;&gt;[% param.name FILTER html %]&lt;/a&gt;&lt;/dt&gt;
</del><ins>+    &lt;dt id=&quot;[% param.name FILTER html %]_desc&quot;&gt;[% param.name FILTER html %]&lt;/dt&gt;
</ins><span class="cx">     &lt;dd&gt;[% panel.param_descs.${param.name} FILTER none %]
</span><span class="cx">       &lt;p&gt;
</span><span class="cx">       [% IF param.type == &quot;t&quot; %]
</span><span class="lines">@@ -60,62 +62,65 @@
</span><span class="cx">           [% END %]
</span><span class="cx">         &lt;/select&gt;
</span><span class="cx">       [% ELSIF param.type == &quot;o&quot; %]
</span><del>-        &lt;script type=&quot;text/javascript&quot;&gt;&lt;!--
-          document.write(&quot;&lt;span style=\&quot;display: none\&quot;&gt;&quot;);
-        // --&gt;
-        &lt;/script&gt;
</del><span class="cx">         &lt;input id=&quot;input_[% param.name FILTER html %]&quot; size=&quot;80&quot;
</span><span class="cx">                name=&quot;[% param.name FILTER html %]&quot;
</span><span class="cx">                value=&quot;[% Param(param.name) FILTER html %]&quot;&gt;&lt;br&gt;
</span><del>-        &lt;script type=&quot;text/javascript&quot;&gt;&lt;!--
-          document.write(&quot;&lt;\/span&gt;&quot;);
-        // --&gt;
-        &lt;/script&gt;
</del><span class="cx">         [% boxSize = 7 %]
</span><span class="cx">         [% boxSize = 3 + param.choices.size IF param.choices.size &lt; 7 %]
</span><span class="cx">         [% plist = Param(param.name).split(',') %]
</span><span class="cx"> 
</span><del>-        &lt;script type=&quot;text/javascript&quot;&gt;&lt;!--
-          document.write(
-            '&lt;table&gt;' +
-            '  &lt;tr&gt;' +
-            '    &lt;td rowspan=&quot;2&quot;&gt;' +
-            '      &lt;select id=&quot;select_[% param.name FILTER html %]&quot;' +
-            '              size=&quot;[% boxSize FILTER html %]&quot;' +
-            '              name=&quot;select_[% param.name FILTER html %]&quot;&gt;' +
-                     [% FOREACH item = plist %]
-            '          &lt;option value=&quot;[% item FILTER html %]&quot;&gt;[% item FILTER html %]&lt;\/option&gt;' +
-                     [% END %]
-            '        &lt;option class=&quot;sortlist_separator&quot;' +
-            '                disabled=&quot;disabled&quot;' +
-            '                value=&quot;[% sortlist_separator %]&quot;&gt;active&amp;uarr;&amp;nbsp;&amp;darr;inactive&lt;\/option&gt;' +
-                     [% FOREACH item = param.choices %]
-                       [% IF lsearch(plist, item) == -1 %]
-            '            &lt;option value=&quot;[% item FILTER html %]&quot;&gt;[% item FILTER html %]&lt;\/option&gt;' +
-                       [% END %]
-                     [% END %]
-            '      &lt;\/select&gt;' +
-            '    &lt;\/td&gt;' +
-            '    &lt;td style=&quot;vertical-align: bottom&quot;&gt;' +
-            '      &lt;button type=&quot;button&quot;' +
-            '              onClick=&quot;sortedList_moveItem(\'[% param.name FILTER html %]\', -1, \'[% sortlist_separator %]\');&quot;&gt;&amp;uarr;&lt;\/button&gt;' +
-            '    &lt;\/td&gt;' +
-            '  &lt;\/tr&gt;' +
-            '  &lt;tr&gt;' +
-            '    &lt;td style=&quot;vertical-align: top&quot;&gt;' +
-            '      &lt;button type=&quot;button&quot;' +
-            '              onClick=&quot;sortedList_moveItem(\'[% param.name FILTER html %]\', +1, \'[% sortlist_separator %]\');&quot;&gt;&amp;darr;&lt;\/button&gt;' +
-            '    &lt;\/td&gt;' +
-            '  &lt;\/tr&gt;' +
-            '&lt;\/table&gt;');
-        // --&gt;
</del><ins>+        &lt;table id=&quot;table_[% param.name FILTER html %]&quot; class=&quot;bz_default_hidden&quot;&gt;
+          &lt;tr&gt;
+            &lt;td rowspan=&quot;2&quot;&gt;
+              &lt;select id=&quot;select_[% param.name FILTER html %]&quot;
+                      name=&quot;select_[% param.name FILTER html %]&quot;
+                      size=&quot;[% boxSize FILTER html %]&quot;&gt;
+                [% FOREACH item = plist %]
+                  &lt;option value=&quot;[% item FILTER html %]&quot;&gt;[% item FILTER html %]&lt;/option&gt;
+                [% END %]
+                &lt;option class=&quot;sortlist_separator&quot; disabled=&quot;disabled&quot;
+                        value=&quot;[% sortlist_separator %]&quot;&gt;active&amp;uarr;&amp;nbsp;&amp;darr;inactive&lt;/option&gt;
+                [% FOREACH item = param.choices %]
+                  [% IF lsearch(plist, item) == -1 %]
+                    &lt;option value=&quot;[% item FILTER html %]&quot;&gt;[% item FILTER html %]&lt;/option&gt;
+                  [% END %]
+                [% END %]
+              &lt;/select&gt;
+            &lt;/td&gt;
+            &lt;td style=&quot;vertical-align: bottom&quot;&gt;
+              &lt;button type=&quot;button&quot;
+                      onClick=&quot;sortedList_moveItem('[% param.name FILTER html %]', -1, '[% sortlist_separator %]');&quot;&gt;&amp;uarr;&lt;/button&gt;
+            &lt;/td&gt;
+          &lt;/tr&gt;
+
+          &lt;tr&gt;
+            &lt;td style=&quot;vertical-align: top&quot;&gt;
+              &lt;button type=&quot;button&quot;
+                      onClick=&quot;sortedList_moveItem('[% param.name FILTER html %]', +1, '[% sortlist_separator %]');&quot;&gt;&amp;darr;&lt;/button&gt;
+            &lt;/td&gt;
+          &lt;/tr&gt;
+        &lt;/table&gt;
+
+        &lt;script type=&quot;text/javascript&quot;&gt;
+            bz_toggleClass(&quot;input_[% param.name FILTER html %]&quot;, &quot;bz_default_hidden&quot;);
+            bz_toggleClass(&quot;table_[% param.name FILTER html %]&quot;, &quot;bz_default_hidden&quot;);
</ins><span class="cx">         &lt;/script&gt;
</span><span class="cx">       [% ELSIF param.type == &quot;s&quot; %]
</span><span class="cx">         &lt;select name=&quot;[% param.name FILTER html %]&quot; id=&quot;[% param.name FILTER html %]&quot;&gt;
</span><span class="cx">           [% FOREACH item = param.choices %]
</span><span class="cx">             &lt;option value=&quot;[% item FILTER html %]&quot;
</span><span class="cx">                     [% &quot; selected=\&quot;selected\&quot;&quot; IF item == Param(param.name) %]&gt;
</span><del>-              [% item FILTER html %]
</del><ins>+              [% IF param.name == &quot;defaultseverity&quot; %]
+                [% display_value(&quot;bug_severity&quot;, item) FILTER html %]
+              [% ELSIF param.name == &quot;defaultplatform&quot; %]
+                [% display_value(&quot;rep_platform&quot;, item) FILTER html %]
+              [% ELSIF param.name == &quot;defaultopsys&quot; %]
+                [% display_value(&quot;op_sys&quot;, item) FILTER html %]
+              [% ELSIF param.name == &quot;duplicate_or_move_bug_status&quot; %]
+                [% display_value(&quot;bug_status&quot;, item) FILTER html %]
+              [% ELSE %]
+                [% item FILTER html %]
+              [% END %]
</ins><span class="cx">             &lt;/option&gt;
</span><span class="cx">           [% END %]
</span><span class="cx">         &lt;/select&gt;
</span><span class="lines">@@ -125,11 +130,13 @@
</span><span class="cx">         &lt;/font&gt;
</span><span class="cx">       [% END %]  
</span><span class="cx">       &lt;/p&gt;
</span><del>-      &lt;p&gt;
-        &lt;input type=&quot;checkbox&quot; name=&quot;reset-[% param.name FILTER html %]&quot;
-               id=&quot;reset-[% param.name FILTER html %]&quot;&gt;
-        &lt;label for=&quot;reset-[% param.name FILTER html %]&quot;&gt;Reset&lt;/label&gt;
-      &lt;/p&gt;
</del><ins>+      [% UNLESS param.no_reset %]
+        &lt;p&gt;
+          &lt;input type=&quot;checkbox&quot; name=&quot;reset-[% param.name FILTER html %]&quot;
+                 id=&quot;reset-[% param.name FILTER html %]&quot;&gt;
+          &lt;label for=&quot;reset-[% param.name FILTER html %]&quot;&gt;Reset&lt;/label&gt;
+        &lt;/p&gt;
+      [% END %]
</ins><span class="cx">       &lt;hr&gt;
</span><span class="cx">     &lt;/dd&gt;
</span><span class="cx">   [% END %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminparamscorehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/params/core.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/params/core.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/params/core.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -25,33 +25,19 @@
</span><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> [% param_descs = {
</span><del>-  maintainer =&gt; &quot;The email address of the person who maintains this installation &quot; _
-                &quot;of ${terms.Bugzilla}.&quot;,
-
</del><span class="cx">   urlbase =&gt; &quot;The URL that is the common initial leading part of all $terms.Bugzilla &quot; _
</span><span class="cx">              &quot;URLs.&quot;,
</span><span class="cx"> 
</span><del>-  docs_urlbase =&gt; &quot;The URL that is the common initial leading part of all &quot; _
-                  &quot;$terms.Bugzilla documentation URLs. &quot; _
-                  &quot;It may be an absolute URL, or a URL relative to urlbase &quot; _
-                  &quot;above. &quot; _
-                  &quot;Leave this empty to suppress links to the documentation.&quot; _
-                  &quot;'%lang%' will be replaced by user's preferred language &quot; _
-                  &quot;(if available).&quot;,
-
</del><span class="cx">   sslbase =&gt; &quot;The URL that is the common initial leading part of all HTTPS &quot; _
</span><span class="cx">              &quot;(SSL) $terms.Bugzilla URLs.&quot;,
</span><span class="cx"> 
</span><del>-  ssl =&gt; &quot;Controls when $terms.Bugzilla should enforce sessions to use HTTPS by &quot; _
-         &quot;using &lt;tt&gt;sslbase&lt;/tt&gt;.&quot;,
</del><ins>+  ssl_redirect =&gt; 
+    &quot;When this is enabled, $terms.Bugzilla will ensure that every page is&quot;
+    _ &quot; accessed over SSL, by redirecting any plain HTTP requests to HTTPS&quot;
+    _ &quot; using the &lt;tt&gt;sslbase&lt;/tt&gt; parameter. Also, when this is enabled,&quot;
+    _ &quot; $terms.Bugzilla will send out links using &lt;tt&gt;sslbase&lt;/tt&gt; in emails&quot;
+    _ &quot; instead of &lt;tt&gt;urlbase&lt;/tt&gt;.&quot;,
</ins><span class="cx"> 
</span><del>-  cookiedomain =&gt; &quot;The domain for $terms.Bugzilla cookies. Normally blank. &quot; _
-                  &quot;If your website is at 'www.foo.com', setting this to &quot; _
-                  &quot;'.foo.com' will also allow 'bar.foo.com' to access &quot; _
-                  &quot;$terms.Bugzilla cookies. This is useful if you have more than &quot; _
-                  &quot;one hostname pointing at the same web server, and you &quot; _
-                  &quot;want them to share the $terms.Bugzilla cookie.&quot;,
-
</del><span class="cx">   cookiepath =&gt; &quot;Path, relative to your web document root, to which to restrict &quot; _
</span><span class="cx">                 &quot;$terms.Bugzilla cookies. Normally this is the URI portion of your URL &quot; _
</span><span class="cx">                 &quot;base. Begin with a / (single slash mark). For instance, if &quot; _
</span><span class="lines">@@ -59,56 +45,4 @@
</span><span class="cx">                 &quot;this parameter to /bugzilla/. Setting it to / will allow &quot; _
</span><span class="cx">                 &quot;all sites served by this web server or virtual host to read &quot; _
</span><span class="cx">                 &quot;$terms.Bugzilla cookies.&quot;,
</span><del>-
-  timezone =&gt; &quot;The timezone that your database server lives in, &quot; _
-              &quot;such as UTC, PDT or JST. If set to '', &quot; _
-              &quot;then the timezone will not be displayed with the timestamps.&quot;,
-
-  utf8 =&gt; &quot;Use UTF-8 (Unicode) encoding for all text in ${terms.Bugzilla}. New &quot; _
-          &quot;installations should set this to true to avoid character encoding &quot; _
-          &quot;problems. &lt;strong&gt;Existing databases should set this to true &quot; _
-          &quot; only after the data has been converted from existing legacy &quot; _
-          &quot; character encodings to UTF-8, using the &quot; _
-          &quot; &lt;kbd&gt;contrib/recode.pl&lt;/kbd&gt; script&lt;/strong&gt;. &lt;br&gt;&lt;br&gt; Note &quot; _
-          &quot; that if you  turn this parameter from &amp;quot;off&amp;quot; to &quot; _
-          &quot; &amp;quot;on&amp;quot;, you must re-run checksetup.pl immediately &quot; _
-          &quot; afterward.&quot;,
-
-  shutdownhtml =&gt; &quot;If this field is non-empty, then $terms.Bugzilla will be completely &quot; _
-                  &quot;disabled and this text will be displayed instead of all the &quot; _
-                  &quot;$terms.Bugzilla pages.&quot;,
-
-  announcehtml =&gt; &quot;If this field is non-empty, then $terms.Bugzilla will &quot; _
-                  &quot;display whatever is in this field at the top of every &quot; _
-                  &quot;HTML page.  The HTML you put in this field is not &quot; _
-                  &quot;wrapped or enclosed in anything; you might want to &quot; _
-                  &quot;wrap it inside a &lt;tt&gt;&amp;lt;div&amp;gt;&lt;/tt&gt;.  Give the div &quot; _
-                  &quot;&lt;em&gt;id=message&lt;/em&gt; to get green text inside a &quot; _
-                  &quot;red box, or &lt;em&gt;class=bz_private&lt;/em&gt; for dark &quot; _
-                  &quot;red on a red background.  Anything defined in &quot; _
-                  &quot;&lt;tt&gt;skins/standard/global.css&lt;/tt&gt; or &quot; _
-                  &quot;&lt;tt&gt;skins/custom/global.css&lt;/tt&gt; will work.  To get &quot; _
-                  &quot;centered text, use &lt;em&gt;style=\&quot;text-align: &quot; _
-                  &quot;center;\&quot;&lt;/em&gt;.&quot;,
-
-  proxy_url =&gt; &quot;$terms.Bugzilla may have to access the web to get notifications about new &quot; _
-               &quot;releases, see the &lt;tt&gt;upgrade_notification&lt;/tt&gt; parameter. In case you are &quot; _
-               &quot;behind a proxy, it may be necessary to enter its URL if the web server &quot; _
-               &quot;group cannot access the HTTP_PROXY environment variable. If you have to &quot; _
-               &quot;authenticate, use the &lt;code&gt;http://user:pass@proxy_url/&lt;/code&gt; syntax.&quot;,
-
-  upgrade_notification =&gt; &quot;&lt;p&gt;$terms.Bugzilla can inform you when a new release is available. &quot; _
-                          &quot;The notification will appear on the $terms.Bugzilla homepage, &quot; _
-                          &quot;for administrators only.&lt;/p&gt;&quot; _
-                          &quot;&lt;ul&gt;&lt;li&gt;'development_snapshot' notifies you about the latest &quot; _
-                          &quot;release on the trunk, i.e. development snapshots.&lt;/li&gt;&quot; _
-                          &quot;&lt;li&gt;'latest_stable_release' notifies you about the most recent release &quot; _
-                          &quot;available on the most recent stable branch. This branch may be &quot; _
-                          &quot;different from the branch your installation is based on.&lt;/li&gt;&quot; _
-                          &quot;&lt;li&gt;'stable_branch_release' notifies you only about new releases &quot; _
-                          &quot;corresponding to the branch your installation is based on. &quot; _
-                          &quot;If you are running a release candidate, you will get &quot; _
-                          &quot;a notification for newer release candidates too.&lt;/li&gt;&quot; _
-                          &quot;&lt;li&gt;'disabled' will never notify you about new releases and no &quot; _
-                          &quot;connection will be established to a remote server.&lt;/li&gt;&lt;/ul&gt;&quot; }
-%]
</del><ins>+} %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminparamsdependencygraphhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/params/dependencygraph.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/params/dependencygraph.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/params/dependencygraph.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -44,6 +44,6 @@
</span><span class="cx">                  The default value is a publicly-accessible webdot server. If you change
</span><span class="cx">                  this value, make certain that the webdot server can read files from your
</span><span class="cx">                  webdot directory. On Apache you do this by editing the .htaccess file,
</span><del>-                 for other systems the needed measures may vary. You can run checksetup.pl
</del><ins>+                 for other systems the needed measures may vary. You can run &lt;kbd&gt;checksetup.pl&lt;/kbd&gt;
</ins><span class="cx">                  to recreate the .htaccess file if it has been lost.&quot;}
</span><del>-%]
</del><span class="cx">\ No newline at end of file
</span><ins>+%]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminparamseditparamshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/params/editparams.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/params/editparams.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/params/editparams.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -27,7 +27,7 @@
</span><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="cx"> 
</span><span class="cx"> [% curpanel = -1 %]
</span><del>-[% panels = panels.sort('sortkey') %]
</del><ins>+[% panels = panels.nsort('sortkey') %]
</ins><span class="cx"> 
</span><span class="cx"> [% FOREACH panel = panels %]
</span><span class="cx">   [% PROCESS &quot;admin/params/${panel.name}.html.tmpl&quot;
</span><span class="lines">@@ -56,7 +56,7 @@
</span><span class="cx">    title = title
</span><span class="cx">    message = message
</span><span class="cx">    style_urls = ['skins/standard/params.css']
</span><del>-   javascript_urls = ['js/params.js']
</del><ins>+   javascript_urls = ['js/params.js', 'js/util.js']
</ins><span class="cx">    doc_section = &quot;parameters.html&quot;
</span><span class="cx"> %]
</span><span class="cx"> 
</span><span class="lines">@@ -73,12 +73,13 @@
</span><span class="cx">         [% FOREACH panel = panels %]
</span><span class="cx">           &lt;tr&gt;
</span><span class="cx">             [% IF panel.current %]
</span><ins>+              [% Hook.process(&quot;current_panel&quot;) %]
</ins><span class="cx">               &lt;td class=&quot;selected_section&quot;&gt;
</span><span class="cx">                 &lt;span title=&quot;[% panel.desc FILTER html %]&quot;&gt;[% panel.title FILTER html %]&lt;/span&gt;
</span><span class="cx">               &lt;/td&gt;
</span><span class="cx">             [% ELSE %]
</span><span class="cx">               &lt;td&gt;
</span><del>-                &lt;a href=&quot;editparams.cgi?section=[% panel.name FILTER url_quote %]&quot;
</del><ins>+                &lt;a href=&quot;editparams.cgi?section=[% panel.name FILTER uri %]&quot;
</ins><span class="cx">                    title=&quot;[% panel.desc FILTER html %]&quot;&gt;[% panel.title FILTER html %]&lt;/a&gt;
</span><span class="cx">               &lt;/td&gt;
</span><span class="cx">             [% END %]
</span><span class="lines">@@ -111,8 +112,7 @@
</span><span class="cx">           &lt;input type=&quot;hidden&quot; name=&quot;section&quot; value=&quot;[% current_panel.name FILTER html %]&quot;&gt;
</span><span class="cx">           &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;save&quot;&gt;
</span><span class="cx">           &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% token FILTER html %]&quot;&gt;
</span><del>-          &lt;input type=&quot;reset&quot; value=&quot;Reset form&quot;&gt;
-          &lt;input type=&quot;submit&quot; name=&quot;action&quot; value=&quot;Save Changes&quot;&gt;
</del><ins>+          &lt;input type=&quot;submit&quot; id=&quot;save-params&quot; value=&quot;Save Changes&quot;&gt;
</ins><span class="cx">         &lt;/form&gt;
</span><span class="cx">       [% END %]
</span><span class="cx">     &lt;/td&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminparamsgeneralhtmltmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/admin/params/general.html.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/params/general.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/params/general.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,86 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Netscape Communications
+  # Corporation. Portions created by Netscape are
+  # Copyright (C) 1998 Netscape Communications Corporation. All
+  # Rights Reserved.
+  #
+  # Contributor(s): Dave Miller &lt;justdave@bugzilla.org&gt;
+  #                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
+  #%]
+
+[% 
+   title = &quot;General&quot;
+   desc = &quot;Miscellaneous general settings that are not required.&quot; 
+%]
+
+[% param_descs = {
+  maintainer =&gt; 
+    &quot;The email address of the person who maintains this installation &quot;
+    _ &quot; of ${terms.Bugzilla}.&quot;,
+
+  docs_urlbase =&gt; 
+    &quot;The URL that is the common initial leading part of all&quot;
+    _ &quot; $terms.Bugzilla documentation URLs. It may be an absolute URL,&quot;
+    _ &quot; or a URL relative to the &lt;tt&gt;urlbase&lt;/tt&gt; parameter. Leave this&quot;
+    _ &quot; empty to suppress links to the documentation.&quot;
+    _ &quot;'%lang%' will be replaced by user's preferred language (if&quot;
+    _ &quot; documentation is available in that language).&quot;,
+
+  utf8 =&gt; 
+    &quot;Use UTF-8 (Unicode) encoding for all text in ${terms.Bugzilla}. New&quot;
+    _ &quot; installations should set this to true to avoid character encoding&quot;
+    _ &quot; problems. &lt;strong&gt;Existing databases should set this to true&quot;
+    _ &quot; only after the data has been converted from existing legacy&quot;
+    _ &quot; character encodings to UTF-8, using the &lt;kbd&gt;contrib/recode.pl&lt;/kbd&gt;&quot;
+    _ &quot; script&lt;/strong&gt;.&quot;
+    _ &quot; &lt;p&gt;Note that if you turn this parameter from &amp;quot;off&amp;quot; to&quot;
+    _ &quot; &amp;quot;on&amp;quot;, you must re-run &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; immediately&quot;
+    _ &quot; afterward.&lt;/p&gt;&quot;,
+
+  shutdownhtml =&gt; 
+    &quot;If this field is non-empty, then $terms.Bugzilla will be completely&quot;
+    _ &quot; disabled and this text will be displayed instead of all the&quot;
+    _ &quot; $terms.Bugzilla pages.&quot;,
+
+  announcehtml =&gt; 
+    &quot;If this field is non-empty, then $terms.Bugzilla will&quot;
+    _ &quot; display whatever is in this field at the top of every&quot;
+    _ &quot; HTML page. The HTML you put in this field is not wrapped or&quot;
+    _ &quot; enclosed in anything. You might want to wrap it inside a&quot;
+    _ &quot;&lt;tt&gt;&amp;lt;div&amp;gt;&lt;/tt&gt;. Give the div &lt;em&gt;id=\&quot;message\&quot;&lt;/em&gt; to get&quot;
+    _ &quot; green text inside a red box, or &lt;em&gt;class=\&quot;bz_private\&quot;&lt;/em&gt; for&quot;
+    _ &quot; dark red on a red background.  Anything defined in &quot;
+    _ &quot; &lt;tt&gt;skins/standard/global.css&lt;/tt&gt; or &lt;tt&gt;skins/custom/global.css&lt;/tt&gt;&quot;
+    _ &quot; will work.  To get centered text, use &lt;em&gt;style=\&quot;text-align: &quot;
+    _  &quot; center;\&quot;&lt;/em&gt;.&quot;,
+
+  upgrade_notification =&gt; 
+    &quot;$terms.Bugzilla can inform you when a new release is available.&quot;
+    _ &quot; The notification will appear on the $terms.Bugzilla homepage,&quot;
+    _ &quot; for administrators only.&quot;
+    _ &quot; &lt;ul&gt;&lt;li&gt;'development_snapshot' notifies you about the development &quot;
+    _ &quot; snapshot that has been released.&lt;/li&gt;&quot;
+    _ &quot; &lt;li&gt;'latest_stable_release' notifies you about the most recent&quot;
+    _ &quot; release available on the most recent stable branch. This branch&quot;
+    _ &quot; may be different from the branch your installation is based on.&lt;/li&gt;&quot;
+    _ &quot; &lt;li&gt;'stable_branch_release' notifies you only about new releases&quot;
+    _ &quot; corresponding to the branch your installation is based on.&quot;
+    _ &quot; If you are running a release candidate, you will get a notification&quot;
+    _ &quot; for newer release candidates too.&lt;/li&gt;&quot;
+    _ &quot; &lt;li&gt;'disabled' will never notify you about new releases and no&quot;
+    _ &quot; connection will be established to a remote server.&lt;/li&gt;&lt;/ul&gt;&quot;
+    _ &quot; &lt;p&gt;Note that if your $terms.Bugzilla server requires a proxy to&quot;
+    _ &quot; access the Internet, you may also need to set the &lt;tt&gt;proxy_url&lt;/tt&gt;&quot;
+    _ &quot; parameter in the Advanced section.&lt;/p&gt;&quot;,
+} %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminparamsgroupsecurityhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/params/groupsecurity.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/params/groupsecurity.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/params/groupsecurity.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -27,12 +27,6 @@
</span><span class="cx">   makeproductgroups =&gt; &quot;If this is on, $terms.Bugzilla will associate $terms.abug group &quot; _
</span><span class="cx">                        &quot;with each product in the database, and use it for querying ${terms.bugs}.&quot;,
</span><span class="cx"> 
</span><del>-  useentrygroupdefault =&gt; &quot;If this is on, $terms.Bugzilla will use product $terms.bug groups &quot; _
-                          &quot;by default to restrict who can enter ${terms.bugs}. If this is on, &quot; _
-                          &quot;users can see any product to which they have entry access in search menus. &quot; _
-                          &quot;If this is off, users can see any product to which they have not &quot; _
-                          &quot;been excluded by a mandatory restriction.&quot;,
-
</del><span class="cx">   chartgroup =&gt; &quot;The name of the group of users who can use the 'New Charts' &quot; _
</span><span class="cx">                 &quot;feature. Administrators should ensure that the public categories &quot; _
</span><span class="cx">                 &quot;and series definitions do not divulge confidential information &quot; _
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminparamsindexhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/params/index.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/params/index.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/params/index.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -16,6 +16,7 @@
</span><span class="cx">   # Rights Reserved.
</span><span class="cx">   #
</span><span class="cx">   # Contributor(s): Frédéric Buclin &lt;LpSolit@gmail.com&gt;
</span><ins>+  #                 Nitish Bezzala &lt;nbezzala@yahoo.com&gt;
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> &lt;p&gt;
</span><span class="lines">@@ -32,11 +33,13 @@
</span><span class="cx">     [% FOREACH panel = panels %]
</span><span class="cx">       [% FOREACH param = panel.param_list.sort('name') %]
</span><span class="cx">         &lt;tr&gt;
</span><del>-          &lt;td&gt;[% param.name FILTER html %]&lt;/td&gt;
</del><span class="cx">           &lt;td&gt;
</span><span class="cx">             &lt;a href=&quot;editparams.cgi?section=
</span><del>-               [%- panel.name FILTER url_quote %]#[% param.name FILTER url_quote %]&quot;&gt;
-               [% panel.title FILTER html %]&lt;/a&gt;
</del><ins>+              [%- panel.name FILTER uri %]#[% param.name FILTER uri %]_desc&quot;&gt;
+              [% param.name FILTER html %]&lt;/a&gt;
+          &lt;/td&gt;    
+          &lt;td&gt;
+            [% panel.title FILTER html %]
</ins><span class="cx">           &lt;/td&gt;
</span><span class="cx">         &lt;/tr&gt;
</span><span class="cx">       [% END %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminparamsmtahtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/params/mta.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/params/mta.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/params/mta.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -45,13 +45,15 @@
</span><span class="cx">   mailfrom =&gt; &quot;The email address of the $terms.Bugzilla mail daemon.  Some email systems &quot; _
</span><span class="cx">               &quot;require this to be a valid email address.&quot;,
</span><span class="cx"> 
</span><del>-  sendmailnow =&gt; &quot;Sites using anything older than version 8.12 of 'sendmail' &quot; _
-                 &quot;can achieve a significant performance increase in the &quot; _
-                 &quot;UI -- at the cost of delaying the sending of mail -- by &quot; _
-                 &quot;disabling this parameter. Sites using 'sendmail' 8.12 or &quot; _
-                 &quot;higher should leave this on, as they will see no benefit from &quot; _
-                 &quot;turning it off. Sites using an MTA other than 'sendmail' &quot; _
-                 &quot;&lt;b&gt;must&lt;/b&gt; leave it on, or no $terms.bug mail will be sent.&quot;,
</del><ins>+  use_mailer_queue =&gt; &quot;In a large $terms.Bugzilla installation, updating&quot;
+    _ &quot; $terms.bugs can be very slow, because $terms.Bugzilla sends all&quot;
+    _ &quot; email at once. If you enable this parameter, $terms.Bugzilla will&quot;
+    _ &quot; queue all mail and then send it in the background. This requires&quot;
+    _ &quot; that you have installed certain Perl modules (as listed by&quot;
+    _ &quot; &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; for this feature), and that you are&quot;
+    _ &quot; running the &lt;code&gt;jobqueue.pl&lt;/code&gt; daemon (otherwise your mail&quot;
+    _ &quot; won't get sent). This affects all mail sent by $terms.Bugzilla,&quot;
+    _ &quot; not just $terms.bug updates.&quot;,
</ins><span class="cx"> 
</span><span class="cx">   smtpserver =&gt; &quot;The SMTP server address (if using SMTP for mail delivery).&quot;,
</span><span class="cx"> 
</span><span class="lines">@@ -66,7 +68,7 @@
</span><span class="cx">                 &quot; $terms.Bugzilla and your SMTP server. You can use this to&quot; _
</span><span class="cx">                 &quot; troubleshoot email problems.&quot;,
</span><span class="cx"> 
</span><del>-  whinedays =&gt; &quot;The number of days that we'll let a $terms.bug sit untouched in a NEW &quot; _
</del><ins>+  whinedays =&gt; &quot;The number of days that we'll let a $terms.bug sit untouched in a CONFIRMED &quot; _
</ins><span class="cx">                &quot;state before our cronjob will whine at the owner.&lt;br&gt; &quot; _
</span><span class="cx">                &quot;Set to 0 to disable whining.&quot;,
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminparamsqueryhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/params/query.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/params/query.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/params/query.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -32,7 +32,7 @@
</span><span class="cx">                                 &lt;/li&gt;
</span><span class="cx">                                 &lt;li&gt;
</span><span class="cx">                                   moderated - quips can be entered, but need to be approved
</span><del>-                                  by an admin before they will be shown.
</del><ins>+                                  by a moderator before they will be shown.
</ins><span class="cx">                                 &lt;/li&gt;
</span><span class="cx">                                 &lt;li&gt;
</span><span class="cx">                                   closed - no new additions to the quips list are allowed.
</span><span class="lines">@@ -51,10 +51,27 @@
</span><span class="cx">                   &quot;access the advanced query page. It's in URL parameter &quot; _
</span><span class="cx">                   &quot;format, which makes it hard to read. Sorry!&quot;,
</span><span class="cx"> 
</span><del>-  quicksearch_comment_cutoff =&gt; &quot;The maximum number of search terms for a QuickSearch &quot; _
-                                &quot;to search comments. If the QuickSearch query contains &quot; _
-                                &quot;more terms than this value, QuickSearch will not search comments.&quot;,
</del><ins>+  search_allow_no_criteria =&gt;
+    &quot;Unless the code explicitly allows all $terms.bugs to be returned, this &quot; _
+    &quot;parameter permits to block the execution of queries with no criteria. &quot; _
+    &quot;When turned off, a query must have some criteria specified to limit &quot; _
+    &quot;the number of $terms.bugs returned to the user. When turned on, a user &quot; _
+    &quot;is allowed to run a query with no criteria and get all $terms.bugs he can &quot; _
+    &quot;see in his list. Turning this parameter on is not recommended on large &quot; _
+    &quot;installations.&quot;,
</ins><span class="cx"> 
</span><del>-  specific_search_allow_empty_words =&gt; &quot;Whether to allow a search on the 'Find a Specific &quot; _
-                                       &quot;Bug' page with an empty 'Words' field.&quot; }
-%]
</del><ins>+  default_search_limit =&gt;
+    &quot;By default, $terms.Bugzilla limits searches done in the web&quot;
+    _ &quot; interface to returning only this many results, for performance&quot;
+    _ &quot; reasons. (This only affects the HTML format of search results--CSV,&quot;
+    _ &quot; XML, and other formats are exempted.) Users can click a link on the&quot;
+    _ &quot; search result page to see all the results.&quot;
+    _ &quot;&lt;p&gt;Usually you should not have to change this--the default value&quot;
+    _ &quot; should be acceptable for almost most installations.&lt;/p&gt;&quot;,
+
+  max_search_results =&gt;
+    &quot;The maximum number of $terms.bugs that a search can&quot;
+    _ &quot; &lt;strong&gt;ever&lt;/strong&gt; return. Tabular and graphical reports&quot;
+    _ &quot; are exempted from this limit, however.&quot;,
+
+} %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminparamsradiushtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/params/radius.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/params/radius.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/params/radius.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -26,13 +26,13 @@
</span><span class="cx">                    &quot;(e.g. &lt;code&gt;radius.company.com&lt;/code&gt;, or &quot; _
</span><span class="cx">                    &quot;&lt;code&gt;radius.company.com:portnum&lt;/code&gt;).&lt;br&gt;&quot; _
</span><span class="cx">                    &quot;Required only if &quot; _
</span><del>-                   &quot;&lt;a href=\&quot;?section=auth#user_verify_class\&quot;&gt;the &quot; _
</del><ins>+                   &quot;&lt;a href=\&quot;?section=auth#user_verify_class_desc\&quot;&gt;the &quot; _
</ins><span class="cx">                    &quot;&lt;code&gt;user_verify_class&lt;/code&gt; parameter&lt;/a&gt; contains &quot; _
</span><span class="cx">                    &quot;&lt;code&gt;RADIUS&lt;/code&gt;.&quot;,
</span><span class="cx"> 
</span><span class="cx">   RADIUS_secret =&gt; &quot;Your RADIUS server's secret.&lt;br&gt;&quot; _
</span><span class="cx">                    &quot;Required only if &quot; _
</span><del>-                   &quot;&lt;a href=\&quot;?section=auth#user_verify_class\&quot;&gt;the &quot; _
</del><ins>+                   &quot;&lt;a href=\&quot;?section=auth#user_verify_class_desc\&quot;&gt;the &quot; _
</ins><span class="cx">                    &quot;&lt;code&gt;user_verify_class&lt;/code&gt; parameter&lt;/a&gt; contains &quot; _
</span><span class="cx">                    &quot;&lt;code&gt;RADIUS&lt;/code&gt;.&quot;,
</span><span class="cx"> 
</span><span class="lines">@@ -40,14 +40,14 @@
</span><span class="cx">                    &quot;data with your RADIUS server. &quot; _
</span><span class="cx">                    &quot;If unspecified, &lt;code&gt;127.0.0.1&lt;/code&gt; will be used.&lt;br&gt;&quot; _
</span><span class="cx">                    &quot;Useful only if &quot; _
</span><del>-                   &quot;&lt;a href=\&quot;?section=auth#user_verify_class\&quot;&gt;the &quot; _
</del><ins>+                   &quot;&lt;a href=\&quot;?section=auth#user_verify_class_desc\&quot;&gt;the &quot; _
</ins><span class="cx">                    &quot;&lt;code&gt;user_verify_class&lt;/code&gt; parameter&lt;/a&gt; &quot; _
</span><span class="cx">                    &quot;contains &lt;code&gt;RADIUS&lt;/code&gt;.&quot;,
</span><span class="cx"> 
</span><span class="cx">   RADIUS_email_suffix =&gt; &quot;Suffix to append to a RADIUS user name to form an &quot; _
</span><span class="cx">                          &quot;e-mail address.&lt;br&gt;&quot; _
</span><span class="cx">                          &quot;Useful only if &quot; _
</span><del>-                         &quot;&lt;a href=\&quot;?section=auth#user_verify_class\&quot;&gt;the &quot; _
</del><ins>+                         &quot;&lt;a href=\&quot;?section=auth#user_verify_class_desc\&quot;&gt;the &quot; _
</ins><span class="cx">                          &quot;&lt;code&gt;user_verify_class&lt;/code&gt; parameter&lt;/a&gt; &quot; _
</span><span class="cx">                          &quot;contains &lt;code&gt;RADIUS&lt;/code&gt;.&quot;,
</span><span class="cx">   }
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminparamsusermatchhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/params/usermatch.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/params/usermatch.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/params/usermatch.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -29,11 +29,8 @@
</span><span class="cx">                      &quot;needs to be selected. This option should not be enabled on &quot; _
</span><span class="cx">                      &quot;sites where there are a large number of users.&quot;,
</span><span class="cx"> 
</span><del>-  usermatchmode =&gt; &quot;Allow match strings to be entered for user names when entering &quot; _
-                   &quot;and editing ${terms.bugs}.&lt;p&gt; &quot; _
-                   &quot;'off' disables matching,&lt;br&gt; &quot; _
-                   &quot;'wildcard' allows only wildcards,&lt;br&gt; &quot; _
-                   &quot;and 'search' allows both wildcards and substring (freetext) matches.&quot;,
</del><ins>+  ajax_user_autocompletion =&gt; &quot;If this option is set, typing characters in a certain user &quot; _
+                              &quot;fields will display a list of matches that can be selected from.&quot;, 
</ins><span class="cx"> 
</span><span class="cx">   maxusermatches =&gt; &quot;Search for no more than this many matches.&lt;br&gt; &quot; _
</span><span class="cx">                     &quot;If set to '1', no users will be displayed on ambiguous matches. &quot; _
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminproductsconfirmdeletehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/products/confirm-delete.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/products/confirm-delete.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/products/confirm-delete.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -31,14 +31,6 @@
</span><span class="cx">   style_urls = ['skins/standard/admin.css']
</span><span class="cx"> %]
</span><span class="cx"> 
</span><del>-[% IF classification %]
-  [% classification_url_part = BLOCK %]&amp;amp;classification=
-    [%- classification.name FILTER url_quote %]
-  [%- END %]
-[% ELSE %]
-  [% classification_url_part = &quot;&quot; %]
-[% END %]
-
</del><span class="cx"> &lt;table border=&quot;1&quot; cellpadding=&quot;4&quot; cellspacing=&quot;0&quot;&gt;
</span><span class="cx">   &lt;tr bgcolor=&quot;#6666FF&quot;&gt;
</span><span class="cx">     &lt;th valign=&quot;top&quot; align=&quot;left&quot;&gt;Field&lt;/th&gt;
</span><span class="lines">@@ -66,8 +58,7 @@
</span><span class="cx">   &lt;tr&gt;
</span><span class="cx">     &lt;td valign=&quot;top&quot;&gt;Product:&lt;/td&gt;
</span><span class="cx">     &lt;td valign=&quot;top&quot;&gt;
</span><del>-      &lt;a href=&quot;editproducts.cgi?product=[% product.name FILTER url_quote %]
-         [%- classification_url_part %]&quot;&gt;
</del><ins>+      &lt;a href=&quot;editproducts.cgi?product=[% product.name FILTER uri %]&quot;&gt;
</ins><span class="cx">         [% product.name FILTER html %]
</span><span class="cx">       &lt;/a&gt;
</span><span class="cx">     &lt;/td&gt;
</span><span class="lines">@@ -102,10 +93,10 @@
</span><span class="cx">   &lt;tr&gt;
</span><span class="cx">     &lt;td&gt;Closed for [% terms.bugs %]:&lt;/td&gt;
</span><span class="cx">     &lt;td&gt;
</span><del>-      [% IF product.disallownew %]
-        closed
-      [% ELSE %]
</del><ins>+      [% IF product.is_active %]
</ins><span class="cx">         open
</span><ins>+      [% ELSE %]
+        closed
</ins><span class="cx">       [% END %]
</span><span class="cx">     &lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><span class="lines">@@ -113,8 +104,7 @@
</span><span class="cx">   &lt;tr&gt;
</span><span class="cx">     &lt;td&gt;
</span><span class="cx">       [% IF product.components.size &gt; 0 %]
</span><del>-        &lt;a href=&quot;editcomponents.cgi?product=[% product.name FILTER url_quote %]
-           [%- classification_url_part %]&quot;
</del><ins>+        &lt;a href=&quot;editcomponents.cgi?product=[% product.name FILTER uri %]&quot;
</ins><span class="cx">            title=&quot;Edit components for product '[% product.name FILTER html %]'&quot;&gt;
</span><span class="cx">           Components:
</span><span class="cx">         &lt;/a&gt;
</span><span class="lines">@@ -148,8 +138,7 @@
</span><span class="cx">   &lt;tr&gt;
</span><span class="cx">     &lt;td&gt;
</span><span class="cx">       [% IF product.versions.size &gt; 0 %]
</span><del>-        &lt;a href=&quot;editversions.cgi?product=[%- product.name FILTER url_quote %]
-           [%- classification_url_part %]&quot;&gt;
</del><ins>+        &lt;a href=&quot;editversions.cgi?product=[%- product.name FILTER uri %]&quot;&gt;
</ins><span class="cx">           Versions:
</span><span class="cx">         &lt;/a&gt;
</span><span class="cx">       [% ELSE %]
</span><span class="lines">@@ -172,8 +161,7 @@
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;td valign=&quot;top&quot;&gt;
</span><span class="cx">         [% IF product.milestones.size &gt; 0 %]
</span><del>-          &lt;a href=&quot;editmilestones.cgi?product=[%- product.name FILTER url_quote %]
-             [%- classification_url_part -%]&quot;&gt;
</del><ins>+          &lt;a href=&quot;editmilestones.cgi?product=[%- product.name FILTER uri %]&quot;&gt;
</ins><span class="cx">             Milestones:
</span><span class="cx">           &lt;/a&gt;
</span><span class="cx">         [% ELSE %]
</span><span class="lines">@@ -196,10 +184,8 @@
</span><span class="cx">     &lt;td&gt;[% terms.Bugs %]:&lt;/td&gt;
</span><span class="cx">     &lt;td&gt;
</span><span class="cx">       [% IF product.bug_count %]
</span><del>-        &lt;a href=&quot;buglist.cgi?product=[%- product.name FILTER url_quote %]
-           [%- classification_url_part %]&quot;
-           title=&quot;List of [% terms.bugs %] for product '
-           [%- product.name FILTER html %]'&quot;&gt;
</del><ins>+        &lt;a href=&quot;buglist.cgi?product=[% product.name FILTER uri %]&quot;
+           title=&quot;List of [% terms.bugs %] for product '[% product.name FILTER html %]'&quot;&gt;
</ins><span class="cx">           [% product.bug_count FILTER html %]
</span><span class="cx">         &lt;/a&gt;
</span><span class="cx">       [% ELSE %]
</span><span class="lines">@@ -262,12 +248,15 @@
</span><span class="cx">   &lt;p&gt;Do you really want to delete this product?&lt;/p&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;form method=&quot;post&quot; action=&quot;editproducts.cgi&quot;&gt;
</span><ins>+    &lt;input type=&quot;checkbox&quot; id=&quot;delete_series&quot; name=&quot;delete_series&quot; value=1&gt;
+    &lt;label for=&quot;delete_series&quot;&gt;
+      Delete all related series (you can also delete them later, by visiting
+      the &lt;a href=&quot;chart.cgi?category=[% product.name FILTER html %]&quot;&gt;New Charts page&lt;/a&gt;.)
+    &lt;/label&gt;&lt;p&gt;
</ins><span class="cx">     &lt;input type=&quot;submit&quot; id=&quot;delete&quot; value=&quot;Yes, delete&quot;&gt;
</span><span class="cx">     &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;delete&quot;&gt;
</span><span class="cx">     &lt;input type=&quot;hidden&quot; name=&quot;product&quot; value=&quot;[% product.name FILTER html %]&quot;&gt;
</span><span class="cx">     &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% token FILTER html %]&quot;&gt;
</span><del>-    &lt;input type=&quot;hidden&quot; name=&quot;classification&quot;
-           value=&quot;[% classification.name FILTER html %]&quot;&gt;
</del><span class="cx">   &lt;/form&gt;
</span><span class="cx"> 
</span><span class="cx"> [% END %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminproductscreatehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/products/create.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/products/create.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/products/create.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -25,14 +25,14 @@
</span><span class="cx"> [% PROCESS global/header.html.tmpl
</span><span class="cx">   title = title
</span><span class="cx">   style_urls = ['skins/standard/admin.css']
</span><ins>+  javascript_urls = ['js/util.js']
</ins><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> [% DEFAULT
</span><del>-  product.votesperuser = &quot;0&quot;,
-  product.maxvotesperbug  = &quot;10000&quot;,
-  product.votestoconfirm = &quot;0&quot;,
</del><ins>+  product.is_active = 1,
</ins><span class="cx">   version = &quot;unspecified&quot;,
</span><del>-  product.defaultmilestone = &quot;---&quot;
</del><ins>+  product.defaultmilestone = constants.DEFAULT_MILESTONE
+  product.allows_unconfirmed = 1
</ins><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> &lt;form method=&quot;post&quot; action=&quot;editproducts.cgi&quot;&gt;
</span><span class="lines">@@ -48,13 +48,13 @@
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th align=&quot;right&quot;&gt;Create chart datasets for this product:&lt;/th&gt;
</span><del>-      &lt;td&gt;&lt;input type=&quot;checkbox&quot; name=&quot;createseries&quot; value=&quot;1&quot;&gt;&lt;/td&gt;
</del><ins>+      &lt;td&gt;
+        &lt;input type=&quot;checkbox&quot; name=&quot;createseries&quot; value=&quot;1&quot; checked=&quot;checked&quot;&gt;
+      &lt;/td&gt;
</ins><span class="cx">     &lt;/tr&gt;
</span><span class="cx">   &lt;/table&gt;
</span><span class="cx"> 
</span><del>-  &lt;input type=&quot;submit&quot; value=&quot;Add&quot;&gt;
-  &lt;input type=&quot;hidden&quot; name=&quot;subcategory&quot; value=&quot;-All-&quot;&gt;
-  &lt;input type=&quot;hidden&quot; name=&quot;open_name&quot;   value=&quot;All Open&quot;&gt;
</del><ins>+  &lt;input type=&quot;submit&quot; id=&quot;add-product&quot; value=&quot;Add&quot;&gt;
</ins><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;new&quot;&gt;
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% token FILTER html %]&quot;&gt;
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;classification&quot;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminproductseditcommonhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/products/edit-common.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/products/edit-common.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/products/edit-common.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -45,12 +45,6 @@
</span><span class="cx"> 
</span><span class="cx"> [% IF Param('usetargetmilestone') -%]
</span><span class="cx">   &lt;tr&gt;
</span><del>-    &lt;th align=&quot;right&quot;&gt;URL describing milestones for this product:&lt;/th&gt;
-    &lt;td&gt;&lt;input type=&quot;text&quot; size=&quot;64&quot; maxlength=&quot;255&quot; name=&quot;milestoneurl&quot;
-               value=&quot;[% product.milestoneurl FILTER html %]&quot;&gt;
-    &lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
</del><span class="cx">     &lt;th align=&quot;right&quot;&gt;Default milestone:&lt;/th&gt;
</span><span class="cx">     &lt;td&gt;
</span><span class="cx">       [% IF product.milestones.size %]
</span><span class="lines">@@ -70,45 +64,20 @@
</span><span class="cx"> [% END %]
</span><span class="cx">     
</span><span class="cx"> &lt;tr&gt;
</span><del>-  &lt;th align=&quot;right&quot;&gt;Closed for [% terms.bug %] entry:&lt;/th&gt;
-  &lt;td&gt;&lt;input type=&quot;checkbox&quot; name=&quot;disallownew&quot; value=&quot;1&quot;
-       [% IF product.disallownew == &quot;1&quot; %]
-             checked=&quot;checked&quot;[% END %]&gt;
</del><ins>+  &lt;th align=&quot;right&quot;&gt;Open for [% terms.bug %] entry:&lt;/th&gt;
+  &lt;td&gt;&lt;input type=&quot;checkbox&quot; name=&quot;is_active&quot; value=&quot;1&quot;
+       [% ' checked=&quot;checked&quot;' IF product.is_active %]&gt;
</ins><span class="cx">   &lt;/td&gt;
</span><span class="cx"> &lt;/tr&gt;
</span><del>-
-[% IF !Param('usevotes') %]
-&lt;tr class=&quot;param_disabled&quot;&gt;
-  &lt;td colspan=&quot;2&quot;
-      style=&quot;font-family: arial; font-style: italic; font-size: 0.7em; text-align: center;&quot;&gt;
-    The 'usevotes' parameter is currently 'off'. These voting
-    settings will take effect when the parameter is next enabled.&lt;/td&gt;
-&lt;/tr&gt;
-[% END %]
-&lt;tr [% IF !Param('usevotes') %]class=&quot;param_disabled&quot; [% END %]&gt;
-  &lt;th align=&quot;right&quot;&gt;Maximum votes per person:&lt;/th&gt;
-  &lt;td&gt;&lt;input size=&quot;5&quot; maxlength=&quot;5&quot; name=&quot;votesperuser&quot; 
-             value=&quot;[% product.votesperuser FILTER html %]&quot;&gt;
-  &lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr [% IF !Param('usevotes') %]class=&quot;param_disabled&quot; [% END %]&gt;
</del><ins>+&lt;tr&gt;
</ins><span class="cx">   &lt;th align=&quot;right&quot;&gt;
</span><del>-    Maximum votes a person can put on a single [% terms.bug %]:
</del><ins>+    &lt;label for=&quot;allows_unconfirmed&quot;&gt;Enable the
+      [%+ display_value('bug_status', 'UNCONFIRMED') FILTER html %] status
+      in this product:&lt;/label&gt;
</ins><span class="cx">   &lt;/th&gt;
</span><del>-  &lt;td&gt;&lt;input size=&quot;5&quot; maxlength=&quot;5&quot; name=&quot;maxvotesperbug&quot; 
-             value=&quot;[% product.maxvotesperbug FILTER html %]&quot;&gt;
</del><ins>+  &lt;td&gt;&lt;input type=&quot;checkbox&quot; id=&quot;allows_unconfirmed&quot; name=&quot;allows_unconfirmed&quot;
+             [% ' checked=&quot;checked&quot;' IF product.allows_unconfirmed %]&gt;
</ins><span class="cx">   &lt;/td&gt;
</span><span class="cx"> &lt;/tr&gt;
</span><del>-&lt;tr [% IF !Param('usevotes') %]class=&quot;param_disabled&quot; [% END %]&gt;
-  &lt;th align=&quot;right&quot;&gt;
-    Confirmation threshold:
-  &lt;/th&gt;
-  &lt;td&gt;
-    Enter the number of votes [% terms.abug %] in this product needs to
-    automatically get out of the
-    &lt;a href=&quot;page.cgi?id=fields.html#status&quot;&gt;[% get_status(&quot;UNCONFIRMED&quot;) FILTER html %]&lt;/a&gt;
-    state.&lt;br&gt;
-    &lt;input size=&quot;5&quot; maxlength=&quot;5&quot; name=&quot;votestoconfirm&quot; 
-           value=&quot;[% product.votestoconfirm FILTER html %]&quot;&gt;
-  &lt;/td&gt;
-&lt;/tr&gt;
</del><ins>+
+[% Hook.process('rows') %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminproductsedithtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/products/edit.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/products/edit.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/products/edit.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -29,6 +29,7 @@
</span><span class="cx"> [% PROCESS global/header.html.tmpl
</span><span class="cx">   title = title
</span><span class="cx">   style_urls = ['skins/standard/admin.css']
</span><ins>+  javascript_urls = ['js/util.js']
</ins><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> [% group_control = {${constants.CONTROLMAPNA}        =&gt; 'NA',
</span><span class="lines">@@ -44,7 +45,7 @@
</span><span class="cx"> 
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th align=&quot;right&quot; valign=&quot;top&quot;&gt;
</span><del>-        &lt;a href=&quot;editcomponents.cgi?product=[% product.name FILTER url_quote %]&quot;&gt;
</del><ins>+        &lt;a href=&quot;editcomponents.cgi?product=[% product.name FILTER uri %]&quot;&gt;
</ins><span class="cx">         Edit components:
</span><span class="cx">         &lt;/a&gt;
</span><span class="cx">       &lt;/th&gt;
</span><span class="lines">@@ -66,7 +67,7 @@
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th align=&quot;right&quot; valign=&quot;top&quot;&gt;
</span><del>-        &lt;a href=&quot;editversions.cgi?product=[% product.name FILTER url_quote %]&quot;&gt;Edit
</del><ins>+        &lt;a href=&quot;editversions.cgi?product=[% product.name FILTER uri %]&quot;&gt;Edit
</ins><span class="cx"> versions:&lt;/a&gt;
</span><span class="cx">       &lt;/th&gt;
</span><span class="cx">       &lt;td&gt;
</span><span class="lines">@@ -83,7 +84,7 @@
</span><span class="cx">     [% IF Param('usetargetmilestone') %]
</span><span class="cx">       &lt;tr&gt;
</span><span class="cx">         &lt;th align=&quot;right&quot; valign=&quot;top&quot;&gt;
</span><del>-          &lt;a href=&quot;editmilestones.cgi?product=[% product.name FILTER url_quote %]&quot;&gt;
</del><ins>+          &lt;a href=&quot;editmilestones.cgi?product=[% product.name FILTER uri %]&quot;&gt;
</ins><span class="cx">           Edit milestones:&lt;/a&gt;
</span><span class="cx">         &lt;/th&gt;
</span><span class="cx">         &lt;td&gt;
</span><span class="lines">@@ -101,14 +102,13 @@
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th align=&quot;right&quot; valign=&quot;top&quot;&gt;
</span><span class="cx">         &lt;a href=&quot;editproducts.cgi?action=editgroupcontrols&amp;product=
</span><del>-          [%- product.name FILTER url_quote %]&amp;classification=
-          [%- classification.name FILTER url_quote %]&quot;&gt;
</del><ins>+          [%- product.name FILTER uri %]&quot;&gt;
</ins><span class="cx">           Edit Group Access Controls:
</span><span class="cx">         &lt;/a&gt;
</span><span class="cx">       &lt;/th&gt;
</span><span class="cx">       &lt;td&gt;
</span><span class="cx">         [% IF product.group_controls.size %]
</span><del>-          [% FOREACH g = product.group_controls.values %]
</del><ins>+          [% FOREACH g = product.group_controls.values.sort(&quot;name&quot;) %]
</ins><span class="cx">             &lt;b&gt;[% g.group.name FILTER html %]:&lt;/b&gt;&amp;nbsp;
</span><span class="cx">             [% IF g.group.isactive %]
</span><span class="cx">               [% group_control.${g.membercontrol} FILTER html %]/
</span><span class="lines">@@ -130,7 +130,7 @@
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th align=&quot;right&quot;&gt;[% terms.Bugs %]:&lt;/th&gt;
</span><del>-      &lt;td&gt;&lt;a href=&quot;buglist.cgi?product=[% product.name FILTER url_quote %]&quot;&gt;
</del><ins>+      &lt;td&gt;&lt;a href=&quot;buglist.cgi?product=[% product.name FILTER uri %]&quot;&gt;
</ins><span class="cx">             [% product.bug_count FILTER html %]&lt;/a&gt;&lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">   &lt;/table&gt;
</span><span class="lines">@@ -139,9 +139,7 @@
</span><span class="cx">         value=&quot;[% product.name FILTER html %]&quot;&gt;
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;update&quot;&gt;
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% token FILTER html %]&quot;&gt;
</span><del>-  &lt;input type=&quot;hidden&quot; name=&quot;classification&quot;
-         value=&quot;[% classification.name FILTER html %]&quot;&gt;
-  &lt;input type=&quot;submit&quot; name=&quot;submit&quot; value=&quot;Save Changes&quot;&gt;
</del><ins>+  &lt;input type=&quot;submit&quot; id=&quot;update-product&quot; value=&quot;Save Changes&quot;&gt;
</ins><span class="cx"> &lt;/form&gt;
</span><span class="cx">   
</span><span class="cx"> [% PROCESS &quot;admin/products/footer.html.tmpl&quot;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminproductsfooterhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/products/footer.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/products/footer.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/products/footer.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -30,10 +30,10 @@
</span><span class="cx"> 
</span><span class="cx"> [% IF Param('useclassification') &amp;&amp; classification %]
</span><span class="cx">   [% classification_url_part = BLOCK %]&amp;amp;classification=
</span><del>-     [%- classification.name FILTER url_quote %]
</del><ins>+     [%- classification.name FILTER uri %]
</ins><span class="cx">   [% END %]
</span><span class="cx">   [% classification_url_part_start = BLOCK %]classification=
</span><del>-     [%- classification.name FILTER url_quote %]
</del><ins>+     [%- classification.name FILTER uri %]
</ins><span class="cx">   [% END %]
</span><span class="cx">   [% classification_text = BLOCK %] 
</span><span class="cx">     of classification '[% classification.name FILTER html %]'
</span><span class="lines">@@ -61,9 +61,7 @@
</span><span class="cx">   Edit product &lt;a 
</span><span class="cx">   title=&quot;Edit Product '[% product.name FILTER html %]' 
</span><span class="cx">          [%- classification_text %]&quot;
</span><del>-  href=&quot;editproducts.cgi?action=edit&amp;amp;product=
-        [%- product.name FILTER url_quote %]
-        [%- classification_url_part %]&quot;&gt;
</del><ins>+  href=&quot;editproducts.cgi?action=edit&amp;amp;product=[% product.name FILTER uri %]&quot;&gt;
</ins><span class="cx">         '[% product.name FILTER html %]'&lt;/a&gt;.
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="lines">@@ -77,7 +75,8 @@
</span><span class="cx"> 
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><del>-[% IF Param('useclassification') &amp;&amp; classification %]
</del><ins>+[% IF Param('useclassification') &amp;&amp; classification
+      &amp;&amp; user.in_group('editclassifications') %]
</ins><span class="cx">   Edit classification &lt;a href=&quot;editclassifications.cgi?action=edit
</span><span class="cx">     [%- classification_url_part %]&quot;&gt;'
</span><span class="cx">     [%- classification.name FILTER html %]'&lt;/a&gt;.
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminproductsgroupcontroledithtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/products/groupcontrol/edit.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/products/groupcontrol/edit.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/products/groupcontrol/edit.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -31,8 +31,6 @@
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;updategroupcontrols&quot;&gt;
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;product&quot; value=&quot;[% product.name FILTER html %]&quot;&gt;
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% token FILTER html %]&quot;&gt;
</span><del>-  &lt;input type=&quot;hidden&quot; name=&quot;classification&quot; 
-         value=&quot;[% classification.name FILTER html %]&quot;&gt;
</del><span class="cx"> 
</span><span class="cx">   &lt;table id=&quot;form&quot; cellspacing=&quot;0&quot; cellpadding=&quot;4&quot; border=&quot;1&quot;&gt;
</span><span class="cx">     &lt;tr bgcolor=&quot;#6666ff&quot;&gt;
</span><span class="lines">@@ -46,23 +44,23 @@
</span><span class="cx">       &lt;th&gt;editbugs&lt;/th&gt;
</span><span class="cx">       &lt;th&gt;[% terms.Bugs %]&lt;/th&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><del>-    [% FOREACH group = groups %]
-      [% IF group.isactive == 0 AND group.bugcount &gt; 0 %]
</del><ins>+    [% FOREACH group = product.group_controls(1).values.sort(&quot;name&quot;) %]
+      [% IF !group.group.isactive AND group.bug_count %]
</ins><span class="cx">         &lt;tr bgcolor=&quot;#bbbbbb&quot;&gt;
</span><span class="cx">           &lt;td&gt;
</span><del>-            [% group.name FILTER html %]
</del><ins>+            [% group.group.name FILTER html %]
</ins><span class="cx">           &lt;/td&gt;
</span><span class="cx">           &lt;td align=&quot;center&quot; colspan=7&gt;
</span><span class="cx">             Disabled
</span><span class="cx">           &lt;/td&gt;
</span><span class="cx">           &lt;td&gt;
</span><del>-            [% group.bugcount %]
</del><ins>+            [% group.bug_count FILTER html %]
</ins><span class="cx">           &lt;/td&gt;
</span><span class="cx">         &lt;tr&gt;
</span><del>-      [% ELSIF group.isactive != 0 %]
</del><ins>+      [% ELSIF group.group.is_active %]
</ins><span class="cx">         &lt;tr&gt;
</span><span class="cx">           &lt;td&gt;
</span><del>-            [% group.name FILTER html %]
</del><ins>+            [% group.group.name FILTER html %]
</ins><span class="cx">           &lt;/td&gt;
</span><span class="cx">           &lt;td&gt;
</span><span class="cx">             &lt;input type=checkbox value=1 name=entry_[% group.id %]
</span><span class="lines">@@ -70,48 +68,48 @@
</span><span class="cx">           &lt;/td&gt;
</span><span class="cx">           &lt;td&gt;
</span><span class="cx">             &lt;select name=&quot;membercontrol_[% group.id %]&quot;&gt;
</span><del>-              &lt;option value=[% const.CONTROLMAPNA %]
</del><ins>+              &lt;option value=[% constants.CONTROLMAPNA %]
</ins><span class="cx">                 [% &quot; selected=\&quot;selected\&quot;&quot;
</span><del>-                  IF group.membercontrol == const.CONTROLMAPNA %]
</del><ins>+                  IF group.membercontrol == constants.CONTROLMAPNA %]
</ins><span class="cx">                 &gt;NA
</span><span class="cx">               &lt;/option&gt;
</span><del>-              &lt;option value=[% const.CONTROLMAPSHOWN %]
</del><ins>+              &lt;option value=[% constants.CONTROLMAPSHOWN %]
</ins><span class="cx">                 [% &quot; selected=\&quot;selected\&quot;&quot;
</span><del>-                  IF group.membercontrol == const.CONTROLMAPSHOWN %]
</del><ins>+                  IF group.membercontrol == constants.CONTROLMAPSHOWN %]
</ins><span class="cx">                 &gt;Shown
</span><span class="cx">               &lt;/option&gt;
</span><del>-              &lt;option value=[% const.CONTROLMAPDEFAULT %]
</del><ins>+              &lt;option value=[% constants.CONTROLMAPDEFAULT %]
</ins><span class="cx">                 [% &quot; selected=\&quot;selected\&quot;&quot;
</span><del>-                  IF group.membercontrol == const.CONTROLMAPDEFAULT %]
</del><ins>+                  IF group.membercontrol == constants.CONTROLMAPDEFAULT %]
</ins><span class="cx">                 &gt;Default
</span><span class="cx">               &lt;/option&gt;
</span><del>-              &lt;option value=[% const.CONTROLMAPMANDATORY %]
</del><ins>+              &lt;option value=[% constants.CONTROLMAPMANDATORY %]
</ins><span class="cx">                 [% &quot; selected=\&quot;selected\&quot;&quot;
</span><del>-                  IF group.membercontrol == const.CONTROLMAPMANDATORY %]
</del><ins>+                  IF group.membercontrol == constants.CONTROLMAPMANDATORY %]
</ins><span class="cx">                 &gt;Mandatory
</span><span class="cx">               &lt;/option&gt;
</span><span class="cx">             &lt;/select&gt;
</span><span class="cx">           &lt;/td&gt;
</span><span class="cx">           &lt;td&gt;
</span><span class="cx">             &lt;select name=&quot;othercontrol_[% group.id %]&quot;&gt;
</span><del>-              &lt;option value=[% const.CONTROLMAPNA %]
</del><ins>+              &lt;option value=[% constants.CONTROLMAPNA %]
</ins><span class="cx">                 [% &quot; selected=\&quot;selected\&quot;&quot;
</span><del>-                  IF group.othercontrol == const.CONTROLMAPNA %]
</del><ins>+                  IF group.othercontrol == constants.CONTROLMAPNA %]
</ins><span class="cx">                 &gt;NA
</span><span class="cx">               &lt;/option&gt;
</span><del>-              &lt;option value=[% const.CONTROLMAPSHOWN %]
</del><ins>+              &lt;option value=[% constants.CONTROLMAPSHOWN %]
</ins><span class="cx">                 [% &quot; selected=\&quot;selected\&quot;&quot;
</span><del>-                  IF group.othercontrol == const.CONTROLMAPSHOWN %]
</del><ins>+                  IF group.othercontrol == constants.CONTROLMAPSHOWN %]
</ins><span class="cx">                 &gt;Shown
</span><span class="cx">               &lt;/option&gt;
</span><del>-              &lt;option value=[% const.CONTROLMAPDEFAULT %]
</del><ins>+              &lt;option value=[% constants.CONTROLMAPDEFAULT %]
</ins><span class="cx">                 [% &quot; selected=\&quot;selected\&quot;&quot;
</span><del>-                  IF group.othercontrol == const.CONTROLMAPDEFAULT %]
</del><ins>+                  IF group.othercontrol == constants.CONTROLMAPDEFAULT %]
</ins><span class="cx">                 &gt;Default
</span><span class="cx">               &lt;/option&gt;
</span><del>-              &lt;option value=[% const.CONTROLMAPMANDATORY %]
</del><ins>+              &lt;option value=[% constants.CONTROLMAPMANDATORY %]
</ins><span class="cx">                 [% &quot; selected=\&quot;selected\&quot;&quot;
</span><del>-                  IF group.othercontrol == const.CONTROLMAPMANDATORY %]
</del><ins>+                  IF group.othercontrol == constants.CONTROLMAPMANDATORY %]
</ins><span class="cx">                 &gt;Mandatory
</span><span class="cx">               &lt;/option&gt;
</span><span class="cx">             &lt;/select&gt;
</span><span class="lines">@@ -133,7 +131,7 @@
</span><span class="cx">             [% &quot; checked=\&quot;checked\&quot;&quot; IF group.editbugs %]&gt;
</span><span class="cx">           &lt;/td&gt;
</span><span class="cx">           &lt;td&gt;
</span><del>-            [% group.bugcount %]
</del><ins>+            [% group.bug_count || 0 FILTER html %]
</ins><span class="cx">           &lt;/td&gt;
</span><span class="cx">         &lt;/tr&gt;
</span><span class="cx">       [% END %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminproductsgroupcontrolupdatedhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/products/groupcontrol/updated.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/products/groupcontrol/updated.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/products/groupcontrol/updated.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -15,10 +15,8 @@
</span><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [%# INTERFACE:
</span><del>-  #      removed_na: array of hashes; groups not applicable for the product.  
-  # added_mandatory: array of hashes; groups mandatory for the product.  
-  #  classification: Bugzilla::Classification object;  product classification.
-  #         product: Bugzilla::Product object; the product.
</del><ins>+  # product: Bugzilla::Product object; the product.
+  # changes: Hashref with changes made to the product group controls.
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [% title = BLOCK %]
</span><span class="lines">@@ -29,16 +27,16 @@
</span><span class="cx">   title = title
</span><span class="cx"> %]
</span><span class="cx"> &lt;p&gt;
</span><del>-[% IF removed_na.size &gt; 0 %]
-  [% FOREACH g = removed_na %]
</del><ins>+[% IF changes._group_controls.now_na.size %]
+  [% FOREACH g = changes._group_controls.now_na %]
</ins><span class="cx">     Removing [% terms.bugs %] from group '[% g.name FILTER html %]' which
</span><span class="cx">     no longer applies to this product&lt;p&gt;
</span><span class="cx">     [% g.bug_count FILTER html %] [%+ terms.bugs %] removed&lt;p&gt;
</span><span class="cx">   [% END %]
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><del>-[% IF added_mandatory.size &gt; 0 %]
-  [% FOREACH g = added_mandatory %]
</del><ins>+[% IF changes._group_controls.now_mandatory.size %]
+  [% FOREACH g = changes._group_controls.now_mandatory %]
</ins><span class="cx">     Adding [% terms.bugs %] to group '[% g.name FILTER html %]' which is 
</span><span class="cx">     mandatory for this product&lt;p&gt;
</span><span class="cx">     [% g.bug_count FILTER html %] [%+ terms.bugs %] added&lt;p&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminproductslistclassificationshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/products/list-classifications.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/products/list-classifications.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/products/list-classifications.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -27,18 +27,11 @@
</span><span class="cx">   title = &quot;Select Classification&quot;
</span><span class="cx"> %]
</span><span class="cx"> 
</span><del>-[% edit_contentlink = BLOCK %]
-  editproducts.cgi?classification=%%name%%
-[% END %]
-[% add_contentlink = BLOCK %]
-  editproducts.cgi?action=add&amp;amp;classification=%%name%%
-[% END %]
-
</del><span class="cx"> [% columns = [
</span><span class="cx">      { 
</span><span class="cx">        name =&gt; &quot;name&quot;
</span><span class="cx">        heading =&gt; &quot;Edit products of...&quot;
</span><del>-       contentlink =&gt; edit_contentlink
</del><ins>+       contentlink =&gt; 'editproducts.cgi?classification=%%name%%'
</ins><span class="cx">      },
</span><span class="cx">      { 
</span><span class="cx">        name =&gt; &quot;description&quot;
</span><span class="lines">@@ -57,10 +50,12 @@
</span><span class="cx">   [% columns.push({
</span><span class="cx">        heading =&gt; &quot;Action...&quot;
</span><span class="cx">        content =&gt; &quot;Add product&quot;
</span><del>-       contentlink =&gt; add_contentlink })
</del><ins>+       contentlink =&gt; 'editproducts.cgi?action=add&amp;amp;classification=%%name%%' })
</ins><span class="cx">   %]
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><ins>+[% Hook.process('before_table') %]
+
</ins><span class="cx"> [% PROCESS admin/table.html.tmpl
</span><span class="cx">      columns = columns
</span><span class="cx">      data = classifications
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminproductslisthtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/products/list.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/products/list.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/products/list.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -26,7 +26,7 @@
</span><span class="cx"> 
</span><span class="cx"> [% IF classification %]
</span><span class="cx">   [% classification_url_part = BLOCK %]&amp;amp;classification=
</span><del>-    [%- classification.name FILTER url_quote %]
</del><ins>+    [%- classification.name FILTER uri %]
</ins><span class="cx">   [%- END %]
</span><span class="cx">   [% classification_title = BLOCK %] 
</span><span class="cx">     in classification '[% classification.name FILTER html %]'
</span><span class="lines">@@ -37,23 +37,11 @@
</span><span class="cx">   title = &quot;Select product $classification_title&quot;
</span><span class="cx"> %]
</span><span class="cx"> 
</span><del>-[% edit_contentlink = BLOCK %]
-  editproducts.cgi?action=edit&amp;amp;product=%%name%%
-  [%- classification_url_part %]
-[% END %]
-[% delete_contentlink = BLOCK %]
-  editproducts.cgi?action=del&amp;amp;product=%%name%%
-  [%- classification_url_part %]
-[% END %]
-[% bug_count_contentlink = BLOCK %]buglist.cgi?product=%%name%%
-  [%- classification_url_part %][% END %]
-
-
</del><span class="cx"> [% columns = [
</span><span class="cx">      { 
</span><span class="cx">        name =&gt; &quot;name&quot;
</span><span class="cx">        heading =&gt; &quot;Edit product...&quot;
</span><del>-       contentlink =&gt; edit_contentlink
</del><ins>+       contentlink =&gt; 'editproducts.cgi?action=edit&amp;amp;product=%%name%%'
</ins><span class="cx">      },
</span><span class="cx">      { 
</span><span class="cx">        name =&gt; &quot;description&quot;
</span><span class="lines">@@ -61,25 +49,11 @@
</span><span class="cx">        allow_html_content =&gt; 1
</span><span class="cx">      },
</span><span class="cx">      { 
</span><del>-       name =&gt; &quot;disallow_new&quot;
</del><ins>+       name =&gt; &quot;is_active&quot;
</ins><span class="cx">        heading =&gt; &quot;Open For New $terms.Bugs&quot;
</span><ins>+       yesno_field =&gt; 1
</ins><span class="cx">      },
</span><del>-     { 
-       name =&gt; &quot;votesperuser&quot;
-       heading =&gt; &quot;Votes Per User&quot;
-       align =&gt; 'right'
-     },
-     { 
-       name =&gt; &quot;maxvotesperbug&quot;
-       heading =&gt; &quot;Maximum Votes Per $terms.Bug&quot;
-       align =&gt; 'right'
-     },
-     { 
-       name =&gt; &quot;votestoconfirm&quot;
-       heading =&gt; &quot;Votes To Confirm&quot;
-       align =&gt; 'right'
-     } ]
-%]
</del><ins>+] %]
</ins><span class="cx"> 
</span><span class="cx"> [% IF showbugcounts %]
</span><span class="cx"> 
</span><span class="lines">@@ -87,7 +61,7 @@
</span><span class="cx">        name =&gt; &quot;bug_count&quot;
</span><span class="cx">        heading =&gt; &quot;$terms.Bug Count&quot;
</span><span class="cx">        align =&gt; 'right'
</span><del>-       contentlink =&gt; bug_count_contentlink
</del><ins>+       contentlink =&gt; 'buglist.cgi?product=%%name%%'
</ins><span class="cx">      })
</span><span class="cx">   %]
</span><span class="cx"> 
</span><span class="lines">@@ -96,23 +70,11 @@
</span><span class="cx"> [% columns.push({
</span><span class="cx">        heading =&gt; &quot;Action&quot;
</span><span class="cx">        content =&gt; &quot;Delete&quot;
</span><del>-       contentlink =&gt; delete_contentlink
</del><ins>+       contentlink =&gt; 'editproducts.cgi?action=del&amp;amp;product=%%name%%'
</ins><span class="cx">      })
</span><span class="cx"> %]
</span><span class="cx"> 
</span><del>-[% overrides.disallow_new = [ {
-     match_value =&gt; &quot;1&quot;
-     match_field =&gt; 'disallow_new'
-     override_content =&gt; 1
-     content =&gt; &quot;No&quot;
-   },
-   {
-     match_value =&gt; 0
-     match_field =&gt; 'disallow_new'
-     override_content =&gt; 1
-     content =&gt; &quot;Yes&quot;
-   }]
-%] 
</del><ins>+[% Hook.process('before_table') %]
</ins><span class="cx"> 
</span><span class="cx"> [% PROCESS admin/table.html.tmpl
</span><span class="cx">      columns = columns
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminproductsupdatedhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/products/updated.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/products/updated.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/products/updated.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -16,38 +16,18 @@
</span><span class="cx">   # Rights Reserved.
</span><span class="cx">   #
</span><span class="cx">   # Contributor(s): Gavin Shelley &lt;bugzilla@chimpychompy.org&gt;
</span><ins>+  #                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [%# INTERFACE:
</span><del>-  #
-  # old_product : Bugzilla::Product Object; old product.
</del><span class="cx">   # product : Bugzilla::Product Object; new product.
</span><del>-  #
</del><span class="cx">   # classification: Bugzilla::Classification Object; The product classification (may be empty or missing)
</span><del>-  #
-  # checkvotes: boolean; is true if vote related fields have changed. If so, 
-  #             then the following parameters will be specified:
-  #
-  # toomanyvotes: list of hashes, each one with an 'id' and a 'name' hash key
-  #               detailing the bug id and the username of users who had too
-  #               many votes for a bug
-  #
-  # toomanytotalvotes: list of hashes, each one with an 'id' and a 'name' hash key
-  #                    detailing the bug id and the username of users who had
-  #                    too many total votes
-  #
-  # confirmedbugs: list of bug ids, which were confirmed by votes
-  #
-  # changer: string; login of the user making the changes, used for mailing
-  #          bug changes if necessary
-  #
</del><ins>+  # changes: hashref with all changes made to the product. Each key is an edited field,
+  #          and its value is an arrayref of the form [old values, new values].
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [% IF classification %]
</span><del>-  [% classification_url_part = BLOCK %]&amp;amp;classification=
-     [%- classification.name FILTER url_quote %]
-  [% END %]
-  [% classification_text = BLOCK %] 
</del><ins>+  [% classification_text = BLOCK %]
</ins><span class="cx">     of classification '[% classification.name FILTER html %]'
</span><span class="cx">   [% END %]
</span><span class="cx"> [% END %]
</span><span class="lines">@@ -58,152 +38,68 @@
</span><span class="cx">   title = title
</span><span class="cx">   style_urls = ['skins/standard/admin.css']
</span><span class="cx"> %]
</span><del>-[% updated = 0 %]
</del><span class="cx"> 
</span><del>-[% IF product.name != old_product.name %]
</del><ins>+[% PROCESS &quot;global/field-descs.none.tmpl&quot; %]
+
+[% IF changes.name.defined %]
</ins><span class="cx">   &lt;p&gt;
</span><del>-  Updated product name from '[% old_product.name FILTER html %]' to 
-  &lt;a href=&quot;editproducts.cgi?action=edit&amp;amp;product=
-  [%- product.name FILTER url_quote %]
-  [%- classification_url_part FILTER none %]&quot;&gt;[% product.name FILTER html %]&lt;/a&gt;.
</del><ins>+  Updated product name from '[% changes.name.0 FILTER html %]' to
+  '&lt;a href=&quot;editproducts.cgi?action=edit&amp;amp;product=
+  [%- product.name FILTER uri %]&quot;&gt;[% product.name FILTER html %]&lt;/a&gt;'.
</ins><span class="cx">   &lt;/p&gt;
</span><del>-  [% updated = 1 %]
</del><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-[% IF product.description != old_product.description %]
</del><ins>+[% IF changes.description.defined %]
</ins><span class="cx">   &lt;p&gt;
</span><span class="cx">     Updated description to:
</span><span class="cx">   &lt;/p&gt;
</span><span class="cx">   &lt;p style=&quot;margin: 1em 3em 1em 3em&quot;&gt;[% product.description FILTER html_light %]&lt;/p&gt;
</span><del>-  [% updated = 1 %]
</del><span class="cx"> [% END %]
</span><span class="cx"> 
</span><del>-[% IF product.disallow_new != old_product.disallow_new %]
</del><ins>+[% IF changes.isactive.defined %]
</ins><span class="cx">   &lt;p&gt;
</span><span class="cx">   Product is now
</span><del>-  [% IF product.disallow_new %]
-    closed to
</del><ins>+  [% IF product.is_active %]
+    open for
</ins><span class="cx">   [% ELSE %]
</span><del>-    open for 
</del><ins>+    closed to 
</ins><span class="cx">   [% END %]
</span><span class="cx">   new [% terms.bugs %].
</span><span class="cx">   &lt;/p&gt;
</span><del>-  [% updated = 1 %]
</del><span class="cx"> [% END %]
</span><span class="cx"> 
</span><del>-[% IF product.milestone_url != old_product.milestone_url %]
</del><ins>+[% IF changes.defaultmilestone.defined %]
</ins><span class="cx">   &lt;p&gt;
</span><del>-  Updated milestone URL 
-  [% IF old_product.milestone_url != '' %]
-    from&lt;br&gt; &lt;a href=&quot;[%- old_product.milestone_url FILTER html %]&quot;&gt;
-    [%- old_product.milestone_url FILTER html %]&lt;/a&gt;
-  [% END %]
-  to
-  [% IF product.milestone_url != '' %]
-     &lt;br&gt;&lt;a href=&quot;[%- product.milestone_url FILTER html %]&quot;&gt;
-     [%- product.milestone_url FILTER html %]&lt;/a&gt;.
-  [% ELSE %]
-    be empty.
-  [% END %]
-  &lt;/p&gt;
-  [% updated = 1 %]
-[% END %]
-
-[% IF product.default_milestone != old_product.default_milestone %]
-  &lt;p&gt;
-  Updated default milestone from '[% old_product.default_milestone FILTER html %]' to
</del><ins>+  Updated default milestone from '[% changes.defaultmilestone.0 FILTER html %]' to
</ins><span class="cx">   '[% product.default_milestone FILTER html %]'.
</span><span class="cx">   &lt;/p&gt;
</span><del>-  [% updated = 1 %]
</del><span class="cx"> [% END %]
</span><del>-  
-[% IF product.votes_per_user != old_product.votes_per_user %]
-  &lt;p&gt;
-  Updated votes per user from
-  [%+ old_product.votes_per_user FILTER html %] to 
-  [%+ product.votes_per_user FILTER html %].
-  &lt;/p&gt;
-  [% updated = 1 %]
-[% END %]
</del><span class="cx"> 
</span><del>-[% IF product.max_votes_per_bug != old_product.max_votes_per_bug %]
</del><ins>+[% IF changes.allows_unconfirmed.defined %]
</ins><span class="cx">   &lt;p&gt;
</span><del>-  Updated maximum votes per [% terms.bug %] from 
-  [%+ old_product.max_votes_per_bug FILTER html %] to 
-  [%+ product.max_votes_per_bug FILTER html %].
</del><ins>+  [% IF product.allows_unconfirmed %]
+    The product now allows the 
+    [%+ display_value('bug_status', 'UNCONFIRMED') FILTER html %] status.
+  [% ELSE %]
+    The product no longer allows the 
+    [%+ display_value('bug_status', 'UNCONFIRMED') FILTER html %] status.
+    Note that any 
+    &lt;a href=&quot;buglist.cgi?product=
+            [%- product.name FILTER uri %]&amp;amp;bug_status=UNCONFIRMED&quot;&gt; 
+    [%- terms.bugs %] that currently have the 
+    [%+ display_value('bug_status', 'UNCONFIRMED') FILTER html %] status&lt;/a&gt;
+    will remain in that status until they are edited.
+  [% END %]
</ins><span class="cx">   &lt;/p&gt;
</span><del>-  [% updated = 1 %]
</del><span class="cx"> [% END %]
</span><span class="cx"> 
</span><del>-[% IF product.votes_to_confirm != old_product.votes_to_confirm %]
-  &lt;p&gt;
-  Updated number of votes needed to confirm a [% terms.bug %] from
-  [%+ old_product.votes_to_confirm FILTER html %] to 
-  [%+ product.votes_to_confirm FILTER html %].
-  &lt;/p&gt;
-  [% updated = 1 %]
-[% END %]
</del><ins>+[% Hook.process('changes') %]
</ins><span class="cx"> 
</span><del>-[% UNLESS updated %]
</del><ins>+[% IF !changes.keys.size %]
</ins><span class="cx">   &lt;p&gt;Nothing changed for product '[% product.name FILTER html %]'.&lt;/p&gt;
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><del>-[%# Note that this display of changed votes and/or confirmed bugs is
-    not very scalable. We could have a _lot_, and we just list them all.
-    One day we should limit this perhaps, or have a more scalable display %]
-
-
-[% IF checkvotes %]
-  &lt;hr&gt;
-
-  &lt;p&gt;Checking existing votes in this product for anybody who now
-  has too many votes for [% terms.abug %]...&lt;br&gt;
-  [% IF toomanyvotes.size &gt; 0 %]
-    [% FOREACH detail = toomanyvotes %]
-      &amp;rarr;removed votes for [% terms.bug %] &lt;a href=&quot;show_bug.cgi?id=
-     [%- detail.id FILTER url_quote %]&quot;&gt;
-     [%- detail.id FILTER html %]&lt;/a&gt; from [% detail.name FILTER html %]&lt;br&gt;
-    [% END %]
-  [% ELSE %]
-    &amp;rarr;there were none.
-  [% END %]
-  &lt;/p&gt;
-
-  &lt;p&gt;Checking existing votes in this product for anybody
-  who now has too many total votes...&lt;br&gt;
-  [% IF toomanytotalvotes.size &gt; 0 %]
-    [% FOREACH detail = toomanytotalvotes %]
-      &amp;rarr;removed votes for [% terms.bug %] &lt;a href=&quot;show_bug.cgi?id=
-     [%- detail.id FILTER url_quote %]&quot;&gt;
-     [%- detail.id FILTER html %]&lt;/a&gt; from [% detail.name FILTER html %]&lt;br&gt;
-    [% END %]
-  [% ELSE %]
-    &amp;rarr;there were none.
-  [% END %]
-  &lt;/p&gt;
-
-  &lt;p&gt;Checking unconfirmed [% terms.bugs %] in this product for any which now have
-  sufficient votes...&lt;br&gt;
-  [% IF confirmedbugs.size &gt; 0 %]
-    [% FOREACH id = confirmedbugs %]
-
-      [%# This is INCLUDED instead of PROCESSED to avoid variables getting
-          overwritten, which happens otherwise %]
-      [% INCLUDE bug/process/results.html.tmpl
-        type = 'votes'
-        mailrecipients = { 'changer' =&gt; changer }
-        header_done = 1
-        id = id
-      %]
-    [% END %]
-  [% ELSE %]
-    &amp;rarr;there were none.
-  [% END %]
-  &lt;/p&gt;
-
-[% END %]
-
</del><span class="cx"> [% PROCESS admin/products/footer.html.tmpl %]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/footer.html.tmpl %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminsanitycheckmessageshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/sanitycheck/messages.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/sanitycheck/messages.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/sanitycheck/messages.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -34,7 +34,8 @@
</span><span class="cx">     [% errortext FILTER html %]: [% INCLUDE bug_list badbugs = badbugs %]
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF san_tag == &quot;bug_check_repair&quot; %]
</span><del>-    &lt;a href=&quot;sanitycheck.cgi?[% param FILTER url_quote %]=1&quot;&gt;[% text FILTER html %]&lt;/a&gt;.
</del><ins>+    &lt;a href=&quot;sanitycheck.cgi?[% param FILTER uri %]=1&amp;amp;token=
+       [%- issue_hash_token(['sanitycheck']) FILTER uri %]&quot;&gt;[% text FILTER html %]&lt;/a&gt;.
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF san_tag == &quot;bug_check_creation_date&quot; %]
</span><span class="cx">     Checking for [% terms.bugs %] with no creation date (which makes them invisible).
</span><span class="lines">@@ -81,12 +82,6 @@
</span><span class="cx">   [% ELSIF san_tag == &quot;bug_check_status_everconfirmed_error_text2&quot; %]
</span><span class="cx">     [% terms.Bugs %] with confirmed status but don't have everconfirmed set
</span><span class="cx"> 
</span><del>-  [% ELSIF san_tag == &quot;bug_check_votes_everconfirmed&quot; %]
-    Checking votes/everconfirmed
-
-  [% ELSIF san_tag == &quot;bug_check_votes_everconfirmed_error_text&quot; %]
-    [% terms.Bugs %] that have enough votes to be confirmed but haven't been
-
</del><span class="cx">   [% ELSIF san_tag == &quot;bug_check_control_values&quot; %]
</span><span class="cx">     Checking for bad values in group_control_map
</span><span class="cx"> 
</span><span class="lines">@@ -142,11 +137,13 @@
</span><span class="cx">     [% END %]
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF san_tag == &quot;cross_check_attachment_has_references&quot; %]
</span><del>-    &lt;a href=&quot;sanitycheck.cgi?remove_invalid_attach_references=1&quot;&gt;Remove
</del><ins>+    &lt;a href=&quot;sanitycheck.cgi?remove_invalid_attach_references=1&amp;amp;token=
+       [%- issue_hash_token(['sanitycheck']) FILTER uri %]&quot;&gt;Remove
</ins><span class="cx">     invalid references to non existent attachments.&lt;/a&gt;
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF san_tag == &quot;cross_check_bug_has_references&quot; %]
</span><del>-    &lt;a href=&quot;sanitycheck.cgi?remove_invalid_bug_references=1&quot;&gt;Remove
</del><ins>+    &lt;a href=&quot;sanitycheck.cgi?remove_invalid_bug_references=1&amp;amp;token=
+       [%- issue_hash_token(['sanitycheck']) FILTER uri %]&quot;&gt;Remove
</ins><span class="cx">     invalid references to non existent [% terms.bugs %].&lt;/a&gt;
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF san_tag == &quot;double_cross_check_to&quot; %]
</span><span class="lines">@@ -169,6 +166,12 @@
</span><span class="cx">       [% END %]
</span><span class="cx">     [% END %]
</span><span class="cx"> 
</span><ins>+  [% ELSIF san_tag == &quot;everconfirmed_start&quot; %]
+    OK, now fixing everconfirmed.
+
+  [% ELSIF san_tag == &quot;everconfirmed_end&quot; %]
+    everconfirmed fixed.
+
</ins><span class="cx">   [% ELSIF san_tag == &quot;flag_check_start&quot; %]
</span><span class="cx">     Checking for flags being in the wrong product/component.
</span><span class="cx"> 
</span><span class="lines">@@ -186,7 +189,8 @@
</span><span class="cx">     [%+ PROCESS bug_link bug_id = bug_id %].
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF san_tag == &quot;flag_fix&quot; %]
</span><del>-    &lt;a href=&quot;sanitycheck.cgi?remove_invalid_flags=1&quot;&gt;Click
</del><ins>+    &lt;a href=&quot;sanitycheck.cgi?remove_invalid_flags=1&amp;amp;token=
+       [%- issue_hash_token(['sanitycheck']) FILTER uri %]&quot;&gt;Click
</ins><span class="cx">     here to delete invalid flags&lt;/a&gt;
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF san_tag == &quot;group_control_map_entries_creation&quot; %]
</span><span class="lines">@@ -222,23 +226,6 @@
</span><span class="cx">   [% ELSIF san_tag == &quot;keyword_check_duplicated_ids&quot; %]
</span><span class="cx">     Duplicate keyword IDs found in [% PROCESS bug_link bug_id = id %].
</span><span class="cx"> 
</span><del>-  [% ELSIF san_tag == &quot;keyword_cache_start&quot; %]
-    Checking cached keywords.
-
-  [% ELSIF san_tag == &quot;keyword_cache_alert&quot; %]
-    [% badbugs.size FILTER none %] [%+ terms.bugs %] found with
-    incorrect keyword cache: [% INCLUDE bug_list badbugs = badbugs %]
-
-  [% ELSIF san_tag == &quot;keyword_cache_fixing&quot; %]
-    OK, now fixing keyword cache.
-
-  [% ELSIF san_tag == &quot;keyword_cache_fixed&quot; %]
-    Keyword cache fixed.
-
-  [% ELSIF san_tag == &quot;keyword_cache_rebuild&quot; %]
-    &lt;a href=&quot;sanitycheck.cgi?rebuildkeywordcache=1&quot;&gt;Click here to
-    rebuild the keyword cache&lt;/a&gt;.
-
</del><span class="cx">   [% ELSIF san_tag == &quot;profile_login_start&quot; %]
</span><span class="cx">     Checking profile logins.
</span><span class="cx"> 
</span><span class="lines">@@ -267,27 +254,9 @@
</span><span class="cx">     half an hour: [% INCLUDE bug_list badbugs = badbugs %]
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF san_tag == &quot;unsent_bugmail_fix&quot; %]
</span><del>-    &lt;a href=&quot;sanitycheck.cgi?rescanallBugMail=1&quot;&gt;Send these mails&lt;/a&gt;.
</del><ins>+    &lt;a href=&quot;sanitycheck.cgi?rescanallBugMail=1&amp;amp;token=
+       [%- issue_hash_token(['sanitycheck']) FILTER uri %]&quot;&gt;Send these mails&lt;/a&gt;.
</ins><span class="cx"> 
</span><del>-  [% ELSIF san_tag == &quot;vote_cache_rebuild_start&quot; %]
-    OK, now rebuilding vote cache.
-
-  [% ELSIF san_tag == &quot;vote_cache_rebuild_end&quot; %]
-    Vote cache has been rebuilt.
-
-  [% ELSIF san_tag == &quot;vote_cache_rebuild_fix&quot; %]
-    &lt;a href=&quot;sanitycheck.cgi?rebuildvotecache=1&quot;&gt;Click here to
-    rebuild the vote cache&lt;/a&gt;
-
-  [% ELSIF san_tag == &quot;vote_cache_alert&quot; %]
-    Bad vote cache for [% PROCESS bug_link bug_id = id %]
-
-  [% ELSIF san_tag == &quot;vote_count_start&quot; %]
-    Checking cached vote counts.
-
-  [% ELSIF san_tag == &quot;vote_count_alert&quot; %]
-    Bad vote sum for [% terms.bug %] [%+ id FILTER html %].
-
</del><span class="cx">   [% ELSIF san_tag == &quot;whines_obsolete_target_deletion_start&quot; %]
</span><span class="cx">     OK, now removing non-existent users/groups from whines.
</span><span class="cx"> 
</span><span class="lines">@@ -304,27 +273,44 @@
</span><span class="cx">     [% END %]
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF san_tag == &quot;whines_obsolete_target_fix&quot; %]
</span><del>-    &lt;a href=&quot;sanitycheck.cgi?remove_old_whine_targets=1&quot;&gt;Click here to
</del><ins>+    &lt;a href=&quot;sanitycheck.cgi?remove_old_whine_targets=1&amp;amp;token=
+       [%- issue_hash_token(['sanitycheck']) FILTER uri %]&quot;&gt;Click here to
</ins><span class="cx">     remove old users/groups&lt;/a&gt;
</span><span class="cx"> 
</span><ins>+  [% ELSE %]
+    [% message = Hook.process(&quot;statuses&quot;) %]
+
+    [% IF message %]
+      [% message FILTER none %]
+    [% ELSE %]
+      The status message string &lt;code&gt;[% san_tag FILTER html %]&lt;/code&gt;
+      was not found. Please send email to [% Param(&quot;maintainer&quot;) %] describing
+      the steps taken to obtain this message.
+    [% END %]
+
</ins><span class="cx">   [% END %]
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><del>-[% san_message FILTER html %]
</del><ins>+[% USE Bugzilla %]
+[% IF Bugzilla.usage_mode == constants.USAGE_MODE_CMDLINE %]
+  [% san_message FILTER none %]
+[% ELSE %]
+  [%# Avoid the txt filter in message.txt.tmpl. %]
+  [% san_message FILTER html %]
+[% END %]
</ins><span class="cx"> 
</span><del>-
</del><span class="cx"> [% BLOCK bug_list %]
</span><span class="cx">   [% FOREACH bug_id = badbugs %]
</span><span class="cx">     [%# Do not use FILTER bug_link() here, because bug_link() calls get_text()
</span><span class="cx">      # which itself calls this template again, generating a recursion error.
</span><span class="cx">      # I doubt having a tooltip with the bug status and summary is so
</span><span class="cx">      # important here anyway, as you can click the &quot;(as buglist)&quot; link. %]
</span><del>-    &lt;a href=&quot;show_bug.cgi?id=[% bug_id FILTER url_quote %]&quot;&gt;[% bug_id FILTER html %]&lt;/a&gt;
</del><ins>+    &lt;a href=&quot;show_bug.cgi?id=[% bug_id FILTER uri %]&quot;&gt;[% bug_id FILTER html %]&lt;/a&gt;
</ins><span class="cx">     [% &quot;, &quot; IF !loop.last %]
</span><span class="cx">   [% END %]
</span><del>-  (&lt;a href=&quot;buglist.cgi?bug_id=[% badbugs.join(&quot;,&quot;) FILTER url_quote %]&quot;&gt;as [% terms.bug %] list&lt;/a&gt;).
</del><ins>+  (&lt;a href=&quot;buglist.cgi?bug_id=[% badbugs.join(&quot;,&quot;) FILTER uri %]&quot;&gt;as [% terms.bug %] list&lt;/a&gt;).
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK bug_link %]
</span><del>-  &lt;a href=&quot;show_bug.cgi?id=[% bug_id FILTER url_quote %]&quot;&gt;[% terms.bug %] [%+ bug_id FILTER html %]&lt;/a&gt;
</del><ins>+  &lt;a href=&quot;show_bug.cgi?id=[% bug_id FILTER uri %]&quot;&gt;[% terms.bug %] [%+ bug_id FILTER html %]&lt;/a&gt;
</ins><span class="cx"> [% END %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminsudohtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/sudo.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/sudo.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/sudo.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -83,8 +83,7 @@
</span><span class="cx">       password&lt;/label&gt;:
</span><span class="cx">       &lt;input type=&quot;hidden&quot; name=&quot;Bugzilla_login&quot; value=&quot;
</span><span class="cx">       [%- user.login FILTER html %]&quot;&gt;
</span><del>-      &lt;input type=&quot;password&quot; id=&quot;Bugzilla_password&quot; name=&quot;Bugzilla_password&quot;
-             maxlength=&quot;20&quot; size=&quot;20&quot;&gt;
</del><ins>+      &lt;input type=&quot;password&quot; id=&quot;Bugzilla_password&quot; name=&quot;Bugzilla_password&quot; size=&quot;20&quot;&gt;
</ins><span class="cx">       &lt;br&gt;
</span><span class="cx">       This is done for two reasons.  First of all, it is done to reduce 
</span><span class="cx">       the chances of someone doing large amounts of damage using your 
</span><span class="lines">@@ -95,7 +94,7 @@
</span><span class="cx">   
</span><span class="cx">   &lt;p&gt;
</span><span class="cx">     Click the button to begin the session:
</span><del>-    &lt;input type=&quot;submit&quot; value=&quot;Begin Session&quot;&gt;
</del><ins>+    &lt;input type=&quot;submit&quot; id=&quot;begin_sudo&quot; value=&quot;Begin Session&quot;&gt;
</ins><span class="cx">     &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;begin-sudo&quot;&gt;
</span><span class="cx">     &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% token FILTER html %]&quot;&gt;
</span><span class="cx">   &lt;/p&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadmintablehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/table.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/table.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/table.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -50,14 +50,26 @@
</span><span class="cx">   #   keys are column names from columns subhashes name field.
</span><span class="cx">   #
</span><span class="cx">   # overrides:
</span><del>-  #   Provides a method for overriding individual table cells. This is
-  #   a hash, whose key is the column name, so the column must be
-  #   named for one of it's cells to be overwritten. The hash value is
-  #   an array. Each item in this array is a hash specifying
-  #   row-matching criteria, and any overridden values. The
-  #   row-matching criteria consist of keys:
-  #     match_field: The name of the row value we want to match
-  #     match_value: The value to match against
</del><ins>+  # Example:
+  #     overrides {                           # first hash
+  #       column_name_to_be_overwriten =&gt; {   # second hash
+  #         name_of_row_to_match_against =&gt; { # third hash
+  #           value_to_match_against =&gt; {     # fourth hash
+  #             content =&gt; &quot;some contents&quot;
+  #             override_content =&gt; 1
+  #           }
+  #         }
+  #       }
+  #     }
+  #
+  #   Provides a method for overriding individual table cells. This is a hash
+  #   (1), whose key is the column name, so the column must be named for
+  #   one of it's cells to be overwritten. The hash value is another hash
+  #   (2). The keys of that second hash are the name of the row to match
+  #   against. The second hash then again points to another hash. Within this
+  #   third hash (3), the keys represent values to match against. The item
+  #   contains a fourth hash (4) specifying overridden values.
+  #   
</ins><span class="cx">   #   Each column value mentioned in the 'columns' documentation above
</span><span class="cx">   #   can be overwritten (apart from name and heading). To override a
</span><span class="cx">   #   table-cell value 'xxx', specify a new 'xxx' value, and specify a
</span><span class="lines">@@ -98,30 +110,30 @@
</span><span class="cx">          yesno_field = c.yesno_field
</span><span class="cx">        %]
</span><span class="cx"> 
</span><del>-      [%# Are there any specific overrides for this column? %]
-      [% FOREACH override = overrides.${c.name} %]
</del><ins>+      [%# Get any specific &quot;important&quot; overrides for this c.name and row.name ? %]
+      [% SET important = overrides.${c.name}.name.${row.name} %]
</ins><span class="cx"> 
</span><del>-        [%# Is the override for this row? %]
-        [% IF override.match_value == row.${override.match_field} %]
</del><ins>+      [% IF important %]
</ins><span class="cx"> 
</span><del>-          [% SET contentlink = override.contentlink 
-             IF override.override_contentlink %]
-          [% SET content = override.content
-             IF override.override_content %]
-          [% SET content_use_field = override.content_use_field
-             IF override.override_content_use_field %]
-          [% SET align = override.align
-             IF override.override_align %]
-          [% SET class = override.class
-             IF override.override_class %]
-          [% SET allow_html_content = override.allow_html_content
-             IF override.override_allow_html_content %]
-          [% SET yesno_field = override.yesno_field
-             IF override.override_yesno_field %]
</del><ins>+          [% FOREACH key IN important.keys %]
+             [% SET ${key} = important.${key} %]
+          [% END %]
</ins><span class="cx"> 
</span><del>-          [% LAST %]
</del><ins>+      [% ELSE %]
</ins><span class="cx"> 
</span><del>-        [% END %]
</del><ins>+          [%# Are there any specific overrides for this column? %]
+          [% FOREACH match_field = overrides.${c.name}.keys %]
+     
+              [% override = overrides.${c.name}.${match_field}.${row.$match_field} %]
+              [% NEXT UNLESS override %]
+
+              [% FOREACH key IN override.keys %]
+                  [% SET ${key} = override.${key} %]
+              [% END %]
+
+              [% LAST %]
+
+          [% END %]
</ins><span class="cx">       [% END %]
</span><span class="cx"> 
</span><span class="cx">       &lt;td [% IF align %] align=&quot;[% align FILTER html %]&quot; [% END %]
</span><span class="lines">@@ -131,8 +143,8 @@
</span><span class="cx">           [% link_uri = contentlink %]
</span><span class="cx">           [% WHILE link_uri.search('%%(.+?)%%')%]
</span><span class="cx">             [% FOREACH m = link_uri.match('%%(.+?)%%') %]
</span><del>-              [% IF row.$m %]
-                [% replacement_value = FILTER url_quote; row.$m; END %]
</del><ins>+              [% IF row.$m.defined %]
+                [% replacement_value = FILTER uri; row.$m; END %]
</ins><span class="cx">               [% ELSE %]
</span><span class="cx">                 [% replacement_value = &quot;&quot; %]
</span><span class="cx">               [% END %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminusersconfirmdeletehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/users/confirm-delete.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/users/confirm-delete.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/users/confirm-delete.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -33,7 +33,6 @@
</span><span class="cx">   # namedquery_group_map:     number of named queries the user has shared
</span><span class="cx">   # profiles_activity:        number of changes made to other users' profiles
</span><span class="cx">   # series:                   number of series the viewed user has created
</span><del>-  # votes:                    number of bugs the viewed user has voted on
</del><span class="cx">   # watch.watched:            number of users the viewed user is being watched
</span><span class="cx">   #                           by
</span><span class="cx">   # watch.watcher:            number of users the viewed user is watching
</span><span class="lines">@@ -69,8 +68,8 @@
</span><span class="cx">     &lt;td&gt;
</span><span class="cx">       [% IF otheruser.groups.size %]
</span><span class="cx">         &lt;ul&gt;
</span><del>-          [% FOREACH group = otheruser.groups.keys %]
-            &lt;li&gt;[% group FILTER html %]&lt;/li&gt;
</del><ins>+          [% FOREACH group = otheruser.groups %]
+            &lt;li&gt;[% group.name FILTER html %]&lt;/li&gt;
</ins><span class="cx">           [% END %]
</span><span class="cx">         &lt;/ul&gt;
</span><span class="cx">       [% ELSE %]
</span><span class="lines">@@ -113,7 +112,7 @@
</span><span class="cx">           &lt;li&gt;
</span><span class="cx">             [% otheruser.login FILTER html %]
</span><span class="cx">             &lt;a href=&quot;buglist.cgi?field0-0-0=attachments.submitter&amp;type0-0-0=equals&amp;value0-0-0=
</span><del>-               [%- otheruser.login FILTER url_quote %]&quot;&gt;has submitted
</del><ins>+               [%- otheruser.login FILTER uri %]&quot;&gt;has submitted
</ins><span class="cx">             [% IF attachments == 1 %]
</span><span class="cx">               one attachment
</span><span class="cx">             [% ELSE %]
</span><span class="lines">@@ -133,7 +132,7 @@
</span><span class="cx">           &lt;li&gt;
</span><span class="cx">             [% otheruser.login FILTER html %]
</span><span class="cx">             &lt;a href=&quot;buglist.cgi?emailreporter1=1&amp;amp;emailtype1=exact&amp;amp;email1=
</span><del>-               [%- otheruser.login FILTER url_quote %]&quot;&gt;has reported
</del><ins>+               [%- otheruser.login FILTER uri %]&quot;&gt;has reported
</ins><span class="cx">             [% IF reporter == 1 %]
</span><span class="cx">               one [% terms.bug %]
</span><span class="cx">             [% ELSE %]
</span><span class="lines">@@ -171,7 +170,7 @@
</span><span class="cx">           &lt;li&gt;
</span><span class="cx">             [% otheruser.login FILTER html %] has
</span><span class="cx">             &lt;a href=&quot;buglist.cgi?field0-0-0=setters.login_name&amp;amp;type0-0-0=equals&amp;amp;value0-0-0=
</span><del>-               [%- otheruser.login FILTER url_quote %]&quot;&gt;set
</del><ins>+               [%- otheruser.login FILTER uri %]&quot;&gt;set
</ins><span class="cx">             or requested
</span><span class="cx">             [% IF flags.setter == 1 %]
</span><span class="cx">               a flag
</span><span class="lines">@@ -192,7 +191,7 @@
</span><span class="cx">           &lt;li&gt;
</span><span class="cx">             [% otheruser.login FILTER html %] has
</span><span class="cx">             &lt;a href=&quot;buglist.cgi?emaillongdesc1=1&amp;amp;emailtype1=exact&amp;amp;email1=
</span><del>-               [%- otheruser.login FILTER url_quote %]&quot;&gt;commented
</del><ins>+               [%- otheruser.login FILTER uri %]&quot;&gt;commented
</ins><span class="cx">             [% IF longdescs == 1 %]
</span><span class="cx">               once on [% terms.abug %]
</span><span class="cx">             [% ELSE %]
</span><span class="lines">@@ -226,8 +225,9 @@
</span><span class="cx">   [% END %]
</span><span class="cx"> 
</span><span class="cx">   [% IF assignee_or_qa || cc || component_cc || email_setting || flags.requestee ||
</span><del>-        namedqueries || profile_setting || quips || series || votes || watch.watched ||
-        watch.watcher || whine_events || whine_schedules %]
</del><ins>+        namedqueries || profile_setting || quips || series || watch.watched ||
+        watch.watcher || whine_events || whine_schedules || otheruser.has_audit_entries ||
+        other_safe %]
</ins><span class="cx">     &lt;div class=&quot;warningmessages&quot;&gt;
</span><span class="cx">       &lt;p&gt;The following deletions are &lt;b&gt;safe&lt;/b&gt; and will not generate
</span><span class="cx">       referential integrity inconsistencies.&lt;/p&gt;
</span><span class="lines">@@ -237,7 +237,7 @@
</span><span class="cx">           &lt;li&gt;
</span><span class="cx">             [% otheruser.login FILTER html %]
</span><span class="cx">             &lt;a href=&quot;buglist.cgi?emailassigned_to1=1&amp;amp;emailqa_contact1=1&amp;amp;emailtype1=exact&amp;amp;email1=
</span><del>-               [%- otheruser.login FILTER url_quote %]&quot;&gt;is
</del><ins>+               [%- otheruser.login FILTER uri %]&quot;&gt;is
</ins><span class="cx">             the assignee or the QA contact of
</span><span class="cx">             [% IF assignee_or_qa == 1 %]
</span><span class="cx">               one [% terms.bug %]
</span><span class="lines">@@ -252,7 +252,7 @@
</span><span class="cx">           &lt;li&gt;
</span><span class="cx">             [% otheruser.login FILTER html %]
</span><span class="cx">             &lt;a href=&quot;buglist.cgi?emailcc1=1&amp;amp;emailtype1=exact&amp;amp;email1=
</span><del>-               [%- otheruser.login FILTER url_quote %]&quot;&gt;is
</del><ins>+               [%- otheruser.login FILTER uri %]&quot;&gt;is
</ins><span class="cx">             on the CC list of
</span><span class="cx">             [% IF cc == 1 %]
</span><span class="cx">               [%+ terms.abug %]
</span><span class="lines">@@ -283,7 +283,7 @@
</span><span class="cx">           &lt;li&gt;
</span><span class="cx">             [% otheruser.login FILTER html %] has been
</span><span class="cx">             &lt;a href=&quot;buglist.cgi?field0-0-0=requestees.login_name&amp;amp;type0-0-0=equals&amp;amp;value0-0-0=
</span><del>-               [%- otheruser.login FILTER url_quote %]&quot;&gt;asked
</del><ins>+               [%- otheruser.login FILTER uri %]&quot;&gt;asked
</ins><span class="cx">             to set
</span><span class="cx">             [% IF flags.requestee == 1 %]
</span><span class="cx">               a flag
</span><span class="lines">@@ -372,23 +372,6 @@
</span><span class="cx">             will have no author anymore, but will remain available.
</span><span class="cx">           &lt;/li&gt;
</span><span class="cx">         [% END %]
</span><del>-        [% IF votes %]
-          &lt;li&gt;
-            [% otheruser.login FILTER html %] has voted on
-            [% IF votes == 1 %]
-              [%+ terms.abug %]
-            [% ELSE %]
-              [%+ votes %] [%+ terms.bugs %]
-            [% END %].
-            If you delete the user account,
-            [% IF votes == 1 %]
-              this vote
-            [% ELSE %]
-              these votes
-            [% END %]
-            will be deleted along with the user account.
-          &lt;/li&gt;
-        [% END %]
</del><span class="cx">         [% IF watch.watched || watch.watcher %]
</span><span class="cx">           &lt;li&gt;
</span><span class="cx">             [% otheruser.login FILTER html %]
</span><span class="lines">@@ -445,6 +428,15 @@
</span><span class="cx">             but the whines themselves will be left unaltered.
</span><span class="cx">           &lt;/li&gt;
</span><span class="cx">         [% END %]
</span><ins>+        [% IF otheruser.has_audit_entries %]
+          &lt;li&gt;
+            The user has performed audited administrative tasks
+            that are logged in the database.
+            If you delete this user account, the audit log entries
+            will no longer be indentifiable.
+          &lt;/li&gt;
+        [% END %]
+        [% Hook.process('warn_safe') %]
</ins><span class="cx">       &lt;/ul&gt;
</span><span class="cx">     &lt;/div&gt;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminuserslisthtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/users/list.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/users/list.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/users/list.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -63,37 +63,34 @@
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [%# Disabled users are crossed out. Missing realnames are noticed in red. %]
</span><del>-[% overrides.login_name = [] %]
-[% overrides.realname = [] %]
</del><ins>+[% overrides.login_name = {} %]
+[% overrides.realname = {} %]
</ins><span class="cx"> 
</span><span class="cx"> [% FOREACH thisuser = users %]
</span><span class="cx">   [% IF !thisuser.realname %]
</span><span class="cx">     [%# We cannot pass one class now and one class later. %]
</span><del>-    [% SET classes = (thisuser.disabledtext ? &quot;bz_inactive missing&quot; : &quot;missing&quot;) %]
-    [% overrides.realname.push({
-        match_value      =&gt; &quot;$thisuser.login_name&quot;
-        match_field      =&gt; 'login_name'
-        content          =&gt; &quot;missing&quot;
-        override_content =&gt; 1
-        class            =&gt; &quot;$classes&quot;
-        override_class   =&gt; 1 })
</del><ins>+    [% SET classes = (thisuser.is_enabled ? &quot;missing&quot; : &quot;bz_inactive missing&quot;) %]
+    [% overrides.realname.login_name.${thisuser.login_name} = {
+           content          =&gt; &quot;missing&quot;
+           override_content =&gt; 1
+           class            =&gt; &quot;$classes&quot;
+           override_class   =&gt; 1
+       }
</ins><span class="cx">     %]
</span><ins>+  [% ELSIF !thisuser.is_enabled %]
+    [% overrides.realname.login_name.${thisuser.login_name} = {
+           class          =&gt; &quot;bz_inactive&quot;
+           override_class =&gt; 1
+       }
+    %]
</ins><span class="cx">   [% END %]
</span><span class="cx"> 
</span><del>-  [% IF thisuser.disabledtext %]
-    [% overrides.login_name.push({
-        match_value    =&gt; &quot;$thisuser.login_name&quot;
-        match_field    =&gt; 'login_name'
-        class          =&gt; &quot;bz_inactive&quot;
-        override_class =&gt; 1 })
</del><ins>+  [% IF !thisuser.is_enabled %]
+    [% overrides.login_name.login_name.${thisuser.login_name} = {
+           class          =&gt; &quot;bz_inactive&quot;
+           override_class =&gt; 1
+       }
</ins><span class="cx">     %]
</span><del>-
-    [% overrides.realname.push({
-        match_value    =&gt; &quot;$thisuser.login_name&quot;
-        match_field    =&gt; 'login_name'
-        class          =&gt; &quot;bz_inactive&quot;
-        override_class =&gt; 1 })
-    %]
</del><span class="cx">   [% END %]
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminuserslistselectvarshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/users/listselectvars.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/users/listselectvars.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/users/listselectvars.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -20,8 +20,8 @@
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK listselectionurlparams %]
</span><span class="cx">   [% FOREACH field = listselectionvalues.keys %]&amp;amp;
</span><del>-    [% field FILTER url_quote %]=
-    [% listselectionvalues.$field FILTER url_quote %]
</del><ins>+    [% field FILTER uri %]=
+    [% listselectionvalues.$field FILTER uri %]
</ins><span class="cx">   [% END %]
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminusersresponsibilitieshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/users/responsibilities.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/users/responsibilities.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/users/responsibilities.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -29,14 +29,15 @@
</span><span class="cx">       &lt;th&gt;Component&lt;/th&gt;
</span><span class="cx">       &lt;th&gt;Default Assignee&lt;/th&gt;
</span><span class="cx">       &lt;th&gt;Default QA Contact&lt;/th&gt;
</span><ins>+      &lt;th&gt;Default CC&lt;/th&gt;
</ins><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     [% FOREACH component = item.components %]
</span><span class="cx">       &lt;tr&gt;
</span><span class="cx">         &lt;td&gt;
</span><span class="cx">           [% IF user.in_group(&quot;editcomponents&quot;, component.product_id) %]
</span><span class="cx">             &lt;a href=&quot;editcomponents.cgi?action=edit&amp;amp;product=
</span><del>-                     [% item.product.name FILTER url_quote %]&amp;amp;component=
-                     [% component.name FILTER url_quote %]&quot;&gt;
</del><ins>+                     [% item.product.name FILTER uri %]&amp;amp;component=
+                     [% component.name FILTER uri %]&quot;&gt;
</ins><span class="cx">           [% END %]
</span><span class="cx">           [% component.name FILTER html %]
</span><span class="cx">           [% IF user.in_group(&quot;editcomponents&quot;, component.product_id) %]
</span><span class="lines">@@ -48,6 +49,9 @@
</span><span class="cx">             [% component.$responsibility.id == otheruser.id ? &quot;X&quot; : &quot;&amp;nbsp;&quot; %]
</span><span class="cx">           &lt;/td&gt;
</span><span class="cx">         [% END %]
</span><ins>+        &lt;td class=&quot;center&quot;&gt;
+          [% component.initial_cc.contains(otheruser) ? &quot;X&quot; : &quot;&amp;nbsp;&quot; %]
+        &lt;/td&gt;
</ins><span class="cx">       &lt;/tr&gt;
</span><span class="cx">     [% END %]
</span><span class="cx">     &lt;/tbody&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminuserssearchhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/users/search.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/users/search.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/users/search.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -62,6 +62,9 @@
</span><span class="cx">     [% END %]
</span><span class="cx">   &lt;/select&gt;&lt;/p&gt;
</span><span class="cx"> [% END %]
</span><ins>+
+[% Hook.process('end') %]
+
</ins><span class="cx"> &lt;/form&gt;
</span><span class="cx"> 
</span><span class="cx"> [% IF editusers %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminusersuserdatahtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/users/userdata.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/users/userdata.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/users/userdata.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -27,10 +27,10 @@
</span><span class="cx">       &lt;input size=&quot;64&quot; maxlength=&quot;255&quot; name=&quot;login&quot; 
</span><span class="cx">              id=&quot;login&quot; value=&quot;[% otheruser.login FILTER html %]&quot; /&gt;
</span><span class="cx">       [% IF editform %]
</span><del>-        [% IF !otheruser.groups.bz_sudo_protect %]
</del><ins>+        [% IF !otheruser.in_group('bz_sudo_protect') %]
</ins><span class="cx">           &lt;br /&gt;
</span><span class="cx">           &lt;a href=&quot;relogin.cgi?action=prepare-sudo&amp;amp;target_login=
</span><del>-          [%- otheruser.login FILTER url_quote %]&quot;&gt;Impersonate this user&lt;/a&gt;
</del><ins>+          [%- otheruser.login FILTER uri %]&quot;&gt;Impersonate this user&lt;/a&gt;
</ins><span class="cx">         [% END %]
</span><span class="cx">       [% END %]
</span><span class="cx">     [% ELSE %]
</span><span class="lines">@@ -38,6 +38,19 @@
</span><span class="cx">     [% END %]
</span><span class="cx">   &lt;/td&gt;
</span><span class="cx"> &lt;/tr&gt;
</span><ins>+[% IF default_authorizer.extern_id_used %]
+  &lt;tr&gt;
+    &lt;th&gt;&lt;label for=&quot;extern_id&quot;&gt;External Login ID:&lt;/label&gt;&lt;/th&gt;
+    &lt;td&gt;
+      [% IF editusers %]
+        &lt;input size=&quot;64&quot; maxlength=&quot;64&quot; name=&quot;extern_id&quot;
+               id=&quot;extern_id&quot; value=&quot;[% otheruser.extern_id FILTER html %]&quot;&gt;
+      [% ELSE %]
+        [% otheruser.extern_id FILTER html %]
+      [% END %]
+    &lt;/td&gt;
+  &lt;/tr&gt;
+[% END %]
</ins><span class="cx"> &lt;tr&gt;
</span><span class="cx">   &lt;th&gt;&lt;label for=&quot;name&quot;&gt;Real name:&lt;/label&gt;&lt;/th&gt;
</span><span class="cx">   &lt;td&gt;
</span><span class="lines">@@ -61,9 +74,8 @@
</span><span class="cx">   &lt;tr&gt;
</span><span class="cx">     &lt;th&gt;&lt;label for=&quot;password&quot;&gt;Password:&lt;/label&gt;&lt;/th&gt;
</span><span class="cx">     &lt;td&gt;
</span><del>-      &lt;input type=&quot;password&quot; size=&quot;16&quot; maxlength=&quot;16&quot; name=&quot;password&quot;
-             autocomplete=&quot;off&quot;
-             id=&quot;password&quot; value=&quot;&quot; /&gt;
</del><ins>+      &lt;input type=&quot;password&quot; size=&quot;16&quot; name=&quot;password&quot; id=&quot;password&quot;
+             value=&quot;&quot; autocomplete=&quot;off&quot; /&gt;
</ins><span class="cx">       [% IF editform %]&lt;br /&gt;
</span><span class="cx">         (Enter new password to change.)
</span><span class="cx">       [% END %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminversionsconfirmdeletehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/versions/confirm-delete.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/versions/confirm-delete.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/versions/confirm-delete.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -52,8 +52,8 @@
</span><span class="cx"> [% IF version.bug_count %]
</span><span class="cx">   &lt;a title=&quot;List of [% terms.bugs %] targetted at version '
</span><span class="cx">            [%- version.name FILTER html %]'&quot;
</span><del>-     href=&quot;buglist.cgi?version=[% version.name FILTER url_quote %]&amp;amp;product=
-          [%- product.name FILTER url_quote %]&quot;&gt;
</del><ins>+     href=&quot;buglist.cgi?version=[% version.name FILTER uri %]&amp;amp;product=
+          [%- product.name FILTER uri %]&quot;&gt;
</ins><span class="cx">           [%- version.bug_count FILTER none %]&lt;/a&gt;
</span><span class="cx"> [% ELSE %]
</span><span class="cx">   None
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminversionsedithtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/versions/edit.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/versions/edit.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/versions/edit.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -37,11 +37,15 @@
</span><span class="cx">   &lt;table border=&quot;0&quot; cellpadding=&quot;4&quot; cellspacing=&quot;0&quot;&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;th valign=&quot;top&quot;&gt;&lt;label for=&quot;version&quot;&gt;Version:&lt;/label&gt;&lt;/th&gt;
</del><ins>+      &lt;th class=&quot;field_label&quot;&gt;&lt;label for=&quot;version&quot;&gt;Version:&lt;/label&gt;&lt;/th&gt;
</ins><span class="cx">       &lt;td&gt;&lt;input id=&quot;version&quot; size=&quot;64&quot; maxlength=&quot;64&quot; name=&quot;version&quot; value=&quot;
</span><span class="cx">       [%- version.name FILTER html %]&quot;&gt;&lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><del>-
</del><ins>+    &lt;tr&gt;
+      &lt;th class=&quot;field_label&quot;&gt;&lt;label for=&quot;isactive&quot;&gt;Enabled For [% terms.Bugs %]:&lt;/label&gt;&lt;/th&gt;
+      &lt;td&gt;&lt;input id=&quot;isactive&quot; name=&quot;isactive&quot; type=&quot;checkbox&quot; value=&quot;1&quot;
+                 [% 'checked=&quot;checked&quot;' IF version.isactive %]&gt;&lt;/td&gt;
+    &lt;/tr&gt;
</ins><span class="cx">   &lt;/table&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;versionold&quot; value=&quot;[% version.name FILTER html %]&quot;&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminversionsfooterhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/versions/footer.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/versions/footer.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/versions/footer.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -38,7 +38,7 @@
</span><span class="cx"> [% UNLESS no_add_version_link %]
</span><span class="cx">   &lt;a title=&quot;Add a version to product '[% product.name FILTER html %]'&quot;
</span><span class="cx">      href=&quot;editversions.cgi?action=add&amp;amp;product=
</span><del>-          [%- product.name FILTER url_quote %]&quot;&gt;Add&lt;/a&gt; a version. 
</del><ins>+          [%- product.name FILTER uri %]&quot;&gt;Add&lt;/a&gt; a version. 
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% IF version.name &amp;&amp; !no_edit_version_link %]
</span><span class="lines">@@ -46,20 +46,20 @@
</span><span class="cx">   title=&quot;Edit Version '[% version.name FILTER html %]' of product '
</span><span class="cx">          [%- product.name FILTER html %]'&quot;
</span><span class="cx">   href=&quot;editversions.cgi?action=edit&amp;amp;product=
</span><del>-        [%- product.name FILTER url_quote %]&amp;amp;version=
-        [%- version.name FILTER url_quote %]&quot;&gt;
</del><ins>+        [%- product.name FILTER uri %]&amp;amp;version=
+        [%- version.name FILTER uri %]&quot;&gt;
</ins><span class="cx">         '[% version.name FILTER html %]'&lt;/a&gt;.
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% UNLESS no_edit_other_versions_link %]
</span><span class="cx">   Edit other versions of product &lt;a 
</span><span class="cx">   href=&quot;editversions.cgi?product=
</span><del>-        [%- product.name FILTER url_quote %]&quot;&gt;'[% product.name FILTER html %]'&lt;/a&gt;.
</del><ins>+        [%- product.name FILTER uri %]&quot;&gt;'[% product.name FILTER html %]'&lt;/a&gt;.
</ins><span class="cx"> 
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx">   Edit product &lt;a 
</span><span class="cx">   href=&quot;editproducts.cgi?action=edit&amp;amp;product=
</span><del>-        [%- product.name FILTER url_quote %]&quot;&gt;'[% product.name FILTER html %]'&lt;/a&gt;.
</del><ins>+        [%- product.name FILTER uri %]&quot;&gt;'[% product.name FILTER html %]'&lt;/a&gt;.
</ins><span class="cx"> 
</span><span class="cx"> &lt;/p&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminversionslisthtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/versions/list.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/versions/list.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/versions/list.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -33,11 +33,11 @@
</span><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> [% edit_contentlink = BLOCK %]editversions.cgi?action=edit&amp;amp;product=
</span><del>-  [%- product.name FILTER url_quote %]&amp;amp;version=%%name%%[% END %]
</del><ins>+  [%- product.name FILTER uri %]&amp;amp;version=%%name%%[% END %]
</ins><span class="cx"> [% delete_contentlink = BLOCK %]editversions.cgi?action=del&amp;amp;product=
</span><del>-  [%- product.name FILTER url_quote %]&amp;amp;version=%%name%%[% END %]
</del><ins>+  [%- product.name FILTER uri %]&amp;amp;version=%%name%%[% END %]
</ins><span class="cx"> [% bug_count_contentlink = BLOCK %]buglist.cgi?version=%%name%%&amp;amp;product=
</span><del>-  [%- product.name FILTER url_quote %][% END %]
</del><ins>+  [%- product.name FILTER uri %][% END %]
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> [% columns = [
</span><span class="lines">@@ -45,6 +45,11 @@
</span><span class="cx">        name =&gt; &quot;name&quot;
</span><span class="cx">        heading =&gt; &quot;Edit version...&quot;
</span><span class="cx">        contentlink =&gt; edit_contentlink
</span><ins>+     },
+     {
+       name =&gt; &quot;isactive&quot;
+       heading =&gt; &quot;Active&quot;
+       yesno_field =&gt; 1
</ins><span class="cx">      }
</span><span class="cx">    ]
</span><span class="cx"> %]
</span><span class="lines">@@ -68,6 +73,8 @@
</span><span class="cx">      })
</span><span class="cx"> %]
</span><span class="cx"> 
</span><ins>+[% Hook.process('before_table') %]
+
</ins><span class="cx"> [% PROCESS admin/table.html.tmpl
</span><span class="cx">      columns = columns
</span><span class="cx">      data = product.versions
</span><span class="lines">@@ -75,7 +82,7 @@
</span><span class="cx"> 
</span><span class="cx"> [% IF ! showbugcounts %]
</span><span class="cx"> 
</span><del>-  &lt;p&gt;&lt;a href=&quot;editversions.cgi?product=[% product.name FILTER url_quote %]&amp;amp;showbugcounts=1&quot;&gt;
</del><ins>+  &lt;p&gt;&lt;a href=&quot;editversions.cgi?product=[% product.name FILTER uri %]&amp;amp;showbugcounts=1&quot;&gt;
</ins><span class="cx">       Redisplay table with [% terms.bug %] counts (slower)&lt;/a&gt;&lt;/p&gt;
</span><span class="cx"> 
</span><span class="cx"> [% END %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminworkflowcommenthtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/workflow/comment.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/workflow/comment.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/workflow/comment.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -49,7 +49,7 @@
</span><span class="cx">     &lt;th&gt;&amp;nbsp;&lt;/th&gt;
</span><span class="cx">     [% FOREACH status = statuses %]
</span><span class="cx">       &lt;th class=&quot;col-header[% status.is_open ? &quot; open-status&quot; : &quot; closed-status&quot; %]&quot;&gt;
</span><del>-        [% status.name FILTER html %]
</del><ins>+        [% display_value(&quot;bug_status&quot;, status.name) FILTER html %]
</ins><span class="cx">       &lt;/th&gt;
</span><span class="cx">     [% END %]
</span><span class="cx">   &lt;/tr&gt;
</span><span class="lines">@@ -59,7 +59,7 @@
</span><span class="cx">   [% FOREACH status = p.merge(statuses) %]
</span><span class="cx">     &lt;tr class=&quot;highlight&quot;&gt;
</span><span class="cx">       &lt;th align=&quot;right&quot; class=&quot;[% status.is_open ? &quot;open-status&quot; : &quot;closed-status&quot; %]&quot;&gt;
</span><del>-        [% status.name FILTER html %]
</del><ins>+        [% display_value(&quot;bug_status&quot;, status.name) FILTER html %]
</ins><span class="cx">       &lt;/th&gt;
</span><span class="cx"> 
</span><span class="cx">       [% FOREACH new_status = statuses %]
</span><span class="lines">@@ -82,7 +82,7 @@
</span><span class="cx"> &lt;p align=&quot;center&quot;&gt;
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;update_comment&quot;&gt;
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% token FILTER html %]&quot;&gt;
</span><del>-  &lt;input type=&quot;submit&quot; value=&quot;Commit Changes&quot;&gt; -
</del><ins>+  &lt;input type=&quot;submit&quot; id=&quot;update_comment&quot; value=&quot;Commit Changes&quot;&gt; -
</ins><span class="cx">   &lt;a href=&quot;editworkflow.cgi?action=edit_comment&quot;&gt;Cancel Changes&lt;/a&gt; -
</span><span class="cx">   &lt;a href=&quot;editworkflow.cgi&quot;&gt;View Current Workflow&lt;/a&gt;
</span><span class="cx"> &lt;/p&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultadminworkflowedithtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/admin/workflow/edit.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/admin/workflow/edit.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/admin/workflow/edit.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -35,8 +35,8 @@
</span><span class="cx"> &lt;p&gt;
</span><span class="cx">   This page allows you to define which status transitions are valid in your workflow.
</span><span class="cx">   For compatibility with older versions of [% terms.Bugzilla %], reopening [% terms.abug %]
</span><del>-  will only display either [% get_status(&quot;UNCONFIRMED&quot;) FILTER html %] or
-  [%+ get_status(&quot;REOPENED&quot;) FILTER html %] (if allowed by your workflow) but not
</del><ins>+  will only display either [% display_value(&quot;bug_status&quot;, &quot;UNCONFIRMED&quot;) FILTER html %] or
+  [%+ display_value(&quot;bug_status&quot;, &quot;REOPENED&quot;) FILTER html %] (if allowed by your workflow) but not
</ins><span class="cx">   both. The decision depends on whether the [% terms.bug %] has ever been confirmed or not.
</span><span class="cx">   So it is a good idea to allow both transitions and let [% terms.Bugzilla %] select the
</span><span class="cx">   correct one.
</span><span class="lines">@@ -54,7 +54,7 @@
</span><span class="cx">     &lt;th&gt;&amp;nbsp;&lt;/th&gt;
</span><span class="cx">     [% FOREACH status = statuses %]
</span><span class="cx">       &lt;th class=&quot;col-header[% status.is_open ? &quot; open-status&quot; : &quot; closed-status&quot; %]&quot;&gt;
</span><del>-        [% status.name FILTER html %]
</del><ins>+        [% display_value(&quot;bug_status&quot;, status.name) FILTER html %]
</ins><span class="cx">       &lt;/th&gt;
</span><span class="cx">     [% END %]
</span><span class="cx">   &lt;/tr&gt;
</span><span class="lines">@@ -64,7 +64,7 @@
</span><span class="cx">   [% FOREACH status = p.merge(statuses) %]
</span><span class="cx">     &lt;tr class=&quot;highlight&quot;&gt;
</span><span class="cx">       &lt;th align=&quot;right&quot; class=&quot;[% status.is_open ? &quot;open-status&quot; : &quot;closed-status&quot; %]&quot;&gt;
</span><del>-        [% status.name FILTER html %]
</del><ins>+        [% display_value(&quot;bug_status&quot;, status.name) FILTER html %]
</ins><span class="cx">       &lt;/th&gt;
</span><span class="cx"> 
</span><span class="cx">       [% FOREACH new_status = statuses %]
</span><span class="lines">@@ -89,7 +89,7 @@
</span><span class="cx"> &lt;p&gt;
</span><span class="cx">   When [% terms.abug %] is marked as a duplicate of another one or is moved
</span><span class="cx">   to another installation, the [% terms.bug %] status is automatically set to
</span><del>-  &lt;b&gt;[% Param(&quot;duplicate_or_move_bug_status&quot;) FILTER html %]&lt;/b&gt;. All transitions to
</del><ins>+  &lt;b&gt;[% display_value(&quot;bug_status&quot;, Param(&quot;duplicate_or_move_bug_status&quot;)) FILTER html %]&lt;/b&gt;. All transitions to
</ins><span class="cx">   this [% terms.bug %] status must then be valid (this is the reason why you cannot edit
</span><span class="cx">   them above).&lt;br&gt;
</span><span class="cx">   Note: you can change this setting by visiting the
</span><span class="lines">@@ -100,7 +100,7 @@
</span><span class="cx"> &lt;p align=&quot;center&quot;&gt;
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;update&quot;&gt;
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% token FILTER html %]&quot;&gt;
</span><del>-  &lt;input type=&quot;submit&quot; value=&quot;Commit Changes&quot;&gt; -
</del><ins>+  &lt;input type=&quot;submit&quot; id=&quot;update_workflow&quot; value=&quot;Commit Changes&quot;&gt; -
</ins><span class="cx">   &lt;a href=&quot;editworkflow.cgi&quot;&gt;Cancel Changes&lt;/a&gt; -
</span><span class="cx">   &lt;a href=&quot;editworkflow.cgi?action=edit_comment&quot;&gt;View Comments Required on Status Transitions&lt;/a&gt;
</span><span class="cx"> &lt;/p&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultattachmentcancelcreatedupehtmltmpl"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/template/en/default/attachment/cancel-create-dupe.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/attachment/cancel-create-dupe.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/attachment/cancel-create-dupe.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,48 +0,0 @@
</span><del>-[%# The contents of this file are subject to the Mozilla Public
-  # License Version 1.1 (the &quot;License&quot;); you may not use this file
-  # except in compliance with the License. You may obtain a copy of
-  # the License at http://www.mozilla.org/MPL/
-  #
-  # Software distributed under the License is distributed on an &quot;AS
-  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
-  # implied. See the License for the specific language governing
-  # rights and limitations under the License.
-  #
-  # The Original Code is the Bugzilla Bug Tracking System.
-  #
-  # The Initial Developer of the Original Code is Olav Vitters.
-  #
-  # Contributor(s): Olav Vitters &lt;olav@bkor.dhs.org&gt;
-  #                 David Lawrence &lt;dkl@redhat.com&gt;
-  #%]
-
-[%# INTERFACE:
-  # bugid:    integer. ID of the bug report that this attachment relates to.
-  # attachid: integer. ID of the previous attachment recently created.
-  #%]
-
-[% PROCESS &quot;global/field-descs.none.tmpl&quot; %]
-
-[% PROCESS global/header.html.tmpl
-  title = &quot;Already filed attachment&quot;
-%]
-
-[% USE Bugzilla %]
-
-&lt;table cellpadding=&quot;20&quot;&gt;
-  &lt;tr&gt;
-    &lt;td bgcolor=&quot;#ff0000&quot;&gt;
-      &lt;font size=&quot;+2&quot;&gt;
-        You already used the form to file
-        &lt;a href=&quot;[% urlbase FILTER html %]attachment.cgi?id=[% attachid FILTER url_quote %]&amp;action=edit&quot;&gt;attachment [% attachid FILTER url_quote %]&lt;/a&gt;.
-      &lt;/font&gt;
-    &lt;/td&gt;
-  &lt;/tr&gt;
-&lt;/table&gt;
-
-&lt;p&gt;
-  You can either &lt;a href=&quot;[% urlbase FILTER html %]attachment.cgi?bugid=[% bugid FILTER url_quote %]&amp;action=enter&quot;&gt;
-  create a new attachment&lt;/a&gt; or [% &quot;go back to $terms.bug $bugid&quot; FILTER bug_link(bugid) FILTER none %].
-&lt;p&gt;
-
-[% PROCESS global/footer.html.tmpl %]
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultattachmentcontenttypeshtmltmpl"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/template/en/default/attachment/content-types.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/attachment/content-types.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/attachment/content-types.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,27 +0,0 @@
</span><del>-[%# The contents of this file are subject to the Mozilla Public
-  # License Version 1.1 (the &quot;License&quot;); you may not use this file
-  # except in compliance with the License. You may obtain a copy of
-  # the License at http://www.mozilla.org/MPL/
-  #
-  # Software distributed under the License is distributed on an &quot;AS
-  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
-  # implied. See the License for the specific language governing
-  # rights and limitations under the License.
-  #
-  # The Original Code is the Bugzilla Bug Tracking System.
-  #
-  # The Initial Developer of the Original Code is Netscape Communications
-  # Corporation. Portions created by Netscape are
-  # Copyright (C) 1998 Netscape Communications Corporation. All
-  # Rights Reserved.
-  #
-  # Contributor(s): Myk Melez &lt;myk@mozilla.org&gt;
-  #%]
-
-          &lt;option value=&quot;text/plain&quot;&gt;plain text (text/plain)&lt;/option&gt;
-          &lt;option value=&quot;text/html&quot;&gt;HTML source (text/html)&lt;/option&gt;
-          &lt;option value=&quot;application/xml&quot;&gt;XML source (application/xml)&lt;/option&gt;
-          &lt;option value=&quot;image/gif&quot;&gt;GIF image (image/gif)&lt;/option&gt;
-          &lt;option value=&quot;image/jpeg&quot;&gt;JPEG image (image/jpeg)&lt;/option&gt;
-          &lt;option value=&quot;image/png&quot;&gt;PNG image (image/png)&lt;/option&gt;
-          &lt;option value=&quot;application/octet-stream&quot;&gt;binary file (application/octet-stream)&lt;/option&gt;
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultattachmentcreatehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/attachment/create.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/attachment/create.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/attachment/create.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -26,20 +26,28 @@
</span><span class="cx"> [%# Define strings that will serve as the title and header of this page %]
</span><span class="cx"> [% title = BLOCK %]Create New Attachment for [% terms.Bug %] #[% bug.bug_id %][% END %]
</span><span class="cx"> [% header = BLOCK %]Create New Attachment for
</span><del>-  [%+ &quot;$terms.Bug $bug.bug_id&quot; FILTER bug_link(bug.bug_id) FILTER none %][% END %]
</del><ins>+  [%+ &quot;$terms.Bug $bug.bug_id&quot; FILTER bug_link(bug) FILTER none %][% END %]
</ins><span class="cx"> [% subheader = BLOCK %][% bug.short_desc FILTER html %][% END %]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/header.html.tmpl
</span><span class="cx">   title = title
</span><span class="cx">   header = header
</span><span class="cx">   subheader = subheader
</span><del>-  onload=&quot;setContentTypeDisabledState(document.entryform);&quot;
-  style_urls = [ 'skins/standard/create_attachment.css' ]
-  javascript_urls = [ &quot;js/attachment.js&quot; ]
</del><ins>+  style_urls = [ 'skins/standard/attachment.css' ]
+  yui = [ 'autocomplete' ]
+  javascript_urls = [ &quot;js/attachment.js&quot;, 'js/field.js', &quot;js/util.js&quot;, &quot;js/TUI.js&quot; ]
</ins><span class="cx">   doc_section = &quot;attachments.html&quot;
</span><span class="cx"> %]
</span><span class="cx"> 
</span><del>-&lt;form name=&quot;entryform&quot; method=&quot;post&quot; action=&quot;attachment.cgi&quot; enctype=&quot;multipart/form-data&quot;&gt;
</del><ins>+&lt;script type=&quot;text/javascript&quot;&gt;
+&lt;!--
+TUI_hide_default('attachment_text_field');
+--&gt;
+&lt;/script&gt;
+
+&lt;form name=&quot;entryform&quot; method=&quot;post&quot; action=&quot;attachment.cgi&quot;
+      enctype=&quot;multipart/form-data&quot;
+      onsubmit=&quot;return validateAttachmentForm(this)&quot;&gt;
</ins><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;bugid&quot; value=&quot;[% bug.bug_id %]&quot;&gt;
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;insert&quot;&gt;
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% token FILTER html %]&quot;&gt;
</span><span class="lines">@@ -54,8 +62,7 @@
</span><span class="cx">         &lt;em&gt;(optional) Check each existing attachment made obsolete by your new attachment.&lt;/em&gt;&lt;br&gt;
</span><span class="cx">         [% IF attachments.size %]
</span><span class="cx">           [% FOREACH attachment = attachments %]
</span><del>-            [% IF ((attachment.isprivate == 0) || (Param(&quot;insidergroup&quot;)
-              &amp;&amp; user.in_group(Param(&quot;insidergroup&quot;)))) %]
</del><ins>+            [% IF ((attachment.isprivate == 0) || user.is_insider) %]
</ins><span class="cx">               &lt;input type=&quot;checkbox&quot; id=&quot;[% attachment.id %]&quot;
</span><span class="cx">                    name=&quot;obsolete&quot; value=&quot;[% attachment.id %]&quot;&gt;
</span><span class="cx">               &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&amp;amp;action=edit&quot;&gt;[% attachment.id %]: [% attachment.description FILTER html %]&lt;/a&gt;&lt;br&gt;
</span><span class="lines">@@ -77,16 +84,17 @@
</span><span class="cx">           &lt;label for=&quot;takebug&quot;&gt;take [% terms.bug %]&lt;/label&gt;
</span><span class="cx">           [% bug_statuses = [] %]
</span><span class="cx">           [% FOREACH bug_status = bug.status.can_change_to %]
</span><del>-            [% NEXT IF bug_status.name == &quot;UNCONFIRMED&quot; &amp;&amp; !bug.product_obj.votes_to_confirm %]
</del><ins>+            [% NEXT IF bug_status.name == &quot;UNCONFIRMED&quot; 
+                       &amp;&amp; !bug.product_obj.allows_unconfirmed %]
</ins><span class="cx">             [% bug_statuses.push(bug_status) IF bug_status.is_open %]
</span><span class="cx">           [% END %]
</span><span class="cx">           [% IF bug_statuses.size %]
</span><span class="cx">             &lt;label for=&quot;takebug&quot;&gt;and set the [% terms.bug %] status to&lt;/label&gt;
</span><span class="cx">             &lt;select id=&quot;bug_status&quot; name=&quot;bug_status&quot;&gt;
</span><del>-              &lt;option value=&quot;[% bug.status.name FILTER html %]&quot;&gt;[% get_status(bug.status.name) FILTER html %] (current)&lt;/option&gt;
</del><ins>+              &lt;option value=&quot;[% bug.status.name FILTER html %]&quot;&gt;[% display_value(&quot;bug_status&quot;, bug.status.name) FILTER html %] (current)&lt;/option&gt;
</ins><span class="cx">               [% FOREACH bug_status = bug_statuses %]
</span><span class="cx">                 [% NEXT IF bug_status.id == bug.status.id %]
</span><del>-                &lt;option value=&quot;[% bug_status.name FILTER html %]&quot;&gt;[% get_status(bug_status.name) FILTER html %]&lt;/option&gt;
</del><ins>+                &lt;option value=&quot;[% bug_status.name FILTER html %]&quot;&gt;[% display_value(&quot;bug_status&quot;, bug_status.name) FILTER html %]&lt;/option&gt;
</ins><span class="cx">               [% END %]
</span><span class="cx">             &lt;/select&gt;
</span><span class="cx">           [% END %]
</span><span class="lines">@@ -107,17 +115,23 @@
</span><span class="cx">         %]
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><del>-    [% IF (Param(&quot;insidergroup&quot;) &amp;&amp; user.in_group(Param(&quot;insidergroup&quot;))) %]
</del><ins>+    [% IF user.is_insider %]
</ins><span class="cx">       &lt;tr&gt;
</span><span class="cx">         &lt;th&gt;Privacy:&lt;/th&gt;
</span><span class="cx">         &lt;td&gt;
</span><del>-          &lt;em&gt;If the attachment is private, check the box below.&lt;/em&gt;&lt;br&gt;
</del><span class="cx">           &lt;input type=&quot;checkbox&quot; name=&quot;isprivate&quot; id=&quot;isprivate&quot;
</span><span class="cx">           value=&quot;1&quot; onClick=&quot;updateCommentPrivacy(this)&quot;&gt;
</span><del>-        &lt;label for=&quot;isprivate&quot;&gt;Private&lt;/label&gt;
</del><ins>+          &lt;label for=&quot;isprivate&quot;&gt;
+            Make attachment and comment private (visible only to members of
+            the &lt;strong&gt;[% Param('insidergroup') FILTER html %]&lt;/strong&gt;
+            group)
+          &lt;/label&gt;
</ins><span class="cx">         &lt;/td&gt;
</span><span class="cx">       &lt;/tr&gt;
</span><span class="cx">     [% END %]
</span><ins>+
+    [% Hook.process('form_before_submit') %]
+
</ins><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th&gt;&amp;nbsp;&lt;/th&gt;
</span><span class="cx">       &lt;td&gt;&lt;input type=&quot;submit&quot; id=&quot;create&quot; value=&quot;Submit&quot;&gt;&lt;/td&gt;
</span><span class="lines">@@ -126,4 +140,6 @@
</span><span class="cx"> 
</span><span class="cx"> &lt;/form&gt;
</span><span class="cx"> 
</span><ins>+[% Hook.process('end') %]
+
</ins><span class="cx"> [% PROCESS global/footer.html.tmpl %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultattachmentcreatedhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/attachment/created.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/attachment/created.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/attachment/created.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -26,23 +26,9 @@
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="cx"> [% bug = bugs.0 %]
</span><del>-[% bodyclasses = ['bz_bug',
-                 &quot;bz_status_$bug.bug_status&quot;,
-                 &quot;bz_component_$bug.component&quot;,
-                 &quot;bz_bug_$bug.bug_id&quot;
-                 ]
-%]
-[% FOREACH group = bug.groups_in %]
-  [% bodyclasses.push(&quot;bz_group_$group.name&quot;) %]
-[% END %]
-
</del><ins>+[% PROCESS &quot;bug/show-header.html.tmpl&quot; %]
</ins><span class="cx"> [% PROCESS global/header.html.tmpl
</span><span class="cx">   title = &quot;Attachment $attachment.id added to $terms.Bug $attachment.bug_id&quot;
</span><del>-  bodyclasses = bodyclasses
-  javascript_urls = [ &quot;js/util.js&quot;, &quot;js/field.js&quot;,
-                      &quot;js/yui/yahoo-dom-event.js&quot;, &quot;js/yui/calendar.js&quot; ]
-  style_urls = [ &quot;skins/standard/yui/calendar.css&quot;, &quot;skins/standard/show_bug.css&quot; ]
-  doc_section = &quot;bug_page.html&quot;
</del><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> &lt;dl&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultattachmentcreateformcontentshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/attachment/createformcontents.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/attachment/createformcontents.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/attachment/createformcontents.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -21,54 +21,48 @@
</span><span class="cx">   #                 Marc Schumann &lt;wurblzap@gmail.com&gt;
</span><span class="cx">   #%]
</span><span class="cx"> 
</span><del>-&lt;tr&gt;
</del><ins>+&lt;tr class=&quot;attachment_data&quot;&gt;
</ins><span class="cx">   &lt;th&gt;&lt;label for=&quot;data&quot;&gt;File&lt;/label&gt;:&lt;/th&gt;
</span><span class="cx">   &lt;td&gt;
</span><del>-    &lt;em&gt;Enter the path to the file on your computer.&lt;/em&gt;&lt;br&gt;
-    &lt;input type=&quot;file&quot; id=&quot;data&quot; name=&quot;data&quot; size=&quot;50&quot;
-      [% IF Param(&quot;allow_attach_url&quot;) %]
-        onchange=&quot;DataFieldHandler()&quot; 
-      [% END %]
-    &gt;
</del><ins>+    &lt;em&gt;Enter the path to the file on your computer&lt;/em&gt; (or
+    &lt;a id=&quot;attachment_data_controller&quot; href=&quot;javascript:TUI_toggle_class('attachment_text_field');
+                                             javascript:TUI_toggle_class('attachment_data')&quot;
+    &gt;paste text as attachment&lt;/a&gt;).&lt;br&gt;
+    &lt;input type=&quot;file&quot; id=&quot;data&quot; name=&quot;data&quot; size=&quot;50&quot; onchange=&quot;DataFieldHandler()&quot;&gt;
</ins><span class="cx">   &lt;/td&gt;
</span><span class="cx"> &lt;/tr&gt;
</span><del>-[% IF Param(&quot;maxlocalattachment&quot;) %]
-&lt;tr&gt;
-  &lt;th&gt;BigFile:&lt;/th&gt;
</del><ins>+&lt;tr class=&quot;attachment_text_field&quot;&gt;
+  &lt;th&gt;&lt;label for=&quot;attach_text&quot;&gt;File&lt;/label&gt;:&lt;/th&gt;
</ins><span class="cx">   &lt;td&gt;
</span><del>-    &lt;input type=&quot;checkbox&quot; id=&quot;bigfile&quot;
-           name=&quot;bigfile&quot; value=&quot;bigfile&quot;&gt;
-    &lt;label for=&quot;bigfile&quot;&gt;
-      Big File - Stored locally and may be purged
-    &lt;/label&gt;
</del><ins>+    &lt;em&gt;Paste the text to be added as an attachment&lt;/em&gt; (or
+    &lt;a id=&quot;attachment_text_field_controller&quot; href=&quot;javascript:TUI_toggle_class('attachment_text_field');
+                                                   javascript:TUI_toggle_class('attachment_data')&quot;
+    &gt;attach a file&lt;/a&gt;).&lt;br&gt;
+    &lt;textarea id=&quot;attach_text&quot; name=&quot;attach_text&quot; cols=&quot;80&quot; rows=&quot;15&quot;
+              onkeyup=&quot;TextFieldHandler()&quot; onblur=&quot;TextFieldHandler()&quot;&gt;&lt;/textarea&gt;
</ins><span class="cx">   &lt;/td&gt;
</span><span class="cx"> &lt;/tr&gt;
</span><del>-[% END %]
-[% IF Param(&quot;allow_attach_url&quot;) %]
</del><span class="cx"> &lt;tr&gt;
</span><del>-  &lt;th&gt;&lt;label for=&quot;attachurl&quot;&gt;AttachURL&lt;/label&gt;:&lt;/th&gt;
</del><ins>+  &lt;th class=&quot;required&quot;&gt;&lt;label for=&quot;description&quot;&gt;Description&lt;/label&gt;:&lt;/th&gt;
</ins><span class="cx">   &lt;td&gt;
</span><del>-    &lt;em&gt;URL to be attached instead.&lt;/em&gt;&lt;br&gt;
-    &lt;input type=&quot;text&quot; id=&quot;attachurl&quot; name=&quot;attachurl&quot; size=&quot;60&quot; 
-           maxlength=&quot;2000&quot;
-           onkeyup=&quot;URLFieldHandler()&quot; onblur=&quot;URLFieldHandler()&quot;&gt;
-  &lt;/td&gt;
-&lt;/tr&gt;
-[% END %]
-&lt;tr&gt;
-  &lt;th&gt;&lt;label for=&quot;description&quot;&gt;Description&lt;/label&gt;:&lt;/th&gt;
-  &lt;td&gt;
</del><span class="cx">     &lt;em&gt;Describe the attachment briefly.&lt;/em&gt;&lt;br&gt;
</span><del>-    &lt;input type=&quot;text&quot; id=&quot;description&quot; name=&quot;description&quot; size=&quot;60&quot; maxlength=&quot;200&quot;&gt;
</del><ins>+    &lt;input type=&quot;text&quot; id=&quot;description&quot; name=&quot;description&quot; class=&quot;required&quot;
+           size=&quot;60&quot; maxlength=&quot;200&quot;&gt;
</ins><span class="cx">   &lt;/td&gt;
</span><span class="cx"> &lt;/tr&gt;
</span><del>-&lt;tr&gt;
</del><ins>+&lt;tr[% ' class=&quot;expert_fields&quot;' UNLESS bug.id %]&gt;
</ins><span class="cx">   &lt;th&gt;Content Type:&lt;/th&gt;
</span><span class="cx">   &lt;td&gt;
</span><span class="cx">     &lt;em&gt;If the attachment is a patch, check the box below.&lt;/em&gt;&lt;br&gt;
</span><span class="cx">     &lt;input type=&quot;checkbox&quot; id=&quot;ispatch&quot; name=&quot;ispatch&quot; value=&quot;1&quot;
</span><span class="cx">            onchange=&quot;setContentTypeDisabledState(this.form);&quot;&gt;
</span><span class="cx">     &lt;label for=&quot;ispatch&quot;&gt;patch&lt;/label&gt;&lt;br&gt;&lt;br&gt;
</span><ins>+    [%# Reset this whenever the page loads so that the JS state is up to date %]
+    &lt;script type=&quot;text/javascript&quot;&gt;
+      YAHOO.util.Event.onDOMReady(function() {
+          bz_fireEvent(document.getElementById('ispatch'), 'change');
+      });
+    &lt;/script&gt;
</ins><span class="cx"> 
</span><span class="cx">     &lt;em&gt;Otherwise, choose a method for determining the content type.&lt;/em&gt;&lt;br&gt;
</span><span class="cx">     &lt;input type=&quot;radio&quot; id=&quot;autodetect&quot;
</span><span class="lines">@@ -79,7 +73,7 @@
</span><span class="cx">       &lt;label for=&quot;list&quot;&gt;select from list&lt;/label&gt;:
</span><span class="cx">       &lt;select name=&quot;contenttypeselection&quot; id=&quot;contenttypeselection&quot;
</span><span class="cx">               onchange=&quot;this.form.contenttypemethod[1].checked = true;&quot;&gt;
</span><del>-        [% PROCESS &quot;attachment/content-types.html.tmpl&quot; %]
</del><ins>+        [% PROCESS content_types %]
</ins><span class="cx">       &lt;/select&gt;&lt;br&gt;
</span><span class="cx">     &lt;input type=&quot;radio&quot; id=&quot;manual&quot;
</span><span class="cx">                  name=&quot;contenttypemethod&quot; value=&quot;manual&quot;&gt;
</span><span class="lines">@@ -89,11 +83,27 @@
</span><span class="cx">              onchange=&quot;if (this.value) this.form.contenttypemethod[2].checked = true;&quot;&gt;
</span><span class="cx">   &lt;/td&gt;
</span><span class="cx"> &lt;/tr&gt;
</span><del>-&lt;tr&gt;
</del><ins>+&lt;tr[% ' class=&quot;expert_fields&quot;' UNLESS bug.id %]&gt;
</ins><span class="cx">   &lt;td&gt; &lt;/td&gt;
</span><span class="cx">   &lt;td&gt;
</span><span class="cx">     [% IF flag_types &amp;&amp; flag_types.size &gt; 0 %]
</span><del>-      [% PROCESS &quot;flag/list.html.tmpl&quot; bug_id=bugid attach_id=attachid %]&lt;br&gt;
</del><ins>+      [% PROCESS &quot;flag/list.html.tmpl&quot; %]&lt;br&gt;
</ins><span class="cx">     [% END %]
</span><span class="cx">   &lt;/td&gt;
</span><span class="cx"> &lt;/tr&gt;
</span><ins>+
+[% BLOCK content_types %]
+  [% mimetypes = [{type =&gt; &quot;text/plain&quot;, desc =&gt; &quot;plain text&quot;},
+                  {type =&gt; &quot;text/html&quot;,  desc =&gt; &quot;HTML source&quot;},
+                  {type =&gt; &quot;application/xml&quot;, desc =&gt; &quot;XML source&quot;},
+                  {type =&gt; &quot;image/gif&quot;,  desc =&gt; &quot;GIF image&quot;},
+                  {type =&gt; &quot;image/jpeg&quot;, desc =&gt; &quot;JPEG image&quot;},
+                  {type =&gt; &quot;image/png&quot;,  desc =&gt; &quot;PNG image&quot;},
+                  {type =&gt; &quot;application/octet-stream&quot;, desc =&gt; &quot;binary file&quot;}]
+  %]
+  [% Hook.process(&quot;mimetypes&quot;, &quot;attachment/createformcontents.html.tmpl&quot;) %]
+
+  [% FOREACH m = mimetypes %]
+    &lt;option value=&quot;[% m.type FILTER html %]&quot;&gt;[% m.desc FILTER html %] ([% m.type FILTER html %])&lt;/option&gt;
+  [% END %]
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultattachmentdifffilehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/attachment/diff-file.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/attachment/diff-file.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/attachment/diff-file.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -16,6 +16,7 @@
</span><span class="cx">   # Rights Reserved.
</span><span class="cx">   #
</span><span class="cx">   # Contributor(s): John Keiser &lt;jkeiser@netscape.com&gt;
</span><ins>+  #                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [%# This line is really long for a reason: to get rid of any possible textnodes
</span><span class="lines">@@ -52,7 +53,7 @@
</span><span class="cx"> [% FOREACH section = sections %]
</span><span class="cx">   [% section_num = section_num + 1 %]
</span><span class="cx">   &lt;tr&gt;&lt;th colspan=&quot;4&quot; class=&quot;section_head&quot;&gt;
</span><del>-    &lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot;&gt;
</del><ins>+    &lt;table id=&quot;[% file.filename FILTER html %]_sec[% section_num %]&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot;&gt;
</ins><span class="cx">     &lt;tr&gt;&lt;th width=&quot;95%&quot; align=&quot;left&quot;&gt;
</span><span class="cx">   [% IF file.is_add %]
</span><span class="cx">     Added
</span><span class="lines">@@ -78,7 +79,7 @@
</span><span class="cx">     &amp;nbsp;&amp;nbsp;[% section.func_info FILTER html IF section.func_info %]
</span><span class="cx">   [% END %] 
</span><span class="cx">     &lt;/th&gt;&lt;th&gt;
</span><del>-  &lt;a name=&quot;[% file.filename FILTER html %]_sec[% section_num %]&quot; href=&quot;#[% file.filename FILTER html %]_sec[% section_num %]&quot;&gt;Link&amp;nbsp;Here&lt;/a&gt;&amp;nbsp;
</del><ins>+  &lt;a href=&quot;#[% file.filename FILTER html %]_sec[% section_num %]&quot;&gt;Link&amp;nbsp;Here&lt;/a&gt;&amp;nbsp;
</ins><span class="cx">     &lt;/th&gt;&lt;/tr&gt;&lt;/table&gt;
</span><span class="cx">   &lt;/th&gt;&lt;/tr&gt;
</span><span class="cx">   [% current_line_old = section.old_start %]
</span><span class="lines">@@ -99,30 +100,31 @@
</span><span class="cx">     [% IF group.plus.size %]
</span><span class="cx">       [% IF group.minus.size %]
</span><span class="cx">         [% i = 0 %]
</span><del>-        [%# We need to store them in external variables. %]
-        [% curr_new = current_line_new %]
-        [% curr_old = current_line_old %]
</del><span class="cx">         [% WHILE (i &lt; group.plus.size || i &lt; group.minus.size) %]
</span><ins>+          [%# WHILE cannot loop more than 1000 times by default, so we break it every 500 times. %]
</ins><span class="cx">           [% currentloop = 0 %]
</span><span class="cx">           [% WHILE currentloop &lt; 500 &amp;&amp; (i &lt; group.plus.size || i &lt; group.minus.size) %]
</span><span class="cx">             &lt;tr&gt;
</span><del>-              &lt;td class=&quot;num&quot;&gt;[% curr_old %]&lt;/td&gt;
</del><ins>+            [% IF i &lt; group.minus.size %]
+              &lt;td class=&quot;num&quot;&gt;[% current_line_old + i %]&lt;/td&gt;
</ins><span class="cx">               &lt;td class=&quot;changed&quot;&gt;&lt;pre&gt;[% group.minus.$i FILTER html %]&lt;/pre&gt;&lt;/td&gt;
</span><del>-              &lt;td class=&quot;num&quot;&gt;[% curr_new %]&lt;/td&gt;
</del><ins>+            [% ELSIF i == group.minus.size %]
+              [% rowspan = group.plus.size - group.minus.size %]
+              &lt;td class=&quot;num&quot;[% IF rowspan &gt; 1 %] rowspan=&quot;[% rowspan FILTER none %]&quot;[% END %]&gt;&lt;/td&gt;
+              &lt;td class=&quot;changed&quot;[% IF rowspan &gt; 1 %] rowspan=&quot;[% rowspan FILTER none %]&quot;[% END %]&gt;&lt;/td&gt;
+            [% END %]
+
+            [% IF i &lt; group.plus.size %]
+              &lt;td class=&quot;num&quot;&gt;[% current_line_new + i %]&lt;/td&gt;
</ins><span class="cx">               &lt;td class=&quot;changed&quot;&gt;&lt;pre&gt;[% group.plus.$i FILTER html %]&lt;/pre&gt;&lt;/td&gt;
</span><ins>+            [% ELSIF i == group.plus.size %]
+              [% rowspan = group.minus.size - group.plus.size %]
+              &lt;td class=&quot;num&quot;[% IF rowspan &gt; 1 %] rowspan=&quot;[% rowspan FILTER none %]&quot;[% END %]&gt;&lt;/td&gt;
+              &lt;td class=&quot;changed&quot;[% IF rowspan &gt; 1 %] rowspan=&quot;[% rowspan FILTER none %]&quot;[% END %]&gt;&lt;/td&gt;
+            [% END %]
</ins><span class="cx">             &lt;/tr&gt;
</span><span class="cx">             [% currentloop = currentloop + 1 %]
</span><span class="cx">             [% i = i + 1 %]
</span><del>-            [% IF i &lt; group.minus.size %]
-              [% curr_old = curr_old + 1 %]
-            [% ELSE %]
-              [% curr_old = &quot;&quot; %]
-            [% END %]
-            [% IF i &lt; group.plus.size %]
-              [% curr_new = curr_new + 1 %]
-            [% ELSE %]
-              [% curr_new = &quot;&quot; %]
-            [% END %]
</del><span class="cx">           [% END %]
</span><span class="cx">         [% END %]
</span><span class="cx">         [% current_line_old = current_line_old + group.minus.size %]
</span><span class="lines">@@ -136,7 +138,10 @@
</span><span class="cx">             &lt;/tr&gt;
</span><span class="cx">           [% ELSE %]
</span><span class="cx">             &lt;tr&gt;
</span><del>-              &lt;td class=&quot;num&quot;&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;
</del><ins>+            [% IF loop.first %]
+              &lt;td class=&quot;num&quot;[% IF group.plus.size &gt; 1 %] rowspan=&quot;[% group.plus.size %]&quot;[% END %]&gt;&lt;/td&gt;
+              &lt;td[% IF group.plus.size &gt; 1 %] rowspan=&quot;[% group.plus.size %]&quot;[% END %]&gt;&lt;/td&gt;
+            [% END %]
</ins><span class="cx">               &lt;td class=&quot;num&quot;&gt;[% current_line_new %]&lt;/td&gt;
</span><span class="cx">               &lt;td class=&quot;added&quot;&gt;&lt;pre&gt;[% line FILTER html %]&lt;/pre&gt;&lt;/td&gt;
</span><span class="cx">             &lt;/tr&gt;
</span><span class="lines">@@ -156,7 +161,10 @@
</span><span class="cx">             &lt;tr&gt;
</span><span class="cx">               &lt;td class=&quot;num&quot;&gt;[% current_line_old %]&lt;/td&gt;
</span><span class="cx">               &lt;td class=&quot;removed&quot;&gt;&lt;pre&gt;[% line FILTER html %]&lt;/pre&gt;&lt;/td&gt;
</span><del>-              &lt;td class=&quot;num&quot;&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;
</del><ins>+            [% IF loop.first %]
+              &lt;td class=&quot;num&quot;[% IF group.minus.size &gt; 1 %] rowspan=&quot;[% group.minus.size %]&quot;[% END %]&gt;&lt;/td&gt;
+              &lt;td[% IF group.minus.size &gt; 1 %] rowspan=&quot;[% group.minus.size %]&quot;[% END %]&gt;&lt;/td&gt;
+            [% END %]
</ins><span class="cx">             &lt;/tr&gt;
</span><span class="cx">           [% END %]
</span><span class="cx">           [% current_line_old = current_line_old + 1 %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultattachmentdifffooterhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/attachment/diff-footer.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/attachment/diff-footer.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/attachment/diff-footer.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -24,6 +24,9 @@
</span><span class="cx"> 
</span><span class="cx">   &lt;br&gt;
</span><span class="cx"> 
</span><ins>+  [% PROCESS global/variables.none.tmpl %]
+  &lt;span&gt;Return to [% &quot;$terms.bug $bugid&quot; FILTER bug_link(bugid) FILTER none %]&lt;/span&gt;
+
</ins><span class="cx">   [% PROCESS global/footer.html.tmpl %]
</span><span class="cx">  
</span><span class="cx"> [% ELSE %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultattachmentdiffheaderhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/attachment/diff-header.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/attachment/diff-header.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/attachment/diff-header.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -30,176 +30,6 @@
</span><span class="cx">   [% END %]
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><del>-[% style = BLOCK %]
-.file_head {
-  font-weight: bold;
-  font-size: 1em;
-  background-color: #c3c3c3;
-  border: 1px solid black;
-}
-
-.file_head a {
-  text-decoration: none; 
-  font-family: monospace; 
-  font-size: 1.1em;
-}
-
-.file_collapse {
-  display: none;
-}
-
-.section_head {
-  background-color: #f0f0f0;
-  border: 1px solid black;
-  text-align: left;
-}
-
-table.file_table {
-  table-layout: fixed;
-  width: 100%;
-  empty-cells: show;
-  border-spacing: 0px;
-  border-collapse: collapse;
-  /* draw border below last open context section in listing */
-  border-bottom: 1px solid black;
-}
-
-tbody.file pre {
-  display: inline;
-  white-space: pre-wrap; /* CSS 3 &amp; CSS 2.1 */
-  white-space: -moz-pre-wrap; /* Gecko &lt; 1.9.1 */
-  white-space: -o-pre-wrap; /* Opera 7 */
-  font-size: 0.9em;
-}
-
-tbody.file pre:empty {
-  display: block;
-}
-
-.changed {
-  background-color: lightblue;
-}
-
-.added {
-  background-color: lightgreen;
-}
-
-.removed {
-  background-color: #FFCC99;
-}
-
-.num {
-  background-color: #ffe9ae;
-  text-align:right;
-  padding: 0 0.3em;
-  width: 3em;
-}
-
-.warning {
-  color: red
-}
-[% END %]
-
-[%# SCRIPT FUNCTIONS %]
-[% javascript = BLOCK %]
-  function collapse_all() {
-    var elem = document.checkboxform.firstChild;
-    while (elem != null) {
-      if (elem.firstChild != null) {
-        var tbody = elem.firstChild.nextSibling;
-        if (tbody.className == 'file') {
-          tbody.className = 'file_collapse';
-          twisty = get_twisty_from_tbody(tbody);
-          twisty.firstChild.nodeValue = '(+)';
-          twisty.nextSibling.checked = false;
-        }
-      }
-      elem = elem.nextSibling;
-    }
-    return false;
-  }
-
-  function expand_all() {
-    var elem = document.checkboxform.firstChild;
-    while (elem != null) {
-      if (elem.firstChild != null) {
-        var tbody = elem.firstChild.nextSibling;
-        if (tbody.className == 'file_collapse') {
-          tbody.className = 'file';
-          twisty = get_twisty_from_tbody(tbody);
-          twisty.firstChild.nodeValue = '(-)';
-          twisty.nextSibling.checked = true;
-        }
-      }
-      elem = elem.nextSibling;
-    }
-    return false;
-  }
-
-  var current_restore_elem;
-
-  function restore_all() {
-    current_restore_elem = null;
-    incremental_restore();
-  }
-
-  function incremental_restore() {
-    if (!document.checkboxform.restore_indicator.checked) {
-      return;
-    }
-    var next_restore_elem;
-    if (current_restore_elem) {
-      next_restore_elem = current_restore_elem.nextSibling;
-    } else {
-      next_restore_elem = document.checkboxform.firstChild;
-    }
-    while (next_restore_elem != null) {
-      current_restore_elem = next_restore_elem;
-      if (current_restore_elem.firstChild != null) {
-        restore_elem(current_restore_elem.firstChild.nextSibling);
-      }
-      next_restore_elem = current_restore_elem.nextSibling;
-    }
-  }
-
-  function restore_elem(elem, alertme) {
-    if (elem.className == 'file_collapse') {
-      twisty = get_twisty_from_tbody(elem);
-      if (twisty.nextSibling.checked) {
-        elem.className = 'file';
-        twisty.firstChild.nodeValue = '(-)';
-      }
-    } else if (elem.className == 'file') {
-      twisty = get_twisty_from_tbody(elem);
-      if (!twisty.nextSibling.checked) {
-        elem.className = 'file_collapse';
-        twisty.firstChild.nodeValue = '(+)';
-      }
-    }
-  }
-
-  function twisty_click(twisty) {
-    tbody = get_tbody_from_twisty(twisty);
-    if (tbody.className == 'file') {
-      tbody.className = 'file_collapse';
-      twisty.firstChild.nodeValue = '(+)';
-      twisty.nextSibling.checked = false;
-    } else {
-      tbody.className = 'file';
-      twisty.firstChild.nodeValue = '(-)';
-      twisty.nextSibling.checked = true;
-    }
-    return false;
-  }
-
-  function get_tbody_from_twisty(twisty) {
-    return twisty.parentNode.parentNode.parentNode.nextSibling;
-  }
-  function get_twisty_from_tbody(tbody) {
-    return tbody.previousSibling.firstChild.nextSibling.firstChild.firstChild;
-  }
-[% END %]
-
</del><span class="cx"> [% onload = 'restore_all(); document.checkboxform.restore_indicator.checked = true' %]
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK viewurl %]attachment.cgi?id=[% id %][% END %]
</span><span class="lines">@@ -221,18 +51,16 @@
</span><span class="cx">   [% subheader = BLOCK %]
</span><span class="cx">     [% bugsummary FILTER html %]
</span><span class="cx">   [% END %]
</span><del>-  [% PROCESS global/header.html.tmpl doc_section = &quot;attachments.html#patchviewer&quot; %]
</del><ins>+  [% PROCESS global/header.html.tmpl doc_section = &quot;attachments.html#patchviewer&quot;
+                                     javascript_urls = &quot;js/attachment.js&quot;
+                                     style_urls = ['skins/standard/attachment.css'] %]
</ins><span class="cx"> [% ELSE %]
</span><span class="cx">   &lt;html&gt;
</span><span class="cx">   &lt;head&gt;
</span><del>-  &lt;style type=&quot;text/css&quot;&gt;
-  [% style %]
-  &lt;/style&gt;
-  &lt;script type=&quot;text/javascript&quot;&gt;
-  &lt;!--
-  [% javascript %]
-  --&gt;
-  &lt;/script&gt;
</del><ins>+  &lt;link href=&quot;[% 'skins/standard/attachment.css' FILTER mtime %]&quot; 
+        rel=&quot;stylesheet&quot; type=&quot;text/css&quot;&gt;
+  &lt;script src=&quot;[% 'js/attachment.js' FILTER mtime %]&quot; 
+          type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
</ins><span class="cx">   &lt;/head&gt;
</span><span class="cx">   &lt;body onload=&quot;[% onload FILTER html %]&quot;&gt;
</span><span class="cx"> [% END %]
</span><span class="lines">@@ -243,7 +71,8 @@
</span><span class="cx">   [% IF headers %]
</span><span class="cx">     &lt;a href=&quot;[% PROCESS viewurl id=attachid %]&quot;&gt;View&lt;/a&gt;
</span><span class="cx">     | &lt;a href=&quot;[% PROCESS editurl id=attachid %]&quot;&gt;Details&lt;/a&gt;
</span><del>-    | &lt;a href=&quot;[% PROCESS diffurl id=attachid %]&amp;amp;context=[% context FILTER url_quote %]&amp;amp;collapsed=[% collapsed FILTER url_quote %]&amp;amp;headers=[% headers FILTER url_quote %]&amp;amp;format=raw&quot;&gt;Raw&amp;nbsp;Unified&lt;/a&gt;
</del><ins>+    | &lt;a href=&quot;[% PROCESS diffurl id=attachid %]&amp;amp;context=[% context FILTER uri %]&amp;amp;collapsed=[% collapsed FILTER uri %]&amp;amp;headers=[% headers FILTER uri %]&amp;amp;format=raw&quot;&gt;Raw&amp;nbsp;Unified&lt;/a&gt;
+    | Return to [% &quot;$terms.bug $bugid&quot; FILTER bug_link(bugid) FILTER none %]
</ins><span class="cx">   [% END %]
</span><span class="cx">   [% IF other_patches.size &gt; 0 %]
</span><span class="cx">     [% IF headers %] |[%END%]
</span><span class="lines">@@ -267,6 +96,7 @@
</span><span class="cx"> [% ELSE %]
</span><span class="cx">   [% IF headers %]
</span><span class="cx">     &lt;a href=&quot;attachment.cgi?oldid=[% oldid %]&amp;amp;newid=[% newid %]&amp;amp;action=interdiff&amp;amp;format=raw&quot;&gt;Raw Unified&lt;/a&gt;
</span><ins>+    | Return to [% &quot;$terms.bug $bugid&quot; FILTER bug_link(bugid) FILTER none %]
</ins><span class="cx">     |
</span><span class="cx">   [% END %]
</span><span class="cx"> [% END %]
</span><span class="lines">@@ -287,12 +117,12 @@
</span><span class="cx">   [% IF context == &quot;patch&quot; %]
</span><span class="cx">     (&lt;strong&gt;Patch&lt;/strong&gt; / 
</span><span class="cx">   [% ELSE %]
</span><del>-    (&lt;a href=&quot;[% PROCESS diffurl id=attachid %]&amp;amp;headers=[% headers FILTER url_quote %]&quot;&gt;Patch&lt;/a&gt; / 
</del><ins>+    (&lt;a href=&quot;[% PROCESS diffurl id=attachid %]&amp;amp;headers=[% headers FILTER uri %]&quot;&gt;Patch&lt;/a&gt; / 
</ins><span class="cx">   [% END %]
</span><span class="cx">   [% IF context == &quot;file&quot; %]
</span><span class="cx">     &lt;strong&gt;File&lt;/strong&gt; /
</span><span class="cx">   [% ELSE %]
</span><del>-    &lt;a href=&quot;[% PROCESS diffurl id=attachid %]&amp;amp;headers=[% headers FILTER url_quote %]&amp;amp;context=file&quot;&gt;File&lt;/a&gt; / 
</del><ins>+    &lt;a href=&quot;[% PROCESS diffurl id=attachid %]&amp;amp;headers=[% headers FILTER uri %]&amp;amp;context=file&quot;&gt;File&lt;/a&gt; / 
</ins><span class="cx">   [% END %]
</span><span class="cx"> 
</span><span class="cx">   [% IF context == &quot;patch&quot; || context == &quot;file&quot; %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultattachmentedithtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/attachment/edit.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/attachment/edit.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/attachment/edit.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -17,6 +17,7 @@
</span><span class="cx">   #
</span><span class="cx">   # Contributor(s): Myk Melez &lt;myk@mozilla.org&gt;
</span><span class="cx">   #                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
</span><ins>+  #                 Guy Pyrzak &lt;guy.pyrzak@gmail.com&gt;
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="lines">@@ -29,143 +30,24 @@
</span><span class="cx">   Attachment [% attachment.id %] Details for
</span><span class="cx">   [%+ &quot;$terms.Bug ${attachment.bug_id}&quot; FILTER bug_link(attachment.bug_id) FILTER none %]
</span><span class="cx"> [% END %]
</span><del>-[% subheader = BLOCK %][% bugsummary FILTER html %][% END %]
</del><ins>+[% subheader = BLOCK %][% attachment.bug.short_desc FILTER html %][% END %]
</ins><span class="cx"> 
</span><span class="cx"> [% PROCESS global/header.html.tmpl
</span><span class="cx">   title = title
</span><span class="cx">   header = header
</span><span class="cx">   subheader = subheader
</span><span class="cx">   doc_section = &quot;attachments.html&quot;
</span><ins>+  javascript_urls = ['js/attachment.js', 'js/field.js']
+  style_urls = ['skins/standard/attachment.css']
+  yui = [ 'autocomplete' ]
+  bodyclasses = &quot;no_javascript&quot;
</ins><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> [%# No need to display the Diff button and iframe if the attachment is not a patch. %]
</span><del>-[% patchviewerinstalled = (patchviewerinstalled &amp;&amp; attachment.ispatch) %]
</del><ins>+[% use_patchviewer = (feature_enabled('patch_viewer') &amp;&amp; attachment.ispatch) %]
+[% can_edit = attachment.validate_can_edit %]
+[% editable_or_hide = can_edit ? &quot;&quot; : &quot; bz_hidden_option&quot; %]
</ins><span class="cx"> 
</span><del>-&lt;script type=&quot;text/javascript&quot;&gt;
-  &lt;!--
-  var prev_mode = 'raw';
-  var current_mode = 'raw';
-  var has_edited = 0;
-  var has_viewed_as_diff = 0;
-  function editAsComment()
-    {
-      switchToMode('edit');
-      has_edited = 1;
-    }
-  function undoEditAsComment()
-    {
-      switchToMode(prev_mode);
-    }
-  function redoEditAsComment()
-    {
-      switchToMode('edit');
-    }
-[% IF patchviewerinstalled %]
-  function viewDiff()
-    {
-      switchToMode('diff');
-
-      // If we have not viewed as diff before, set the view diff frame URL
-      if (!has_viewed_as_diff) {
-        var viewDiffFrame = document.getElementById('viewDiffFrame');
-        viewDiffFrame.src =
-            'attachment.cgi?id=[% attachment.id %]&amp;action=diff&amp;headers=0';
-        has_viewed_as_diff = 1;
-      }
-    }
-[% END %]
-  function viewRaw()
-    {
-      switchToMode('raw');
-    }
-
-  function switchToMode(mode)
-    {
-      if (mode == current_mode) {
-        alert('switched to same mode!  This should not happen.');
-        return;
-      }
-
-      // Switch out of current mode
-      if (current_mode == 'edit') {
-        hideElementById('editFrame');
-        hideElementById('undoEditButton');
-      } else if (current_mode == 'raw') {
-        hideElementById('viewFrame');
-[% IF patchviewerinstalled %]
-        hideElementById('viewDiffButton');
-[% END %]
-        hideElementById(has_edited ? 'redoEditButton' : 'editButton');
-        hideElementById('smallCommentFrame');
-      } else if (current_mode == 'diff') {
-[% IF patchviewerinstalled %]
-        hideElementById('viewDiffFrame');
-[% END %]
-        hideElementById('viewRawButton');
-        hideElementById(has_edited ? 'redoEditButton' : 'editButton');
-        hideElementById('smallCommentFrame');
-      }
-
-      // Switch into new mode
-      if (mode == 'edit') {
-        showElementById('editFrame');
-        showElementById('undoEditButton');
-      } else if (mode == 'raw') {
-        showElementById('viewFrame');
-[% IF patchviewerinstalled %]
-        showElementById('viewDiffButton');
-[% END %]
-        showElementById(has_edited ? 'redoEditButton' : 'editButton');
-        showElementById('smallCommentFrame');
-      } else if (mode == 'diff') {
-[% IF patchviewerinstalled %]
-        showElementById('viewDiffFrame');
-[% END %]
-        showElementById('viewRawButton');
-        showElementById(has_edited ? 'redoEditButton' : 'editButton');
-        showElementById('smallCommentFrame');
-      }
-
-      prev_mode = current_mode;
-      current_mode = mode;
-    }
-
-  function hideElementById(id)
-  {
-    var elm = document.getElementById(id);
-    if (elm) {
-      elm.style.display = 'none';
-    }
-  }
-
-  function showElementById(id, val)
-  {
-    var elm = document.getElementById(id);
-    if (elm) {
-      if (!val) val = 'inline';
-      elm.style.display = val;
-    }
-  }
-
-  function normalizeComments()
-  {
-    // Remove the unused comment field from the document so its contents
-    // do not get transmitted back to the server.
-
-    var small = document.getElementById('smallCommentFrame');
-    var big = document.getElementById('editFrame');
-    if ( (small) &amp;&amp; (small.style.display == 'none') )
-    {
-      small.parentNode.removeChild(small);
-    }
-    if ( (big) &amp;&amp; (big.style.display == 'none') )
-    {
-      big.parentNode.removeChild(big);
-    }
-  }
-  //--&gt;
-&lt;/script&gt;
-
</del><span class="cx"> &lt;form method=&quot;post&quot; action=&quot;attachment.cgi&quot; onsubmit=&quot;normalizeComments();&quot;&gt;
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;id&quot; value=&quot;[% attachment.id %]&quot;&gt;
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;update&quot;&gt;
</span><span class="lines">@@ -175,163 +57,254 @@
</span><span class="cx">     &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% issue_hash_token([attachment.id, attachment.modification_time]) FILTER html %]&quot;&gt;
</span><span class="cx">   [% END %]
</span><span class="cx"> 
</span><del>-  &lt;table class=&quot;attachment_info&quot; width=&quot;100%&quot;&gt;
-
-    &lt;tr&gt;
-      &lt;td width=&quot;25%&quot;&gt;
-        &lt;small&gt;
-        &lt;b&gt;&lt;label for=&quot;description&quot;&gt;Description&lt;/label&gt;:&lt;/b&gt;&lt;br&gt;
</del><ins>+  &lt;div id=&quot;attachment_info&quot; class=&quot;attachment_info [% IF can_edit %] edit[% ELSE %] read[% END%]&quot;&gt;
+    &lt;div id=&quot;attachment_attributes&quot;&gt;
+      &lt;div id=&quot;attachment_information_read_only&quot; class=&quot;[% &quot;bz_private&quot; IF attachment.isprivate %]&quot;&gt;
+        &lt;div class=&quot;title&quot;&gt;
+          [% &quot;[patch]&quot; IF attachment.ispatch%] 
+          &lt;span class=&quot;[% &quot;bz_obsolete&quot; IF attachment.isobsolete %]&quot; title=&quot;[% &quot;obsolete&quot; IF attachment.isobsolete %]&quot;&gt;              
+            [% attachment.description FILTER html %]
+          &lt;/span&gt;
+          [% IF can_edit %]
+            &lt;span class=&quot;bz_edit&quot;&gt;(&lt;a href=&quot;javascript:toggle_attachment_details_visibility()&quot;&gt;edit details&lt;/a&gt;)&lt;/span&gt;
+          [% END %]
+        &lt;/div&gt;
+        &lt;div class=&quot;details&quot;&gt;
+          [% attachment.filename FILTER html %] ([% attachment.contenttype FILTER html %]),
+          [% IF attachment.datasize %]
+            [%+ attachment.datasize FILTER unitconvert %]
+          [% ELSE %]
+            &lt;em&gt;deleted&lt;/em&gt;
+          [% END %], created by [%+ INCLUDE global/user.html.tmpl who = attachment.attacher %]
+          [% IF attachment.isprivate %];
+            &lt;span class=&quot;bz_private&quot;&gt;only visible to &lt;strong&gt;[% Param('insidergroup') FILTER html %]&lt;/strong&gt; members&lt;/span&gt;
+          [% END %]
+        &lt;/div&gt;
+      &lt;/div&gt;
+      &lt;div id=&quot;attachment_information_edit&quot;&gt;
+        &lt;span class=&quot;bz_hide&quot;&gt;
+          (&lt;a href=&quot;javascript:toggle_attachment_details_visibility();&quot;&gt;hide&lt;/a&gt;)
+        &lt;/span&gt;
+        &lt;div id=&quot;attachment_description&quot;&gt;
+          &lt;label for=&quot;description&quot;&gt;Description:&lt;/label&gt;&amp;nbsp;
</ins><span class="cx">           [% INCLUDE global/textarea.html.tmpl
</span><span class="cx">             id             = 'description'
</span><span class="cx">             name           = 'description'
</span><span class="cx">             minrows        = 3
</span><span class="cx">             cols           = 25
</span><span class="cx">             wrap           = 'soft'
</span><ins>+            classes        = 'block' _ editable_or_hide
</ins><span class="cx">             defaultcontent = attachment.description
</span><del>-          %]&lt;br&gt;
</del><ins>+          %]          
+        &lt;/div&gt;
</ins><span class="cx"> 
</span><del>-        [% IF attachment.isurl %]
-            &lt;input type=&quot;hidden&quot; name=&quot;filename&quot;
-                   value=&quot;[% attachment.filename FILTER html %]&quot;&gt;
-            &lt;input type=&quot;hidden&quot; name=&quot;contenttypeentry&quot;
-                   value=&quot;[% attachment.contenttype FILTER html %]&quot;&gt;
-        [% ELSE %]
-          &lt;b&gt;&lt;label for=&quot;filename&quot;&gt;Filename&lt;/label&gt;:&lt;/b&gt;&lt;br&gt;
-            &lt;input type=&quot;text&quot; size=&quot;20&quot; id=&quot;filename&quot; name=&quot;filename&quot;
-                   value=&quot;[% attachment.filename FILTER html %]&quot;&gt;&lt;br&gt;
-          &lt;b&gt;Size:&lt;/b&gt;
-          [% IF attachment.datasize %]
-            [%+ attachment.datasize FILTER unitconvert %]
-          [% ELSE %]
-            &lt;em&gt;deleted&lt;/em&gt;
-          [% END %]&lt;br&gt;
</del><ins>+          &lt;div id=&quot;attachment_filename&quot;&gt;
+            &lt;label for=&quot;filename&quot;&gt;Filename:&lt;/label&gt;
+            &lt;input type=&quot;text&quot; size=&quot;20&quot;  class=&quot;text block[% editable_or_hide %]&quot;
+                   id=&quot;filename&quot; name=&quot;filename&quot;
+                   value=&quot;[% attachment.filename FILTER html %]&quot;&gt;     
+          &lt;/div&gt;
</ins><span class="cx"> 
</span><del>-          &lt;b&gt;&lt;label for=&quot;contenttypeentry&quot;&gt;MIME Type&lt;/label&gt;:&lt;/b&gt;&lt;br&gt;
-            &lt;input type=&quot;text&quot; size=&quot;20&quot;
</del><ins>+          &lt;div id=&quot;attachment_mimetype&quot;&gt;
+            &lt;label for=&quot;contenttypeentry&quot;&gt;MIME Type:&lt;/label&gt;
+            &lt;input type=&quot;text&quot; size=&quot;20&quot; class=&quot;text block[% editable_or_hide %]&quot;
</ins><span class="cx">                    id=&quot;contenttypeentry&quot; name=&quot;contenttypeentry&quot;
</span><del>-                   value=&quot;[% attachment.contenttype FILTER html %]&quot;&gt;&lt;br&gt;
</del><ins>+                   value=&quot;[% attachment.contenttype FILTER html %]&quot;&gt;                   
+          &lt;/div&gt;
+          
+          &lt;div id=&quot;attachment_creator&quot;&gt;
+            &lt;span class=&quot;label&quot;&gt;Creator:&lt;/span&gt;
+            [%+ INCLUDE global/user.html.tmpl who = attachment.attacher %]
+          &lt;/div&gt;
+          
+          &lt;div id=&quot;attachment_size&quot;&gt;
+            &lt;span class=&quot;label&quot;&gt;Size:&lt;/span&gt;
+            [% IF attachment.datasize %]
+              [%+ attachment.datasize FILTER unitconvert %]
+            [% ELSE %]
+              &lt;em&gt;deleted&lt;/em&gt;
+            [% END %]
+          &lt;/div&gt;
</ins><span class="cx"> 
</span><del>-          &lt;input type=&quot;checkbox&quot; id=&quot;ispatch&quot; name=&quot;ispatch&quot; value=&quot;1&quot;
-                 [%+ 'checked=&quot;checked&quot;' IF attachment.ispatch %]&gt;
-          &lt;label for=&quot;ispatch&quot;&gt;patch&lt;/label&gt;
-        [% END %]
-          &lt;input type=&quot;checkbox&quot; id=&quot;isobsolete&quot; name=&quot;isobsolete&quot; value=&quot;1&quot;
-                 [%+ 'checked=&quot;checked&quot;' IF attachment.isobsolete %]&gt;
-          &lt;label for=&quot;isobsolete&quot;&gt;obsolete&lt;/label&gt;
-          [% IF (Param(&quot;insidergroup&quot;) &amp;&amp; user.in_group(Param(&quot;insidergroup&quot;))) %]
-            &lt;input type=&quot;checkbox&quot; id=&quot;isprivate&quot; name=&quot;isprivate&quot; value=&quot;1&quot;
-                   [% &quot; checked&quot; IF attachment.isprivate %]&gt;
-            &lt;label for=&quot;isprivate&quot;&gt;private&lt;/label&gt;&lt;br&gt;
-          [% END %]
-          &lt;br&gt;
-        &lt;/small&gt;
</del><ins>+          &lt;div id=&quot;attachment_ispatch&quot;&gt;
+            &lt;input type=&quot;checkbox&quot; id=&quot;ispatch&quot; name=&quot;ispatch&quot; value=&quot;1&quot;
+                   [%+ 'checked=&quot;checked&quot;' IF attachment.ispatch %]&gt;
+                   &lt;label for=&quot;ispatch&quot;&gt;patch&lt;/label&gt;
+          &lt;/div&gt;
</ins><span class="cx"> 
</span><del>-        [% IF flag_types.size &gt; 0 %]
-          [% PROCESS &quot;flag/list.html.tmpl&quot; bug_id = attachment.bug_id
-                                           attach_id = attachment.id %]&lt;br&gt;
-        [% END %]
</del><ins>+        &lt;div class=&quot;readonly&quot;&gt;
+          &lt;div class=&quot;checkboxes&quot;&gt;
+            &lt;div id=&quot;attachment_isobsolete&quot;&gt;
+              &lt;input type=&quot;checkbox&quot; id=&quot;isobsolete&quot; name=&quot;isobsolete&quot; value=&quot;1&quot;                     
+                     [%+ 'checked=&quot;checked&quot;' IF attachment.isobsolete %]&gt;
+                &lt;label for=&quot;isobsolete&quot;&gt;obsolete&lt;/label&gt;
+            &lt;/div&gt;
</ins><span class="cx"> 
</span><del>-        &lt;div id=&quot;smallCommentFrame&quot;&gt;
-          &lt;b&gt;&lt;small&gt;&lt;label for=&quot;comment&quot;&gt;Comment&lt;/label&gt; (on the
-          [%+ terms.bug %]):&lt;/small&gt;&lt;/b&gt;&lt;br&gt;
</del><ins>+            [% IF user.is_insider %]
+              &lt;div id=&quot;attachment_isprivate&quot;&gt;
+                &lt;input type=&quot;checkbox&quot; id=&quot;isprivate&quot; name=&quot;isprivate&quot; value=&quot;1&quot;
+                       [%+ 'checked=&quot;checked&quot;' IF attachment.isprivate %]&gt;
+                [% IF can_edit %]
+                  &lt;label for=&quot;isprivate&quot;&gt;private (only visible to
+                    &lt;strong&gt;[% Param('insidergroup') FILTER html %]&lt;/strong&gt;)
+                  &lt;/label&gt;
+                [% ELSE %]
+                  &lt;span class=&quot;label&quot;&gt;Is Private:&lt;/span&gt;
+                  [%+ attachment.isprivate ? &quot;yes&quot; : &quot;no&quot; %]
+                [% END %]
+              &lt;/div&gt;
+            [% END %]
+          &lt;/div&gt;
+        &lt;/div&gt;                    
+      &lt;/div&gt;
+
+      &lt;div id=&quot;attachment_view_window&quot;&gt;
+        [% IF !attachment.datasize %]
+          &lt;div&gt;&lt;b&gt;The content of this attachment has been deleted.&lt;/b&gt;&lt;/div&gt;
+        [% ELSIF !Param(&quot;allow_attachment_display&quot;) %]
+          &lt;div id=&quot;view_disabled&quot;&gt;
+            &lt;p&gt;&lt;b&gt;
+              The attachment is not viewable in your browser due to security
+              restrictions enabled by your [% terms.Bugzilla %] administrator.
+            &lt;/b&gt;&lt;/p&gt;
+            &lt;p&gt;&lt;b&gt;
+              In order to view the attachment, you first have to
+              &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&quot;&gt;download it&lt;/a&gt;.
+            &lt;/b&gt;&lt;/p&gt;
+          &lt;/div&gt;
+        [% ELSIF attachment.is_viewable %]
+          &lt;div&gt;
</ins><span class="cx">             [% INCLUDE global/textarea.html.tmpl
</span><ins>+              id      = 'editFrame'
+              name    = 'comment'
+              classes   = 'bz_default_hidden'
+              minrows = 10
+              cols    = 80
+              wrap    = 'soft'
+              disabled = 'disabled'
+              defaultcontent = (attachment.contenttype.match('^text\/')) ?
+                                 attachment.data.replace('(.*\n|.+)', '&gt;$1') : undef
+            %]
+            [% IF attachment.contenttype == 'text/plain' AND is_safe_url(attachment.data) %]
+              &lt;p&gt;
+                &lt;a href=&quot;[% attachment.data FILTER html %]&quot;&gt;
+                  [% IF attachment.datasize &lt; 120 %]
+                    [% attachment.data FILTER html %]
+                  [% ELSE %]
+                    [% attachment.data FILTER truncate(80) FILTER html %]
+                    ...
+                    [% attachment.data.match('.*(.{20})$').0 FILTER html %]
+                  [% END %]
+                &lt;/a&gt;
+              &lt;/p&gt;
+            [% ELSIF attachment.contenttype == &quot;text/html&quot; %]
+              [%# For security reasons (clickjacking, embedded scripts), we never
+                # render HTML pages from here. The source code is displayed instead. %]
+              [% INCLUDE global/textarea.html.tmpl
+                 id      = 'viewFrame'
+                 minrows = 10
+                 cols    = 80
+                 defaultcontent = attachment.data
+                 readonly = 'readonly'
+              %]
+            [% ELSE %]
+              &lt;iframe id=&quot;viewFrame&quot; src=&quot;attachment.cgi?id=[% attachment.id %]&quot;&gt;
+                &lt;b&gt;You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
+                &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&quot;&gt;View the attachment on a separate page&lt;/a&gt;.&lt;/b&gt;
+              &lt;/iframe&gt;
+            [% END %]
+            &lt;script type=&quot;text/javascript&quot;&gt;
+              &lt;!--
+              var patchviewerinstalled = 0;
+              var attachment_id = [% attachment.id %];
+              if (typeof document.getElementById == &quot;function&quot;) {
+                [% IF use_patchviewer %]
+                  var patchviewerinstalled = 1;
+                  document.write('&lt;iframe id=&quot;viewDiffFrame&quot; class=&quot;bz_default_hidden&quot;&gt;&lt;\/iframe&gt;');
+                [% END %]
+                [% IF user.id %]
+                  document.write('&lt;button type=&quot;button&quot; id=&quot;editButton&quot; onclick=&quot;editAsComment(patchviewerinstalled);&quot;&gt;Edit Attachment As Comment&lt;\/button&gt;');
+                  document.write('&lt;button type=&quot;button&quot; id=&quot;undoEditButton&quot; onclick=&quot;undoEditAsComment(patchviewerinstalled);&quot; class=&quot;bz_default_hidden&quot;&gt;Undo Edit As Comment&lt;\/button&gt;');
+                  document.write('&lt;button type=&quot;button&quot; id=&quot;redoEditButton&quot; onclick=&quot;redoEditAsComment(patchviewerinstalled);&quot; class=&quot;bz_default_hidden&quot;&gt;Redo Edit As Comment&lt;\/button&gt;');
+                  var editFrame = document.getElementById('editFrame');
+                  if (editFrame) {
+                    editFrame.disabled = false;
+                  }
+                [% END %]
+                [% IF use_patchviewer %]
+                  document.write('&lt;button type=&quot;button&quot; id=&quot;viewDiffButton&quot; onclick=&quot;viewDiff(attachment_id, patchviewerinstalled);&quot;&gt;View Attachment As Diff&lt;\/button&gt;');
+                [% END %]
+                document.write('&lt;button type=&quot;button&quot; id=&quot;viewRawButton&quot; onclick=&quot;viewRaw(patchviewerinstalled);&quot; class=&quot;bz_default_hidden&quot;&gt;View Attachment As Raw&lt;\/button&gt;');
+              }
+              //--&gt;
+            &lt;/script&gt;
+          &lt;/div&gt;
+        [% ELSE %]
+          &lt;div id=&quot;noview&quot;&gt;
+            &lt;p&gt;&lt;b&gt;
+              Attachment is not viewable in your browser because its MIME type 
+              ([% attachment.contenttype FILTER html %]) is not one that your browser is 
+              able to display.
+            &lt;/b&gt;&lt;/p&gt;
+            &lt;p&gt;&lt;b&gt;
+              &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&quot;&gt;Download the attachment&lt;/a&gt;.
+            &lt;/b&gt;&lt;/p&gt;
+          &lt;/div&gt;
+        [% END %]
+      &lt;/div&gt;
+      &lt;div id=&quot;attachment_comments_and_flags&quot;&gt;
+        [% IF user.id %]
+          &lt;div id=&quot;smallCommentFrame&quot; &gt;
+            &lt;label for=&quot;comment&quot;&gt;Comment (on the [% terms.bug %]):&lt;/label&gt;
+            [% classNames = 'block' %]
+            [% classNames = &quot;$classes bz_private&quot; IF attachment.isprivate %]
+            [% INCLUDE global/textarea.html.tmpl
</ins><span class="cx">               id      = 'comment'
</span><span class="cx">               name    = 'comment'
</span><del>-              minrows = 5
-              cols    = 25
</del><ins>+              minrows = 10
+              cols    = 80
</ins><span class="cx">               wrap    = 'soft'
</span><del>-            %]&lt;br&gt;
</del><ins>+              classes = classNames          
+            %]
+          &lt;/div&gt;
+        [% END %]             
+        &lt;div id=&quot;attachment_flags&quot;&gt;
+          [% IF attachment.flag_types.size &gt; 0 %]
+              [% PROCESS &quot;flag/list.html.tmpl&quot; flag_types = attachment.flag_types
+                                               read_only_flags = !can_edit
+              %]
+     
+          [% END %]
</ins><span class="cx">         &lt;/div&gt;
</span><span class="cx"> 
</span><del>-        &lt;input type=&quot;submit&quot; value=&quot;Submit&quot; id=&quot;update&quot;&gt;&lt;br&gt;&lt;br&gt;
-        &lt;strong&gt;Actions:&lt;/strong&gt;
-        &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&quot;&gt;View&lt;/a&gt;
-        [% IF attachment.ispatch &amp;&amp; patchviewerinstalled %]
-         | &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&amp;amp;action=diff&quot;&gt;Diff&lt;/a&gt;
-        [% END %]
-        [% IF Param(&quot;allow_attachment_deletion&quot;)
-              &amp;&amp; user.groups.admin
-              &amp;&amp; attachment.datasize &gt; 0 %]
-          | &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&amp;amp;action=delete&quot;&gt;Delete&lt;/a&gt;
-        [% END %]
-      &lt;/td&gt;
</del><ins>+        [% Hook.process('form_before_submit') %]
</ins><span class="cx"> 
</span><del>-      [% IF !attachment.datasize %]
-        &lt;td width=&quot;75%&quot;&gt;&lt;b&gt;The content of this attachment has been deleted.&lt;/b&gt;&lt;/td&gt;
-      [% ELSIF attachment.isurl %]
-        &lt;td width=&quot;75%&quot;&gt;
-          &lt;a href=&quot;[% attachment.data FILTER html %]&quot;&gt;
-            [% IF attachment.datasize &lt; 120 %]
-              [% attachment.data FILTER html %]
-            [% ELSE %]
-              [% attachment.data FILTER truncate(80) FILTER html %]
-              &amp;nbsp;...
-              [% attachment.data.match(&quot;.*(.{20})$&quot;).0 FILTER html %]
-            [% END %]
-          &lt;/a&gt;
-        &lt;/td&gt;
-      [% ELSIF !Param(&quot;allow_attachment_display&quot;) %]
-        &lt;td id=&quot;view_disabled&quot; width=&quot;50%&quot;&gt;
-          &lt;p&gt;&lt;b&gt;
-            The attachment is not viewable in your browser due to security
-            restrictions enabled by [% terms.Bugzilla %].
-          &lt;/b&gt;&lt;/p&gt;
-          &lt;p&gt;&lt;b&gt;
-            In order to view the attachment, you first have to
-            &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&quot;&gt;download it&lt;/a&gt;.
-          &lt;/b&gt;&lt;/p&gt;
-        &lt;/td&gt;
-      [% ELSIF attachment.is_viewable %]
-        &lt;td width=&quot;75%&quot;&gt;
-          [% INCLUDE global/textarea.html.tmpl
-            id      = 'editFrame'
-            name    = 'comment'
-            style   = 'height: 400px; width: 100%; display: none'
-            minrows = 10
-            cols    = 80
-            wrap    = 'soft'
-            defaultcontent = (attachment.contenttype.match('^text\/')) ?
-                               attachment.data.replace('(.*\n|.+)', '&gt;$1') : undef
-          %]
-          &lt;iframe id=&quot;viewFrame&quot; src=&quot;attachment.cgi?id=[% attachment.id %]&quot; style=&quot;height: 400px; width: 100%;&quot;&gt;
-            &lt;b&gt;You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
-            &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&quot;&gt;View the attachment on a separate page&lt;/a&gt;.&lt;/b&gt;
-          &lt;/iframe&gt;
-          &lt;script type=&quot;text/javascript&quot;&gt;
-            &lt;!--
-            if (typeof document.getElementById == &quot;function&quot;) {
-[% IF patchviewerinstalled %]
-              document.write('&lt;iframe id=&quot;viewDiffFrame&quot; style=&quot;height: 400px; width: 100%; display: none;&quot;&gt;&lt;\/iframe&gt;');
-[% END %]
-              document.write('&lt;button type=&quot;button&quot; id=&quot;editButton&quot; onclick=&quot;editAsComment();&quot;&gt;Edit Attachment As Comment&lt;\/button&gt;');
-              document.write('&lt;button type=&quot;button&quot; id=&quot;undoEditButton&quot; onclick=&quot;undoEditAsComment();&quot; style=&quot;display: none;&quot;&gt;Undo Edit As Comment&lt;\/button&gt;');
-              document.write('&lt;button type=&quot;button&quot; id=&quot;redoEditButton&quot; onclick=&quot;redoEditAsComment();&quot; style=&quot;display: none;&quot;&gt;Redo Edit As Comment&lt;\/button&gt;');
-[% IF patchviewerinstalled %]
-              document.write('&lt;button type=&quot;button&quot; id=&quot;viewDiffButton&quot; onclick=&quot;viewDiff();&quot;&gt;View Attachment As Diff&lt;\/button&gt;');
-[% END %]
-              document.write('&lt;button type=&quot;button&quot; id=&quot;viewRawButton&quot; onclick=&quot;viewRaw();&quot; style=&quot;display: none;&quot;&gt;View Attachment As Raw&lt;\/button&gt;');
-            }
-            //--&gt;
-          &lt;/script&gt;
-        &lt;/td&gt;
-      [% ELSE %]
-        &lt;td id=&quot;noview&quot; width=&quot;50%&quot;&gt;
-          &lt;p&gt;&lt;b&gt;
-            Attachment is not viewable in your browser because its MIME type 
-            ([% attachment.contenttype FILTER html %]) is not one that your browser is 
-            able to display.
-          &lt;/b&gt;&lt;/p&gt;
-          &lt;p&gt;&lt;b&gt;
-            &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&quot;&gt;Download the attachment&lt;/a&gt;.
-          &lt;/b&gt;&lt;/p&gt;
-        &lt;/td&gt;
-      [% END %]
</del><ins>+        [% IF user.id %]       
+          &lt;div id=&quot;update_container&quot;&gt;
+            &lt;input type=&quot;submit&quot; value=&quot;Submit&quot; id=&quot;update&quot;&gt;
+          &lt;/div&gt;
+        [% END %]        
+      &lt;/div&gt;        
+    &lt;/div&gt;
+  &lt;/div&gt;
+&lt;/form&gt;
</ins><span class="cx"> 
</span><del>-    &lt;/tr&gt;
</del><ins>+&lt;div id=&quot;attachment_actions&quot;&gt;
+  &lt;span class=&quot;label&quot;&gt;Actions:&lt;/span&gt;
+  &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&quot;&gt;View&lt;/a&gt;
+  [% IF use_patchviewer %]
+    | &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&amp;amp;action=diff&quot;&gt;Diff&lt;/a&gt;
+  [% END %]
+  [% IF Param(&quot;allow_attachment_deletion&quot;)
+        &amp;&amp; user.in_group('admin')
+        &amp;&amp; attachment.datasize &gt; 0 %]
+    | &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&amp;amp;action=delete&quot;&gt;Delete&lt;/a&gt;
+  [% END %]
+  [% Hook.process('action') %]
+&lt;/div&gt;
</ins><span class="cx"> 
</span><del>-  &lt;/table&gt;
-
-  Attachments on this [% terms.Bug %]:
</del><ins>+&lt;div id=&quot;attachment_list&quot;&gt;
+  Attachments on [% &quot;$terms.bug ${attachment.bug_id}&quot; FILTER bug_link(attachment.bug_id) FILTER none %]:
</ins><span class="cx">   [% FOREACH a = attachments %]
</span><span class="cx">     [% IF a == attachment.id %]
</span><span class="cx">       [%+ a %]
</span><span class="lines">@@ -340,9 +313,15 @@
</span><span class="cx">     [% END %]
</span><span class="cx">     [% &quot; |&quot; UNLESS loop.last() %]
</span><span class="cx">   [% END %]
</span><ins>+&lt;/div&gt;
+[% IF can_edit %]
+  &lt;script type=&quot;text/javascript&quot;&gt;
+    &lt;!--
+      YAHOO.util.Dom.removeClass( document.body, &quot;no_javascript&quot; );
+      toggle_attachment_details_visibility( );
+    --&gt;
+  &lt;/script&gt;
+[% END %]
+[% Hook.process('end') %]
</ins><span class="cx"> 
</span><del>-&lt;/form&gt;
-
-&lt;br&gt;
-
</del><span class="cx"> [% PROCESS global/footer.html.tmpl %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultattachmentlisthtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/attachment/list.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/attachment/list.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/attachment/list.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -19,41 +19,46 @@
</span><span class="cx">   #                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
</span><span class="cx">   #%]
</span><span class="cx"> 
</span><ins>+[% RETURN UNLESS attachments.size || Param(&quot;maxattachmentsize&quot;) || Param(&quot;maxlocalattachment&quot;) %]
+
</ins><span class="cx"> &lt;script type=&quot;text/javascript&quot;&gt;
</span><del>-  &lt;!--
-  function toggle_display(link) {
</del><ins>+&lt;!--
+function toggle_display(link) {
</ins><span class="cx">     var table = document.getElementById(&quot;attachment_table&quot;);
</span><del>-    var rows = table.getElementsByTagName(&quot;tr&quot;);
-    var originalHeight = table.offsetHeight; // Store current height for scrolling
</del><ins>+    var view_all = document.getElementById(&quot;view_all&quot;);
+    var hide_obsolete_url_parameter = &quot;&amp;hide_obsolete=1&quot;;
+    // Store current height for scrolling later
+    var originalHeight = table.offsetHeight;
+    var rows = YAHOO.util.Dom.getElementsByClassName(
+        'bz_tr_obsolete', 'tr', table);
</ins><span class="cx"> 
</span><del>-    var toggle;
-    if (link.innerHTML == &quot;Show Obsolete&quot;) {
-      toggle = &quot;&quot;; // This should be 'table-row', but IE 6 doesn't understand it.
-      link.innerHTML = &quot;Hide Obsolete&quot;;
</del><ins>+    for (var i = 0; i &lt; rows.length; i++) {
+        bz_toggleClass(rows[i], 'bz_default_hidden');
</ins><span class="cx">     }
</span><ins>+
+    if (YAHOO.util.Dom.hasClass(rows[0], 'bz_default_hidden')) {
+        link.innerHTML = &quot;Show Obsolete&quot;;
+        view_all.href = view_all.href + hide_obsolete_url_parameter 
+    }
</ins><span class="cx">     else {
</span><del>-      toggle = &quot;none&quot;;
-      link.innerHTML = &quot;Show Obsolete&quot;;
</del><ins>+        link.innerHTML = &quot;Hide Obsolete&quot;;
+        view_all.href = view_all.href.replace(hide_obsolete_url_parameter,&quot;&quot;);
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    for (var i = 0; i &lt; rows.length; i++) {
-      if (rows[i].className.match('bz_tr_obsolete'))
-        rows[i].style.display = toggle;
-    }
-
</del><span class="cx">     var newHeight = table.offsetHeight;
</span><ins>+    // This scrolling makes the window appear to not move at all.
</ins><span class="cx">     window.scrollBy(0, newHeight - originalHeight);
</span><span class="cx"> 
</span><span class="cx">     return false;
</span><del>-  }
-  //--&gt;
</del><ins>+}
+//--&gt;
</ins><span class="cx"> &lt;/script&gt;
</span><span class="cx"> 
</span><span class="cx"> &lt;br&gt;
</span><span class="cx"> &lt;table id=&quot;attachment_table&quot; cellspacing=&quot;0&quot; cellpadding=&quot;4&quot;&gt;
</span><del>-  &lt;tr&gt;
</del><ins>+  &lt;tr id=&quot;a0&quot;&gt;
</ins><span class="cx">     &lt;th colspan=&quot;[% show_attachment_flags ? 3 : 2 %]&quot; align=&quot;left&quot;&gt;
</span><del>-      &lt;a name=&quot;a0&quot; id=&quot;a0&quot;&gt;Attachments&lt;/a&gt;
</del><ins>+      Attachments
</ins><span class="cx">     &lt;/th&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -66,11 +71,15 @@
</span><span class="cx">       [% IF attachment.isobsolete %]
</span><span class="cx">         [% obsolete_attachments = obsolete_attachments + 1 %]
</span><span class="cx">       [% END %]
</span><del>-      &lt;tr class=&quot;[% &quot;bz_private&quot; IF attachment.isprivate %][%-%]
-                 [%+ &quot;bz_tr_obsolete&quot; IF attachment.isobsolete %]&quot;&gt;
</del><ins>+      &lt;tr id=&quot;a[% count %]&quot; class=&quot;[% &quot;bz_contenttype_&quot; _ attachment.contenttype
+                     FILTER css_class_quote %]
+                 [% &quot; bz_patch&quot; IF attachment.ispatch %]
+                 [% &quot; bz_private&quot; IF attachment.isprivate %]
+                 [% &quot; bz_tr_obsolete bz_default_hidden&quot; 
+                     IF attachment.isobsolete %]&quot;&gt;
</ins><span class="cx">         &lt;td valign=&quot;top&quot;&gt;
</span><span class="cx">           [% IF attachment.datasize %]
</span><del>-            &lt;a name=&quot;a[% count %]&quot; href=&quot;attachment.cgi?id=[% attachment.id %]&quot;
</del><ins>+            &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&quot;
</ins><span class="cx">                title=&quot;View the content of the attachment&quot;&gt;
</span><span class="cx">           [% END %]
</span><span class="cx">           &lt;b&gt;[% attachment.description FILTER html FILTER obsolete(attachment.isobsolete) %]&lt;/b&gt;
</span><span class="lines">@@ -81,8 +90,6 @@
</span><span class="cx">               ([% attachment.datasize FILTER unitconvert %],
</span><span class="cx">               [% IF attachment.ispatch %]
</span><span class="cx">                 patch)
</span><del>-              [% ELSIF attachment.isurl %]
-                url)
</del><span class="cx">               [% ELSE %]
</span><span class="cx">                 [%+ attachment.contenttype FILTER html %])
</span><span class="cx">               [% END %]
</span><span class="lines">@@ -95,10 +102,7 @@
</span><span class="cx">                title=&quot;Go to the comment associated with the attachment&quot;&gt;
</span><span class="cx">               [%- attachment.attached FILTER time %]&lt;/a&gt;,
</span><span class="cx"> 
</span><del>-            &lt;a href=&quot;mailto:[% attachment.attacher.email FILTER html %]&quot;
-               title=&quot;Write an email to the creator of the attachment&quot;&gt;
-              [% attachment.attacher.name || attachment.attacher.login FILTER html %]
-            &lt;/a&gt;
</del><ins>+            [% INCLUDE global/user.html.tmpl who = attachment.attacher %]
</ins><span class="cx">           &lt;/span&gt;
</span><span class="cx">         &lt;/td&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -108,10 +112,22 @@
</span><span class="cx">               &lt;i&gt;no flags&lt;/i&gt;
</span><span class="cx">             [% ELSE %]
</span><span class="cx">               [% FOREACH flag = attachment.flags %]
</span><del>-                [% flag.setter.nick FILTER html %]:
</del><ins>+                [% IF user.id %]
+                  &lt;span title=&quot;[% flag.setter.identity FILTER html %]&quot;&gt;[% flag.setter.nick FILTER html %]&lt;/span&gt;:
+                [% ELSIF flag.setter.name %]
+                  &lt;span title=&quot;[% flag.setter.name FILTER html %]&quot;&gt;[% flag.setter.nick FILTER html %]&lt;/span&gt;:
+                [% ELSE %]
+                  [% flag.setter.nick FILTER html %]:
+                [% END %]
</ins><span class="cx">                 [%+ flag.type.name FILTER html FILTER no_break %][% flag.status %]
</span><span class="cx">                 [%+ IF flag.status == &quot;?&quot; &amp;&amp; flag.requestee %]
</span><del>-                  ([% flag.requestee.nick FILTER html %])
</del><ins>+                  [% IF user.id %]
+                    (&lt;span title=&quot;[% flag.requestee.identity FILTER html %]&quot;&gt;[% flag.requestee.nick FILTER html %]&lt;/span&gt;)
+                  [% ELSIF flag.requestee.name %]
+                    (&lt;span title=&quot;[% flag.requestee.name FILTER html %]&quot;&gt;[% flag.requestee.nick FILTER html %]&lt;/span&gt;)
+                  [% ELSE %]
+                    ([% flag.requestee.nick FILTER html %])
+                  [% END %]
</ins><span class="cx">                 [% END %]&lt;br&gt;
</span><span class="cx">               [% END %]
</span><span class="cx">             [% END %]
</span><span class="lines">@@ -120,7 +136,7 @@
</span><span class="cx"> 
</span><span class="cx">         &lt;td valign=&quot;top&quot;&gt;
</span><span class="cx">           &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&amp;amp;action=edit&quot;&gt;Details&lt;/a&gt;
</span><del>-          [% IF attachment.ispatch &amp;&amp; patchviewerinstalled %]
</del><ins>+          [% IF attachment.ispatch &amp;&amp; feature_enabled('patch_viewer') %]
</ins><span class="cx">             | &lt;a href=&quot;attachment.cgi?id=[% attachment.id %]&amp;amp;action=diff&quot;&gt;Diff&lt;/a&gt;
</span><span class="cx">           [% END %]
</span><span class="cx">           [% Hook.process(&quot;action&quot;) %]
</span><span class="lines">@@ -134,15 +150,20 @@
</span><span class="cx">       [% IF attachments.size %]
</span><span class="cx">         &lt;span class=&quot;bz_attach_view_hide&quot;&gt;
</span><span class="cx">           [% IF obsolete_attachments %]
</span><del>-            &lt;a href=&quot;#a0&quot; onClick=&quot;return toggle_display(this);&quot;&gt;Hide Obsolete&lt;/a&gt; ([% obsolete_attachments %])
</del><ins>+            &lt;a href=&quot;#a0&quot; onclick=&quot;return toggle_display(this);&quot;&gt;Show
+              Obsolete&lt;/a&gt; ([% obsolete_attachments %])
</ins><span class="cx">           [% END %]
</span><span class="cx">           [% IF Param(&quot;allow_attachment_display&quot;) %]
</span><del>-            &lt;a href=&quot;attachment.cgi?bugid=[% bugid %]&amp;amp;action=viewall&quot;&gt;View All&lt;/a&gt;
</del><ins>+            &lt;a id=&quot;view_all&quot; href=&quot;attachment.cgi?bugid=
+                  [%- bugid %]&amp;amp;action=viewall
+                  [%- &quot;&amp;amp;hide_obsolete=1&quot; IF obsolete_attachments %]&quot;&gt;View All&lt;/a&gt;
</ins><span class="cx">           [% END %]
</span><span class="cx">         &lt;/span&gt;
</span><span class="cx">       [% END %]
</span><del>-      &lt;a href=&quot;attachment.cgi?bugid=[% bugid %]&amp;amp;action=enter&quot;&gt;Add an attachment&lt;/a&gt;
-      (proposed patch, testcase, etc.)
</del><ins>+      [% IF Param(&quot;maxattachmentsize&quot;) || Param(&quot;maxlocalattachment&quot;) %]
+        &lt;a href=&quot;attachment.cgi?bugid=[% bugid %]&amp;amp;action=enter&quot;&gt;Add an attachment&lt;/a&gt;
+        (proposed patch, testcase, etc.)
+      [% END %]
</ins><span class="cx">     &lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> &lt;/table&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultattachmentmidairhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/attachment/midair.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/attachment/midair.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/attachment/midair.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -51,7 +51,7 @@
</span><span class="cx"> &lt;p&gt;
</span><span class="cx">   Your comment was:&lt;br&gt;
</span><span class="cx">   &lt;blockquote&gt;&lt;pre class=&quot;bz_comment_text&quot;&gt;
</span><del>-    [% cgi.param(&quot;comment&quot;) FILTER wrap_comment FILTER html %]
</del><ins>+    [% cgi.param(&quot;comment&quot;) FILTER html %]
</ins><span class="cx">   &lt;/pre&gt;&lt;/blockquote&gt;
</span><span class="cx"> &lt;/p&gt;
</span><span class="cx"> [% END %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultattachmentshowmultiplehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/attachment/show-multiple.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/attachment/show-multiple.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/attachment/show-multiple.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -21,7 +21,7 @@
</span><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="cx"> [% filtered_summary = bugsummary FILTER html %]
</span><span class="cx"> [% header = BLOCK %]View All Attachments for
</span><del>-  [%+ &quot;$terms.Bug $bug.bug_id&quot; FILTER bug_link(bug.bug_id) FILTER none %][% END %]
</del><ins>+  [%+ &quot;$terms.Bug $bug.id&quot; FILTER bug_link(bug) FILTER none %][% END %]
</ins><span class="cx"> 
</span><span class="cx"> [% title = BLOCK %]
</span><span class="cx">   View All Attachments for [% terms.Bug %] [%+ bug.bug_id FILTER html %]
</span><span class="lines">@@ -31,8 +31,14 @@
</span><span class="cx">   title = title
</span><span class="cx">   header = header
</span><span class="cx">   subheader = filtered_summary
</span><ins>+  style_urls = ['skins/standard/attachment.css']
</ins><span class="cx"> %]
</span><del>-
</del><ins>+[% IF hide_obsolete %]
+  &lt;div id=&quot;hidden_obsolete_message&quot;&gt;
+    Obsolete attachments are hidden. To view all attachments (including obsolete) 
+    &lt;a href=&quot;attachment.cgi?bugid=[% bug.id FILTER html %]&amp;amp;action=viewall&quot;&gt;click here&lt;/a&gt;.
+  &lt;/div&gt;
+[% END %]
</ins><span class="cx"> &lt;br&gt;
</span><span class="cx"> 
</span><span class="cx"> [% FOREACH a = attachments %]
</span><span class="lines">@@ -82,10 +88,22 @@
</span><span class="cx">   &lt;/table&gt;
</span><span class="cx"> 
</span><span class="cx">   [% IF a.is_viewable %]
</span><del>-    &lt;iframe src=&quot;attachment.cgi?id=[% a.id %]&quot; width=&quot;75%&quot; height=&quot;350&quot;&gt;
-      &lt;b&gt;You cannot view the attachment on this page because your browser does not support IFRAMEs.
-      &lt;a href=&quot;attachment.cgi?id=[% a.id %]&quot;&gt;View the attachment on a separate page&lt;/a&gt;.&lt;/b&gt;
-    &lt;/iframe&gt;
</del><ins>+    [% IF a.contenttype == &quot;text/html&quot; %]
+      [%# For security reasons (clickjacking, embedded scripts), we never
+        # render HTML pages from here. The source code is displayed instead. %]
+      [% INCLUDE global/textarea.html.tmpl
+         minrows = 10
+         cols    = 80
+         defaultcontent = a.data
+         readonly = 'readonly'
+         classes = 'viewall_frame'
+      %]
+    [% ELSE %]
+      &lt;iframe src=&quot;attachment.cgi?id=[% a.id %]&quot; class=&quot;viewall_frame&quot;&gt;
+        &lt;b&gt;You cannot view the attachment on this page because your browser does not support IFRAMEs.
+        &lt;a href=&quot;attachment.cgi?id=[% a.id %]&quot;&gt;View the attachment on a separate page&lt;/a&gt;.&lt;/b&gt;
+      &lt;/iframe&gt;
+    [% END %]
</ins><span class="cx">   [% ELSE %]
</span><span class="cx">     &lt;p&gt;&lt;b&gt;
</span><span class="cx">       Attachment cannot be viewed because its MIME type is not text/*, image/*, or application/vnd.mozilla.*.
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultattachmentupdatedhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/attachment/updated.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/attachment/updated.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/attachment/updated.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -25,28 +25,10 @@
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="cx"> [% bug = bugs.0 %]
</span><del>-[% filtered_desc = bug.short_desc FILTER html %]
-[% filtered_timestamp = bug.delta_ts FILTER time %]
-[% bodyclasses = ['bz_bug',
-                 &quot;bz_status_$bug.bug_status&quot;,
-                 &quot;bz_component_$bug.component&quot;,
-                 &quot;bz_bug_$bug.bug_id&quot;
-                 ]
-%]
-[% FOREACH group = bug.groups_in %]
-  [% bodyclasses.push(&quot;bz_group_$group.name&quot;) %]
-[% END %]
</del><span class="cx"> 
</span><ins>+[% PROCESS &quot;bug/show-header.html.tmpl&quot; %]
</ins><span class="cx"> [% PROCESS global/header.html.tmpl
</span><span class="cx">   title = &quot;Changes Submitted to Attachment $attachment.id of $terms.Bug $attachment.bug_id&quot;
</span><del>-  header = &quot;$terms.Bug&amp;nbsp;$attachment.bug_id&quot;
-  subheader = filtered_desc
-  header_addl_info = &quot;Last modified: $filtered_timestamp&quot;
-  bodyclasses = bodyclasses
-  javascript_urls = [ &quot;js/util.js&quot;, &quot;js/field.js&quot;,
-                      &quot;js/yui/yahoo-dom-event.js&quot;, &quot;js/yui/calendar.js&quot; ]
-  style_urls = [ &quot;skins/standard/yui/calendar.css&quot;, &quot;skins/standard/show_bug.css&quot; ]
-  doc_section = &quot;bug_page.html&quot;
</del><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> &lt;dl&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultbugactivityshowhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/bug/activity/show.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/bug/activity/show.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/bug/activity/show.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -35,14 +35,14 @@
</span><span class="cx">  %]
</span><span class="cx"> 
</span><span class="cx"> &lt;p&gt;
</span><del>-  [% &quot;Back to $terms.bug $bug.bug_id&quot; FILTER bug_link(bug.bug_id) FILTER none %]
</del><ins>+  [% &quot;Back to $terms.bug $bug.bug_id&quot; FILTER bug_link(bug) FILTER none %]
</ins><span class="cx"> &lt;/p&gt;
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS bug/activity/table.html.tmpl %]
</span><span class="cx"> 
</span><span class="cx"> [% IF operations.size &gt; 0 %]
</span><span class="cx">   &lt;p&gt;
</span><del>-    [% &quot;Back to $terms.bug $bug.bug_id&quot; FILTER bug_link(bug.bug_id) FILTER none %]
</del><ins>+    [% &quot;Back to $terms.bug $bug.bug_id&quot; FILTER bug_link(bug) FILTER none %]
</ins><span class="cx">   &lt;/p&gt;
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultbugactivitytablehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/bug/activity/table.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/bug/activity/table.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/bug/activity/table.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -17,6 +17,7 @@
</span><span class="cx">   #
</span><span class="cx">   # Contributor(s): Gervase Markham &lt;gerv@gerv.net&gt;
</span><span class="cx">   #                 David D. Kilzer &lt;ddkilzer@kilzer.net&gt;
</span><ins>+  #                 Reed Loden &lt;reed@reedloden.com&gt;
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [%# INTERFACE:
</span><span class="lines">@@ -33,7 +34,6 @@
</span><span class="cx">   #                  it was affected by an old Bugzilla bug.)
</span><span class="cx">   #%]
</span><span class="cx"> 
</span><del>-[% PROCESS global/variables.none.tmpl %]
</del><span class="cx"> [% PROCESS &quot;global/field-descs.none.tmpl&quot; %]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS bug/time.html.tmpl %]
</span><span class="lines">@@ -61,7 +61,7 @@
</span><span class="cx">     [% FOREACH operation = operations %]
</span><span class="cx">       &lt;tr&gt;
</span><span class="cx">         &lt;td rowspan=&quot;[% operation.changes.size %]&quot; valign=&quot;top&quot;&gt;
</span><del>-          [% operation.who FILTER html %]
</del><ins>+          [% operation.who FILTER email FILTER html %]
</ins><span class="cx">         &lt;/td&gt;
</span><span class="cx">         &lt;td rowspan=&quot;[% operation.changes.size %]&quot; valign=&quot;top&quot;&gt;
</span><span class="cx">           [% operation.when FILTER time %]
</span><span class="lines">@@ -73,50 +73,47 @@
</span><span class="cx">                 &lt;a href=&quot;attachment.cgi?id=[% change.attachid %]&quot;&gt;
</span><span class="cx">                 Attachment #[% change.attachid %]&lt;/a&gt;
</span><span class="cx">               [% END %]
</span><del>-              [%+ change.field %]
-            &lt;/td&gt;
-            &lt;td&gt;
-              [% IF change.removed.defined %]
-                [% IF change.fieldname == 'estimated_time' ||
-                      change.fieldname == 'remaining_time' ||
-                      change.fieldname == 'work_time' %]
-                  [% PROCESS formattimeunit time_unit=change.removed %]
-                [% ELSIF change.fieldname == 'bug_status' %]
-                  [% get_status(change.removed) FILTER html %]
-                [% ELSIF change.fieldname == 'resolution' %]
-                  [% get_resolution(change.removed) FILTER html %]
-                [% ELSIF change.fieldname == 'blocked' ||
-                         change.fieldname == 'dependson' %]
-                  [% change.removed FILTER bug_list_link FILTER none %]
-                [% ELSE %]
-                  [% change.removed FILTER html %]
-                [% END %]
</del><ins>+              [% IF change.comment.defined %]
+                 [% comment_desc = field_descs.${change.fieldname} %]
+                 [% comment_num = &quot;Comment $change.comment.count&quot; FILTER bug_link(bug.bug_id, comment_num =&gt; change.comment.count) %]
+                 [% comment_desc.replace('^(Comment )?', &quot;$comment_num &quot;) FILTER none %]
</ins><span class="cx">               [% ELSE %]
</span><del>-                &amp;nbsp;
</del><ins>+                [%+ field_descs.${change.fieldname} FILTER html %]
</ins><span class="cx">               [% END %]
</span><span class="cx">             &lt;/td&gt;
</span><del>-            &lt;td&gt;
-              [% IF change.added.defined %]
-                [% IF change.fieldname == 'estimated_time' ||
-                      change.fieldname == 'remaining_time' ||
-                      change.fieldname == 'work_time' %]
-                  [% PROCESS formattimeunit time_unit=change.added %]
-                [% ELSIF change.fieldname == 'bug_status' %]
-                  [% get_status(change.added) FILTER html %]
-                [% ELSIF change.fieldname == 'resolution' %]
-                  [% get_resolution(change.added) FILTER html %]
-                [% ELSIF change.fieldname == 'blocked' ||
-                         change.fieldname == 'dependson' %]
-                  [% change.added FILTER bug_list_link FILTER none %]
-                [% ELSE %]
-                  [% change.added FILTER html %]
-                [% END %]
-              [% ELSE %]
-                &amp;nbsp;
-              [% END %]
-            &lt;/td&gt;
</del><ins>+            [% PROCESS change_column change_type = change.removed %]
+            [% PROCESS change_column change_type = change.added %]
</ins><span class="cx">         [% END %]
</span><span class="cx">       &lt;/tr&gt;
</span><span class="cx">     [% END %]
</span><span class="cx">   &lt;/table&gt;
</span><ins>+[% ELSE %]
+  &lt;p&gt;
+    No changes have been made to this [% terms.bug %] yet.
+  &lt;/p&gt;
</ins><span class="cx"> [% END %]
</span><ins>+
+[% BLOCK change_column %]
+  &lt;td&gt;
+    [% IF change_type.defined %]
+      [% IF change.fieldname == 'estimated_time' ||
+            change.fieldname == 'remaining_time' ||
+            change.fieldname == 'work_time' %]
+        [% PROCESS formattimeunit time_unit=change_type %]
+      [% ELSIF change.fieldname == 'blocked' ||
+               change.fieldname == 'dependson' %]
+        [% change_type FILTER bug_list_link FILTER none %]
+      [% ELSIF change.fieldname == 'assigned_to' ||
+               change.fieldname == 'reporter' ||
+               change.fieldname == 'qa_contact' ||
+               change.fieldname == 'cc' ||
+               change.fieldname == 'flagtypes.name' %]
+        [% display_value(change.fieldname, change_type) FILTER email FILTER html %]
+      [% ELSE %]
+        [% display_value(change.fieldname, change_type) FILTER html %]
+      [% END %]
+    [% ELSE %]
+      &amp;nbsp;
+    [% END %]
+  &lt;/td&gt;
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultbugcommentshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/bug/comments.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/bug/comments.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/bug/comments.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -22,78 +22,10 @@
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS bug/time.html.tmpl %]
</span><span class="cx"> 
</span><del>-  &lt;script type=&quot;text/javascript&quot;&gt;
-  &lt;!--
-  function updateCommentPrivacy(checkbox, id) {
-    var comment_elem = document.getElementById('comment_text_'+id).parentNode;
-    if (checkbox.checked) {
-      if (!comment_elem.className.match('bz_private')) {
-        comment_elem.className = comment_elem.className.concat(' bz_private');
-      }
-    }
-    else {
-      comment_elem.className =
-        comment_elem.className.replace(/(\s*|^)bz_private(\s*|$)/, '$2');
-    }
-  }
</del><ins>+&lt;script src=&quot;[% 'js/comments.js' FILTER mtime %]&quot; type=&quot;text/javascript&quot;&gt;
+&lt;/script&gt;
</ins><span class="cx"> 
</span><del>-  /* The functions below expand and collapse comments  */
-
-  function toggle_comment_display(link, comment_id) {
-    var comment = document.getElementById('comment_text_' + comment_id);
-    var re = new RegExp(/\bcollapsed\b/);
-    if (comment.className.match(re))
-        expand_comment(link, comment);
-    else
-        collapse_comment(link, comment);
-  }
-
-  function toggle_all_comments(action) {
-    var num_comments = [% comments.size FILTER html %];
-
-    // If for some given ID the comment doesn't exist, this doesn't mean
-    // there are no more comments, but that the comment is private and
-    // the user is not allowed to view it.
-
-    for (var id = 0; id &lt; num_comments; id++) {
-        var comment = document.getElementById('comment_text_' + id);
-        if (!comment)
-            continue;
-
-        var link = document.getElementById('comment_link_' + id);
-        if (action == 'collapse')
-            collapse_comment(link, comment);
-        else
-            expand_comment(link, comment);
-    }
-  }
-
-  function collapse_comment(link, comment) {
-    link.innerHTML = &quot;(+)&quot;;
-    link.title = &quot;Expand the comment.&quot;;
-    comment.className = &quot;collapsed&quot;;
-  }
-
-  function expand_comment(link, comment) {
-    link.innerHTML = &quot;(-)&quot;;
-    link.title = &quot;Collapse the comment&quot;;
-    comment.className = &quot;&quot;;
-  }
-
-  /* This way, we are sure that browsers which do not support JS
-   * won't display this link  */
-
-  function addCollapseLink(count) {
-    document.write(' &lt;a href=&quot;#&quot; id=&quot;comment_link_' + count +
-                   '&quot; onclick=&quot;toggle_comment_display(this, ' +  count +
-                   '); return false;&quot; title=&quot;Collapse the comment.&quot;&gt;(-)&lt;/a&gt; ');
-  }
-  //--&gt;
-  &lt;/script&gt;
-
-
</del><span class="cx"> [% DEFAULT start_at = 0 mode = &quot;show&quot; %]
</span><del>-[% isinsider = Param(&quot;insidergroup&quot;) &amp;&amp; user.in_group(Param(&quot;insidergroup&quot;)) %]
</del><span class="cx"> [% sort_order = user.settings.comment_sort_order.value %]
</span><span class="cx"> 
</span><span class="cx"> [%# NOTE: (start_at &gt; 0) means we came here from a midair collision,
</span><span class="lines">@@ -120,11 +52,10 @@
</span><span class="cx">     [% END %]
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><del>-[% IF mode == &quot;edit&quot; %]
-  &lt;a href=&quot;#&quot; onclick=&quot;toggle_all_comments('collapse'); return false;&quot;&gt;Collapse All Comments&lt;/a&gt; -
-  &lt;a href=&quot;#&quot; onclick=&quot;toggle_all_comments('expand'); return false;&quot;&gt;Expand All Comments&lt;/a&gt;
-  &lt;hr&gt;
-[% END %]
</del><ins>+&lt;!-- This auto-sizes the comments and positions the collapse/expand links 
+     to the right. --&gt;
+&lt;table class=&quot;bz_comment_table&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot;&gt;&lt;tr&gt;
+&lt;td&gt;
</ins><span class="cx"> 
</span><span class="cx"> [% FOREACH comment = comments %]
</span><span class="cx">   [% IF count &gt;= start_at %]
</span><span class="lines">@@ -134,73 +65,106 @@
</span><span class="cx">   [% count = count + increment %]
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><ins>+[% IF user.settings.comment_box_position.value == &quot;before_comments&quot; &amp;&amp; user.id %]
+  &lt;div class=&quot;bz_add_comment&quot;&gt;
+    &lt;a href=&quot;#&quot; 
+       onclick=&quot;return goto_add_comments();&quot;&gt;
+       Add Comment&lt;/a&gt;
+  &lt;/div&gt;
+[% END %]
+
</ins><span class="cx"> [%# Note: this template is used in multiple places; if you use this hook,
</span><span class="cx">   # make sure you are aware of this fact.
</span><span class="cx">   #%]  
</span><span class="cx"> [% Hook.process(&quot;aftercomments&quot;) %]
</span><span class="cx"> 
</span><ins>+&lt;/td&gt;
+&lt;td&gt;
+  [% IF mode == &quot;edit&quot; %]
+    &lt;ul class=&quot;bz_collapse_expand_comments&quot;&gt;
+      &lt;li&gt;&lt;a href=&quot;#&quot; onclick=&quot;toggle_all_comments('collapse'); 
+                               return false;&quot;&gt;Collapse All Comments&lt;/a&gt;&lt;/li&gt;
+      &lt;li&gt;&lt;a href=&quot;#&quot; onclick=&quot;toggle_all_comments('expand');
+                               return false;&quot;&gt;Expand All Comments&lt;/a&gt;&lt;/li&gt;
+      [% IF user.settings.comment_box_position.value == &quot;after_comments&quot; &amp;&amp; user.id %]
+        &lt;li class=&quot;bz_add_comment&quot;&gt;&lt;a href=&quot;#&quot; 
+            onclick=&quot;return goto_add_comments('bug_status_bottom');&quot;&gt;
+            Add Comment&lt;/a&gt;&lt;/li&gt;
+      [% END %]                               
+    &lt;/ul&gt;
+  [% END %]
+&lt;/td&gt;
+&lt;/tr&gt;&lt;/table&gt;
+
</ins><span class="cx"> [%############################################################################%]
</span><span class="cx"> [%# Block for individual comments                                            #%]
</span><span class="cx"> [%############################################################################%]
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK a_comment %]
</span><del>-  [% IF NOT comment.isprivate || isinsider %]
-    &lt;div class=&quot;bz_comment[% &quot; bz_private&quot; IF comment.isprivate %]
</del><ins>+  [% RETURN IF comment.is_private AND ! user.is_insider %]
+  [% comment_text = comment.body_full %]
+  [% RETURN IF comment_text == '' AND (comment.work_time - 0) != 0 AND !user.is_timetracker %]
+
+    &lt;div id=&quot;c[% count %]&quot; class=&quot;bz_comment[% &quot; bz_private&quot; IF comment.is_private %]
</ins><span class="cx">                 [% &quot; bz_comment_hilite&quot; IF marks.$count %]
</span><span class="cx">                 [% &quot; bz_first_comment&quot; IF count == description %]&quot;&gt;
</span><span class="cx">       [% IF count == description %]
</span><span class="cx">         [% class_name = &quot;bz_first_comment_head&quot; %]
</span><del>-        [% comment_label = &quot;&quot; %]
-        [% comment_link = &quot;Description&quot; %]
-        [% decoration = &quot;&quot; %]
</del><ins>+        [% comment_label = &quot;Description&quot; %]
</ins><span class="cx">       [% ELSE %]
</span><span class="cx">         [% class_name = &quot;bz_comment_head&quot; %]
</span><del>-        [% comment_label = &quot;Comment&quot; %]
-        [% comment_link = &quot;#&quot; _ count %]
-        [% decoration = '&lt;span class=&quot;comment_rule&quot;&gt;-------&lt;/span&gt;' %]
</del><ins>+        [% comment_label = &quot;Comment &quot; _ count %]
</ins><span class="cx">       [% END %]
</span><span class="cx"> 
</span><del>-      &lt;span class=&quot;[% class_name FILTER html %]&quot;&gt;
-        [%# Do not filter decoration as it's a real HTML tag. No XSS risk. %]
-        [% decoration FILTER none %]
-        &lt;i&gt;[% comment_label FILTER html %]
-        &lt;a name=&quot;c[% count %]&quot; href=&quot;show_bug.cgi?id=[% bug.bug_id %]#c[% count %]&quot;&gt;
-          [% comment_link FILTER html %]&lt;/a&gt; From
-        &lt;span class=&quot;vcard&quot;&gt;
-          &lt;a class=&quot;fn email&quot; href=&quot;mailto:[% comment.author.email FILTER html %]&quot;&gt;
-            [% (comment.author.name || comment.author.login) FILTER html %]&lt;/a&gt;
-        &lt;/span&gt;
-        [% FOREACH group = comment.author.direct_group_membership %]
-          [% NEXT UNLESS group.icon_url %]
-          &lt;img src=&quot;[% group.icon_url FILTER html %]&quot;
-               alt=&quot;[% group.name FILTER html %]&quot;
-               title=&quot;[% group.name FILTER html %] - [% group.description FILTER html %]&quot;&gt;
-        [% END %]
</del><ins>+      &lt;div class=&quot;[% class_name FILTER html %]&quot;&gt;
</ins><span class="cx"> 
</span><del>-        [%+ comment.time FILTER time %]&lt;/i&gt;
-
</del><span class="cx">         [% IF mode == &quot;edit&quot; %]
</span><del>-          &lt;script type=&quot;text/javascript&quot;&gt;&lt;!--
-            addCollapseLink([% count %]);
-            addReplyLink([% count %], [% comment.id %]); //--&gt;
-          &lt;/script&gt;
</del><ins>+          &lt;span class=&quot;bz_comment_actions&quot;&gt;
+            &lt;script type=&quot;text/javascript&quot;&gt;&lt;!--
+              addReplyLink([% count %], [% comment.id %]);
+              addCollapseLink([% count %], 'Toggle comment display'); // --&gt;
+            &lt;/script&gt;
+          &lt;/span&gt;
</ins><span class="cx">         [% END %]
</span><del>-        [%+ decoration FILTER none %]
-      &lt;/span&gt;
</del><span class="cx"> 
</span><del>-      [% IF mode == &quot;edit&quot; &amp;&amp; isinsider %]
-        &lt;i&gt;
-          &lt;input type=&quot;hidden&quot; value=&quot;1&quot;
-                 name=&quot;defined_isprivate_[% comment.id %]&quot;&gt;
-          &lt;input type=&quot;checkbox&quot;
-                 name=&quot;isprivate_[% comment.id %]&quot; value=&quot;1&quot;
-                 id=&quot;isprivate_[% comment.id %]&quot;
-                 onClick=&quot;updateCommentPrivacy(this, [% count %])&quot;
-                 [% &quot; checked=\&quot;checked\&quot;&quot; IF comment.isprivate %]&gt;
-          &lt;label for=&quot;isprivate_[% comment.id %]&quot;&gt;Private&lt;/label&gt;
-        &lt;/i&gt;
-      [% END %]
-      [% IF user.in_group(Param('timetrackinggroup')) &amp;&amp;
</del><ins>+        [% IF mode == &quot;edit&quot; &amp;&amp; user.is_insider %]
+          &lt;div class=&quot;bz_private_checkbox&quot;&gt;
+            &lt;input type=&quot;hidden&quot; value=&quot;1&quot;
+                   name=&quot;defined_isprivate_[% comment.id %]&quot;&gt;
+            &lt;input type=&quot;checkbox&quot;
+                   name=&quot;isprivate_[% comment.id %]&quot; value=&quot;1&quot;
+                   id=&quot;isprivate_[% comment.id %]&quot;
+                   onClick=&quot;updateCommentPrivacy(this, [% count %])&quot;
+                   [% &quot; checked=\&quot;checked\&quot;&quot; IF comment.is_private %]&gt;
+            &lt;label for=&quot;isprivate_[% comment.id %]&quot;&gt;Private&lt;/label&gt;
+          &lt;/div&gt;
+        [% END %]
+
+        &lt;span class=&quot;bz_comment_number&quot;&gt;
+          &lt;a 
+             href=&quot;show_bug.cgi?id=[% bug.bug_id %]#c[% count %]&quot;&gt;
+            [%- comment_label FILTER html %]&lt;/a&gt;
+        &lt;/span&gt;
+
+        &lt;span class=&quot;bz_comment_user&quot;&gt;
+          [% INCLUDE global/user.html.tmpl who = comment.author %]
+        &lt;/span&gt;
+
+        &lt;span class=&quot;bz_comment_user_images&quot;&gt;
+          [% FOREACH group = comment.author.direct_group_membership %]
+            [% NEXT UNLESS group.icon_url %]
+            &lt;img src=&quot;[% group.icon_url FILTER html %]&quot;
+                 alt=&quot;[% group.name FILTER html %]&quot;
+                 title=&quot;[% group.name FILTER html %] - [% group.description FILTER html %]&quot;&gt;
+          [% END %]
+        &lt;/span&gt;
+
+        &lt;span class=&quot;bz_comment_time&quot;&gt;
+          [%+ comment.creation_ts FILTER time %]
+        &lt;/span&gt;
+      &lt;/div&gt;
+
+      [% IF user.is_timetracker &amp;&amp;
</ins><span class="cx">             (comment.work_time &gt; 0 || comment.work_time &lt; 0) %]
</span><span class="cx">          &lt;br&gt;
</span><span class="cx">          Additional hours worked: 
</span><span class="lines">@@ -210,15 +174,9 @@
</span><span class="cx"> [%# Don't indent the &lt;pre&gt; block, since then the spaces are displayed in the
</span><span class="cx">   # generated HTML
</span><span class="cx">   #%]
</span><del>-[% IF comment.already_wrapped %]
-    [% wrapped_comment = comment.body %]
-[% ELSE %]
-    [% wrapped_comment = comment.body FILTER wrap_comment %]
-[% END %]
</del><span class="cx"> &lt;pre class=&quot;bz_comment_text&quot; 
</span><span class="cx">      [% ' id=&quot;comment_text_' _ count _ '&quot;' IF mode == &quot;edit&quot; %]&gt;
</span><del>-  [%- wrapped_comment FILTER quoteUrls(bug.bug_id) -%]
</del><ins>+  [%- comment_text FILTER quoteUrls(bug, comment) -%]
</ins><span class="cx"> &lt;/pre&gt;
</span><span class="cx">     &lt;/div&gt;
</span><del>-  [% END %]
</del><span class="cx"> [% END %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultbugcreateconfirmcreatedupehtmltmpl"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/template/en/default/bug/create/confirm-create-dupe.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/bug/create/confirm-create-dupe.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/bug/create/confirm-create-dupe.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,57 +0,0 @@
</span><del>-[%# The contents of this file are subject to the Mozilla Public
-  # License Version 1.1 (the &quot;License&quot;); you may not use this file
-  # except in compliance with the License. You may obtain a copy of
-  # the License at http://www.mozilla.org/MPL/
-  #
-  # Software distributed under the License is distributed on an &quot;AS
-  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
-  # implied. See the License for the specific language governing
-  # rights and limitations under the License.
-  #
-  # The Original Code is the Bugzilla Bug Tracking System.
-  #
-  # The Initial Developer of the Original Code is Olav Vitters.
-  #
-  # Contributor(s): Olav Vitters &lt;olav@bkor.dhs.org&gt;
-  #%]
-
-[%# INTERFACE:
-  # bugid: integer. ID of the bug previously used to create a bug.
-  # allow_override: boolean int. Is 1 if the user may submit the bug again.
-  #%]
-
-[% PROCESS &quot;global/field-descs.none.tmpl&quot; %]
-
-[% PROCESS global/header.html.tmpl
-  title = &quot;Already filed $terms.bug&quot;
-%]
-
-[% USE Bugzilla %]
-
-&lt;table cellpadding=&quot;20&quot;&gt;
-  &lt;tr&gt;
-    &lt;td bgcolor=&quot;#ff0000&quot;&gt;
-      &lt;font size=&quot;+2&quot;&gt;
-        You already used the form to file [% &quot;$terms.bug $bugid&quot; FILTER bug_link(bugid) FILTER none %].
-      &lt;/font&gt;
-    &lt;/td&gt;
-  &lt;/tr&gt;
-&lt;/table&gt;
-
-&lt;p&gt;&lt;font size=&quot;big&quot;&gt;You are highly encouraged to visit [% &quot;$terms.bug $bugid&quot;
-FILTER bug_link(bugid) FILTER none %].&lt;/font&gt;&lt;/p&gt;
-
-[% IF allow_override %]
-  &lt;p&gt;If you are sure you used the same form to submit a new [% terms.bug %],
-  click 'File [% terms.bug %] again'.&lt;p&gt;
-
-  &lt;form name=&quot;create&quot; id=&quot;create&quot; method=&quot;post&quot; action=&quot;post_bug.cgi&quot;
-  [%- IF Bugzilla.cgi.param(&quot;data&quot;) %] enctype=&quot;multipart/form-data&quot;[% END %]&gt;
-    [% PROCESS &quot;global/hidden-fields.html.tmpl&quot;
-               exclude=&quot;^(Bugzilla_login|Bugzilla_password|ignore_token)$&quot; %]
-    &lt;input type=&quot;hidden&quot; name=&quot;ignore_token&quot; value=&quot;[% bugid FILTER html %]&quot;&gt;
-    &lt;input type=&quot;submit&quot; value=&quot;File [% terms.bug %] again&quot; id=&quot;file_bug_again&quot;&gt;
-  &lt;/form&gt;
-[% END %]
-
-[% PROCESS global/footer.html.tmpl %]
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultbugcreatecreateguidedhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/bug/create/create-guided.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/bug/create/create-guided.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/bug/create/create-guided.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -34,6 +34,8 @@
</span><span class="cx">    style = &quot;#somebugs { width: 100%; height: 500px }&quot;
</span><span class="cx">  %]
</span><span class="cx"> 
</span><ins>+[% style = &quot;&quot; %]
+
</ins><span class="cx"> &lt;p&gt;
</span><span class="cx">   &lt;font color=&quot;red&quot;&gt;
</span><span class="cx">     This is a template used on mozilla.org.  This template, and the
</span><span class="lines">@@ -67,8 +69,7 @@
</span><span class="cx"> }
</span><span class="cx"> &lt;/script&gt;
</span><span class="cx"> 
</span><del>-&lt;a name=&quot;step1&quot;&gt;&lt;/a&gt;
-&lt;h3&gt;Step 1 of 3 - has your [% terms.bug %] already been reported?&lt;/h3&gt;
</del><ins>+&lt;h3 id=&quot;step1&quot;&gt;Step 1 of 3 - has your [% terms.bug %] already been reported?&lt;/h3&gt;
</ins><span class="cx"> 
</span><span class="cx"> &lt;p&gt;
</span><span class="cx">   &lt;font color=&quot;red&quot;&gt;Please don't skip this step - half of all 
</span><span class="lines">@@ -83,7 +84,7 @@
</span><span class="cx"> [% ELSIF product.name == &quot;Thunderbird&quot; %]
</span><span class="cx">   [% productstring = &quot;product=Mozilla%20Application%20Suite&amp;amp;product=Thunderbird&quot; %]
</span><span class="cx"> [% ELSE %]
</span><del>-  [% productstring = BLOCK %]product=[% product.name FILTER url_quote %][% END %]
</del><ins>+  [% productstring = BLOCK %]product=[% product.name FILTER uri %][% END %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> &lt;p&gt;
</span><span class="lines">@@ -136,8 +137,7 @@
</span><span class="cx"> &lt;/p&gt;
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-&lt;a name=&quot;step2&quot;&gt;&lt;/a&gt;
-&lt;h3&gt;Step 2 of 3 - give information&lt;/h3&gt;
</del><ins>+&lt;h3 id=&quot;step2&quot;&gt;Step 2 of 3 - give information&lt;/h3&gt;
</ins><span class="cx"> 
</span><span class="cx"> &lt;p&gt;
</span><span class="cx">   If you've tried a few searches and your [% terms.bug %] really isn't in 
</span><span class="lines">@@ -207,7 +207,7 @@
</span><span class="cx">         To pick the right component, you could use the same one as
</span><span class="cx">         similar [% terms.bugs %] you found in your search, or read the full list of
</span><span class="cx">         &lt;a target=&quot;_blank&quot; href=&quot;describecomponents.cgi?product=
</span><del>-            [% product.name FILTER url_quote %]&quot;&gt;component
</del><ins>+            [% product.name FILTER uri %]&quot;&gt;component
</ins><span class="cx">         descriptions&lt;/a&gt; (opens in new window) if you need more help.
</span><span class="cx">       &lt;/p&gt;
</span><span class="cx">     &lt;/td&gt;
</span><span class="lines">@@ -471,11 +471,12 @@
</span><span class="cx">       &lt;/p&gt;
</span><span class="cx">     &lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><ins>+
+  [% Hook.process('form') %]
</ins><span class="cx"> &lt;/table&gt;
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-&lt;a name=&quot;step3&quot;&gt;&lt;/a&gt;
-&lt;h3&gt;Step 3 of 3 - submit the [% terms.bug %] report&lt;/h3&gt;
</del><ins>+&lt;h3 id=&quot;step3&quot;&gt;Step 3 of 3 - submit the [% terms.bug %] report&lt;/h3&gt;
</ins><span class="cx"> 
</span><span class="cx"> &lt;p&gt;
</span><span class="cx">   &lt;input type=&quot;submit&quot; id=&quot;report&quot; value=&quot;    Submit [% terms.Bug %] Report    &quot;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultbugcreatecreatehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/bug/create/create.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/bug/create/create.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/bug/create/create.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -30,11 +30,13 @@
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/header.html.tmpl
</span><span class="cx">   title = title
</span><del>-  style_urls = [ 'skins/standard/create_attachment.css',
-                 'skins/standard/yui/calendar.css' ]
</del><ins>+  yui = [ 'autocomplete', 'calendar', 'datatable', 'button' ]
+  style_urls = [ 'skins/standard/attachment.css',
+                 'skins/standard/enter_bug.css' ]
</ins><span class="cx">   javascript_urls = [ &quot;js/attachment.js&quot;, &quot;js/util.js&quot;,
</span><del>-                      &quot;js/yui/yahoo-dom-event.js&quot;, &quot;js/yui/calendar.js&quot;,
-                      &quot;js/field.js&quot; ]
</del><ins>+                      &quot;js/field.js&quot;, &quot;js/TUI.js&quot;, &quot;js/bug.js&quot; ]
+  onload = &quot;set_assign_to(); hideElementById('attachment_true');
+            showElementById('attachment_false'); showElementById('btn_no_attachment');&quot;
</ins><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> &lt;script type=&quot;text/javascript&quot;&gt;
</span><span class="lines">@@ -52,6 +54,7 @@
</span><span class="cx"> [% END %]
</span><span class="cx"> [% count = 0 %]
</span><span class="cx"> [%- FOREACH c = product.components %]
</span><ins>+    [% NEXT IF NOT c.is_active %]
</ins><span class="cx">     components[[% count %]] = &quot;[% c.name FILTER js %]&quot;;
</span><span class="cx">     comp_desc[[% count %]] = &quot;[% c.description FILTER html_light FILTER js %]&quot;;
</span><span class="cx">     initialowners[[% count %]] = &quot;[% c.default_assignee.login FILTER js %]&quot;;
</span><span class="lines">@@ -128,9 +131,10 @@
</span><span class="cx">             if (inputElement.name.search(/^flag_type-(\d+)$/) != -1) {
</span><span class="cx">                 var id = inputElement.name.replace(/^flag_type-(\d+)$/, &quot;$1&quot;);
</span><span class="cx">                 inputElement.disabled = true;
</span><del>-                // Also disable the requestee field, if it exists.
</del><ins>+                // Also hide the requestee field, if it exists.
</ins><span class="cx">                 inputElement = document.getElementById(&quot;requestee_type-&quot; + id);
</span><del>-                if (inputElement) inputElement.disabled = true;
</del><ins>+                if (inputElement)
+                  YAHOO.util.Dom.addClass(inputElement.parentNode, 'bz_default_hidden');
</ins><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">         // Now enable flags available for the selected component.
</span><span class="lines">@@ -147,57 +151,76 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-function handleWantsAttachment(wants_attachment) {
-    if (wants_attachment) {
-        document.getElementById('attachment_false').style.display = 'none';
-        document.getElementById('attachment_true').style.display = 'block';
-    }
-    else {
-        document.getElementById('attachment_false').style.display = 'block';
-        document.getElementById('attachment_true').style.display = 'none';
-        clearAttachmentFields();
-    }
-}
</del><ins>+var status_comment_required = new Array();
+[% FOREACH status = bug_status %]
+  status_comment_required['[% status.name FILTER js %]'] = 
+    [% status.comment_required_on_change_from() ? 'true' : 'false' %]
+[% END %]
</ins><span class="cx"> 
</span><ins>+TUI_alternates['expert_fields'] = 'Show Advanced Fields';
+// Hide the Advanced Fields by default, unless the user has a cookie
+// that specifies otherwise.
+TUI_hide_default('expert_fields');
+// Also hide the &quot;Paste text as attachment&quot; textarea by default.
+TUI_hide_default('attachment_text_field');
</ins><span class="cx"> --&gt;
</span><span class="cx"> &lt;/script&gt;
</span><span class="cx"> 
</span><span class="cx"> &lt;form name=&quot;Create&quot; id=&quot;Create&quot; method=&quot;post&quot; action=&quot;post_bug.cgi&quot;
</span><del>-      enctype=&quot;multipart/form-data&quot;&gt;
</del><ins>+      class=&quot;enter_bug_form&quot; enctype=&quot;multipart/form-data&quot;
+      onsubmit=&quot;return validateEnterBug(this)&quot;&gt;
</ins><span class="cx"> &lt;input type=&quot;hidden&quot; name=&quot;product&quot; value=&quot;[% product.name FILTER html %]&quot;&gt;
</span><span class="cx"> &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% token FILTER html %]&quot;&gt;
</span><span class="cx"> 
</span><del>-&lt;table cellspacing=&quot;4&quot; cellpadding=&quot;2&quot; border=&quot;0&quot;&gt;
</del><ins>+&lt;table&gt;
</ins><span class="cx"> &lt;tbody&gt;
</span><span class="cx">   &lt;tr&gt;
</span><span class="cx">     &lt;td colspan=&quot;4&quot;&gt;
</span><span class="cx">     [%# Migration note: The following file corresponds to the old Param
</span><span class="cx">       # 'entryheaderhtml'
</span><span class="cx">       #%]
</span><del>-    [% INCLUDE 'bug/create/user-message.html.tmpl' %]
</del><ins>+    [% PROCESS 'bug/create/user-message.html.tmpl' %]
</ins><span class="cx">     &lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;tr&gt;
</span><del>-    &lt;td colspan=&quot;4&quot;&gt;&amp;nbsp;&lt;/td&gt;
</del><ins>+    &lt;td colspan=&quot;2&quot;&gt;
+      &lt;a id=&quot;expert_fields_controller&quot; class=&quot;controller bz_default_hidden&quot;
+         href=&quot;javascript:TUI_toggle_class('expert_fields')&quot;&gt;Hide
+        Advanced Fields&lt;/a&gt;
+      [%# Show the link if the browser supports JS %]
+      &lt;script type=&quot;text/javascript&quot;&gt;
+        YAHOO.util.Dom.removeClass('expert_fields_controller', 
+                                   'bz_default_hidden');
+      &lt;/script&gt;
+    &lt;/td&gt;
+    &lt;td colspan=&quot;2&quot;&gt;
+      (&lt;span class=&quot;required_star&quot;&gt;*&lt;/span&gt; =
+      &lt;span class=&quot;required_explanation&quot;&gt;Required Field&lt;/span&gt;)
+   &lt;/td&gt;
</ins><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;tr&gt;
</span><del>-    &lt;th&gt;Product:&lt;/th&gt;
-    &lt;td width=&quot;10%&quot;&gt;[% product.name FILTER html %]&lt;/td&gt;
-
-    &lt;th&gt;Reporter:&lt;/th&gt;
-    &lt;td width=&quot;100%&quot;&gt;[% user.login FILTER html %]&lt;/td&gt;
</del><ins>+    [% INCLUDE bug/field.html.tmpl
+      bug = default, field = bug_fields.product, editable = 0,
+      value = product.name %]
+    [% INCLUDE bug/field.html.tmpl
+      bug = default, field = bug_fields.reporter, editable = 0,
+      value = user.login %]
</ins><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> 
</span><span class="cx">   [%# We can't use the select block in these two cases for various reasons. %]
</span><span class="cx">   &lt;tr&gt;
</span><del>-    &lt;th&gt;
-      &lt;a href=&quot;describecomponents.cgi?product=[% product.name FILTER url_quote %]&quot;&gt;
-      Component&lt;/a&gt;:
-    &lt;/th&gt;
-    &lt;td&gt;
-      &lt;select name=&quot;component&quot; onchange=&quot;set_assign_to();&quot; size=&quot;7&quot;&gt;
</del><ins>+    [% component_desc_url = BLOCK -%]
+      describecomponents.cgi?product=[% product.name FILTER uri %]
+    [% END %]
+    [% INCLUDE &quot;bug/field-label.html.tmpl&quot;
+      field = bug_fields.component editable = 1
+      desc_url = component_desc_url
+    %]      
+    &lt;td id=&quot;field_container_component&quot;&gt;
+      &lt;select name=&quot;component&quot; id=&quot;component&quot; onchange=&quot;set_assign_to();&quot;
+              size=&quot;7&quot; aria-required=&quot;true&quot; class=&quot;required&quot;&gt;
</ins><span class="cx">         [%# Build the lists of assignees and QA contacts if &quot;usemenuforusers&quot; is enabled. %]
</span><span class="cx">         [% IF Param(&quot;usemenuforusers&quot;) %]
</span><span class="cx">           [% assignees_list = user.get_userlist.clone %]
</span><span class="lines">@@ -205,8 +228,15 @@
</span><span class="cx">         [% END %]
</span><span class="cx"> 
</span><span class="cx">         [%- FOREACH c = product.components %]
</span><ins>+          [% NEXT IF NOT c.is_active %]
</ins><span class="cx">           &lt;option value=&quot;[% c.name FILTER html %]&quot;
</span><del>-            [% &quot; selected=\&quot;selected\&quot;&quot; IF c.name == default.component_ %]&gt;
</del><ins>+                  id=&quot;v[% c.id FILTER html %]_component&quot;
+            [% IF c.name == default.component_ %]
+              [%# This is for bug/field.html.tmpl, for visibility-related
+                # controls. %]
+              [% default.component_id = c.id %]
+              selected=&quot;selected&quot;
+            [% END %]&gt;
</ins><span class="cx">             [% c.name FILTER html -%]
</span><span class="cx">           &lt;/option&gt;
</span><span class="cx">           [% IF Param(&quot;usemenuforusers&quot;) %]
</span><span class="lines">@@ -217,9 +247,16 @@
</span><span class="cx">           [% END %]
</span><span class="cx">         [%- END %]
</span><span class="cx">       &lt;/select&gt;
</span><ins>+
+      &lt;script type=&quot;text/javascript&quot;&gt;
+       &lt;!--
+         [%+ INCLUDE &quot;bug/field-events.js.tmpl&quot; 
+                     field = bug_fields.component, product = product %]
+       //--&gt;
+       &lt;/script&gt;
</ins><span class="cx">     &lt;/td&gt;
</span><span class="cx"> 
</span><del>-    &lt;td colspan=&quot;2&quot;&gt;
</del><ins>+    &lt;td colspan=&quot;2&quot; id=&quot;comp_desc_container&quot;&gt;
</ins><span class="cx">       [%# Enclose the fieldset in a nested table so that its width changes based
</span><span class="cx">         # on the length on the component description. %]
</span><span class="cx">       &lt;table&gt;
</span><span class="lines">@@ -236,91 +273,87 @@
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;tr&gt;
</span><del>-    &lt;th rowspan=&quot;3&quot;&gt;Version:&lt;/th&gt;
</del><ins>+    [% INCLUDE &quot;bug/field-label.html.tmpl&quot;
+      field = bug_fields.version editable = 1 rowspan = 3 
+    %]
</ins><span class="cx">     &lt;td rowspan=&quot;3&quot;&gt;
</span><del>-      &lt;select name=&quot;version&quot; size=&quot;5&quot;&gt;
</del><ins>+      &lt;select name=&quot;version&quot; id=&quot;version&quot; size=&quot;5&quot;&gt;
</ins><span class="cx">         [%- FOREACH v = version %]
</span><del>-          &lt;option value=&quot;[% v FILTER html %]&quot;
-            [% ' selected=&quot;selected&quot;' IF v == default.version %]&gt;[% v FILTER html -%]
</del><ins>+          [% NEXT IF NOT v.is_active %]
+          &lt;option value=&quot;[% v.name FILTER html %]&quot;
+            [% ' selected=&quot;selected&quot;' IF v.name == default.version %]&gt;[% v.name FILTER html -%]
</ins><span class="cx">           &lt;/option&gt;
</span><span class="cx">         [%- END %]
</span><span class="cx">       &lt;/select&gt;
</span><span class="cx">     &lt;/td&gt;
</span><span class="cx"> 
</span><del>-    [% sel = { description =&gt; 'Severity', name =&gt; 'bug_severity' } %]
-    [% INCLUDE select %]
</del><ins>+    [% INCLUDE bug/field.html.tmpl
+      bug = default, field = bug_fields.bug_severity, editable = 1, 
+      value = default.bug_severity %]
</ins><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;tr&gt;
</span><del>-    [% sel = { description =&gt; 'Platform', name =&gt; 'rep_platform' } %]
-    [% INCLUDE select %]
</del><ins>+    [% INCLUDE bug/field.html.tmpl
+      bug = default, field = bug_fields.rep_platform, editable = 1,
+      value = default.rep_platform %]
</ins><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;tr&gt;
</span><del>-    [% sel = { description =&gt; 'OS', name =&gt; 'op_sys' } %]
-    [% INCLUDE select %]
</del><ins>+    [% INCLUDE bug/field.html.tmpl 
+       bug = default, field = bug_fields.op_sys, editable = 1, 
+       value = default.op_sys %]
</ins><span class="cx">   &lt;/tr&gt;
</span><ins>+  [% IF !Param('defaultplatform') || !Param('defaultopsys') %]
+    &lt;tr&gt;
+      &lt;th colspan=&quot;3&quot;&gt;&amp;nbsp;&lt;/th&gt;
+      &lt;td id=&quot;os_guess_note&quot; class=&quot;comment&quot;&gt;
+        &lt;div&gt;We've made a guess at your
+        [% IF Param('defaultplatform') %]
+          operating system. Please check it
+        [% ELSIF Param('defaultopsys') %]
+          platform. Please check it
+        [% ELSE %]
+          operating system and platform. Please check them
+        [% END %]
+        and make any corrections if necessary.&lt;/div&gt;
+      &lt;/td&gt;
+    &lt;/tr&gt;
+  [% END %]
</ins><span class="cx"> &lt;/tbody&gt;
</span><span class="cx"> 
</span><span class="cx"> &lt;tbody class=&quot;expert_fields&quot;&gt;
</span><span class="cx">   &lt;tr&gt;
</span><span class="cx">     [% IF Param('usetargetmilestone') &amp;&amp; Param('letsubmitterchoosemilestone') %]
</span><del>-      [% sel = { description =&gt; 'Target Milestone', name =&gt; 'target_milestone' } %]
-      [% INCLUDE select %]
</del><ins>+      [% INCLUDE select field = bug_fields.target_milestone %]
</ins><span class="cx">     [% ELSE %]
</span><span class="cx">       &lt;td colspan=&quot;2&quot;&gt;&amp;nbsp;&lt;/td&gt;
</span><span class="cx">     [% END %]
</span><span class="cx"> 
</span><span class="cx">     [% IF Param('letsubmitterchoosepriority') %]
</span><del>-      [% sel = { description =&gt; 'Priority', name =&gt; 'priority' } %]
-      [% INCLUDE select %]
</del><ins>+      [% INCLUDE bug/field.html.tmpl
+        bug = default, field = bug_fields.priority, editable = 1, 
+        value = default.priority %]
</ins><span class="cx">     [% ELSE %]
</span><del>-      &lt;td colspan=&quot;2&quot;&gt;
-        &lt;input type=&quot;hidden&quot; name=&quot;priority&quot; value=&quot;[% default.priority FILTER html %]&quot;&gt;
-      &lt;/td&gt;
</del><ins>+      &lt;td colspan=&quot;2&quot;&gt;&amp;nbsp;&lt;/td&gt;
</ins><span class="cx">     [% END %]
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> &lt;/tbody&gt;
</span><span class="cx"> 
</span><del>-[% IF !Param('defaultplatform') || !Param('defaultopsys') %]
-  &lt;tbody&gt;
-    &lt;tr&gt;
-      &lt;th&gt;&amp;nbsp;&lt;/th&gt;
-      &lt;td colspan=&quot;3&quot; class=&quot;comment&quot;&gt;
-        We've made a guess at your
-        [% IF Param('defaultplatform') %]
-          operating system. Please check it
-        [% ELSIF Param('defaultopsys') %]
-          platform. Please check it
-        [% ELSE %]
-          operating system and platform. Please check them
-        [% END %]
-        and make any corrections if necessary.
-      &lt;/td&gt;
-    &lt;/tr&gt;
-  &lt;/tbody&gt;
-[% END %]
-
</del><span class="cx"> &lt;tbody class=&quot;expert_fields&quot;&gt;
</span><span class="cx">   &lt;tr&gt;
</span><span class="cx">     &lt;td colspan=&quot;4&quot;&gt;&amp;nbsp;&lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;tr&gt;
</span><del>-[% IF bug_status.size &lt;= 1 %]
-  &lt;input type=&quot;hidden&quot; name=&quot;bug_status&quot; 
-         value=&quot;[% default.bug_status FILTER html %]&quot;&gt;
-    &lt;th&gt;Initial State:&lt;/th&gt;
-    &lt;td&gt;[% get_status(default.bug_status) FILTER html %]&lt;/td&gt;
-[% ELSE %]
-    [% sel = { description =&gt; 'Initial State', name =&gt; 'bug_status' } %]
-    [% INCLUDE select %]
-[% END %]
</del><ins>+    [% INCLUDE bug/field.html.tmpl
+      bug = default, field = bug_fields.bug_status,
+      editable = (bug_status.size &gt; 1), value = default.bug_status
+      override_legal_values = bug_status %]
</ins><span class="cx"> 
</span><span class="cx">     &lt;td&gt;&amp;nbsp;&lt;/td&gt;
</span><span class="cx">     [%# Calculate the number of rows we can use for flags %]
</span><span class="cx">     [% num_rows = 6 + (Param(&quot;useqacontact&quot;) ? 1 : 0) +
</span><del>-                      (user.in_group(Param('timetrackinggroup')) ? 3 : 0) +
</del><ins>+                      (user.is_timetracker ? 3 : 0) +
</ins><span class="cx">                       (Param(&quot;usebugaliases&quot;) ? 1 : 0)
</span><span class="cx">     %]
</span><span class="cx"> 
</span><span class="lines">@@ -346,9 +379,12 @@
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;tr&gt;
</span><del>-    &lt;th&gt;&lt;a href=&quot;page.cgi?id=fields.html#assigned_to&quot;&gt;Assign To&lt;/a&gt;:&lt;/th&gt;
</del><ins>+    [% INCLUDE &quot;bug/field-label.html.tmpl&quot;
+      field = bug_fields.assigned_to editable = 1
+    %]
</ins><span class="cx">     &lt;td colspan=&quot;2&quot;&gt;
</span><span class="cx">       [% INCLUDE global/userselect.html.tmpl
</span><ins>+         id =&gt; &quot;assigned_to&quot;
</ins><span class="cx">          name =&gt; &quot;assigned_to&quot;
</span><span class="cx">          value =&gt; assigned_to
</span><span class="cx">          disabled =&gt; assigned_to_disabled
</span><span class="lines">@@ -362,9 +398,12 @@
</span><span class="cx">   
</span><span class="cx"> [% IF Param(&quot;useqacontact&quot;) %]
</span><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;th&gt;QA Contact:&lt;/th&gt;
</del><ins>+      [% INCLUDE &quot;bug/field-label.html.tmpl&quot;
+        field = bug_fields.qa_contact editable = 1
+      %]
</ins><span class="cx">       &lt;td colspan=&quot;2&quot;&gt;
</span><span class="cx">       [% INCLUDE global/userselect.html.tmpl
</span><ins>+         id =&gt; &quot;qa_contact&quot;
</ins><span class="cx">          name =&gt; &quot;qa_contact&quot;
</span><span class="cx">          value =&gt; qa_contact
</span><span class="cx">          disabled =&gt; qa_contact_disabled
</span><span class="lines">@@ -378,9 +417,12 @@
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx">   &lt;tr&gt;
</span><del>-    &lt;th&gt;CC:&lt;/th&gt;
</del><ins>+    [% INCLUDE &quot;bug/field-label.html.tmpl&quot;
+      field = bug_fields.cc editable = 1 
+    %]
</ins><span class="cx">     &lt;td colspan=&quot;2&quot;&gt;
</span><span class="cx">       [% INCLUDE global/userselect.html.tmpl
</span><ins>+         id =&gt; &quot;cc&quot;
</ins><span class="cx">          name =&gt; &quot;cc&quot;
</span><span class="cx">          value =&gt; cc
</span><span class="cx">          disabled =&gt; cc_disabled
</span><span class="lines">@@ -391,13 +433,9 @@
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;tr&gt;
</span><del>-    &lt;th&gt;Default CC:&lt;/th&gt;
</del><ins>+    &lt;th&gt;Default [% field_descs.cc FILTER html %]:&lt;/th&gt;
</ins><span class="cx">     &lt;td colspan=&quot;2&quot;&gt;
</span><span class="cx">       &lt;div id=&quot;initial_cc&quot;&gt;
</span><del>-          &lt;!-- This has to happen after everything above renders,
-               and onload doesn't work. So this is as good a place
-               as any to put it. --&gt;
-          &lt;script type=&quot;text/javascript&quot;&gt;set_assign_to();&lt;/script&gt;
</del><span class="cx">       &lt;/div&gt;
</span><span class="cx">    &lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><span class="lines">@@ -406,19 +444,19 @@
</span><span class="cx">     &lt;td colspan=&quot;3&quot;&gt;&amp;nbsp;&lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> 
</span><del>-[% IF user.in_group(Param('timetrackinggroup')) %]
</del><ins>+[% IF user.is_timetracker %]
</ins><span class="cx">   &lt;tr&gt;
</span><del>-    &lt;th&gt;Estimated Hours:&lt;/th&gt;
</del><ins>+    [% INCLUDE &quot;bug/field-label.html.tmpl&quot;
+      field = bug_fields.estimated_time editable = 1
+    %]
</ins><span class="cx">     &lt;td colspan=&quot;2&quot;&gt;
</span><del>-      &lt;input name=&quot;estimated_time&quot; size=&quot;6&quot; maxlength=&quot;6&quot; value=&quot;0.0&quot;&gt;
</del><ins>+      &lt;input name=&quot;estimated_time&quot; size=&quot;6&quot; maxlength=&quot;6&quot; value=&quot;[% estimated_time FILTER html %]&quot;&gt;
</ins><span class="cx">     &lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx">   &lt;tr&gt;
</span><del>-    &lt;th&gt;Deadline:&lt;/th&gt;
-    &lt;td colspan=&quot;2&quot;&gt;
-      &lt;input name=&quot;deadline&quot; size=&quot;10&quot; maxlength=&quot;10&quot; value=&quot;[% deadline FILTER html %]&quot;&gt;
-      &lt;small&gt;(YYYY-MM-DD)&lt;/small&gt;
-    &lt;/td&gt;
</del><ins>+    [% INCLUDE bug/field.html.tmpl
+      bug = default, field = bug_fields.deadline, value = deadline,
+      editable = 1, value_span = 2 %] 
</ins><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;tr&gt;
</span><span class="lines">@@ -428,18 +466,22 @@
</span><span class="cx"> 
</span><span class="cx"> [% IF Param(&quot;usebugaliases&quot;) %]
</span><span class="cx">   &lt;tr&gt;
</span><del>-    &lt;th&gt;Alias:&lt;/th&gt;
</del><ins>+    [% INCLUDE &quot;bug/field-label.html.tmpl&quot;
+      field = bug_fields.alias editable = 1
+    %]
</ins><span class="cx">     &lt;td colspan=&quot;2&quot;&gt;
</span><del>-      &lt;input name=&quot;alias&quot; size=&quot;20&quot;&gt;
</del><ins>+      &lt;input name=&quot;alias&quot; size=&quot;20&quot; value=&quot;[% alias FILTER html %]&quot;&gt;
</ins><span class="cx">     &lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx">   &lt;tr&gt;
</span><del>-    &lt;th&gt;URL:&lt;/th&gt;
-    &lt;td colspan=&quot;2&quot;&gt;
-      &lt;input name=&quot;bug_file_loc&quot; size=&quot;40&quot;
-             value=&quot;[% bug_file_loc FILTER html %]&quot;&gt;
</del><ins>+    [% INCLUDE &quot;bug/field-label.html.tmpl&quot;
+      field = bug_fields.bug_file_loc editable = 1
+    %]
+    &lt;td colspan=&quot;2&quot; class=&quot;field_value&quot;&gt;
+      &lt;input name=&quot;bug_file_loc&quot; id=&quot;bug_file_loc&quot; class=&quot;text_input&quot;
+             size=&quot;40&quot; value=&quot;[% bug_file_loc FILTER html %]&quot;&gt;
</ins><span class="cx">     &lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> &lt;/tbody&gt;
</span><span class="lines">@@ -450,22 +492,66 @@
</span><span class="cx">   [% FOREACH field = Bugzilla.active_custom_fields %]
</span><span class="cx">     [% NEXT UNLESS field.enter_bug %]
</span><span class="cx">     [% SET value = ${field.name}.defined ? ${field.name} : &quot;&quot; %]
</span><del>-    &lt;tr&gt;
-      [% PROCESS bug/field.html.tmpl editable=1 value_span=3 %]
</del><ins>+    &lt;tr [% 'class=&quot;expert_fields&quot;' IF !field.is_mandatory %]&gt;
+      [% INCLUDE bug/field.html.tmpl 
+        bug = default, field = field, value = value, editable = 1, 
+        value_span = 3 %]
</ins><span class="cx">     &lt;/tr&gt;
</span><span class="cx">   [% END %]
</span><ins>+&lt;/tbody&gt;
</ins><span class="cx"> 
</span><ins>+&lt;tbody&gt;
+
</ins><span class="cx">   &lt;tr&gt;
</span><del>-    &lt;th&gt;Summary:&lt;/th&gt;
-    &lt;td colspan=&quot;3&quot;&gt;
</del><ins>+    [% INCLUDE &quot;bug/field-label.html.tmpl&quot;
+      field = bug_fields.short_desc editable = 1
+    %]
+    &lt;td colspan=&quot;3&quot; class=&quot;field_value&quot;&gt;
</ins><span class="cx">       &lt;input name=&quot;short_desc&quot; size=&quot;70&quot; value=&quot;[% short_desc FILTER html %]&quot;
</span><del>-             maxlength=&quot;255&quot; spellcheck=&quot;true&quot;&gt;
</del><ins>+             maxlength=&quot;255&quot; spellcheck=&quot;true&quot; aria-required=&quot;true&quot;
+             class=&quot;required text_input&quot; id=&quot;short_desc&quot;&gt;
</ins><span class="cx">     &lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> 
</span><ins>+  [% IF feature_enabled('jsonrpc') AND !cloned_bug_id %]
+    &lt;tr id=&quot;possible_duplicates_container&quot; class=&quot;bz_default_hidden&quot;&gt;
+      &lt;th&gt;Possible&lt;br&gt;Duplicates:&lt;/th&gt;
+      &lt;td colspan=&quot;3&quot;&gt;
+        &lt;div id=&quot;possible_duplicates&quot;&gt;&lt;/div&gt;
+        &lt;script type=&quot;text/javascript&quot;&gt;
+          var dt_columns = [ 
+              { key: &quot;id&quot;, label: &quot;[% field_descs.bug_id FILTER js %]&quot;,
+                formatter: YAHOO.bugzilla.dupTable.formatBugLink },
+              { key: &quot;summary&quot;, 
+                label: &quot;[% field_descs.short_desc FILTER js %]&quot;,
+                formatter: &quot;text&quot; },
+              { key: &quot;status&quot;,
+                label: &quot;[% field_descs.bug_status FILTER js %]&quot;,
+                formatter: YAHOO.bugzilla.dupTable.formatStatus },
+              { key: &quot;update_token&quot;, label: '',
+                formatter: YAHOO.bugzilla.dupTable.formatCcButton }
+          ];
+          YAHOO.bugzilla.dupTable.addCcMessage = &quot;Add Me to the CC List&quot;;
+          YAHOO.bugzilla.dupTable.init({
+            container: 'possible_duplicates',
+            columns: dt_columns,
+            product_name: '[% product.name FILTER js %]',
+            summary_field: 'short_desc',
+            options: {
+              MSG_LOADING: 'Searching for possible duplicates...',
+              MSG_EMPTY:   'No possible duplicates found.',
+              SUMMARY:     'Possible Duplicates'
+            }
+          });
+        &lt;/script&gt;
+      &lt;/td&gt;
+    &lt;/tr&gt;
+  [% END %]
+
</ins><span class="cx">   &lt;tr&gt;
</span><span class="cx">     &lt;th&gt;Description:&lt;/th&gt;
</span><span class="cx">     &lt;td colspan=&quot;3&quot;&gt;
</span><ins>+
</ins><span class="cx">       [% defaultcontent = BLOCK %]
</span><span class="cx">         [% IF cloned_bug_id %]
</span><span class="cx"> +++ This [% terms.bug %] was initially created as a clone of [% terms.Bug %] #[% cloned_bug_id %] +++
</span><span class="lines">@@ -488,40 +574,33 @@
</span><span class="cx">     &lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> 
</span><del>-  [% IF Param(&quot;insidergroup&quot;) &amp;&amp; user.in_group(Param(&quot;insidergroup&quot;)) %]
-    &lt;tr&gt;
</del><ins>+  [% IF user.is_insider %]
+    &lt;tr class=&quot;expert_fields&quot;&gt;
</ins><span class="cx">       &lt;th&gt;&amp;nbsp;&lt;/th&gt;
</span><span class="cx">       &lt;td colspan=&quot;3&quot;&gt;
</span><span class="cx">         &amp;nbsp;&amp;nbsp;
</span><del>-        &lt;input type=&quot;checkbox&quot; id=&quot;commentprivacy&quot; name=&quot;commentprivacy&quot;
-          [% &quot; checked=\&quot;checked\&quot;&quot; IF commentprivacy %]&gt;
-        &lt;label for=&quot;commentprivacy&quot;&gt;
-          Initial Description is Private
</del><ins>+        &lt;input type=&quot;checkbox&quot; id=&quot;comment_is_private&quot; name=&quot;comment_is_private&quot;
+          [% ' checked=&quot;checked&quot;' IF comment_is_private %]
+               onClick=&quot;updateCommentTagControl(this, 'comment')&quot;&gt;
+        &lt;label for=&quot;comment_is_private&quot;&gt;
+          Make description and any new attachment private (visible only to members 
+          of the &lt;strong&gt;[% Param('insidergroup') FILTER html %]&lt;/strong&gt; group)
</ins><span class="cx">         &lt;/label&gt;
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">   [% END %]
</span><del>-&lt;/tbody&gt;
</del><span class="cx"> 
</span><del>-&lt;tbody class=&quot;expert_fields&quot;&gt;
</del><ins>+  [% IF Param(&quot;maxattachmentsize&quot;) || Param(&quot;maxlocalattachment&quot;) %]
</ins><span class="cx">   &lt;tr&gt;
</span><span class="cx">     &lt;th&gt;Attachment:&lt;/th&gt;
</span><span class="cx">     &lt;td colspan=&quot;3&quot;&gt;
</span><del>-      &lt;script type=&quot;text/javascript&quot;&gt;
-        &lt;!--
-        document.write( '&lt;div id=&quot;attachment_false&quot;&gt;'
-                      +   '&lt;input type=&quot;button&quot; value=&quot;Add an attachment&quot; '
-                      +          'onClick=&quot;handleWantsAttachment(true)&quot;&gt; '
-                      +   '&lt;em style=&quot;display: none&quot;&gt;This button has no '
-                      +   'functionality for you because your browser does '
-                      +   'not support CSS or does not use it.&lt;\/em&gt;'
-                      + '&lt;\/div&gt;'
-                      + '&lt;div id=&quot;attachment_true&quot; style=&quot;display: none&quot;&gt;'
-                      +   '&lt;input type=&quot;button&quot; '
-                      +          'value=&quot;Don\'t add an attachment &quot; '
-                      +          'onClick=&quot;handleWantsAttachment(false)&quot;&gt;');
-        //--&gt;
-      &lt;/script&gt;
</del><ins>+      &lt;div id=&quot;attachment_false&quot; class=&quot;bz_default_hidden&quot;&gt;
+        &lt;input type=&quot;button&quot; value=&quot;Add an attachment&quot; onClick=&quot;handleWantsAttachment(true)&quot;&gt;
+      &lt;/div&gt;
+
+      &lt;div id=&quot;attachment_true&quot;&gt;
+        &lt;input type=&quot;button&quot; id=&quot;btn_no_attachment&quot; value=&quot;Don't add an attachment&quot;
+               class=&quot;bz_default_hidden&quot;  onClick=&quot;handleWantsAttachment(false)&quot;&gt;
</ins><span class="cx">         &lt;fieldset&gt;
</span><span class="cx">           &lt;legend&gt;Add an attachment&lt;/legend&gt;
</span><span class="cx">           &lt;table class=&quot;attachment_entry&quot;&gt;
</span><span class="lines">@@ -531,33 +610,36 @@
</span><span class="cx">                        flag_table_id =&quot;attachment_flags&quot; %]
</span><span class="cx">           &lt;/table&gt;
</span><span class="cx">         &lt;/fieldset&gt;
</span><del>-      &lt;script type=&quot;text/javascript&quot;&gt;
-        &lt;!--
-        document.write('&lt;\/div&gt;');
-        //--&gt;
-      &lt;/script&gt;
</del><ins>+      &lt;/div&gt;
</ins><span class="cx">     &lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><ins>+  [% END %]
+&lt;/tbody&gt;
</ins><span class="cx"> 
</span><ins>+&lt;tbody class=&quot;expert_fields&quot;&gt;
</ins><span class="cx">   [% IF user.in_group('editbugs', product.id) %]
</span><span class="cx">     [% IF use_keywords %]
</span><span class="cx">       &lt;tr&gt;
</span><del>-        &lt;th&gt;&lt;a href=&quot;describekeywords.cgi&quot;&gt;Keywords&lt;/a&gt;:&lt;/th&gt;
-        &lt;td colspan=&quot;3&quot;&gt;
-          &lt;input id=&quot;keywords&quot; name=&quot;keywords&quot; size=&quot;40&quot;
-                 value=&quot;[% keywords FILTER html %]&quot;&gt; (optional)
-        &lt;/td&gt;
</del><ins>+        [% INCLUDE bug/field.html.tmpl
+           bug = default, field = bug_fields.keywords, editable = 1,
+           value = keywords, desc_url = &quot;describekeywords.cgi&quot;,
+           value_span = 2
+        %]
</ins><span class="cx">       &lt;/tr&gt;
</span><span class="cx">     [% END %]
</span><span class="cx"> 
</span><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;th&gt;Depends on:&lt;/th&gt;
</del><ins>+      [% INCLUDE &quot;bug/field-label.html.tmpl&quot;
+        field = bug_fields.dependson editable = 1
+      %]
</ins><span class="cx">       &lt;td colspan=&quot;3&quot;&gt;
</span><span class="cx">         &lt;input name=&quot;dependson&quot; accesskey=&quot;d&quot; value=&quot;[% dependson FILTER html %]&quot;&gt;
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;th&gt;Blocks:&lt;/th&gt;
</del><ins>+      [% INCLUDE &quot;bug/field-label.html.tmpl&quot;
+        field = bug_fields.blocked editable = 1
+      %]
</ins><span class="cx">       &lt;td colspan=&quot;3&quot;&gt;
</span><span class="cx">         &lt;input name=&quot;blocked&quot; accesskey=&quot;b&quot; value=&quot;[% blocked FILTER html %]&quot;&gt;
</span><span class="cx">       &lt;/td&gt;
</span><span class="lines">@@ -565,14 +647,15 @@
</span><span class="cx">   [% END %]
</span><span class="cx"> &lt;/tbody&gt;
</span><span class="cx"> 
</span><del>-&lt;tbody&gt;
-  [% IF group.size %]
</del><ins>+&lt;tbody class=&quot;expert_fields&quot;&gt;
+  [% IF product.groups_available.size %]
</ins><span class="cx">   &lt;tr&gt;
</span><span class="cx">     &lt;th&gt;&amp;nbsp;&lt;/th&gt;
</span><span class="cx">     &lt;td colspan=&quot;3&quot;&gt;
</span><span class="cx">       &lt;br&gt;
</span><span class="cx">         &lt;strong&gt;
</span><del>-          Only users in all of the selected groups can view this [% terms.bug %]:
</del><ins>+          Only users in all of the selected groups can view this 
+          [%+ terms.bug %]:
</ins><span class="cx">         &lt;/strong&gt;
</span><span class="cx">       &lt;br&gt;
</span><span class="cx">       &lt;font size=&quot;-1&quot;&gt;
</span><span class="lines">@@ -582,31 +665,32 @@
</span><span class="cx">       &lt;br&gt;
</span><span class="cx"> 
</span><span class="cx">       &lt;!-- Checkboxes --&gt;
</span><del>-      [% FOREACH g = group %]
-        &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
-        &lt;input type=&quot;checkbox&quot; id=&quot;bit-[% g.bit %]&quot;
-          name=&quot;bit-[% g.bit %]&quot; value=&quot;1&quot;
-          [% &quot; checked=\&quot;checked\&quot;&quot; IF g.checked %]&gt;
-          &lt;label for=&quot;bit-[% g.bit %]&quot;&gt;[% g.description FILTER html_light %]&lt;/label&gt;&lt;br&gt;
</del><ins>+      &lt;input type=&quot;hidden&quot; name=&quot;defined_groups&quot; value=&quot;1&quot;&gt;
+      [% FOREACH group = product.groups_available %]
+        &lt;input type=&quot;checkbox&quot; id=&quot;group_[% group.id FILTER html %]&quot;
+               name=&quot;groups&quot; value=&quot;[% group.name FILTER html %]&quot;
+               [% ' checked=&quot;checked&quot;' IF default.groups.contains(group.name)
+                                          OR group.is_default %]&gt;
+        &lt;label for=&quot;group_[% group.id FILTER html %]&quot;&gt;
+          [%- group.description FILTER html_light %]&lt;/label&gt;&lt;br&gt;
</ins><span class="cx">       [% END %]
</span><span class="cx">     &lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx">   [% END %]
</span><ins>+&lt;/tbody&gt;
</ins><span class="cx"> 
</span><ins>+&lt;tbody&gt;
</ins><span class="cx">   [%# Form controls for entering additional data about the bug being created. %]
</span><span class="cx">   [% Hook.process(&quot;form&quot;) %]
</span><span class="cx"> 
</span><span class="cx">   &lt;tr&gt;
</span><span class="cx">     &lt;th&gt;&amp;nbsp;&lt;/th&gt;
</span><span class="cx">     &lt;td colspan=&quot;3&quot;&gt;
</span><del>-      &lt;input type=&quot;submit&quot; id=&quot;commit&quot; value=&quot;Commit&quot;
-             onclick=&quot;if (this.form.short_desc.value == '')
-             { alert('Please enter a summary sentence for this [% terms.bug %].');
-               return false; } return true;&quot;&gt;
</del><ins>+      &lt;input type=&quot;submit&quot; id=&quot;commit&quot; value=&quot;Submit [% terms.Bug %]&quot;&gt;
</ins><span class="cx">       &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
</span><span class="cx">       &lt;input type=&quot;submit&quot; name=&quot;maketemplate&quot; id=&quot;maketemplate&quot;
</span><span class="cx">              value=&quot;Remember values as bookmarkable template&quot;
</span><del>-             class=&quot;expert_fields&quot;&gt;
</del><ins>+             onclick=&quot;bz_no_validate_enter_bug=true&quot; class=&quot;expert_fields&quot;&gt;
</ins><span class="cx">     &lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> &lt;/tbody&gt;
</span><span class="lines">@@ -624,22 +708,19 @@
</span><span class="cx"> [%############################################################################%]
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK select %]
</span><del>-  [% IF sel.description %]
-    &lt;th&gt;
-      &lt;a href=&quot;page.cgi?id=fields.html#[% sel.name %]&quot;&gt;[% sel.description %]&lt;/a&gt;:
-    &lt;/th&gt;
-  [% END %]
</del><span class="cx"> 
</span><ins>+  [% INCLUDE &quot;bug/field-label.html.tmpl&quot;
+    field = field editable = 1
+  %]
</ins><span class="cx">   &lt;td&gt;
</span><del>-    &lt;select name=&quot;[% sel.name %]&quot;&gt;
-    [%- FOREACH x = ${sel.name} %]
-      &lt;option value=&quot;[% x FILTER html %]&quot;
-        [% &quot; selected=\&quot;selected\&quot;&quot; IF x == default.${sel.name} %]&gt;
-        [% IF sel.name == &quot;bug_status&quot; %]
-          [% get_status(x) FILTER html %]
-        [% ELSE %]
-          [% x FILTER html %]
-        [% END %]&lt;/option&gt;
</del><ins>+    &lt;select name=&quot;[% field.name FILTER html %]&quot; 
+            id=&quot;[% field.name FILTER html %]&quot;&gt;
+    [%- FOREACH x = ${field.name} %]
+      [% NEXT IF NOT x.is_active %]
+      &lt;option value=&quot;[% x.name FILTER html %]&quot;
+        [% &quot; selected=\&quot;selected\&quot;&quot; IF x.name == default.${field.name} %]&gt;
+        [% display_value(field.name, x.name) FILTER html %]
+      &lt;/option&gt;
</ins><span class="cx">     [% END %]
</span><span class="cx">     &lt;/select&gt;
</span><span class="cx">   &lt;/td&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultbugcreatecreatedhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/bug/create/created.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/bug/create/created.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/bug/create/created.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -24,23 +24,16 @@
</span><span class="cx">   #     type: string; type of change for this bug, either 'created' if this bug
</span><span class="cx">   #         was created or 'dep' if it was added as a dependent/blocker
</span><span class="cx">   #     id: integer; the ID of the bug
</span><del>-  # mailrecipients: hash; contains the BugMail recipients, for details on
-  #     this contents, see template bug/process/bugmail.html.tmpl
</del><span class="cx">   # bug: object; Bugzilla::Bug object of the bug that was created (used in
</span><span class="cx">   #     template bug/edit.html.tmpl
</span><del>-  # bug_list: array of integers; sorted bug list (used in template
-  #     bug/navigate.html.tmpl)
</del><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="cx"> 
</span><ins>+[% PROCESS &quot;bug/show-header.html.tmpl&quot; %]
</ins><span class="cx"> [% PROCESS global/header.html.tmpl
</span><del>-  title = &quot;$terms.Bug $id Submitted&quot;
-  javascript_urls = [ &quot;js/util.js&quot;, &quot;js/field.js&quot;,
-                        &quot;js/yui/yahoo-dom-event.js&quot;, &quot;js/yui/calendar.js&quot; ]
-  style_urls = [ &quot;skins/standard/yui/calendar.css&quot;, &quot;skins/standard/show_bug.css&quot; ]
-  
-  
</del><ins>+  title = &quot;$terms.Bug $id Submitted &amp;ndash; $filtered_desc&quot;
+  header = &quot;$terms.Bug&amp;nbsp;$id Submitted&quot;
</ins><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> [% header_done = 1 %]
</span><span class="lines">@@ -49,8 +42,7 @@
</span><span class="cx">   [% PROCESS bug/process/results.html.tmpl
</span><span class="cx">      type = item.type
</span><span class="cx">      id = item.id
</span><del>-     mail = item.mail
-     mailrecipients = mailrecipients
</del><ins>+     sent_bugmail = item
</ins><span class="cx">    %]
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultbugdependencygraphhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/bug/dependency-graph.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/bug/dependency-graph.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/bug/dependency-graph.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -21,7 +21,6 @@
</span><span class="cx"> [%# INTERFACE:
</span><span class="cx">   # bug_id: integer. The number of the bug(s).
</span><span class="cx">   # multiple_bugs: boolean. True if bug_id contains &gt; 1 bug number.
</span><del>-  # doall: boolean. True if we are displaying every bug in the database.
</del><span class="cx">   # showsummary: boolean. True if we are showing bug summaries.
</span><span class="cx">   # rankdir: string. &quot;TB&quot; if we are ranking top-to-bottom,
</span><span class="cx">                      &quot;LR&quot; if left-to-right.
</span><span class="lines">@@ -37,7 +36,7 @@
</span><span class="cx">    header = title
</span><span class="cx">  %]
</span><span class="cx"> 
</span><del>-[% IF NOT multiple_bugs AND NOT doall %]
</del><ins>+[% IF NOT multiple_bugs %]
</ins><span class="cx">   [% filtered_desc = short_desc FILTER html %]
</span><span class="cx">   [% title = &quot;$title for $terms.bug $bug_id&quot;
</span><span class="cx">      header = &quot;$header for $terms.bug &lt;a href=\&quot;show_bug.cgi?id=$bug_id\&quot;&gt;$bug_id&lt;/a&gt;&quot;
</span><span class="lines">@@ -82,8 +81,6 @@
</span><span class="cx">             Restrict to [% terms.bugs %] having a direct relationship with entered [% terms.bugs %]&lt;/option&gt;
</span><span class="cx">           &lt;option value=&quot;web&quot; [% 'selected=&quot;selected&quot;' IF display == &quot;web&quot; %]&gt;
</span><span class="cx">             Show all [% terms.bugs %] having any relationship with entered [% terms.bugs %]&lt;/option&gt;
</span><del>-          &lt;option value=&quot;doall&quot; [% 'selected=&quot;selected&quot;' IF display == &quot;doall&quot; %]&gt;
-            Show every [% terms.bug %] in the system with dependencies&lt;/option&gt;
</del><span class="cx">         &lt;/select&gt;
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultbugdependencytreehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/bug/dependency-tree.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/bug/dependency-tree.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/bug/dependency-tree.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -64,14 +64,14 @@
</span><span class="cx">         [% IF ids.size %]
</span><span class="cx">             depends on 
</span><span class="cx">         [% ELSE %]
</span><del>-            does not depend on any [% terms.bugs %].
</del><ins>+            does not depend on any [% 'open ' IF hide_resolved %][% terms.bugs %].
</ins><span class="cx">         [% END %]
</span><span class="cx">     [% ELSIF type == 2 %]
</span><span class="cx">         [% tree_name = &quot;blocked_tree&quot; %]
</span><span class="cx">         [% IF ids.size %] 
</span><span class="cx">             blocks 
</span><span class="cx">         [% ELSE %]
</span><del>-            does not block any [% terms.bugs %].
</del><ins>+            does not block any [% 'open ' IF hide_resolved %][% terms.bugs %].
</ins><span class="cx">         [% END %]
</span><span class="cx">     [% END %]
</span><span class="cx">     [% IF ids.size %]
</span><span class="lines">@@ -83,7 +83,7 @@
</span><span class="cx">   [% IF ids.size %]
</span><span class="cx">     ([% IF maxdepth -%]Up to [% maxdepth %] level[% &quot;s&quot; IF maxdepth &gt; 1 %] deep | [% END -%]
</span><span class="cx">     &lt;a href=&quot;buglist.cgi?bug_id=[% ids.join(&quot;,&quot;) %]&quot;&gt;view as [% terms.bug %] list&lt;/a&gt;
</span><del>-    [% IF user.groups.editbugs &amp;&amp; ids.size &gt; 1 %]
</del><ins>+    [% IF user.in_group('editbugs') &amp;&amp; ids.size &gt; 1 %]
</ins><span class="cx">       | &lt;a href=&quot;buglist.cgi?bug_id=[% ids.join(&quot;,&quot;) %]&amp;amp;tweak=1&quot;&gt;change several&lt;/a&gt;
</span><span class="cx">     [% END %])
</span><span class="cx">     &lt;ul class=&quot;tree&quot;&gt;
</span><span class="lines">@@ -129,7 +129,7 @@
</span><span class="cx">     [% extra_class = &quot; b_open&quot; %]
</span><span class="cx">     [% extra_args = 'onclick=&quot;return doToggle(this, event)&quot;' %] 
</span><span class="cx">   [% END %]
</span><del>-  &lt;a name=&quot;b[% bugid %]&quot; 
</del><ins>+  &lt;a id=&quot;b[% bugid %]&quot; 
</ins><span class="cx">      class=&quot;b [%+ extra_class FILTER none %]&quot;
</span><span class="cx">      title=&quot;Click to expand or contract this portion of the tree. Hold down the Ctrl key while clicking to expand or contract all subtrees.&quot;
</span><span class="cx">      [% extra_args FILTER none %]&gt;&amp;nbsp;&amp;nbsp;&lt;/a&gt;
</span><span class="lines">@@ -144,7 +144,7 @@
</span><span class="cx">       &lt;span class=&quot;summ_text&quot;&gt;[%+ bug.short_desc FILTER html %]&lt;/span&gt;
</span><span class="cx">       &lt;span class=&quot;summ_info&quot;&gt;[[% INCLUDE buginfo %]]&lt;/span&gt;
</span><span class="cx">     &lt;/a&gt;
</span><del>-    &lt;a href=&quot;showdependencytree.cgi?id=[% bugid FILTER url_quote %]&quot;
</del><ins>+    &lt;a href=&quot;showdependencytree.cgi?id=[% bugid FILTER uri %]&quot;
</ins><span class="cx">        class=&quot;tree_link&quot;&gt;
</span><span class="cx">       &lt;img src=&quot;skins/standard/dependency-tree/tree.png&quot;
</span><span class="cx">            title=&quot;See dependency tree for [% terms.bug %] [%+ bugid FILTER html %]&quot;&gt;
</span><span class="lines">@@ -153,8 +153,8 @@
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK buginfo %]
</span><del>-  [% get_status(bug.bug_status) FILTER html -%] [%+ get_resolution(bug.resolution) FILTER html %];
-  [%-%] assigned to [% bug.assigned_to.login FILTER html %]
</del><ins>+  [% display_value(&quot;bug_status&quot;, bug.bug_status) FILTER html -%] [%+ display_value(&quot;resolution&quot;, bug.resolution) FILTER html %];
+  [%-%] assigned to [% bug.assigned_to.login FILTER email FILTER html %]
</ins><span class="cx">   [%-%][% &quot;; Target: &quot; _ bug.target_milestone IF bug.target_milestone %]
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultbugedithtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/bug/edit.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/bug/edit.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/bug/edit.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -40,7 +40,7 @@
</span><span class="cx">        */
</span><span class="cx">       [% IF user.settings.quote_replies.value != 'off' %]
</span><span class="cx">         document.write('[&lt;a href=&quot;#add_comment&quot; onclick=&quot;replyToComment(' + 
</span><del>-                       id + ',' + real_id + ');&quot;&gt;reply&lt;' + '/a&gt;]');
</del><ins>+                       id + ',' + real_id + '); return false;&quot;&gt;reply&lt;' + '/a&gt;]');
</ins><span class="cx">       [% END %]
</span><span class="cx">   }
</span><span class="cx"> 
</span><span class="lines">@@ -52,24 +52,15 @@
</span><span class="cx">         /* pre id=&quot;comment_name_N&quot; */
</span><span class="cx">         var text_elem = document.getElementById('comment_text_'+id);
</span><span class="cx">         var text = getText(text_elem);
</span><del>-
-        /* make sure we split on all newlines -- IE or Moz use \r and \n
-         * respectively.
-         */
-        text = text.split(/\r|\n/);
-
-        for (var i=0; i &lt; text.length; i++) {
-            replytext += &quot;&gt; &quot; + text[i] + &quot;\n&quot;; 
-        }
-
-        replytext = prefix + replytext + &quot;\n&quot;;
</del><ins>+        replytext = prefix + wrapReplyText(text);
</ins><span class="cx">       [% ELSIF user.settings.quote_replies.value == 'simple_reply' %]
</span><span class="cx">         replytext = prefix;
</span><span class="cx">       [% END %]
</span><span class="cx"> 
</span><del>-    [% IF Param(&quot;insidergroup&quot;) &amp;&amp; user.in_group(Param(&quot;insidergroup&quot;)) %]
</del><ins>+    [% IF user.is_insider %]
</ins><span class="cx">       if (document.getElementById('isprivate_' + real_id).checked) {
</span><span class="cx">           document.getElementById('newcommentprivacy').checked = 'checked';
</span><ins>+          updateCommentTagControl(document.getElementById('newcommentprivacy'), 'comment'); 
</ins><span class="cx">       }
</span><span class="cx">     [% END %]
</span><span class="cx"> 
</span><span class="lines">@@ -107,7 +98,7 @@
</span><span class="cx">       return text;
</span><span class="cx">   }
</span><span class="cx"> 
</span><del>-[% IF user.in_group(Param('timetrackinggroup')) %]
</del><ins>+[% IF user.is_timetracker %]
</ins><span class="cx">   var fRemainingTime = [% bug.remaining_time %]; // holds the original value
</span><span class="cx">   function adjustRemainingTime() {
</span><span class="cx">       // subtracts time spent from remaining time
</span><span class="lines">@@ -128,26 +119,27 @@
</span><span class="cx"> 
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><del>-  function updateCommentTagControl(checkbox, form) {
-      if (checkbox.checked) {
-          form.comment.className='bz_private';
-      } else {
-          form.comment.className='';
-      }
-  }
</del><ins>+  /* Index all classifications so we can keep track of the classification
+   * for the selected product, which could control field visibility.
+   */
+  var all_classifications = new Array([% bug.choices.product.size %]);
+  [%- FOREACH product = bug.choices.product %]
+      all_classifications['[% product.name FILTER js %]'] = '
+          [%- product.classification.name FILTER js %]';
+  [%- END %]
</ins><span class="cx"> 
</span><span class="cx">   //--&gt;
</span><span class="cx">   &lt;/script&gt;
</span><span class="cx"> 
</span><del>-&lt;form name=&quot;changeform&quot; method=&quot;post&quot; action=&quot;process_bug.cgi&quot;&gt;
</del><ins>+&lt;form name=&quot;changeform&quot; id=&quot;changeform&quot; method=&quot;post&quot; action=&quot;process_bug.cgi&quot;&gt;
</ins><span class="cx"> 
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;delta_ts&quot; value=&quot;[% bug.delta_ts %]&quot;&gt;
</span><del>-  &lt;input type=&quot;hidden&quot; name=&quot;longdesclength&quot; value=&quot;[% bug.longdescs.size %]&quot;&gt;
</del><ins>+  &lt;input type=&quot;hidden&quot; name=&quot;longdesclength&quot; value=&quot;[% bug.comments.size %]&quot;&gt;
</ins><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;id&quot; value=&quot;[% bug.bug_id %]&quot;&gt;
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% issue_hash_token([bug.id, bug.delta_ts]) FILTER html %]&quot;&gt;
</span><span class="cx"> 
</span><span class="cx">   [% PROCESS section_title %]
</span><del>-  &lt;table&gt;
</del><ins>+  &lt;table class=&quot;edit_form&quot;&gt;
</ins><span class="cx">     &lt;tr&gt;
</span><span class="cx">       [%# 1st Column %]
</span><span class="cx">       &lt;td id=&quot;bz_show_bug_column_1&quot; class=&quot;bz_show_bug_column&quot;&gt;     
</span><span class="lines">@@ -189,7 +181,9 @@
</span><span class="cx">          
</span><span class="cx">          [% PROCESS section_cclist %]
</span><span class="cx">          
</span><del>-         [% PROCESS section_spacer %] 
</del><ins>+         [% PROCESS section_spacer %]
+
+         [% PROCESS section_see_also %] 
</ins><span class="cx">          
</span><span class="cx">          [% PROCESS section_customfields %]
</span><span class="cx">          
</span><span class="lines">@@ -209,90 +203,43 @@
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">   &lt;/table&gt;
</span><span class="cx"> 
</span><del>-  
-  [% PROCESS section_restrict_visibility %]
-  [% IF user.in_group(Param('timetrackinggroup')) %]
-    &lt;br&gt;
-    [% PROCESS section_timetracking %]
-  [% END %]
-  
</del><ins>+  &lt;table id=&quot;bz_big_form_parts&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;&lt;tr&gt;
+  &lt;td&gt;
+    [% IF user.is_timetracker %]
+      [% PROCESS section_timetracking %]
+    [% END %]
</ins><span class="cx"> 
</span><del>-[%# *** Attachments *** %]
</del><ins>+    [%# *** Attachments *** %]
</ins><span class="cx"> 
</span><del>-  [% PROCESS attachment/list.html.tmpl
-             attachments = bug.attachments
-             bugid       = bug.bug_id
-             num_attachment_flag_types = bug.num_attachment_flag_types
-             show_attachment_flags = bug.show_attachment_flags
-   %]
</del><ins>+    [% PROCESS attachment/list.html.tmpl
+               attachments = bug.attachments
+               bugid       = bug.bug_id
+               num_attachment_flag_types = bug.num_attachment_flag_types
+               show_attachment_flags = bug.show_attachment_flags
+    %]
</ins><span class="cx"> 
</span><ins>+    [% IF user.settings.comment_box_position.value == 'before_comments' %]
+      [% PROCESS comment_box %]
+    [% END %]
+  &lt;/td&gt;
+  &lt;td&gt;
+    [% PROCESS section_restrict_visibility %]
+  &lt;/td&gt;
+  &lt;/tr&gt;&lt;/table&gt;
</ins><span class="cx"> 
</span><del>-[%# *** Comments Groups *** %]
</del><ins>+  [%# *** Additional Comments *** %]
+  &lt;div id=&quot;comments&quot;&gt;
+    [% PROCESS bug/comments.html.tmpl
+      comments = bug.comments
+      mode = user.id ? &quot;edit&quot; : &quot;show&quot;
+    %]
+  &lt;/div&gt;
</ins><span class="cx"> 
</span><del>-  &lt;br&gt;
-  &lt;table cellpadding=&quot;1&quot; cellspacing=&quot;1&quot;&gt;
-    &lt;tr&gt;
-      &lt;td id=&quot;comment_status_commit&quot;&gt;
-        &lt;!-- The table keeps the commit button aligned with the box. --&gt;
-        &lt;a name=&quot;add_comment&quot;&gt;&lt;/a&gt;
-        [% IF user.id %]
-        &lt;table&gt;&lt;tr&gt;&lt;td&gt;
-          &lt;label for=&quot;comment&quot; accesskey=&quot;c&quot;&gt;&lt;b&gt;Additional &lt;u&gt;C&lt;/u&gt;omments&lt;/b&gt;&lt;/label&gt;:
-          [% IF Param(&quot;insidergroup&quot;) &amp;&amp; user.in_group(Param(&quot;insidergroup&quot;)) %]
-            &lt;input type=&quot;checkbox&quot; name=&quot;commentprivacy&quot; value=&quot;1&quot;
-                   id=&quot;newcommentprivacy&quot;
-                   onClick=&quot;updateCommentTagControl(this, form)&quot;&gt;
-            &lt;label for=&quot;newcommentprivacy&quot;&gt;Private&lt;/label&gt;
-          [% END %]
-          &lt;br&gt;
-          [% INCLUDE global/textarea.html.tmpl
-                     name      = 'comment'
-                     id        = 'comment'
-                     minrows   = 10
-                     maxrows   = 25
-                     cols      = constants.COMMENT_COLS
-          %]
-          &lt;br&gt;
-          &lt;div id=&quot;knob-buttons&quot;&gt;
-            &lt;input type=&quot;submit&quot; value=&quot;Commit&quot; id=&quot;commit&quot;&gt;
-            [% IF bug.user.canmove %]
-              &lt;input type=&quot;submit&quot; name=&quot;action&quot; id=&quot;action&quot; value=&quot;[% Param(&quot;move-button-text&quot;) %]&quot;&gt;
-            [% END %]
-          &lt;/div&gt;
-          &lt;table class=&quot;status&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
-            &lt;tr&gt;
-              &lt;td class=&quot;field_label&quot;&gt;
-                &lt;b&gt;&lt;a href=&quot;page.cgi?id=fields.html#status&quot;&gt;Status&lt;/a&gt;&lt;/b&gt;:
-              &lt;/td&gt;
-              &lt;td&gt;
-                &lt;a name=&quot;bug_status_bottom&quot;&gt;&lt;/a&gt;
-                [% PROCESS bug/knob.html.tmpl %]
-              &lt;/td&gt;
-            &lt;/tr&gt;
-          &lt;/table&gt;
-        &lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
-        [% ELSE %]
-          &lt;fieldset&gt;
-            &lt;legend&gt;Note&lt;/legend&gt;
-            &lt;p&gt;
-              You need to
-              &lt;a href=&quot;[% IF Param('ssl') != 'never' %][% Param('sslbase') %][% END %]show_bug.cgi?id=[% bug.bug_id %]&amp;amp;GoAheadAndLogIn=1&quot;&gt;log in&lt;/a&gt;
-              before you can comment on or make changes to this [% terms.bug %].
-            &lt;/p&gt;
-          &lt;/fieldset&gt;
-        [% END %]
-        [%# *** Additional Comments *** %]
-        &lt;hr&gt;
-        &lt;div id=&quot;comments&quot;&gt;
-        [% PROCESS bug/comments.html.tmpl
-           comments = bug.longdescs
-           mode = user.id ? &quot;edit&quot; : &quot;show&quot;
-         %]
-        &lt;/div&gt;
-        
-      &lt;/td&gt;
-    &lt;/tr&gt;
-  &lt;/table&gt;
</del><ins>+  [% IF user.settings.comment_box_position.value == 'after_comments' %]
+    &lt;hr&gt;
+    [% PROCESS comment_box %]
+  [% END %]        
+
</ins><span class="cx"> &lt;/form&gt;
</span><span class="cx"> 
</span><span class="cx"> [%############################################################################%]
</span><span class="lines">@@ -301,17 +248,17 @@
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK section_title %]
</span><span class="cx">   [%# That's the main table, which contains all editable fields. %]
</span><del>-  &lt;div class=&quot;bz_alias_short_desc_container&quot;&gt;
-    
</del><ins>+  &lt;div class=&quot;bz_alias_short_desc_container edit_form&quot;&gt;
+      [% PROCESS commit_button id=&quot;_top&quot;%]
</ins><span class="cx">      &lt;a href=&quot;show_bug.cgi?id=[% bug.bug_id %]&quot;&gt;
</span><del>-        &lt;b&gt;[% terms.Bug %]&amp;nbsp;[% bug.bug_id FILTER html %]&lt;/b&gt;&lt;/a&gt; - 
-     &lt;span id=&quot;summary_alias_container&quot; class=&quot;bz_default_hidden&quot;&gt; 
</del><ins>+        [%-# %]&lt;b&gt;[% terms.Bug %]&amp;nbsp;[% bug.bug_id FILTER html %]&lt;/b&gt;
+     [%-# %]&lt;/a&gt; -&lt;span id=&quot;summary_alias_container&quot; class=&quot;bz_default_hidden&quot;&gt; 
</ins><span class="cx">       [% IF Param(&quot;usebugaliases&quot;) %]
</span><span class="cx">         [% IF bug.alias != &quot;&quot; %]
</span><span class="cx">           (&lt;span id=&quot;alias_nonedit_display&quot;&gt;[% bug.alias FILTER html %]&lt;/span&gt;) 
</span><span class="cx">         [% END %]
</span><span class="cx">       [% END %]
</span><del>-      &lt;span id=&quot;short_desc_nonedit_display&quot;&gt;[% bug.short_desc FILTER html %]&lt;/span&gt;
</del><ins>+      &lt;span id=&quot;short_desc_nonedit_display&quot;&gt;[% bug.short_desc FILTER quoteUrls(bug) %]&lt;/span&gt;
</ins><span class="cx">       [% IF bug.check_can_change_field('short_desc', 0, 1) || 
</span><span class="cx">             bug.check_can_change_field('alias', 0, 1)  %]
</span><span class="cx">         &lt;small class=&quot;editme&quot;&gt;(&lt;a href=&quot;#&quot; id=&quot;editme_action&quot;&gt;edit&lt;/a&gt;)&lt;/small&gt;
</span><span class="lines">@@ -373,23 +320,35 @@
</span><span class="cx">     [%#  PRODUCT  #%]
</span><span class="cx">     [%#############%]
</span><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;td class=&quot;field_label&quot;&gt;
-        &lt;label for=&quot;product&quot; accesskey=&quot;p&quot;&gt;&lt;b&gt;&lt;u&gt;P&lt;/u&gt;roduct&lt;/b&gt;&lt;/label&gt;:
-      &lt;/td&gt;
-      [% PROCESS select selname =&gt; &quot;product&quot; %]
</del><ins>+       [% INCLUDE bug/field.html.tmpl
+            bug = bug, field = bug_fields.product,
+            override_legal_values = bug.choices.product
+            desc_url = 'describecomponents.cgi', value = bug.product
+            editable = bug.check_can_change_field('product', 0, 1) %]
</ins><span class="cx">     &lt;/tr&gt;
</span><ins>+
+    [%# Classification is here so that it can be used in value controllers
+      # and visibility controllers. It comes after product because
+      # it uses some javascript that depends on the existence of the
+      # product field.
+      #%]
+    &lt;tr class=&quot;bz_default_hidden&quot;&gt;
+       [% INCLUDE bug/field.html.tmpl
+            bug = bug field = bug_fields.classification
+            override_legal_values = bug.choices.classification
+            value = bug.classification
+            editable = bug.check_can_change_field('product', 0, 1) %]
+    &lt;/tr&gt;
</ins><span class="cx">     [%###############%]    
</span><span class="cx">     [%#  Component  #%]
</span><span class="cx">     [%###############%]
</span><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;td class=&quot;field_label&quot;&gt;
-        &lt;label for=&quot;component&quot; accesskey=&quot;m&quot;&gt;
-          &lt;b&gt;&lt;a href=&quot;describecomponents.cgi?product=[% bug.product FILTER url_quote %]&quot;&gt;
-            Co&lt;u&gt;m&lt;/u&gt;ponent&lt;/a&gt;:
-          &lt;/b&gt;
-        &lt;/label&gt;
-      &lt;/td&gt;
-      [% PROCESS select selname =&gt; &quot;component&quot; %]
</del><ins>+      [% INCLUDE bug/field.html.tmpl
+          bug = bug, field = bug_fields.component, value = bug.component
+          override_legal_values = bug.choices.component
+          desc_url = &quot;describecomponents.cgi?product=$bug.product&quot;
+          editable = bug.check_can_change_field('component', 0, 1)
+      %]
</ins><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;td class=&quot;field_label&quot;&gt;
</span><span class="lines">@@ -405,9 +364,15 @@
</span><span class="cx">       &lt;td class=&quot;field_label&quot;&gt;
</span><span class="cx">         &lt;label for=&quot;rep_platform&quot; accesskey=&quot;h&quot;&gt;&lt;b&gt;Platform&lt;/b&gt;&lt;/label&gt;:
</span><span class="cx">       &lt;/td&gt;
</span><del>-      &lt;td&gt;
-       [% PROCESS select selname =&gt; &quot;rep_platform&quot; no_td=&gt; 1 %]
-       [%+ PROCESS select selname =&gt; &quot;op_sys&quot; no_td=&gt; 1 %]
</del><ins>+      &lt;td class=&quot;field_value&quot;&gt;
+       [% INCLUDE bug/field.html.tmpl
+            bug = bug, field = bug_fields.rep_platform,
+            no_tds = 1, value = bug.rep_platform
+            editable = bug.check_can_change_field('rep_platform', 0, 1) %]
+       [%+ INCLUDE bug/field.html.tmpl 
+            bug = bug, field = bug_fields.op_sys, 
+            no_tds = 1, value = bug.op_sys
+            editable = bug.check_can_change_field('op_sys', 0, 1) %]
</ins><span class="cx">        &lt;script type=&quot;text/javascript&quot;&gt;
</span><span class="cx">          assignToDefaultOnChange(['product', 'component']);
</span><span class="cx">        &lt;/script&gt;
</span><span class="lines">@@ -429,9 +394,9 @@
</span><span class="cx">     &lt;/td&gt;
</span><span class="cx">     &lt;td id=&quot;bz_field_status&quot;&gt;
</span><span class="cx">       &lt;span id=&quot;static_bug_status&quot;&gt;
</span><del>-        [% get_status(bug.bug_status) FILTER html %]
</del><ins>+        [% display_value(&quot;bug_status&quot;, bug.bug_status) FILTER html %]
</ins><span class="cx">         [% IF bug.resolution %]
</span><del>-          [%+ get_resolution(bug.resolution) FILTER html %]
</del><ins>+          [%+ display_value(&quot;resolution&quot;, bug.resolution) FILTER html %]
</ins><span class="cx">           [% IF bug.dup_id %]
</span><span class="cx">             of [% &quot;${terms.bug} ${bug.dup_id}&quot; FILTER bug_link(bug.dup_id) FILTER none %]
</span><span class="cx">           [% END %]
</span><span class="lines">@@ -452,7 +417,7 @@
</span><span class="cx"> [% BLOCK section_details2 %]
</span><span class="cx"> 
</span><span class="cx">  [%###############################################################%]
</span><del>- [%# Importance (priority, severity and votes) #%]
</del><ins>+ [%# Importance (priority and severity) #%]
</ins><span class="cx">  [%###############################################################%]
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;td class=&quot;field_label&quot;&gt;
</span><span class="lines">@@ -460,36 +425,24 @@
</span><span class="cx">           &lt;b&gt;&lt;a href=&quot;page.cgi?id=fields.html#importance&quot;&gt;&lt;u&gt;I&lt;/u&gt;mportance&lt;/a&gt;&lt;/b&gt;&lt;/label&gt;:
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">       &lt;td&gt;
</span><del>-        [% PROCESS select selname =&gt; &quot;priority&quot; no_td=&gt;1 %] 
-        [% PROCESS select selname = &quot;bug_severity&quot; no_td=&gt;1 %]
-        [% IF bug.use_votes %]
-          &lt;span id=&quot;votes_container&quot;&gt;
-          [% IF bug.votes %] 
-            with 
-            &lt;a href=&quot;votes.cgi?action=show_bug&amp;amp;bug_id=[% bug.bug_id %]&quot;&gt;
-              [% bug.votes %] 
-              [% IF bug.votes == 1 %]
-                vote
-              [% ELSE %]
-                votes
-              [% END %]&lt;/a&gt; 
-          [% END %]    
-          (&lt;a href=&quot;votes.cgi?action=show_user&amp;amp;bug_id=
-                  [% bug.bug_id %]#vote_[% bug.bug_id %]&quot;&gt;vote&lt;/a&gt;)
-          &lt;/span&gt;  
-        [% END %]
</del><ins>+       [% INCLUDE bug/field.html.tmpl
+            bug = bug, field = bug_fields.priority,
+            no_tds = 1, value = bug.priority
+            editable = bug.check_can_change_field('priority', 0, 1) %]
+       [%+ INCLUDE bug/field.html.tmpl
+            bug = bug, field = bug_fields.bug_severity,
+            no_tds = 1, value = bug.bug_severity
+            editable = bug.check_can_change_field('bug_severity', 0, 1) %]
+        [% Hook.process('after_importance', 'bug/edit.html.tmpl') %]
</ins><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx"> 
</span><span class="cx">     [% IF Param(&quot;usetargetmilestone&quot;) &amp;&amp; bug.target_milestone %]
</span><span class="cx">       &lt;tr&gt;
</span><span class="cx">         &lt;td class=&quot;field_label&quot;&gt;
</span><del>-          &lt;label for=&quot;target_milestone&quot;&gt;&lt;b&gt;
-            [% IF bug.milestoneurl %]
-              &lt;a href=&quot;[% bug.milestoneurl FILTER html %]&quot;&gt;
-            [% END %]
-            Target&amp;nbsp;Milestone[% &quot;&lt;/a&gt;&quot; IF bug.milestoneurl %]
-          [%%]&lt;/b&gt;&lt;/label&gt;:
</del><ins>+          &lt;label for=&quot;target_milestone&quot;&gt;
+              &lt;a href=&quot;page.cgi?id=fields.html#target_milestone&quot;&gt;
+            Target&amp;nbsp;Milestone&lt;/a&gt;&lt;/label&gt;:
</ins><span class="cx">         &lt;/td&gt;
</span><span class="cx">         [% PROCESS select selname = &quot;target_milestone&quot; %]
</span><span class="cx">       &lt;/tr&gt;
</span><span class="lines">@@ -511,8 +464,12 @@
</span><span class="cx">         [% IF bug.check_can_change_field(&quot;assigned_to&quot;, 0, 1) %]
</span><span class="cx">           &lt;div id=&quot;bz_assignee_edit_container&quot; class=&quot;bz_default_hidden&quot;&gt;
</span><span class="cx">             &lt;span&gt;
</span><del>-              [% INCLUDE user_identity user=&gt; bug.assigned_to %]
</del><ins>+              [% INCLUDE global/user.html.tmpl who = bug.assigned_to %]
</ins><span class="cx">               (&lt;a href=&quot;#&quot; id=&quot;bz_assignee_edit_action&quot;&gt;edit&lt;/a&gt;)
</span><ins>+              [% IF bug.assigned_to.id != user.id %]
+                (&lt;a title=&quot;Reassign to yourself&quot; 
+                    href=&quot;#&quot; id=&quot;bz_assignee_take_action&quot;&gt;take&lt;/a&gt;)
+              [% END %]
</ins><span class="cx">             &lt;/span&gt;
</span><span class="cx">           &lt;/div&gt;
</span><span class="cx">           &lt;div id=&quot;bz_assignee_input&quot;&gt;
</span><span class="lines">@@ -520,6 +477,7 @@
</span><span class="cx">                  id =&gt; &quot;assigned_to&quot;
</span><span class="cx">                  name =&gt; &quot;assigned_to&quot;
</span><span class="cx">                  value =&gt; bug.assigned_to.login
</span><ins>+                 classes =&gt; [&quot;bz_userfield&quot;]
</ins><span class="cx">                  size =&gt; 30
</span><span class="cx">             %]
</span><span class="cx">             &lt;br&gt;
</span><span class="lines">@@ -532,10 +490,16 @@
</span><span class="cx">                              'bz_assignee_edit_action', 
</span><span class="cx">                              'assigned_to', 
</span><span class="cx">                              '[% bug.assigned_to.login FILTER js %]' );
</span><ins>+           hideEditableField('bz_assignee_edit_container',
+                             'bz_assignee_input',
+                             'bz_assignee_take_action',
+                             'assigned_to',
+                             '[% bug.assigned_to.login FILTER js %]',
+                             '[% user.login FILTER js %]' );
</ins><span class="cx">            initDefaultCheckbox('assignee');                  
</span><span class="cx">           &lt;/script&gt;
</span><span class="cx">         [% ELSE %]
</span><del>-          [% INCLUDE user_identity user =&gt; bug.assigned_to %]
</del><ins>+          [% INCLUDE global/user.html.tmpl who = bug.assigned_to %]
</ins><span class="cx">         [% END %]
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="lines">@@ -546,13 +510,12 @@
</span><span class="cx">         &lt;label for=&quot;qa_contact&quot; accesskey=&quot;q&quot;&gt;&lt;b&gt;&lt;u&gt;Q&lt;/u&gt;A Contact&lt;/b&gt;&lt;/label&gt;:
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">       &lt;td&gt;
</span><del>-
</del><span class="cx">         [% IF bug.check_can_change_field(&quot;qa_contact&quot;, 0, 1) %]
</span><span class="cx">           [% IF bug.qa_contact != &quot;&quot; %]
</span><span class="cx">            &lt;div id=&quot;bz_qa_contact_edit_container&quot; class=&quot;bz_default_hidden&quot;&gt;
</span><span class="cx">             &lt;span&gt;
</span><span class="cx">               &lt;span id=&quot;bz_qa_contact_edit_display&quot;&gt;
</span><del>-              [% INCLUDE user_identity user=&gt; bug.qa_contact %]&lt;/span&gt;
</del><ins>+              [% INCLUDE global/user.html.tmpl who = bug.qa_contact %]&lt;/span&gt;
</ins><span class="cx">               (&lt;a href=&quot;#&quot; id=&quot;bz_qa_contact_edit_action&quot;&gt;edit&lt;/a&gt;)
</span><span class="cx">             &lt;/span&gt;
</span><span class="cx">           &lt;/div&gt;
</span><span class="lines">@@ -563,6 +526,7 @@
</span><span class="cx">                 name =&gt; &quot;qa_contact&quot;
</span><span class="cx">                 value =&gt; bug.qa_contact.login
</span><span class="cx">                 size =&gt; 30
</span><ins>+                classes =&gt; [&quot;bz_userfield&quot;]
</ins><span class="cx">                 emptyok =&gt; 1
</span><span class="cx">             %]
</span><span class="cx">             &lt;br&gt;
</span><span class="lines">@@ -580,7 +544,7 @@
</span><span class="cx">             initDefaultCheckbox('qa_contact');
</span><span class="cx">           &lt;/script&gt;
</span><span class="cx">         [% ELSE %]
</span><del>-          [% INCLUDE user_identity user =&gt; bug.qa_contact %]
</del><ins>+          [% INCLUDE global/user.html.tmpl who = bug.qa_contact %]
</ins><span class="cx">         [% END %]
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="lines">@@ -591,23 +555,16 @@
</span><span class="cx"> [%# Block for URL Keyword and Whiteboard                                     #%]
</span><span class="cx"> [%############################################################################%]
</span><span class="cx"> [% BLOCK section_url_keyword_whiteboard %]
</span><del>-[%# *** URL Whiteboard Keywords *** %]
</del><span class="cx">   &lt;tr&gt;
</span><del>-    &lt;td class=&quot;field_label&quot;&gt;
-      &lt;label for=&quot;bug_file_loc&quot; accesskey=&quot;u&quot;&gt;&lt;b&gt;
-        [% IF bug.bug_file_loc 
-           AND NOT bug.bug_file_loc.match(&quot;^(javascript|data)&quot;) %]
-          &lt;a href=&quot;[% bug.bug_file_loc FILTER html %]&quot;&gt;&lt;u&gt;U&lt;/u&gt;RL&lt;/a&gt;
-        [% ELSE %]
-          &lt;u&gt;U&lt;/u&gt;RL
-        [% END %]
-      [%%]&lt;/b&gt;&lt;/label&gt;:
-    &lt;/td&gt;
</del><ins>+    [% INCLUDE &quot;bug/field-label.html.tmpl&quot;
+      field = bug_fields.bug_file_loc
+      editable = 1
+      accesskey = &quot;u&quot;
+    %]
</ins><span class="cx">     &lt;td&gt;
</span><span class="cx">       [% IF bug.check_can_change_field(&quot;bug_file_loc&quot;, 0, 1) %]
</span><span class="cx">         &lt;span id=&quot;bz_url_edit_container&quot; class=&quot;bz_default_hidden&quot;&gt; 
</span><del>-        [% IF bug.bug_file_loc 
-           AND NOT bug.bug_file_loc.match(&quot;^(javascript|data)&quot;) %]
</del><ins>+        [% IF is_safe_url(bug.bug_file_loc) %]
</ins><span class="cx">            &lt;a href=&quot;[% bug.bug_file_loc FILTER html %]&quot; target=&quot;_blank&quot;
</span><span class="cx">               title=&quot;[% bug.bug_file_loc FILTER html %]&quot;&gt;
</span><span class="cx">              [% bug.bug_file_loc FILTER truncate(40) FILTER html %]&lt;/a&gt;
</span><span class="lines">@@ -618,7 +575,8 @@
</span><span class="cx">       [% END %]
</span><span class="cx">       &lt;span id=&quot;bz_url_input_area&quot;&gt;
</span><span class="cx">         [% url_output =  PROCESS input no_td=1 inputname =&gt; &quot;bug_file_loc&quot; size =&gt; &quot;40&quot; colspan =&gt; 2 %]
</span><del>-        [% IF NOT bug.check_can_change_field(&quot;bug_file_loc&quot;, 0, 1)  %]
</del><ins>+        [% IF NOT bug.check_can_change_field(&quot;bug_file_loc&quot;, 0, 1)
+              AND is_safe_url(bug.bug_file_loc) %]
</ins><span class="cx">           &lt;a href=&quot;[% bug.bug_file_loc FILTER html %]&quot;&gt;[% url_output FILTER none %]&lt;/a&gt;
</span><span class="cx">         [% ELSE %]
</span><span class="cx">           [% url_output FILTER none %]
</span><span class="lines">@@ -651,8 +609,13 @@
</span><span class="cx">         &lt;label for=&quot;keywords&quot; accesskey=&quot;k&quot;&gt;
</span><span class="cx">           &lt;b&gt;&lt;a href=&quot;describekeywords.cgi&quot;&gt;&lt;u&gt;K&lt;/u&gt;eywords&lt;/a&gt;&lt;/b&gt;&lt;/label&gt;:
</span><span class="cx">       &lt;/td&gt;
</span><del>-      [% PROCESS input inputname =&gt; &quot;keywords&quot; size =&gt; 40 colspan =&gt; 2
-                       value =&gt; bug.keywords.join(', ') %]
</del><ins>+      &lt;td class=&quot;field_value&quot; colspan=&quot;2&quot;&gt;
+        [% INCLUDE bug/field.html.tmpl
+           bug = bug, field = bug_fields.keywords, value = bug.keywords
+           editable = bug.check_can_change_field(&quot;keywords&quot;, 0, 1),
+           no_tds = 1
+        %]
+      &lt;/td&gt;
</ins><span class="cx">     &lt;/tr&gt;
</span><span class="cx">   [% END %]
</span><span class="cx"> [% END %]
</span><span class="lines">@@ -662,13 +625,13 @@
</span><span class="cx"> [%############################################################################%]
</span><span class="cx"> [% BLOCK section_dependson_blocks %]
</span><span class="cx">   &lt;tr&gt;
</span><del>-    [% PROCESS dependencies
-               dep = { title =&gt; &quot;Depends&amp;nbsp;on&quot;, fieldname =&gt; &quot;dependson&quot; } %]
</del><ins>+    [% INCLUDE dependencies 
+         field = bug_fields.dependson deps = bug.depends_on_obj %]
</ins><span class="cx">   &lt;/tr&gt;
</span><span class="cx">   
</span><span class="cx">   &lt;tr&gt;
</span><del>-    [% PROCESS dependencies accesskey = &quot;b&quot;
-               dep = { title =&gt; &quot;&lt;u&gt;B&lt;/u&gt;locks&quot;, fieldname =&gt; &quot;blocked&quot; } %]
</del><ins>+    [% INCLUDE dependencies 
+         field = bug_fields.blocked deps = bug.blocks_obj %]
</ins><span class="cx">   
</span><span class="cx">   &lt;tr&gt;
</span><span class="cx">     &lt;th&gt;&amp;nbsp;&lt;/th&gt;
</span><span class="lines">@@ -691,103 +654,93 @@
</span><span class="cx"> [% BLOCK section_restrict_visibility %]
</span><span class="cx">   [% RETURN UNLESS bug.groups.size %]
</span><span class="cx"> 
</span><del>-  [% inallgroups = 1 %]
-  [% inagroup = 0 %]
-  [% emitted_description = 0 %]
</del><ins>+  &lt;div class=&quot;bz_group_visibility_section&quot;&gt;
+    [% inallgroups = 1 %]
+    [% inagroup = 0 %]
+    [% emitted_description = 0 %]
</ins><span class="cx"> 
</span><del>-  [% FOREACH group = bug.groups %]
-    [% SET inallgroups = 0 IF NOT group.ingroup %]
-    [% SET inagroup = 1 IF group.ison %]
</del><ins>+    [% FOREACH group = bug.groups %]
+      [% SET inallgroups = 0 IF NOT group.ingroup %]
+      [% SET inagroup = 1 IF group.ison %]
</ins><span class="cx"> 
</span><del>-    [% NEXT IF group.mandatory %]
</del><ins>+      [% NEXT IF group.mandatory %]
</ins><span class="cx"> 
</span><del>-    [% IF NOT emitted_description %]
-      [% emitted_description = 1 %]
-      &lt;table&gt;
-        &lt;tr&gt;
-          &lt;td class=&quot;field_label&quot;&gt;
-            &lt;label id=&quot;bz_restrict_group_visibility_label&quot;&gt;&lt;b&gt;Restrict Group Visibility&lt;/b&gt;:&lt;/label&gt;
-          &lt;/td&gt;
-          &lt;td&gt;
-            &lt;div id=&quot;bz_restrict_group_visibility_help&quot;&gt;
-              &lt;b&gt;Only users in all of the selected groups can view this [% terms.bug %]:&lt;/b&gt;
-              &lt;br&gt;
-              &lt;small&gt;
-                (Unchecking all boxes makes this a more public [% terms.bug %].)
-              &lt;/small&gt;
-            &lt;/div&gt;
-    [% END %]
</del><ins>+      [% IF NOT emitted_description %]
+        [% emitted_description = 1 %]
+          &lt;div id=&quot;bz_restrict_group_visibility_help&quot;&gt;
+            &lt;b&gt;Only users in all of the selected groups can view this 
+              [%+ terms.bug %]:&lt;/b&gt;
+             &lt;p class=&quot;instructions&quot;&gt;
+               Unchecking all boxes makes this a more public [% terms.bug %].
+             &lt;/p&gt;
+          &lt;/div&gt;
+      [% END %]
</ins><span class="cx"> 
</span><del>-    [% IF group.ingroup %]
-      &lt;input type=&quot;hidden&quot; name=&quot;defined_bit-[% group.bit %]&quot; value=&quot;1&quot;&gt;
-    [% END %]
-    &lt;input type=&quot;checkbox&quot; value=&quot;1&quot; name=&quot;bit-[% group.bit %]&quot; id=&quot;bit-[% group.bit %]&quot;
-           [% ' checked=&quot;checked&quot;' IF group.ison %]
-           [% ' disabled=&quot;disabled&quot;' IF NOT group.ingroup %]&gt;
-    &lt;label for=&quot;bit-[% group.bit %]&quot;&gt;[% group.description FILTER html_light %]&lt;/label&gt;
-    &lt;br&gt;
-  [% END %]
</del><ins>+      [% IF group.ingroup %]
+        &lt;input type=&quot;hidden&quot; name=&quot;defined_groups&quot; 
+               value=&quot;[% group.name FILTER html %]&quot;&gt;
+      [% END %]
</ins><span class="cx"> 
</span><del>-  [% IF emitted_description %]
-    [% IF NOT inallgroups %]
-      &lt;b&gt;Only members of a group can change the visibility of [% terms.abug %] for that group.&lt;/b&gt;
</del><ins>+      &lt;input type=&quot;checkbox&quot; value=&quot;[% group.name FILTER html %]&quot;
+             name=&quot;groups&quot; id=&quot;group_[% group.bit %]&quot;
+             [% ' checked=&quot;checked&quot;' IF group.ison %]
+             [% ' disabled=&quot;disabled&quot;' IF NOT group.ingroup %]&gt;
+      &lt;label for=&quot;group_[% group.bit %]&quot;&gt;
+      [%- group.description FILTER html_light %]&lt;/label&gt;
</ins><span class="cx">       &lt;br&gt;
</span><span class="cx">     [% END %]
</span><del>-      &lt;/td&gt;
-    &lt;/tr&gt;
-    [% &quot;&lt;/table&gt;&quot; IF NOT inagroup %]
-  [% END %]
</del><span class="cx"> 
</span><del>-  [% IF inagroup %]
-    [% IF NOT emitted_description %]
-      [% emitted_description = 1 %]
-      &lt;table&gt;
</del><ins>+    [% IF emitted_description %]
+      [% IF NOT inallgroups %]
+        &lt;p class=&quot;instructions&quot;&gt;Only members of a group can change the 
+          visibility of [% terms.abug %] for that group.&lt;/p&gt;
+      [% END %]
</ins><span class="cx">     [% END %]
</span><del>-    &lt;tr&gt;
-      &lt;td class=&quot;field_label&quot;&gt;
-        &lt;label id=&quot;bz_enable_role_visibility_label&quot;&gt;&lt;b&gt;Enable Role Visibility&lt;/b&gt;:&lt;/label&gt;
-      &lt;/td&gt;
-      &lt;td&gt;
-        &lt;div id=&quot;bz_enable_role_visibility_help&quot;&gt;
-          &lt;b&gt;Users in the roles selected below can always view this [% terms.bug %]:&lt;/b&gt;
-          &lt;br&gt;
-          &lt;small&gt;
-            (The assignee
-            [% IF (Param('useqacontact')) %]
-               and QA contact
-            [% END %]
-            can always see [% terms.abug %], and this section does not take effect unless
-            the [% terms.bug %] is restricted to at least one group.)
-          &lt;/small&gt;
</del><ins>+
+    [% IF inagroup %]
+      &lt;div id=&quot;bz_enable_role_visibility_help&quot;&gt;
+        &lt;b&gt;Users in the roles selected below can always view 
+          this [% terms.bug %]:&lt;/b&gt;
+      &lt;/div&gt;
+      &lt;div id=&quot;bz_enable_role_visibility&quot;&gt;
+        &lt;div&gt;
+          [% user_can_edit_accessible = 
+            bug.check_can_change_field(&quot;reporter_accessible&quot;, 0, 1) 
+          %]
+          [% IF user_can_edit_accessible %]
+            &lt;input type=&quot;hidden&quot; name=&quot;defined_reporter_accessible&quot; value=&quot;1&quot;&gt;
+          [% END %]
+          &lt;input type=&quot;checkbox&quot; value=&quot;1&quot;
+                 name=&quot;reporter_accessible&quot; id=&quot;reporter_accessible&quot;
+                 [% &quot; checked&quot; IF bug.reporter_accessible %]
+                 [% &quot; disabled=\&quot;disabled\&quot;&quot; UNLESS user_can_edit_accessible %]&gt;
+          &lt;label for=&quot;reporter_accessible&quot;&gt;Reporter&lt;/label&gt;
</ins><span class="cx">         &lt;/div&gt;
</span><span class="cx">         &lt;div&gt;
</span><del>-          &lt;div&gt;
-            [% user_can_edit_accessible = bug.check_can_change_field(&quot;reporter_accessible&quot;, 0, 1) %]
-            [% IF user_can_edit_accessible %]
-              &lt;input type=&quot;hidden&quot; name=&quot;defined_reporter_accessible&quot; value=&quot;1&quot;&gt;
-            [% END %]
-            &lt;input type=&quot;checkbox&quot; value=&quot;1&quot;
-                   name=&quot;reporter_accessible&quot; id=&quot;reporter_accessible&quot;
-                   [% &quot; checked&quot; IF bug.reporter_accessible %]
-                   [% &quot; disabled=\&quot;disabled\&quot;&quot; UNLESS user_can_edit_accessible %]&gt;
-            &lt;label for=&quot;reporter_accessible&quot;&gt;Reporter&lt;/label&gt;
-          &lt;/div&gt;
-          &lt;div&gt;
-            [% user_can_edit_accessible = bug.check_can_change_field(&quot;cclist_accessible&quot;, 0, 1) %]
-            [% IF user_can_edit_accessible %]
-              &lt;input type=&quot;hidden&quot; name=&quot;defined_cclist_accessible&quot; value=&quot;1&quot;&gt;
-            [% END %]
-            &lt;input type=&quot;checkbox&quot; value=&quot;1&quot;
-                   name=&quot;cclist_accessible&quot; id=&quot;cclist_accessible&quot;
-                   [% &quot; checked&quot; IF bug.cclist_accessible %]
-                   [% &quot; disabled=\&quot;disabled\&quot;&quot; UNLESS user_can_edit_accessible %]&gt;
-            &lt;label for=&quot;cclist_accessible&quot;&gt;CC List&lt;/label&gt;
-          &lt;/div&gt;
</del><ins>+          [% user_can_edit_accessible = 
+            bug.check_can_change_field(&quot;cclist_accessible&quot;, 0, 1) 
+          %]
+          [% IF user_can_edit_accessible %]
+            &lt;input type=&quot;hidden&quot; name=&quot;defined_cclist_accessible&quot; value=&quot;1&quot;&gt;
+          [% END %]
+          &lt;input type=&quot;checkbox&quot; value=&quot;1&quot;
+                 name=&quot;cclist_accessible&quot; id=&quot;cclist_accessible&quot;
+                 [% &quot; checked&quot; IF bug.cclist_accessible %]
+                 [% &quot; disabled=\&quot;disabled\&quot;&quot; UNLESS user_can_edit_accessible %]&gt;
+          &lt;label for=&quot;cclist_accessible&quot;&gt;CC List&lt;/label&gt;
</ins><span class="cx">         &lt;/div&gt;
</span><del>-      &lt;/td&gt;
-    &lt;/tr&gt;
-  &lt;/table&gt;
-  [% END %]
</del><ins>+        &lt;p class=&quot;instructions&quot;&gt;
+          The assignee
+          [% IF (Param('useqacontact')) %]
+             and QA contact
+          [% END %]
+          can always see [% terms.abug %], and this section does not
+          take effect unless the [% terms.bug %] is restricted to at
+          least one group.
+        &lt;/p&gt;
+      &lt;/div&gt;
+    [% END %]
+  &lt;/div&gt; [%# bz_group_visibility_section %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [%############################################################################%]
</span><span class="lines">@@ -800,7 +753,7 @@
</span><span class="cx">       &lt;b&gt;Reported&lt;/b&gt;:
</span><span class="cx">     &lt;/td&gt;
</span><span class="cx">     &lt;td&gt;
</span><del>-     [% bug.creation_ts FILTER time %] by [% INCLUDE user_identity user =&gt; bug.reporter %]
</del><ins>+     [% bug.creation_ts FILTER time %] by [% INCLUDE global/user.html.tmpl who = bug.reporter %]
</ins><span class="cx">     &lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx">   
</span><span class="lines">@@ -820,11 +773,10 @@
</span><span class="cx"> [%# Block for CC LIST                                                        #%]
</span><span class="cx"> [%############################################################################%]
</span><span class="cx"> [% BLOCK section_cclist %]
</span><del>-  [% IF user.id %]
</del><span class="cx">     &lt;tr&gt;
</span><del>-        &lt;td class=&quot;field_label&quot;&gt;
-          &lt;label for=&quot;newcc&quot; accesskey=&quot;a&quot;&gt;&lt;b&gt;CC List&lt;/b&gt;:&lt;/label&gt;
-        &lt;/td&gt;
</del><ins>+      &lt;td class=&quot;field_label&quot;&gt;
+        &lt;label for=&quot;newcc&quot; accesskey=&quot;a&quot;&gt;&lt;b&gt;CC List&lt;/b&gt;:&lt;/label&gt;
+      &lt;/td&gt;
</ins><span class="cx">       &lt;td&gt;
</span><span class="cx">         [% IF user.id %]
</span><span class="cx">           [% IF NOT bug.cc || NOT bug.cc.contains(user.login) %]
</span><span class="lines">@@ -853,47 +805,76 @@
</span><span class="cx">             including you
</span><span class="cx">           [% END %]
</span><span class="cx">         [% END %]
</span><del>-        &lt;span id=&quot;cc_edit_area_showhide_container&quot; class=&quot;bz_default_hidden&quot;&gt;
-          (&lt;a href=&quot;#&quot; id=&quot;cc_edit_area_showhide&quot;&gt;edit&lt;/a&gt;)
-        &lt;/span&gt;
</del><ins>+        [% IF user.id || bug.cc.size %]
+          &lt;span id=&quot;cc_edit_area_showhide_container&quot; class=&quot;bz_default_hidden&quot;&gt;
+            (&lt;a href=&quot;#&quot; id=&quot;cc_edit_area_showhide&quot;&gt;[% IF user.id %]edit[% ELSE %]show[% END %]&lt;/a&gt;)
+          &lt;/span&gt;
+        [% END %]
</ins><span class="cx">         &lt;div id=&quot;cc_edit_area&quot;&gt;
</span><del>-          &lt;div&gt;
</del><ins>+          &lt;br&gt;
+          [% IF user.id %]
</ins><span class="cx">             &lt;div&gt;
</span><del>-              &lt;label for=&quot;cc&quot;&gt;
-                &lt;b&gt;Add&lt;/b&gt;
-              &lt;/label&gt;
</del><ins>+              &lt;div&gt;&lt;label for=&quot;cc&quot;&gt;&lt;b&gt;Add&lt;/b&gt;&lt;/label&gt;&lt;/div&gt;
+              [% INCLUDE global/userselect.html.tmpl
+                  id =&gt; &quot;newcc&quot;
+                  name =&gt; &quot;newcc&quot;
+                  value =&gt; &quot;&quot;
+                  size =&gt; 30
+                  classes =&gt; [&quot;bz_userfield&quot;]
+                  multiple =&gt; 5
+                %]
</ins><span class="cx">             &lt;/div&gt;
</span><del>-            [% INCLUDE global/userselect.html.tmpl
-                id =&gt; &quot;newcc&quot;
-                name =&gt; &quot;newcc&quot;
-                value =&gt; &quot;&quot;
-                size =&gt; 30
-                multiple =&gt; 5
-              %]
-          &lt;/div&gt;
-        [% IF bug.cc %]
-          &lt;select id=&quot;cc&quot; name=&quot;cc&quot; multiple=&quot;multiple&quot; size=&quot;5&quot;&gt;
-          [% FOREACH c = bug.cc %]
-            &lt;option value=&quot;[% c FILTER html %]&quot;&gt;[% c FILTER html %]&lt;/option&gt;
</del><span class="cx">           [% END %]
</span><del>-          &lt;/select&gt;
-          [% IF user.id %]
-            &lt;br&gt;
-            &lt;input type=&quot;checkbox&quot; id=&quot;removecc&quot; name=&quot;removecc&quot;&gt;
-            [%%]&lt;label for=&quot;removecc&quot;&gt;Remove selected CCs&lt;/label&gt;
-            &lt;br&gt;
</del><ins>+          [% IF bug.cc %]
+            &lt;select id=&quot;cc&quot; multiple=&quot;multiple&quot; size=&quot;5&quot;
+              [% IF bug.user.canedit %]name=&quot;cc&quot;[% END %]&gt;
+              [% FOREACH c = bug.cc %]
+                &lt;option value=&quot;[% c FILTER email FILTER html %]&quot;&gt;
+                  [% c FILTER email FILTER html %]&lt;/option&gt;
+              [% END %]
+            &lt;/select&gt;
+            [% IF user.id &amp;&amp; !bug.user.canedit %]
+              &lt;input type=&quot;hidden&quot; name=&quot;cc&quot; value=&quot;[% user.login FILTER email FILTER html %]&quot;&gt;
+            [% END %]
+            [% IF user.id AND (bug.user.canedit OR bug.cc.contains(user.login)) %]
+              &lt;br&gt;
+              &lt;input type=&quot;checkbox&quot; id=&quot;removecc&quot; name=&quot;removecc&quot;&gt;
+              &lt;label for=&quot;removecc&quot;&gt;
+                [% IF bug.user.canedit %]
+                  Remove selected CCs
+                [% ELSE %]
+                  Remove me from the CC list
+                [% END %]
+              &lt;/label&gt;
+              &lt;br&gt;
+            [% END %]
</ins><span class="cx">           [% END %]
</span><ins>+        &lt;/div&gt;
+        [% IF user.id || bug.cc.size %]
+          &lt;script type=&quot;text/javascript&quot;&gt;
+            hideEditableField( 'cc_edit_area_showhide_container', 
+                               'cc_edit_area', 
+                               'cc_edit_area_showhide', 
+                               '', 
+                               '');  
+          &lt;/script&gt;
</ins><span class="cx">         [% END %]
</span><del>-        &lt;/div&gt;
-        &lt;script type=&quot;text/javascript&quot;&gt;
-          hideEditableField( 'cc_edit_area_showhide_container', 
-                             'cc_edit_area', 
-                             'cc_edit_area_showhide', 
-                             '', 
-                             '');  
-        &lt;/script&gt;
</del><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><ins>+[% END %]
+
+[%############################################################################%]
+[%# Block for See Also                                                       #%]
+[%############################################################################%]
+[% BLOCK section_see_also %]
+  [% IF Param('use_see_also') || bug.see_also.size %]
+    &lt;tr&gt;
+      [% INCLUDE bug/field.html.tmpl 
+           field    = bug_fields.see_also
+           value    = bug.see_also
+           editable = bug.check_can_change_field('see_also', 0, 1)
+      %]
+    &lt;/tr&gt;
</ins><span class="cx">   [% END %]
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="lines">@@ -912,30 +893,18 @@
</span><span class="cx">   [% END %]
</span><span class="cx">   [% IF show_bug_flags %]
</span><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;td class=&quot;field_label&quot;&gt;
</del><ins>+      &lt;td class=&quot;field_label flags_label&quot;&gt;
</ins><span class="cx">         &lt;label&gt;&lt;b&gt;Flags:&lt;/b&gt;&lt;/label&gt;
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">       &lt;td&gt;&lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;td colspan=&quot;2&quot;&gt;
</span><del>-      [% IF user.id %]
</del><span class="cx">         [% IF bug.flag_types.size &gt; 0 %]
</span><span class="cx">           [% PROCESS &quot;flag/list.html.tmpl&quot; flag_no_header = 1
</span><span class="cx">                                            flag_types = bug.flag_types
</span><span class="cx">                                            any_flags_requesteeble = bug.any_flags_requesteeble %]
</span><span class="cx">         [% END %]
</span><del>-      [% ELSE %]
-        [% FOREACH type = bug.flag_types %]
-          [% FOREACH flag = type.flags %]
-              [% flag.setter.nick FILTER html %]:
-              [%+ type.name FILTER html FILTER no_break %][% flag.status %]
-              [%+ IF flag.requestee %]
-                ([% flag.requestee.nick FILTER html %])
-              [% END %]&lt;br&gt;
-          [% END %]
-        [% END %]
-      [% END %]         
</del><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">   [% END %]
</span><span class="lines">@@ -947,14 +916,19 @@
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK section_customfields %]
</span><span class="cx"> [%# *** Custom Fields *** %]
</span><del>-
</del><span class="cx">   [% USE Bugzilla %]
</span><span class="cx">   [% FOREACH field = Bugzilla.active_custom_fields %]
</span><span class="cx">     &lt;tr&gt;
</span><del>-      [% PROCESS bug/field.html.tmpl value=bug.${field.name}
</del><ins>+      [% PROCESS bug/field.html.tmpl value = bug.${field.name}
</ins><span class="cx">                                      editable = bug.check_can_change_field(field.name, 0, 1)
</span><span class="cx">                                      value_span = 2 %]
</span><span class="cx">     &lt;/tr&gt;
</span><ins>+    [% IF extra_field_item %]
+      &lt;tr&gt;
+        &lt;th class=&quot;field_label&quot;&gt;[% extra_field_item.header FILTER none %]&lt;/th&gt;
+        &lt;td&gt;[% extra_field_item.data FILTER none %]&lt;/td&gt;
+      &lt;/tr&gt;
+    [% END %]
</ins><span class="cx">   [% END %]
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="lines">@@ -977,37 +951,36 @@
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK dependencies %]
</span><span class="cx"> 
</span><del>-  &lt;th class=&quot;field_label&quot;&gt;
-    &lt;label for=&quot;[% dep.fieldname %]&quot;[% &quot; accesskey=\&quot;$accesskey\&quot;&quot; IF accesskey %]&gt;
-    [% dep.title %]&lt;/label&gt;:
-  &lt;/th&gt;
-  &lt;td&gt;    
-    &lt;span id=&quot;[% dep.fieldname %]_input_area&quot;&gt;
-      [% IF bug.check_can_change_field(dep.fieldname, 0, 1) %]
-        &lt;input name=&quot;[% dep.fieldname %]&quot; id=&quot;[% dep.fieldname %]&quot;
-               value=&quot;[% bug.${dep.fieldname}.join(', ') %]&quot;&gt;
</del><ins>+  [% INCLUDE &quot;bug/field-label.html.tmpl&quot; %]
+
+  &lt;td&gt;
+    &lt;span id=&quot;[% field.name FILTER html %]_input_area&quot;&gt;
+      [% IF bug.check_can_change_field(field.name, 0, 1) %]
+        &lt;input name=&quot;[% field.name FILTER html %]&quot; 
+               id=&quot;[% field.name FILTER html %]&quot; class=&quot;text_input&quot;
+               value=&quot;[% bug.${field.name}.join(', ') FILTER html %]&quot;&gt;
</ins><span class="cx">       [% END %]
</span><span class="cx">     &lt;/span&gt;
</span><span class="cx">     
</span><del>-    [% FOREACH depbug = bug.${dep.fieldname} %]
-      [% depbug FILTER bug_link(depbug) FILTER none %][% &quot; &quot; %]
</del><ins>+    [% FOREACH dep_bug = deps %]
+      [% dep_bug.id FILTER bug_link(dep_bug, use_alias =&gt; 1)
+                    FILTER none %][% &quot; &quot; %]
</ins><span class="cx">     [% END %]
</span><del>-    [% IF bug.check_can_change_field(dep.fieldname, 0, 1) %]
-      &lt;span id=&quot;[% dep.fieldname %]_edit_container&quot; class=&quot;edit_me bz_default_hidden&quot; &gt;
-        (&lt;a href=&quot;#&quot; id=&quot;[% dep.fieldname %]_edit_action&quot;&gt;edit&lt;/a&gt;)
</del><ins>+    [% IF bug.check_can_change_field(field.name, 0, 1) %]
+      &lt;span id=&quot;[% field.name FILTER html %]_edit_container&quot; 
+            class=&quot;edit_me bz_default_hidden&quot;&gt;
+        (&lt;a href=&quot;#&quot; id=&quot;[% field.name FILTER html %]_edit_action&quot;&gt;edit&lt;/a&gt;)
</ins><span class="cx">       &lt;/span&gt;
</span><span class="cx">       &lt;script type=&quot;text/javascript&quot;&gt;
</span><del>-        hideEditableField('[% dep.fieldname %]_edit_container', 
-                          '[% dep.fieldname %]_input_area', 
-                          '[% dep.fieldname %]_edit_action', 
-                          '[% dep.fieldname %]', 
-                          &quot;[% bug.${dep.fieldname}.join(', ') %]&quot;);
</del><ins>+        hideEditableField('[% field.name FILTER js %]_edit_container', 
+                          '[% field.name FILTER js %]_input_area', 
+                          '[% field.name FILTER js %]_edit_action', 
+                          '[% field.name FILTER js %]', 
+                          '[% bug.${field.name}.join(', ') FILTER js %]');
</ins><span class="cx">       &lt;/script&gt;
</span><span class="cx">     [% END %]
</span><span class="cx">   &lt;/td&gt;
</span><span class="cx">   
</span><del>-  [% accesskey = undef %]
-  
</del><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [%############################################################################%]
</span><span class="lines">@@ -1070,9 +1043,9 @@
</span><span class="cx">         [% PROCESS formattimeunit time_unit=bug.estimated_time - (bug.actual_time + bug.remaining_time) %]
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">        &lt;td&gt;
</span><del>-         &lt;input name=&quot;deadline&quot; id=&quot;deadline&quot; value=&quot;[% bug.deadline %]&quot;
-                size=&quot;10&quot; maxlength=&quot;10&quot;&gt;&lt;br /&gt;
-         &lt;small&gt;(YYYY-MM-DD)&lt;/small&gt;
</del><ins>+         [% INCLUDE bug/field.html.tmpl
+           field = bug_fields.deadline, value = bug.deadline, no_tds = 1
+           editable = bug.check_can_change_field('deadline', 0, 1) %]
</ins><span class="cx">       &lt;/td&gt;        
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     &lt;tr&gt;
</span><span class="lines">@@ -1086,28 +1059,91 @@
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [%############################################################################%]
</span><ins>+[%# Block for the Additional Comments box                                    #%]
+[%############################################################################%]
+
+[% BLOCK comment_box %]
+  &lt;div id=&quot;add_comment&quot; class=&quot;bz_section_additional_comments&quot;&gt;
+    [% IF user.id %]
+      &lt;label for=&quot;comment&quot; accesskey=&quot;c&quot;&gt;&lt;b&gt;Additional 
+        &lt;u&gt;C&lt;/u&gt;omments&lt;/b&gt;&lt;/label&gt;:
+
+      [% IF user.is_insider %]
+        &lt;input type=&quot;checkbox&quot; name=&quot;comment_is_private&quot; value=&quot;1&quot;
+               id=&quot;newcommentprivacy&quot;
+               onClick=&quot;updateCommentTagControl(this, 'comment')&quot;&gt;
+        &lt;label for=&quot;newcommentprivacy&quot;&gt;
+          Make comment private (visible only to members of the
+          &lt;strong&gt;[% Param('insidergroup') FILTER html %]&lt;/strong&gt; group)
+        &lt;/label&gt;
+      [% END %]
+
+      &lt;!-- This table keeps the submit button aligned with the box. --&gt;
+      &lt;table&gt;&lt;tr&gt;&lt;td&gt;
+        [% INCLUDE global/textarea.html.tmpl
+                   name      = 'comment'
+                   id        = 'comment'
+                   minrows   = 10
+                   maxrows   = 25
+                   cols      = constants.COMMENT_COLS
+        %]
+        [% Hook.process(&quot;after_comment_textarea&quot;, 'bug/edit.html.tmpl') %]
+        &lt;br&gt;
+        [% PROCESS commit_button id=&quot;&quot;%]
+
+        &lt;table id=&quot;bug_status_bottom&quot;
+               class=&quot;status&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
+          &lt;tr&gt;
+            &lt;td class=&quot;field_label&quot;&gt;
+              &lt;b&gt;&lt;a href=&quot;page.cgi?id=fields.html#status&quot;&gt;Status&lt;/a&gt;&lt;/b&gt;:
+            &lt;/td&gt;
+            &lt;td&gt;
+              [% PROCESS bug/knob.html.tmpl %]
+            &lt;/td&gt;
+          &lt;/tr&gt;
+        &lt;/table&gt;
+      &lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
+
+    [%# For logged-out users %]
+    [% ELSE %]
+      &lt;table&gt;
+        &lt;tr&gt;
+          &lt;td&gt;
+            &lt;fieldset&gt;
+              &lt;legend&gt;Note&lt;/legend&gt;
+              You need to
+              &lt;a href=&quot;show_bug.cgi?id=
+                      [%- bug.bug_id %]&amp;amp;GoAheadAndLogIn=1&quot;&gt;log in&lt;/a&gt;
+              before you can comment on or make changes to this [% terms.bug %].
+            &lt;/fieldset&gt;
+          &lt;/td&gt;
+        &lt;/tr&gt; 
+      &lt;/table&gt;
+    [% END %]
+  &lt;/div&gt;
+[% END %]
+
+[%############################################################################%]
</ins><span class="cx"> [%# Block for SELECT fields                                                  #%]
</span><span class="cx"> [%############################################################################%]
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK select %]
</span><del>-  [% IF NOT no_td %]
</del><span class="cx">   &lt;td&gt;
</span><del>-  [% END %]
-    [% IF bug.check_can_change_field(selname, 0, 1) AND bug.choices.${selname}.size &gt; 1 %]
</del><ins>+    [% IF bug.check_can_change_field(selname, 0, 1) 
+          AND bug.choices.${selname}.size &gt; 1 %]
</ins><span class="cx">       &lt;select id=&quot;[% selname %]&quot; name=&quot;[% selname %]&quot;&gt;
</span><span class="cx">         [% FOREACH x = bug.choices.${selname} %]
</span><del>-          &lt;option value=&quot;[% x FILTER html %]&quot;
-            [% &quot; selected&quot; IF x == bug.${selname} %]&gt;[% x FILTER html %]
</del><ins>+          [% NEXT IF NOT x.is_active AND x.name != bug.${selname} %]
+          &lt;option value=&quot;[% x.name FILTER html %]&quot;
+            [% &quot; selected&quot; IF x.name == bug.${selname} %]&gt;
+            [%- x.name FILTER html %]
</ins><span class="cx">           &lt;/option&gt;
</span><span class="cx">         [% END %]
</span><span class="cx">       &lt;/select&gt;
</span><span class="cx">     [% ELSE %]
</span><span class="cx">       [% bug.${selname} FILTER html %]
</span><span class="cx">     [% END %]
</span><del>-  [% IF NOT no_td %]
</del><span class="cx">   &lt;/td&gt;
</span><del>-  [% END %]
-  [% no_td = 0 %]
</del><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [%############################################################################%]
</span><span class="lines">@@ -1120,7 +1156,7 @@
</span><span class="cx">   [% END %]
</span><span class="cx">     [% val = value ? value : bug.$inputname %]
</span><span class="cx">     [% IF bug.check_can_change_field(inputname, 0, 1) %]
</span><del>-       &lt;input id=&quot;[% inputname %]&quot; name=&quot;[% inputname %]&quot;
</del><ins>+       &lt;input id=&quot;[% inputname %]&quot; name=&quot;[% inputname %]&quot; class=&quot;text_input&quot;
</ins><span class="cx">               value=&quot;[% val FILTER html %]&quot;[% &quot; size=\&quot;$size\&quot;&quot; IF size %]
</span><span class="cx">               [% &quot; maxlength=\&quot;$maxlength\&quot;&quot; IF maxlength %]
</span><span class="cx">               [% &quot; spellcheck=\&quot;$spellcheck\&quot;&quot; IF spellcheck %]&gt;
</span><span class="lines">@@ -1143,23 +1179,11 @@
</span><span class="cx">   [% value = undef %]
</span><span class="cx">   [% spellcheck = undef %]
</span><span class="cx"> [% END %]
</span><del>-
-[%############################################################################%]
-[%# Block for user identities. Wraps the information inside of an hCard.     #%]
-[%############################################################################%]
-
-[% BLOCK user_identity %]
-  &lt;span class=&quot;vcard&quot;&gt;
-    [% FILTER collapse %]
-      [% IF user.name %]
-        &lt;a class=&quot;email&quot; href=&quot;mailto:[% user.email FILTER html %]&quot; 
-           title=&quot;[% user.email FILTER html %]&quot;
-          &gt;&lt;span class=&quot;fn&quot;&gt;[% user.name FILTER html %]&lt;/span
-        &gt;&lt;/a&gt;
-      [% ELSE %]
-        &lt;a class=&quot;fn email&quot; href=&quot;mailto:[% user.email FILTER html %]&quot;&gt;
-          [% user.email FILTER html %]&lt;/a&gt;
-      [% END %]
-    [% END %]&lt;/span&gt;
</del><ins>+[% BLOCK commit_button %]
+  [% IF user.id %]
+    &lt;div class=&quot;knob-buttons&quot;&gt;
+      &lt;input type=&quot;submit&quot; value=&quot;Save Changes&quot; 
+             id=&quot;commit[% id FILTER css_class_quote %]&quot;&gt;
+    &lt;/div&gt;
+  [% END %]
</ins><span class="cx"> [% END %]
</span><del>-
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultbugfieldeventsjstmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/bug/field-events.js.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/bug/field-events.js.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/bug/field-events.js.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,57 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is the San Jose State 
+  # University Foundation. Portions created by the Initial Developer
+  # are Copyright (C) 2008 the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s): Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[%# INTERFACE:
+  #   field: a Bugzilla::Field object
+  #   product: (optional) a Bugzilla::Product object. When specified,
+  #            components are restricted to this product.
+  #%]
+
+[% FOREACH controlled_field = field.controls_visibility_of %]
+  showFieldWhen('[% controlled_field.name FILTER js %]',
+                '[% field.name FILTER js %]', [
+  [%- FOREACH visibility_value = controlled_field.visibility_values -%]
+    '[%- visibility_value.name FILTER js -%]'[% &quot;,&quot; UNLESS loop.last %]
+  [%- END %]
+  ]);
+[% END %]
+
+[% legal_values = [] %]
+[% IF field.name == &quot;component&quot; AND product %]
+  [% legal_values = product.components %]
+[% ELSE %]
+  [% legal_values = field.legal_values %]
+[% END %]
+
+[% FOREACH legal_value = legal_values %]
+  [% FOREACH controlled_field = legal_value.controlled_values.keys %]
+    [% SET cont_ids = [] %]
+    [% FOREACH val = legal_value.controlled_values.$controlled_field %]
+      [% cont_ids.push(val.id) %]
+    [% END %]
+    [% NEXT IF !cont_ids.size %]
+    showValueWhen('[% controlled_field FILTER js %]',
+                  [[% cont_ids.join(',') FILTER js %]],
+                  '[% field.name FILTER js %]',
+                  [% legal_value.id FILTER js %]);
+  [% END %]
+[% END %]
+[% IF field.name == 'classification' %]
+  YAHOO.util.Event.on('product', 'change', setClassification);
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultbugfieldhelpnonetmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/bug/field-help.none.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/bug/field-help.none.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/bug/field-help.none.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,241 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Netscape Communications
+  # Corporation. Portions created by Netscape are
+  # Copyright (C) 1998 Netscape Communications Corporation. All
+  # Rights Reserved.
+  #
+  # Contributor(s): Gervase Markham &lt;gerv@gerv.net&gt;
+  #                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[%# This file describes both bug fields and search fields.
+  # As calling this template once per label is very expensive,
+  # it is called only by Template.pm. %]
+
+[% RETURN UNLESS in_template_var %]
+
+[% vars.help_html = {
+
+# Note that all these keys here are in alphabetical order, though
+# search-specific fields are at the bottom.
+
+##############
+# Bug Fields #
+##############
+
+alias =&gt;
+  &quot;A short, unique name assigned to $terms.abug in order to assist with
+   looking it up and referring to it in other places in ${terms.Bugzilla}.&quot;,
+
+assigned_to =&gt;
+  &quot;The person in charge of resolving the ${terms.bug}.&quot;,
+
+blocked =&gt;
+  &quot;This $terms.bug must be resolved before the $terms.bugs listed in this
+   field can be resolved.&quot;,
+
+bug_file_loc =&gt;
+  &quot;$terms.Bugs can have a URL associated with them - for example, a&quot;
+  _ &quot; pointer to a web site where the problem is seen.&quot;,
+
+bug_id =&gt;
+  &quot;The numeric id of $terms.abug, unique within this entire installation&quot;
+  _ &quot; of ${terms.Bugzilla}.&quot;,
+
+bug_severity =&gt;
+  &quot;How severe the $terms.bug is, or whether it's an enhancement.&quot;,
+
+bug_status =&gt;
+  &quot;$terms.Abug may be in any of a number of states.&quot;,
+
+cc =&gt;
+  &quot;Users who may not have a direct role to play on this $terms.bug, but who
+   are interested in its progress.&quot;,
+
+classification =&gt; 
+  &quot;$terms.Bugs are categorised into Classifications, Products and&quot;
+  _ &quot; Components. classifications is the top-level categorisation.&quot;,   
+
+component =&gt; 
+  &quot;Components are second-level categories; each belongs to a&quot;
+  _ &quot; particular Product. Select a Product to narrow down this list.&quot;,
+
+creation_ts =&gt;
+  &quot;When the $terms.bug was filed.&quot;,
+
+deadline =&gt;
+  &quot;The date that this $terms.bug must be resolved by, entered in YYYY-MM-DD
+   format.&quot;,
+
+delta_ts =&gt;
+  &quot;When this $terms.bug was last updated.&quot;,
+
+dependson =&gt;
+  &quot;The $terms.bugs listed here must be resolved before this $terms.bug
+   can be resolved.&quot;,
+
+estimated_time =&gt;
+  &quot;The amount of time that has been estimated it will take to resolve
+   this ${terms.bug}.&quot;,
+
+keywords =&gt;
+   &quot;You can add keywords from a defined list to $terms.bugs, in order&quot;
+   _ &quot; to tag and group them.&quot;,
+
+longdesc =&gt;
+  &quot;$terms.Bugs have comments added to them by $terms.Bugzilla users.&quot;
+  _ &quot; You can search for some text in those comments.&quot;,
+
+op_sys =&gt;
+  &quot;The operating system the $terms.bug was observed on.&quot;,
+
+percentage_complete =&gt;
+  &quot;How close to 100% done this $terms.bug is, by comparing its
+   $vars.field_descs.work_time to its ${vars.field_descs.estimated_time}.&quot;,
+
+priority =&gt;
+  &quot;Engineers prioritize their $terms.bugs using this field.&quot;,
+
+# Note that this has extra text added below if useclassification is on.
+product =&gt;
+  &quot;$terms.Bugs are categorised into Products and Components.&quot;,
+
+qa_contact =&gt;
+  &quot;The person responsible for confirming this $terms.bug if it is&quot;
+  _ &quot; unconfirmed, and for verifying the fix once the $terms.bug&quot;
+  _ &quot; has been resolved.&quot;,
+
+remaining_time =&gt;
+  &quot;The number of hours of work left on this $terms.bug, calculated by
+   subtracting the $vars.field_descs.work_time from the 
+   ${vars.field_descs.estimated_time}.&quot;,
+
+rep_platform =&gt; 
+  &quot;The hardware platform the $terms.bug was observed on.&quot;,
+
+reporter =&gt;
+  &quot;The person who filed this ${terms.bug}.&quot;,
+
+resolution =&gt;
+  &quot;If $terms.abug is in a resolved state, then one of these reasons&quot;
+  _ &quot; will be given for its resolution.&quot;,
+
+see_also =&gt;
+  &quot;This allows you to refer to $terms.bugs in other installations.
+   You can enter a URL to $terms.abug in the 'Add $terms.Bug URLs'
+   field to note that that $terms.bug is related to this one. You can
+   enter multiple URLs at once by separating them with a comma.
+
+   &lt;p&gt;You should normally use this field to refer to $terms.bugs in
+     &lt;em&gt;other&lt;/em&gt; installations. For $terms.bugs in this
+     installation, it is better to use the $vars.field_descs.dependson and 
+     $vars.field_descs.blocked fields.&lt;/p&gt;&quot;,
+
+short_desc =&gt;
+  &quot;The $terms.bug summary is a short sentence which succinctly&quot;
+  _ &quot; describes what the $terms.bug is about.&quot;,
+
+status_whiteboard =&gt;
+  &quot;Each $terms.bug has a free-form single line text entry box for&quot;
+  _ &quot; adding tags and status information.&quot;,
+
+target_milestone =&gt;
+   &quot;The $vars.field_descs.target_milestone field is used to define when the&quot;
+   _ &quot; engineer the $terms.bug is assigned to expects to fix it.&quot;,
+
+version =&gt;
+  &quot;The version field defines the version of the software the&quot;
+  _ &quot; $terms.bug was found in.&quot;,
+
+votes =&gt;
+  &quot;Some $terms.bugs can be voted for, and you can limit your search to&quot;
+  _ &quot; $terms.bugs with more than a certain number of votes.&quot;,
+
+work_time =&gt;
+  &quot;The total amount of time spent on this $terms.bug so far.&quot;,
+
+##########################
+# Search-specific fields #
+##########################
+
+chfield =&gt;
+  &quot;You can search for specific types of change - this field defines&quot;
+  _&quot; which field you are interested in changes for.&quot;,
+
+# Duplicated to chfieldto below, also.
+chfieldfrom =&gt;
+  &quot;Specify the start and end dates either in YYYY-MM-DD format
+   optionally followed by HH:mm, in 24 hour clock), or in relative
+   dates such as 1h, 2d, 3w, 4m, 5y, which respectively mean one hour,
+   two days, three weeks, four months, or five years ago. 0d is last
+   midnight, and 0h, 0w, 0m, 0y is the beginning of this hour, week,
+   month, or year.&quot;,
+
+chfieldvalue =&gt;
+  &quot;The value the field defined above changed to during that time.&quot;,
+
+content =&gt;
+  &quot;This is a field available in searches that does a Google-like
+   'full-text' search on the $vars.field_descs.short_desc and
+   $vars.field_descs.longdesc fields.&quot;,
+
+# Duplicated to email2 below, also.
+email1 =&gt;
+  &quot;Every $terms.bug has people associated with it in different&quot;
+  _ &quot; roles. Here, you can search on what people are in what role.&quot;,
+
+} %]
+
+[% vars.help_html.email2 = vars.help_html.email1 %]
+[% vars.help_html.chfieldto = vars.help_html.chfieldfrom %]
+[% vars.help_html.deadlinefrom = vars.help_html.deadline %]
+[% vars.help_html.deadlineto = vars.help_html.deadline %]
+
+[% help_all_note = BLOCK %]
+  &lt;strong&gt;Note:&lt;/strong&gt; When searching, selecting the option &quot;All&quot;
+  only finds [% terms.bugs %] whose value for this field is literally
+  the word &quot;All&quot;.
+[% END %]
+[% FOREACH all_field = ['op_sys', 'rep_platform'] %]
+  [% vars.help_html.$all_field = vars.help_html.$all_field _ ' ' _ help_all_note %]
+[% END %]
+
+[% IF Param('useclassification') %]
+  [% vars.help_html.product = vars.help_html.product 
+      _ &quot; Select a Classification to narrow down this list.&quot; %]
+[% END %]
+
+[% FOREACH help_field = bug_fields.keys %]
+
+  [%# Add help for custom fields. %]
+  [% IF !vars.help_html.${help_field}.defined %]
+    [% SET field_type = bug_fields.${help_field}.type %]
+    [% field_type_desc = BLOCK -%]
+      [% field_types.$field_type FILTER html %]
+    [%- END %]
+    [% vars.help_html.${help_field} = 
+      &quot;A custom $field_type_desc field in this installation&quot;
+      _ &quot; of ${terms.Bugzilla}.&quot; %]
+  [% END %]
+
+  [%# Add help for the search types, for query.cgi. %]
+  [% type_desc = BLOCK %]
+    The type of [% vars.field_descs.${help_field} FILTER html %] search you 
+    would like.
+  [% END %]
+  [% SET type_name = help_field _ '_type' %]
+  [% vars.help_html.$type_name = type_desc %]
+[% END %]
+
+[% Hook.process(&quot;end&quot;) %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultbugfieldlabelhtmltmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/bug/field-label.html.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/bug/field-label.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/bug/field-label.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,53 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2010 the
+  # Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s):
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[%# INTERFACE:
+  #   field: a Bugzilla::Field object
+  #   desc_url: An alternate link to help for the field.
+  #   hidden: True if the field label should start hidden.
+  #   rowspan: a &quot;rowspan&quot; value for the label's &lt;th&gt;.
+  #   tag_name: the tag to use to surround the label
+  #   accesskey: access key for the label
+  #%]
+
+[% DEFAULT tag_name = &quot;th&quot; %]
+&lt;[% tag_name FILTER html %] class=&quot;field_label [% ' bz_hidden_field' IF hidden %]
+           [%- ' required' IF field.is_mandatory &amp;&amp; NOT bug.id %]&quot;
+    id=&quot;field_label_[% field.name FILTER html %]&quot;
+    [% IF rowspan %] rowspan=&quot;[% rowspan FILTER html %]&quot;[% END %]&gt;
+
+  [% IF editable %]
+    &lt;label for=&quot;[% field.name FILTER html %]&quot;[% IF accesskey %] accesskey=&quot;[% accesskey FILTER html %]&quot;[% END %]&gt;
+  [% END %]
+
+  &lt;a 
+    [% IF help_html.${field.name}.defined %]
+      title=&quot;[% help_html.${field.name} FILTER txt FILTER collapse FILTER html %]&quot;
+      class=&quot;field_help_link&quot;
+    [% END %]
+    [% IF desc_url %]
+      href=&quot;[% desc_url FILTER html %]&quot;
+    [% ELSE %]
+      href=&quot;page.cgi?id=fields.html#[% field.name FILTER uri %]&quot;
+    [% END %]
+  &gt;[%- field_descs.${field.name} FILTER html %]:&lt;/a&gt;
+
+  [% '&lt;/label&gt;' IF editable %]
+&lt;/[% tag_name FILTER html %]&gt;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultbugfieldhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/bug/field.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/bug/field.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/bug/field.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -17,37 +17,51 @@
</span><span class="cx">   #
</span><span class="cx">   # Contributor(s): Myk Melez &lt;myk@mozilla.org&gt;
</span><span class="cx">   #                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
</span><ins>+  #                 Elliotte Martin &lt;elliotte_martin@yahoo.com&gt;
+  #                 Guy Pyrzak &lt;guy.pyrzak@gmail.com&gt;
+  #                 Reed Loden &lt;reed@reedloden.com&gt;
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [%# INTERFACE:
</span><span class="cx">   #   field: a Bugzilla::Field object
</span><span class="cx">   #   value: The value of the field for this bug.
</span><ins>+  #   override_legal_values (optional): The list of legal values, for select fields.
</ins><span class="cx">   #   editable: Whether the field should be displayed as an editable
</span><span class="cx">   #             &lt;input&gt; or as just the plain text of its value.
</span><span class="cx">   #   allow_dont_change: display the --do_not_change-- option for select fields.
</span><span class="cx">   #   value_span: A colspan for the table cell containing
</span><span class="cx">   #               the field value.
</span><ins>+  #   no_tds: boolean; if true, don't display the label &lt;th&gt; or the 
+  #           wrapping &lt;td&gt; for the field.
+  #   bug (optional): The current Bugzilla::Bug being displayed, or a hash 
+  #                   with default field values being displayed on a page.
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><del>-&lt;th class=&quot;field_label&quot;&gt;
-  [% IF editable %]
-    &lt;label for=&quot;[% field.name FILTER html %]&quot;&gt;
-  [% END %]
-    [% field_descs.${field.name} FILTER html %]:
-  [% '&lt;/label&gt;' IF editable %]
-&lt;/th&gt;
</del><ins>+[% SET hidden = 0 %]
+[% IF bug AND !field.is_visible_on_bug(bug) %]
+  [% SET hidden = 1 %]
+[% END %]
</ins><span class="cx"> 
</span><del>-&lt;td class=&quot;field_value&quot; [% &quot;colspan=\&quot;$value_span\&quot;&quot; FILTER none IF value_span %]&gt;
</del><ins>+[% IF NOT no_tds %]
+  [% PROCESS &quot;bug/field-label.html.tmpl&quot; %]
+  &lt;td class=&quot;field_value [% ' bz_hidden_field' IF hidden %]&quot;
+      id=&quot;field_container_[% field.name FILTER html %]&quot; 
+      [% &quot; colspan=\&quot;$value_span\&quot;&quot; FILTER none IF value_span %]&gt;
+[% END %]
+[% Hook.process('start_field_column') %]
</ins><span class="cx"> [% IF editable %]
</span><span class="cx">   [% SWITCH field.type %]
</span><span class="cx">     [% CASE constants.FIELD_TYPE_FREETEXT %]
</span><del>-        &lt;input id=&quot;[% field.name FILTER html %]&quot; name=&quot;[% field.name FILTER html %]&quot;
</del><ins>+        &lt;input id=&quot;[% field.name FILTER html %]&quot; class=&quot;text_input&quot;
+               name=&quot;[% field.name FILTER html %]&quot;
</ins><span class="cx">                value=&quot;[% value FILTER html %]&quot; size=&quot;40&quot;
</span><del>-               maxlength=&quot;[% constants.MAX_FREETEXT_LENGTH FILTER none %]&quot;&gt;
</del><ins>+               maxlength=&quot;[% constants.MAX_FREETEXT_LENGTH FILTER none %]&quot;
+               [% ' aria-required=&quot;true&quot;' IF field.is_mandatory %]&gt;
</ins><span class="cx">     [% CASE constants.FIELD_TYPE_DATETIME %]
</span><span class="cx">       &lt;input name=&quot;[% field.name FILTER html %]&quot; size=&quot;20&quot;
</span><span class="cx">              id=&quot;[% field.name FILTER html %]&quot;
</span><span class="cx">              value=&quot;[% value FILTER html %]&quot;
</span><ins>+             [% ' aria-required=&quot;true&quot;' IF field.is_mandatory %]
</ins><span class="cx">              onchange=&quot;updateCalendarFromField(this)&quot;&gt;
</span><span class="cx">       &lt;button type=&quot;button&quot; class=&quot;calendar_button&quot;
</span><span class="cx">               id=&quot;button_calendar_[% field.name FILTER html %]&quot;
</span><span class="lines">@@ -55,12 +69,32 @@
</span><span class="cx">         &lt;span&gt;Calendar&lt;/span&gt;
</span><span class="cx">       &lt;/button&gt;
</span><span class="cx"> 
</span><del>-      &lt;div id=&quot;con_calendar_[% field.name FILTER html %]&quot;
-           class=&quot;yui-skin-sam&quot;&gt;&lt;/div&gt;
</del><ins>+      &lt;div id=&quot;con_calendar_[% field.name FILTER html %]&quot;&gt;&lt;/div&gt;
</ins><span class="cx"> 
</span><span class="cx">       &lt;script type=&quot;text/javascript&quot;&gt;
</span><span class="cx">         createCalendar('[% field.name FILTER js %]')
</span><span class="cx">       &lt;/script&gt;
</span><ins>+    [% CASE constants.FIELD_TYPE_BUG_ID %]
+        &lt;span id=&quot;[% field.name FILTER html %]_input_area&quot;&gt;
+          &lt;input name=&quot;[% field.name FILTER html %]&quot; id=&quot;[% field.name FILTER html %]&quot;
+                 value=&quot;[% value FILTER html %]&quot; size=&quot;7&quot;
+                 [% ' aria-required=&quot;true&quot;' IF field.is_mandatory %]&gt;
+
+        &lt;/span&gt;
+
+        [% IF value %]  
+          [% value FILTER bug_link(value, use_alias =&gt; 1) FILTER none %]
+        [% END %]
+        &lt;span id=&quot;[% field.name FILTER html %]_edit_container&quot; class=&quot;edit_me bz_default_hidden&quot;&gt;
+          (&lt;a href=&quot;#&quot; id=&quot;[% field.name FILTER html %]_edit_action&quot;&gt;edit&lt;/a&gt;)
+        &lt;/span&gt;
+        &lt;script type=&quot;text/javascript&quot;&gt;
+        hideEditableField('[% field.name FILTER js %]_edit_container',
+                          '[% field.name FILTER js %]_input_area',
+                          '[% field.name FILTER js %]_edit_action',
+                          '[% field.name FILTER js %]',
+                          &quot;[% value FILTER js %]&quot;);
+        &lt;/script&gt;
</ins><span class="cx">     [% CASE [ constants.FIELD_TYPE_SINGLE_SELECT 
</span><span class="cx">               constants.FIELD_TYPE_MULTI_SELECT ] %]
</span><span class="cx">         &lt;select id=&quot;[% field.name FILTER html %]&quot; 
</span><span class="lines">@@ -71,6 +105,7 @@
</span><span class="cx">                         [% SET field_size = field.legal_values.size %]
</span><span class="cx">                     [% END %]
</span><span class="cx">                     size=&quot;[% field_size FILTER html %]&quot; multiple=&quot;multiple&quot;
</span><ins>+                    [% ' aria-required=&quot;true&quot;' IF field.is_mandatory %]
</ins><span class="cx">                 [% END %]
</span><span class="cx">                 &gt;
</span><span class="cx">           [% IF allow_dont_change %]
</span><span class="lines">@@ -79,11 +114,26 @@
</span><span class="cx">               [% dontchange FILTER html %]
</span><span class="cx">             &lt;/option&gt;
</span><span class="cx">           [% END %]
</span><del>-          [% FOREACH legal_value = field.legal_values %]
-            &lt;option value=&quot;[% legal_value FILTER html %]&quot;
-                [%- &quot; selected=\&quot;selected\&quot;&quot; IF value.contains(legal_value).size %]&gt;
-                [%- legal_value FILTER html %]&lt;/option&gt;
</del><ins>+          [% IF override_legal_values %]
+            [% legal_values = override_legal_values %]
+          [% ELSE %]
+            [% legal_values = field.legal_values %]
</ins><span class="cx">           [% END %]
</span><ins>+          [% FOREACH legal_value = legal_values %]
+            [% NEXT IF NOT legal_value.is_active AND NOT value.contains(legal_value.name).size %]
+            &lt;option value=&quot;[% legal_value.name FILTER html %]&quot;
+                    id=&quot;v[% legal_value.id FILTER html %]_
+                        [%- field.name FILTER html %]&quot;
+              [%# We always show selected values, even if they should be
+                # hidden %]
+              [% IF value.contains(legal_value.name).size %]
+                selected=&quot;selected&quot;
+              [% ELSIF bug AND !legal_value.is_visible_on_bug(bug) %]
+                class=&quot;bz_hidden_option&quot; disabled=&quot;disabled&quot;
+              [% END %]&gt;
+              [%- display_value(field.name, legal_value.name) FILTER html ~%]
+            &lt;/option&gt;
+          [% END %]
</ins><span class="cx">         &lt;/select&gt;
</span><span class="cx">         [%# When you pass an empty multi-select in the web interface,
</span><span class="cx">           # it doesn't appear at all in the CGI object. Instead of
</span><span class="lines">@@ -95,15 +145,110 @@
</span><span class="cx">         [% IF field.type == constants.FIELD_TYPE_MULTI_SELECT %]
</span><span class="cx">           &lt;input type=&quot;hidden&quot; name=&quot;defined_[% field.name FILTER html %]&quot;&gt;
</span><span class="cx">         [% END %]
</span><ins>+
+        &lt;script type=&quot;text/javascript&quot;&gt;
+        &lt;!--
+          initHidingOptionsForIE('[% field.name FILTER js %]');
+          [%+ INCLUDE &quot;bug/field-events.js.tmpl&quot;
+                      field = field, product = bug.product_obj %]
+        //--&gt;
+        &lt;/script&gt;
+
</ins><span class="cx">      [% CASE constants.FIELD_TYPE_TEXTAREA %]
</span><span class="cx">        [% INCLUDE global/textarea.html.tmpl
</span><span class="cx">            id = field.name name = field.name minrows = 4 maxrows = 8
</span><del>-           cols = 60 defaultcontent = value %]
</del><ins>+           cols = 60 defaultcontent = value mandatory = field.is_mandatory %]
+     [% CASE constants.FIELD_TYPE_BUG_URLS %]
+       [% '&lt;ul class=&quot;bug_urls&quot;&gt;' IF value.size %]
+       [% FOREACH bug_url = value %]
+         &lt;li&gt;
+           [% PROCESS bug_url_link bug_url = bug_url %]
+           &lt;label&gt;&lt;input type=&quot;checkbox&quot; value=&quot;[% bug_url.name FILTER html %]&quot;
+                         name=&quot;remove_[% field.name FILTER html %]&quot;&gt;
+             Remove&lt;/label&gt;
+         &lt;/li&gt;
+       [% END %]
+       [% '&lt;/ul&gt;' IF value.size %]
+
+       [% IF Param('use_see_also') %]
+         &lt;span id=&quot;container_showhide_[% field.name FILTER html %]&quot;
+               class=&quot;bz_default_hidden&quot;&gt;
+           &lt;a href=&quot;#&quot; id=&quot;showhide_[% field.name FILTER html %]&quot;&gt;(add)&lt;/a&gt;
+         &lt;/span&gt;
+         &lt;div id=&quot;container_[% field.name FILTER html %]&quot;&gt;
+           &lt;label for=&quot;[% field.name FILTER html %]&quot;&gt;
+             &lt;strong&gt;Add [% terms.Bug %] URLs:&lt;/strong&gt;
+           &lt;/label&gt;&lt;br&gt;
+           &lt;input type=&quot;text&quot; id=&quot;[% field.name FILTER html %]&quot; size=&quot;40&quot;
+                  class=&quot;text_input&quot; name=&quot;[% field.name FILTER html %]&quot;&gt;
+         &lt;/div&gt;
+         &lt;script type=&quot;text/javascript&quot;&gt;
+             setupEditLink('[% field.name FILTER js %]');
+         &lt;/script&gt;
+       [% END %]
+     [% CASE constants.FIELD_TYPE_KEYWORDS %]
+       &lt;div id=&quot;keyword_container&quot;&gt;
+         &lt;input type=&quot;text&quot; id=&quot;[% field.name FILTER html %]&quot; size=&quot;40&quot;
+                class=&quot;text_input&quot; name=&quot;[% field.name FILTER html %]&quot;
+                value=&quot;[% value FILTER html %]&quot;&gt;
+         &lt;div id=&quot;keyword_autocomplete&quot;&gt;&lt;/div&gt;
+       &lt;/div&gt;
+       &lt;script type=&quot;text/javascript&quot; defer=&quot;defer&quot;&gt;
+         YAHOO.bugzilla.keyword_array = [
+           [%- FOREACH keyword = all_keywords %]
+             [%-# %]&quot;[% keyword.name FILTER js %]&quot;
+             [%- &quot;,&quot; IF NOT loop.last %][% END %]];
+         YAHOO.bugzilla.keywordAutocomplete.init('[% field.name FILTER js %]', 
+                                                 'keyword_autocomplete');
+       &lt;/script&gt;
</ins><span class="cx">   [% END %]
</span><del>-[% ELSIF field.type == constants.FIELD_TYPE_TEXTAREA %]
-  &lt;div class=&quot;uneditable_textarea&quot;&gt;[% value FILTER wrap_comment(60)
-                                            FILTER html %]&lt;/div&gt;
</del><span class="cx"> [% ELSE %]
</span><del>-  [% value.join(', ') FILTER html %]
</del><ins>+  [% SWITCH field.type %]
+    [% CASE constants.FIELD_TYPE_TEXTAREA %]
+      &lt;div class=&quot;uneditable_textarea&quot;&gt;[% value FILTER html %]&lt;/div&gt;
+    [% CASE constants.FIELD_TYPE_BUG_ID %]
+      [% IF value %]  
+          [% value FILTER bug_link(value, use_alias =&gt; 1) FILTER none %]
+      [% END %]
+    [% CASE [ constants.FIELD_TYPE_SINGLE_SELECT 
+              constants.FIELD_TYPE_MULTI_SELECT ] %]
+      [% FOREACH val = value %]
+        [% display_value(field.name, val) FILTER html %]
+        [% ', ' UNLESS loop.last() %]
+      [% END %]
+    [% CASE constants.FIELD_TYPE_BUG_URLS %]
+      [% '&lt;ul class=&quot;bug_urls&quot;&gt;' IF value.size %]
+        [% FOREACH bug_url = value %]
+          &lt;li&gt;
+            [% PROCESS bug_url_link bug_url = bug_url %]
+          &lt;/li&gt;
+        [% END %]
+      [% '&lt;/ul&gt;' IF value.size %]
+    [% CASE %]
+      [% value.join(', ') FILTER html %]
+  [% END %]
</ins><span class="cx"> [% END %]
</span><del>-&lt;/td&gt;
</del><ins>+[% Hook.process('end_field_column') %]
+[% '&lt;/td&gt;' IF NOT no_tds %]
+
+[%# for reverse relationships, we show this pseudo-field after the main field %]
+[% IF bug.id &amp;&amp; field.is_relationship %]
+    [% extra_field_item = {} %]
+    [% extra_field_item.header = field.reverse_desc _ &quot;:&quot; FILTER html %]
+    [% extra_field_item.data = BLOCK %]
+        [% FOREACH depbug = bug.related_bugs(field) %]
+            [% depbug.id FILTER bug_link(depbug, use_alias =&gt; 1) FILTER none %][% &quot; &quot; %]
+        [% END %]
+    [% END %]
+[% ELSE %]
+    [% extra_field_item = '' %]
+[% END %]
+
+[% BLOCK bug_url_link %]
+  [% IF bug_url.isa('Bugzilla::BugUrl::Bugzilla::Local') %]
+    [% bug_url.target_bug_id FILTER bug_link(bug_url.target_bug_id, use_alias =&gt; 1) FILTER none %]
+  [% ELSE %]
+    &lt;a href=&quot;[% bug_url.name FILTER html %]&quot;&gt;
+      [% bug_url.name FILTER html %]&lt;/a&gt;
+  [% END %]
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultbugformat_commenttxttmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/bug/format_comment.txt.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/bug/format_comment.txt.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/bug/format_comment.txt.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,60 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Marc Schumann.
+  # Portions created by Marc Schumann are Copyright (c) 2008 Marc Schumann.
+  # All rights reserved.
+  #
+  # Contributor(s): Marc Schumann &lt;wurblzap@gmail.com&gt;
+  #%]
+
+[%# NOTE: Everywhere you use this template, you must call 
+  # &quot;FILTER remove('^X')&quot; on the result. This is unfortunately the only way
+  # to preserve leading whitespace in comments.
+  #%]
+
+[%# INTERFACE:
+  #   comment: A Bugzilla::Comment object.
+  #   is_bugmail: boolean; True if this comment is going into a plain-text
+  #               bugmail.
+  #%]
+
+[%# Please don't use field-descs here. It can slow down Bugzilla. %]
+[% PROCESS 'global/variables.none.tmpl' %]
+
+[% SET comment_body = comment.body %]
+
+[% IF comment.type == constants.CMT_DUPE_OF %]
+X[% comment_body %]
+
+*** This [% terms.bug %] has been marked as a duplicate of [% terms.bug %] [%+ comment.extra_data %] ***
+[% ELSIF comment.type == constants.CMT_HAS_DUPE %]
+*** [% terms.Bug %] [%+ comment.extra_data %] has been marked as a duplicate of this [% terms.bug %]. ***
+[% ELSIF comment.type == constants.CMT_ATTACHMENT_CREATED %]
+Created attachment [% comment.extra_data %]
+[% IF is_bugmail %]
+  --&gt; [% urlbase _ &quot;attachment.cgi?id=&quot; _ comment.extra_data _ &quot;&amp;action=edit&quot; %]
+[% END %]
+[%+ comment.attachment.description %]
+
+[%+ comment.body %]
+[% ELSIF comment.type == constants.CMT_ATTACHMENT_UPDATED %]
+Comment on attachment [% comment.extra_data %]
+[% IF is_bugmail %]
+  --&gt; [% urlbase _ &quot;attachment.cgi?id=&quot; _ comment.extra_data %]
+[% END %]
+[%+ comment.attachment.description %]
+
+[%+ comment.body %]
+[% ELSE %]
+X[% Hook.process('type') %]
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultbugknobhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/bug/knob.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/bug/knob.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/bug/knob.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -23,71 +23,33 @@
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="cx"> &lt;div id=&quot;status&quot;&gt;
</span><del>-  [% initial_action_shown = 0 %]
-  [% show_resolution = 0 %]
-  [% bug_status_select_displayed = 0 %]
</del><ins>+  [% PROCESS bug/field.html.tmpl
+      no_tds = 1
+      field  = bug_fields.bug_status
+      value  = bug.bug_status
+      override_legal_values = bug.choices.bug_status
+      editable = bug.choices.bug_status.size &gt; 1
+  %]
</ins><span class="cx"> 
</span><del>-  [% closed_status_array = [] %]
-  [%# These actions are based on the current custom workflow. %]
-  [% FOREACH bug_status = bug.status.can_change_to %]
-    [% NEXT IF bug.isunconfirmed &amp;&amp; bug_status.is_open &amp;&amp; !bug.user.canconfirm %]
-    [% NEXT IF bug.isopened &amp;&amp; !bug.isunconfirmed &amp;&amp; bug_status.is_open &amp;&amp; !bug.user.canedit %]
-    [% NEXT IF (!bug_status.is_open || !bug.isopened) &amp;&amp; !bug.user.canedit &amp;&amp; !bug.user.isreporter %]
-    [%# Special hack to only display UNCO or REOP when reopening, but not both;
-      # for compatibility with older versions. %]
-    [% NEXT IF !bug.isopened &amp;&amp; (bug.everconfirmed &amp;&amp; bug_status.name == &quot;UNCONFIRMED&quot;
-                                 || !bug.everconfirmed &amp;&amp; bug_status.name == &quot;REOPENED&quot;) %]
-    [% IF NOT bug_status_select_displayed %]
-      &lt;select name=&quot;bug_status&quot; id=&quot;bug_status&quot;&gt;
-      [% bug_status_select_displayed = 1 %]
-    [% END %]
-    [% PROCESS initial_action %]
-    [% NEXT IF bug_status.name == bug.bug_status %]
-    &lt;option value=&quot;[% bug_status.name FILTER html %]&quot;&gt;
-      [% get_status(bug_status.name) FILTER html %]
-    &lt;/option&gt;
-    [% IF  !bug_status.is_open  %]
-      [% show_resolution = 1 %]
-      [% filtered_status = bug_status.name FILTER js %]
-      [% closed_status_array.push( filtered_status ) %]
-    [% END %]
</del><ins>+  [% IF bug.resolution 
+        OR bug.check_can_change_field('resolution', bug.resolution, 1)
+  %]
+    &lt;noscript&gt;&lt;br&gt;resolved&amp;nbsp;as&amp;nbsp;&lt;/noscript&gt;
</ins><span class="cx">   [% END %]
</span><span class="cx"> 
</span><del>-  [%# These actions are special and are independent of the workflow. %]
-  [% IF bug.user.canedit || bug.user.isreporter %]
-    [% IF NOT bug_status_select_displayed %]
-      &lt;select name=&quot;bug_status&quot; id=&quot;bug_status&quot;&gt;
-      [% bug_status_select_displayed = 1 %] 
-    [% END %]
-    [% IF bug.isopened %]
-      [% IF bug.resolution %]
-        [% PROCESS initial_action %]
-      [% END %]
-    [% ELSIF bug.resolution != &quot;MOVED&quot; || bug.user.canmove  %]
-        [% PROCESS initial_action %]
-        [% show_resolution = 1 %]
-    [% END %]
-  [% END %]  
-  [% IF bug_status_select_displayed %]
-    &lt;/select&gt;
-  [% ELSE %]
-      [% get_status(bug.bug_status) FILTER html %]
-      [% IF bug.resolution %]
-        [%+ get_resolution(bug.resolution) FILTER html %]
-        [% IF bug.dup_id %]
-          &lt;span id=&quot;duplicate_display&quot;&gt;of 
-          [% &quot;${terms.bug} ${bug.dup_id}&quot; FILTER bug_link(bug.dup_id) FILTER none %]&lt;/span&gt;
-        [% END %]
-      [% END %]
-  [% END %]
-  [% IF bug.user.canedit || bug.user.isreporter %]  
-    [% IF show_resolution %]
-      &lt;noscript&gt;&lt;br&gt;resolved&amp;nbsp;as&amp;nbsp;&lt;/noscript&gt;
-      &lt;span id=&quot;resolution_settings&quot;&gt;[% PROCESS select_resolution %]&lt;/span&gt;
-    [% END %]
</del><ins>+  &lt;span id=&quot;resolution_settings&quot;&gt;
+  [% PROCESS bug/field.html.tmpl
+      no_tds = 1
+      field  = bug_fields.resolution
+      value  = bug.resolution
+      override_legal_values = bug.choices.resolution
+      editable = bug.check_can_change_field('resolution', bug.resolution, 1)
+  %]
+  &lt;/span&gt;
+
+  [% IF bug.check_can_change_field('dup_id', 0, 1) %]
</ins><span class="cx">     &lt;noscript&gt;&lt;br&gt; duplicate&lt;/noscript&gt;
</span><del>-    
-    &lt;span id=&quot;duplicate_settings&quot;&gt;of 
</del><ins>+    &lt;span id=&quot;duplicate_settings&quot;&gt;of
</ins><span class="cx">       &lt;span id=&quot;dup_id_container&quot; class=&quot;bz_default_hidden&quot;&gt;
</span><span class="cx">         [% &quot;${terms.bug} ${bug.dup_id}&quot; FILTER bug_link(bug.dup_id) FILTER none %]
</span><span class="cx">         (&lt;a href=&quot;#&quot; id=&quot;dup_id_edit_action&quot;&gt;edit&lt;/a&gt;)
</span><span class="lines">@@ -95,15 +57,27 @@
</span><span class="cx">       &gt;&lt;input id=&quot;dup_id&quot; name=&quot;dup_id&quot; size=&quot;6&quot;
</span><span class="cx">               value=&quot;[% bug.dup_id FILTER html %]&quot;&gt;
</span><span class="cx">     &lt;/span&gt;
</span><ins>+    [% IF bug.dup_id %]
+        &lt;noscript&gt;[% bug.dup_id FILTER bug_link(bug.dup_id) FILTER none %]&lt;/noscript&gt;
+    [% END %]
</ins><span class="cx">     &lt;div id=&quot;dup_id_discoverable&quot; class=&quot;bz_default_hidden&quot;&gt;
</span><span class="cx">       &lt;a href=&quot;#&quot; id=&quot;dup_id_discoverable_action&quot;&gt;Mark as Duplicate&lt;/a&gt;
</span><span class="cx">     &lt;/div&gt;
</span><ins>+  [% ELSIF bug.dup_id %]
+    &lt;noscript&gt;&lt;br&gt; duplicate&lt;/noscript&gt;
+    &lt;span id=&quot;duplicate_display&quot;&gt;of 
+      [% &quot;${terms.bug} ${bug.dup_id}&quot; FILTER bug_link(bug.dup_id) FILTER none %]&lt;/span&gt;
</ins><span class="cx">   [% END %]
</span><span class="cx"> &lt;/div&gt;
</span><ins>+
</ins><span class="cx"> &lt;script type=&quot;text/javascript&quot;&gt;
</span><del>-  var close_status_array = new Array(&quot;[% closed_status_array.join('&quot;, &quot;') FILTER replace(',$', '')
-                                                                FILTER none %]&quot;);
-  YAHOO.util.Dom.setStyle('dup_id_discoverable', 'display', 'block');
</del><ins>+  var close_status_array = [
+    [% FOREACH status = bug.choices.bug_status %]
+      [% NEXT IF status.is_open %]
+      '[% status.name FILTER js %]'[% ',' UNLESS loop.last %]
+    [% END %]
+  ];
+  YAHOO.util.Dom.removeClass('dup_id_discoverable', 'bz_default_hidden');
</ins><span class="cx">   hideEditableField( &quot;dup_id_container&quot;, &quot;dup_id&quot;, 'dup_id_edit_action',
</span><span class="cx">                      'dup_id', '[% bug.dup_id FILTER js %]' )
</span><span class="cx">   showHideStatusItems( &quot;&quot;,  ['[% &quot;is_duplicate&quot; IF bug.dup_id %]',
</span><span class="lines">@@ -120,31 +94,7 @@
</span><span class="cx">   YAHOO.util.Event.addListener( window, 'load',  showHideStatusItems,
</span><span class="cx">                               ['[% &quot;is_duplicate&quot; IF bug.dup_id %]',
</span><span class="cx">                                '[% bug.bug_status FILTER js %]'] );
</span><del>-&lt;/script&gt;
</del><span class="cx"> 
</span><del>-[%# Common actions %]
-
-[% BLOCK initial_action %]
-  [% IF !initial_action_shown %]
-    &lt;option selected value=&quot;[% bug.bug_status FILTER html %]&quot;&gt;
-      [% get_status(bug.bug_status) FILTER html %]
-    &lt;/option&gt;
-    [% IF !bug.isopened  %] 
-      [% show_resolution = 1 %]
-      [% filtered_status = bug.bug_status FILTER js %]
-      [% closed_status_array.push(filtered_status) %]
-    [% END %]
-    [% initial_action_shown = 1 %]
-  [% END %]
-[% END %]
-
-[% BLOCK select_resolution %]
-  &lt;select name=&quot;resolution&quot; id=&quot;resolution&quot;&gt;
-    [% FOREACH r = bug.choices.resolution %]
-      [% NEXT IF r == &quot;MOVED&quot; &amp;&amp; bug.resolution != &quot;MOVED&quot; %]
-      &lt;option value=&quot;[% r FILTER html %]&quot;
-      [% &quot;selected&quot; IF r == bug.resolution %]&gt;
-        [% get_resolution(r) FILTER html %]&lt;/option&gt;
-    [% END %]
-  &lt;/select&gt;
-[% END %]
</del><ins>+  [% INCLUDE &quot;bug/field-events.js.tmpl&quot; field = select_fields.bug_status %]
+  [% INCLUDE &quot;bug/field-events.js.tmpl&quot; field = select_fields.resolution %]
+&lt;/script&gt;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultbuglinkhtmltmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/bug/link.html.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/bug/link.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/bug/link.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,61 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2010 the
+  # Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s):
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[%# INTERFACE:
+  #   bug: a Bugzilla::Bug object
+  #   link_text: the text that we're highlighting.
+  #   use_alias: boolean; If true, we display the bug's alias as the link
+  #              text instead of link_text.
+  #   comment_num: If defined, make this a link to that comment on the bug.
+  #   full_url: boolean; If true, generate links that include the full
+  #             urlbase. (This is for emails, mostly.)
+  #%]
+
+[% IF !bug %]
+  &amp;lt;missing&amp;gt;
+  [% RETURN %]
+[% END %]
+
+[%# We use &quot;FILTER none&quot; here because link_title is filtered down below. %]
+[% link_title = BLOCK %]
+  [% display_value('bug_status', bug.bug_status) FILTER none %]
+  [%+ display_value('resolution', bug.resolution) FILTER none %]
+[% END %]
+
+[% IF user.can_see_bug(bug) %]
+  [% link_title = link_title _ ' - ' _ bug.short_desc %]
+
+  [% IF use_alias &amp;&amp; bug.alias %]
+    [% link_text = bug.alias %]
+  [% END %]
+[% END %]
+
+[% SET anchor = '' %]
+[% IF comment_num.defined %]
+  [% anchor = &quot;#c$comment_num&quot; %]
+[% END %]
+
+&lt;a class=&quot;bz_bug_link 
+          bz_status_[% bug.bug_status FILTER css_class_quote %] 
+          [% ' bz_closed' IF !bug.isopened %]&quot;
+   title=&quot;[% link_title FILTER collapse FILTER html %]&quot;
+   href=&quot;[% urlbase FILTER html IF full_url %]show_bug.cgi?id=
+         [%~ bug.id FILTER uri %][% anchor FILTER html %]&quot;&gt;
+  [%~ link_text FILTER html %]&lt;/a&gt;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultbugnavigatehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/bug/navigate.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/bug/navigate.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/bug/navigate.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -16,17 +16,20 @@
</span><span class="cx">   # Rights Reserved.
</span><span class="cx">   #
</span><span class="cx">   # Contributor(s): Gervase Markham &lt;gerv@gerv.net&gt;
</span><ins>+  #                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><ins>+[% RETURN IF !bug %]
+
</ins><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="cx"> [% IF bottom_navigator == 1 %]
</span><span class="cx">   &lt;ul class=&quot;related_actions&quot;&gt;
</span><span class="cx">     &lt;li&gt;&lt;a href=&quot;show_bug.cgi?format=multiple&amp;amp;id=
</span><del>-                [% bug.bug_id FILTER url_quote %]&quot;&gt;Format For Printing&lt;/a&gt;&lt;/li&gt;
</del><ins>+                [% bug.bug_id FILTER uri %]&quot;&gt;Format For Printing&lt;/a&gt;&lt;/li&gt;
</ins><span class="cx">     &lt;li&gt;&amp;nbsp;-&amp;nbsp;&lt;a href=&quot;show_bug.cgi?ctype=xml&amp;amp;id=
</span><del>-                        [% bug.bug_id  FILTER url_quote %]&quot;&gt;XML&lt;/a&gt;&lt;/li&gt;
</del><ins>+                        [% bug.bug_id  FILTER uri %]&quot;&gt;XML&lt;/a&gt;&lt;/li&gt;
</ins><span class="cx">     &lt;li&gt;&amp;nbsp;-&amp;nbsp;&lt;a href=&quot;enter_bug.cgi?cloned_bug_id=
</span><del>-                        [% bug.bug_id  FILTER url_quote %]&quot;&gt;Clone This 
</del><ins>+                        [% bug.bug_id  FILTER uri %]&quot;&gt;Clone This 
</ins><span class="cx">                         [% terms.Bug %]&lt;/a&gt;&lt;/li&gt;
</span><span class="cx">     [%# Links to more things users can do with this bug. %]
</span><span class="cx">     [% Hook.process(&quot;links&quot;) %]
</span><span class="lines">@@ -36,49 +39,49 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> &lt;div class=&quot;navigation&quot;&gt;
</span><del>-[% IF bug_list &amp;&amp; bug_list.size &gt; 0 %]
-  [% this_bug_idx = lsearch(bug_list, bug.bug_id) %]
</del><ins>+[% SET my_search = user.recent_search_for(bug) %]
+[% IF my_search %]
+  [% SET last_bug_list = my_search.bug_list %]
+  [% SET this_bug_idx = lsearch(last_bug_list, bug.id) %]
</ins><span class="cx">   &lt;b&gt;[% terms.Bug %] List:&lt;/b&gt;
</span><del>-  [% IF this_bug_idx != -1 %]
-    ([% this_bug_idx + 1 %] of [% bug_list.size %])
-  [% END %]
</del><span class="cx"> 
</span><del>-[% IF this_bug_idx != -1 %]
-  &lt;a href=&quot;show_bug.cgi?id=[% bug_list.first %]&quot;&gt;First&lt;/a&gt;
-  &lt;a href=&quot;show_bug.cgi?id=[% bug_list.last %]&quot;&gt;Last&lt;/a&gt;
-[% END %]
</del><ins>+  ([% this_bug_idx + 1 %] of [% last_bug_list.size %])
</ins><span class="cx"> 
</span><del>-  [% IF bug.bug_id %]
-    [% IF this_bug_idx != -1 %]
-      [% IF this_bug_idx &gt; 0 %]
-        [% prev_bug = this_bug_idx - 1 %]
-        &lt;a href=&quot;show_bug.cgi?id=[% bug_list.$prev_bug %]&quot;&gt;Prev&lt;/a&gt;
-      [% ELSE %]
-        &lt;i&gt;&lt;font color=&quot;#777777&quot;&gt;Prev&lt;/font&gt;&lt;/i&gt;
-      [% END %]
</del><ins>+  &lt;a href=&quot;show_bug.cgi?id=
+           [%- last_bug_list.first FILTER uri %]&amp;amp;list_id=
+           [%- my_search.id FILTER uri %]&quot;&gt;First&lt;/a&gt;
+  &lt;a href=&quot;show_bug.cgi?id=
+           [%- last_bug_list.last FILTER uri %]&amp;amp;list_id=
+           [%- my_search.id FILTER uri %]&quot;&gt;Last&lt;/a&gt;
</ins><span class="cx"> 
</span><del>-      [% IF this_bug_idx + 1 &lt; bug_list.size %]
-        [% next_bug = this_bug_idx + 1 %]
-        &lt;a href=&quot;show_bug.cgi?id=[% bug_list.$next_bug %]&quot;&gt;Next&lt;/a&gt;
-      [% ELSE %]
-        &lt;i&gt;&lt;font color=&quot;#777777&quot;&gt;Next&lt;/font&gt;&lt;/i&gt;
-      [% END %]
-    [% ELSE %]
-      (This [% terms.bug %] is not in your last search results)
-    [% END %]
</del><ins>+  [% IF this_bug_idx &gt; 0 %]
+    [% prev_bug = this_bug_idx - 1 %]
+    &lt;a href=&quot;show_bug.cgi?id=
+             [%- last_bug_list.$prev_bug FILTER uri %]&amp;amp;list_id=
+             [%- my_search.id FILTER uri %]&quot;&gt;Prev&lt;/a&gt;
</ins><span class="cx">   [% ELSE %]
</span><del>-    &amp;nbsp;&amp;nbsp;
</del><ins>+    &lt;i&gt;&lt;font color=&quot;#777777&quot;&gt;Prev&lt;/font&gt;&lt;/i&gt;
</ins><span class="cx">   [% END %]
</span><span class="cx"> 
</span><del>-  &amp;nbsp;&amp;nbsp;&lt;a href=&quot;buglist.cgi?regetlastlist=1&quot;&gt;Show last search results&lt;/a&gt;
</del><ins>+  [% IF this_bug_idx + 1 &lt; last_bug_list.size %]
+    [% next_bug = this_bug_idx + 1 %]
+    &lt;a href=&quot;show_bug.cgi?id=
+             [%- last_bug_list.$next_bug FILTER uri %]&amp;amp;list_id=
+             [%- my_search.id FILTER uri %]&quot;&gt;Next&lt;/a&gt;
+  [% ELSE %]
+    &lt;i&gt;&lt;font color=&quot;#777777&quot;&gt;Next&lt;/font&gt;&lt;/i&gt;
+  [% END %]
+
+  &amp;nbsp;&amp;nbsp;&lt;a href=&quot;buglist.cgi?regetlastlist=
+              [%- my_search.id FILTER uri %]&quot;&gt;Show last search results&lt;/a&gt;
</ins><span class="cx"> [% ELSE %]
</span><del>-  [%# Either !bug_list || bug_list.size &lt;= 0 %]
</del><span class="cx">   [%# With no list, don't show link to search results %]
</span><span class="cx">   &lt;i&gt;&lt;font color=&quot;#777777&quot;&gt;First&lt;/font&gt;&lt;/i&gt;
</span><span class="cx">   &lt;i&gt;&lt;font color=&quot;#777777&quot;&gt;Last&lt;/font&gt;&lt;/i&gt;
</span><span class="cx">   &lt;i&gt;&lt;font color=&quot;#777777&quot;&gt;Prev&lt;/font&gt;&lt;/i&gt;
</span><span class="cx">   &lt;i&gt;&lt;font color=&quot;#777777&quot;&gt;Next&lt;/font&gt;&lt;/i&gt;
</span><span class="cx">   &amp;nbsp;&amp;nbsp;
</span><del>-  &lt;i&gt;&lt;font color=&quot;#777777&quot;&gt;No search results available&lt;/font&gt;&lt;/i&gt;
</del><ins>+  &lt;i&gt;&lt;font color=&quot;#777777&quot;&gt;This [% terms.bug %] is not in your last
+    search results.&lt;/font&gt;&lt;/i&gt;
</ins><span class="cx"> [% END %]
</span><span class="cx"> &lt;/div&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultbugprocessbugmailhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/bug/process/bugmail.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/bug/process/bugmail.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/bug/process/bugmail.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -20,34 +20,21 @@
</span><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [%# INTERFACE:
</span><del>-  # mailing_bugid: string. ID of the bug this mail is concerning.
-  # mailrecipients: hash. People involved in this change. Hash has up to five
-  #                elements:
-  #                changer: string. The login name of the user who made the
-  #                change.
-  #
-  #                For bug changes where people need to be notified:
-  #                 owner: string. The login name of the bug assignee.
-  #                 reporter: string. The login name of the bug reporter.
-  #                 qacontact: string. The login name of the bug's QA contact.
-  #                  Optional.
-  #                 cc: list of strings. The login names of those on the CC
-  #                  list.
</del><ins>+  # mailing_bugid: The bug ID that email is being sent for.
+  # sent_bugmail: The results of Bugzilla::BugMail::Send().
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="cx"> 
</span><del>-[% mail = SendBugMail(mailing_bugid, mailrecipients) %]
-
</del><span class="cx"> &lt;dl&gt;
</span><span class="cx"> [% PROCESS emails
</span><span class="cx">    description = &quot;Email sent to&quot;
</span><del>-   names = mail.sent
</del><ins>+   names = sent_bugmail.sent
</ins><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS emails
</span><span class="cx">    description = &quot;Excluding&quot;
</span><del>-   names = mail.excluded
</del><ins>+   names = sent_bugmail.excluded
</ins><span class="cx"> %]
</span><span class="cx"> &lt;/dl&gt;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultbugprocessheaderhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/bug/process/header.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/bug/process/header.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/bug/process/header.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -26,6 +26,8 @@
</span><span class="cx"> 
</span><span class="cx"> [% USE Bugzilla %]
</span><span class="cx"> 
</span><ins>+[% PROCESS &quot;bug/show-header.html.tmpl&quot; %]
+
</ins><span class="cx"> [% IF    title_tag == &quot;bug_processed&quot; %]
</span><span class="cx">   [% title = BLOCK %]
</span><span class="cx">     [% IF Bugzilla.cgi.param('id') %]
</span><span class="lines">@@ -37,13 +39,8 @@
</span><span class="cx">   [% END %]
</span><span class="cx"> [% ELSIF title_tag == &quot;mid_air&quot; %]
</span><span class="cx">   [% title = &quot;Mid-air collision!&quot; %]
</span><del>-[% ELSIF title_tag == &quot;change_votes&quot; %]
-  [% title = &quot;Change Votes&quot; %]
</del><span class="cx"> [% END %]
</span><span class="cx"> 
</span><del>-[% PROCESS global/header.html.tmpl
-  javascript_urls = [ &quot;js/util.js&quot;, &quot;js/field.js&quot;,
-                      &quot;js/yui/yahoo-dom-event.js&quot;, &quot;js/yui/calendar.js&quot; ]
-  style_urls = [ &quot;skins/standard/yui/calendar.css&quot;, &quot;skins/standard/show_bug.css&quot; ]
-  doc_section = &quot;bug_page.html&quot;
-%]
</del><ins>+[% Hook.process('title') %]
+
+[% PROCESS global/header.html.tmpl %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultbugprocessmidairhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/bug/process/midair.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/bug/process/midair.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/bug/process/midair.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -45,7 +45,7 @@
</span><span class="cx"> 
</span><span class="cx"> &lt;p&gt;
</span><span class="cx">   Someone else has made changes to
</span><del>-  [%+ &quot;$terms.bug $bug.id&quot; FILTER bug_link(bug.id) FILTER none %]
</del><ins>+  [%+ &quot;$terms.bug $bug.id&quot; FILTER bug_link(bug) FILTER none %]
</ins><span class="cx">   at the same time you were trying to.
</span><span class="cx">   The changes made were:
</span><span class="cx"> &lt;/p&gt;
</span><span class="lines">@@ -67,7 +67,7 @@
</span><span class="cx"> &lt;p&gt;
</span><span class="cx">   Your comment was:&lt;br&gt;
</span><span class="cx">   &lt;blockquote&gt;&lt;pre class=&quot;bz_comment_text&quot;&gt;
</span><del>-    [% cgi.param(&quot;comment&quot;) FILTER wrap_comment FILTER html %]
</del><ins>+    [% cgi.param(&quot;comment&quot;) FILTER html %]
</ins><span class="cx">   &lt;/pre&gt;&lt;/blockquote&gt;
</span><span class="cx"> &lt;/p&gt;
</span><span class="cx"> [% END %]
</span><span class="lines">@@ -88,9 +88,23 @@
</span><span class="cx">         [% &quot;, except for the added comment(s)&quot; IF comments.size &gt; start_at %].
</span><span class="cx">     &lt;/form&gt;
</span><span class="cx">   &lt;/li&gt;
</span><ins>+  [% IF cgi.param(&quot;comment&quot;) %]
+    &lt;li&gt;
+      &lt;form method=&quot;post&quot; action=&quot;process_bug.cgi&quot;&gt;
+        &lt;input type=&quot;hidden&quot; name=&quot;id&quot; value=&quot;[% cgi.param(&quot;id&quot;) FILTER html %]&quot;&gt;
+        &lt;input type=&quot;hidden&quot; name=&quot;delta_ts&quot; value=&quot;[% bug.delta_ts FILTER html %]&quot;&gt;
+        &lt;input type=&quot;hidden&quot; name=&quot;comment&quot; value=&quot;[% cgi.param(&quot;comment&quot;) FILTER html %]&quot;&gt;
+        &lt;input type=&quot;hidden&quot; name=&quot;comment_is_private&quot;
+               value=&quot;[% cgi.param(&quot;comment_is_private&quot;) FILTER html %]&quot;&gt;
+        &lt;input type=&quot;hidden&quot; name=&quot;longdesclength&quot; value=&quot;[% bug.comments.size %]&quot;&gt;
+        &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% cgi.param(&quot;token&quot;) FILTER html %]&quot;&gt;
+        &lt;input type=&quot;submit&quot; id=&quot;process_comment&quot; value=&quot;Submit only my new comment&quot;&gt;
+      &lt;/form&gt;
+    &lt;/li&gt;
+  [% END %]
</ins><span class="cx">   &lt;li&gt;
</span><span class="cx">     Throw away my changes, and
</span><del>-    [%+ &quot;revisit $terms.bug $bug.id&quot; FILTER bug_link(bug.id) FILTER none %]
</del><ins>+    [%+ &quot;revisit $terms.bug $bug.id&quot; FILTER bug_link(bug) FILTER none %]
</ins><span class="cx">   &lt;/li&gt;
</span><span class="cx"> &lt;/ul&gt;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultbugprocessresultshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/bug/process/results.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/bug/process/results.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/bug/process/results.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -24,8 +24,6 @@
</span><span class="cx">   # type: string; the type of change/check that was made: &quot;bug&quot; when a bug
</span><span class="cx">   #   is changed, &quot;dupe&quot; when a duplication notation is added to a bug,
</span><span class="cx">   #   and &quot;dep&quot; when a bug is checked for changes to its dependencies.
</span><del>-  #
-  # mailrecipients: hash; BugMail recipient params. Optional.
</del><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="lines">@@ -44,12 +42,13 @@
</span><span class="cx">     'bug' =&gt; &quot;Changes submitted for $link&quot; ,
</span><span class="cx">     'dupe' =&gt; &quot;Duplicate notation added to $link&quot; ,
</span><span class="cx">     'dep' =&gt; &quot;Checking for dependency changes on $link&quot; ,
</span><del>-    'votes' =&gt; &quot;$Link confirmed by number of votes&quot; ,
</del><span class="cx">     'created' =&gt; &quot;$Link has been added to the database&quot; ,
</span><span class="cx">     'move' =&gt; &quot;$Link has been moved to another database&quot; ,
</span><span class="cx">   }
</span><span class="cx"> %]
</span><span class="cx"> 
</span><ins>+[% Hook.process('title') %]
+
</ins><span class="cx"> &lt;dl&gt;
</span><span class="cx">   &lt;dt&gt;[% title.$type %]&lt;/dt&gt;
</span><span class="cx">   &lt;dd&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultbugprocessverifynewproducthtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/bug/process/verify-new-product.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/bug/process/verify-new-product.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/bug/process/verify-new-product.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -40,8 +40,9 @@
</span><span class="cx"> 
</span><span class="cx"> [% SET exclude_items = ['version', 'component', 'target_milestone'] %]
</span><span class="cx"> [% IF verify_bug_groups %]
</span><del>-  [% exclude_items.push('bit-\d+') %]
</del><ins>+  [% exclude_items.push('groups', 'defined_groups') %]
</ins><span class="cx"> [% END %]
</span><ins>+[% Hook.process('exclude') %]
</ins><span class="cx"> 
</span><span class="cx"> [% PROCESS &quot;global/hidden-fields.html.tmpl&quot;
</span><span class="cx">      exclude = '^' _ exclude_items.join('|') _ '$' %]
</span><span class="lines">@@ -110,6 +111,7 @@
</span><span class="cx">                  size=10 %]
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">     [% END %]
</span><ins>+    [% Hook.process('field') %]
</ins><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> &lt;/table&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -122,9 +124,9 @@
</span><span class="cx">     [%+ terms.Bugs %] will no longer be restricted to these groups and may become
</span><span class="cx">     public if no other group applies:&lt;br&gt;
</span><span class="cx">     [% FOREACH group = old_groups %]
</span><del>-      &lt;input type=&quot;checkbox&quot; id=&quot;bit-[% group.id FILTER html %]&quot;
-             name=&quot;bit-[% group.id FILTER html %]&quot; disabled=&quot;disabled&quot; value=&quot;1&quot;&gt;
-      &lt;label for=&quot;bit-[% group.id FILTER html %]&quot;&gt;
</del><ins>+      &lt;input type=&quot;checkbox&quot; id=&quot;group_[% group.id FILTER html %]&quot;
+             name=&quot;groups&quot; disabled=&quot;disabled&quot; value=&quot;[% group.name FILTER html %]&quot;&gt;
+      &lt;label for=&quot;group_[% group.id FILTER html %]&quot;&gt;
</ins><span class="cx">         [% group.name FILTER html %]: [% group.description FILTER html %]
</span><span class="cx">       &lt;/label&gt;
</span><span class="cx">       &lt;br&gt;
</span><span class="lines">@@ -152,16 +154,15 @@
</span><span class="cx">     &lt;p&gt;These groups are optional. You can decide to restrict [% terms.bugs %] to
</span><span class="cx">     one or more of the following groups:&lt;br&gt;
</span><span class="cx">     [% FOREACH group = optional_groups %]
</span><del>-      &lt;input type=&quot;hidden&quot; name=&quot;defined_bit-[% group.group.id FILTER html %]&quot;
-             value=&quot;1&quot;&gt;
-      &lt;input type=&quot;checkbox&quot; id=&quot;bit-[% group.group.id FILTER html %]&quot;
-             name=&quot;bit-[% group.group.id FILTER html %]&quot;
-             [%+ ((group.membercontrol == constants.CONTROLMAPDEFAULT &amp;&amp; user.in_group(group.group.name))
</del><ins>+      &lt;input type=&quot;hidden&quot; name=&quot;defined_groups&quot;
+             value=&quot;[% group.group.name FILTER html %]&quot;&gt;
+      &lt;input type=&quot;checkbox&quot; id=&quot;group_[% group.group.id FILTER html %]&quot;
+             name=&quot;groups&quot;
+             [% ' checked=&quot;checked&quot;' IF ((group.membercontrol == constants.CONTROLMAPDEFAULT &amp;&amp; user.in_group(group.group.name))
</ins><span class="cx">                  || (group.othercontrol == constants.CONTROLMAPDEFAULT &amp;&amp; !user.in_group(group.group.name))
</span><del>-                 || cgi.param(&quot;bit-$group.group.id&quot;) == 1) ?
-                 'checked=&quot;checked&quot;' : ''
-             %] value=&quot;1&quot;&gt;
-      &lt;label for=&quot;bit-[% group.group.id FILTER html %]&quot;&gt;
</del><ins>+                 || cgi.param(&quot;groups&quot;).contains(group.group.name)) %]
+             value=&quot;[% group.group.name FILTER html %]&quot;&gt;
+      &lt;label for=&quot;group_[% group.group.id FILTER html %]&quot;&gt;
</ins><span class="cx">         [% group.group.name FILTER html %]: [% group.group.description FILTER html %]
</span><span class="cx">       &lt;/label&gt;
</span><span class="cx">       &lt;br&gt;
</span><span class="lines">@@ -173,9 +174,10 @@
</span><span class="cx">     &lt;p&gt;These groups are mandatory and [% terms.bugs %] will be automatically
</span><span class="cx">     restricted to these groups:&lt;br&gt;
</span><span class="cx">     [% FOREACH group = mandatory_groups %]
</span><del>-      &lt;input type=&quot;checkbox&quot; id=&quot;bit-[% group.group.id FILTER html %]&quot; checked=&quot;checked&quot;
-             name=&quot;bit-[% group.group.id FILTER html %]&quot; value=&quot;1&quot; disabled=&quot;disabled&quot;&gt;
-      &lt;label for=&quot;bit-[% group.group.id FILTER html %]&quot;&gt;
</del><ins>+      &lt;input type=&quot;checkbox&quot; id=&quot;group_[% group.group.id FILTER html %]&quot;
+              checked=&quot;checked&quot; disabled=&quot;disabled&quot;
+             name=&quot;groups&quot; value=&quot;[% group.group.name FILTER html %]&quot;&gt;
+      &lt;label for=&quot;group_[% group.group.id FILTER html %]&quot;&gt;
</ins><span class="cx">         [% group.group.name FILTER html %]: [% group.group.description FILTER html %]
</span><span class="cx">       &lt;/label&gt;
</span><span class="cx">       &lt;br&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultbugshowheaderhtmltmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/bug/show-header.html.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/bug/show-header.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/bug/show-header.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,63 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Netscape Communications
+  # Corporation. Portions created by Netscape are
+  # Copyright (C) 1998 Netscape Communications Corporation. All
+  # Rights Reserved.
+  #
+  # Contributor(s): Gervase Markham &lt;gerv@gerv.net&gt;
+  #                 Vaskin Kissoyan &lt;vkissoyan@yahoo.com&gt;
+  #                 Bradley Baetz &lt;bbaetz@student.usyd.edu.au&gt;
+  #                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[%# This template should be called with PROCESS before processing
+  # &quot;global/header.html.tmpl&quot; in any template that is going to load the
+  # bug form. It expects only a &quot;bug&quot; object, and can even manage to get
+  # along without that. Some of these variables are just defaults that will
+  # be overridden by the calling templates.
+  #%]
+
+[% filtered_desc = bug.short_desc FILTER html %]
+[% subheader = filtered_desc %]
+[% filtered_timestamp = bug.delta_ts FILTER time %]
+[% title = &quot;$terms.Bug $bug.bug_id &amp;ndash; $filtered_desc&quot; %]
+[% header = &quot;$terms.Bug&amp;nbsp;$bug.bug_id&quot; %]
+[% header_addl_info = &quot;Last modified: $filtered_timestamp&quot; %]
+[% yui = ['autocomplete', 'calendar'] %]
+[% javascript_urls = [ &quot;js/util.js&quot;, &quot;js/field.js&quot; ] %]
+[% IF bug.defined %]
+  [% unfiltered_title = &quot;$terms.Bug $bug.bug_id â€“ $bug.short_desc&quot; %]
+  [% javascript =  BLOCK %]
+    if( !document.location.href.match(/show_bug\.cgi/) &amp;&amp; history &amp;&amp; history.replaceState ) {
+      history.replaceState( null, 
+                         &quot;[% unfiltered_title FILTER js %]&quot;,  
+                         &quot;show_bug.cgi?id=[% bug.bug_id FILTER js %]&quot; );
+      document.title = &quot;[% unfiltered_title FILTER js %]&quot;;
+    }
+    [% javascript FILTER none %]
+  [% END %]
+[% END %]
+[% style_urls = [ &quot;skins/standard/show_bug.css&quot; ] %]
+[% doc_section = &quot;bug_page.html&quot; %]
+[% bodyclasses = ['bz_bug',
+                  &quot;bz_status_$bug.bug_status&quot;,
+                  &quot;bz_product_$bug.product&quot;,
+                  &quot;bz_component_$bug.component&quot;,
+                  &quot;bz_bug_$bug.bug_id&quot;,
+                  ] %]
+[% FOREACH group = bug.groups_in %]
+  [% bodyclasses.push(&quot;bz_group_$group.name&quot;) %]
+[% END %]
+
+[% Hook.process('end') %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultbugshowmultiplehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/bug/show-multiple.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/bug/show-multiple.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/bug/show-multiple.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -66,7 +66,7 @@
</span><span class="cx">     [% terms.Bug %] 
</span><span class="cx">     &lt;a href=&quot;show_bug.cgi?id=[% bug.bug_id FILTER html %]&quot;&gt;[% bug.bug_id FILTER html %]&lt;/a&gt;
</span><span class="cx">     [% IF Param(&quot;usebugaliases&quot;) AND bug.alias AND NOT bug.error %]
</span><del>-      (&lt;a href=&quot;show_bug.cgi?id=[% bug.alias FILTER url_quote %]&quot;&gt;
</del><ins>+      (&lt;a href=&quot;show_bug.cgi?id=[% bug.alias FILTER uri %]&quot;&gt;
</ins><span class="cx">         [% bug.alias FILTER html %]&lt;/a&gt;)
</span><span class="cx">     [% END %]
</span><span class="cx">   &lt;/h1&gt;
</span><span class="lines">@@ -129,8 +129,8 @@
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th&gt;[% field_descs.bug_status  FILTER html %]:&lt;/th&gt;
</span><span class="cx">       &lt;td&gt;
</span><del>-        [% get_status(bug.bug_status) FILTER html %]
-        [%+ get_resolution(bug.resolution) FILTER html %]
</del><ins>+        [% display_value(&quot;bug_status&quot;, bug.bug_status) FILTER html %]
+        [%+ display_value(&quot;resolution&quot;, bug.resolution) FILTER html %]
</ins><span class="cx">       &lt;/td&gt;
</span><span class="cx"> 
</span><span class="cx">       [% PROCESS rightcell %]
</span><span class="lines">@@ -139,7 +139,7 @@
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th&gt;[% field_descs.bug_severity FILTER html %]:&lt;/th&gt;
</span><span class="cx">       &lt;td class=&quot;bz_[% bug.bug_severity FILTER css_class_quote -%]&quot;&gt;
</span><del>-        [% bug.bug_severity FILTER html %]
</del><ins>+        [% display_value(&quot;bug_severity&quot;, bug.bug_severity) FILTER html %]
</ins><span class="cx">       &lt;/td&gt;
</span><span class="cx"> 
</span><span class="cx">       [% PROCESS rightcell %]
</span><span class="lines">@@ -163,16 +163,28 @@
</span><span class="cx">       &lt;tr&gt;
</span><span class="cx">         &lt;th&gt;[% field_descs.bug_file_loc FILTER html %]:&lt;/th&gt;
</span><span class="cx">         &lt;td colspan=&quot;3&quot;&gt;
</span><del>-          [% IF bug.bug_file_loc.match(&quot;^(javascript|data)&quot;) %]
-            [% bug.bug_file_loc FILTER html %]
-          [% ELSE %]
</del><ins>+          [% IF is_safe_url(bug.bug_file_loc) %]
</ins><span class="cx">             &lt;a href=&quot;[% bug.bug_file_loc FILTER html %]&quot;&gt;
</span><span class="cx">                      [% bug.bug_file_loc FILTER html %]&lt;/a&gt;
</span><ins>+          [% ELSE %]
+            [% bug.bug_file_loc FILTER html %]
</ins><span class="cx">           [% END %]
</span><span class="cx">         &lt;/td&gt;
</span><span class="cx">       &lt;/tr&gt;
</span><span class="cx">     [% END %]
</span><span class="cx"> 
</span><ins>+    [% IF bug.see_also.size %]
+      &lt;tr&gt;
+        &lt;th&gt;[% field_descs.see_also FILTER html %]:&lt;/th&gt;
+        &lt;td colspan=&quot;3&quot;&gt;
+          [% FOREACH see_also = bug.see_also %]
+            &lt;a href=&quot;[% see_also.name FILTER html %]&quot;&gt;[% see_also.name FILTER html %]&lt;/a&gt;
+            [% &quot;&lt;br&gt;&quot; IF not loop.last() %]
+          [% END %]
+        &lt;/td&gt;
+      &lt;/tr&gt;
+    [% END %]
+
</ins><span class="cx">     [% IF Param(&quot;usestatuswhiteboard&quot;) %]
</span><span class="cx">       [% PROCESS row cell = &quot;status_whiteboard&quot; fullrow = 1 %]
</span><span class="cx">     [% END %]
</span><span class="lines">@@ -186,6 +198,13 @@
</span><span class="cx">         [% PROCESS bug/field.html.tmpl value=bug.${field.name} editable=0 %]
</span><span class="cx">         [%# Even-numbered fields get a closing &lt;tr&gt; %]
</span><span class="cx">         [% '&lt;/tr&gt;' IF !(field_counter % 2) %]
</span><ins>+        [% IF extra_field_item %]
+          [% field_counter = field_counter + 1 %]
+          [% '&lt;tr&gt;' IF field_counter % 2 %]
+          &lt;th&gt;[% extra_field_item.header FILTER none %]&lt;/th&gt;
+          &lt;td&gt;[% extra_field_item.data FILTER none %]&lt;/td&gt;
+          [% '&lt;/tr&gt;' IF !(field_counter % 2) %]
+        [% END %]
</ins><span class="cx">     [% END %]
</span><span class="cx">     [%# And we have to finish the row if we ended on an odd number. %]
</span><span class="cx">     [% '&lt;th&gt;&lt;/th&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;' IF field_counter % 2 %]
</span><span class="lines">@@ -195,7 +214,7 @@
</span><span class="cx">       [% PROCESS dependencies name = &quot;blocked&quot;  %]
</span><span class="cx">     [% END %]
</span><span class="cx"> 
</span><del>-    [% IF user.in_group(Param(&quot;timetrackinggroup&quot;)) %]
</del><ins>+    [% IF user.is_timetracker %]
</ins><span class="cx">       &lt;tr&gt;
</span><span class="cx">         &lt;th&gt;Time tracking:&lt;/th&gt;
</span><span class="cx">         &lt;td colspan=&quot;3&quot;&gt;
</span><span class="lines">@@ -289,7 +308,7 @@
</span><span class="cx">   &lt;br&gt;
</span><span class="cx"> 
</span><span class="cx">   [% PROCESS bug/comments.html.tmpl
</span><del>-     comments = bug.longdescs %]
</del><ins>+     comments = bug.comments %]
</ins><span class="cx"> 
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="lines">@@ -301,7 +320,7 @@
</span><span class="cx"> [% BLOCK row %]
</span><span class="cx">   &lt;tr&gt;
</span><span class="cx">     &lt;th&gt;[% field_descs.${cell} FILTER html %]:&lt;/th&gt;
</span><del>-    &lt;td[% &quot; colspan=3&quot; IF fullrow %]&gt;[% bug.${cell} FILTER html %]&lt;/td&gt;
</del><ins>+    &lt;td[% &quot; colspan=3&quot; IF fullrow %]&gt;[% display_value(cell, bug.${cell}) FILTER html %]&lt;/td&gt;
</ins><span class="cx">     [% PROCESS rightcell IF !fullrow %]
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx">   [% fullrow = 0 %]
</span><span class="lines">@@ -336,12 +355,12 @@
</span><span class="cx">       &lt;th class=&quot;rightcell&quot;&gt;[% field_descs.cc FILTER html %]:&lt;/th&gt;
</span><span class="cx">       &lt;td&gt;
</span><span class="cx">         [% FOREACH c = bug.cc %]
</span><del>-          [% c FILTER html %][% &quot;, &quot; IF not loop.last() %]
</del><ins>+          [% c FILTER email FILTER html %][% &quot;, &quot; IF not loop.last() %]
</ins><span class="cx">         [% END %]
</span><span class="cx">     [% ELSIF name == &quot;reporter&quot; || name == &quot;assigned_to&quot; 
</span><span class="cx">              || name == &quot;qa_contact&quot; %]
</span><span class="cx">       &lt;th class=&quot;rightcell&quot;&gt;[% field_descs.${name} FILTER html %]:&lt;/th&gt;
</span><del>-      &lt;td&gt;[% bug.${name}.identity FILTER html %]&lt;/td&gt;
</del><ins>+      &lt;td&gt;[% bug.${name}.identity FILTER email FILTER html %]&lt;/td&gt;
</ins><span class="cx">     [% ELSIF name == &quot;flags&quot; %]
</span><span class="cx">         &lt;th class=&quot;rightcell&quot;&gt;Flags:&lt;/th&gt;
</span><span class="cx">         &lt;td&gt;
</span><span class="lines">@@ -357,7 +376,7 @@
</span><span class="cx">         &lt;/td&gt;
</span><span class="cx">     [% ELSIF name != &quot;&quot; %]
</span><span class="cx">       &lt;th class=&quot;rightcell&quot;&gt;[% field_descs.${name} FILTER html %]:&lt;/th&gt;
</span><del>-      &lt;td&gt;[% bug.${name} FILTER html %]&lt;/td&gt;
</del><ins>+      &lt;td&gt;[% display_value(name, bug.${name}) FILTER html %]&lt;/td&gt;
</ins><span class="cx">     [% ELSE %]
</span><span class="cx">       &lt;td&gt;&amp;nbsp;&lt;/td&gt;
</span><span class="cx">       &lt;td&gt;&amp;nbsp;&lt;/td&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultbugshowhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/bug/show.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/bug/show.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/bug/show.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -27,28 +27,8 @@
</span><span class="cx"> [% bug = bugs.0 %]
</span><span class="cx"> 
</span><span class="cx"> [% IF !header_done %]
</span><del>-  [% filtered_desc = bug.short_desc FILTER html %]
-  [% filtered_timestamp = bug.delta_ts FILTER time %]
-  [% bodyclasses = ['bz_bug',
-                   &quot;bz_status_$bug.bug_status&quot;,
-                   &quot;bz_component_$bug.component&quot;,
-                   &quot;bz_bug_$bug.bug_id&quot;
-                   ]
-  %]
-  [% FOREACH group = bug.groups_in %]
-    [% bodyclasses.push(&quot;bz_group_$group.name&quot;) %]
-  [% END %]
-  [% PROCESS global/header.html.tmpl
-    title = &quot;$terms.Bug $bug.bug_id &amp;ndash; $filtered_desc&quot;
-    header = &quot;$terms.Bug&amp;nbsp;$bug.bug_id&quot;
-    subheader = filtered_desc
-    header_addl_info = &quot;Last modified: $filtered_timestamp&quot;
-    bodyclasses = bodyclasses
-    javascript_urls = [ &quot;js/util.js&quot;, &quot;js/field.js&quot;,
-                        &quot;js/yui/yahoo-dom-event.js&quot;, &quot;js/yui/calendar.js&quot; ]
-    style_urls = [ &quot;skins/standard/yui/calendar.css&quot;, &quot;skins/standard/show_bug.css&quot; ]
-    doc_section = &quot;bug_page.html&quot;
-  %]
</del><ins>+  [% PROCESS &quot;bug/show-header.html.tmpl&quot; %]
+  [% PROCESS global/header.html.tmpl %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% IF nextbug %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultbugshowxmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/bug/show.xml.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/bug/show.xml.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/bug/show.xml.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -25,9 +25,13 @@
</span><span class="cx"> 
</span><span class="cx"> &lt;bugzilla version=&quot;[% constants.BUGZILLA_VERSION %]&quot;
</span><span class="cx">           urlbase=&quot;[% urlbase FILTER xml %]&quot;
</span><ins>+          [%# Note that the maintainer's email is not filtered, 
+            # intentionally. Even logged-out users should be able
+            # to see that, since it will be in error messages anyway. 
+          %]
</ins><span class="cx">           maintainer=&quot;[% Param('maintainer') FILTER xml %]&quot;
</span><span class="cx"> [% IF user.id %]
</span><del>-          exporter=&quot;[% user.email FILTER xml %]&quot;
</del><ins>+          exporter=&quot;[% user.email FILTER email FILTER xml %]&quot;
</ins><span class="cx"> [% END %]
</span><span class="cx"> &gt;
</span><span class="cx"> 
</span><span class="lines">@@ -53,70 +57,56 @@
</span><span class="cx">       [% IF displayfields.group %]
</span><span class="cx">         [% FOREACH g = bug.groups %]
</span><span class="cx">           [% NEXT UNLESS g.ison %]
</span><del>-          &lt;group&gt;[% g.name FILTER xml %]&lt;/group&gt;
</del><ins>+          &lt;group id=&quot;[% g.bit FILTER xml %]&quot;&gt;[% g.name FILTER xml %]&lt;/group&gt;
</ins><span class="cx">         [% END %]
</span><span class="cx">       [% END %]
</span><span class="cx"> 
</span><span class="cx">       [%# Bug Flags %]
</span><del>-      [% FOREACH type = bug.flag_types %]
-        [% FOREACH flag = type.flags %]
-          &lt;flag name=&quot;[% type.name FILTER xml %]&quot;
-                id=&quot;[% flag.id FILTER xml %]&quot;
-                status=&quot;[% flag.status FILTER xml %]&quot;
-                setter=&quot;[% flag.setter.login FILTER xml %]&quot;
-          [% IF flag.requestee %]
-              requestee=&quot;[% flag.requestee.login FILTER xml %]&quot;
-          [% END %]
-          /&gt;
-        [% END %]
-      [% END %]
</del><ins>+      [% PROCESS section_flags obj =&gt; bug %]
+
</ins><span class="cx">       [% IF displayfields.long_desc %]
</span><del>-        [% FOREACH c = bug.longdescs %]
-          [% NEXT IF c.isprivate &amp;&amp; !user.in_group(Param(&quot;insidergroup&quot;)) %]
-          &lt;long_desc isprivate=&quot;[% c.isprivate FILTER xml %]&quot;&gt;
-            &lt;who name=&quot;[% c.author.name FILTER xml %]&quot;&gt;[% c.author.email FILTER xml %]&lt;/who&gt;
-            &lt;bug_when&gt;[% c.time FILTER time FILTER xml %]&lt;/bug_when&gt;
-            [% IF user.in_group(Param('timetrackinggroup')) &amp;&amp; (c.work_time - 0 != 0) %]
</del><ins>+        [% FOREACH c = bug.comments %]
+          [% NEXT IF c.is_private &amp;&amp; !user.is_insider %]
+          &lt;long_desc isprivate=&quot;[% c.is_private FILTER xml %]&quot;&gt;
+            &lt;commentid&gt;[% c.id FILTER xml %]&lt;/commentid&gt;
+            [% IF c.is_about_attachment %]
+              &lt;attachid&gt;[% c.extra_data FILTER xml %]&lt;/attachid&gt;
+            [% END %]
+            &lt;who name=&quot;[% c.author.name FILTER xml %]&quot;&gt;[% c.author.email FILTER email FILTER xml %]&lt;/who&gt;
+            &lt;bug_when&gt;[% c.creation_ts FILTER time(&quot;%Y-%m-%d %T %z&quot;) FILTER xml %]&lt;/bug_when&gt;
+            [% IF user.is_timetracker &amp;&amp; (c.work_time - 0 != 0) %]
</ins><span class="cx">               &lt;work_time&gt;[% PROCESS formattimeunit time_unit = c.work_time FILTER xml %]&lt;/work_time&gt;
</span><span class="cx">             [% END %]
</span><del>-            &lt;thetext&gt;[% c.body FILTER xml %]&lt;/thetext&gt;
</del><ins>+            &lt;thetext&gt;[% c.body_full FILTER xml %]&lt;/thetext&gt;
</ins><span class="cx">           &lt;/long_desc&gt;
</span><span class="cx">         [% END %]
</span><span class="cx">       [% END %]
</span><span class="cx">       
</span><span class="cx">       [% IF displayfields.attachment %]
</span><span class="cx">         [% FOREACH a = bug.attachments %]
</span><del>-          [% NEXT IF a.isprivate &amp;&amp; !user.in_group(Param(&quot;insidergroup&quot;)) %]
</del><ins>+          [% NEXT IF a.isprivate &amp;&amp; !user.is_insider %]
</ins><span class="cx">           &lt;attachment
</span><span class="cx">               isobsolete=&quot;[% a.isobsolete FILTER xml %]&quot;
</span><span class="cx">               ispatch=&quot;[% a.ispatch FILTER xml %]&quot;
</span><span class="cx">               isprivate=&quot;[% a.isprivate FILTER xml %]&quot;
</span><span class="cx">           &gt;
</span><span class="cx">             &lt;attachid&gt;[% a.id %]&lt;/attachid&gt;
</span><del>-            &lt;date&gt;[% a.attached FILTER time FILTER xml %]&lt;/date&gt;
</del><ins>+            &lt;date&gt;[% a.attached FILTER time(&quot;%Y-%m-%d %T %z&quot;) FILTER xml %]&lt;/date&gt;
+            &lt;delta_ts&gt;[% a.modification_time FILTER time(&quot;%Y-%m-%d %T %z&quot;) FILTER xml %]&lt;/delta_ts&gt;
</ins><span class="cx">             &lt;desc&gt;[% a.description FILTER xml %]&lt;/desc&gt;
</span><span class="cx">             &lt;filename&gt;[% a.filename FILTER xml %]&lt;/filename&gt;
</span><span class="cx">             &lt;type&gt;[% a.contenttype FILTER xml %]&lt;/type&gt;
</span><span class="cx">             &lt;size&gt;[% a.datasize FILTER xml %]&lt;/size&gt;
</span><del>-            &lt;attacher&gt;[% a.attacher.email FILTER xml %]&lt;/attacher&gt;
</del><ins>+            &lt;attacher&gt;[% a.attacher.email FILTER email FILTER xml %]&lt;/attacher&gt;
</ins><span class="cx">             [%# This is here so automated clients can still use attachment.cgi %]
</span><span class="cx">             [% IF displayfields.token &amp;&amp; user.id %]
</span><span class="cx">               &lt;token&gt;[% issue_hash_token([a.id, a.modification_time]) FILTER xml %]&lt;/token&gt;
</span><span class="cx">             [% END %]
</span><span class="cx">             [% IF displayfields.attachmentdata %]
</span><span class="cx">               &lt;data encoding=&quot;base64&quot;&gt;[% a.data FILTER base64 %]&lt;/data&gt;
</span><del>-            [% END %]        
</del><ins>+            [% END %]
</ins><span class="cx"> 
</span><del>-            [% FOREACH flag = a.flags %]
-              &lt;flag name=&quot;[% flag.type.name FILTER xml %]&quot;
-                    id=&quot;[% flag.id FILTER xml %]&quot;
-                    status=&quot;[% flag.status FILTER xml %]&quot;
-                    setter=&quot;[% flag.setter.email FILTER xml %]&quot;
-                    [% IF flag.status == &quot;?&quot; &amp;&amp; flag.requestee %]
-                      requestee=&quot;[% flag.requestee.email FILTER xml %]&quot;
-                    [% END %]
-               /&gt;
-            [% END %]
</del><ins>+            [% PROCESS section_flags obj =&gt; a %]
</ins><span class="cx">           &lt;/attachment&gt;
</span><span class="cx">         [% END %]
</span><span class="cx">       [% END %]
</span><span class="lines">@@ -130,7 +120,13 @@
</span><span class="cx"> &lt;/bugzilla&gt;
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK bug_field %]
</span><del>-  [% FOREACH val = bug.$field %]
</del><ins>+  [% field_values = bug.$field %]
+  [%# Work around TT bug https://rt.cpan.org/Public/Bug/Display.html?id=9802 %]
+  [% IF bug.$field.size == 1 %]
+    [% field_values = [bug.$field.first] %]
+  [% END %]
+
+  [% FOREACH val = field_values %]
</ins><span class="cx">     [%# We need to handle some fields differently. This should become
</span><span class="cx">       # nicer once we have custfields, and a type attribute for the fields
</span><span class="cx">       #%]
</span><span class="lines">@@ -138,10 +134,31 @@
</span><span class="cx">     [% IF field == 'reporter' OR field == 'assigned_to' OR
</span><span class="cx">           field == 'qa_contact' %]
</span><span class="cx">       [% name = val.name %]
</span><del>-      [% val = val.email %]
</del><ins>+      [% val = val.email FILTER email %]
+    [% ELSIF field == 'cc' %]
+        [% val = val FILTER email %]
</ins><span class="cx">     [% ELSIF field == 'creation_ts' OR field == 'delta_ts' %]
</span><del>-      [% val = val FILTER time %]
</del><ins>+      [% val = val FILTER time(&quot;%Y-%m-%d %T %z&quot;) %]
+    [% ELSIF field == &quot;see_also&quot; %]
+      [% val = val.name %]
</ins><span class="cx">     [% END %]
</span><del>-    &lt;[% field %][% IF name != '' %] name=&quot;[% name FILTER xml %]&quot;[% END -%]&gt;[% val FILTER xml %]&lt;/[% field %]&gt;
</del><ins>+    &lt;[% field %][% IF name != '' %] name=&quot;[% name FILTER xml %]&quot;[% END -%]&gt;
+      [%- val FILTER xml %]&lt;/[% field %]&gt;
</ins><span class="cx">   [% END %]
</span><span class="cx"> [% END %]
</span><ins>+
+[% BLOCK section_flags %]
+  [% RETURN UNLESS displayfields.flag %]
+  
+  [% FOREACH flag = obj.flags %]
+    &lt;flag name=&quot;[% flag.type.name FILTER xml %]&quot;
+          id=&quot;[% flag.id FILTER xml %]&quot;
+          type_id=&quot;[% flag.type_id FILTER xml %]&quot;
+          status=&quot;[% flag.status FILTER xml %]&quot;
+          setter=&quot;[% flag.setter.email FILTER email FILTER xml %]&quot;
+      [% IF flag.status == &quot;?&quot; &amp;&amp; flag.requestee %]
+          requestee=&quot;[% flag.requestee.email FILTER email FILTER xml %]&quot;
+      [% END %]
+    /&gt;
+  [% END %]
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultbugsummarizetimehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/bug/summarize-time.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/bug/summarize-time.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/bug/summarize-time.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -14,8 +14,6 @@
</span><span class="cx">   #                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
</span><span class="cx">   #%]
</span><span class="cx"> 
</span><del>-[% USE date %]
-
</del><span class="cx"> [% PROCESS &quot;global/field-descs.none.tmpl&quot; %]
</span><span class="cx"> 
</span><span class="cx"> [% title = &quot;Time Summary &quot; %]
</span><span class="lines">@@ -34,13 +32,15 @@
</span><span class="cx">     header = header 
</span><span class="cx">     style_urls = [&quot;skins/standard/summarize-time.css&quot;]
</span><span class="cx">     doc_section = &quot;timetracking.html&quot;
</span><ins>+    yui = ['calendar']
+    javascript_urls = [ &quot;js/util.js&quot;, &quot;js/field.js&quot; ]
</ins><span class="cx">     %]
</span><span class="cx"> 
</span><span class="cx"> [% INCLUDE query_form %]
</span><span class="cx"> 
</span><span class="cx"> [% IF do_report %]
</span><span class="cx"> 
</span><del>-  [% global.grand_total = 0 %]
</del><ins>+  [% global.grand_total = 0 global.estimated = 0 global.remaining = 0 %]
</ins><span class="cx"> 
</span><span class="cx">   [% FOREACH workdata = part_list %]
</span><span class="cx">     [%# parts contains date ranges (from, to). %]
</span><span class="lines">@@ -61,6 +61,16 @@
</span><span class="cx">     [% END %]
</span><span class="cx">   [% END %]
</span><span class="cx"> 
</span><ins>+  [% IF detailed %]
+    &lt;h4 style=&quot;margin: 0&quot;&gt;
+      Total of [% global.remaining FILTER format(&quot;%.2f&quot;) %]h remains from
+      original estimate of [% global.estimated FILTER format(&quot;%.2f&quot;) %]h
+      [% IF global.deadline %]
+        (deadline [% global.deadline FILTER html %])
+      [% END %]
+    &lt;/h4&gt;
+  [% END %]
+
</ins><span class="cx">   [% IF monthly %]
</span><span class="cx">     &lt;h4 style=&quot;margin: 0&quot;&gt;Total of [% global.grand_total FILTER format(&quot;%.2f&quot;) %] hours worked&lt;/h4&gt;
</span><span class="cx">     &lt;hr noshade size=&quot;1&quot;&gt;
</span><span class="lines">@@ -103,6 +113,7 @@
</span><span class="cx">     [% col = 0 subtotal = 0%]
</span><span class="cx">     [% FOREACH bugdata=ownerdata.nsort(&quot;bug_id&quot;) %]
</span><span class="cx">         [% bug_id = bugdata.bug_id %]
</span><ins>+        [% INCLUDE calc_bug_total id=bug_id %]
</ins><span class="cx">         [% global.bug_count.$bug_id = 1 %]
</span><span class="cx">         [% IF detailed %]
</span><span class="cx">             [% INCLUDE bug_header cid=col id=bug_id bugdata=bugdata extra=1 %]
</span><span class="lines">@@ -141,6 +152,7 @@
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK do_one_bug %]
</span><span class="cx">     [% subtotal = 0.00 cid = 0 %]
</span><ins>+    [% INCLUDE calc_bug_total id=id %]
</ins><span class="cx">     [% global.bug_count.$id = 1 %]
</span><span class="cx">     [% INCLUDE bug_header id=id %]
</span><span class="cx"> 
</span><span class="lines">@@ -176,14 +188,47 @@
</span><span class="cx">         &lt;td width=&quot;80&quot; valign=&quot;top&quot;&gt;
</span><span class="cx">           &lt;b&gt;[% &quot;$terms.Bug $id&quot; FILTER bug_link(id) FILTER none %]&lt;/b&gt;
</span><span class="cx">         &lt;/td&gt;
</span><del>-        &lt;td width=&quot;100&quot;&gt;&lt;b&gt;[% get_status(bugs.$id.bug_status) FILTER html %]&lt;/b&gt;&lt;/td&gt;
</del><ins>+        &lt;td width=&quot;100&quot;&gt;&lt;b&gt;[% display_value(&quot;bug_status&quot;, bugs.$id.bug_status) FILTER html %]&lt;/b&gt;&lt;/td&gt;
</ins><span class="cx">         &lt;td colspan=&quot;2&quot;&gt;[% bugs.$id.short_desc FILTER html %]&lt;/td&gt;
</span><span class="cx">         [% IF extra %]
</span><span class="cx">           &lt;td align=&quot;right&quot; valign=&quot;top&quot;&gt;[% bugdata.total_time FILTER html %]&lt;/td&gt;
</span><span class="cx">         [% END %]
</span><span class="cx">     &lt;/tr&gt;
</span><ins>+    [% IF detailed %]
+      &lt;tr class=&quot;bug_header[% '2' IF cid % 2 %]&quot;&gt;
+        &lt;td&gt;&amp;nbsp;&lt;/td&gt;
+        &lt;td colspan=&quot;3&quot;&gt;
+          &lt;table width=&quot;100%&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot;&gt;
+            &lt;tr&gt;
+              &lt;td width=&quot;33%&quot;&gt;
+                Estimated: [% bugs.$id.estimated_time FILTER format(&quot;%.2f&quot;) %]h
+              &lt;/td&gt;
+              &lt;td width=&quot;33%&quot;&gt;
+                Remaining: [% bugs.$id.remaining_time FILTER format(&quot;%.2f&quot;) %]h
+              &lt;/td&gt;
+              &lt;td width=&quot;33%&quot;&gt;
+                Deadline: [% bugs.$id.deadline || &quot;&lt;b&gt;Not set&lt;/b&gt;&quot; %]
+              &lt;/td&gt;
+            &lt;/tr&gt;
+          &lt;/table&gt;
+        &lt;/td&gt;
+        [% IF extra %]
+          &lt;td&gt;&amp;nbsp;&lt;/td&gt;
+        [% END %]
+      &lt;/tr&gt;
+   [% END %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><ins>+[% BLOCK calc_bug_total %]
+  [% IF !global.bug_count.$id %]
+    [% global.estimated = global.estimated + bugs.$id.estimated_time %]
+    [% global.remaining = global.remaining + bugs.$id.remaining_time %]
+    [% IF !global.deadline || bugs.$id.deadline &amp;&amp;
+          global.deadline.replace(&quot;-&quot;, &quot;&quot;) &lt; bugs.$id.deadline.replace(&quot;-&quot;, &quot;&quot;) %]
+      [% SET global.deadline = bugs.$id.deadline %]
+    [% END %]
+  [% END %]
+[% END %]
</ins><span class="cx"> 
</span><span class="cx"> [% BLOCK inactive_report %]
</span><span class="cx">     &lt;h3&gt;Inactive [% terms.bugs %]&lt;/h3&gt;
</span><span class="lines">@@ -238,11 +283,23 @@
</span><span class="cx">              for=&quot;start_date&quot;&gt;Period &lt;u&gt;s&lt;/u&gt;tarting&lt;/label&gt;&lt;/b&gt;: 
</span><span class="cx"> &lt;/td&gt;&lt;td colspan=&quot;3&quot;&gt;
</span><span class="cx">   &lt;input type=&quot;text&quot; id=&quot;start_date&quot; name=&quot;start_date&quot; size=&quot;11&quot;
</span><del>-  align=&quot;right&quot; value=&quot;[% start_date FILTER html %]&quot; maxlength=&quot;10&quot;&gt;
</del><ins>+         align=&quot;right&quot; value=&quot;[% start_date FILTER html %]&quot; maxlength=&quot;10&quot;
+         onchange=&quot;updateCalendarFromField(this)&quot;&gt;
+  &lt;button type=&quot;button&quot; class=&quot;calendar_button&quot;
+    id=&quot;button_calendar_start_date&quot;
+    onclick=&quot;showCalendar('start_date')&quot;&gt;&lt;span&gt;Calendar&lt;/span&gt;
+  &lt;/button&gt;
+  &lt;div id=&quot;con_calendar_start_date&quot;&gt;&lt;/div&gt;
</ins><span class="cx">   &amp;nbsp;
</span><span class="cx">   &lt;b&gt;and &lt;label accesskey=&quot;e&quot; for=&quot;end_date&quot;&gt;&lt;u&gt;e&lt;/u&gt;nding&lt;/label&gt;&lt;/b&gt;: 
</span><span class="cx">   &lt;input type=&quot;text&quot; name=&quot;end_date&quot; size=&quot;11&quot; id=&quot;end_date&quot;
</span><del>-  align=&quot;right&quot; value =&quot;[% end_date FILTER html %]&quot; maxlength=&quot;10&quot;&gt;
</del><ins>+         align=&quot;right&quot; value =&quot;[% end_date FILTER html %]&quot; maxlength=&quot;10&quot;
+         onchange=&quot;updateCalendarFromField(this)&quot;&gt;
+  &lt;button type=&quot;button&quot; class=&quot;calendar_button&quot;
+    id=&quot;button_calendar_end_date&quot;
+    onclick=&quot;showCalendar('end_date')&quot;&gt;&lt;span&gt;Calendar&lt;/span&gt;
+  &lt;/button&gt;
+  &lt;div id=&quot;con_calendar_end_date&quot;&gt;&lt;/div&gt;
</ins><span class="cx"> &lt;/td&gt;&lt;td align=&quot;right&quot;&gt;
</span><span class="cx">   &lt;input type=&quot;submit&quot; id=&quot;summarize&quot; value=&quot;Summarize&quot;&gt;
</span><span class="cx"> &lt;/td&gt;&lt;/tr&gt;
</span><span class="lines">@@ -286,7 +343,9 @@
</span><span class="cx"> &lt;/form&gt;
</span><span class="cx"> &lt;script type=&quot;text/javascript&quot;&gt;
</span><span class="cx"> &lt;!--
</span><del>-   document.forms['summary'].start_date.focus()
</del><ins>+  createCalendar('start_date');
+  createCalendar('end_date');
+  document.forms['summary'].start_date.focus();
</ins><span class="cx"> //--&gt;&lt;/script&gt;
</span><span class="cx"> &lt;hr noshade size=1&gt;
</span><span class="cx"> [% END %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultconfigjstmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/config.js.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/config.js.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/config.js.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -61,7 +61,7 @@
</span><span class="cx"> // =============
</span><span class="cx"> 
</span><span class="cx"> [% FOREACH cf = custom_fields %]
</span><del>-var [% cf.name FILTER js %] = [ [% FOREACH x = cf.legal_values %]'[% x FILTER js %]', [% END %] ];
</del><ins>+var [% cf.name FILTER js %] = [ [% FOREACH x = cf.legal_values %]'[% x.name FILTER js %]', [% END %] ];
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultconfigrdftmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/config.rdf.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/config.rdf.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/config.rdf.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -19,6 +19,10 @@
</span><span class="cx">   #                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
</span><span class="cx">   #%]
</span><span class="cx"> 
</span><ins>+[%# The url to the installation is going to be displayed many times.
+  # So we cache it here for better performance.
+ %]
+[% escaped_urlbase = BLOCK %][% urlbase FILTER xml %][% END %]
</ins><span class="cx"> &lt;?xml version=&quot;1.0&quot;[% IF Param('utf8') %] encoding=&quot;UTF-8&quot;[% END %]?&gt;
</span><span class="cx"> &lt;!-- Note: this interface is experimental and under development.
</span><span class="cx">    - We may and probably will make breaking changes to it in the future. --&gt;
</span><span class="lines">@@ -27,7 +31,7 @@
</span><span class="cx">      xmlns:rdf=&quot;http://www.w3.org/1999/02/22-rdf-syntax-ns#&quot;
</span><span class="cx">      xmlns:bz=&quot;http://www.bugzilla.org/rdf#&quot;&gt;
</span><span class="cx"> 
</span><del>-&lt;bz:installation rdf:about=&quot;[% urlbase FILTER xml %]&quot;&gt;
</del><ins>+&lt;bz:installation rdf:about=&quot;[% escaped_urlbase %]&quot;&gt;
</ins><span class="cx">   &lt;bz:install_version&gt;[% constants.BUGZILLA_VERSION FILTER html %]&lt;/bz:install_version&gt;
</span><span class="cx">   &lt;bz:maintainer&gt;[% Param('maintainer') FILTER html %]&lt;/bz:maintainer&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -107,7 +111,7 @@
</span><span class="cx">   &lt;bz:[% cf.name FILTER html %]&gt;
</span><span class="cx">     &lt;Seq&gt;
</span><span class="cx">       [% FOREACH item = cf.legal_values %]
</span><del>-        &lt;li&gt;[% item FILTER html %]&lt;/li&gt;
</del><ins>+        &lt;li&gt;[% item.name FILTER html %]&lt;/li&gt;
</ins><span class="cx">       [% END %]
</span><span class="cx">     &lt;/Seq&gt;
</span><span class="cx">   &lt;/bz:[% cf.name FILTER html %]&gt;
</span><span class="lines">@@ -118,14 +122,15 @@
</span><span class="cx">     &lt;Seq&gt;
</span><span class="cx">       [% FOREACH product = products %]
</span><span class="cx">         &lt;li&gt;
</span><del>-          &lt;bz:product rdf:about=&quot;[% urlbase FILTER xml %]product.cgi?name=[% product.name FILTER url_quote %]&quot;&gt;
</del><ins>+          &lt;bz:product rdf:about=&quot;[% escaped_urlbase %]product.cgi?name=[% product.name FILTER uri %]&quot;&gt;
</ins><span class="cx">             &lt;bz:name&gt;[% product.name FILTER html %]&lt;/bz:name&gt;
</span><ins>+            &lt;bz:allows_unconfirmed&gt;[% product.allows_unconfirmed FILTER html %]&lt;/bz:allows_unconfirmed&gt;
</ins><span class="cx"> 
</span><span class="cx">             &lt;bz:components&gt;
</span><span class="cx">               &lt;Seq&gt;
</span><span class="cx">                 [% FOREACH component = product.components %]
</span><del>-                  &lt;li resource=&quot;[% urlbase FILTER xml %]component.cgi?name=[% component.name FILTER url_quote 
-                      %]&amp;amp;product=[% product.name FILTER url_quote %]&quot;/&gt;
</del><ins>+                  &lt;li resource=&quot;[% escaped_urlbase %]component.cgi?name=[% component.name FILTER uri
+                      %]&amp;amp;product=[% product.name FILTER uri %]&quot;/&gt;
</ins><span class="cx">                 [% END %]
</span><span class="cx">               &lt;/Seq&gt;
</span><span class="cx">             &lt;/bz:components&gt;
</span><span class="lines">@@ -133,7 +138,7 @@
</span><span class="cx">             &lt;bz:versions&gt;
</span><span class="cx">               &lt;Seq&gt;
</span><span class="cx">                 [% FOREACH version = product.versions %]
</span><del>-                  &lt;li resource=&quot;[% urlbase FILTER xml %]version.cgi?name=[% version.name FILTER url_quote %]&quot;/&gt;
</del><ins>+                  &lt;li resource=&quot;[% escaped_urlbase %]version.cgi?name=[% version.name FILTER uri %]&quot;/&gt;
</ins><span class="cx">                 [% END %]
</span><span class="cx">               &lt;/Seq&gt;
</span><span class="cx">             &lt;/bz:versions&gt;
</span><span class="lines">@@ -142,7 +147,7 @@
</span><span class="cx">               &lt;bz:target_milestones&gt;
</span><span class="cx">                 &lt;Seq&gt;
</span><span class="cx">                   [% FOREACH milestone = product.milestones %]
</span><del>-                    &lt;li resource=&quot;[% urlbase FILTER xml %]milestone.cgi?name=[% milestone.name FILTER url_quote %]&quot;/&gt;
</del><ins>+                    &lt;li resource=&quot;[% escaped_urlbase %]milestone.cgi?name=[% milestone.name FILTER uri %]&quot;/&gt;
</ins><span class="cx">                   [% END %]
</span><span class="cx">                 &lt;/Seq&gt;
</span><span class="cx">               &lt;/bz:target_milestones&gt;
</span><span class="lines">@@ -160,20 +165,22 @@
</span><span class="cx">       [% FOREACH product = products %]
</span><span class="cx">         [% FOREACH component = product.components %]
</span><span class="cx">           &lt;li&gt;
</span><del>-            &lt;bz:component rdf:about=&quot;[% urlbase FILTER xml %]component.cgi?name=[% component.name FILTER url_quote 
-                          %]&amp;amp;product=[% product.name FILTER url_quote %]&quot;&gt;
</del><ins>+            &lt;bz:component rdf:about=&quot;[% escaped_urlbase %]component.cgi?name=[% component.name FILTER uri
+                          %]&amp;amp;product=[% product.name FILTER uri %]&quot;&gt;
</ins><span class="cx">               &lt;bz:name&gt;[% component.name FILTER html %]&lt;/bz:name&gt;
</span><del>-              &lt;bz:flag_types&gt;
-                &lt;Seq&gt;
-                  [% flag_types = component.flag_types.bug.merge(component.flag_types.attachment) %]
-                  [% FOREACH flag_type = flag_types %]
-                    [% NEXT UNLESS flag_type.is_active %]
-                    [% all_visible_flag_types.${flag_type.id} = flag_type %]
-                    &lt;li resource=&quot;[% urlbase FILTER xml %]flags.cgi?id=[% flag_type.id FILTER url_quote
-                        %]&amp;amp;name=[% flag_type.name FILTER url_quote %]&quot; /&gt;
-                  [% END %]
-                &lt;/Seq&gt;
-              &lt;/bz:flag_types&gt;
</del><ins>+              [% IF show_flags %]
+                &lt;bz:flag_types&gt;
+                  &lt;Seq&gt;
+                    [% flag_types = component.flag_types.bug.merge(component.flag_types.attachment) %]
+                    [% FOREACH flag_type = flag_types %]
+                      [% NEXT UNLESS flag_type.is_active %]
+                      [% all_visible_flag_types.${flag_type.id} = flag_type %]
+                      &lt;li resource=&quot;[% escaped_urlbase %]flag.cgi?id=[% flag_type.id FILTER uri
+                          %]&amp;amp;name=[% flag_type.name FILTER uri %]&quot; /&gt;
+                    [% END %]
+                  &lt;/Seq&gt;
+                &lt;/bz:flag_types&gt;
+              [% END %]
</ins><span class="cx">             &lt;/bz:component&gt;
</span><span class="cx">           &lt;/li&gt;
</span><span class="cx">         [% END %]
</span><span class="lines">@@ -186,7 +193,7 @@
</span><span class="cx">       [% FOREACH product = products %]
</span><span class="cx">         [% FOREACH version = product.versions %]
</span><span class="cx">           &lt;li&gt;
</span><del>-            &lt;bz:version rdf:about=&quot;[% urlbase FILTER xml %]version.cgi?name=[% version.name FILTER url_quote %]&quot;&gt;
</del><ins>+            &lt;bz:version rdf:about=&quot;[% escaped_urlbase %]version.cgi?name=[% version.name FILTER uri %]&quot;&gt;
</ins><span class="cx">               &lt;bz:name&gt;[% version.name FILTER html %]&lt;/bz:name&gt;
</span><span class="cx">             &lt;/bz:version&gt;
</span><span class="cx">           &lt;/li&gt;
</span><span class="lines">@@ -201,7 +208,7 @@
</span><span class="cx">         [% FOREACH product = products %]
</span><span class="cx">           [% FOREACH milestone = product.milestones %]
</span><span class="cx">             &lt;li&gt;
</span><del>-              &lt;bz:target_milestone rdf:about=&quot;[% urlbase FILTER xml %]milestone.cgi?name=[% milestone.name FILTER url_quote %]&quot;&gt;
</del><ins>+              &lt;bz:target_milestone rdf:about=&quot;[% escaped_urlbase %]milestone.cgi?name=[% milestone.name FILTER uri %]&quot;&gt;
</ins><span class="cx">                 &lt;bz:name&gt;[% milestone.name FILTER html %]&lt;/bz:name&gt;
</span><span class="cx">               &lt;/bz:target_milestone&gt;
</span><span class="cx">             &lt;/li&gt;
</span><span class="lines">@@ -211,31 +218,37 @@
</span><span class="cx">     &lt;/bz:target_milestones&gt;
</span><span class="cx">   [% END %]
</span><span class="cx"> 
</span><del>-  &lt;bz:flag_types&gt;
-    &lt;Seq&gt;
-      [% FOREACH flag_type = all_visible_flag_types.values.sort('name') %]
-        &lt;li&gt;
-          &lt;bz:flag_type rdf:about=&quot;[% urlbase FILTER xml %]flag.cgi?id=[% flag_type.id FILTER url_quote
-                        %]&amp;amp;name=[% flag_type.name FILTER url_quote %]&quot;&gt;
-            &lt;bz:id&gt;[% flag_type.id FILTER html %]&lt;/bz:id&gt;
-            &lt;bz:name&gt;[% flag_type.name FILTER html %]&lt;/bz:name&gt;
-            &lt;bz:description&gt;[% flag_type.description FILTER html %]&lt;/bz:description&gt;
-            &lt;bz:type&gt;[% flag_type.target_type FILTER html %]&lt;/bz:type&gt;
-            &lt;bz:requestable&gt;[% flag_type.is_requestable FILTER html %]&lt;/bz:requestable&gt;
-            &lt;bz:specifically_requestable&gt;[% flag_type.is_requesteeble FILTER html %]&lt;/bz:specifically_requestable&gt;
-            &lt;bz:multiplicable&gt;[% flag_type.is_multiplicable FILTER html %]&lt;/bz:multiplicable&gt;
-          &lt;/bz:flag_type&gt;
-        &lt;/li&gt;
-      [% END %]
-    &lt;/Seq&gt;
-  &lt;/bz:flag_types&gt;
</del><ins>+  [% IF show_flags %]
+    &lt;bz:flag_types&gt;
+      &lt;Seq&gt;
+        [% FOREACH flag_type = all_visible_flag_types.values.sort('name') %]
+          &lt;li&gt;
+            &lt;bz:flag_type rdf:about=&quot;[% escaped_urlbase %]flag.cgi?id=[% flag_type.id FILTER uri
+                          %]&amp;amp;name=[% flag_type.name FILTER uri %]&quot;&gt;
+              &lt;bz:id&gt;[% flag_type.id FILTER html %]&lt;/bz:id&gt;
+              &lt;bz:name&gt;[% flag_type.name FILTER html %]&lt;/bz:name&gt;
+              &lt;bz:description&gt;[% flag_type.description FILTER html %]&lt;/bz:description&gt;
+              &lt;bz:type&gt;[% flag_type.target_type FILTER html %]&lt;/bz:type&gt;
+              &lt;bz:requestable&gt;[% flag_type.is_requestable FILTER html %]&lt;/bz:requestable&gt;
+              &lt;bz:specifically_requestable&gt;[% flag_type.is_requesteeble FILTER html %]&lt;/bz:specifically_requestable&gt;
+              &lt;bz:multiplicable&gt;[% flag_type.is_multiplicable FILTER html %]&lt;/bz:multiplicable&gt;
+              [% IF user.in_group(&quot;editcomponents&quot;) %]
+                &lt;bz:grant_group&gt;[% flag_type.grant_group.name FILTER html %]&lt;/bz:grant_group&gt;
+                &lt;bz:request_group&gt;[% flag_type.request_group.name FILTER html %]&lt;/bz:request_group&gt;
+              [% END %]
+            &lt;/bz:flag_type&gt;
+          &lt;/li&gt;
+        [% END %]
+      &lt;/Seq&gt;
+    &lt;/bz:flag_types&gt;
+  [% END %]
</ins><span class="cx"> 
</span><span class="cx">   &lt;bz:fields&gt;
</span><span class="cx">     &lt;Seq&gt;
</span><span class="cx">       [% PROCESS &quot;global/field-descs.none.tmpl&quot; %]
</span><span class="cx">       [% FOREACH item = field %]
</span><span class="cx">         &lt;li&gt;
</span><del>-          &lt;bz:field rdf:about=&quot;[% urlbase FILTER xml %]field.cgi?name=[% item.name FILTER url_quote %]&quot;&gt;
</del><ins>+          &lt;bz:field rdf:about=&quot;[% escaped_urlbase %]field.cgi?name=[% item.name FILTER uri %]&quot;&gt;
</ins><span class="cx">             &lt;bz:name&gt;[% item.name FILTER html %]&lt;/bz:name&gt;
</span><span class="cx">             &lt;bz:description&gt;[% (field_descs.${item.name} OR item.description) FILTER html %]&lt;/bz:description&gt;
</span><span class="cx">             [%-# These values are meaningful for custom fields only. %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultemailbugmailcommontxttmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/email/bugmail-common.txt.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/email/bugmail-common.txt.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/email/bugmail-common.txt.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,38 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Guy Pyrzak
+  # Portions created by the Initial Developer are Copyright (C) 2010 the
+  # Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s): Guy Pyrzak &lt;guy.pyrzak@gmail.com&gt;
+  #%]
+  
+[% PROCESS &quot;global/field-descs.none.tmpl&quot; %]
+
+[% field_label = field_descs.${change.field_name} %]
+[% old_value = display_value(change.field_name, change.old) %]
+[% new_value = display_value(change.field_name, change.new) %]
+
+[% IF change.field_name == &quot;estimated_time&quot; || change.field_name == &quot;remaining_time&quot; %]
+  [% old_value = old_value FILTER format('%.2f') %]
+  [% new_value = new_value FILTER format('%.2f') %]
+[% END %]
+
+[% IF change.attach_id %]
+  [% field_label = field_label.replace('^(Attachment )?', &quot;Attachment #${change.attach_id} &quot;) %]
+[% END %]
+
+[% IF change.field_name == 'longdescs.isprivate' %]
+  [% field_label = field_label.replace('^(Comment )?', &quot;Comment #${change.num} &quot;) %]
+[% END %]
+  
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultemailbugmailheadertxttmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/email/bugmail-header.txt.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/email/bugmail-header.txt.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/email/bugmail-header.txt.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,47 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Netscape Communications
+  # Corporation. Portions created by Netscape are
+  # Copyright (C) 1998 Netscape Communications Corporation. All
+  # Rights Reserved.
+  #
+  # Contributor(s): André Batosti &lt;batosti@async.com.br&gt;
+  #                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
+  #                 Guy Pyrzak &lt;guy.pyrzak@gmail.com&gt;
+  #%]
+  
+[% PROCESS &quot;global/field-descs.none.tmpl&quot; %]
+[% PROCESS &quot;global/reason-descs.none.tmpl&quot; %]
+[% isnew = bug.lastdiffed ? 0 : 1 %]
+
+From: [% Param('mailfrom') %]
+To: [% to_user.email %]
+Subject: [[% terms.Bug %] [%+ bug.id %]] [% 'New: ' IF isnew %][%+ bug.short_desc %]
+Date: [% date %]
+X-Bugzilla-Reason: [% reasonsheader %]
+X-Bugzilla-Type: [% isnew ? 'new' : 'changed' %]
+X-Bugzilla-Watch-Reason: [% reasonswatchheader %]
+[% IF Param('useclassification') %]
+X-Bugzilla-Classification: [% bug.classification %]
+[% END %]
+X-Bugzilla-Product: [% bug.product %]
+X-Bugzilla-Component: [% bug.component %]
+X-Bugzilla-Keywords: [% bug.keywords %]
+X-Bugzilla-Severity: [% bug.bug_severity %]
+X-Bugzilla-Who: [% changer.login %]
+X-Bugzilla-Status: [% bug.bug_status %]
+X-Bugzilla-Priority: [% bug.priority %]
+X-Bugzilla-Assigned-To: [% bug.assigned_to.login %]
+X-Bugzilla-Target-Milestone: [% bug.target_milestone %]
+X-Bugzilla-Changed-Fields: [% changedfields.join(&quot; &quot;) %]
+[%+ threadingmarker %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultemailbugmailhtmltmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/email/bugmail.html.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/email/bugmail.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/email/bugmail.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,128 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Guy Pyrzak
+  # Portions created by the Initial Developer are Copyright (C) 2010 the
+  # Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s): Guy Pyrzak &lt;guy.pyrzak@gmail.com&gt;
+  #%]
+  
+[% PROCESS &quot;global/field-descs.none.tmpl&quot; %]
+[% PROCESS &quot;global/reason-descs.none.tmpl&quot; %]
+
+[% isnew = bug.lastdiffed ? 0 : 1 %]
+&lt;html&gt;
+    &lt;head&gt;
+      &lt;base href=&quot;[% urlbase FILTER html %]&quot; /&gt;
+    &lt;/head&gt;
+    &lt;body&gt;
+      [% PROCESS generate_diffs %]
+      &lt;p&gt;
+      [% FOREACH comment = new_comments.reverse %]
+        &lt;div&gt;
+          [% IF comment.count %]
+            &lt;b&gt;[% &quot;Comment # ${comment.count}&quot; FILTER bug_link( bug, 
+              {comment_num =&gt; comment.count, full_url =&gt; 1}) FILTER none %] 
+              from [% INCLUDE global/user.html.tmpl who = comment.author %]&lt;/b&gt;
+          [% END %]
+        &lt;pre&gt;[% comment.body_full({ wrap =&gt; 1 }) FILTER quoteUrls(bug, comment) %]&lt;/pre&gt;
+        &lt;/div&gt;
+      [% END %]
+      &lt;/p&gt;
+      &lt;hr&gt;
+      &lt;span&gt;You are receiving this mail because:&lt;/span&gt;
+      
+      &lt;ul&gt;
+      [% FOREACH reason = reasons %]
+        [%  IF reason_descs.$reason  %]
+          &lt;li&gt;[% reason_descs.$reason FILTER html %]&lt;/li&gt;
+        [% END %]
+      [% END %]
+      [% FOREACH reason = reasons_watch %]
+        [% IF watch_reason_descs.$reason %]
+          &lt;li&gt;[% watch_reason_descs.$reason FILTER html %]&lt;/li&gt;
+        [% END %]
+      [% END %]
+      &lt;/ul&gt;
+    &lt;/body&gt;
+&lt;/html&gt;
+
+[% BLOCK generate_diffs %]
+  [% SET in_table = 0 %]
+  [% last_changer = 0 %]
+    [% FOREACH change = diffs %]
+      [% IF !isnew &amp;&amp; changer.id != last_changer %]
+        [% last_changer = changer.id %]
+        [% IF in_table == 1 %]
+          &lt;/table&gt;
+          [% SET in_table = 0 %]
+        [% END %]
+        [% IF change.blocker %]
+              [% &quot;${terms.Bug} ${bug.id}&quot; FILTER bug_link(bug, full_url =&gt; 1) FILTER none  %] depends 
+              on [% &quot;${terms.bug} ${change.blocker.id}&quot; 
+                  FILTER bug_link(change.blocker, full_url =&gt; 1) FILTER none %],
+              which changed state.
+        [% ELSE %]
+              [% INCLUDE global/user.html.tmpl who = change.who %]
+              changed [% &quot;${terms.Bug} ${bug.id}&quot; FILTER bug_link(bug, full_url =&gt; 1) FILTER none %]
+        [% END %]
+        &lt;br&gt;
+          [% IF in_table == 0 %]
+             &lt;table border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;8&quot;&gt;
+             [% SET in_table = 1 %]
+          [% END %]
+          &lt;tr&gt;
+            &lt;th&gt;What&lt;/th&gt;
+            &lt;th&gt;Removed&lt;/th&gt;
+            &lt;th&gt;Added&lt;/th&gt;
+          &lt;/tr&gt;
+      [% END %]
+
+      [% PROCESS &quot;email/bugmail-common.txt.tmpl&quot; %]
+      [% IF in_table == 0 %]
+         &lt;table border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;8&quot;&gt;
+         [% SET in_table = 1 %]
+      [% END %]
+      [% IF isnew %]
+        &lt;tr&gt;
+          &lt;th&gt;[% field_label FILTER html %]&lt;/th&gt;
+          &lt;td&gt;
+            [% IF change.field_name == &quot;bug_id&quot; %]
+              [% new_value FILTER bug_link(bug, full_url =&gt; 1) FILTER none %]
+            [% ELSE %]
+              [% new_value FILTER html %]
+            [% END %]
+          &lt;/td&gt;
+        &lt;/tr&gt;
+      [% ELSE %]
+         &lt;tr&gt;
+           &lt;td style=&quot;text-align:right;&quot;&gt;[% field_label FILTER html %]&lt;/td&gt;
+           &lt;td&gt;
+             [% IF old_value %]
+               [% old_value FILTER html %]
+             [% ELSE %]
+               &amp;nbsp;
+             [% END%]
+           &lt;/td&gt;
+           &lt;td&gt;
+             [% IF new_value %]
+               [% new_value FILTER html %]
+             [% ELSE %]
+               &amp;nbsp;
+             [% END%]
+           &lt;/td&gt;
+         &lt;/tr&gt;
+      [% END %]
+    [% END %]
+  [% '&lt;/table&gt;' IF in_table %]
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultemailbugmailtxttmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/email/bugmail.txt.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/email/bugmail.txt.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/email/bugmail.txt.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,76 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Netscape Communications
+  # Corporation. Portions created by Netscape are
+  # Copyright (C) 1998 Netscape Communications Corporation. All
+  # Rights Reserved.
+  #
+  # Contributor(s): André Batosti &lt;batosti@async.com.br&gt;
+  #                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
+  #                 Guy Pyrzak &lt;guy.pyrzak@gmail.com&gt;
+  #%]
+
+[% PROCESS &quot;global/field-descs.none.tmpl&quot; %]
+[% PROCESS &quot;global/reason-descs.none.tmpl&quot; %]
+
+[% isnew = bug.lastdiffed ? 0 : 1 %]
+
+[%+ PROCESS generate_diffs -%]
+
+[% FOREACH comment = new_comments %]
+
+[%- IF comment.count %]
+--- Comment #[% comment.count %] from [% comment.author.identity %] ---
+[% END %]
+[%+ comment.body_full({ is_bugmail =&gt; 1, wrap =&gt; 1 }) %]
+[% END %]
+
+-- [%# Protect the trailing space of the signature marker %]
+You are receiving this mail because:
+[% SET reason_lines = [] %]
+[% FOREACH reason = reasons %]
+  [% reason_lines.push(reason_descs.$reason) IF reason_descs.$reason %]
+[% END %]
+[% FOREACH reason = reasons_watch %]
+  [% reason_lines.push(watch_reason_descs.$reason)
+       IF watch_reason_descs.$reason %]
+[% END %]
+[%+ reason_lines.join(&quot;\n&quot;) %]
+
+[% BLOCK generate_diffs %]
+  [% urlbase %]show_bug.cgi?id=[% bug.id %]
+
+[%+ last_changer = 0 %]
+  [% FOREACH change = diffs %]
+    [% IF !isnew &amp;&amp; changer.id != last_changer %]
+      [% last_changer = changer.id %]
+      [% IF change.blocker %]
+        [% terms.Bug %] [%+ bug.id %] depends on [% terms.bug %] [%+ change.blocker.id %], which changed state.
+
+[%+ terms.Bug %] [%+ change.blocker.id %] Summary: [% change.blocker.short_desc %]
+[%+ urlbase %]show_bug.cgi?id=[% change.blocker.id %]
+      [% ELSE %]
+        [%~ changer.identity %] changed:
+      [% END %]
+
+           What    |Removed                     |Added
+----------------------------------------------------------------------------
+[%+ END %][%# End of IF. This indentation is intentional! ~%]
+    [% PROCESS &quot;email/bugmail-common.txt.tmpl&quot;%]
+    [%~ IF isnew %]
+      [% format_columns(2, field_label _ &quot;:&quot;, new_value) -%]
+    [% ELSE %]
+      [% format_columns(3, field_label, old_value, new_value) -%]
+    [% END %]
+  [% END -%]
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultemaillockouttxttmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/email/lockout.txt.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/email/lockout.txt.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/email/lockout.txt.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,39 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is the Mozilla Corporation.
+  # Portions created by the Initial Developer are Copyright (C) 2008
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s):
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+From: [% Param('mailfrom') %]
+To: [% Param('maintainer') %]
+Subject: [[% terms.Bugzilla %]] Account Lock-Out: [% locked_user.login %] ([% attempts.0.ip_addr %])
+X-Bugzilla-Type: admin
+
+The IP address [% attempts.0.ip_addr %] failed too many login attempts (
+[%- constants.MAX_LOGIN_ATTEMPTS +%]) for
+the account [% locked_user.login %]. 
+
+The login attempts occurred at these times:
+
+[% FOREACH login = attempts %]
+  [%+ login.login_time FILTER time %]
+[% END %]
+
+This IP will be able to log in again using this account at
+[%+ unlock_at FILTER time %].
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultemailnewchangedmailtxttmpl"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/template/en/default/email/newchangedmail.txt.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/email/newchangedmail.txt.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/email/newchangedmail.txt.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,79 +0,0 @@
</span><del>-[%# The contents of this file are subject to the Mozilla Public
-  # License Version 1.1 (the &quot;License&quot;); you may not use this file
-  # except in compliance with the License. You may obtain a copy of
-  # the License at http://www.mozilla.org/MPL/
-  #
-  # Software distributed under the License is distributed on an &quot;AS
-  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
-  # implied. See the License for the specific language governing
-  # rights and limitations under the License.
-  #
-  # The Original Code is the Bugzilla Bug Tracking System.
-  #
-  # The Initial Developer of the Original Code is Netscape Communications
-  # Corporation. Portions created by Netscape are
-  # Copyright (C) 1998 Netscape Communications Corporation. All
-  # Rights Reserved.
-  #
-  # Contributor(s): André Batosti &lt;batosti@async.com.br&gt;
-  #%]
-
-[% PROCESS &quot;global/variables.none.tmpl&quot; %]
-From: [% Param('mailfrom') %]
-To: [% to %]
-Subject: [[% terms.Bug %] [%+ bugid %]] [% 'New: ' IF isnew %][%+ summary %]
-X-Bugzilla-Reason: [% reasonsheader %]
-X-Bugzilla-Type: newchanged
-X-Bugzilla-Watch-Reason: [% reasonswatchheader %]
-[% IF Param('useclassification') %]
-X-Bugzilla-Classification: [% classification %]
-[% END %]
-X-Bugzilla-Product: [% product %]
-X-Bugzilla-Component: [% comp %]
-X-Bugzilla-Keywords: [% keywords %]
-X-Bugzilla-Severity: [% severity %]
-X-Bugzilla-Who: [% changer %]
-X-Bugzilla-Status: [% status %]
-X-Bugzilla-Priority: [% priority %]
-X-Bugzilla-Assigned-To: [% assignedto %]
-X-Bugzilla-Target-Milestone: [% targetmilestone %]
-X-Bugzilla-Changed-Fields: [% changedfields %]
-[%+ threadingmarker %]
-
-[%+ urlbase %]show_bug.cgi?id=[% bugid %]
-
-[%+ diffs %]
-
--- 
-Configure [% terms.bug %]mail: [% urlbase %]userprefs.cgi?tab=email
-------- You are receiving this mail because: -------
-[% FOREACH relationship = reasons %]
-  [% SWITCH relationship %]
-    [% CASE constants.REL_ASSIGNEE %]
-You are the assignee for the [% terms.bug %].
-    [% CASE constants.REL_REPORTER %]
-You reported the [% terms.bug %].
-    [% CASE constants.REL_QA %]
-You are the QA contact for the [% terms.bug %].
-    [% CASE constants.REL_CC %]
-You are on the CC list for the [% terms.bug %].
-    [% CASE constants.REL_VOTER %]
-You are a voter for the [% terms.bug %].
-    [% CASE constants.REL_GLOBAL_WATCHER %]
-You are watching all [% terms.bug %] changes.
-  [% END %]
-[% END %]
-[% FOREACH relationship = reasons_watch %]
-  [% SWITCH relationship %]
-    [% CASE constants.REL_ASSIGNEE %]
-You are watching the assignee of the [% terms.bug %].
-    [% CASE constants.REL_REPORTER %]
-You are watching the reporter.
-    [% CASE constants.REL_QA %]
-You are watching the QA contact of the [% terms.bug %].
-    [% CASE constants.REL_CC %]
-You are watching someone on the CC list of the [% terms.bug %].
-    [% CASE constants.REL_VOTER %]
-You are watching a voter for the [% terms.bug %].
-  [% END %]
-[% END %]
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultemailsanitychecktxttmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/email/sanitycheck.txt.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/email/sanitycheck.txt.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/email/sanitycheck.txt.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -33,4 +33,4 @@
</span><span class="cx"> No errors have been found.
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><del>-[% output FILTER txt %]
</del><ins>+[% output %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultemailvotesremovedtxttmpl"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/template/en/default/email/votes-removed.txt.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/email/votes-removed.txt.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/email/votes-removed.txt.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,55 +0,0 @@
</span><del>-[%# The contents of this file are subject to the Mozilla Public
-  # License Version 1.1 (the &quot;License&quot;); you may not use this file
-  # except in compliance with the License. You may obtain a copy of
-  # the License at http://www.mozilla.org/MPL/
-  #
-  # Software distributed under the License is distributed on an &quot;AS
-  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
-  # implied. See the License for the specific language governing
-  # rights and limitations under the License.
-  #
-  # The Original Code is the Bugzilla Bug Tracking System.
-  #
-  # The Initial Developer of the Original Code is Netscape Communications
-  # Corporation. Portions created by Netscape are
-  # Copyright (C) 1998 Netscape Communications Corporation. All
-  # Rights Reserved.
-  #
-  # Contributor(s): Emmanuel Seyman &lt;eseyman@linagora.com&gt;
-  #%]
-
-[% PROCESS global/variables.none.tmpl %]
-
-From: [% Param('mailfrom') %]
-To: [% to %]
-Subject: [% terms.Bug %] [%+ bugid %] Some or all of your votes have been removed.
-X-Bugzilla-Type: voteremoved
-
-Some or all of your votes have been removed from [% terms.bug %] [%+ bugid %].
-
-You had [% votesold FILTER html %] [%+ IF votesold == 1 %]vote[% ELSE %]votes[% END
-%] on this [% terms.bug %], but [% votesremoved FILTER html %] have been removed.
-
-[% IF votesnew %]
-You still have [% votesnew FILTER html %] [%+ IF votesnew == 1 %]vote[% ELSE %]votes[% END %] on this [% terms.bug %].
-[% ELSE %]
-You have no more votes remaining on this [% terms.bug %].
-[% END %]
-
-Reason:
-[% IF reason == &quot;votes_bug_moved&quot; %]
-  This [% terms.bug %] has been moved to a different product.
-
-[% ELSIF reason == &quot;votes_too_many_per_bug&quot; %]
-  The rules for voting on this product has changed;
-  you had too many votes for a single [% terms.bug %].
-
-[% ELSIF reason == &quot;votes_too_many_per_user&quot; %]
-  The rules for voting on this product has changed; you had
-  too many total votes, so all votes have been removed.
-[% END %]
-
-
-
-[% urlbase %]show_bug.cgi?id=[% bugid %]
-
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultemailwhinetxttmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/email/whine.txt.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/email/whine.txt.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/email/whine.txt.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -30,31 +30,30 @@
</span><span class="cx"> [% terms.bug %] tracking system ([% urlbase %]) that require
</span><span class="cx"> attention.
</span><span class="cx"> 
</span><del>-All of these [% terms.bugs %] are in the [% get_status(&quot;NEW&quot;) %] or
-[% get_status(&quot;REOPENED&quot;) %] state, and have not been
-touched in [% Param(&quot;whinedays&quot;) %] days or more.
</del><ins>+All of these [% terms.bugs %] are in the [% display_value(&quot;bug_status&quot;, &quot;CONFIRMED&quot;) %]
+state, and have not been touched in [% Param(&quot;whinedays&quot;) %] days or more.
</ins><span class="cx"> You need to take a look at them, and decide on an initial action.
</span><span class="cx"> 
</span><span class="cx"> Generally, this means one of three things:
</span><span class="cx"> 
</span><del>-(1) You decide this [% terms.bug %] is really quick to deal with (like, it's [% get_resolution(&quot;INVALID&quot;) %]),
</del><ins>+(1) You decide this [% terms.bug %] is really quick to deal with (like, it's [% display_value(&quot;resolution&quot;, &quot;INVALID&quot;) %]),
</ins><span class="cx">     and so you get rid of it immediately.
</span><span class="cx"> (2) You decide the [% terms.bug %] doesn't belong to you, and you reassign it to
</span><span class="cx">     someone else. (Hint: if you don't know who to reassign it to, make
</span><span class="cx">     sure that the Component field seems reasonable, and then use the
</span><del>-    &quot;Reassign [% terms.bug %] to default assignee of selected component&quot; option.)
</del><ins>+    &quot;Reset Assignee to default&quot; option.)
</ins><span class="cx"> (3) You decide the [% terms.bug %] belongs to you, but you can't solve it this moment.
</span><del>-    Just use the &quot;Accept [% terms.bug %]&quot; command.
</del><ins>+    Accept the [% terms.bug %] by setting the status to [% display_value(&quot;bug_status&quot;, &quot;IN_PROGRESS&quot;) %].
</ins><span class="cx"> 
</span><del>-To get a list of all [% get_status(&quot;NEW&quot;) %]/[% get_status(&quot;REOPENED&quot;) %] [%+ terms.bugs %], you can use this URL (bookmark
</del><ins>+To get a list of all [% display_value(&quot;bug_status&quot;, &quot;CONFIRMED&quot;) %] [%+ terms.bugs %], you can use this URL (bookmark
</ins><span class="cx"> it if you like!):
</span><span class="cx"> 
</span><del>- [% urlbase %]buglist.cgi?bug_status=NEW&amp;bug_status=REOPENED&amp;assigned_to=[% email %]
</del><ins>+ [% urlbase %]buglist.cgi?bug_status=CONFIRMED&amp;assigned_to=[% email %]
</ins><span class="cx"> 
</span><span class="cx"> Or, you can use the general query page, at 
</span><span class="cx"> [%+ urlbase %]query.cgi
</span><span class="cx"> 
</span><del>-Appended below are the individual URLs to get to all of your [% get_status(&quot;NEW&quot;) %] [%+ terms.bugs %]
</del><ins>+Appended below are the individual URLs to get to all of your [% display_value(&quot;bug_status&quot;, &quot;CONFIRMED&quot;) %] [%+ terms.bugs %]
</ins><span class="cx"> that haven't been touched for [% Param(&quot;whinedays&quot;) %] days or more.
</span><span class="cx"> 
</span><span class="cx"> You will get this message once a day until you've dealt with these [% terms.bugs %]!
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultextensionsconfigpmtmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/extensions/config.pm.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/extensions/config.pm.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/extensions/config.pm.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,41 @@
</span><ins>+[%# -*- mode: perl -*- %]
+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2009 the
+  # Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s):
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[%# INTERFACE:
+  # name: string; The name of the extension.
+  #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% PROCESS extensions/license.txt.tmpl %]
+
+package B[% %]ugzilla::Extension::[% name %];
+use strict;
+
+use constant NAME =&gt; '[% name %]';
+
+use constant REQUIRED_MODULES =&gt; [
+];
+
+use constant OPTIONAL_MODULES =&gt; [
+];
+
+__PACKAGE__-&gt;NAME;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultextensionsextensionpmtmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/extensions/extension.pm.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/extensions/extension.pm.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/extensions/extension.pm.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,46 @@
</span><ins>+[%# -*- mode: perl -*- %]
+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2009 the
+  # Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s):
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[%# INTERFACE:
+  # name: string; The name of the extension.
+  #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% PROCESS extensions/license.txt.tmpl %]
+
+package B[% %]ugzilla::Extension::[% name %];
+use strict;
+use base qw(B[% %]ugzilla::Extension);
+
+# This code for this is in [% path %]/lib/Util.pm
+use B[% %]ugzilla::Extension::[% name %]::Util;
+
+our $VERSION = '0.01';
+
+# See the documentation of B[% %]ugzilla::Hook (&quot;perldoc B[% %]ugzilla::Hook&quot; 
+# in the bugzilla directory) for a list of all available hooks.
+sub install_update_db {
+    my ($self, $args) = @_;
+
+}
+
+__PACKAGE__-&gt;NAME;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultextensionshookreadmetxttmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/extensions/hook-readme.txt.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/extensions/hook-readme.txt.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/extensions/hook-readme.txt.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,27 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2009 the
+  # Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s):
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+Template hooks go in this directory. Template hooks are called in normal
+[%+ terms.Bugzilla %] templates like [[% '%' %] Hook.process('some-hook') %].
+More information about them can be found in the documentation of 
+B[% %]ugzilla::Extension. (Do &quot;perldoc B[% %]ugzilla::Extension&quot; from the main
+[%+ terms.Bugzilla %] directory to see that documentation.)
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultextensionslicensetxttmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/extensions/license.txt.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/extensions/license.txt.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/extensions/license.txt.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,47 @@
</span><ins>+[%# -*- mode: perl -*- %]
+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2009 the
+  # Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s):
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[%# INTERFACE:
+  # name: string; The name of the extension.
+  #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the [% name %] [%+ terms.Bugzilla %] Extension.
+#
+# The Initial Developer of the Original Code is YOUR NAME
+# Portions created by the Initial Developer are Copyright (C) [% year %] the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   YOUR NAME &lt;YOUR EMAIL ADDRESS&gt;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultextensionsnamereadmetxttmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/extensions/name-readme.txt.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/extensions/name-readme.txt.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/extensions/name-readme.txt.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,38 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2009 the
+  # Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s):
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+Normal templates go in this directory. You can load them in your
+code like this:
+
+use B[% %]ugzilla::Error;
+my $template = B[% %]ugzilla-&gt;template;
+$template-&gt;process('[% name FILTER lower %]/some-template.html.tmpl')
+  or ThrowTemplateError($template-&gt;error());
+
+That would be how to load a file called some-template.html.tmpl that
+was in this directory.
+
+Note that you have to be careful that the full path of your template
+never conflicts with a template that exists in [% terms.Bugzilla %] or in 
+another extension, or your template might override that template. That's why
+we created this directory called '[% name FILTER lower %]' for you, so you
+can put your templates in here to help avoid conflicts.
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultextensionsutilpmtmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/extensions/util.pm.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/extensions/util.pm.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/extensions/util.pm.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,42 @@
</span><ins>+[%# -*- mode: perl -*- %]
+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2009 the
+  # Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s):
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[%# INTERFACE:
+  # name: string; The name of the extension.
+  #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+[% PROCESS extensions/license.txt.tmpl %]
+
+package B[% %]ugzilla::Extension::[% name %]::Util;
+use strict;
+use base qw(Exporter);
+our @EXPORT = qw(
+    
+);
+
+# This file can be loaded by your extension via 
+# &quot;use B[% %]ugzilla::Extension::[% name %]::Util&quot;. You can put functions
+# used by your extension in here. (Make sure you also list them in
+# @EXPORT.)
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultextensionswebreadmetxttmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/extensions/web-readme.txt.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/extensions/web-readme.txt.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/extensions/web-readme.txt.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,29 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2010 the
+  # Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s):
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[% PROCESS global/variables.none.tmpl %]
+
+Web-accessible files, like JavaScript, CSS, and images go in this
+directory. You can reference them directly in your HTML. For example,
+if you have a file called &quot;style.css&quot; and your extension is called
+&quot;Foo&quot;, you would put it in &quot;extensions/Foo/web/style.css&quot;, and then
+you could link to it in HTML like:
+
+&lt;link href=&quot;extensions/Foo/web/style.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot;&gt;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultfilterexceptionspl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/filterexceptions.pl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/filterexceptions.pl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/filterexceptions.pl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -34,7 +34,7 @@
</span><span class="cx"> #                                   [% foo.push() %]
</span><span class="cx"> # TT loop variables               - [% loop.count %]
</span><span class="cx"> # Already-filtered stuff          - [% wibble FILTER html %]
</span><del>-#   where the filter is one of html|csv|js|url_quote|quoteUrls|time|uri|xml|none
</del><ins>+#   where the filter is one of html|csv|js|quoteUrls|time|uri|xml|none
</ins><span class="cx"> 
</span><span class="cx"> %::safe = (
</span><span class="cx"> 
</span><span class="lines">@@ -57,27 +57,9 @@
</span><span class="cx">   'type.id', 
</span><span class="cx"> ],
</span><span class="cx"> 
</span><del>-'search/boolean-charts.html.tmpl' =&gt; [
-  '&quot;field${chartnum}-${rownum}-${colnum}&quot;', 
-  '&quot;value${chartnum}-${rownum}-${colnum}&quot;', 
-  '&quot;type${chartnum}-${rownum}-${colnum}&quot;', 
-  'field.name', 
-  'type.name',
-  'type.description', 
-  '&quot;${chartnum}-${rownum}-${newor}&quot;', 
-  '&quot;${chartnum}-${newand}-0&quot;', 
-  'newchart',
-  'jsmagic',
-],
-
</del><span class="cx"> 'search/form.html.tmpl' =&gt; [
</span><del>-  'qv.value',
</del><span class="cx">   'qv.name',
</span><span class="cx">   'qv.description',
</span><del>-  'field.name',
-  'field.description',
-  'field.accesskey',
-  'sel.name',
</del><span class="cx"> ],
</span><span class="cx"> 
</span><span class="cx"> 'search/search-specific.html.tmpl' =&gt; [
</span><span class="lines">@@ -96,24 +78,6 @@
</span><span class="cx">   'request.attach_id', 
</span><span class="cx"> ],
</span><span class="cx"> 
</span><del>-'reports/components.html.tmpl' =&gt; [
-  'numcols',
-],
-
-'reports/duplicates-table.html.tmpl' =&gt; [
-  'column.name', 
-  'column.description',
-  'bug.count', 
-  'bug.delta', 
-],
-
-'reports/duplicates.html.tmpl' =&gt; [
-  'bug_ids_string', 
-  'maxrows',
-  'changedsince',
-  'reverse',
-],
-
</del><span class="cx"> 'reports/keywords.html.tmpl' =&gt; [
</span><span class="cx">   'keyword.bug_count', 
</span><span class="cx"> ],
</span><span class="lines">@@ -124,7 +88,6 @@
</span><span class="cx"> ],
</span><span class="cx"> 
</span><span class="cx"> 'reports/report-table.html.tmpl' =&gt; [
</span><del>-  '&quot;&amp;amp;$tbl_vals&quot; IF tbl_vals', 
</del><span class="cx">   '&quot;&amp;amp;$col_vals&quot; IF col_vals', 
</span><span class="cx">   '&quot;&amp;amp;$row_vals&quot; IF row_vals', 
</span><span class="cx">   'classes.$row_idx.$col_idx', 
</span><span class="lines">@@ -147,13 +110,6 @@
</span><span class="cx">   'cumulate',
</span><span class="cx"> ],
</span><span class="cx"> 
</span><del>-'reports/duplicates.rdf.tmpl' =&gt; [
-  'template_version', 
-  'bug.id', 
-  'bug.count', 
-  'bug.delta', 
-],
-
</del><span class="cx"> 'reports/chart.html.tmpl' =&gt; [
</span><span class="cx">   'width', 
</span><span class="cx">   'height', 
</span><span class="lines">@@ -184,10 +140,6 @@
</span><span class="cx">   'default.series_id', 
</span><span class="cx"> ],
</span><span class="cx"> 
</span><del>-'list/change-columns.html.tmpl' =&gt; [
-  'column', 
-],
-
</del><span class="cx"> 'list/edit-multiple.html.tmpl' =&gt; [
</span><span class="cx">   'group.id', 
</span><span class="cx">   'menuname',
</span><span class="lines">@@ -265,12 +217,7 @@
</span><span class="cx"> ],
</span><span class="cx"> 
</span><span class="cx"> 'global/site-navigation.html.tmpl' =&gt; [
</span><del>-  'bug_list.first', 
-  'bug_list.$prev_bug', 
-  'bug_list.$next_bug', 
-  'bug_list.last', 
</del><span class="cx">   'bug.bug_id', 
</span><del>-  'bug.votes', 
</del><span class="cx"> ],
</span><span class="cx"> 
</span><span class="cx"> 'bug/comments.html.tmpl' =&gt; [
</span><span class="lines">@@ -297,32 +244,18 @@
</span><span class="cx"> ],
</span><span class="cx"> 
</span><span class="cx"> 'bug/edit.html.tmpl' =&gt; [
</span><del>-  'bug.deadline',
</del><span class="cx">   'bug.remaining_time', 
</span><span class="cx">   'bug.delta_ts', 
</span><span class="cx">   'bug.bug_id', 
</span><del>-  'bug.votes', 
</del><span class="cx">   'group.bit', 
</span><del>-  'dep.title', 
-  'dep.fieldname', 
-  'bug.${dep.fieldname}.join(\', \')', 
</del><span class="cx">   'selname',
</span><del>-  '&quot; accesskey=\&quot;$accesskey\&quot;&quot; IF accesskey',
</del><span class="cx">   'inputname',
</span><span class="cx">   '&quot; colspan=\&quot;$colspan\&quot;&quot; IF colspan',
</span><span class="cx">   '&quot; size=\&quot;$size\&quot;&quot; IF size',
</span><span class="cx">   '&quot; maxlength=\&quot;$maxlength\&quot;&quot; IF maxlength',
</span><del>-  'flag.status',
</del><span class="cx">   '&quot; spellcheck=\&quot;$spellcheck\&quot;&quot; IF spellcheck',
</span><span class="cx"> ],
</span><span class="cx"> 
</span><del>-'bug/navigate.html.tmpl' =&gt; [
-  'bug_list.first', 
-  'bug_list.last', 
-  'bug_list.$prev_bug', 
-  'bug_list.$next_bug', 
-],
-
</del><span class="cx"> 'bug/show-multiple.html.tmpl' =&gt; [
</span><span class="cx">   'attachment.id', 
</span><span class="cx">   'flag.status',
</span><span class="lines">@@ -343,6 +276,10 @@
</span><span class="cx">   'subtotal FILTER format(&quot;%.2f&quot;)',
</span><span class="cx">   'work_time FILTER format(&quot;%.2f&quot;)',
</span><span class="cx">   'global.total FILTER format(&quot;%.2f&quot;)',
</span><ins>+  'global.remaining FILTER format(&quot;%.2f&quot;)',
+  'global.estimated FILTER format(&quot;%.2f&quot;)',
+  'bugs.$id.remaining_time FILTER format(&quot;%.2f&quot;)',
+  'bugs.$id.estimated_time FILTER format(&quot;%.2f&quot;)',
</ins><span class="cx"> ],
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="lines">@@ -353,19 +290,6 @@
</span><span class="cx">        FILTER format(&quot;%d&quot;)', 
</span><span class="cx"> ],
</span><span class="cx"> 
</span><del>-'bug/votes/list-for-bug.html.tmpl' =&gt; [
-  'voter.vote_count', 
-  'total', 
-],
-
-'bug/votes/list-for-user.html.tmpl' =&gt; [
-  'product.maxperbug', 
-  'bug.id', 
-  'bug.count', 
-  'product.total', 
-  'product.maxvotes', 
-],
-
</del><span class="cx"> 'bug/process/results.html.tmpl' =&gt; [
</span><span class="cx">   'title.$type', 
</span><span class="cx">   '&quot;$terms.Bug $id&quot; FILTER bug_link(id)',
</span><span class="lines">@@ -373,9 +297,6 @@
</span><span class="cx"> ],
</span><span class="cx"> 
</span><span class="cx"> 'bug/create/create.html.tmpl' =&gt; [
</span><del>-  'g.bit',
-  'sel.name',
-  'sel.description',
</del><span class="cx">   'cloned_bug_id',
</span><span class="cx"> ],
</span><span class="cx"> 
</span><span class="lines">@@ -387,7 +308,6 @@
</span><span class="cx"> 
</span><span class="cx"> 'bug/activity/table.html.tmpl' =&gt; [
</span><span class="cx">   'change.attachid', 
</span><del>-  'change.field', 
</del><span class="cx"> ],
</span><span class="cx"> 
</span><span class="cx"> 'attachment/create.html.tmpl' =&gt; [
</span><span class="lines">@@ -403,7 +323,8 @@
</span><span class="cx"> 'attachment/edit.html.tmpl' =&gt; [
</span><span class="cx">   'attachment.id', 
</span><span class="cx">   'attachment.bug_id', 
</span><del>-  'a', 
</del><ins>+  'a',
+  'editable_or_hide',
</ins><span class="cx"> ],
</span><span class="cx"> 
</span><span class="cx"> 'attachment/list.html.tmpl' =&gt; [
</span><span class="lines">@@ -432,8 +353,6 @@
</span><span class="cx">   'bugid',
</span><span class="cx">   'oldid',
</span><span class="cx">   'newid',
</span><del>-  'style',
-  'javascript',
</del><span class="cx">   'patch.id',
</span><span class="cx"> ],
</span><span class="cx"> 
</span><span class="lines">@@ -446,8 +365,6 @@
</span><span class="cx">   'section_num',
</span><span class="cx">   'current_line_old',
</span><span class="cx">   'current_line_new',
</span><del>-  'curr_old',
-  'curr_new'
</del><span class="cx"> ],
</span><span class="cx"> 
</span><span class="cx"> 'admin/admin.html.tmpl' =&gt; [
</span><span class="lines">@@ -458,6 +375,12 @@
</span><span class="cx">   'link_uri'
</span><span class="cx"> ],
</span><span class="cx"> 
</span><ins>+'admin/custom_fields/cf-js.js.tmpl' =&gt; [
+  'constants.FIELD_TYPE_SINGLE_SELECT',
+  'constants.FIELD_TYPE_MULTI_SELECT',
+  'constants.FIELD_TYPE_BUG_ID',
+],
+
</ins><span class="cx"> 'admin/params/common.html.tmpl' =&gt; [
</span><span class="cx">   'sortlist_separator', 
</span><span class="cx"> ],
</span><span class="lines">@@ -467,22 +390,17 @@
</span><span class="cx"> ],
</span><span class="cx"> 
</span><span class="cx"> 'admin/products/groupcontrol/edit.html.tmpl' =&gt; [
</span><del>-  'group.bugcount', 
-  'group.id', 
-  'const.CONTROLMAPNA', 
-  'const.CONTROLMAPSHOWN', 
-  'const.CONTROLMAPDEFAULT', 
-  'const.CONTROLMAPMANDATORY', 
</del><ins>+  'group.id',
+  'constants.CONTROLMAPNA', 
+  'constants.CONTROLMAPSHOWN',
+  'constants.CONTROLMAPDEFAULT',
+  'constants.CONTROLMAPMANDATORY',
</ins><span class="cx"> ],
</span><span class="cx"> 
</span><span class="cx"> 'admin/products/list.html.tmpl' =&gt; [
</span><span class="cx">   'classification_url_part', 
</span><span class="cx"> ],
</span><span class="cx"> 
</span><del>-'admin/products/confirm-delete.html.tmpl' =&gt; [
-  'classification_url_part', 
-],
-
</del><span class="cx"> 'admin/products/footer.html.tmpl' =&gt; [
</span><span class="cx">   'classification_url_part', 
</span><span class="cx">   'classification_text', 
</span><span class="lines">@@ -494,12 +412,8 @@
</span><span class="cx"> ],
</span><span class="cx"> 
</span><span class="cx"> 'admin/flag-type/edit.html.tmpl' =&gt; [
</span><del>-  'action', 
</del><span class="cx">   'type.id', 
</span><del>-  'type.target_type', 
</del><span class="cx">   'type.sortkey || 1',
</span><del>-  'typeLabelLowerPlural',
-  'typeLabelLowerSingular',
</del><span class="cx">   'selname',
</span><span class="cx"> ],
</span><span class="cx"> 
</span><span class="lines">@@ -526,7 +440,6 @@
</span><span class="cx">   'flags.setter',
</span><span class="cx">   'longdescs',
</span><span class="cx">   'quips',
</span><del>-  'votes',
</del><span class="cx">   'series',
</span><span class="cx">   'watch.watched',
</span><span class="cx">   'watch.watcher',
</span><span class="lines">@@ -554,8 +467,8 @@
</span><span class="cx">   'new_status.id',
</span><span class="cx"> ],
</span><span class="cx"> 
</span><del>-'account/login.html.tmpl' =&gt; [
-  'target', 
</del><ins>+'account/auth/login-small.html.tmpl' =&gt; [
+  'qs_suffix',
</ins><span class="cx"> ],
</span><span class="cx"> 
</span><span class="cx"> 'account/prefs/email.html.tmpl' =&gt; [
</span><span class="lines">@@ -573,4 +486,8 @@
</span><span class="cx">   'group.id',
</span><span class="cx"> ],
</span><span class="cx"> 
</span><ins>+'config.rdf.tmpl' =&gt; [
+  'escaped_urlbase',
+],
+
</ins><span class="cx"> );
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultflaglisthtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/flag/list.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/flag/list.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/flag/list.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -18,59 +18,7 @@
</span><span class="cx">   # Contributor(s): Myk Melez &lt;myk@mozilla.org&gt;
</span><span class="cx">   #%]
</span><span class="cx"> 
</span><del>-&lt;script type=&quot;text/javascript&quot;&gt;
-&lt;!-- 
-  // Enables or disables a requestee field depending on whether or not
-  // the user is requesting the corresponding flag.
-  function toggleRequesteeField(flagField, no_focus)
-  {
-    // Convert the ID of the flag field into the ID of its corresponding
-    // requestee field and then use the ID to get the field.
-    var id = flagField.name.replace(/flag(_type)?-(\d+)/, &quot;requestee$1-$2&quot;);
-    var requesteeField = document.getElementById(id);
-    if (!requesteeField) return;
-    
-    // Enable or disable the requestee field based on the value
-    // of the flag field.
-    if (flagField.value == &quot;?&quot;) {
-        requesteeField.disabled = false;
-        if (!no_focus) requesteeField.focus();
-    } else                         
-        requesteeField.disabled = true;
-  }
-  
-  // Disables requestee fields when the window is loaded since they shouldn't
-  // be enabled until the user requests that flag type.
-  function disableRequesteeFields()
-  {
-    var inputElements = document.getElementsByTagName(&quot;input&quot;);
-    var selectElements = document.getElementsByTagName(&quot;select&quot;);
-    //You cannot update Node lists, so you must create an array to combine the NodeLists
-    var allElements = [];
-    for( var i=0; i &lt; inputElements.length; i++ ) {
-        allElements[allElements.length] = inputElements.item(i);
-    }
-    for( var i=0; i &lt; selectElements.length; i++ ) { //Combine inputs with selects
-        allElements[allElements.length] = selectElements.item(i);
-    }
-    var inputElement, id, flagField;
-    for ( var i=0 ; i&lt;allElements.length ; i++ )
-    {
-      inputElement = allElements[i];
-      if (inputElement.name.search(/^requestee(_type)?-(\d+)$/) != -1)
-      {
-        // Convert the ID of the requestee field into the ID of its corresponding
-        // flag field and then use the ID to get the field.
-        id = inputElement.name.replace(/requestee(_type)?-(\d+)/, &quot;flag$1-$2&quot;);
-        flagField = document.getElementById(id);
-        if (flagField &amp;&amp; flagField.value != &quot;?&quot;)
-            inputElement.disabled = true;
-      }
-    }
-  }
-  window.onload = disableRequesteeFields;
-// --&gt;
-&lt;/script&gt;
</del><ins>+[% IF user.id AND !read_only_flags %]
</ins><span class="cx"> 
</span><span class="cx"> [%# We list flags by looping twice over the flag types relevant for the bug.
</span><span class="cx">   # In the first loop, we display existing flags and then, for active types,
</span><span class="lines">@@ -82,6 +30,8 @@
</span><span class="cx"> 
</span><span class="cx"> [% DEFAULT flag_table_id = &quot;flags&quot; %]
</span><span class="cx"> 
</span><ins>+&lt;script src=&quot;[% 'js/flag.js' FILTER mtime %]&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
+
</ins><span class="cx"> &lt;table id=&quot;[% flag_table_id FILTER html %]&quot;&gt;
</span><span class="cx">   [% UNLESS flag_no_header %]
</span><span class="cx">     &lt;tr&gt;
</span><span class="lines">@@ -97,13 +47,13 @@
</span><span class="cx">   [% END %]
</span><span class="cx"> 
</span><span class="cx">   [%# Step 1: Display every flag type (except inactive types with no flags). %]
</span><del>-  [% FOREACH type = flag_types %]
-    
-    [%# Step 1a: Display existing flag(s). %]
</del><ins>+  [% FOREACH type = flag_types -%]
+
+    [%-# Step 1a: Display existing flag(s). %]
</ins><span class="cx">     [% FOREACH flag = type.flags %]
</span><span class="cx">       &lt;tr&gt;
</span><span class="cx">         &lt;td&gt;
</span><del>-          [% flag.setter.nick FILTER html %]:
</del><ins>+          &lt;span title=&quot;[% flag.setter.identity FILTER html %]&quot;&gt;[% flag.setter.nick FILTER html %]&lt;/span&gt;:
</ins><span class="cx">         &lt;/td&gt;
</span><span class="cx">         &lt;td&gt;
</span><span class="cx">           &lt;label title=&quot;[% type.description FILTER html %]&quot;
</span><span class="lines">@@ -114,9 +64,9 @@
</span><span class="cx">           &lt;select id=&quot;flag-[% flag.id %]&quot; name=&quot;flag-[% flag.id %]&quot; 
</span><span class="cx">                   title=&quot;[% type.description FILTER html %]&quot;
</span><span class="cx">                   onchange=&quot;toggleRequesteeField(this);&quot;
</span><del>-                  class=&quot;flag_select&quot;&gt;
</del><ins>+                  class=&quot;flag_select flag_type-[% type.id %]&quot;&gt;
</ins><span class="cx">             [%# Only display statuses the user is allowed to set. %]
</span><del>-            [% IF user.can_request_flag(type) %]
</del><ins>+            [% IF user.can_request_flag(type) || flag.setter_id == user.id %]
</ins><span class="cx">               &lt;option value=&quot;X&quot;&gt;&lt;/option&gt;
</span><span class="cx">             [% END %]
</span><span class="cx">             [% IF type.is_active %]
</span><span class="lines">@@ -138,6 +88,7 @@
</span><span class="cx">           &lt;td&gt;
</span><span class="cx">             [% IF (type.is_active &amp;&amp; type.is_requestable &amp;&amp; type.is_requesteeble) || flag.requestee %]
</span><span class="cx">               &lt;span style=&quot;white-space: nowrap;&quot;&gt;
</span><ins>+                [% SET flag_custom_list = [] %]
</ins><span class="cx">                 [% IF Param('usemenuforusers') %]
</span><span class="cx">                   [% flag_custom_list = flag.type.grant_list %]
</span><span class="cx">                   [% IF !(type.is_active &amp;&amp; type.is_requestable &amp;&amp; type.is_requesteeble) %]
</span><span class="lines">@@ -146,77 +97,27 @@
</span><span class="cx">                         nothing else. %]
</span><span class="cx">                     [% flag_custom_list = [flag.requestee] %]
</span><span class="cx">                   [% END %]
</span><del>-                  [% INCLUDE global/userselect.html.tmpl
-                             name     =&gt; &quot;requestee-$flag.id&quot;
-                             id       =&gt; &quot;requestee-$flag.id&quot;
-                             value    =&gt; flag.requestee.login
-                             multiple =&gt; 0
-                             emptyok  =&gt; 1
-                             custom_userlist =&gt; flag_custom_list
-                  %]
-                [% ELSE %]
-                  (&lt;input type=&quot;text&quot; size=&quot;30&quot; maxlength=&quot;255&quot;
-                          id=&quot;requestee-[% flag.id %]&quot; 
-                          name=&quot;requestee-[% flag.id %]&quot;
-                          [% IF flag.status == &quot;?&quot; &amp;&amp; flag.requestee %]
-                            value=&quot;[% flag.requestee.login FILTER html %]&quot;
-                          [% END %]&gt;)
</del><span class="cx">                 [% END %]
</span><ins>+                [% INCLUDE global/userselect.html.tmpl
+                           name     =&gt; &quot;requestee-$flag.id&quot;
+                           id       =&gt; &quot;requestee-$flag.id&quot;
+                           value    =&gt; flag.requestee.login
+                           multiple =&gt; 0
+                           emptyok  =&gt; 1
+                           classes =&gt; [&quot;requestee&quot;]
+                           custom_userlist =&gt; flag_custom_list
+                %]
</ins><span class="cx">               &lt;/span&gt;
</span><span class="cx">             [% END %]
</span><span class="cx">           &lt;/td&gt;
</span><span class="cx">         [% END %]
</span><span class="cx">       &lt;/tr&gt;
</span><del>-    [% END %]
-    
-    [%# Step 1b: Display UI for setting flag. %]
</del><ins>+    [% END -%]
+
+    [%-# Step 1b: Display UI for setting flag. %]
</ins><span class="cx">     [% IF (!type.flags || type.flags.size == 0) &amp;&amp; type.is_active %]
</span><del>-      &lt;tr&gt;
-        &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-        &lt;td&gt;
-          &lt;label title=&quot;[% type.description FILTER html %]&quot;
-                 for=&quot;flag_type-[% type.id %]&quot;&gt;
-            [%- type.name FILTER html FILTER no_break %]&lt;/label&gt;
-        &lt;/td&gt;
-        &lt;td&gt;
-          &lt;select id=&quot;flag_type-[% type.id %]&quot; name=&quot;flag_type-[% type.id %]&quot; 
-                  title=&quot;[% type.description FILTER html %]&quot;
-                  [% &quot; disabled=\&quot;disabled\&quot;&quot; UNLESS (type.is_requestable &amp;&amp; user.can_request_flag(type)) || user.can_set_flag(type) %]
-                  onchange=&quot;toggleRequesteeField(this);&quot;
-                  class=&quot;flag_select&quot;&gt;
-            &lt;option value=&quot;X&quot;&gt;&lt;/option&gt;
-            [% IF type.is_requestable &amp;&amp; user.can_request_flag(type) %]
-              &lt;option value=&quot;?&quot;&gt;?&lt;/option&gt;
-            [% END %]
-            [% IF user.can_set_flag(type) %]
-              &lt;option value=&quot;+&quot;&gt;+&lt;/option&gt;
-              &lt;option value=&quot;-&quot;&gt;-&lt;/option&gt;
-            [% END %]
-          &lt;/select&gt;
-        &lt;/td&gt;
-        [% IF any_flags_requesteeble %]
-          &lt;td&gt;
-            [% IF type.is_requestable &amp;&amp; type.is_requesteeble %]
-              &lt;span style=&quot;white-space: nowrap;&quot;&gt;
-                [% IF Param('usemenuforusers') %]
-                  [% INCLUDE global/userselect.html.tmpl
-                             name     =&gt; &quot;requestee_type-$type.id&quot;
-                             id       =&gt; &quot;requestee_type-$type.id&quot;
-                             multiple =&gt; type.is_multiplicable * 3
-                             emptyok  =&gt; !type.is_multiplicable
-                             value    =&gt; &quot;&quot;
-                             custom_userlist =&gt; type.grant_list
-                  %]
-                [% ELSE %]
-                  (&lt;input type=&quot;text&quot; size=&quot;30&quot; maxlength=&quot;255&quot;
-                          id=&quot;requestee_type-[% type.id %]&quot;
-                          name=&quot;requestee_type-[% type.id %]&quot;&gt;)
-                [% END %]
-              &lt;/span&gt;
-            [% END %]
-          &lt;/td&gt;
-        [% END %]
-      &lt;/tr&gt;
</del><ins>+
+      [% PROCESS flag_row first_cell_empty = 1 addl_text = &quot;&quot; %]
</ins><span class="cx">     [% END %]
</span><span class="cx">   [% END %]
</span><span class="cx"> 
</span><span class="lines">@@ -227,51 +128,89 @@
</span><span class="cx">         &lt;tr&gt;&lt;td colspan=&quot;3&quot;&gt;&lt;hr&gt;&lt;/td&gt;&lt;/tr&gt;
</span><span class="cx">         [% separator_displayed = 1 %]
</span><span class="cx">     [% END %]
</span><del>-    &lt;tr&gt;
-      &lt;td colspan=&quot;2&quot;&gt;
-        addl. &lt;label title=&quot;[% type.description FILTER html %]&quot;
-                     for=&quot;flag_type-[% type.id %]&quot;&gt;
-          [%- type.name FILTER html FILTER no_break %]&lt;/label&gt;
-      &lt;/td&gt;
-      &lt;td&gt;
-        &lt;select id=&quot;flag_type-[% type.id %]&quot; name=&quot;flag_type-[% type.id %]&quot; 
-                title=&quot;[% type.description FILTER html %]&quot;
-                [% &quot; disabled=\&quot;disabled\&quot;&quot; UNLESS (type.is_requestable &amp;&amp; user.can_request_flag(type)) || user.can_set_flag(type) %]
-                onchange=&quot;toggleRequesteeField(this);&quot;
-                class=&quot;flag_select&quot;&gt;
-          &lt;option value=&quot;X&quot;&gt;&lt;/option&gt;
-          [% IF type.is_requestable &amp;&amp; user.can_request_flag(type) %]
-            &lt;option value=&quot;?&quot;&gt;?&lt;/option&gt;
-          [% END %]
-          [% IF user.can_set_flag(type) %]
-            &lt;option value=&quot;+&quot;&gt;+&lt;/option&gt;
-            &lt;option value=&quot;-&quot;&gt;-&lt;/option&gt;
-          [% END %]
-        &lt;/select&gt;
-      &lt;/td&gt;
-      [% IF any_flags_requesteeble %]
-        &lt;td&gt;
-          [% IF type.is_requestable &amp;&amp; type.is_requesteeble %]
-            &lt;span style=&quot;white-space: nowrap;&quot;&gt;
-              [% IF Param('usemenuforusers') %]
-                [% INCLUDE global/userselect.html.tmpl
-                           name     =&gt; &quot;requestee_type-$type.id&quot;
-                           id       =&gt; &quot;requestee_type-$type.id&quot;
-                           multiple =&gt; type.is_multiplicable * 3
-                           emptyok  =&gt; !type.is_multiplicable
-                           value    =&gt; &quot;&quot;
-                           custom_userlist =&gt; type.grant_list
-                %]
-              [% ELSE %]
-                (&lt;input type=&quot;text&quot; size=&quot;30&quot; maxlength=&quot;255&quot;
-                        id=&quot;requestee_type-[% type.id %]&quot; 
-                        name=&quot;requestee_type-[% type.id %]&quot;&gt;)
-              [% END %]
-            &lt;/span&gt;
-          [% END %]
-        &lt;/td&gt;
</del><ins>+
+    [% PROCESS flag_row first_cell_empty = 0 addl_text = &quot;addl.&quot; %]
+  [% END %]
+&lt;/table&gt;
+
+[% ELSE %]
+  [%# The user is logged out. Display flags as read-only. %]
+  [% header_displayed = 0 %]
+  [% FOREACH type = flag_types %]
+    [% FOREACH flag = type.flags %]
+      [% IF !flag_no_header AND !header_displayed %]
+        &lt;p&gt;&lt;b&gt;Flags:&lt;/b&gt;&lt;/p&gt;
+        [% header_displayed = 1 %]
</ins><span class="cx">       [% END %]
</span><del>-    &lt;/tr&gt;
</del><ins>+      [% IF flag.setter.name %]
+        &lt;span title=&quot;[% flag.setter.name FILTER html %]&quot;&gt;[% flag.setter.nick FILTER html %]&lt;/span&gt;:
+      [% ELSE %]
+        [% flag.setter.nick FILTER html %]:
+      [% END %]
+      [%+ type.name FILTER html FILTER no_break %][% flag.status %]
+      [% IF flag.requestee %]
+        [% IF flag.requestee.name %]
+          (&lt;span title=&quot;[% flag.requestee.name FILTER html %]&quot;&gt;[% flag.requestee.nick FILTER html %]&lt;/span&gt;)
+        [% ELSE %]
+          ([% flag.requestee.nick FILTER html %])
+        [% END %]
+      [% END %]&lt;br&gt;
+    [% END %]
</ins><span class="cx">   [% END %]
</span><ins>+[% END %]
</ins><span class="cx"> 
</span><del>-&lt;/table&gt;
</del><ins>+[%# Display a table row for unset flags %]
+
+[% BLOCK flag_row %]
+  &lt;tr&gt;
+  [% IF first_cell_empty %]
+    &lt;td&gt;&amp;nbsp;&lt;/td&gt;
+    &lt;td&gt;
+  [% ELSE %]
+    &lt;td colspan=&quot;2&quot;&gt;
+  [% END %]
+
+      [% addl_text FILTER html %]
+      &lt;label title=&quot;[% type.description FILTER html %]&quot; for=&quot;flag_type-[% type.id %]&quot;&gt;
+        [%- type.name FILTER html FILTER no_break %]&lt;/label&gt;
+    &lt;/td&gt;
+    &lt;td&gt;
+      &lt;select id=&quot;flag_type-[% type.id %]&quot; name=&quot;flag_type-[% type.id %]&quot;
+              title=&quot;[% type.description FILTER html %]&quot;
+              [% &quot; disabled=\&quot;disabled\&quot;&quot; UNLESS (type.is_requestable &amp;&amp; user.can_request_flag(type)) || user.can_set_flag(type) %]
+              onchange=&quot;toggleRequesteeField(this);&quot;
+              class=&quot;flag_select flag_type-[% type.id %]&quot;&gt;
+        &lt;option value=&quot;X&quot;&gt;&lt;/option&gt;
+        [% IF type.is_requestable &amp;&amp; user.can_request_flag(type) %]
+          &lt;option value=&quot;?&quot;&gt;?&lt;/option&gt;
+        [% END %]
+        [% IF user.can_set_flag(type) %]
+          &lt;option value=&quot;+&quot;&gt;+&lt;/option&gt;
+          &lt;option value=&quot;-&quot;&gt;-&lt;/option&gt;
+        [% END %]
+      &lt;/select&gt;
+    &lt;/td&gt;
+    [% IF any_flags_requesteeble %]
+      &lt;td&gt;
+        [% IF type.is_requestable &amp;&amp; type.is_requesteeble %]
+          &lt;span style=&quot;white-space: nowrap;&quot;&gt;
+            [% SET grant_list = [] %]
+            [% IF Param('usemenuforusers') %]
+              [% grant_list = type.grant_list %]
+            [% END %]
+            [% INCLUDE  global/userselect.html.tmpl
+                        name     =&gt; &quot;requestee_type-$type.id&quot;
+                        id       =&gt; &quot;requestee_type-$type.id&quot;
+                        multiple =&gt; type.is_multiplicable * 3
+                        emptyok  =&gt; !type.is_multiplicable
+                        value    =&gt; &quot;&quot;
+                        custom_userlist =&gt; grant_list
+                        classes =&gt; [&quot;requestee&quot;]
+            %]            
+            
+          &lt;/span&gt;
+        [% END %]
+      &lt;/td&gt;
+    [% END %]
+  &lt;/tr&gt;
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultglobalchooseclassificationhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/global/choose-classification.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/global/choose-classification.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/global/choose-classification.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -29,13 +29,11 @@
</span><span class="cx"> [% PROCESS global/header.html.tmpl %]
</span><span class="cx"> 
</span><span class="cx"> &lt;table&gt;
</span><del>-        
-[% IF Param('showallproducts') %]
</del><span class="cx">   &lt;tr&gt;
</span><span class="cx">     &lt;th align=&quot;right&quot;&gt;
</span><del>-      &lt;a href=&quot;[% target FILTER url_quote %]?classification=__all
-            [% IF cloned_bug_id %]&amp;amp;cloned_bug_id=[% cloned_bug_id FILTER url_quote %][% END -%] 
-            [%- IF format %]&amp;amp;format=[% format FILTER url_quote %][% END %]&quot;&gt;
</del><ins>+      &lt;a href=&quot;[% target FILTER uri %]?classification=__all
+            [% IF cloned_bug_id %]&amp;amp;cloned_bug_id=[% cloned_bug_id FILTER uri %][% END -%] 
+            [%- IF format %]&amp;amp;format=[% format FILTER uri %][% END %]&quot;&gt;
</ins><span class="cx">       All&lt;/a&gt;:
</span><span class="cx">     &lt;/th&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -44,14 +42,13 @@
</span><span class="cx">   &lt;tr&gt;
</span><span class="cx">     &lt;th colspan=&quot;2&quot;&gt;&amp;nbsp;&lt;/th&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><del>-[% END %]
</del><span class="cx"> 
</span><span class="cx"> [% FOREACH class = classifications %]
</span><span class="cx">   &lt;tr&gt;
</span><span class="cx">     &lt;th align=&quot;right&quot;&gt;
</span><del>-      &lt;a href=&quot;[% target FILTER url_quote %]?classification=[% class.name FILTER url_quote -%]
-            [%- IF cloned_bug_id %]&amp;amp;cloned_bug_id=[% cloned_bug_id FILTER url_quote %][% END -%] 
-            [%- IF format %]&amp;amp;format=[% format FILTER url_quote %][% END %]&quot;&gt;
</del><ins>+      &lt;a href=&quot;[% target FILTER uri %]?classification=[% class.name FILTER uri -%]
+            [%- IF cloned_bug_id %]&amp;amp;cloned_bug_id=[% cloned_bug_id FILTER uri %][% END -%] 
+            [%- IF format %]&amp;amp;format=[% format FILTER uri %][% END %]&quot;&gt;
</ins><span class="cx">       [% class.name FILTER html %]&lt;/a&gt;:
</span><span class="cx">     &lt;/th&gt;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultglobalchooseproducthtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/global/choose-product.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/global/choose-product.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/global/choose-product.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -31,15 +31,17 @@
</span><span class="cx"> 
</span><span class="cx"> [% IF target == &quot;enter_bug.cgi&quot; %]
</span><span class="cx">   [% title = &quot;Enter $terms.Bug&quot; %]
</span><del>-  [% subheader = BLOCK %]First, you must pick a product on which to enter [% terms.abug %]. [% END %]
</del><ins>+  [% h2 = BLOCK %]First, you must pick a product on which to enter [% terms.abug %]: [% END %]
</ins><span class="cx"> [% ELSIF target == &quot;describecomponents.cgi&quot; %]
</span><del>-  [% title = &quot;$terms.Bugzilla Component Descriptions&quot; %]
-  [% subheader = &quot;Please specify the product whose components you want described.&quot; %]
</del><ins>+  [% title = &quot;Browse&quot; %]
+  [% h2 = &quot;Select a product category to browse:&quot; %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% DEFAULT title = &quot;Choose a Product&quot; %]
</span><span class="cx"> [% PROCESS global/header.html.tmpl %]
</span><span class="cx"> 
</span><ins>+&lt;h2&gt;[% h2 FILTER html %]&lt;/h2&gt;
+
</ins><span class="cx"> &lt;table&gt;
</span><span class="cx"> 
</span><span class="cx"> [% FOREACH c = classifications %]
</span><span class="lines">@@ -53,9 +55,9 @@
</span><span class="cx">   [% FOREACH p = c.products %]
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th align=&quot;right&quot; valign=&quot;top&quot;&gt;
</span><del>-        &lt;a href=&quot;[% target %]?product=[% p.name FILTER url_quote -%]
-              [%- IF cloned_bug_id %]&amp;amp;cloned_bug_id=[% cloned_bug_id FILTER url_quote %][% END -%] 
-              [%- IF format %]&amp;amp;format=[% format FILTER url_quote %][% END %]&quot;&gt;
</del><ins>+        &lt;a href=&quot;[% target %]?product=[% p.name FILTER uri -%]
+              [%- IF cloned_bug_id %]&amp;amp;cloned_bug_id=[% cloned_bug_id FILTER uri %][% END -%] 
+              [%- IF format %]&amp;amp;format=[% format FILTER uri %][% END %]&quot;&gt;
</ins><span class="cx">         [% p.name FILTER html FILTER no_break %]&lt;/a&gt;:&amp;nbsp;
</span><span class="cx">       &lt;/th&gt;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultglobalcodeerrorhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/global/code-error.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/global/code-error.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/global/code-error.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -32,22 +32,12 @@
</span><span class="cx">   # in this file; if you do not wish to change it, use the &quot;none&quot; filter.
</span><span class="cx">   #%]
</span><span class="cx"> 
</span><del>-[% PROCESS global/variables.none.tmpl %]
</del><ins>+[% PROCESS &quot;global/field-descs.none.tmpl&quot; %]
</ins><span class="cx"> 
</span><span class="cx"> [% DEFAULT title = &quot;Internal Error&quot; %]
</span><span class="cx"> 
</span><span class="cx"> [% error_message = BLOCK %]
</span><del>-  [% IF    error == &quot;action_unrecognized&quot; %]
-    [% docslinks = {'query.html' =&gt; &quot;Searching for $terms.bugs&quot;,
-                    'query.html#list' =&gt; &quot;$terms.Bug lists&quot;} %]
-    I don't recognize the value (&lt;em&gt;[% action FILTER html %]&lt;/em&gt;)
-    of the &lt;em&gt;action&lt;/em&gt; variable.
-  
-  [% ELSIF error == &quot;attachment_already_obsolete&quot; %]
-    Attachment #[% attach_id FILTER html %] ([% description FILTER html %]) 
-    is already obsolete.
-
-  [% ELSIF error == &quot;auth_invalid_email&quot; %]
</del><ins>+  [% IF error == &quot;auth_invalid_email&quot; %]
</ins><span class="cx">     [% title = &quot;Invalid Email Address&quot; %]
</span><span class="cx">     We received an email address (&lt;b&gt;[% addr FILTER html %]&lt;/b&gt;)
</span><span class="cx">     that didn't pass our syntax checking for a legal email address,
</span><span class="lines">@@ -56,10 +46,9 @@
</span><span class="cx">       A legal address must contain exactly one '@',
</span><span class="cx">       and at least one '.' after the @.
</span><span class="cx">     [% ELSE %]
</span><del>-      [%+ Param('emailregexpdesc') %]
</del><ins>+      [%+ Param('emailregexpdesc') FILTER html_light %]
</ins><span class="cx">     [% END %]
</span><del>-    It must also not contain any of these special characters:
-    &lt;tt&gt;\ ( ) &amp;amp; &amp;lt; &amp;gt; , ; : &amp;quot; [ ]&lt;/tt&gt;, or any whitespace.
</del><ins>+    It also must not contain any illegal characters.
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;authres_unhandled&quot; %]
</span><span class="cx">     The result value of [% value FILTER html %] was not handled by
</span><span class="lines">@@ -101,12 +90,12 @@
</span><span class="cx">   
</span><span class="cx">   [% ELSIF error == &quot;chart_file_open_fail&quot; %]
</span><span class="cx">     Unable to open the chart datafile &lt;tt&gt;[% filename FILTER html %]&lt;/tt&gt;.
</span><del>-  
-  [% ELSIF error == &quot;chart_lines_not_installed&quot; %]
-    [% admindocslinks = {'installation.html#install-perlmodules' =&gt; 'Installing Perl modules necessary for Charting'} %]
-    Charts will not work without the Chart::Lines Perl module being installed.
-    Run checksetup.pl for installation instructions.
-
</del><ins>+ 
+  [% ELSIF error == &quot;column_alter_nonexistent_fk&quot; %]
+    You attempted to modify the foreign key for 
+    [%+ table FILTER html %].[% column FILTER html %], but there is
+    no foreign key on that column.

</ins><span class="cx">   [% ELSIF error == &quot;column_not_null_without_default&quot; %]
</span><span class="cx">     Failed adding the column [% name FILTER html %]:
</span><span class="cx">     You cannot add a NOT NULL column with no default to an existing table
</span><span class="lines">@@ -117,9 +106,26 @@
</span><span class="cx">     without specifying a default or something for $set_nulls_to, because
</span><span class="cx">     there are NULL values currently in it.
</span><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;comment_extra_data_not_allowed&quot; %]
+    You tried to set the &lt;code&gt;extra_data&lt;/code&gt; field to 
+    '[% extra_data FILTER html %]' but comments of type [% type FILTER html %]
+    do not accept an &lt;code&gt;extra_data&lt;/code&gt; argument.
+
+  [% ELSIF error == &quot;comment_extra_data_required&quot; %]
+    Comments of type [% type FILTER html %] require an &lt;code&gt;extra_data&lt;/code&gt;
+    argument to be set.
+
+  [% ELSIF error == &quot;comment_extra_data_not_numeric&quot; %]
+    You tried to set the &lt;code&gt;extra_data&lt;/code&gt; field to
+    '[% extra_data FILTER html %]' but comments of type [% type FILTER html %]
+    require a numeric &lt;code&gt;extra_data&lt;/code&gt; argument.
+
+  [% ELSIF error == &quot;comment_type_invalid&quot; %]
+    '[% type FILTER html %]' is not a valid comment type.
+
</ins><span class="cx">   [% ELSIF error == &quot;db_rename_conflict&quot; %]
</span><span class="cx">     Name conflict: Cannot rename [% old FILTER html %] to
</span><del>-    [% new FILTER html %] because [% new FILTER html %] already exists.
</del><ins>+    [%+ new FILTER html %] because [% new FILTER html %] already exists.
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;cookies_need_value&quot; %]
</span><span class="cx">     Every cookie must have a value.
</span><span class="lines">@@ -136,27 +142,56 @@
</span><span class="cx">       address.
</span><span class="cx">     [% END %]
</span><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;extension_invalid&quot; %]
-    An error occurred processing hook [% name FILTER html %] in
-    extension [% extension FILTER html %]: [% errstr FILTER html %]
</del><ins>+  [% ELSIF error == &quot;extension_disabled&quot; %]
+    [% title = &quot;Extension Disabled&quot; %]
+    You cannot access this page because the extension '[% name FILTER html %]'
+    is disabled.
</ins><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;extension_must_be_subclass&quot; %]
+    &lt;code&gt;[% package FILTER html %]&lt;/code&gt; from 
+    &lt;code&gt;[% filename FILTER html %]&lt;/code&gt; is not a subclass of
+    &lt;code&gt;[% class FILTER html %]&lt;/code&gt;.
+
+  [% ELSIF error == &quot;extension_must_return_name&quot; %]
+    &lt;code&gt;[% extension FILTER html %]&lt;/code&gt; returned
+    &lt;code&gt;[% returned FILTER html %]&lt;/code&gt;, which is not a valid name
+    for an extension. Extensions must return their name, not &lt;code&gt;1&lt;/code&gt;
+    or a number. See the documentation of
+    &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/Extension.html&quot;&gt;Bugzilla::Extension&lt;/a&gt;
+    for details.
+
+  [% ELSIF error == &quot;extension_no_name&quot; %]
+    We did not find a &lt;code&gt;NAME&lt;/code&gt; method in 
+    &lt;code&gt;[% package FILTER html %]&lt;/code&gt; (loaded from
+    &lt;code&gt;[% filename FILTER html %]&lt;/code&gt;). This means that
+    the extension has one or more of the following problems:
+
+    &lt;ul&gt;
+      &lt;li&gt;&lt;code&gt;[% filename FILTER html %]&lt;/code&gt; did not define a
+        &lt;code&gt;[% package FILTER html %]&lt;/code&gt; package.&lt;/li&gt;
+      &lt;li&gt;&lt;code&gt;[% package FILTER html %]&lt;/code&gt; did not define a
+        &lt;code&gt;NAME&lt;/code&gt; method (or the &lt;code&gt;NAME&lt;/code&gt; method
+        returned an empty string).&lt;/li&gt;
+    &lt;/ul&gt;
+
</ins><span class="cx">   [% ELSIF error == &quot;extern_id_conflict&quot; %]
</span><span class="cx">     The external ID '[% extern_id FILTER html %]' already exists
</span><span class="cx">     in the database for '[% username FILTER html %]', but your
</span><span class="cx">     account source says that '[% extern_user FILTER html %]' has that ID.
</span><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;field_type_mismatch&quot; %]
-    Cannot seem to handle &lt;code&gt;[% field FILTER html %]&lt;/code&gt;
-    and &lt;code&gt;[% type FILTER html %]&lt;/code&gt; together.
</del><ins>+  [% ELSIF error == &quot;field_choice_must_use_type&quot; %]
+    When you call a class method on &lt;code&gt;Bugzilla::Field::Choice&lt;/code&gt;,
+    you must call &lt;code&gt;Bugzilla::Field::Choice-&amp;gt;type('some_field')&lt;/code&gt;
+    to generate the right class (you can't call class methods directly
+    on Bugzilla::Field::Choice).
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;field_not_custom&quot; %]
</span><span class="cx">     '[% field.description FILTER html %]' ([% field.name FILTER html %])
</span><span class="cx">     is not a custom field.
</span><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;gd_not_installed&quot; %]
-    [% admindocslinks = {'installation.html#install-perlmodules' =&gt; 'Installing Perl modules necessary for Charting'} %]
-    Charts will not work without the GD Perl module being installed.
-    Run checksetup.pl for installation instructions.
</del><ins>+  [% ELSIF error == &quot;field_type_not_specified&quot; %]
+    [% title = &quot;Field Type Not Specified&quot; %]
+    You must specify a type when creating a custom field.
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;illegal_content_type_method&quot; %]
</span><span class="cx">     Your form submission got corrupted somehow.  The &lt;em&gt;content
</span><span class="lines">@@ -168,25 +203,10 @@
</span><span class="cx">   [% ELSIF error == &quot;illegal_field&quot; %]
</span><span class="cx">     A legal [% field FILTER html %] was not set.
</span><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;inactive_group&quot; %]
-    Attempted to add [% terms.bug %] to the '[% name FILTER html %]'
-    group, which is not used for [% terms.bugs %].
-
</del><span class="cx">   [% ELSIF error == &quot;invalid_attach_id_to_obsolete&quot; %]
</span><span class="cx">      The attachment number of one of the attachments you wanted to obsolete,
</span><del>-     [% attach_id FILTER html %], is invalid.
</del><ins>+     [%+ attach_id FILTER html %], is invalid.
</ins><span class="cx">           
</span><del>-  [% ELSIF error == &quot;invalid_column_name_cookie&quot; %]
-    [% title = &quot;Invalid Column Name&quot; %]
-     The custom sort order specified in your cookie contains an invalid
-     column name &lt;em&gt;[% fragment FILTER html %]&lt;/em&gt;. 
-     The cookie has been cleared.
-         
-  [% ELSIF error == &quot;invalid_column_name_form&quot; %]
-    [% title = &quot;Invalid Column Name&quot; %]
-     The custom sort order specified in your form submission contains an
-     invalid column name &lt;em&gt;[% fragment FILTER html %]&lt;/em&gt;.
-
</del><span class="cx">   [% ELSIF error == &quot;invalid_customfield_type&quot; %]
</span><span class="cx">     [% title = &quot;Invalid Field Type&quot; %]
</span><span class="cx">     The type &lt;em&gt;[% type FILTER html %]&lt;/em&gt; is not a valid field type.
</span><span class="lines">@@ -195,6 +215,12 @@
</span><span class="cx">     [% title = &quot;Invalid Dimensions&quot; %]
</span><span class="cx">     The width or height specified is not a positive integer.
</span><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;invalid_feature&quot; %]
+    [% title = &quot;Invalid Feature Name&quot; %]
+    [% feature FILTER html %] is not a valid feature name. See
+    &lt;code&gt;OPTIONAL_MODULES&lt;/code&gt; in 
+    &lt;code&gt;Bugzilla::Install::Requirements&lt;/code&gt; for valid names.
+
</ins><span class="cx">   [% ELSIF error == &quot;invalid_flag_association&quot; %]
</span><span class="cx">     [% title = &quot;Invalid Flag Association&quot; %]
</span><span class="cx">     Some flags do not belong to
</span><span class="lines">@@ -209,6 +235,10 @@
</span><span class="cx">     The series_id [% series_id FILTER html %] is not valid. It may be that
</span><span class="cx">     this series has been deleted.
</span><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;invalid_timestamp&quot; %]
+    The entered timestamp &lt;code&gt;[% timestamp FILTER html %]&lt;/code&gt; could not
+    be parsed into a valid date and time.
+
</ins><span class="cx">   [% ELSIF error == &quot;invalid_webservergroup&quot; %]
</span><span class="cx">     There is no such group: [% group FILTER html %]. Check your $webservergroup
</span><span class="cx">     setting in [% constants.bz_locations.localconfig FILTER html %].
</span><span class="lines">@@ -217,38 +247,32 @@
</span><span class="cx">     Attachment [% attach_id FILTER html %] ([% description FILTER html %]) 
</span><span class="cx">     is attached to [% terms.bug %] [%+ attach_bug_id FILTER html %], 
</span><span class="cx">     but you tried to flag it as obsolete while creating a new attachment to 
</span><del>-    [% terms.bug %] [%+ my_bug_id FILTER html %].
</del><ins>+    [%+ terms.bug %] [%+ my_bug_id FILTER html %].
</ins><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;flags_not_available&quot; %]
-    [% title = &quot;Flag Editing not Allowed&quot; %]
-    [% IF type == &quot;b&quot; %]
-      Flags cannot be set or changed when
-      changing several [% terms.bugs %] at once.
-    [% ELSE %]
-      References to existing flags when creating
-      a new attachment are invalid.
-    [% END %] 
</del><ins>+  [% ELSIF error == &quot;feature_disabled&quot; %]
+    The [% install_string(&quot;feature_$feature&quot;) FILTER html %] feature is not
+    available in this [% terms.Bugzilla %]. 
+    [% IF user.in_group('admin') %]
+      If you would like to enable this feature, please run 
+      &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; to see how to install the necessary
+      requirements for this feature.
+    [% END %]
</ins><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;flag_unexpected_object&quot; %]
+    [% title = &quot;Object Not Recognized&quot; %]
+    Flags cannot be set for objects of type [% caller FILTER html %].
+    They can only be set for [% terms.bugs %] and attachments.
+
</ins><span class="cx">   [% ELSIF error == &quot;flag_requestee_disabled&quot; %]
</span><span class="cx">     [% title = &quot;Flag not Requestable from Specific Person&quot; %]
</span><span class="cx">     You can't ask a specific person for
</span><span class="cx">     &lt;em&gt;[% type.name FILTER html %]&lt;/em&gt;.
</span><span class="cx">   
</span><del>-  [% ELSIF error == &quot;flag_status_invalid&quot; %]
-    The flag status &lt;em&gt;[% status FILTER html %]&lt;/em&gt;
-    [% IF id %]
-      for flag ID #[% id FILTER html %]
-    [% END %]
-    is invalid.
-
</del><span class="cx">   [% ELSIF error == &quot;flag_type_inactive&quot; %]
</span><span class="cx">     [% title = &quot;Inactive Flag Type&quot; %]
</span><span class="cx">     The flag type [% type FILTER html %] is inactive and cannot be used
</span><span class="cx">     to create new flags.
</span><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;flag_type_nonexistent&quot; %]
-    There is no flag type with the ID &lt;em&gt;[% id FILTER html %]&lt;/em&gt;.
-
</del><span class="cx">   [% ELSIF error == &quot;flag_type_target_type_invalid&quot; %]
</span><span class="cx">     The target type was neither &lt;em&gt;[% terms.bug %]&lt;/em&gt; nor &lt;em&gt;attachment&lt;/em&gt;
</span><span class="cx">     but rather &lt;em&gt;[% target_type FILTER html %]&lt;/em&gt;.
</span><span class="lines">@@ -271,6 +295,17 @@
</span><span class="cx">       given.
</span><span class="cx">     [% END %]
</span><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;jobqueue_insert_failed&quot; %]
+   [% title = &quot;Job Queue Failure&quot; %]
+    Inserting a &lt;code&gt;[% job FILTER html %]&lt;/code&gt; job into the Job 
+    Queue failed with the following error: [% errmsg FILTER html %]
+
+  [% ELSIF error == &quot;jobqueue_no_job_mapping&quot; %]
+    &lt;code&gt;Bugzilla::JobQueue&lt;/code&gt; has not been configured to handle
+    the job &quot;[% job FILTER html %]&quot;.  You need to add this job type
+    to the &lt;code&gt;JOB_MAP&lt;/code&gt; constant in &lt;code&gt;Bugzilla::JobQueue&lt;/code&gt;,
+    perhaps by using the 'job_map' hook.
+
</ins><span class="cx">   [% ELSIF error == &quot;ldap_bind_failed&quot; %]
</span><span class="cx">     Failed to bind to the LDAP server. The error message was: 
</span><span class="cx">     &lt;code&gt;[% errstr FILTER html %]&lt;/code&gt;
</span><span class="lines">@@ -287,7 +322,11 @@
</span><span class="cx">   [% ELSIF error == &quot;ldap_search_error&quot; %]
</span><span class="cx">     An error occurred while trying to search LDAP for 
</span><span class="cx">     &amp;quot;[% username FILTER html %]&amp;quot;: 
</span><del>-   &lt;code&gt;[% errstr FILTER html %]&lt;/code&gt;
</del><ins>+    [% IF errstr %]
+      &lt;code&gt;[% errstr FILTER html %]&lt;/code&gt;
+    [% ELSE %]
+      Unable to find user in LDAP
+    [% END %]
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;ldap_server_not_defined&quot; %]
</span><span class="cx">     The LDAP server for authentication has not been defined.
</span><span class="lines">@@ -295,7 +334,7 @@
</span><span class="cx">   [% ELSIF error == &quot;mail_send_error&quot; %]
</span><span class="cx">     There was an error sending mail from '[% mail.header('From') FILTER html %]'
</span><span class="cx">     to '[% mail.header('To') FILTER html %]':
</span><del>-    [% msg FILTER html %]
</del><ins>+    [%+ msg FILTER html %]
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;missing_bug_id&quot; %]
</span><span class="cx">     No [% terms.bug %] ID was given.
</span><span class="lines">@@ -309,9 +348,10 @@
</span><span class="cx">   [% ELSIF error == &quot;need_quipid&quot; %]
</span><span class="cx">     A valid quipid is needed.
</span><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;no_manual_moved&quot; %]
-    You cannot set the resolution of [% terms.abug %] to MOVED without
-    moving the [% terms.bug %].
</del><ins>+  [% ELSIF error == &quot;object_dep_sort_loop&quot; %]
+    There is a loop in VALIDATOR_DEPENDENCIES involving
+    '[%+ field FILTER html %]'. Here are the fields we considered:
+    [%+ considered.join(', ') FILTER html %].
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;param_invalid&quot; %]
</span><span class="cx">     [% title = &quot;Invalid Parameter&quot; %]
</span><span class="lines">@@ -320,8 +360,8 @@
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;param_must_be_numeric&quot; %]
</span><span class="cx">     [% title = &quot;Invalid Parameter&quot; %]
</span><del>-    Invalid parameter passed to [% function FILTER html %].
-    It must be numeric.
</del><ins>+    Invalid parameter &lt;code&gt;[% param FILTER html %]&lt;/code&gt; passed to 
+    &lt;code&gt;[% function FILTER html %]&lt;/code&gt;: It must be numeric.
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;param_required&quot; %]
</span><span class="cx">     [% title = &quot;Missing Parameter&quot; %]
</span><span class="lines">@@ -329,6 +369,22 @@
</span><span class="cx">     a &lt;code&gt;[% param FILTER html %]&lt;/code&gt; argument, and that
</span><span class="cx">     argument was not set.
</span><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;params_required&quot; %]
+    [% title = &quot;Missing Parameter&quot; %]
+    The function &lt;code&gt;[% function FILTER html %]&lt;/code&gt; requires
+    that you set one of the following parameters:
+    &lt;code&gt;[% params.join(', ') FILTER html %]&lt;/code&gt;
+
+  [% ELSIF error == &quot;product_empty_group_controls&quot; %]
+    [% title = &quot;Missing Group Controls&quot; %]
+    New settings must be defined to edit group controls for
+    the [% group.name FILTER html %] group.
+
+  [% ELSIF error == &quot;product_illegal_group_control&quot; %]
+    [% title = &quot;Illegal Group Control&quot; %]
+    '[% value FILTER html %]' is not a legal value for
+    the '[% field FILTER html %]' field.
+
</ins><span class="cx">   [% ELSIF error == &quot;protection_violation&quot; %]
</span><span class="cx">     The function &lt;code&gt;[% function FILTER html %]&lt;/code&gt; was called
</span><span class="cx"> 
</span><span class="lines">@@ -349,12 +405,6 @@
</span><span class="cx">     An error occurred while preparing for a RADIUS authentication request:
</span><span class="cx">     &lt;code&gt;[% errstr FILTER html %]&lt;/code&gt;.
</span><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;unknown_comparison_type&quot; %]
-    Specified comparison type is not supported.
-
-  [% ELSIF error == &quot;request_queue_group_invalid&quot; %]
-    The group field &lt;em&gt;[% group FILTER html %]&lt;/em&gt; is invalid.
-
</del><span class="cx">   [% ELSIF error == &quot;report_axis_invalid&quot; %]
</span><span class="cx">     &lt;em&gt;[% val FILTER html %]&lt;/em&gt; is not a valid value for 
</span><span class="cx">     [%+ IF    fld == &quot;x&quot; %]the horizontal axis
</span><span class="lines">@@ -362,9 +412,16 @@
</span><span class="cx">     [%+ ELSIF fld == &quot;z&quot; %]the multiple tables/images
</span><span class="cx">     [%+ ELSE %]a report axis[% END %] field.
</span><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;search_cp_without_op&quot; %]
+    Search argument f[% id FILTER html %] is &quot;CP&quot; but there is no
+    matching &quot;OP&quot; before it.
+
+  [% ELSIF error == &quot;search_invalid_joiner&quot; %]
+    '[% joiner FILTER html %]' is not a valid joiner for a search.
+
</ins><span class="cx">   [% ELSIF error == &quot;setting_info_invalid&quot; %]
</span><span class="cx">     To create a new setting, you must supply a setting name, a list of 
</span><del>-    value/sortindex pairs, and the devault value.
</del><ins>+    value/sortindex pairs, and the default value.
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;setting_name_invalid&quot; %]
</span><span class="cx">     The setting name &lt;em&gt;[% name FILTER html %]&lt;/em&gt; is not a valid
</span><span class="lines">@@ -379,12 +436,6 @@
</span><span class="cx">     The value &quot;&lt;code&gt;[% value FILTER html %]&lt;/code&gt;&quot; is not in the list of
</span><span class="cx">     legal values for the &lt;em&gt;[% name FILTER html %]&lt;/em&gt; setting.
</span><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;soap_not_installed&quot; %]
-    [% admindocslinks = {'installation.html#install-perlmodules' =&gt; 'Installing Perl modules'} %]
-    The XMLRPC interface will not work without the SOAP::Lite Perl module being
-    installed.
-    Run checksetup.pl for installation instructions.
-
</del><span class="cx">   [% ELSIF error == &quot;token_generation_error&quot; %]
</span><span class="cx">     Something is seriously wrong with the token generation system.
</span><span class="cx"> 
</span><span class="lines">@@ -400,12 +451,8 @@
</span><span class="cx">   [% ELSIF error == &quot;undefined_field&quot; %]
</span><span class="cx">     Form field [% field FILTER html %] was not defined.
</span><span class="cx">     
</span><del>-  [% ELSIF error == &quot;unknown_action&quot; %]
-    [% IF action %]
-       Unknown action [% action FILTER html %]!
-    [% ELSE %]
-       I could not figure out what you wanted to do.
-    [% END %]
</del><ins>+  [% ELSIF error == &quot;unknown_method&quot; %]
+    The requested method '[% method FILTER html %]' was not found.
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;usage_mode_invalid&quot; %]
</span><span class="cx">     '[% invalid_usage_mode FILTER html %]' is not a valid usage mode.
</span><span class="lines">@@ -417,11 +464,6 @@
</span><span class="cx">   [% ELSIF error == &quot;not_in_transaction&quot; %]
</span><span class="cx">     Attempted to end transaction without starting one first.
</span><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;comma_operator_deprecated&quot; %]
-    [% title = &quot;SQL query generator internal error&quot; %]
-    There is an internal error in the SQL query generation code,
-    creating queries with implicit JOIN.
-
</del><span class="cx">   [% ELSIF error == &quot;invalid_post_bug_submit_action&quot; %]
</span><span class="cx">     Invalid setting for post_bug_submit_action
</span><span class="cx"> 
</span><span class="lines">@@ -478,14 +520,15 @@
</span><span class="cx"> 
</span><span class="cx"> &lt;table cellpadding=&quot;20&quot;&gt;
</span><span class="cx">   &lt;tr&gt;
</span><del>-    &lt;td bgcolor=&quot;#ff0000&quot;&gt;
-      &lt;font size=&quot;+2&quot;&gt;
-        [% error_message FILTER none %]
-      &lt;/font&gt;
</del><ins>+    &lt;td id=&quot;error_msg&quot; class=&quot;throw_error&quot;&gt;
+      [% error_message FILTER none %]
</ins><span class="cx">     &lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> &lt;/table&gt;
</span><span class="cx"> 
</span><ins>+&lt;p&gt;Traceback:&lt;/p&gt;
+&lt;pre&gt;[% traceback FILTER html %]&lt;/pre&gt;
+
</ins><span class="cx"> [% IF variables %]
</span><span class="cx">   &lt;pre&gt;
</span><span class="cx"> Variables:
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultglobalcommonlinkshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/global/common-links.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/global/common-links.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/global/common-links.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -20,10 +20,12 @@
</span><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [% DEFAULT qs_suffix = &quot;&quot; %]
</span><ins>+[% USE Bugzilla %]
</ins><span class="cx"> 
</span><span class="cx"> &lt;ul class=&quot;links&quot;&gt;
</span><span class="cx">   &lt;li&gt;&lt;a href=&quot;./&quot;&gt;Home&lt;/a&gt;&lt;/li&gt;
</span><span class="cx">   &lt;li&gt;&lt;span class=&quot;separator&quot;&gt;| &lt;/span&gt;&lt;a href=&quot;enter_bug.cgi&quot;&gt;New&lt;/a&gt;&lt;/li&gt;
</span><ins>+  &lt;li&gt;&lt;span class=&quot;separator&quot;&gt;| &lt;/span&gt;&lt;a href=&quot;describecomponents.cgi&quot;&gt;Browse&lt;/a&gt;&lt;/li&gt;
</ins><span class="cx">   &lt;li&gt;&lt;span class=&quot;separator&quot;&gt;| &lt;/span&gt;&lt;a href=&quot;query.cgi&quot;&gt;Search&lt;/a&gt;&lt;/li&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;li class=&quot;form&quot;&gt;
</span><span class="lines">@@ -32,9 +34,12 @@
</span><span class="cx">         onsubmit=&quot;if (this.quicksearch.value == '')
</span><span class="cx">                   { alert('Please enter one or more search terms first.');
</span><span class="cx">                     return false; } return true;&quot;&gt;
</span><del>-    &lt;input class=&quot;txt&quot; type=&quot;text&quot; id=&quot;quicksearch[% qs_suffix FILTER html %]&quot; name=&quot;quicksearch&quot;&gt;
-    &lt;input class=&quot;btn&quot; type=&quot;submit&quot; value=&quot;Find&quot; id=&quot;find[% qs_suffix FILTER html %]&quot;&gt;
-    [%-# Work around FF bug: keep this on one line %]&lt;/form&gt;&lt;/li&gt;
</del><ins>+    &lt;input class=&quot;txt&quot; type=&quot;text&quot; id=&quot;quicksearch[% qs_suffix FILTER html %]&quot; name=&quot;quicksearch&quot; 
+           title=&quot;Quick Search&quot; value=&quot;[% quicksearch FILTER html %]&quot;&gt;
+    &lt;input class=&quot;btn&quot; type=&quot;submit&quot; value=&quot;Search&quot; 
+           id=&quot;find[% qs_suffix FILTER html %]&quot;&gt;
+    [%-# Work around FF bug: keep this on one line %]&lt;/form&gt;
+  &lt;a href=&quot;page.cgi?id=quicksearch.html&quot; title=&quot;Quicksearch Help&quot;&gt;[?]&lt;/a&gt;&lt;/li&gt;
</ins><span class="cx"> 
</span><span class="cx">   &lt;li&gt;&lt;span class=&quot;separator&quot;&gt;| &lt;/span&gt;&lt;a href=&quot;report.cgi&quot;&gt;Reports&lt;/a&gt;&lt;/li&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -42,24 +47,20 @@
</span><span class="cx">     [% IF Param('shutdownhtml') || Bugzilla.has_flags %]
</span><span class="cx">       &lt;span class=&quot;separator&quot;&gt;| &lt;/span&gt;
</span><span class="cx">       [% IF user.id %]
</span><del>-        &lt;a href=&quot;request.cgi?requester=[% user.login FILTER url_quote %]&amp;amp;requestee=
-                 [% user.login FILTER url_quote %]&amp;amp;do_union=1&amp;amp;group=type&amp;amp;action=queue&quot;&gt;My Requests&lt;/a&gt;
</del><ins>+        &lt;a href=&quot;request.cgi?requester=[% user.login FILTER uri %]&amp;amp;requestee=
+                 [% user.login FILTER uri %]&amp;amp;do_union=1&amp;amp;group=type&amp;amp;action=queue&quot;&gt;My Requests&lt;/a&gt;
</ins><span class="cx">       [% ELSE %]
</span><span class="cx">         &lt;a href=&quot;request.cgi&quot;&gt;Requests&lt;/a&gt;
</span><span class="cx">       [% END %]
</span><span class="cx">     [% END %]
</span><span class="cx">   [%-# Work around FF bug: keep this on one line %]&lt;/li&gt;
</span><span class="cx"> 
</span><del>-  [% IF user.id &amp;&amp; Param('usevotes') %]
-    &lt;li&gt;&lt;span class=&quot;separator&quot;&gt;| &lt;/span&gt;&lt;a href=&quot;votes.cgi?action=show_user&quot;&gt;My&amp;nbsp;Votes&lt;/a&gt;&lt;/li&gt;
-  [% END %]
-
</del><span class="cx">   [% IF user.login %]
</span><span class="cx">     &lt;li&gt;&lt;span class=&quot;separator&quot;&gt;| &lt;/span&gt;&lt;a href=&quot;userprefs.cgi&quot;&gt;Preferences&lt;/a&gt;&lt;/li&gt;
</span><del>-    [% IF user.groups.tweakparams || user.groups.editusers || user.can_bless
-          || (Param('useclassification') &amp;&amp; user.groups.editclassifications)
-          || user.groups.editcomponents || user.groups.admin || user.groups.creategroups
-          || user.groups.editkeywords || user.groups.bz_canusewhines
</del><ins>+    [% IF user.in_group('tweakparams') || user.in_group('editusers') || user.can_bless
+          || (Param('useclassification') &amp;&amp; user.in_group('editclassifications'))
+          || user.in_group('editcomponents') || user.in_group('admin') || user.in_group('creategroups')
+          || user.in_group('editkeywords') || user.in_group('bz_canusewhines')
</ins><span class="cx">           || user.get_products_by_permission(&quot;editcomponents&quot;).size %]
</span><span class="cx">       &lt;li&gt;&lt;span class=&quot;separator&quot;&gt;| &lt;/span&gt;&lt;a href=&quot;admin.cgi&quot;&gt;Administration&lt;/a&gt;&lt;/li&gt;
</span><span class="cx">     [% END %]
</span><span class="lines">@@ -69,7 +70,7 @@
</span><span class="cx">     &lt;li&gt;
</span><span class="cx">       &lt;span class=&quot;separator&quot;&gt;| &lt;/span&gt;
</span><span class="cx">       [% IF user.authorizer.can_logout %]
</span><del>-        &lt;a href=&quot;relogin.cgi&quot;&gt;Log&amp;nbsp;out&lt;/a&gt;
</del><ins>+        &lt;a href=&quot;index.cgi?logout=1&quot;&gt;Log&amp;nbsp;out&lt;/a&gt;
</ins><span class="cx">       [% ELSE %]
</span><span class="cx">         Logged&amp;nbsp;in&amp;nbsp;as
</span><span class="cx">       [% END %]
</span><span class="lines">@@ -82,41 +83,29 @@
</span><span class="cx">       [% END %]
</span><span class="cx">     [%-# Work around FF bug: keep this on one line %]&lt;/li&gt;
</span><span class="cx">   [% ELSE %]
</span><ins>+  
+    [% PROCESS link_to_documentation %]
+    
</ins><span class="cx">     [% IF Param('createemailregexp')
</span><span class="cx">           &amp;&amp; user.authorizer.user_can_create_account %]
</span><del>-      &lt;li&gt;&lt;span class=&quot;separator&quot;&gt;| &lt;/span&gt;&lt;a href=&quot;createaccount.cgi&quot;&gt;New&amp;nbsp;Account&lt;/a&gt;&lt;/li&gt;
</del><ins>+      &lt;li id=&quot;new_account_container[% qs_suffix FILTER html %]&quot;&gt;
+        &lt;span class=&quot;separator&quot;&gt;| &lt;/span&gt;
+        &lt;a href=&quot;createaccount.cgi&quot;&gt;New&amp;nbsp;Account&lt;/a&gt;
+      &lt;/li&gt;
</ins><span class="cx">     [% END %]
</span><span class="cx"> 
</span><del>-    [% PROCESS link_to_documentation %]
-
-    [% IF user.authorizer.can_login %]
-      [%# Use the current script name. If an empty name is returned,
-        # then we are accessing the home page. %]
-
-      [% script_name = cgi.url(Relative =&gt; 1) %]
-
-      [% IF cgi.request_method == &quot;POST&quot; OR script_name.match(&quot;relogin&quot;) %]
-        [% script_name = &quot;&quot; %]
-      [% END %]
-
-      [%# If SSL is in use, use 'sslbase', else use 'urlbase'. %]
-      [% IF Param(&quot;sslbase&quot;) != &quot;&quot; &amp;&amp; Param(&quot;ssl&quot;) != &quot;never&quot; %]
-        [% script_name = Param(&quot;sslbase&quot;) _ script_name %]
-      [% ELSE %]
-        [% script_name = Param(&quot;urlbase&quot;) _ script_name %]
-      [% END %]
-
-      [% IF cgi.request_method == &quot;GET&quot; AND cgi.query_string %]
-        [% script_name = script_name _ &quot;?&quot; _ cgi.query_string %]
-        [% script_name = script_name _ &quot;&amp;GoAheadAndLogIn=1&quot; IF !cgi.query_string.match(&quot;GoAheadAndLogIn&quot;) %]
-      [% ELSE %]
-        [% script_name = script_name _ &quot;?GoAheadAndLogIn=1&quot; %]
-      [% END %]
-        
-      &lt;li&gt;&lt;span class=&quot;separator&quot;&gt;| &lt;/span&gt;&lt;a href=&quot;[% script_name FILTER html %]&quot;&gt;Log&amp;nbsp;In&lt;/a&gt;&lt;/li&gt;
</del><ins>+    [%# Only display one login form when we're on a LOGIN_REQUIRED page. That
+      # way, we're guaranteed that the user will use the form that has 
+      # hidden_fields in it (the center form) instead of this one. Also, it's
+      # less confusing to have one form (as opposed to  three) when you're 
+      # required to log in.
+      #%]
+    [% IF user.authorizer.can_login &amp;&amp; !Bugzilla.page_requires_login %]
+      [% PROCESS &quot;account/auth/login-small.html.tmpl&quot; %]
</ins><span class="cx">     [% END %]
</span><span class="cx">   [% END %]
</span><span class="cx"> &lt;/ul&gt;
</span><ins>+
</ins><span class="cx"> [% Hook.process(&quot;link-row&quot;) %]
</span><span class="cx"> [% BLOCK link_to_documentation %]
</span><span class="cx">     [% IF doc_section &amp;&amp; Param('docs_urlbase') %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultglobalconfirmactionhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/global/confirm-action.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/global/confirm-action.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/global/confirm-action.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -27,6 +27,7 @@
</span><span class="cx">                                    style_urls = ['skins/standard/global.css'] %]
</span><span class="cx"> 
</span><span class="cx"> &lt;div class=&quot;throw_error&quot;&gt;
</span><ins>+&lt;!--reason=[%reason FILTER html %]--&gt;
</ins><span class="cx">   [% IF reason == &quot;expired_token&quot; %]
</span><span class="cx">     Your changes have been rejected because you exceeded the time limit
</span><span class="cx">     of [% constants.MAX_TOKEN_AGE FILTER html %] days before submitting your
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultglobalconfirmusermatchhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/global/confirm-user-match.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/global/confirm-user-match.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/global/confirm-user-match.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -38,10 +38,26 @@
</span><span class="cx"> [%# use the global field descs %]
</span><span class="cx"> [% PROCESS &quot;global/field-descs.none.tmpl&quot; %]
</span><span class="cx"> 
</span><ins>+[%# This lists fields which use the user auto-completion feature and which
+  # are not listed in field_descs. %]
+[% field_labels = { # Used by editcomponents.cgi
+                    &quot;initialcc&quot;               =&gt; &quot;Default CC List&quot;,
+                    &quot;initialowner&quot;            =&gt; &quot;Default Assignee&quot;,
+                    &quot;initialqacontact&quot;        =&gt; &quot;Default QA Contact&quot;,
+                    # Used by process_bug.cgi
+                    &quot;masscc&quot;                  =&gt; &quot;CC List&quot;,
+                    # Used by request.cgi
+                    &quot;requester&quot;               =&gt; &quot;Requester&quot;,
+                    &quot;requestee&quot;               =&gt; &quot;Requestee&quot;,
+                    # Used by userprefs.cgi
+                    &quot;new_watchedusers&quot;        =&gt; &quot;Watch List&quot;,
+
+   }
+%]
</ins><span class="cx"> [% IF matchsuccess == 1 %]
</span><span class="cx">   [% PROCESS global/header.html.tmpl title=&quot;Confirm Match&quot; %]
</span><span class="cx"> 
</span><del>-[% USE Bugzilla %]
</del><ins>+  [% USE Bugzilla %]
</ins><span class="cx"> 
</span><span class="cx">   &lt;form method=&quot;post&quot; 
</span><span class="cx">   [% IF script -%]
</span><span class="lines">@@ -70,9 +86,13 @@
</span><span class="cx">   [% PROCESS global/header.html.tmpl title=&quot;Match Failed&quot; %]
</span><span class="cx">   &lt;p&gt;
</span><span class="cx">     [% terms.Bugzilla %] was unable to make any match at all for one or more of
</span><del>-    the names and/or email addresses you entered on the previous page.&lt;br&gt;
-    Please go back and try other names or email addresses.
</del><ins>+    the names and/or email addresses you entered on the previous page.
+    [% IF !user.id %]
+      &lt;b&gt;Note: You are currently logged out. Only exact matches against e-mail
+      addresses will be performed.&lt;/b&gt;
+    [% END %]
</ins><span class="cx">   &lt;/p&gt;
</span><ins>+  &lt;p&gt;Please go back and try other names or email addresses.&lt;/p&gt;
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx">   &lt;table border=&quot;0&quot;&gt;
</span><span class="lines">@@ -130,10 +150,11 @@
</span><span class="cx">                 [% ELSE %]
</span><span class="cx">                   matched
</span><span class="cx">                   &lt;b&gt;[% query.value.users.0.identity FILTER html %]&lt;/b&gt;
</span><ins>+                  &lt;input type=&quot;hidden&quot; name=&quot;[% field.key FILTER html %]&quot;
+                         value=&quot;[% query.value.users.0.login FILTER html %]&quot;&gt;
</ins><span class="cx">                 [% END %]
</span><span class="cx">             [% ELSE %]
</span><del>-                [% IF (query.key.length &lt; 3) &amp;&amp; !(Param('emailsuffix'))
-                    &amp;&amp; (Param('usermatchmode') == 'search') %]
</del><ins>+                [% IF (query.key.length &lt; 3) &amp;&amp; !Param('emailsuffix') %]
</ins><span class="cx">                   &lt;font color=&quot;#FF0000&quot;&gt;was too short for substring match
</span><span class="cx">                   (minimum 3 characters)&lt;/font&gt;
</span><span class="cx">                 [% ELSE %]
</span><span class="lines">@@ -155,7 +176,10 @@
</span><span class="cx"> 
</span><span class="cx"> [% IF matchsuccess == 1 %]
</span><span class="cx"> 
</span><del>-  [% PROCESS &quot;global/hidden-fields.html.tmpl&quot; exclude=&quot;^Bugzilla_(login|password)$&quot; %]
</del><ins>+  [% SET exclude_these = 
+           matches.keys.merge(['Bugzilla_login', 'Bugzilla_password']) %]
+  [% SET exclude = '^' _ exclude_these.join('|') _ '$' %]
+  [% PROCESS &quot;global/hidden-fields.html.tmpl&quot; exclude = exclude %]
</ins><span class="cx"> 
</span><span class="cx">   &lt;p&gt;
</span><span class="cx">     &lt;input type=&quot;submit&quot; id=&quot;continue&quot; value=&quot;Continue&quot;&gt;
</span><span class="lines">@@ -170,14 +194,12 @@
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK field_names %]
</span><span class="cx"> 
</span><del>-  [% IF field_descs.${field_name} %]
-    [%  field_descs.${field_name} FILTER html -%]
-
-  [%-# ELSIF for things that don't belong in the field_descs hash here -%]
-
</del><ins>+  [% IF field_descs.$field_name %]
+    [% field_descs.$field_name FILTER html %]
+  [% ELSIF field_labels.$field_name %]
+    [% field_labels.$field_name FILTER html %]
</ins><span class="cx">   [% ELSIF field_name.match(&quot;^requestee&quot;) %]
</span><span class="cx">     [% fields.${field_name}.flag_type.name %] requestee
</span><del>-
</del><span class="cx">   [% ELSE %]
</span><span class="cx">     [% field_name FILTER html %]
</span><span class="cx">   [% END %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultglobalfielddescsnonetmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/global/field-descs.none.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/global/field-descs.none.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/global/field-descs.none.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -16,115 +16,141 @@
</span><span class="cx">   # Rights Reserved.
</span><span class="cx">   #
</span><span class="cx">   # Contributor(s): Gervase Markham &lt;gerv@gerv.net&gt;
</span><ins>+  #                 Elliotte Martin &lt;elliotte_martin@yahoo.com&gt;
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [%# Remember to PROCESS rather than INCLUDE this template. %]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="cx"> 
</span><del>-[% field_descs = { &quot;[Bug creation]&quot;          =&gt; &quot;[$terms.Bug creation]&quot;,
-                   &quot;actual_time&quot;             =&gt; &quot;Actual Hours&quot;
-                   &quot;alias&quot;                   =&gt; &quot;Alias&quot;,
-                   &quot;assigned_to&quot;             =&gt; &quot;Assignee&quot;,
-                   &quot;attach_data.thedata&quot;     =&gt; &quot;Attachment data&quot;,
-                   &quot;attachments.description&quot; =&gt; &quot;Attachment description&quot;,
-                   &quot;attachments.filename&quot;    =&gt; &quot;Attachment filename&quot;,
-                   &quot;attachments.mimetype&quot;    =&gt; &quot;Attachment mime type&quot;,
-                   &quot;attachments.ispatch&quot;     =&gt; &quot;Attachment is patch&quot;,
-                   &quot;attachments.isobsolete&quot;  =&gt; &quot;Attachment is obsolete&quot;,
-                   &quot;attachments.isprivate&quot;   =&gt; &quot;Attachment is private&quot;,
-                   &quot;attachments.isurl&quot;       =&gt; &quot;Attachment is a URL&quot;,
-                   &quot;attachments.submitter&quot;   =&gt; &quot;Attachment creator&quot;,
-                   &quot;blocked&quot;                 =&gt; &quot;Blocks&quot;,
-                   &quot;bug_file_loc&quot;            =&gt; &quot;URL&quot;,
-                   &quot;bug_group&quot;               =&gt; &quot;Group&quot;,
-                   &quot;bug_id&quot;                  =&gt; &quot;$terms.Bug ID&quot;,
-                   &quot;bug_severity&quot;            =&gt; &quot;Severity&quot;,
-                   &quot;bug_status&quot;              =&gt; &quot;Status&quot;,
-                   &quot;changeddate&quot;             =&gt; &quot;Changed&quot;,
-                   &quot;cc&quot;                      =&gt; &quot;CC&quot;,
-                   &quot;classification&quot;          =&gt; &quot;Classification&quot;,
-                   &quot;cclist_accessible&quot;       =&gt; &quot;CC list accessible&quot;,
-                   &quot;commenter&quot;               =&gt; &quot;Commenter&quot;,
-                   &quot;component_id&quot;            =&gt; &quot;Component ID&quot;,
-                   &quot;component&quot;               =&gt; &quot;Component&quot;,
-                   &quot;content&quot;                 =&gt; &quot;Content&quot;,
-                   &quot;creation_ts&quot;             =&gt; &quot;Creation date&quot;,
-                   &quot;deadline&quot;                =&gt; &quot;Deadline&quot;,
-                   &quot;delta_ts&quot;                =&gt; &quot;Changed&quot;,
-                   &quot;dependson&quot;               =&gt; &quot;Depends on&quot;,
-                   &quot;dup_id&quot;                  =&gt; &quot;Duplicate&quot;,
-                   &quot;estimated_time&quot;          =&gt; &quot;Orig. Est.&quot;,
-                   &quot;everconfirmed&quot;           =&gt; &quot;Ever confirmed&quot;,
-                   &quot;flagtypes.name&quot;          =&gt; &quot;Flag&quot;,
-                   &quot;keywords&quot;                =&gt; &quot;Keywords&quot;,
-                   &quot;longdesc&quot;                =&gt; &quot;Comment&quot;,
-                   &quot;longdescs.isprivate&quot;     =&gt; &quot;Comment is private&quot;,
-                   &quot;newcc&quot;                   =&gt; &quot;CC&quot;,
-                   &quot;op_sys&quot;                  =&gt; &quot;OS&quot;,
-                   &quot;opendate&quot;                =&gt; &quot;Opened&quot;,
-                   &quot;owner_idle_time&quot;         =&gt; &quot;Time Since Assignee Touched&quot;,
-                   &quot;percentage_complete&quot;     =&gt; &quot;%Complete&quot;,
-                   &quot;priority&quot;                =&gt; &quot;Priority&quot;,
-                   &quot;product_id&quot;              =&gt; &quot;Product ID&quot;,
-                   &quot;product&quot;                 =&gt; &quot;Product&quot;,
-                   &quot;qa_contact&quot;              =&gt; &quot;QA Contact&quot;,
-                   &quot;remaining_time&quot;          =&gt; &quot;Hours Left&quot;,
-                   &quot;rep_platform&quot;            =&gt; &quot;Hardware&quot;,
-                   &quot;reporter&quot;                =&gt; &quot;Reporter&quot;,
-                   &quot;reporter_accessible&quot;     =&gt; &quot;Reporter accessible&quot;,
-                   &quot;requestees.login_name&quot;   =&gt; &quot;Flag Requestee&quot;,
-                   &quot;resolution&quot;              =&gt; &quot;Resolution&quot;,
-                   &quot;setters.login_name&quot;      =&gt; &quot;Flag Setter&quot;,
-                   &quot;setting&quot;                 =&gt; &quot;Setting&quot;,
-                   &quot;settings&quot;                =&gt; &quot;Settings&quot;,
-                   &quot;short_desc&quot;              =&gt; &quot;Summary&quot;,
-                   &quot;status_whiteboard&quot;       =&gt; &quot;Whiteboard&quot;,
-                   &quot;target_milestone&quot;        =&gt; &quot;Target Milestone&quot;,
-                   &quot;version&quot;                 =&gt; &quot;Version&quot;,
-                   &quot;votes&quot;                   =&gt; &quot;Votes&quot;,
-                   &quot;work_time&quot;               =&gt; &quot;Hours Worked&quot;} %]
</del><ins>+[% SET search_descs = {
+  &quot;noop&quot;           =&gt; &quot;---&quot;,
+  &quot;equals&quot;         =&gt; &quot;is equal to&quot;,
+  &quot;notequals&quot;      =&gt; &quot;is not equal to&quot;,
+  &quot;anyexact&quot;       =&gt; &quot;is equal to any of the strings&quot;,
+  &quot;substring&quot;      =&gt; &quot;contains the string&quot;,
+  &quot;casesubstring&quot;  =&gt; &quot;contains the string (exact case)&quot;,
+  &quot;notsubstring&quot;   =&gt; &quot;does not contain the string&quot;,
+  &quot;anywordssubstr&quot; =&gt; &quot;contains any of the strings&quot;,
+  &quot;allwordssubstr&quot; =&gt; &quot;contains all of the strings&quot;,
+  &quot;nowordssubstr&quot;  =&gt; &quot;contains none of the strings&quot;,
+  &quot;regexp&quot;         =&gt; &quot;matches regular expression&quot;,
+  &quot;notregexp&quot;      =&gt; &quot;does not match regular expression&quot;,
+  &quot;lessthan&quot;       =&gt; &quot;is less than&quot;,
+  &quot;lessthaneq&quot;     =&gt; &quot;is less than or equal to&quot;,
+  &quot;greaterthan&quot;    =&gt; &quot;is greater than&quot;,
+  &quot;greaterthaneq&quot;  =&gt; &quot;is greater than or equal to&quot;,
+  &quot;anywords&quot;       =&gt; &quot;contains any of the words&quot;,
+  &quot;allwords&quot;       =&gt; &quot;contains all of the words&quot;,
+  &quot;nowords&quot;        =&gt; &quot;contains none of the words&quot;,
+  &quot;changedbefore&quot;  =&gt; &quot;changed before&quot;,
+  &quot;changedafter&quot;   =&gt; &quot;changed after&quot;,
+  &quot;changedfrom&quot;    =&gt; &quot;changed from&quot;,
+  &quot;changedto&quot;      =&gt; &quot;changed to&quot;,
+  &quot;changedby&quot;      =&gt; &quot;changed by&quot;,
+  &quot;matches&quot;        =&gt; &quot;matches&quot;,
+  &quot;notmatches&quot;      =&gt; &quot;does not match&quot;,
+} %]
</ins><span class="cx"> 
</span><del>-[%# Also include any custom fields or fields which don't have a
-    Description here, by copying their Description from the
-    database. If you want to override this for your language
-    or your installation, just use a hook. %]
-
-[% UNLESS Param('shutdownhtml') %]
-  [% USE Bugzilla %]
-  [% FOREACH bz_field = Bugzilla.get_fields() %]
-    [% SET field_descs.${bz_field.name} = bz_field.description
-       IF !field_descs.${bz_field.name}.defined %]
-  [% END %]
-[% END %]
-
</del><span class="cx"> [% field_types = { ${constants.FIELD_TYPE_UNKNOWN}       =&gt; &quot;Unknown Type&quot;,
</span><span class="cx">                    ${constants.FIELD_TYPE_FREETEXT}      =&gt; &quot;Free Text&quot;,
</span><span class="cx">                    ${constants.FIELD_TYPE_SINGLE_SELECT} =&gt; &quot;Drop Down&quot;,
</span><span class="cx">                    ${constants.FIELD_TYPE_MULTI_SELECT}  =&gt; &quot;Multiple-Selection Box&quot;,
</span><span class="cx">                    ${constants.FIELD_TYPE_TEXTAREA}      =&gt; &quot;Large Text Box&quot;,
</span><span class="cx">                    ${constants.FIELD_TYPE_DATETIME}      =&gt; &quot;Date/Time&quot;,
</span><ins>+                   ${constants.FIELD_TYPE_BUG_ID}        =&gt; &quot;$terms.Bug ID&quot;,
</ins><span class="cx">                 } %]
</span><span class="cx"> 
</span><del>-[% status_descs = { &quot;UNCONFIRMED&quot; =&gt; &quot;UNCONFIRMED&quot;,
-                    &quot;NEW&quot;         =&gt; &quot;NEW&quot;,
-                    &quot;ASSIGNED&quot;    =&gt; &quot;ASSIGNED&quot;,
-                    &quot;REOPENED&quot;    =&gt; &quot;REOPENED&quot;,
-                    &quot;RESOLVED&quot;    =&gt; &quot;RESOLVED&quot;,
-                    &quot;VERIFIED&quot;    =&gt; &quot;VERIFIED&quot;,
-                    &quot;CLOSED&quot;      =&gt; &quot;CLOSED&quot; } %]
</del><ins>+[% IF in_template_var %]
+  [% PROCESS &quot;global/value-descs.none.tmpl&quot; %]
+  [% SET vars.value_descs = value_descs %]
+  [% SET vars.terms = terms %]
</ins><span class="cx"> 
</span><del>-[% MACRO get_status(status) GET status_descs.$status || status %]
</del><ins>+  [%# field_descs is loaded as a global template variable and cached
+    # across all templates--see VARIABLES in Bugzilla/Template.pm.
+    #%]
+  [% vars.field_descs = {
+    &quot;[Bug creation]&quot;          =&gt; &quot;[$terms.Bug creation]&quot;,
+     &quot;actual_time&quot;             =&gt; &quot;Actual Hours&quot;,
+     &quot;alias&quot;                   =&gt; &quot;Alias&quot;,
+     &quot;assigned_to&quot;             =&gt; &quot;Assignee&quot;,
+     &quot;assigned_to_realname&quot;    =&gt; &quot;Assignee Real Name&quot;,
+     &quot;attach_data.thedata&quot;     =&gt; &quot;Attachment data&quot;,
+     &quot;attachments.description&quot; =&gt; &quot;Attachment description&quot;,
+     &quot;attachments.filename&quot;    =&gt; &quot;Attachment filename&quot;,
+     &quot;attachments.mimetype&quot;    =&gt; &quot;Attachment mime type&quot;,
+     &quot;attachments.ispatch&quot;     =&gt; &quot;Attachment is patch&quot;,
+     &quot;attachments.isobsolete&quot;  =&gt; &quot;Attachment is obsolete&quot;,
+     &quot;attachments.isprivate&quot;   =&gt; &quot;Attachment is private&quot;,
+     &quot;attachments.submitter&quot;   =&gt; &quot;Attachment creator&quot;,
+     &quot;blocked&quot;                 =&gt; &quot;Blocks&quot;,
+     &quot;bug_file_loc&quot;            =&gt; &quot;URL&quot;,
+     &quot;bug_group&quot;               =&gt; &quot;Group&quot;,
+     &quot;bug_id&quot;                  =&gt; &quot;$terms.Bug ID&quot;,
+     &quot;bug_severity&quot;            =&gt; &quot;Severity&quot;,
+     &quot;bug_status&quot;              =&gt; &quot;Status&quot;,
+     &quot;changeddate&quot;             =&gt; &quot;Changed&quot;,
+     &quot;cc&quot;                      =&gt; &quot;CC&quot;,
+     &quot;classification&quot;          =&gt; &quot;Classification&quot;,
+     &quot;cclist_accessible&quot;       =&gt; &quot;CC list accessible&quot;,
+     &quot;commenter&quot;               =&gt; &quot;Commenter&quot;,
+     &quot;component_id&quot;            =&gt; &quot;Component ID&quot;,
+     &quot;component&quot;               =&gt; &quot;Component&quot;,
+     &quot;content&quot;                 =&gt; &quot;Content&quot;,
+     &quot;creation_ts&quot;             =&gt; &quot;Creation date&quot;,
+     &quot;days_elapsed&quot;            =&gt; &quot;Days since $terms.bug changed&quot;,
+     &quot;deadline&quot;                =&gt; &quot;Deadline&quot;,
+     &quot;delta_ts&quot;                =&gt; &quot;Changed&quot;,
+     &quot;dependson&quot;               =&gt; &quot;Depends on&quot;,
+     &quot;dup_id&quot;                  =&gt; &quot;Duplicate&quot;,
+     &quot;estimated_time&quot;          =&gt; &quot;Orig. Est.&quot;,
+     &quot;everconfirmed&quot;           =&gt; &quot;Ever confirmed&quot;,
+     &quot;flagtypes.name&quot;          =&gt; &quot;Flags&quot;,
+     &quot;keywords&quot;                =&gt; &quot;Keywords&quot;,
+     &quot;longdesc&quot;                =&gt; &quot;Comment&quot;,
+     &quot;longdescs.count&quot;         =&gt; &quot;Number of Comments&quot;,
+     &quot;longdescs.isprivate&quot;     =&gt; &quot;Comment is private&quot;,
+     &quot;newcc&quot;                   =&gt; &quot;CC&quot;,
+     &quot;op_sys&quot;                  =&gt; &quot;OS&quot;,
+     &quot;opendate&quot;                =&gt; &quot;Opened&quot;,
+     &quot;owner_idle_time&quot;         =&gt; &quot;Time Since Assignee Touched&quot;,
+     &quot;percentage_complete&quot;     =&gt; &quot;%Complete&quot;,
+     &quot;priority&quot;                =&gt; &quot;Priority&quot;,
+     &quot;product_id&quot;              =&gt; &quot;Product ID&quot;,
+     &quot;product&quot;                 =&gt; &quot;Product&quot;,
+     &quot;qa_contact&quot;              =&gt; &quot;QA Contact&quot;,
+     &quot;qa_contact_realname&quot;     =&gt; &quot;QA Contact Real Name&quot;,
+     &quot;remaining_time&quot;          =&gt; &quot;Hours Left&quot;,
+     &quot;rep_platform&quot;            =&gt; &quot;Hardware&quot;,
+     &quot;reporter&quot;                =&gt; &quot;Reporter&quot;,
+     &quot;reporter_accessible&quot;     =&gt; &quot;Reporter accessible&quot;,
+     &quot;reporter_realname&quot;       =&gt; &quot;Reporter Real Name&quot;,
+     &quot;requestees.login_name&quot;   =&gt; &quot;Flag Requestee&quot;,
+     &quot;resolution&quot;              =&gt; &quot;Resolution&quot;,
+     &quot;see_also&quot;                =&gt; &quot;See Also&quot;,
+     &quot;setters.login_name&quot;      =&gt; &quot;Flag Setter&quot;,
+     &quot;setting&quot;                 =&gt; &quot;Setting&quot;,
+     &quot;settings&quot;                =&gt; &quot;Settings&quot;,
+     &quot;short_desc&quot;              =&gt; &quot;Summary&quot;,
+     &quot;status_whiteboard&quot;       =&gt; &quot;Whiteboard&quot;,
+     &quot;tag.name&quot;                =&gt; &quot;Tags&quot;,
+     &quot;target_milestone&quot;        =&gt; &quot;Target Milestone&quot;,
+     &quot;version&quot;                 =&gt; &quot;Version&quot;,
+     &quot;work_time&quot;               =&gt; &quot;Hours Worked&quot;,
+  } %]
</ins><span class="cx"> 
</span><del>-[% resolution_descs = { &quot;FIXED&quot;      =&gt; &quot;FIXED&quot;,
-                        &quot;INVALID&quot;    =&gt; &quot;INVALID&quot;,
-                        &quot;WONTFIX&quot;    =&gt; &quot;WONTFIX&quot;,
-                        &quot;DUPLICATE&quot;  =&gt; &quot;DUPLICATE&quot;,
-                        &quot;WORKSFORME&quot; =&gt; &quot;WORKSFORME&quot;,
-                        &quot;MOVED&quot;      =&gt; &quot;MOVED&quot;,
-                        &quot;---&quot;        =&gt; &quot;---&quot;,
-                        &quot; &quot;          =&gt; &quot; &quot; } %]
</del><ins>+  [%# Also include any custom fields or fields which don't have a
+      Description here, by copying their Description from the
+      database. If you want to override this for your language
+      or your installation, just use a hook. %]
+  [% UNLESS Param('shutdownhtml') %]
+    [% FOREACH bz_field = bug_fields.values %]
+      [% SET vars.field_descs.${bz_field.name} = bz_field.description
+         IF !vars.field_descs.${bz_field.name}.defined %]
+    [% END %]
+  [% END %]
</ins><span class="cx"> 
</span><del>-[% MACRO get_resolution(res) GET resolution_descs.$res || res %]
</del><ins>+  [% PROCESS &quot;bug/field-help.none.tmpl&quot; %]
+[% END %]
</ins><span class="cx"> 
</span><span class="cx"> [% Hook.process(&quot;end&quot;) %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultglobalfooterhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/global/footer.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/global/footer.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/global/footer.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -33,7 +33,7 @@
</span><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> &lt;div id=&quot;footer&quot;&gt;
</span><del>-  &lt;div class=&quot;intro&quot;&gt;&lt;/div&gt;
</del><ins>+  &lt;div class=&quot;intro&quot;&gt;[% Hook.process('intro') %]&lt;/div&gt;
</ins><span class="cx"> 
</span><span class="cx"> [%# Migration note: the old param 'blurbhtml' goes here %]
</span><span class="cx"> 
</span><span class="lines">@@ -41,9 +41,11 @@
</span><span class="cx"> 
</span><span class="cx">            [% PROCESS &quot;global/useful-links.html.tmpl&quot; %]
</span><span class="cx"> 
</span><del>-  &lt;div class=&quot;outro&quot;&gt;&lt;/div&gt;
</del><ins>+  &lt;div class=&quot;outro&quot;&gt;[% Hook.process('outro') %]&lt;/div&gt;
</ins><span class="cx"> &lt;/div&gt;
</span><del>-&lt;script defer src=&quot;/committers-autocomplete.js&quot;&gt;&lt;/script&gt;
</del><ins>+
+[% Hook.process(&quot;end&quot;) %]
+
</ins><span class="cx"> &lt;/body&gt;
</span><span class="cx"> &lt;/html&gt;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultglobalheaderhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/global/header.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/global/header.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/global/header.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -46,8 +46,41 @@
</span><span class="cx">   header_addl_info = &quot;&quot;
</span><span class="cx">   onload = &quot;&quot;
</span><span class="cx">   style_urls = []
</span><ins>+  yui = []
</ins><span class="cx"> %]
</span><span class="cx"> 
</span><ins>+[% SET yui_css = {
+  autocomplete =&gt; 1,
+  calendar     =&gt; 1,
+  datatable    =&gt; 1,
+  button       =&gt; 1,
+} %]
+
+[%# Note: This is simple dependency resolution--you can't have dependencies
+  # that depend on each other. You have to specify all of a module's deps,
+  # if that module is going to be specified in &quot;yui&quot;.
+  #%]
+[% SET yui_deps = {
+  autocomplete =&gt; ['json', 'connection', 'datasource'],
+  datatable    =&gt; ['json', 'connection', 'datasource', 'element'],
+} %]
+
+[%# When using certain YUI modules, we need to process certain
+  # extra JS templates.
+  #%]
+[% SET yui_templates = {
+  datatable =&gt; ['global/value-descs.js.tmpl'],
+} %]
+
+[%# These are JS URLs that are *always* on the page and come before
+  # every other JS URL.
+  #%]
+[% SET starting_js_urls = [
+    &quot;js/yui/yahoo-dom-event/yahoo-dom-event.js&quot;,
+    &quot;js/yui/cookie/cookie-min.js&quot;,
+] %]
+
+
</ins><span class="cx"> [%# We should be able to set the default value of the header variable
</span><span class="cx">   # to the value of the title variable using the DEFAULT directive,
</span><span class="cx">   # but that doesn't work if a caller sets header to the empty string
</span><span class="lines">@@ -59,105 +92,48 @@
</span><span class="cx"> 
</span><span class="cx"> &lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;
</span><span class="cx">                       &quot;http://www.w3.org/TR/html4/loose.dtd&quot;&gt;
</span><del>-&lt;html&gt;
</del><ins>+&lt;html lang=&quot;en&quot;&gt;
</ins><span class="cx">   &lt;head&gt;
</span><ins>+    [% Hook.process(&quot;start&quot;) %]
</ins><span class="cx">     &lt;title&gt;[% title %]&lt;/title&gt;
</span><span class="cx"> 
</span><ins>+    [% IF Param('utf8') %]
+      &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;&gt;
+    [% END %]
+
</ins><span class="cx"> [%# Migration note: contents of the old Param 'headerhtml' would go here %]
</span><span class="cx"> 
</span><span class="cx">     [% PROCESS &quot;global/site-navigation.html.tmpl&quot; %]
</span><span class="cx"> 
</span><span class="cx">     [% PROCESS 'global/setting-descs.none.tmpl' %]
</span><span class="cx"> 
</span><del>-    [%# Set up the skin CSS cascade:
-      #  1. Standard Bugzilla stylesheet set (persistent)
-      #  2. Standard Bugzilla stylesheet set (selectable)
-      #  3. All third-party &quot;skin&quot; stylesheet sets (selectable)
-      #  4. Page-specific styles
-      #  5. Custom Bugzilla stylesheet set (persistent)
-      # &quot;Selectable&quot; skin file sets may be either preferred or alternate.
-      # Exactly one is preferred, determined by the &quot;skin&quot; user preference.
-      #%]
-    [% IF user.settings.skin.value != 'standard' %]
-      [% user_skin = user.settings.skin.value %]
-    [% END %]
-    [% style_urls.unshift('skins/standard/global.css') %]
</del><ins>+    [% SET yui = yui_resolve_deps(yui, yui_deps) %]
+    [% SET css_sets = css_files(style_urls, yui, yui_css) %]
</ins><span class="cx"> 
</span><span class="cx">     [%# CSS cascade, part 1: Standard Bugzilla stylesheet set (persistent).
</span><span class="cx">       # Always present.
</span><span class="cx">       #%]
</span><del>-    [% FOREACH style_url = style_urls %]
-      &lt;link href=&quot;[% style_url FILTER html %]&quot;
-            rel=&quot;stylesheet&quot;
-            type=&quot;text/css&quot;&gt;
</del><ins>+    [%# This allows people to switch back to the &quot;Classic&quot; skin if they
+      # are in another skin. 
+      #%]
+    &lt;link href=&quot;[% 'skins/standard/global.css' FILTER mtime FILTER html %]&quot;
+          rel=&quot;alternate stylesheet&quot; 
+          title=&quot;[% setting_descs.standard FILTER html %]&quot;&gt;
+    [% FOREACH style_url = css_sets.standard %]
+      [% PROCESS format_css_link css_set_name = 'standard' %]
</ins><span class="cx">     [% END %]
</span><del>-    &lt;!--[if IE]&gt;
-      [%# Internet Explorer treats [if IE] HTML comments as uncommented.
-        # Use it to import CSS fixes so that Bugzilla looks decent on IE, too.
-        #%]
-      &lt;link href=&quot;skins/standard/IE-fixes.css&quot;
-            rel=&quot;stylesheet&quot;
-            type=&quot;text/css&quot;&gt;
-    &lt;![endif]--&gt;
</del><span class="cx"> 
</span><del>-    [%# CSS cascade, part 2: Standard Bugzilla stylesheet set (selectable)
-      # Present if skin selection is enabled.
</del><ins>+    [%# CSS cascade, part 2 &amp; 3: Third-party stylesheet set (selected and
+      # selectable). All third-party skins are present as alternate
+      # stylesheets, even if they are not currently in use.
</ins><span class="cx">       #%]
</span><del>-    [% IF user.settings.skin.is_enabled %]
-      [% FOREACH style_url = style_urls %]
-        &lt;link href=&quot;[% style_url FILTER html %]&quot;
-              rel=&quot;[% 'alternate ' IF user_skin %]stylesheet&quot;
-              title=&quot;[% setting_descs.standard FILTER html %]&quot;
-              type=&quot;text/css&quot;&gt;
-      [% END %]
-      &lt;!--[if IE]&gt;
-        [%# Internet Explorer treats [if IE] HTML comments as uncommented.
-          # Use it to import CSS fixes so that Bugzilla looks decent on IE,
-          # too.
-          #%]
-        &lt;link href=&quot;skins/standard/IE-fixes.css&quot;
-              rel=&quot;[% 'alternate ' IF user_skin %]stylesheet&quot;
-              title=&quot;[% setting_descs.standard FILTER html %]&quot;
-              type=&quot;text/css&quot;&gt;
-      &lt;![endif]--&gt;
</del><ins>+    [% FOREACH style_url = css_sets.skin %]
+      [% PROCESS format_css_link css_set_name = user.settings.skin.value %]
</ins><span class="cx">     [% END %]
</span><span class="cx"> 
</span><del>-    [%# CSS cascade, part 3: Third-party stylesheet set (selectable).
-      # All third-party skins are present if skin selection is enabled.
-      # The admin-selected skin is always present.
-      #%]
-    [% FOREACH contrib_skin = user.settings.skin.legal_values %]
-      [% NEXT IF contrib_skin == 'standard' %]
-      [% NEXT UNLESS contrib_skin == user_skin
-                  OR user.settings.skin.is_enabled %]
-      [% contrib_skin = contrib_skin FILTER url_quote %]
-      [% IF contrib_skin.match('\.css$') %]
-        [%# 1st skin variant: single-file stylesheet %]
-        &lt;link href=&quot;[% &quot;skins/contrib/$contrib_skin&quot; %]&quot;
-              rel=&quot;[% 'alternate ' UNLESS contrib_skin == user_skin %]stylesheet&quot;
-              title=&quot;[% contrib_skin FILTER html %]&quot;
-              type=&quot;text/css&quot;&gt;
-      [% ELSE %]
-        [%# 2nd skin variant: stylesheet set %]
-        [% FOREACH style_url = style_urls %]
-          [% IF style_url.match('^skins/standard/') %]
-            &lt;link href=&quot;[% style_url.replace('^skins/standard/',
-                                             &quot;skins/contrib/$contrib_skin/&quot;) %]&quot;
-                  rel=&quot;[% 'alternate ' UNLESS contrib_skin == user_skin %]stylesheet&quot;
-                  title=&quot;[% contrib_skin FILTER html %]&quot;
-                  type=&quot;text/css&quot;&gt;
-          [% END %]
-        [% END %]
-        &lt;!--[if IE]&gt;
-          [%# Internet Explorer treats [if IE] HTML comments as uncommented.
-            # Use it to import CSS fixes so that Bugzilla looks decent on IE,
-            # too.
-            #%]
-          &lt;link href=&quot;skins/contrib/[% contrib_skin FILTER html %]/IE-fixes.css&quot;
-                rel=&quot;[% 'alternate ' UNLESS contrib_skin == user_skin %]stylesheet&quot;
-                title=&quot;[% contrib_skin FILTER html %]&quot;
-                type=&quot;text/css&quot;&gt;
-        &lt;![endif]--&gt;
</del><ins>+    [% FOREACH alternate_skin = css_sets.alternate.keys %]
+      [% FOREACH style_url = css_sets.alternate.$alternate_skin %]
+        [% PROCESS format_css_link css_set_name = alternate_skin %]
</ins><span class="cx">       [% END %]
</span><span class="cx">     [% END %]
</span><span class="cx"> 
</span><span class="lines">@@ -173,39 +149,85 @@
</span><span class="cx">       # Always present. Site administrators may override all other style
</span><span class="cx">       # definitions, including skins, using custom stylesheets.
</span><span class="cx">       #%]
</span><del>-    [% FOREACH style_url = style_urls %]
-      [% IF style_url.match('^skins/standard/') %]
-        &lt;link href=&quot;[% style_url.replace('^skins/standard/', &quot;skins/custom/&quot;)
-                       FILTER html %]&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot;&gt;
-      [% END %]
</del><ins>+    [% FOREACH style_url = css_sets.custom %]
+      [% PROCESS format_css_link css_set_name = 'standard' %]
</ins><span class="cx">     [% END %]
</span><del>-    &lt;!--[if IE]&gt;
-      [%# Internet Explorer treats [if IE] HTML comments as uncommented.
-        # Use it to import CSS fixes so that Bugzilla looks decent on IE, too.
-        #%]
-      &lt;link href=&quot;skins/custom/IE-fixes.css&quot;
-            rel=&quot;stylesheet&quot;
-            type=&quot;text/css&quot;&gt;
-    &lt;![endif]--&gt;
</del><span class="cx"> 
</span><ins>+    [%# YUI Scripts %]
+    [% FOREACH yui_name = yui %]
+      [% starting_js_urls.push(&quot;js/yui/$yui_name/${yui_name}-min.js&quot;) %]
+    [% END %]
+    [% starting_js_urls.push('js/global.js') %]
</ins><span class="cx"> 
</span><del>-    [% IF javascript %]
-      &lt;script type=&quot;text/javascript&quot;&gt;
-        [% javascript %]
-      &lt;/script&gt;
</del><ins>+    [% FOREACH javascript_url = starting_js_urls %]
+      [% PROCESS format_js_link %]
</ins><span class="cx">     [% END %]
</span><span class="cx"> 
</span><del>-    [% IF javascript_urls %]
-      [% FOREACH javascript_url = javascript_urls %]
-        &lt;script src=&quot;[% javascript_url FILTER html %]&quot; type=&quot;text/javascript&quot;&gt;&lt;/script&gt;
-      [% END %]
-      [% IF javascript_urls.grep('yui/').size %]
-        &lt;script type=&quot;text/javascript&quot;&gt;
-          YAHOO.namespace('bugzilla');
-          if( YAHOO.env.ua.gecko )
-            YAHOO.util.Event._simpleRemove(window, &quot;unload&quot;, YAHOO.util.Event._unload);
-        &lt;/script&gt;
-      [% END %]
</del><ins>+    &lt;script type=&quot;text/javascript&quot;&gt;
+    &lt;!--
+        YAHOO.namespace('bugzilla');
+        YAHOO.util.Event.addListener = function (el, sType, fn, obj, overrideContext) {
+               if ( (&quot;onpagehide&quot; in window || YAHOO.env.ua.gecko) &amp;&amp; sType === &quot;unload&quot;) { sType = &quot;pagehide&quot;; };
+               var capture = ((sType == &quot;focusin&quot; || sType == &quot;focusout&quot;) &amp;&amp; !YAHOO.env.ua.ie) ? true : false;
+               return this._addListener(el, this._getType(sType), fn, obj, overrideContext, capture);
+         };
+        if ( &quot;onpagehide&quot; in window || YAHOO.env.ua.gecko) {
+            YAHOO.util.Event._simpleRemove(window, &quot;unload&quot;, 
+                                           YAHOO.util.Event._unload);
+        }
+        [%# The language selector needs javascript to set its cookie,
+          # so it is hidden in HTML/CSS by the &quot;bz_default_hidden&quot; class.
+          # If the browser can run javascript, it will then &quot;unhide&quot;
+          # the language selector using the following code.
+          #%]
+        function unhide_language_selector() { 
+            YAHOO.util.Dom.removeClass(
+                'lang_links_container', 'bz_default_hidden'
+            ); 
+        } 
+        YAHOO.util.Event.onDOMReady(unhide_language_selector);
+
+        [%# Make some Bugzilla information available to all scripts. 
+          # We don't import every parameter and constant because we
+          # don't want to add a lot of uncached JS to every page. 
+          #%]
+        var BUGZILLA = {
+            param: {
+                cookiepath: '[% Param('cookiepath') FILTER js %]',
+                maxusermatches: [% Param('maxusermatches') FILTER js %]
+            },
+            constant: {
+                COMMENT_COLS: [% constants.COMMENT_COLS FILTER js %]
+            },
+            string: {
+                [%# Please keep these in alphabetical order. %]
+
+                attach_desc_required:
+                    'You must enter a Description for this attachment.',
+                component_required:
+                    'You must select a Component for this [% terms.bug %].',
+                description_required:
+                    'You must enter a Description for this [% terms.bug %].',
+                short_desc_required:
+                    'You must enter a Summary for this [% terms.bug %].',
+                version_required:
+                    'You must select a Version for this [% terms.bug %].'
+            }
+        };
+
+        [% FOREACH yui_name = yui %]
+          [% FOREACH yui_template = yui_templates.$yui_name %]
+            [% INCLUDE $yui_template %]
+          [% END %]
+        [% END %]
+        [% IF javascript %]
+          [% javascript %]
+        [% END %]
+    // --&gt;
+    &lt;/script&gt;
+
+    [% FOREACH javascript_url = javascript_urls %]
+      [% PROCESS format_js_link %]
</ins><span class="cx">     [% END %]
</span><span class="cx"> 
</span><span class="cx">     [%# this puts the live bookmark up on firefox for the Atom feed %]
</span><span class="lines">@@ -230,13 +252,12 @@
</span><span class="cx">         class=&quot;[% urlbase.replace('^https?://','').replace('/$','').replace('[-~@:/.]+','-') %]
</span><span class="cx">                [% FOREACH class = bodyclasses %]
</span><span class="cx">                  [% ' ' %][% class FILTER css_class_quote %]
</span><del>-               [% END %]&quot;&gt;
</del><ins>+               [% END %] yui-skin-sam&quot;&gt;
</ins><span class="cx"> 
</span><span class="cx"> [%# Migration note: the following file corresponds to the old Param
</span><span class="cx">   # 'bannerhtml'
</span><span class="cx">   #%]
</span><span class="cx"> 
</span><del>-
</del><span class="cx"> &lt;div id=&quot;header&quot;&gt;
</span><span class="cx"> 
</span><span class="cx"> [% INCLUDE global/banner.html.tmpl %]
</span><span class="lines">@@ -262,10 +283,27 @@
</span><span class="cx"> &lt;/tr&gt;
</span><span class="cx"> &lt;/table&gt;
</span><span class="cx"> 
</span><ins>+&lt;table id=&quot;lang_links_container&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot;
+       class=&quot;bz_default_hidden&quot;&gt;&lt;tr&gt;&lt;td&gt;
+[% IF Bugzilla.languages.size &gt; 1 %]
+  &lt;ul class=&quot;links&quot;&gt;
+  [% FOREACH lang = Bugzilla.languages.sort %]
+    &lt;li&gt;[% IF NOT loop.first %]&lt;span class=&quot;separator&quot;&gt; | &lt;/span&gt;[% END %]
+    [% IF lang == current_language %]
+      &lt;span class=&quot;lang_current&quot;&gt;[% lang FILTER html FILTER upper %]&lt;/span&gt;
+    [% ELSE %]
+      &lt;a href=&quot;#&quot; onclick=&quot;set_language('[% lang FILTER none %]');&quot;&gt;
+       [%- lang FILTER html FILTER upper %]&lt;/a&gt;
+    [% END %]
+    &lt;/li&gt;
+  [% END %]
+  &lt;/ul&gt;
+[% END %]
+&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
+
</ins><span class="cx"> [% PROCESS &quot;global/common-links.html.tmpl&quot; qs_suffix = &quot;_top&quot; %]
</span><ins>+&lt;/div&gt; [%# header %]
</ins><span class="cx"> 
</span><del>-&lt;/div&gt;
-
</del><span class="cx"> &lt;div id=&quot;bugzilla-body&quot;&gt;
</span><span class="cx"> 
</span><span class="cx"> [% IF Param('announcehtml') %]
</span><span class="lines">@@ -275,3 +313,41 @@
</span><span class="cx"> [% IF message %]
</span><span class="cx"> &lt;div id=&quot;message&quot;&gt;[% message %]&lt;/div&gt;
</span><span class="cx"> [% END %]
</span><ins>+
+[% BLOCK format_css_link %]
+  [% IF style_url.match('/IE-fixes\.css') %]
+    &lt;!--[if lte IE 7]&gt;
+      [%# Internet Explorer treats [if IE] HTML comments as uncommented.
+        # We use it to import CSS fixes so that Bugzilla looks decent on IE 7
+        # and below.
+        #%]
+  [% END %]
+
+  [% IF css_set_name == 'standard'
+       OR css_set_name == user.settings.skin.value
+  %]
+    [% SET css_rel = 'stylesheet' %]
+    [% SET css_set_display_name = setting_descs.${user.settings.skin.value}
+                                  || user.settings.skin.value %]
+  [% ELSE %]
+    [% SET css_rel = 'alternate stylesheet' %]
+    [% SET css_set_display_name = setting_descs.$css_set_name || css_set_name %]
+  [% END %]
+
+  [% IF css_set_name == 'standard' %]
+    [% SET css_title_link = '' %]
+  [% ELSE %]
+    [% css_title_link = BLOCK ~%]
+      title=&quot;[% css_set_display_name FILTER html %]&quot;
+    [% END %]
+  [% END %]
+
+  &lt;link href=&quot;[% style_url FILTER html %]&quot; rel=&quot;[% css_rel FILTER none %]&quot;
+        type=&quot;text/css&quot; [% css_title_link FILTER none %]&gt;
+
+  [% '&lt;![endif]--&gt;' IF style_url.match('/IE-fixes\.css') %]
+[% END %]
+
+[% BLOCK format_js_link %]
+  &lt;script type=&quot;text/javascript&quot; src=&quot;[% javascript_url FILTER mtime FILTER html %]&quot;&gt;&lt;/script&gt;
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultglobalhelphtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/global/help.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/global/help.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/global/help.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -23,8 +23,9 @@
</span><span class="cx"> 
</span><span class="cx"> [% IF cgi.param(&quot;help&quot;) %]
</span><span class="cx">   &lt;script type=&quot;text/javascript&quot;&gt; &lt;!--
</span><del>-    [% FOREACH h = help_html %]
-      g_helpTexts[&quot;[% h.id FILTER js %]&quot;] = &quot;[%- h.html FILTER js -%]&quot;;
</del><ins>+    [% FOREACH help_name = help_html.keys %]
+      g_helpTexts[&quot;[% help_name FILTER js %]&quot;] = 
+        &quot;[%- help_html.$help_name FILTER js -%]&quot;;
</ins><span class="cx">     [% END %]
</span><span class="cx">     // --&gt;
</span><span class="cx">   &lt;/script&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultglobalhiddenfieldshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/global/hidden-fields.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/global/hidden-fields.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/global/hidden-fields.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -52,7 +52,7 @@
</span><span class="cx">   [% ELSE %]
</span><span class="cx">     [% FOREACH mvalue = cgi.param(field).slice(0) %]
</span><span class="cx">       &lt;input type=&quot;hidden&quot; name=&quot;[% field FILTER html %]&quot;
</span><del>-             value=&quot;[% mvalue FILTER html FILTER html_linebreak %]&quot;&gt;
</del><ins>+             value=&quot;[% mvalue FILTER html_linebreak %]&quot;&gt;
</ins><span class="cx">     [% END %]
</span><span class="cx">   [% END %]
</span><span class="cx"> [% END %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultglobalmessageshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/global/messages.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/global/messages.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/global/messages.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -31,16 +31,11 @@
</span><span class="cx"> 
</span><span class="cx"> [% message = BLOCK %]
</span><span class="cx">   [% IF    message_tag == &quot;account_created&quot; %]
</span><del>-    [% title = &quot;User $otheruser.login created&quot; %]
-    A new user account [% otheruser.login FILTER html %] has been created
</del><ins>+    The user account [% otheruser.login FILTER html %] has been created
</ins><span class="cx">     successfully.
</span><span class="cx">     [% IF groups.size %]
</span><span class="cx">       You may want to edit the group settings now, using the form below.
</span><span class="cx">     [% END %]
</span><del>-    [% IF login_info %]
-      You can now go to the &lt;a href=&quot;index.cgi&quot;&gt;Log In&lt;/a&gt; page to enter
-      this [% terms.Bugzilla %] installation.
-    [% END %]
</del><span class="cx"> 
</span><span class="cx">   [% ELSIF message_tag == &quot;account_creation_canceled&quot; %]
</span><span class="cx">     [% title = &quot;User Account Creation Canceled&quot; %]
</span><span class="lines">@@ -65,6 +60,10 @@
</span><span class="cx">               A new password has been set.
</span><span class="cx">             [% ELSIF field == 'disabledtext' %]
</span><span class="cx">               The disable text has been modified.
</span><ins>+            [% ELSIF field == 'is_enabled' %]
+              The user has been [% otheruser.is_enabled ? 'enabled' : 'disabled' %].
+            [% ELSIF field == 'extern_id' %]
+              The user's External Login ID has been modified.
</ins><span class="cx">             [% ELSIF field == 'disable_mail' %]
</span><span class="cx">               [% IF otheruser.email_disabled %]
</span><span class="cx">                 [% terms.Bug %]mail has been disabled.
</span><span class="lines">@@ -114,35 +113,27 @@
</span><span class="cx">     The user account [% otheruser.login FILTER html %] has been deleted
</span><span class="cx">     successfully.
</span><span class="cx"> 
</span><ins>+  [% ELSIF message_tag == &quot;account_disabled&quot; %]
+    The user account [% account FILTER html %] is disabled, so you
+    cannot change its password.
+
</ins><span class="cx">   [% ELSIF message_tag == &quot;attachment_creation_failed&quot; %]
</span><span class="cx">     The [% terms.bug %] was created successfully, but attachment creation
</span><span class="cx">     failed.
</span><span class="cx">     Please add your attachment by clicking the &quot;Add an Attachment&quot; link
</span><span class="cx">     below.
</span><span class="cx"> 
</span><del>-  [% ELSIF message_tag == &quot;bug_confirmed_by_votes&quot; %]
-    *** This [% terms.bug %] has been confirmed by popular vote. ***
</del><ins>+  [% ELSIF message_tag == &quot;bug_group_description&quot; %]
+    Access to [% terms.bugs %] in the [% product.name FILTER html %] product
</ins><span class="cx"> 
</span><del>-  [% ELSIF message_tag == &quot;bug_duplicate_of&quot; %]
-    *** This [% terms.bug %] has been marked as a duplicate of [% terms.bug %] [%+ dupe_of FILTER html %] ***
-
-  [% ELSIF message_tag == &quot;bug_has_duplicate&quot; %]
-    *** [% terms.Bug %] [%+ dupe FILTER html %] has been marked as a duplicate of this [% terms.bug %]. ***
-
-  [% ELSIF message_tag == &quot;bug_moved_to&quot; %]
-    &lt;p&gt;[% terms.Bug %] moved to [% Param(&quot;move-to-url&quot;) FILTER html %].&lt;/p&gt;
-    &lt;p&gt;If the move succeeded, [% login FILTER html %] will receive a mail
-    containing the number of the new [% terms.bug %] in the other database.
-    If all went well, please mark this [% terms.bug %] verified, and paste
-    in a link to the new [% terms.bug %]. Otherwise, reopen this [% terms.bug %].
-
</del><span class="cx">   [% ELSIF message_tag == &quot;buglist_adding_field&quot; %]
</span><span class="cx">     [% title = &quot;Adding field to search page...&quot; %]
</span><span class="cx">     [% link  = &quot;Click here if the page does not redisplay automatically.&quot; %]
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF message_tag == &quot;buglist_updated_named_query&quot; %]
</span><ins>+    [% title = &quot;Search updated&quot; %]
</ins><span class="cx">     Your search named &lt;code&gt;&lt;a 
</span><del>-     href=&quot;buglist.cgi?cmdtype=runnamed&amp;amp;namedcmd=[% queryname FILTER url_quote %]&quot;
</del><ins>+     href=&quot;buglist.cgi?cmdtype=runnamed&amp;amp;namedcmd=[% queryname FILTER uri %]&quot;
</ins><span class="cx">     &gt;[% queryname FILTER html %]&lt;/a&gt;&lt;/code&gt; has been updated.
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF message_tag == &quot;buglist_new_default_query&quot; %]
</span><span class="lines">@@ -150,22 +141,19 @@
</span><span class="cx">     also bookmark the result of any individual search.
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF message_tag == &quot;buglist_new_named_query&quot; %]
</span><ins>+    [% title = &quot;Search created&quot; %]
</ins><span class="cx">     OK, you have a new search named &lt;code&gt;&lt;a
</span><del>-     href=&quot;buglist.cgi?cmdtype=runnamed&amp;amp;namedcmd=[% queryname FILTER url_quote %]&quot;
</del><ins>+     href=&quot;buglist.cgi?cmdtype=runnamed&amp;amp;namedcmd=[% queryname FILTER uri %]&quot;
</ins><span class="cx">     &gt;[% queryname FILTER html %]&lt;/a&gt;&lt;/code&gt;.
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF message_tag == &quot;buglist_query_gone&quot; %]
</span><span class="cx">     [% title = &quot;Search is gone&quot; %]
</span><del>-    [% link  = &quot;Go back to the search page.&quot; %]
</del><ins>+    [% link  = &quot;Un-forget the search&quot; %]
</ins><span class="cx">     OK, the &lt;b&gt;[% namedcmd FILTER html %]&lt;/b&gt; search is gone.
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF message_tag == &quot;buglist_sorted_by_relevance&quot; %]
</span><span class="cx">     [% terms.Bugs %] on this list are sorted by relevance, with the most
</span><span class="cx">     relevant [% terms.bugs %] at the top.
</span><del>-    [% IF bugs.size == constants.FULLTEXT_BUGLIST_LIMIT %]
-      Only the [% constants.FULLTEXT_BUGLIST_LIMIT FILTER html %]
-      most relevant [% terms.bugs %] are shown.
-    [% END %]
</del><span class="cx"> 
</span><span class="cx">   [% ELSIF message_tag == &quot;change_columns&quot; %]
</span><span class="cx">     [% title = &quot;Change columns&quot; %]
</span><span class="lines">@@ -179,26 +167,31 @@
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF message_tag == &quot;classification_deleted&quot; %]
</span><span class="cx">     [% title = &quot;Classification Deleted&quot; %]
</span><del>-    The &lt;em&gt;[% classification FILTER html %]&lt;/em&gt; classification has been deleted.
</del><ins>+    The &lt;em&gt;[% classification.name FILTER html %]&lt;/em&gt; classification has been deleted.
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF message_tag == &quot;classification_updated&quot; %]
</span><del>-    [% IF updated_classification || updated_description || updated_sortkey %]
-      [% title = &quot;Classification Updated&quot; %]
-      Changes to the &lt;em&gt;[% classification FILTER html %]&lt;/em&gt; classification
</del><ins>+    [% title = &quot;Classification Updated&quot; %]
+    [% IF changes.keys.size %]
+      Changes to the &lt;em&gt;[% classification.name FILTER html %]&lt;/em&gt; classification
</ins><span class="cx">       have been saved:
</span><span class="cx">       &lt;ul&gt;
</span><del>-        [% IF updated_classification %]
-          &lt;li&gt;Classification name updated&lt;/li&gt;
</del><ins>+        [% IF changes.name.defined %]
+          &lt;li&gt;Name updated to '[% classification.name FILTER html %]'&lt;/li&gt;
</ins><span class="cx">         [% END %]
</span><del>-        [% IF updated_description %]
-          &lt;li&gt;Description updated&lt;/li&gt;
</del><ins>+        [% IF changes.description.defined %]
+          [% IF classification.description %]
+            &lt;li&gt;Description updated to '[% classification.description FILTER html %]'&lt;/li&gt;
+          [% ELSE %]
+            &lt;li&gt;Description removed&lt;/li&gt;
+          [% END %]
</ins><span class="cx">         [% END %]
</span><del>-        [% IF updated_sortkey %]
-          &lt;li&gt;Sortkey updated&lt;/li&gt;
</del><ins>+        [% IF changes.sortkey.defined %]
+          &lt;li&gt;Sortkey updated to '[% classification.sortkey FILTER html %]'&lt;/li&gt;
</ins><span class="cx">         [% END %]
</span><ins>+        [% Hook.process('classification_updated_fields') %]
</ins><span class="cx">       &lt;/ul&gt;
</span><span class="cx">     [% ELSE %]
</span><del>-      No changes made to &lt;em&gt;[% classification FILTER html %]&lt;/em&gt;.
</del><ins>+      No changes made to &lt;em&gt;[% classification.name FILTER html %]&lt;/em&gt;.
</ins><span class="cx">     [% END %]
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF message_tag == &quot;component_created&quot; %]
</span><span class="lines">@@ -245,6 +238,11 @@
</span><span class="cx">           &lt;li&gt;Default CC list deleted&lt;/li&gt;
</span><span class="cx">         [% END %]
</span><span class="cx">       [% END %]
</span><ins>+      [% IF changes.isactive.defined %]
+        &lt;li&gt;[% comp.is_active ? &quot;Enabled&quot; : &quot;Disabled&quot; %] for [% terms.bugs %]&lt;/li&gt;
+      [% END %]
+      [% Hook.process('component_updated_fields') %]
+      &lt;/ul&gt;
</ins><span class="cx">     [% ELSE %]
</span><span class="cx">       No changes made to &lt;em&gt;[% comp.name FILTER html %]&lt;/em&gt;.
</span><span class="cx">     [% END %]
</span><span class="lines">@@ -287,44 +285,63 @@
</span><span class="cx">     The request to change the email address for the
</span><span class="cx">     account [%+ old_email FILTER html %] to 
</span><span class="cx">     [%+ new_email FILTER html %] has been canceled.
</span><del>-   Your old account settings have been reinstated.
</del><ins>+    Your old account settings have been reinstated.
</ins><span class="cx"> 
</span><ins>+  [% ELSIF message_tag == &quot;extension_created&quot; %]
+    An extension named [% name FILTER html %] has been created
+    in [% path FILTER html %]. Make sure you change &quot;YOUR NAME&quot; and 
+    &quot;YOUR EMAIL ADDRESS&quot; in the code to your name and your email address.
+
</ins><span class="cx">   [% ELSIF message_tag == &quot;field_value_created&quot; %]
</span><span class="cx">     [% title = &quot;New Field Value Created&quot; %]
</span><del>-    The value &lt;em&gt;[% value FILTER html %]&lt;/em&gt; has been added as a valid choice
-    for the &lt;em&gt;[% field.description FILTER html %]&lt;/em&gt;
</del><ins>+    The value &lt;em&gt;[% value.name FILTER html %]&lt;/em&gt; has been added as a 
+    valid choice for the &lt;em&gt;[% field.description FILTER html %]&lt;/em&gt;
</ins><span class="cx">     (&lt;em&gt;[% field.name FILTER html %]&lt;/em&gt;) field.
</span><span class="cx">     [% IF field.name == &quot;bug_status&quot; %]
</span><del>-      You should now visit the &lt;a href=&quot;editworkflow.cgi&quot;&gt;status workflow page&lt;/a&gt;
-      to include your new [% terms.bug %] status.
</del><ins>+      You should now visit the &lt;a href=&quot;editworkflow.cgi&quot;&gt;status workflow 
+      page&lt;/a&gt; to include your new [% terms.bug %] status.
</ins><span class="cx">     [% END %]
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF message_tag == &quot;field_value_deleted&quot; %]
</span><span class="cx">     [% title = &quot;Field Value Deleted&quot; %]
</span><del>-    The value &lt;em&gt;[% value FILTER html %]&lt;/em&gt; of the
</del><ins>+    The value &lt;em&gt;[% value.name FILTER html %]&lt;/em&gt; of the
</ins><span class="cx">     &lt;em&gt;[% field.description FILTER html %]&lt;/em&gt;
</span><span class="cx">     (&lt;em&gt;[% field.name FILTER html %]&lt;/em&gt;) field has been deleted.
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF message_tag == &quot;field_value_updated&quot; %]
</span><span class="cx">     [% title = &quot;Field Value Updated&quot; %]
</span><del>-    [% IF updated_value || updated_sortkey %]
-      Changes to the &lt;em&gt;[% value FILTER html %]&lt;/em&gt; value of the
</del><ins>+    [% IF changes.keys.size %]
+      The &lt;em&gt;[% value_old FILTER html %]&lt;/em&gt; value of the
</ins><span class="cx">       &lt;em&gt;[% field.description FILTER html %]&lt;/em&gt;
</span><del>-      (&lt;em&gt;[% field.name FILTER html %]&lt;/em&gt;) field have been changed:
</del><ins>+      (&lt;em&gt;[% field.name FILTER html %]&lt;/em&gt;) field has been changed:
</ins><span class="cx">       &lt;ul&gt;
</span><del>-        [% IF updated_value %]
-          &lt;li&gt;Field value updated to &lt;em&gt;[% value FILTER html %]&lt;/em&gt;&lt;/li&gt;
-          [% IF default_value_updated %]
-            (note that this value is the default for this field. All
-            references to the default value will now point to this new value)
</del><ins>+        [% IF changes.value %]
+          &lt;li&gt;Field value updated to 
+            &lt;em&gt;[% changes.value.1 FILTER html %]&lt;/em&gt;.
+            [% IF value.is_default %]
+              (Note that this value is the default for this field. All
+              references to the default value will now point to this new value.)
+            [% END %]
+          &lt;/li&gt;
+        [% END %]
+        [% IF changes.sortkey %]
+          &lt;li&gt;Sortkey updated to 
+            &lt;em&gt;[% changes.sortkey.1 FILTER html %]&lt;/em&gt;.&lt;/li&gt;
+        [% END %]
+        [% IF changes.visibility_value_id %]
+          [% IF value.visibility_value.defined %]
+            &lt;li&gt;It only appears when 
+              [%+ value.field.value_field.description FILTER html %] is set to
+              '[%+ value.visibility_value.name FILTER html %]'.&lt;/li&gt;
+          [% ELSE %]
+            &lt;li&gt;It now always appears, no matter what 
+              [%+ value.field.value_field.description FILTER html %] is set to.
+            &lt;/li&gt;
</ins><span class="cx">           [% END %]
</span><span class="cx">         [% END %]
</span><del>-        [% IF updated_sortkey %]
-          &lt;li&gt;Field value sortkey updated to &lt;em&gt;[% sortkey FILTER html %]&lt;/em&gt;&lt;/li&gt;
-        [% END %]
</del><span class="cx">       &lt;/ul&gt;
</span><span class="cx">     [% ELSE %]
</span><del>-      No changes made to the field value &lt;em&gt;[% value FILTER html %]&lt;/em&gt;.
</del><ins>+      No changes made to the field value &lt;em&gt;[% value_old FILTER html %]&lt;/em&gt;.
</ins><span class="cx">     [% END %]
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF message_tag == &quot;flag_cleared&quot; %]
</span><span class="lines">@@ -340,10 +357,10 @@
</span><span class="cx">     [% field_descs.$field_name FILTER html %]
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF message_tag == &quot;get_resolution&quot; %]
</span><del>-    [% get_resolution(resolution) FILTER html %]
</del><ins>+    [% display_value(&quot;resolution&quot;, resolution) FILTER html %]
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF message_tag == &quot;get_status&quot; %]
</span><del>-    [% get_status(status) FILTER html %]
</del><ins>+    [% display_value(&quot;bug_status&quot;, status) FILTER html %]
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF message_tag == &quot;group_created&quot; %]
</span><span class="cx">     [% title = &quot;New Group Created&quot; %]
</span><span class="lines">@@ -430,6 +447,14 @@
</span><span class="cx">       group.
</span><span class="cx">     [% END %]
</span><span class="cx"> 
</span><ins>+  [% ELSIF message_tag == &quot;invalid_column_name&quot; %]
+    The custom sort order specified contains one or more invalid
+    column names: &lt;em&gt;[% invalid_fragments.join(', ') FILTER html %]&lt;/em&gt;.
+    They have been removed from the sort list.
+
+  [% ELSIF message_tag == &quot;job_queue_depth&quot; %]
+    [% count FILTER html %] jobs in the queue.
+
</ins><span class="cx">   [% ELSIF message_tag == &quot;keyword_created&quot; %]
</span><span class="cx">     [% title = &quot;New Keyword Created&quot; %]
</span><span class="cx">     The keyword &lt;em&gt;[% name FILTER html %]&lt;/em&gt; has been created.
</span><span class="lines">@@ -437,10 +462,6 @@
</span><span class="cx">   [% ELSIF message_tag == &quot;keyword_deleted&quot; %]
</span><span class="cx">     [% title = &quot;Keyword Deleted&quot; %]
</span><span class="cx">     The &lt;em&gt;[% keyword.name FILTER html %]&lt;/em&gt; keyword has been deleted.
</span><del>-    &lt;b&gt;After you have finished editing keywords, you need to
-    &lt;a href=&quot;sanitycheck.cgi?rebuildkeywordcache=1&quot;&gt;rebuild the keyword
-    cache&lt;/a&gt;&lt;/b&gt; (on a very large installation of [% terms.Bugzilla %],
-    this can take several minutes).
</del><span class="cx"> 
</span><span class="cx">   [% ELSIF message_tag == &quot;keyword_updated&quot; %]
</span><span class="cx">     [% title = &quot;Keyword Updated&quot; %]
</span><span class="lines">@@ -449,13 +470,7 @@
</span><span class="cx">       been saved:
</span><span class="cx">       &lt;ul&gt;
</span><span class="cx">         [% IF changes.name.defined %]
</span><del>-          &lt;li&gt;
-            Keyword renamed to &lt;em&gt;[% keyword.name FILTER html %]&lt;/em&gt;.
-            &lt;b&gt;After you have finished editing keywords, you need to
-            &lt;a href=&quot;sanitycheck.cgi?rebuildkeywordcache=1&quot;&gt;rebuild
-            the keyword cache&lt;/a&gt;&lt;/b&gt; (on a very large installation
-            of [% terms.Bugzilla %], this can take several minutes).
-          &lt;/li&gt;
</del><ins>+          &lt;li&gt;Keyword renamed to &lt;em&gt;[% keyword.name FILTER html %]&lt;/em&gt;.&lt;/li&gt;
</ins><span class="cx">         [% END %]
</span><span class="cx">         [% IF changes.description.defined %]
</span><span class="cx">           &lt;li&gt;Description updated to &lt;em&gt;[% keyword.description FILTER html %]&lt;/em&gt;&lt;/li&gt;
</span><span class="lines">@@ -477,6 +492,44 @@
</span><span class="cx">     [% title = &quot;$terms.Bugzilla Login Changed&quot; %]
</span><span class="cx">     Your [% terms.Bugzilla %] login has been changed.
</span><span class="cx"> 
</span><ins>+  [% ELSIF message_tag == &quot;migrate_component_created&quot; %]
+    Component created: [% comp.name FILTER html %]
+    (in [% product.name FILTER html %])
+
+  [% ELSIF message_tag == &quot;migrate_creating_bugs&quot; %]
+    Creating [% terms.bugs %]...
+
+  [% ELSIF message_tag == &quot;migrate_field_created&quot; %]
+    New custom field: [% field.description FILTER html %]
+    ([% field.name FILTER html %])
+
+  [% ELSIF message_tag == &quot;migrate_product_created&quot; %]
+    Product created: [% created.name FILTER html %]
+
+  [% ELSIF message_tag == &quot;migrate_reading_bugs&quot; %]
+    Reading [% terms.bugs %]...
+
+  [% ELSIF message_tag == &quot;migrate_reading_products&quot; %]
+    Reading products...
+
+  [% ELSIF message_tag == &quot;migrate_reading_users&quot; %]
+    Reading users...
+
+  [% ELSIF message_tag == &quot;migrate_translating_bugs&quot; %]
+    Converting [% terms.bug %] values to be appropriate for 
+    [%+ terms.Bugzilla %]...
+
+  [% ELSIF message_tag == &quot;migrate_user_created&quot; %]
+    User created: [% created.email FILTER html %]
+    [% IF password %] Password: [% password FILTER html %][% END %]
+
+  [% ELSIF message_tag == &quot;migrate_value_created&quot; %]
+    [% IF product.defined %]
+      [% product.name FILTER html %]
+    [% END %]
+    [%+ field_descs.${field.name} FILTER html %] value
+    created: [% value FILTER html %]
+
</ins><span class="cx">   [% ELSIF message_tag == &quot;milestone_created&quot; %]
</span><span class="cx">     [% title = &quot;Milestone Created&quot; %]
</span><span class="cx">     The milestone &lt;em&gt;[% milestone.name FILTER html %]&lt;/em&gt; has been created.
</span><span class="lines">@@ -501,6 +554,9 @@
</span><span class="cx">         [% IF changes.sortkey.defined %]
</span><span class="cx">           &lt;li&gt;Sortkey updated to &lt;em&gt;[% milestone.sortkey FILTER html %]&lt;/em&gt;
</span><span class="cx">         [% END %]
</span><ins>+        [% IF changes.isactive.defined %]
+          &lt;li&gt;[% milestone.is_active ? &quot;Enabled&quot; : &quot;Disabled&quot; %] for [% terms.bugs %]&lt;/li&gt;
+        [% END %]
</ins><span class="cx">       &lt;/ul&gt;
</span><span class="cx">     [% ELSE %]
</span><span class="cx">       No changes made to milestone &lt;em&gt;[% milestone.name FILTER html %]&lt;/em&gt;.
</span><span class="lines">@@ -512,7 +568,7 @@
</span><span class="cx">       [% FOREACH param = param_changed %]
</span><span class="cx">         Changed &lt;em&gt;[% param FILTER html %]&lt;/em&gt;&lt;br&gt;
</span><span class="cx">         [% IF param == 'utf8' &amp;&amp; Param('utf8') %]
</span><del>-          &lt;strong&gt;You must now re-run checksetup.pl.&lt;/strong&gt;&lt;br&gt;
</del><ins>+          &lt;strong&gt;You must now re-run &lt;kbd&gt;checksetup.pl&lt;/kbd&gt;.&lt;/strong&gt;&lt;br&gt;
</ins><span class="cx">         [% END %]
</span><span class="cx">       [% END %]
</span><span class="cx">     [% ELSE %]
</span><span class="lines">@@ -539,20 +595,74 @@
</span><span class="cx">     Your password has been changed.
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF message_tag == &quot;flag_type_created&quot; %]
</span><del>-    [% title = &quot;Flag Type Created&quot; %]
</del><ins>+    [% title = BLOCK %]Flag Type '[% name FILTER html %]' Created[% END %]
</ins><span class="cx">     The flag type &lt;em&gt;[% name FILTER html %]&lt;/em&gt; has been created.
</span><span class="cx"> 
</span><del>-  [% ELSIF message_tag == &quot;flag_type_changes_saved&quot; %]
-    [% title = &quot;Flag Type Changes Saved&quot; %]
-    Your changes to the flag type &lt;em&gt;[% name FILTER html %]&lt;/em&gt;
-    have been saved.
</del><ins>+  [% ELSIF message_tag == &quot;flag_type_updated&quot; %]
+    [% title = BLOCK %]Flag Type '[% flagtype.name FILTER html %]' Updated[% END %]
+    [% IF changes.size %]
+      Changes to the flag type &lt;em&gt;[% flagtype.name FILTER html %]&lt;/em&gt;
+      have been saved:
+      &lt;ul&gt;
+        [% IF changes.is_active.defined %]
+          &lt;li&gt;Flag type is now [% flagtype.is_active ? &quot;active&quot; : &quot;inactive&quot; %]&lt;/li&gt;
+        [% END %]
+        [% IF changes.name.defined %]
+          &lt;li&gt;Flag type renamed to &lt;em&gt;[% flagtype.name FILTER html %]&lt;/em&gt;&lt;/li&gt;
+        [% END %]
+        [% IF changes.description.defined %]
+          &lt;li&gt;Description updated to &lt;em&gt;[% flagtype.description FILTER html %]&lt;/em&gt;&lt;/li&gt;
+        [% END %]
+        [% IF changes.cc_list.defined %]
+          [% IF flagtype.cc_list %]
+            &lt;li&gt;CC list updated to &lt;em&gt;[% flagtype.cc_list FILTER html %]&lt;/em&gt;&lt;/li&gt;
+          [% ELSE %]
+            &lt;li&gt;CC list is now empty&lt;/li&gt;
+          [% END %]
+        [% END %]
+        [% IF changes.sortkey.defined %]
+          &lt;li&gt;Sortkey updated to &lt;em&gt;[% flagtype.sortkey FILTER html %]&lt;/em&gt;&lt;/li&gt;
+        [% END %]
+        [% IF changes.is_requestable.defined %]
+          &lt;li&gt;Flag type is [% &quot;no longer&quot; UNLESS flagtype.is_requestable %] requestable&lt;/li&gt;
+        [% END %]
+        [% IF changes.is_requesteeble.defined AND flagtype.is_requestable %]
+          &lt;li&gt;
+            Flag type is [% &quot;no longer&quot; UNLESS flagtype.is_requesteeble %]
+            specifically requestable
+          &lt;/li&gt;
+        [% END %]
+        [% IF changes.is_multiplicable.defined %]
+          &lt;li&gt;Flag type is [% &quot;no longer&quot; UNLESS flagtype.is_multiplicable %] multiplicable&lt;/li&gt;
+        [% END %]
+        [% IF changes.grant_group_id.defined %]
+          [% IF flagtype.grant_group_id %]
+            &lt;li&gt;Grant group updated to &lt;em&gt;[% flagtype.grant_group.name FILTER html %]&lt;/em&gt;&lt;/li&gt;
+          [% ELSE %]
+            &lt;li&gt;Grant group deleted&lt;/li&gt;
+          [% END %]
+        [% END %]
+        [% IF changes.request_group_id.defined %]
+          [% IF flagtype.request_group_id %]
+            &lt;li&gt;Request group updated to &lt;em&gt;[% flagtype.request_group.name FILTER html %]&lt;/em&gt;&lt;/li&gt;
+          [% ELSE %]
+            &lt;li&gt;Request group deleted&lt;/li&gt;
+          [% END %]
+        [% END %]
+        [% IF changes.inclusions.defined || changes.exclusions.defined %]
+          &lt;li&gt;The inclusions and exclusions lists have been updated&lt;/li&gt;
+        [% END %]
+     &lt;/ul&gt;
+    [% ELSE %]
+      No changes made to flag type &lt;em&gt;[% flagtype.name FILTER html %]&lt;/em&gt;.
+    [% END %]
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF message_tag == &quot;flag_type_deleted&quot; %]
</span><del>-    [% title = &quot;Flag Type Deleted&quot; %]
</del><ins>+    [% title = BLOCK %]Flag Type '[% name FILTER html %]' Deleted[% END %]
</ins><span class="cx">     The flag type &lt;em&gt;[% name FILTER html %]&lt;/em&gt; has been deleted.
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF message_tag == &quot;flag_type_deactivated&quot; %]
</span><del>-    [% title = &quot;Flag Type Deactivated&quot; %]
</del><ins>+    [% title = BLOCK %]Flag Type '[% flag_type.name FILTER html %]' Deactivated[% END %]
</ins><span class="cx">     The flag type &lt;em&gt;[% flag_type.name FILTER html %]&lt;/em&gt; has been deactivated.
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF message_tag == &quot;install_admin_get_email&quot; %]
</span><span class="lines">@@ -599,12 +709,41 @@
</span><span class="cx">   [% ELSIF message_tag == &quot;install_fk_drop&quot; %]
</span><span class="cx">     Dropping foreign key: [% table FILTER html %].[% column FILTER html %] -&amp;gt; [% fk.TABLE FILTER html %].[% fk.COLUMN FILTER html %]...
</span><span class="cx"> 
</span><ins>+  [% ELSIF message_tag == &quot;install_fk_invalid&quot; %]
+    ERROR: There are invalid values for the [% column FILTER html %] column in the [% table FILTER html %]
+    table. (These values do not exist in the [% foreign_table FILTER html %] table, in the 
+    [%+ foreign_column FILTER html %] column.)
+
+    Before continuing with checksetup, you will need to fix these values,
+    either by deleting these rows from the database, or changing the values
+    of [% column FILTER html %] in [% table FILTER html %] to point to valid values in [% foreign_table FILTER html %].[% foreign_column FILTER html %].
+
+    The bad values from the [% table FILTER html %].[% column FILTER html %] column are:
+    [%+ values.join(', ') FILTER html %]
+
+  [% ELSIF message_tag == &quot;install_fk_invalid_fixed&quot; %]
+    WARNING: There were invalid values in [% table FILTER html %].[% column FILTER html %]
+    that have been [% IF action == 'delete' %]deleted[% ELSE %]set to NULL[% END %]:
+    [%+ values.join(', ') FILTER html %]
+
+  [% ELSIF message_tag == &quot;install_fk_setup&quot; %]
+    Setting up foreign keys...
+
</ins><span class="cx">   [% ELSIF message_tag == &quot;install_group_create&quot; %]
</span><span class="cx">     Creating group [% name FILTER html %]...
</span><span class="cx"> 
</span><ins>+  [% ELSIF message_tag == &quot;install_groups_setup&quot; %]
+    Creating default groups...
+
</ins><span class="cx">   [% ELSIF message_tag == &quot;install_setting_new&quot; %]
</span><span class="cx">     Adding a new user setting called '[% name FILTER html %]'
</span><span class="cx"> 
</span><ins>+  [% ELSIF message_tag == &quot;install_setting_setup&quot; %]
+    Setting up user preferences...
+
+  [% ELSIF message_tag == &quot;install_success&quot; %]
+    checksetup.pl complete.
+
</ins><span class="cx">   [% ELSIF message_tag == &quot;install_table_drop&quot; %]
</span><span class="cx">     Dropping the '[% name FILTER html %]' table...
</span><span class="cx"> 
</span><span class="lines">@@ -652,10 +791,13 @@
</span><span class="cx">     Verify that the file permissions in your [% terms.Bugzilla %] directory are
</span><span class="cx">     suitable for your system. Avoid unnecessary write access.
</span><span class="cx"> 
</span><ins>+  [% ELSIF message_tag == &quot;install_workflow_init&quot; %]
+    Setting up the default status workflow...
+
</ins><span class="cx">   [% ELSIF message_tag == &quot;product_created&quot; %]
</span><span class="cx">     [% title = &quot;Product Created&quot; %]
</span><span class="cx">     The product &lt;em&gt;[% product.name FILTER html %]&lt;/em&gt; has been created. You will need to
</span><del>-    &lt;a href=&quot;editcomponents.cgi?action=add&amp;product=[% product.name FILTER url_quote %]&quot;&gt;
</del><ins>+    &lt;a href=&quot;editcomponents.cgi?action=add&amp;product=[% product.name FILTER uri %]&quot;&gt;
</ins><span class="cx">     add at least one component&lt;/a&gt; before anyone can enter [% terms.bugs %] against this product.
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF message_tag == &quot;product_deleted&quot; %]
</span><span class="lines">@@ -689,6 +831,9 @@
</span><span class="cx">   [% ELSIF message_tag == &quot;series_all_closed&quot; %]
</span><span class="cx">     All Closed
</span><span class="cx"> 
</span><ins>+  [% ELSIF message_tag == &quot;series_subcategory&quot; %]
+    -All-
+
</ins><span class="cx">   [% ELSIF message_tag == &quot;sudo_started&quot; %]
</span><span class="cx">     [% title = &quot;Sudo session started&quot; %]
</span><span class="cx">       The sudo session has been started.  For the next 6 hours, or until you 
</span><span class="lines">@@ -708,10 +853,14 @@
</span><span class="cx">       has been created. Note that you may need to wait up to 
</span><span class="cx">       [%+ series.frequency * 2 %] days before there will be enough data for a
</span><span class="cx">       chart of this series to be produced.
</span><del>-      &lt;br&gt;&lt;br&gt;
-      Go back or 
-      &lt;a href=&quot;query.cgi?format=create-series&quot;&gt;create another series&lt;/a&gt;.
-    
</del><ins>+
+  [% ELSIF message_tag == &quot;series_deleted&quot; %]
+    [% title = &quot;Series Deleted&quot; %]
+    The series &lt;em&gt;[% series.category FILTER html %] /
+      [%+ series.subcategory FILTER html %] /
+      [%+ series.name FILTER html %]&lt;/em&gt;
+      has been deleted.
+
</ins><span class="cx">   [% ELSIF message_tag == &quot;shutdown&quot; %]
</span><span class="cx">     [% title = &quot;$terms.Bugzilla is Down&quot; %]
</span><span class="cx">     [% Param(&quot;shutdownhtml&quot;) %]
</span><span class="lines">@@ -720,6 +869,18 @@
</span><span class="cx">       The cookie that was remembering your login is now gone.
</span><span class="cx">     [% END %]
</span><span class="cx"> 
</span><ins>+  [% ELSIF message_tag == &quot;tag_updated&quot; %]
+    [% title = &quot;Tag Updated&quot; %]
+    The '&lt;a href=&quot;buglist.cgi?tag=[% tag FILTER uri %]&quot;&gt;[% tag FILTER html %]&lt;/a&gt;'
+    tag has been
+    [% IF action == &quot;add&quot; %]
+      added to
+    [% ELSE %]
+      removed from
+    [% END %]
+    [%+ buglist.size &gt; 1 ? terms.bugs : terms.bug %]
+    [%+ buglist.join(&quot;, &quot;) FILTER html %].
+
</ins><span class="cx">   [% ELSIF message_tag == &quot;term&quot; %]
</span><span class="cx">     [% terms.$term FILTER html %]
</span><span class="cx"> 
</span><span class="lines">@@ -748,20 +909,42 @@
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF message_tag == &quot;version_updated&quot; %]
</span><span class="cx">     [% title = &quot;Version Updated&quot; %]
</span><del>-    Version renamed as &lt;em&gt;[% version.name FILTER html %]&lt;/em&gt;.
</del><ins>+    [% IF changes.size %]
+      Changes to the version &lt;em&gt;[% version.name FILTER html %]&lt;/em&gt;
+      have been saved:
+      &lt;ul&gt;
+        [% IF changes.value.defined %]
+          &lt;li&gt;Version renamed to &lt;em&gt;[% version.name FILTER html %]&lt;/em&gt;&lt;/li&gt;
+        [% END %]
+        [% IF changes.isactive.defined %]
+          &lt;li&gt;[% version.is_active ? &quot;Enabled&quot; : &quot;Disabled&quot; %] for [% terms.bugs %]&lt;/li&gt;
+        [% END %]
+      &lt;/ul&gt;
+    [% ELSE %]
+      No changes made to version &lt;em&gt;[% version.name FILTER html %]&lt;/em&gt;.
+    [% END %]
</ins><span class="cx"> 
</span><ins>+  [% ELSIF message_tag == &quot;whine_query_failed&quot; %]
+    The query '[% query_name FILTER html %]' from [% author.login FILTER html %]
+    failed: [% reason FILTER html %]
+
</ins><span class="cx">   [% ELSIF message_tag == &quot;workflow_updated&quot; %]
</span><span class="cx">     The workflow has been updated.
</span><ins>+  [% END %]
+[% END %]
</ins><span class="cx"> 
</span><del>-  [% ELSE %]
-    [%# Give sensible error if error functions are used incorrectly.
-      #%]        
</del><ins>+[% IF !message %]
+  [% message = Hook.process('messages') %]
+[% END %]
+
+[%# Give sensible error if the message function is used incorrectly. #%]
+[% IF !message %]
+  [% message = BLOCK %]
</ins><span class="cx">     You are using [% terms.Bugzilla %]'s messaging functions incorrectly. You
</span><span class="cx">     passed in the string '[% message_tag %]'. The correct use is to pass
</span><span class="cx">     in a tag, and define that tag in the file messages.html.tmpl.&lt;br&gt;
</span><span class="cx">     &lt;br&gt;
</span><del>-    If you are a [% terms.Bugzilla %] end-user seeing this message, please 
</del><ins>+    If you are a [% terms.Bugzilla %] end-user seeing this message, please
</ins><span class="cx">     save this page and send it to [% Param('maintainer') %].
</span><del>-    
</del><span class="cx">   [% END %]
</span><span class="cx"> [% END %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultglobalperbugquerieshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/global/per-bug-queries.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/global/per-bug-queries.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/global/per-bug-queries.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -51,21 +51,16 @@
</span><span class="cx">       //--&gt;
</span><span class="cx">     &lt;/script&gt;
</span><span class="cx"> 
</span><del>-    [%# Get existing lists of bugs for this user %]
-    [% lists_of_bugs = [] %]
-    [% FOREACH q = user.queries %]
-      [% NEXT UNLESS q.bug_ids_only %]
-      [% lists_of_bugs.push(q.name) %]
-    [% END %]
</del><span class="cx">     &lt;div class=&quot;label&quot;&gt;&lt;/div&gt;
</span><span class="cx">     &lt;ul class=&quot;links&quot;&gt;&lt;li class=&quot;form&quot;&gt;
</span><span class="cx">       &lt;form id=&quot;list_of_bugs&quot; action=&quot;buglist.cgi&quot; method=&quot;get&quot;&gt;
</span><span class="cx">         &lt;input type=&quot;hidden&quot; name=&quot;cmdtype&quot; value=&quot;doit&quot;&gt;
</span><span class="cx">         &lt;input type=&quot;hidden&quot; name=&quot;remtype&quot; value=&quot;asnamed&quot;&gt;
</span><span class="cx">         &lt;input type=&quot;hidden&quot; name=&quot;list_of_bugs&quot; value=&quot;1&quot;&gt;
</span><ins>+        &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% issue_hash_token(['savedsearch']) FILTER html %]&quot;&gt;
</ins><span class="cx">         &lt;select id=&quot;lob_action&quot; name=&quot;action&quot; onchange=&quot;update_text();&quot;&gt;
</span><span class="cx">           &lt;option value=&quot;add&quot;&gt;Add&lt;/option&gt;
</span><del>-          [% IF lists_of_bugs.size %]
</del><ins>+          [% IF user.tags.size %]
</ins><span class="cx">             &lt;option value=&quot;remove&quot;&gt;Remove&lt;/option&gt;
</span><span class="cx">           [% END %]
</span><span class="cx">         &lt;/select&gt;
</span><span class="lines">@@ -76,15 +71,15 @@
</span><span class="cx">           the named tag
</span><span class="cx">         [% END %]
</span><span class="cx"> 
</span><del>-        [% IF lists_of_bugs.size %]
</del><ins>+        [% IF user.tags.size %]
</ins><span class="cx">           &lt;select id=&quot;lob_oldqueryname&quot; name=&quot;oldqueryname&quot;&gt;
</span><del>-            [% FOREACH query = lists_of_bugs %]
-              &lt;option value=&quot;[% query FILTER html %]&quot;&gt;[% query FILTER html %]&lt;/option&gt;
</del><ins>+            [% FOREACH tag = user.tags.keys %]
+              &lt;option value=&quot;[% tag FILTER html %]&quot;&gt;[% tag FILTER html %]&lt;/option&gt;
</ins><span class="cx">             [% END %]
</span><span class="cx">           &lt;/select&gt;
</span><span class="cx">         [% END %]
</span><span class="cx">         &lt;span id=&quot;lob_new_query_text&quot;&gt;
</span><del>-          [% &quot; or create and add the tag&quot; IF lists_of_bugs.size %]
</del><ins>+          [% &quot; or create and add the tag&quot; IF user.tags.size %]
</ins><span class="cx">           &lt;input class=&quot;txt&quot; type=&quot;text&quot; id=&quot;lob_newqueryname&quot;
</span><span class="cx">                  size=&quot;20&quot; maxlength=&quot;64&quot; name=&quot;newqueryname&quot;
</span><span class="cx">                  onkeyup=&quot;manage_old_lists();&quot;&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultglobalreasondescsnonetmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/global/reason-descs.none.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/global/reason-descs.none.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/global/reason-descs.none.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,40 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2010
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s): 
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[% SET reason_descs = {
+  ${constants.REL_ASSIGNEE} =&gt; &quot;You are the assignee for the ${terms.bug}.&quot;,
+  ${constants.REL_REPORTER} =&gt; &quot;You reported the ${terms.bug}.&quot;,
+  ${constants.REL_QA}       =&gt; &quot;You are the QA Contact for the ${terms.bug}.&quot;,
+  ${constants.REL_CC}       =&gt; &quot;You are on the CC list for the ${terms.bug}.&quot;,
+  ${constants.REL_GLOBAL_WATCHER} =&gt; &quot;You are watching all $terms.bug changes.&quot;,
+} %]
+
+[% SET watch_reason_descs =&gt; {
+  ${constants.REL_ASSIGNEE} =&gt;
+    &quot;You are watching the assignee of the ${terms.bug}.&quot;,
+  ${constants.REL_REPORTER} =&gt;
+    &quot;You are watching the reporter of the ${terms.bug}.&quot;,
+  ${constants.REL_QA}       =&gt;
+    &quot;You are watching the QA Contact of the ${terms.bug}.&quot;,
+  ${constants.REL_CC}       =&gt;
+    &quot;You are watching someone on the CC list of the ${terms.bug}.&quot;,
+} %]
+
+[% Hook.process('end') %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultglobalsettingdescsnonetmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/global/setting-descs.none.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/global/setting-descs.none.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/global/setting-descs.none.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -43,5 +43,16 @@
</span><span class="cx">    &quot;quote_replies&quot;                    =&gt; &quot;Quote the associated comment when you click on its reply link&quot;,
</span><span class="cx">    &quot;quoted_reply&quot;                     =&gt; &quot;Quote the full comment&quot;,
</span><span class="cx">    &quot;simple_reply&quot;                     =&gt; &quot;Reference the comment number only&quot;,
</span><ins>+   &quot;comment_box_position&quot;             =&gt; &quot;Position of the Additional Comments box&quot;,
+   &quot;before_comments&quot;                  =&gt; &quot;Before other comments&quot;,
+   &quot;after_comments&quot;                   =&gt; &quot;After other comments&quot;,
+   &quot;timezone&quot;                         =&gt; &quot;Timezone used to display dates and times&quot;,
+   &quot;local&quot;                            =&gt; &quot;Same as the server&quot;,
+   &quot;quicksearch_fulltext&quot;             =&gt; &quot;Include comments when performing quick searches (slower)&quot;,
+   &quot;email_format&quot;                     =&gt; &quot;Preferred email format&quot;,
+   &quot;html&quot;                             =&gt; &quot;HTML&quot;,
+   &quot;text_only&quot;                        =&gt; &quot;Text Only&quot;,
</ins><span class="cx">                    } 
</span><span class="cx"> %]
</span><ins>+
+[% Hook.process('settings') %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultglobalsitenavigationhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/global/site-navigation.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/global/site-navigation.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/global/site-navigation.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -20,7 +20,6 @@
</span><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [%# INTERFACE:
</span><del>-  # bug_list: list of integers. List of bug numbers of current query (if any).
</del><span class="cx">   # bug.bug_id: integer. Number of current bug (for navigation purposes)
</span><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="lines">@@ -32,38 +31,13 @@
</span><span class="cx"> [% IF NOT (cgi.user_agent(&quot;MSIE [1-6]&quot;) OR cgi.user_agent(&quot;Mozilla/4&quot;)) %]
</span><span class="cx">   &lt;link rel=&quot;Top&quot; href=&quot;[% urlbase FILTER html %]&quot;&gt;
</span><span class="cx"> 
</span><del>-  [%# *** Bug List Navigation *** %]
-  [% IF bug_list &amp;&amp; bug_list.size &gt; 0 %]
-    &lt;link rel=&quot;Up&quot; href=&quot;buglist.cgi?regetlastlist=1&quot;&gt;
-
-    &lt;link rel=&quot;First&quot; href=&quot;show_bug.cgi?id=[% bug_list.first %]&quot;&gt;
-    &lt;link rel=&quot;Last&quot; href=&quot;show_bug.cgi?id=[% bug_list.last %]&quot;&gt;
-
-    [% IF bug &amp;&amp; bug.bug_id %]
-      [% current_bug_idx = lsearch(bug_list, bug.bug_id) %]
-      [% IF current_bug_idx != -1 %]
-
-        [% IF current_bug_idx &gt; 0 %]
-          [% prev_bug = current_bug_idx - 1 %]
-          &lt;link rel=&quot;Prev&quot; href=&quot;show_bug.cgi?id=[% bug_list.$prev_bug %]&quot;&gt;
-        [% END %]
-
-        [% IF current_bug_idx + 1 &lt; bug_list.size %]
-          [% next_bug = current_bug_idx + 1 %]
-          &lt;link rel=&quot;Next&quot; href=&quot;show_bug.cgi?id=[% bug_list.$next_bug %]&quot;&gt;
-        [% END %]
-
-      [% END %]
-    [% END %]
-  [% END %]
-
</del><span class="cx">   [%# *** Attachment *** %]
</span><span class="cx">   [% IF attachment &amp;&amp; attachment.bug_id %]
</span><span class="cx">     &lt;link rel=&quot;Up&quot; href=&quot;show_bug.cgi?id=[% attachment.bug_id FILTER none %]&quot;&gt;
</span><span class="cx">   [% END %]
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-  [%# *** Dependencies, Votes, Activity, Print-version *** %]
</del><ins>+  [%# *** Dependencies, Activity, Print-version *** %]
</ins><span class="cx">   [% IF bug %]
</span><span class="cx">     &lt;link rel=&quot;Show&quot; title=&quot;Dependency Tree&quot;
</span><span class="cx">           href=&quot;showdependencytree.cgi?id=[% bug.bug_id %]&amp;amp;hide_resolved=1&quot;&gt;
</span><span class="lines">@@ -72,11 +46,6 @@
</span><span class="cx">             href=&quot;showdependencygraph.cgi?id=[% bug.bug_id %]&quot;&gt;
</span><span class="cx">     [% END %]
</span><span class="cx"> 
</span><del>-    [% IF bug.use_votes %]
-      &lt;link rel=&quot;Show&quot; title=&quot;Votes ([% bug.votes %])&quot;
-            href=&quot;votes.cgi?action=show_bug&amp;amp;bug_id=[% bug.bug_id %]&quot;&gt;
-    [% END %]
-
</del><span class="cx">       &lt;link rel=&quot;Show&quot; title=&quot;[% terms.Bug %] Activity&quot;
</span><span class="cx">             href=&quot;show_activity.cgi?id=[% bug.bug_id %]&quot;&gt;
</span><span class="cx">       &lt;link rel=&quot;Show&quot; title=&quot;Printer-Friendly Version&quot;
</span><span class="lines">@@ -86,42 +55,36 @@
</span><span class="cx"> 
</span><span class="cx">   [%# *** Saved Searches *** %]
</span><span class="cx">   [% IF user.showmybugslink %]
</span><del>-    [% user_login = user.login FILTER url_quote %]
</del><ins>+    [% user_login = user.login FILTER uri %]
</ins><span class="cx">     &lt;link rel=&quot;Saved&amp;nbsp;Searches&quot; title=&quot;My [% terms.Bugs %]&quot;
</span><span class="cx">           href=&quot;[% Param('mybugstemplate').replace('%userid%', user_login) %]&quot;&gt;
</span><span class="cx">   [% END %]
</span><span class="cx"> 
</span><del>-  [% FOREACH q = user.queries %]
-    &lt;link rel=&quot;Saved&amp;nbsp;Searches&quot; 
-          title=&quot;[% q.name FILTER html %]&quot;
-          href=&quot;buglist.cgi?cmdtype=runnamed&amp;amp;namedcmd=[% q.name FILTER url_quote %]&quot;&gt;
-  [% END %]
-
</del><span class="cx">   [% FOREACH q = user.queries_subscribed %]
</span><span class="cx">     &lt;link rel=&quot;Saved&amp;nbsp;Search&quot;
</span><span class="cx">           title=&quot;[% q.name FILTER html %] ([% q.user.login FILTER html %])&quot;
</span><span class="cx">           href=&quot;buglist.cgi?cmdtype=dorem&amp;amp;remaction=run&amp;amp;namedcmd=
</span><del>-                 [% q.name FILTER url_quote %]&amp;amp;sharer_id=
-                 [% q.user.id FILTER url_quote %]&quot;&gt;
</del><ins>+                 [% q.name FILTER uri %]&amp;amp;sharer_id=
+                 [% q.user.id FILTER uri %]&quot;&gt;
</ins><span class="cx">   [% END %]
</span><span class="cx"> 
</span><span class="cx">   [%# *** Bugzilla Administration Tools *** %]
</span><span class="cx">   [% IF user.login %] 
</span><span class="cx">     [% '&lt;link rel=&quot;Administration&quot; title=&quot;Parameters&quot;    
</span><del>-              href=&quot;editparams.cgi&quot;&gt;' IF user.groups.tweakparams %]
</del><ins>+              href=&quot;editparams.cgi&quot;&gt;' IF user.in_group('tweakparams') %]
</ins><span class="cx">     [% '&lt;link rel=&quot;Administration&quot; title=&quot;Users&quot;    
</span><del>-              href=&quot;editusers.cgi&quot;&gt;' IF user.groups.editusers %]
</del><ins>+              href=&quot;editusers.cgi&quot;&gt;' IF user.in_group('editusers') %]
</ins><span class="cx">     [% '&lt;link rel=&quot;Administration&quot; title=&quot;Products&quot; href=&quot;editproducts.cgi&quot;&gt;'
</span><del>-       IF user.groups.editcomponents || user.get_products_by_permission(&quot;editcomponents&quot;).size %]
</del><ins>+       IF user.in_group('editcomponents') || user.get_products_by_permission(&quot;editcomponents&quot;).size %]
</ins><span class="cx">     [% '&lt;link rel=&quot;Administration&quot; title=&quot;Flag Types&quot;   
</span><del>-              href=&quot;editflagtypes.cgi&quot;&gt;' IF user.groups.editcomponents %]
</del><ins>+              href=&quot;editflagtypes.cgi&quot;&gt;' IF user.in_group('editcomponents') %]
</ins><span class="cx">     [% '&lt;link rel=&quot;Administration&quot; title=&quot;Groups&quot;        
</span><del>-              href=&quot;editgroups.cgi&quot;&gt;' IF user.groups.creategroups %]
</del><ins>+              href=&quot;editgroups.cgi&quot;&gt;' IF user.in_group('creategroups') %]
</ins><span class="cx">     [% '&lt;link rel=&quot;Administration&quot; title=&quot;Keywords&quot;      
</span><del>-              href=&quot;editkeywords.cgi&quot;&gt;' IF user.groups.editkeywords %]
</del><ins>+              href=&quot;editkeywords.cgi&quot;&gt;' IF user.in_group('editkeywords') %]
</ins><span class="cx">     [% '&lt;link rel=&quot;Administration&quot; title=&quot;Whining&quot;       
</span><del>-              href=&quot;editwhines.cgi&quot;&gt;' IF user.groups.bz_canusewhines %]
</del><ins>+              href=&quot;editwhines.cgi&quot;&gt;' IF user.in_group('bz_canusewhines') %]
</ins><span class="cx">     [% '&lt;link rel=&quot;Administration&quot; title=&quot;Sanity Check&quot;  
</span><del>-              href=&quot;sanitycheck.cgi&quot;&gt;' IF user.groups.editcomponents %]
</del><ins>+              href=&quot;sanitycheck.cgi&quot;&gt;' IF user.in_group('editcomponents') %]
</ins><span class="cx">   [% END %]  
</span><span class="cx"> [% END %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultglobaltabshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/global/tabs.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/global/tabs.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/global/tabs.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -35,9 +35,13 @@
</span><span class="cx"> 
</span><span class="cx">       [% FOREACH tab = tabs %]
</span><span class="cx">         [% IF tab.name == current_tab_name %]
</span><del>-          &lt;td class=&quot;selected&quot;&gt;[% tab.label FILTER html %]&lt;/td&gt;
</del><ins>+          &lt;td id=&quot;tab_[% tab.name FILTER html %]&quot; class=&quot;selected&quot;&gt;
+            [% tab.label FILTER html %]&lt;/td&gt;
</ins><span class="cx">         [% ELSE %]
</span><del>-          &lt;td class=&quot;clickable_area&quot; onClick=&quot;document.location='[% tab.link FILTER html %]'&quot;&gt;&lt;a href=&quot;[% tab.link FILTER html %]&quot;&gt;[% tab.label FILTER html %]&lt;/a&gt;&lt;/td&gt;
</del><ins>+          &lt;td id=&quot;tab_[% tab.name FILTER html %]&quot; class=&quot;clickable_area&quot;
+              onClick=&quot;document.location='[% tab.link FILTER html %]'&quot;&gt;
+            &lt;a href=&quot;[% tab.link FILTER html %]&quot;&gt;[% tab.label FILTER html %]&lt;/a&gt;
+          &lt;/td&gt;
</ins><span class="cx">         [% END %]
</span><span class="cx">       [% END %]
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultglobaltextareahtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/global/textarea.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/global/textarea.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/global/textarea.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -19,7 +19,10 @@
</span><span class="cx">   # name:           (optional) The &quot;name&quot;-attribute of the textarea.
</span><span class="cx">   # accesskey:      (optional) The &quot;accesskey&quot;-attribute of the textarea.
</span><span class="cx">   # style:          (optional) The &quot;style&quot;-attribute of the textarea.
</span><ins>+  # classes:        (optional) The &quot;class&quot;-attribute of the textarea.
</ins><span class="cx">   # wrap:           (deprecated; optional) The &quot;wrap&quot;-attribute of the textarea.
</span><ins>+  # disabled:       (optional) Disable the textarea.
+  # readonly:       (optional) Prevent the textarea from being edited.
</ins><span class="cx">   # minrows:        (required) Number of rows the textarea shall have initially
</span><span class="cx">   #                 and when not having focus.
</span><span class="cx">   # maxrows:        (optional) Number of rows the textarea shall have if
</span><span class="lines">@@ -30,13 +33,18 @@
</span><span class="cx">   #                 minrows will be used.
</span><span class="cx">   # cols:           (required) Number of columns the textarea shall have.
</span><span class="cx">   # defaultcontent: (optional) Default content for the textarea.
</span><ins>+  # mandatory:      (optional) Boolean specifying whether or not the textarea
+  #                 is mandatory.
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> &lt;textarea [% IF name %]name=&quot;[% name FILTER html %]&quot;[% END %]
</span><span class="cx">           [% IF id %] id=&quot;[% id FILTER html %]&quot;[% END %]
</span><span class="cx">           [% IF accesskey %] accesskey=&quot;[% accesskey FILTER html %]&quot;[% END %]
</span><span class="cx">           [% IF style %] style=&quot;[% style FILTER html %]&quot;[% END %]
</span><ins>+          [% IF classes %] class=&quot;[% classes FILTER html %]&quot;[% END %]
</ins><span class="cx">           [% IF wrap %] wrap=&quot;[% wrap FILTER html %]&quot;[% END %]
</span><ins>+          [% IF disabled %] disabled=&quot;disabled&quot;[% END %]
+          [% IF readonly %] readonly=&quot;readonly&quot;[% END %]
</ins><span class="cx">           [% IF defaultrows &amp;&amp; user.settings.zoom_textareas.value == 'off' %]
</span><span class="cx">             rows=&quot;[% defaultrows FILTER html %]&quot;
</span><span class="cx">           [% ELSE %]
</span><span class="lines">@@ -45,4 +53,7 @@
</span><span class="cx">           cols=&quot;[% cols FILTER html %]&quot;
</span><span class="cx">           [% IF maxrows &amp;&amp; user.settings.zoom_textareas.value == 'on' %]
</span><span class="cx">             onFocus=&quot;this.rows=[% maxrows FILTER html %]&quot;
</span><ins>+          [% END %]
+          [% IF mandatory %]
+            aria-required=&quot;true&quot;
</ins><span class="cx">           [% END %]&gt;[% defaultcontent FILTER html %]&lt;/textarea&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultglobalusefullinkshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/global/useful-links.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/global/useful-links.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/global/useful-links.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -27,7 +27,6 @@
</span><span class="cx"> 
</span><span class="cx"> &lt;ul id=&quot;useful-links&quot;&gt;
</span><span class="cx">   &lt;li id=&quot;links-actions&quot;&gt;
</span><del>-    &lt;div class=&quot;label&quot;&gt;Actions: &lt;/div&gt;
</del><span class="cx">       [% PROCESS &quot;global/common-links.html.tmpl&quot; qs_suffix = &quot;_bottom&quot; %]
</span><span class="cx">   &lt;/li&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -38,12 +37,9 @@
</span><span class="cx">   %]
</span><span class="cx">     [% print_pipe = 0 %]
</span><span class="cx">     &lt;li id=&quot;links-saved&quot;&gt;
</span><del>-      &lt;div class=&quot;label&quot;&gt;
-        Saved Searches:
-      &lt;/div&gt;
</del><span class="cx">       &lt;ul class=&quot;links&quot;&gt;
</span><span class="cx">         [% IF user.showmybugslink %]
</span><del>-          [% filtered_username = user.login FILTER url_quote %]
</del><ins>+          [% filtered_username = user.login FILTER uri %]
</ins><span class="cx">           &lt;li&gt;&lt;a href=&quot;[% Param('mybugstemplate').replace('%userid%', filtered_username) %]&quot;&gt;My [% terms.Bugs %]&lt;/a&gt;&lt;/li&gt;
</span><span class="cx">           [% print_pipe = 1 %]
</span><span class="cx">         [% END %]
</span><span class="lines">@@ -51,7 +47,7 @@
</span><span class="cx">         [% FOREACH q = user.queries %]
</span><span class="cx">           [% IF q.link_in_footer %]
</span><span class="cx">             &lt;li&gt;[% '&lt;span class=&quot;separator&quot;&gt;| &lt;/span&gt;' IF print_pipe %]
</span><del>-            &lt;a href=&quot;buglist.cgi?cmdtype=runnamed&amp;amp;namedcmd=[% q.name FILTER url_quote %]&quot;&gt;[% q.name FILTER html %]&lt;/a&gt;&lt;/li&gt;
</del><ins>+            &lt;a href=&quot;buglist.cgi?cmdtype=runnamed&amp;amp;namedcmd=[% q.name FILTER uri %]&quot;&gt;[% q.name FILTER html %]&lt;/a&gt;&lt;/li&gt;
</ins><span class="cx">             [% print_pipe = 1 %]
</span><span class="cx">           [% END %]
</span><span class="cx">         [% END %]
</span><span class="lines">@@ -65,8 +61,8 @@
</span><span class="cx">           &lt;li&gt;
</span><span class="cx">             [% '&lt;span class=&quot;separator&quot;&gt;| &lt;/span&gt;' IF print_pipe %]
</span><span class="cx">             &lt;a href=&quot;buglist.cgi?cmdtype=dorem&amp;amp;remaction=run&amp;amp;namedcmd=
</span><del>-                     [% q.name FILTER url_quote %]&amp;amp;sharer_id=
-                     [% q.user.id FILTER url_quote %]&quot;
</del><ins>+                     [% q.name FILTER uri %]&amp;amp;sharer_id=
+                     [% q.user.id FILTER uri %]&quot;
</ins><span class="cx">                class=&quot;shared&quot;
</span><span class="cx">                title=&quot;Shared by [% q.user.identity FILTER html %]&quot;
</span><span class="cx">                &gt;[% q.name FILTER html FILTER no_break %]&lt;/a&gt;&lt;/li&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultglobalusererrorhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/global/user-error.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/global/user-error.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/global/user-error.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -17,6 +17,7 @@
</span><span class="cx">   #
</span><span class="cx">   # Contributor(s): Gervase Markham &lt;gerv@gerv.net&gt;
</span><span class="cx">   #                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
</span><ins>+  #                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [%# INTERFACE:
</span><span class="lines">@@ -32,10 +33,10 @@
</span><span class="cx">   # in this file; if you do not wish to change it, use the &quot;none&quot; filter.
</span><span class="cx">   #
</span><span class="cx">   # Extension- or custom-specific error handling  can be easily added 
</span><del>-  # via hooks: just place your &lt;extension&gt;-errors.html.tmpl into 
-  # template/en/extension/hook/global/user-error.html.tmpl/errors/
-  # Note: be aware of uniqueness of error string parameter value, since 
-  # nobody can guarantee the hook files processing order in the future
</del><ins>+  # via hooks: just place additional code into
+  # template/en/hook/global/user-error-errors.html.tmpl
+  # Note: be aware of uniqueness of error string parameter value, since
+  # nobody can guarantee the hook files processing order in the future.
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="lines">@@ -76,6 +77,12 @@
</span><span class="cx">       that login name.
</span><span class="cx">     [% END %]
</span><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;account_locked&quot; %]
+    [% title = &quot;Account Locked&quot; %]
+    Your IP ([% ip_addr FILTER html %]) has been locked out of this
+    account until [% unlock_at FILTER time %], as you have
+    exceeded the maximum number of login attempts.
+
</ins><span class="cx">   [% ELSIF error == &quot;alias_has_comma_or_space&quot; %]
</span><span class="cx">     [% title = &quot;Invalid Characters In Alias&quot; %]
</span><span class="cx">     The alias you entered, &lt;em&gt;[% alias FILTER html %]&lt;/em&gt;,
</span><span class="lines">@@ -102,6 +109,11 @@
</span><span class="cx">     [% terms.Bug %] aliases cannot be longer than 20 characters.
</span><span class="cx">     Please choose a shorter alias.
</span><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;attachment_bug_id_mismatch&quot; %]
+    [% title = &quot;Invalid Attachments&quot; %]
+    You tried to perform an action on attachments from different [% terms.bugs %].
+    This operation requires all attachments to be from the same [% terms.bug %].
+
</ins><span class="cx">   [% ELSIF error == &quot;auth_cant_create_account&quot; %]
</span><span class="cx">     [% title = &quot;Can't create accounts&quot; %]
</span><span class="cx">     This site is using an authentication scheme which does not permit
</span><span class="lines">@@ -138,24 +150,32 @@
</span><span class="cx">       delete
</span><span class="cx">     [% ELSIF action == &quot;edit&quot; %]
</span><span class="cx">       add, modify or delete
</span><del>-    [% ELSIF action == &quot;move&quot; %]
-      move
</del><span class="cx">     [% ELSIF action == &quot;run&quot; %]
</span><span class="cx">       run
</span><span class="cx">     [% ELSIF action == &quot;schedule&quot; %]
</span><span class="cx">       schedule
</span><ins>+    [% ELSIF action == &quot;search&quot; %]
+      search
</ins><span class="cx">     [% ELSIF action == &quot;use&quot; %]
</span><span class="cx">       use
</span><span class="cx">     [% ELSIF action == &quot;approve&quot; %]
</span><span class="cx">       approve
</span><ins>+    [% ELSE %]
+      [%+ Hook.process('auth_failure_action') %]
</ins><span class="cx">     [% END %]
</span><span class="cx"> 
</span><span class="cx">     [% IF object == &quot;administrative_pages&quot; %]
</span><span class="cx">       administrative pages
</span><span class="cx">     [% ELSIF object == &quot;attachment&quot; %]
</span><del>-      this attachment
</del><ins>+      [% IF attach_id %]
+        attachment #[% attach_id FILTER html %]
+      [% ELSE %]
+        this attachment
+      [% END %]
</ins><span class="cx">     [% ELSIF object == &quot;bugs&quot; %]
</span><span class="cx">       [%+ terms.bugs %]
</span><ins>+    [% ELSIF object == &quot;bug_fields&quot; %]
+      the [% field_descs.$field FILTER html %] field
</ins><span class="cx">     [% ELSIF object == &quot;charts&quot; %]
</span><span class="cx">       the &quot;New Charts&quot; feature
</span><span class="cx">     [% ELSIF object == &quot;classifications&quot; %]
</span><span class="lines">@@ -194,14 +214,17 @@
</span><span class="cx">       a sudo session
</span><span class="cx">     [% ELSIF object == &quot;timetracking_summaries&quot; %]
</span><span class="cx">       time-tracking summary reports
</span><del>-    [% ELSIF object == &quot;user&quot; %]
-      the user you specified
</del><ins>+    [% ELSIF object == &quot;user&quot; %]  
+      the user [% IF userid %] with ID '[% userid FILTER html %]'
+      [% ELSE %]you specified [% END %]
</ins><span class="cx">     [% ELSIF object == &quot;users&quot; %]
</span><span class="cx">       users
</span><span class="cx">     [% ELSIF object == &quot;versions&quot; %]
</span><span class="cx">       versions
</span><span class="cx">     [% ELSIF object == &quot;workflow&quot; %]
</span><span class="cx">       the workflow
</span><ins>+    [% ELSE %]
+      [%+ Hook.process('auth_failure_object') %]
</ins><span class="cx">     [% END %].
</span><span class="cx"> 
</span><span class="cx">     [% Hook.process(&quot;auth_failure&quot;) %]
</span><span class="lines">@@ -225,23 +248,63 @@
</span><span class="cx">     You are not authorized to access [% terms.bug %] #[% bug_id FILTER html %].
</span><span class="cx">     To see this [% terms.bug %], you must
</span><span class="cx">     first &lt;a href=&quot;show_bug.cgi?id=
</span><del>-                   [% bug_id FILTER url_quote %]&amp;amp;GoAheadAndLogIn=1&quot;&gt;log
</del><ins>+                   [% bug_id FILTER uri %]&amp;amp;GoAheadAndLogIn=1&quot;&gt;log
</ins><span class="cx">     in to an account&lt;/a&gt; with the appropriate permissions.
</span><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;bug_url_invalid&quot; %]
+    [% title = &quot;Invalid $terms.Bug URL&quot; %]
+    &lt;code&gt;[% url FILTER html %]&lt;/code&gt; is not a valid URL to [% terms.abug %].
+    [% IF reason == 'http' %]
+      URLs must start with &quot;http&quot; or &quot;https&quot;.
+    [% ELSIF reason == 'path_only' %]
+      You must specify a full URL.
+    [% ELSIF reason == 'show_bug' %]
+      [%+ field_descs.see_also FILTER html %] URLs should point to one of:
+      &lt;ul&gt;
+        &lt;li&gt;&lt;code&gt;show_bug.cgi&lt;/code&gt; in a [% terms.Bugzilla %]
+          installation.&lt;/li&gt;
+        &lt;li&gt;A b[% %]ug on launchpad.net&lt;/li&gt;
+        &lt;li&gt;An issue on code.google.com.&lt;/li&gt;
+        &lt;li&gt;A b[% %]ug on b[% %]ugs.debian.org.&lt;/li&gt;
+        &lt;li&gt;An issue in a JIRA installation.&lt;/li&gt;
+        &lt;li&gt;A ticket in a Trac installation.&lt;/li&gt;
+        &lt;li&gt;A b[% %]ug in a MantisBT installation.&lt;/li&gt;
+        &lt;li&gt;A b[% %]ug on sourceforge.net.&lt;/li&gt;
+      &lt;/ul&gt;
+    [% ELSIF reason == 'id' %]
+      There is no valid [% terms.bug %] id in that URL.
+    [% END %]
+
+  [% ELSIF error == &quot;bug_url_too_long&quot; %]
+    [% title = &quot;Invalid $terms.Bug URL&quot; %]
+    [% terms.Bug %] URLs can not be longer than 
+    [%+ constants.MAX_BUG_URL_LENGTH FILTER none %] characters long.
+    &lt;code&gt;[% url FILTER html %]&lt;/code&gt; is too long.
+
</ins><span class="cx">   [% ELSIF error == &quot;buglist_parameters_required&quot; %]
</span><span class="cx">     [% title = &quot;Parameters Required&quot; %]
</span><span class="cx">     [% docslinks = {'query.html' =&gt; &quot;Searching for $terms.bugs&quot;,
</span><span class="cx">                     'query.html#list' =&gt; &quot;$terms.Bug lists&quot;} %]
</span><span class="cx">     You may not search, or create saved searches, without any search terms.
</span><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;cc_remove_denied&quot; %]
+    [% title = &quot;Change Denied&quot; %]
+    You do not have permission to remove other people from the CC list.
+
</ins><span class="cx">   [% ELSIF error == &quot;chart_too_large&quot; %]
</span><span class="cx">     [% title = &quot;Chart Too Large&quot; %]
</span><span class="cx">     Sorry, but 2000 x 2000 is the maximum size for a chart.
</span><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;comment_id_invalid&quot; %]
+    [% id FILTER html %] is not a valid comment id.
+
</ins><span class="cx">   [% ELSIF error == &quot;comment_invalid_isprivate&quot; %]
</span><span class="cx">     You tried to modify the privacy of comment id [% id FILTER html %],
</span><span class="cx">     but that is not a valid comment on this [% terms.bug %].
</span><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;comment_is_private&quot; %]
+    Comment id [% id FILTER html %] is private.
+
</ins><span class="cx">   [% ELSIF error == &quot;comment_required&quot; %]
</span><span class="cx">     [% title = &quot;Comment Required&quot; %]
</span><span class="cx">     You have to specify a
</span><span class="lines">@@ -256,13 +319,19 @@
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;comment_too_long&quot; %]
</span><span class="cx">     [% title = &quot;Comment Too Long&quot; %]
</span><del>-    Comments cannot be longer than 65,535 characters.
</del><ins>+    Comments cannot be longer than 
+    [%+ constants.MAX_COMMENT_LENGTH FILTER html %] characters.
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;auth_classification_not_enabled&quot; %]
</span><span class="cx">     [% title = &quot;Classification Not Enabled&quot; %]
</span><span class="cx">     Sorry, classification is not enabled.
</span><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;classification_not_specified&quot; %]
</del><ins>+  [% ELSIF error == &quot;classification_name_too_long&quot; %]
+    [% title = &quot;Classification Name Too Long&quot; %]
+    The name of a classification is limited to [% constants.MAX_CLASSIFICATION_SIZE FILTER html %]
+    characters. '[% name FILTER html %]' is too long ([% name.length %] characters).
+
+[% ELSIF error == &quot;classification_not_specified&quot; %]
</ins><span class="cx">     [% title = &quot;You Must Supply A Classification Name&quot; %]
</span><span class="cx">     You must enter a classification name.
</span><span class="cx"> 
</span><span class="lines">@@ -270,19 +339,10 @@
</span><span class="cx">     [% title = &quot;Classification Already Exists&quot; %]
</span><span class="cx">     A classification with the name '[% name FILTER html %]' already exists.
</span><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;classification_doesnt_exist&quot; %]
-    [% title = &quot;Classification Does Not Exist&quot; %]
-    The classification '[% name FILTER html %]' does not exist.
-
-  [% ELSIF error == &quot;classification_doesnt_exist_for_product&quot; %]
-    [% title = &quot;Classification Does Not Exist For Product&quot; %]
-    The classification '[% classification FILTER html %]' does not exist
-    for product '[% product FILTER html %]'.
-
</del><span class="cx">   [% ELSIF error == &quot;classification_invalid_sortkey&quot; %]
</span><span class="cx">     [% title = &quot;Invalid Sortkey for Classification&quot; %]
</span><del>-    The sortkey &lt;em&gt;[% sortkey FILTER html %]&lt;/em&gt; for the '[% name FILTER html %]'
-    classification is invalid. It must be a positive integer.
</del><ins>+    The sortkey '[% sortkey FILTER html %]' is invalid. It must be an
+    integer between 0 and [% constants.MAX_SMALLINT FILTER html %].
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;classification_not_deletable&quot; %]
</span><span class="cx">     [% title = &quot;Default Classification Can Not Be Deleted&quot; %]
</span><span class="lines">@@ -314,8 +374,8 @@
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;component_name_too_long&quot; %]
</span><span class="cx">     [% title = &quot;Component Name Is Too Long&quot; %]
</span><del>-    The name of a component is limited to 64 characters. 
-    '[% name FILTER html %]' is too long ([% name.length %] characters).
</del><ins>+    The name of a component is limited to [% constants.MAX_COMPONENT_SIZE FILTER html %]
+    characters. '[% name FILTER html %]' is too long ([% name.length %] characters).
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;component_need_initialowner&quot; %]
</span><span class="cx">     [% title = &quot;Component Requires Default Assignee&quot; %]
</span><span class="lines">@@ -402,12 +462,30 @@
</span><span class="cx">     does not exist or you aren't authorized to
</span><span class="cx">     enter [% terms.abug %] into it.
</span><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;extension_create_no_name&quot; %]
+    You must specify a name for your extension, as an argument to this script.
+
+  [% ELSIF error == &quot;extension_first_letter_caps&quot; %]
+    The first letter of your extension's name must be a capital letter.
+    (You specified '[% name FILTER html %]'.)
+
</ins><span class="cx">   [% ELSIF error == &quot;field_already_exists&quot; %]
</span><span class="cx">     [% title = &quot;Field Already Exists&quot; %]
</span><span class="cx">     The field '[% field.name FILTER html %]'     
</span><span class="cx">     ([% field.description FILTER html %]) already exists. Please
</span><span class="cx">     choose another name.
</span><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;field_cant_control_self&quot; %]
+    [% title = &quot;Field Can't Control Itself&quot; %]
+    The [% field.description FILTER html %] field can't be set to control 
+    itself.
+
+  [% ELSIF error == &quot;field_control_must_be_select&quot; %]
+    [% title = &quot;Invalid Field Type Selected&quot; %]
+    Only drop-down and multi-select fields can be used to control
+    the visibility/values of other fields. [% field.description FILTER html %]
+    is not the right type of field.
+
</ins><span class="cx">   [% ELSIF error == &quot;field_invalid_name&quot; %]
</span><span class="cx">     [% title = &quot;Invalid Field Name&quot; %]
</span><span class="cx">     '[% name FILTER html %]' is not a valid name for a field.
</span><span class="lines">@@ -426,69 +504,92 @@
</span><span class="cx">     [% title = &quot;Missing Name for Field&quot; %]
</span><span class="cx">     You must enter a name for this field.
</span><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;field_value_control_select_only&quot; %]
+    [% title = &quot;Invalid Value Control Field&quot; %]
+    Only Drop-Down or Multi-Select fields can have a field that
+    controls their values.
+
+  [% ELSIF error == &quot;field_visibility_values_must_be_selected&quot; %]
+    [% title = &quot;Missing visibility field values&quot; %]
+    At least one value must be selected for the visibility field
+    '[% field.name FILTER html %]'.
+
</ins><span class="cx">   [% ELSIF error == &quot;fieldname_invalid&quot; %]
</span><span class="cx">     [% title = &quot;Specified Field Does Not Exist&quot; %]
</span><del>-    The field '[% field FILTER html %]' does not exist or 
</del><ins>+    The field '[% field.name FILTER html %]' does not exist or 
</ins><span class="cx">     cannot be edited with this interface.
</span><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;fieldname_not_specified&quot; %]
-    [% title = &quot;Field Name Not Specified&quot; %]
-    No field name specified when trying to edit field values.
-
</del><span class="cx">   [% ELSIF error == &quot;fieldvalue_already_exists&quot; %]
</span><span class="cx">     [% title = &quot;Field Value Already Exists&quot; %]
</span><del>-    The value '[% value FILTER html %]' already exists for the
-    '[%- field.description FILTER html %]' field.
</del><ins>+    The value '[% value.name FILTER html %]' already exists for the
+    [%+ field.description FILTER html %] field.
</ins><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;fieldvalue_doesnt_exist&quot; %]
-    [% title = &quot;Specified Field Value Does Not Exist&quot; %]
-    The value '[% value FILTER html %]' does not exist for
-    the '[% field FILTER html %]' field.
</del><ins>+  [% ELSIF error == &quot;fieldvalue_is_controller&quot; %]
+    [% title = &quot;Value Controls Other Fields&quot; %]
+    You cannot delete the [% value.field.description FILTER html %]
+    '[% value.name FILTER html %]' because
+    [% IF fields.size %]
+      it controls the visibility of the following fields:
+      [%+ fields.join(', ') FILTER html %].
+    [% END %]
+    [% ' Also, ' IF fields.size AND vals.size %]
+    [% IF vals.size %]
+      it controls the visibility of the following field values:
+      &lt;ul&gt;
+        [% FOREACH field_name = vals.keys %]
+          [% FOREACH val = vals.${field_name} %]
+            &lt;li&gt;[% val.field.name FILTER html %]:
+              '[% val.name FILTER html %]'&lt;/li&gt;
+          [% END %]
+        [% END %]
+      &lt;/ul&gt;
+    [% END %]
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;fieldvalue_is_default&quot; %]
</span><span class="cx">     [% title = &quot;Specified Field Value Is Default&quot; %]
</span><del>-    '[% value FILTER html %]' is the default value for
-    the '[% field.description FILTER html %]' field and cannot be deleted.
-    [% IF user.groups.tweakparams %]
</del><ins>+    '[% value.name FILTER html %]' is the default value for
+    the '[% field.description FILTER html %]' field and cannot be deleted
+    or disabled.
+    [% IF user.in_group('tweakparams') %]
</ins><span class="cx">       You have to &lt;a href=&quot;editparams.cgi?section=bugfields#
</span><del>-      [%- param_name FILTER url_quote %]&quot;&gt;change&lt;/a&gt; the default value first.
</del><ins>+      [%- param_name FILTER uri %]&quot;&gt;change&lt;/a&gt; the default value first.
</ins><span class="cx">     [% END %]
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;fieldvalue_name_too_long&quot; %]
</span><span class="cx">     [% title = &quot;Field Value Is Too Long&quot; %]
</span><del>-    The value of a field is limited to 60 characters.
</del><ins>+    The value of a field is limited to 
+    [%+ constants.FIELD_VALUE_MAX_SIZE FILTER none %] characters. 
</ins><span class="cx">     '[% value FILTER html %]' is too long ([% value.length %] characters).
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;fieldvalue_not_editable&quot; %]
</span><span class="cx">     [% title = &quot;Field Value Not Editable&quot; %]
</span><del>-    The value '[% old_value FILTER html %]' cannot be renamed because
-    it plays some special role for the '[% field.description FILTER html %]' field.
</del><ins>+    The value '[% old_value.name FILTER html %]' cannot be renamed because
+    it plays some special role for the '[% field.description FILTER html %]'
+    field.
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;fieldvalue_not_deletable&quot; %]
</span><span class="cx">     [% title = &quot;Field Value Not Deletable&quot; %]
</span><del>-    The value '[% value FILTER html %]' cannot be removed because
-    it plays some special role for the '[% field.description FILTER html %]' field.
</del><ins>+    The value '[% value.name FILTER html %]' cannot be removed or
+    disabled, because it plays some special role for the 
+    '[% field.description FILTER html %]' field.
</ins><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;fieldvalue_not_specified&quot; %]
-    [% title = &quot;Field Value Not Specified&quot; %]
-    No field value specified when trying to edit a field value.
-
</del><span class="cx">   [% ELSIF error == &quot;fieldvalue_reserved_word&quot; %]
</span><span class="cx">     [% title = &quot;Reserved Word Not Allowed&quot; %]
</span><del>-    You cannot use the '[% value FILTER html %]' value for the
</del><ins>+    You cannot use the value '[% value FILTER html %]' for the
</ins><span class="cx">     '[% field.description FILTER html %]' field. This value is used internally.
</span><span class="cx">     Please choose another one.
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;fieldvalue_sortkey_invalid&quot; %]
</span><span class="cx">     [% title = &quot;Invalid Field Value Sortkey&quot; %]
</span><del>-    The sortkey '[% sortkey FILTER html %]' for the '[% name FILTER html %]'
-    field is not a valid (positive) number.
</del><ins>+    The sortkey '[% sortkey FILTER html %]' for the 
+    [%+ field.description FILTER html %] field is not a valid 
+    (positive) number.
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;fieldvalue_still_has_bugs&quot; %]
</span><span class="cx">     [% title = &quot;You Cannot Delete This Field Value&quot; %]
</span><del>-    You cannot delete the value '[% value FILTER html %]' from the 
-    '[% field FILTER html %]' field, because there are still
-    [%+ count FILTER html %] [%+ terms.bugs %] using it.
</del><ins>+    You cannot delete the value '[% value.name FILTER html %]' from the 
+    [%+ field.description FILTER html %] field, because there are still
+    [%+ value.bug_count FILTER html %] [%+ terms.bugs %] using it.
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;fieldvalue_undefined&quot; %]
</span><span class="cx">     [% title = &quot;Undefined Value Not Allowed&quot; %]
</span><span class="lines">@@ -498,28 +599,25 @@
</span><span class="cx">     [% title = &quot;No File Specified&quot; %]
</span><span class="cx">     You did not specify a file to attach.
</span><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;filename_not_specified&quot; %]
+    [% title = &quot;No Filename Specified&quot; %]
+    You must specify a filename for this attachment.
+
</ins><span class="cx">   [% ELSIF error == &quot;file_too_large&quot; %]
</span><span class="cx">     [% title = &quot;File Too Large&quot; %]
</span><ins>+    [%# Convert maxlocalattachment from Mb to Kb %]
+    [% max_local = Param('maxlocalattachment') * 1024 %]
+    [% max_limit = [Param('maxattachmentsize'), max_local] %]
</ins><span class="cx">     The file you are trying to attach is [% filesize FILTER html %] 
</span><del>-    kilobytes (KB) in size. Non-patch attachments cannot be more than
-    [%+ Param('maxattachmentsize') %] KB. &lt;br&gt;
</del><ins>+    kilobytes (KB) in size. Attachments cannot be more than
+    [%# Hack to get the max value between both limits %]
+    [%+ max_limit.nsort.last FILTER html %] KB. &lt;br&gt;
</ins><span class="cx">     We recommend that you store your attachment elsewhere
</span><del>-    [% IF Param(&quot;allow_attach_url&quot;) %]
-      and then specify the URL to this file on the attachment
-      creation page in the &lt;b&gt;AttachURL&lt;/b&gt; field.
-    [% ELSE %]
-      and then insert the URL to it in a comment, or in the URL field
-      for this [% terms.bug %].
-    [% END %]
</del><ins>+    and then paste the URL to this file on the attachment
+    creation page in the appropriate text field.
</ins><span class="cx">     &lt;br&gt;Alternately, if your attachment is an image, you could convert
</span><span class="cx">     it to a compressible format like JPG or PNG and try again.
</span><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;flag_not_multiplicable&quot; %]
-    [% docslinks = {'flags-overview.html' =&gt; 'An overview on Flags',
-                    'flags.html' =&gt; 'Using Flags'} %]
-    You can't ask more than one person at a time for
-    &lt;em&gt;[% type.name FILTER html %]&lt;/em&gt;.
-
</del><span class="cx">   [% ELSIF error == &quot;flag_requestee_needs_privs&quot; %]
</span><span class="cx">     [% title = &quot;Flag Requestee Needs Privileges&quot; %]
</span><span class="cx">     [% requestee.identity FILTER html %] does not have permission to set the
</span><span class="lines">@@ -558,6 +656,24 @@
</span><span class="cx">     and the user you asked isn't in that group.  Please choose someone else
</span><span class="cx">     to ask, or ask an administrator to add the user to the group.
</span><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;flag_status_invalid&quot; %]
+    [% title = &quot;Flag Status Invalid&quot; %]
+    The flag status &lt;em&gt;[% status FILTER html %]&lt;/em&gt;
+    [% IF id %]
+      for flag ID #[% id FILTER html %]
+    [% END %]
+    is invalid.
+
+  [% ELSIF error == &quot;flag_type_cannot_deactivate&quot; %]
+    [% title = &quot;Cannot Deactivate Flag Type&quot; %]
+    Sorry, but the flag type '[% flagtype.name FILTER html %]' also applies to some
+    products you cannot see, and so you are not allowed to deactivate it.
+
+  [% ELSIF error == &quot;flag_type_cannot_delete&quot; %]
+    [% title = &quot;Flag Type Deletion Not Allowed&quot; %]
+    Sorry, but the flag type '[% flagtype.name FILTER html %]' also applies to some
+    products you cannot see, and so you are not allowed to delete it.
+
</ins><span class="cx">   [% ELSIF error == &quot;flag_type_cc_list_invalid&quot; %]
</span><span class="cx">     [% title = &quot;Flag Type CC List Invalid&quot; %]
</span><span class="cx">     [% admindocslinks = {'flags-overview.html#flags-admin'  =&gt; 'Administering Flags'} %]
</span><span class="lines">@@ -570,7 +686,7 @@
</span><span class="cx">   [% ELSIF error == &quot;flag_type_description_invalid&quot; %]
</span><span class="cx">     [% title = &quot;Flag Type Description Invalid&quot; %]
</span><span class="cx">     [% admindocslinks = {'flags-overview.html#flags-admin'  =&gt; 'Administering Flags'} %]
</span><del>-    The description must be less than 32K.
</del><ins>+    You must enter a description for this flag type.
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;flag_type_name_invalid&quot; %]
</span><span class="cx">     [% title = &quot;Flag Type Name Invalid&quot; %]
</span><span class="lines">@@ -578,6 +694,17 @@
</span><span class="cx">     The name &lt;em&gt;[% name FILTER html %]&lt;/em&gt; must be 1-50 characters long
</span><span class="cx">     and must not contain any spaces or commas.
</span><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;flag_type_not_editable&quot; %]
+    [% title = &quot;Flag Type Not Editable&quot; %]
+    You are not allowed to edit properties of the '[% flagtype.name FILTER html %]'
+    flag type, because this flag type is not available for the products you can administer.
+
+  [% ELSIF error == &quot;flag_type_not_multiplicable&quot; %]
+    [% docslinks = {'flags-overview.html' =&gt; 'An overview on Flags',
+                    'flags.html' =&gt; 'Using Flags'} %]
+    You cannot have several &lt;em&gt;[% type.name FILTER html %]&lt;/em&gt; flags
+    for this [% IF attachment %] attachment [% ELSE %] [%+ terms.bug %] [% END %].
+
</ins><span class="cx">   [% ELSIF error == &quot;flag_update_denied&quot; %]
</span><span class="cx">     [% title = &quot;Flag Modification Denied&quot; %]
</span><span class="cx">     [% admindocslinks = {'flags-overview.html#flags-admin'  =&gt; 'Administering Flags',
</span><span class="lines">@@ -598,30 +725,25 @@
</span><span class="cx">     
</span><span class="cx">   [% ELSIF error == &quot;flag_type_sortkey_invalid&quot; %]
</span><span class="cx">     [% title = &quot;Flag Type Sort Key Invalid&quot; %]
</span><del>-    The sort key must be an integer between 0 and 32767 inclusive.
-    It cannot be &lt;em&gt;[% sortkey FILTER html %]&lt;/em&gt;.
</del><ins>+    The sort key &lt;em&gt;[% sortkey FILTER html %]&lt;/em&gt; must be an integer
+    between 0 and [% constants.MAX_SMALLINT FILTER none %].
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;freetext_too_long&quot; %]
</span><span class="cx">     [% title = &quot;Text Too Long&quot; %]
</span><del>-    The text you entered is too long ([% text.length FILTER html %] characters,
-    above the maximum length allowed of [% constants.MAX_FREETEXT_LENGTH FILTER none %]
-    characters):
-    &lt;p&gt;&lt;em&gt;[% text FILTER html %]&lt;/em&gt;&lt;/p&gt;
</del><ins>+    The text you entered in the [% field_descs.$field FILTER html %]
+    field is too long ([% text.length FILTER html %] characters,
+    above the maximum length allowed of
+    [%+ constants.MAX_FREETEXT_LENGTH FILTER none %] characters).
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;group_cannot_delete&quot; %]
</span><span class="cx">     [% title = &quot;Cannot Delete Group&quot; %]
</span><del>-    The &lt;em&gt;[% name FILTER html %]&lt;/em&gt; group cannot be deleted because
</del><ins>+    The &lt;em&gt;[% group.name FILTER html %]&lt;/em&gt; group cannot be deleted because
</ins><span class="cx">     there are
</span><del>-    &lt;a href=&quot;editgroups.cgi?action=del&amp;amp;group=[% gid FILTER url_quote %]&quot;&gt;records&lt;/a&gt;
</del><ins>+    &lt;a href=&quot;editgroups.cgi?action=del&amp;amp;group=
+             [%- group.id FILTER uri %]&quot;&gt;records&lt;/a&gt;
</ins><span class="cx">     in the database which refer to it. All references to this group must
</span><span class="cx">     be removed before you can remove it.
</span><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;group_change_denied&quot; %]
-    [% title = &quot;Cannot Add/Remove That Group&quot; %]
-    You tried to add or remove group id [% group_id FILTER html %]
-    from [% terms.bug %] [%+ bug.id FILTER html %], but you do not
-    have permissions to do so.
-
</del><span class="cx">   [% ELSIF error == &quot;group_exists&quot; %]
</span><span class="cx">     [% title = &quot;The group already exists&quot; %]
</span><span class="cx">     The group [% name FILTER html %] already exists.
</span><span class="lines">@@ -642,36 +764,32 @@
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;group_invalid_removal&quot; %]
</span><del>-    You tried to remove [% terms.bug %] [%+ bug.id FILTER html %]
-    from group id [% group_id FILTER html %], but [% terms.bugs %] in the 
-    '[% product FILTER html %]' product can not be removed from that
-    group.
-    
-  [% ELSIF error == &quot;group_invalid_restriction&quot; %]
-    You tried to restrict [% terms.bug %] [%+ bug.id FILTER html %] to
-    to group id [% group_id FILTER html %], but [% terms.bugs %] in the
-    '[% product FILTER html %]' product can not be restricted to
-    that group.
</del><ins>+    You tried to remove [% terms.bug %] [%+ bug_id FILTER html %]
+    from the '[% name FILTER html %]' group, but either this group does not exist,
+    or you are not allowed to remove [% terms.bugs %] from this group in the
+    '[% product FILTER html %]' product.
</ins><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;group_restriction_not_allowed&quot; %]
+    [% title = &quot;Group Restriction Not Allowed&quot; %]
+    You tried to restrict [% bug_id ? &quot;$terms.bug $bug_id&quot; : terms.abug FILTER html %]
+    to the '[% name FILTER html %]' group, but either this group does not exist,
+    or you are not allowed to restrict [% terms.bugs %] to this group in the
+    '[% product FILTER html %]' product.
+
</ins><span class="cx">   [% ELSIF error == &quot;group_not_specified&quot; %]
</span><span class="cx">     [% title = &quot;Group not specified&quot; %]
</span><span class="cx">     No group was specified.
</span><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;group_not_visible&quot; %]
+    [% title = &quot;Group Not Allowed&quot; %]
+    You are not allowed to see members of the [% group.name FILTER html %]
+    group.
+
</ins><span class="cx">   [% ELSIF error == &quot;system_group_not_deletable&quot; %]
</span><span class="cx">     [% title = &quot;System Groups not deletable&quot; %]
</span><span class="cx">     &lt;em&gt;[% name FILTER html %]&lt;/em&gt; is a system group.
</span><span class="cx">     This group cannot be deleted.
</span><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;group_unknown&quot; %]
-    [% title = &quot;Unknown Group&quot; %]
-    The group [% name FILTER html %] does not exist. Please specify
-    a valid group name. Create it first if necessary!
-
-  [% ELSIF error == &quot;illegal_at_least_x_votes&quot; %]
-    [% title = &quot;Your Search Makes No Sense&quot; %]
-    The &lt;em&gt;At least ___ votes&lt;/em&gt; field must be a simple number. 
-    You entered &lt;tt&gt;[% value FILTER html %]&lt;/tt&gt;, which isn't.
-    
</del><span class="cx">   [% ELSIF error == &quot;illegal_attachment_edit&quot; %]
</span><span class="cx">     [% title = &quot;Unauthorized Action&quot; %]
</span><span class="cx">     You are not authorized to edit attachment [% attach_id FILTER html %].
</span><span class="lines">@@ -681,11 +799,6 @@
</span><span class="cx">     You are not authorized to edit attachments on [% terms.bug %] 
</span><span class="cx">     [%+ bug_id FILTER html %].
</span><span class="cx">          
</span><del>-  [% ELSIF error == &quot;illegal_attachment_is_patch&quot; %]
-    [% title = &quot;Your Search Makes No Sense&quot; %]
-    The only legal values for the &lt;em&gt;Attachment is patch&lt;/em&gt; field are
-    0 and 1.
-
</del><span class="cx">   [% ELSIF error == &quot;illegal_bug_status_transition&quot; %]
</span><span class="cx">     [% title = &quot;Illegal $terms.Bug Status Change&quot; %]
</span><span class="cx">     [% IF old.defined %]
</span><span class="lines">@@ -707,9 +820,9 @@
</span><span class="cx">       to &lt;em&gt;[% newvalue.join(', ') FILTER html %]&lt;/em&gt;
</span><span class="cx">     [% END %]
</span><span class="cx">     , but only
</span><del>-    [% IF privs &lt; 3 %]
</del><ins>+    [% IF privs &lt; constants.PRIVILEGES_REQUIRED_EMPOWERED %]
</ins><span class="cx">       the assignee
</span><del>-      [% IF privs &lt; 2 %] or reporter [% END %]
</del><ins>+      [% IF privs &lt; constants.PRIVILEGES_REQUIRED_ASSIGNEE %] or reporter [% END %]
</ins><span class="cx">       of the [% terms.bug %], or
</span><span class="cx">     [% END %]
</span><span class="cx">     a user with the required permissions may change that field.
</span><span class="lines">@@ -721,11 +834,6 @@
</span><span class="cx">     but only a user allowed to edit 
</span><span class="cx">     both related [% terms.bugs %] may change that field.
</span><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;illegal_changed_in_last_x_days&quot; %]
-    [% title = &quot;Your Search Makes No Sense&quot; %]
-    The &lt;em&gt;Changed in last ___ days&lt;/em&gt; field must be a simple number. 
-    You entered &lt;tt&gt;[% value FILTER html %]&lt;/tt&gt;, which isn't.
-    
</del><span class="cx">   [% ELSIF error == &quot;illegal_date&quot; %]
</span><span class="cx">     [% title = &quot;Illegal Date&quot; %]
</span><span class="cx">     '&lt;tt&gt;[% date FILTER html %]&lt;/tt&gt;' is not a legal date.
</span><span class="lines">@@ -741,11 +849,10 @@
</span><span class="cx">       A legal address must contain exactly one '@',
</span><span class="cx">       and at least one '.' after the @.
</span><span class="cx">     [% ELSE %]
</span><del>-      [%+ Param('emailregexpdesc') %]
</del><ins>+      [%+ Param('emailregexpdesc') FILTER html_light %]
</ins><span class="cx">     [% END %]
</span><del>-    It must also not contain any of these special characters:
-    &lt;tt&gt;\ ( ) &amp;amp; &amp;lt; &amp;gt; , ; : &amp;quot; [ ]&lt;/tt&gt;, or any whitespace.
-    
</del><ins>+    It also must not contain any illegal characters.
+
</ins><span class="cx">   [% ELSIF error == &quot;illegal_frequency&quot; %]
</span><span class="cx">     [% title = &quot;Too Frequent&quot; %]
</span><span class="cx">     Unless you are an administrator, you may not create series which are 
</span><span class="lines">@@ -757,11 +864,6 @@
</span><span class="cx">     Your group control combination for group &amp;quot;
</span><span class="cx">     [% groupname FILTER html %]&amp;quot; is illegal.
</span><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;illegal_is_obsolete&quot; %]
-    [% title = &quot;Your Search Makes No Sense&quot; %]
-    The only legal values for the &lt;em&gt;Attachment is obsolete&lt;/em&gt; field are
-    0 and 1.
-
</del><span class="cx">   [% ELSIF error == &quot;illegal_query_name&quot; %]
</span><span class="cx">     [% title = &quot;Illegal Search Name&quot; %]
</span><span class="cx">     The name of your search cannot contain any of the following characters: 
</span><span class="lines">@@ -784,6 +886,11 @@
</span><span class="cx">     [% IF format %]
</span><span class="cx">       Please use the format '&lt;tt&gt;[% format FILTER html %]&lt;/tt&gt;'.
</span><span class="cx">     [% END %]
</span><ins>+
+  [% ELSIF error == &quot;illegal_regexp&quot; %]
+    [% title = &quot;Illegal Regular Expression&quot; %]
+    The regular expression you provided [% value FILTER html %] is not valid.
+    The error was: [% dberror FILTER html %].
</ins><span class="cx">         
</span><span class="cx">   [% ELSIF error == &quot;insufficient_data_points&quot; %]
</span><span class="cx">     [% docslinks = {'reporting.html' =&gt; 'Reporting'} %]
</span><span class="lines">@@ -823,9 +930,9 @@
</span><span class="cx">     [% title = &quot;Invalid Content-Type&quot; %]
</span><span class="cx">     The content type &lt;em&gt;[% contenttype FILTER html %]&lt;/em&gt; is invalid.
</span><span class="cx">     Valid types must be of the form &lt;em&gt;foo/bar&lt;/em&gt; where &lt;em&gt;foo&lt;/em&gt;
</span><del>-    is either &lt;em&gt;application, audio, image, message, model, multipart,
-    text,&lt;/em&gt; or &lt;em&gt;video&lt;/em&gt;.
-    
</del><ins>+    is one of &lt;em&gt;[% constants.LEGAL_CONTENT_TYPES.join(', ') FILTER html %]&lt;/em&gt;
+    and &lt;em&gt;bar&lt;/em&gt; must not contain any special characters (such as &quot;=&quot;, &quot;?&quot;, ...).
+
</ins><span class="cx">   [% ELSIF error == &quot;invalid_context&quot; %]
</span><span class="cx">     [% title = &quot;Invalid Context&quot; %]
</span><span class="cx">     The context [% context FILTER html %] is invalid (must be a number,
</span><span class="lines">@@ -833,7 +940,7 @@
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;invalid_datasets&quot; %]
</span><span class="cx">     [% title = &quot;Invalid Datasets&quot; %]
</span><del>-    Invalid datasets &lt;em&gt;[% datasets FILTER html %]&lt;/em&gt;. Only digits,
</del><ins>+    Invalid datasets &lt;em&gt;[% datasets.join(&quot;:&quot;) FILTER html %]&lt;/em&gt;. Only digits,
</ins><span class="cx">     letters and colons are allowed.
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;invalid_format&quot; %]
</span><span class="lines">@@ -896,7 +1003,40 @@
</span><span class="cx">   [% ELSIF error == &quot;invalid_username_or_password&quot; %]
</span><span class="cx">     [% title = &quot;Invalid Username Or Password&quot; %]
</span><span class="cx">     The username or password you entered is not valid.
</span><ins>+    [%# People get two login attempts before being warned about
+      # being locked out.
+      #%]
+    [% IF remaining &lt;=  2 %]
+      If you do not enter the correct password after 
+      [%+ remaining FILTER html %] more attempt(s), you will be
+      locked out of this account for 
+      [%+ constants.LOGIN_LOCKOUT_INTERVAL FILTER html %] minutes.
+    [% END %]
</ins><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;json_rpc_get_method_required&quot; %]
+    When using JSON-RPC over GET, you must specify a 'method'
+    parameter. See the documentation at
+    [%+ docs_urlbase FILTER html %]api/Bugzilla/WebService/Server/JSONRPC.html
+
+  [% ELSIF error == &quot;json_rpc_illegal_content_type&quot; %]
+    When using JSON-RPC over POST, you cannot send data as
+    [%+ content_type FILTER html %]. Only application/json and
+    application/json-rpc are allowed.
+
+  [% ELSIF error == &quot;json_rpc_invalid_params&quot; %]
+    Could not parse the 'params' argument as valid JSON.
+    Error: [% err_msg FILTER html %]
+    Value: [% params FILTER html %]
+
+  [% ELSIF error == &quot;json_rpc_invalid_callback&quot; %]
+    You cannot use '[% callback FILTER html %]' as your 'callback' parameter.
+    For security reasons, only letters, numbers, and the following
+    characters are allowed in the 'callback' parameter: &lt;code&gt;[]._&lt;/code&gt;
+
+  [% ELSIF error == &quot;json_rpc_post_only&quot; %]
+    For security reasons, you must use HTTP POST to call the
+    '[% method FILTER html %]' method.
+
</ins><span class="cx">   [% ELSIF error == &quot;keyword_already_exists&quot; %]
</span><span class="cx">     [% title = &quot;Keyword Already Exists&quot; %]
</span><span class="cx">     A keyword with the name [% name FILTER html %] already exists.
</span><span class="lines">@@ -913,11 +1053,6 @@
</span><span class="cx">     [% title = &quot;Invalid Keyword Name&quot; %]
</span><span class="cx">     You may not use commas or whitespace in a keyword name.
</span><span class="cx">      
</span><del>-  [% ELSIF error == &quot;local_file_too_large&quot; %]
-    [% title = &quot;Local File Too Large&quot; %]
-    Local file uploads must not exceed 
-    [% Param('maxlocalattachment') %] MB in size.
-
</del><span class="cx">   [% ELSIF error == &quot;login_needed_for_password_change&quot; %]
</span><span class="cx">     [% title = &quot;Login Name Required&quot; %]
</span><span class="cx">     You must enter a login name when requesting to change your password.
</span><span class="lines">@@ -927,6 +1062,19 @@
</span><span class="cx">     You can't use %user% without being logged in, because %user% refers
</span><span class="cx">     to your login name, which we don't know.
</span><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;login_required&quot; %]
+    [%# Used for non-web-based LOGIN_REQUIRED situations. %]
+    You must log in before using this part of [% terms.Bugzilla %].
+
+  [% ELSIF error == &quot;migrate_config_created&quot; %]
+    The file &lt;kbd&gt;[% file FILTER html %]&lt;/kbd&gt; contains configuration
+    variables that must be set before continuing with the migration.
+
+  [% ELSIF error == &quot;migrate_from_invalid&quot; %]
+    '[% from FILTER html %]' is not a valid type of [% terms.bug %]-tracker
+    to migrate from. See the contents of the &lt;kbd&gt;B[% %]ugzilla/Migrate/&lt;/kbd&gt;
+    directory for a list of valid [% terms.bug %]-trackers.
+
</ins><span class="cx">   [% ELSIF error == &quot;milestone_already_exists&quot; %]
</span><span class="cx">     [% title = &quot;Milestone Already Exists&quot; %]
</span><span class="cx">     [% admindocslinks = {'products.html' =&gt; 'Administering products',
</span><span class="lines">@@ -948,8 +1096,8 @@
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;milestone_name_too_long&quot; %]
</span><span class="cx">     [% title = &quot;Milestone Name Is Too Long&quot; %]
</span><del>-    The name of a milestone is limited to 20 characters. 
-    '[% name FILTER html %]' is too long ([% name.length %] characters).
</del><ins>+    The name of a milestone is limited to [% constants.MAX_MILESTONE_SIZE FILTER html %]
+    characters. '[% name FILTER html %]' is too long ([% name.length %] characters).
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;milestone_required&quot; %]
</span><span class="cx">     [% title = &quot;Milestone Required&quot; %]
</span><span class="lines">@@ -982,10 +1130,10 @@
</span><span class="cx">     [% admindocslinks = {'products.html'   =&gt; 'Administering products',
</span><span class="cx">                          'components.html' =&gt; 'Creating a component'} %]
</span><span class="cx">     Sorry, the product &lt;em&gt;[% product.name FILTER html %]&lt;/em&gt;
</span><del>-    has to have at least one component in order for you to
</del><ins>+    has to have at least one active component in order for you to
</ins><span class="cx">     enter [% terms.abug %] into it.&lt;br&gt;
</span><span class="cx">     [% IF user.in_group(&quot;editcomponents&quot;, product.id) %]
</span><del>-      &lt;a href=&quot;editcomponents.cgi?action=add&amp;amp;product=[% product.name FILTER url_quote %]&quot;&gt;Create
</del><ins>+      &lt;a href=&quot;editcomponents.cgi?action=add&amp;amp;product=[% product.name FILTER uri %]&quot;&gt;Create
</ins><span class="cx">       a new component&lt;/a&gt;.
</span><span class="cx">     [% ELSE %]
</span><span class="cx">       Please contact [% Param(&quot;maintainer&quot;) %] and ask them
</span><span class="lines">@@ -1015,11 +1163,6 @@
</span><span class="cx">     [% docslinks = {'reporting.html' =&gt; 'Reporting'} %]
</span><span class="cx">     You must specify one or more datasets to plot.
</span><span class="cx">     
</span><del>-  [% ELSIF error == &quot;missing_email_type&quot; %]
-    [% title = &quot;Your Search Makes No Sense&quot; %]
-    You must specify one or more fields in which to search for
-    &lt;tt&gt;[% email FILTER html %]&lt;/tt&gt;.
-    
</del><span class="cx">   [% ELSIF error == &quot;missing_frequency&quot; %]
</span><span class="cx">     [% title = &quot;Missing Frequency&quot; %]
</span><span class="cx">     [% docslinks = {'reporting.html' =&gt; 'Reporting'} %]
</span><span class="lines">@@ -1046,11 +1189,6 @@
</span><span class="cx">     A valid resolution is required to mark [% terms.bugs %] as
</span><span class="cx">     [%+ status FILTER upper FILTER html %].
</span><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;move_bugs_disabled&quot; %]
-    [% title = BLOCK %][% terms.Bug %] Moving Disabled[% END %]
-    Sorry, [% terms.bug %] moving has been disabled. If you need
-    to move [% terms.abug %], please contact [% Param(&quot;maintainer&quot;) %].
-
</del><span class="cx">   [% ELSIF error == &quot;missing_subcategory&quot; %]
</span><span class="cx">     [% title = &quot;Missing Subcategory&quot; %]
</span><span class="cx">     You did not specify a subcategory for this series.
</span><span class="lines">@@ -1059,16 +1197,20 @@
</span><span class="cx">     [% title = &quot;Missing Version&quot; %]
</span><span class="cx">     [% admindocslinks = {'versions.html' =&gt; 'Defining versions'} %]
</span><span class="cx">     Sorry, the product &lt;em&gt;[% product.name FILTER html %]&lt;/em&gt;
</span><del>-    has to have at least one version in order for you to
</del><ins>+    has to have at least one active version in order for you to
</ins><span class="cx">     enter [% terms.abug %] into it.&lt;br&gt;
</span><span class="cx">     [% IF user.in_group(&quot;editcomponents&quot;, product.id) %]
</span><del>-      &lt;a href=&quot;editversions.cgi?action=add&amp;amp;product=[% product.name FILTER url_quote %]&quot;&gt;Create
</del><ins>+      &lt;a href=&quot;editversions.cgi?action=add&amp;amp;product=[% product.name FILTER uri %]&quot;&gt;Create
</ins><span class="cx">       a new version&lt;/a&gt;.
</span><span class="cx">     [% ELSE %]
</span><span class="cx">       Please contact [% Param(&quot;maintainer&quot;) %] and ask them
</span><span class="cx">       to add a version to this product.
</span><span class="cx">     [% END %]
</span><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;multiple_alias_not_allowed&quot; %]
+    You cannot set aliases when modifying multiple [% terms.bugs %]
+    at once.
+
</ins><span class="cx">   [% ELSIF error == &quot;need_quip&quot; %]
</span><span class="cx">     [% title = &quot;Quip Required&quot; %]
</span><span class="cx">     [% docslinks = {'quips.html' =&gt; 'About quips'} %]
</span><span class="lines">@@ -1092,48 +1234,10 @@
</span><span class="cx">       to view.
</span><span class="cx">     [% END %]
</span><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;no_bug_ids&quot; %]
-    [% title = BLOCK %]No [% terms.Bugs %] Selected[% END %]
-    You didn't choose any [% terms.bugs %] to
-    [% IF action == &quot;add&quot; %] add to [% ELSE %] remove from [% END %]
-    the [% tag FILTER html %] tag.
-
-  [% ELSIF error == &quot;no_bugs_in_list&quot; %]
-    [% title = &quot;Delete Tag?&quot; %]
-    This will remove all [% terms.bugs %] from the
-    [% tag FILTER html %] tag. This will delete the tag completely. Click
-    &lt;a href=&quot;buglist.cgi?cmdtype=dorem&amp;amp;remaction=forget&amp;amp;namedcmd=
-    [%- tag FILTER url_quote %]&quot;&gt;here&lt;/a&gt; if you really want to delete it.
-
-  [% ELSIF error == &quot;no_bugs_to_remove&quot; %]
</del><ins>+  [% ELSIF error == &quot;no_tag_to_edit&quot; %]
</ins><span class="cx">     [% title = &quot;No Tag Selected&quot; %]
</span><del>-    You didn't select a tag from which to remove [% terms.bugs %].
</del><ins>+    You tried to create or remove a tag with no name.
</ins><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;no_dupe_stats&quot; %]
-    [% title = &quot;Cannot Find Duplicate Statistics&quot; %]
-    [% admindocslinks = {'extraconfig.html' =&gt; 'Setting up the collecstats.pl job'} %]
-    There are no duplicate statistics for today ([% today FILTER html %]) 
-    or yesterday.
-
-  [% ELSIF error == &quot;no_dupe_stats_error_today&quot; %]
-    [% title = &quot;Error Reading Today's Dupes File&quot; %]
-    [% admindocslinks = {'extraconfig.html' =&gt; 'Setting up the collecstats.pl job'} %]
-    An error occurred opening today's dupes file: [% error_msg FILTER html %].
-
-  [% ELSIF error == &quot;no_dupe_stats_error_whenever&quot; %]
-    [% title = &quot;Error Reading Previous Dupes File&quot; %]
-    [% admindocslinks = {'extraconfig.html' =&gt; 'Setting up the collecstats.pl job'} %]
-    An error occurred opening [% changedsince FILTER html %] days ago
-    ([% whenever FILTER html %])'s dupes file:
-    [% error_msg FILTER html %].
-
-  [% ELSIF error == &quot;no_dupe_stats_error_yesterday&quot; %]
-    [% title = &quot;Error Reading Yesterday's Dupes File&quot; %]
-    [% admindocslinks = {'extraconfig.html' =&gt; 'Setting up the collecstats.pl job'} %]
-    There are no duplicate statistics for today ([% today FILTER html %]), 
-    and an error
-    occurred opening yesterday's dupes file: [% error_msg FILTER html %].
-
</del><span class="cx">   [% ELSIF error == &quot;no_initial_bug_status&quot; %]
</span><span class="cx">     [% title = &quot;No Initial $terms.Bug Status&quot; %]
</span><span class="cx">     No [% terms.bug %] status is available on [% terms.bug %] creation.
</span><span class="lines">@@ -1156,10 +1260,6 @@
</span><span class="cx">     Either no products have been defined to enter [% terms.bugs %] against or you have not
</span><span class="cx">     been given access to any.
</span><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;no_valid_action&quot; %]
-    [% title = &quot;No valid action specified&quot; %]
-    Cannot edit [% field_descs.$field FILTER html %]: no valid action was specified.
-
</del><span class="cx">   [% ELSIF error == &quot;number_not_numeric&quot; %]
</span><span class="cx">     [% title = &quot;Numeric Value Required&quot; %]
</span><span class="cx">     The value '[% num FILTER html %]' in the 
</span><span class="lines">@@ -1178,22 +1278,30 @@
</span><span class="cx">     in the &lt;em&gt;[% field_descs.$field FILTER html %]&lt;/em&gt; field 
</span><span class="cx">     is less than the minimum allowable value of '[% min_num FILTER html %]'.
</span><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;object_name_not_specified&quot; %]
-    [% type = BLOCK %][% PROCESS object_name %][% END %]
</del><ins>+  [% ELSIF error == &quot;object_not_specified&quot; %]
+    [% type = BLOCK %][% INCLUDE object_name class = class %][% END %]
</ins><span class="cx">     [% title = BLOCK %][% type FILTER ucfirst FILTER html %] Not 
</span><span class="cx">     Specified[% END %]
</span><span class="cx">     You must select/enter a [% type FILTER html %].
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;object_does_not_exist&quot; %]
</span><del>-    [% type = BLOCK %][% PROCESS object_name %][% END %]
</del><ins>+    [% type = BLOCK %][% INCLUDE object_name class = class %][% END %]
</ins><span class="cx">     [% title = BLOCK %]Invalid [% type FILTER ucfirst FILTER html %][% END %]
</span><del>-    There is no [% type FILTER html %] named '[% name FILTER html %]'
</del><ins>+    There is no [% type FILTER html %] 
+    [% IF id.defined %]
+      with the id '[% id FILTER html %]'
+    [% ELSE %]
+      named '[% name FILTER html %]'
+    [% END %]
</ins><span class="cx">     [% IF product.defined %]
</span><span class="cx">       in the '[% product.name FILTER html %]' product
</span><span class="cx">     [% END %].
</span><span class="cx">     [% IF class == &quot;Bugzilla::User&quot; %]
</span><span class="cx">       Either you mis-typed the name or that user has not yet registered
</span><span class="cx">       for a [% terms.Bugzilla %] account.
</span><ins>+    [% ELSIF class == &quot;Bugzilla::Keyword&quot; %]
+      The legal keyword names are &lt;a href=&quot;describekeywords.cgi&quot;&gt;listed
+      here&lt;/a&gt;.
</ins><span class="cx">     [% END %]
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;old_password_incorrect&quot; %]
</span><span class="lines">@@ -1212,67 +1320,55 @@
</span><span class="cx">     [% title = &quot;Passwords Don't Match&quot; %]
</span><span class="cx">     The two passwords you entered did not match.
</span><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;password_too_long&quot; %]
-    [% title = &quot;Password Too Long&quot; %]
-    The password must be no more than
-    [%+ constants.USER_PASSWORD_MAX_LENGTH FILTER html %] characters long.
</del><ins>+  [% ELSIF error == &quot;password_current_too_short&quot; %]
+    [% title = &quot;New Password Required&quot; %]
+    Your password is currently less than
+    [%+ constants.USER_PASSWORD_MIN_LENGTH FILTER html %] characters long,
+    which is the new minimum length required for passwords.
+    You must &lt;a href=&quot;token.cgi?a=reqpw&amp;amp;loginname=[% locked_user.email FILTER uri %]&quot;&gt;
+    request a new password&lt;/a&gt; in order to log in again.
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;password_too_short&quot; %]
</span><span class="cx">     [% title = &quot;Password Too Short&quot; %]
</span><span class="cx">     The password must be at least
</span><span class="cx">     [%+ constants.USER_PASSWORD_MIN_LENGTH FILTER html %] characters long.
</span><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;patch_too_large&quot; %]
-    [% title = &quot;File Too Large&quot; %]
-    The file you are trying to attach is [% filesize FILTER html %] 
-    kilobytes (KB) in size.
-    Patches cannot be more than [% Param('maxpatchsize') %] KB in size.
-    Try breaking your patch into several pieces.
</del><ins>+  [% ELSIF error == &quot;password_not_complex&quot; %]
+     [% title = &quot;Password Fails Requirements&quot; %]
+     [% passregex = Param('password_complexity') %]
+     The password must contain at least one:
+     &lt;ul&gt;
+       [% IF passregex.search('letters') %]
+         &lt;li&gt;UPPERCASE letter&lt;/li&gt;
+         &lt;li&gt;lowercase letter&lt;/li&gt;
+       [% END %]
+       [% IF passregex.search('numbers') %]
+         &lt;li&gt;digit&lt;/li&gt;
+       [% END %]
+       [% IF passregex.search('specialchars') %]
+         &lt;li&gt;special character&lt;/li&gt;
+       [% END %]
+     &lt;/ul&gt;
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;product_access_denied&quot; %]
</span><del>-    Either the product '[% product FILTER html %]' does not exist or
-    you don't have access to it.
</del><ins>+    [% title = &quot;Product Access Denied&quot; %]
+    Either the product 
+    [%+ IF id.defined %]
+      with the id [% id FILTER html %]
+    [% ELSE %]
+      '[% name FILTER html %]'
+    [% END %]
+    does not exist or you don't have access to it.
</ins><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;product_doesnt_exist&quot; %]
-    [% title = &quot;Specified Product Does Not Exist&quot; %]
-    The product '[% product FILTER html %]' does not exist.
</del><ins>+  [% ELSIF error == &quot;product_illegal_group&quot; %]
+    [% title = &quot;Illegal Group&quot; %]
+    [% group.name FILTER html %] is not an active [% terms.bug %] group
+    and so you cannot edit group controls for it.
</ins><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;product_votes_per_bug_must_be_nonnegative&quot; %]
-    [% title = &quot;Maximum Votes Must Be Non-negative&quot; %]
-    [% admindocslinks = {'voting.html' =&gt; 'Setting up the voting feature'} %]
-    '[% maxvotesperbug FILTER html %]' is an invalid value for the 
-    &lt;em&gt;'Maximum Votes Per [% terms.Bug %]'&lt;/em&gt; field, which should
-    contain a non-negative number.
-
-  [% ELSIF error == &quot;product_votes_per_user_must_be_nonnegative&quot; %]
-    [% title = &quot;Votes Per User Must Be Non-negative&quot; %]
-    [% admindocslinks = {'voting.html' =&gt; 'Setting up the voting feature'} %]
-    '[% votesperuser FILTER html %]' is an invalid value for the 
-    &lt;em&gt;'Votes Per User'&lt;/em&gt; field, which should contain a
-    non-negative number.
-
-  [% ELSIF error == &quot;product_votes_to_confirm_must_be_nonnegative&quot; %]
-    [% title = &quot;Votes To Confirm Must Be Non-negative&quot; %]
-    [% admindocslinks = {'voting.html' =&gt; 'Setting up the voting feature'} %]
-    '[% votestoconfirm FILTER html %]' is an invalid value for the 
-    &lt;em&gt;'Votes To Confirm'&lt;/em&gt; field, which should contain a
-    non-negative number.
-
-  [% ELSIF error == &quot;product_cant_delete_description&quot; %]
-    [% title = &quot;Cannot delete product description&quot; %]
-    [% admindocslinks = {'products.html' =&gt; 'Administering products'} %]
-    Cannot delete the description for product
-    '[% product FILTER html %]'.
-
-  [% ELSIF error == &quot;product_cant_delete_name&quot; %]
-    [% title = &quot;Cannot delete product name&quot; %]
-    [% admindocslinks = {'products.html' =&gt; 'Administering products'} %]
-    Cannot delete the product name for product '[% product FILTER html %]'.
-
</del><span class="cx">   [% ELSIF error == &quot;product_name_already_in_use&quot; %]
</span><del>-    [% title = &quot;Product name already in use&quot; %]
</del><ins>+    [% title = &quot;Product name already exists&quot; %]
</ins><span class="cx">     [% admindocslinks = {'products.html' =&gt; 'Administering products'} %]
</span><del>-    The product name '[% product FILTER html %]' is already in use.
</del><ins>+    The product name '[% product FILTER html %]' already exists.
</ins><span class="cx">   
</span><span class="cx">   [% ELSIF error == &quot;product_name_diff_in_case&quot; %]
</span><span class="cx">     [% title = &quot;Product name differs only in case&quot; %]
</span><span class="lines">@@ -1280,19 +1376,17 @@
</span><span class="cx">     The product name '[% product FILTER html %]' differs from existing 
</span><span class="cx">     product '[% existing_product FILTER html %]' only in case.
</span><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;product_name_too_long&quot; %]
+    [% title = &quot;Product name too long&quot; %]
+    The name of a product is limited to [% constants.MAX_PRODUCT_SIZE FILTER html %]
+    characters. '[% name FILTER html %]' is too long ([% name.length %] characters).
+
</ins><span class="cx">   [% ELSIF error == &quot;product_must_define_defaultmilestone&quot; %]
</span><span class="cx">     [% title = &quot;Must define new default milestone&quot; %]
</span><span class="cx">     [% admindocslinks = {'products.html' =&gt; 'Administering products',
</span><span class="cx">                          'milestones.html' =&gt; 'About Milestones'} %]
</span><del>-    [% IF classification %]
-      [% classification_url_part = BLOCK %]&amp;amp;classification=
-        [%- classification FILTER url_quote %]
-      [% END %]
-    [% END %]
-    You must &lt;a href=&quot;editmilestones.cgi?action=add&amp;amp;product=
-    [%- product FILTER url_quote %]
-    [%- classification_url_part FILTER none %]&quot;&gt;
-    create the milestone '[% defaultmilestone FILTER html %]'&lt;/a&gt; before
</del><ins>+    You must &lt;a href=&quot;editmilestones.cgi?action=add&amp;amp;product=[% product FILTER uri %]&quot;&gt;
+    create the milestone '[% milestone FILTER html %]'&lt;/a&gt; before
</ins><span class="cx">     it can be made the default milestone for product '[% product FILTER html %]'.
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;product_admin_denied&quot; %]
</span><span class="lines">@@ -1302,7 +1396,7 @@
</span><span class="cx">   [% ELSIF error == &quot;product_blank_name&quot; %]
</span><span class="cx">     [% title = &quot;Blank Product Name Not Allowed&quot; %]
</span><span class="cx">     [% admindocslinks = {'products.html' =&gt; 'Administering products'} %]
</span><del>-    You must enter a name for the new product.
</del><ins>+    You must enter a name for the product.
</ins><span class="cx">   
</span><span class="cx">   [% ELSIF error == &quot;product_disabled&quot; %]
</span><span class="cx">     [% title = BLOCK %]Product closed for [% terms.Bug %] Entry[% END %]
</span><span class="lines">@@ -1327,32 +1421,23 @@
</span><span class="cx">   [% ELSIF error == &quot;product_must_have_description&quot; %]
</span><span class="cx">     [% title = &quot;Product needs Description&quot; %]
</span><span class="cx">     [% admindocslinks = {'products.html' =&gt; 'Administering products'} %]
</span><del>-    You must enter a description for product '[% product FILTER html %]'.
</del><ins>+    You must enter a description for this product.
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;product_must_have_version&quot; %]
</span><span class="cx">     [% title = &quot;Product needs Version&quot; %]
</span><span class="cx">     [% admindocslinks = {'products.html' =&gt; 'Administering products',
</span><span class="cx">                          'versions.html' =&gt; 'Administering versions'} %]
</span><del>-    You must enter a version for product '[% product FILTER html %]'.
</del><ins>+    You must enter a valid version to create a new product.
</ins><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;product_not_specified&quot; %]
-    [% title = &quot;No Product Specified&quot; %]
-    [% admindocslinks = {'products.html'   =&gt; 'Administering products',
-                         'components.html' =&gt; 'Administering components',
-                         'milestones.html' =&gt; 'Administering milestones',
-                         'versions.html'   =&gt; 'Administering versions'} %]
-    No product specified when trying to edit components, milestones, versions
-    or product.
</del><ins>+  [% ELSIF error == &quot;product_unknown_component&quot; %]
+    [% title = &quot;Unknown Component&quot; %]
+    Product '[% product FILTER html %]' has no component
+    [% IF comp_id %]
+      with ID [% comp_id FILTER html %].
+    [% ELSE %]
+      named '[% comp FILTER html %]'.
+    [% END %]
</ins><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;query_name_exists&quot; %]
-    [% title = &quot;Search Name Already In Use&quot; %]
-    The name &lt;em&gt;[% name FILTER html %]&lt;/em&gt; is already used by another
-    saved search. You first have to
-    &lt;a href=&quot;buglist.cgi?cmdtype=dorem&amp;amp;remaction=forget&amp;amp;namedcmd=
-    [%- name FILTER url_quote %]&amp;amp;token=
-    [% issue_hash_token([query_id, name]) FILTER url_quote %]&quot;&gt;delete&lt;/a&gt;
-    it if you really want to use this name.
-
</del><span class="cx">   [% ELSIF error == &quot;query_name_missing&quot; %]
</span><span class="cx">     [% title = &quot;No Search Name Specified&quot; %]
</span><span class="cx">     [% docslinks = {'query.html#list' =&gt; &quot;$terms.Bug lists&quot;} %]
</span><span class="lines">@@ -1360,22 +1445,46 @@
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;query_name_too_long&quot; %]
</span><span class="cx">     [% title = &quot;Query Name Too Long&quot; %]
</span><del>-    The name of the query must be less than 64 characters long.
</del><ins>+    The name of the query must be less than [% constants.MAX_LEN_QUERY_NAME FILTER html %]
+    characters long.
</ins><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;quicksearch_unknown_field&quot; %]
-    [% title = &quot;Unknown QuickSearch Field&quot; %]
-    [% IF fields.unique.size == 1 %]
-      Field &lt;code&gt;[% fields.first FILTER html %]&lt;/code&gt; is not a known field.
</del><ins>+  [% ELSIF error == &quot;quicksearch_invalid_query&quot; %]
+    [% title = &quot;Invalid Query&quot; %]
+    Your query is invalid.
+    [% IF operators %]
+      The [% operators.shift FILTER html %] operator cannot be followed by
+      [%+ operators.shift FILTER html %].
</ins><span class="cx">     [% ELSE %]
</span><del>-      Fields
-      [% FOREACH field = fields.unique.sort %]
-         &lt;code&gt;[% field FILTER html %]&lt;/code&gt;
-         [% ', ' UNLESS loop.last() %]
-      [% END %]
-      are not known fields.
</del><ins>+      A query cannot start with AND or OR, nor can it end with AND, OR or NOT.
+      They are reserved operators and must be quoted if you want to look for
+      these strings.
</ins><span class="cx">     [% END %]
</span><del>-    The legal field names are &lt;a href=&quot;page.cgi?id=quicksearchhack.html&quot;&gt;listed here&lt;/a&gt;.
</del><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;quicksearch_unbalanced_quotes&quot; %]
+    [% title = &quot;Badly Formatted Query&quot; %]
+    [% terms.Bugzilla %] is unable to parse your query correctly:
+    &lt;em&gt;[% string FILTER html %]&lt;/em&gt;.&lt;br&gt;
+    If you use quotes to enclose strings, make sure both quotes are present.
+    If you really want to look for a quote in a string, type \&quot; instead of &quot;.
+    For instance, &lt;em&gt;&quot;I'm so \&quot;special\&quot;, really&quot;&lt;/em&gt; (with quotes) will be
+    interpreted as &lt;em&gt;I'm so &quot;special&quot;, really&lt;/em&gt;.
+
+  [% ELSIF error == &quot;quicksearch_unknown_field&quot; %]
+    [% title = &quot;QuickSearch Error&quot; %]
+    There is a problem with your search:
+    [% FOREACH field = unknown %]
+      &lt;p&gt;&lt;code&gt;[% field FILTER html %]&lt;/code&gt; is not a valid field name.&lt;/p&gt;
+    [% END %]
+    [% FOREACH field = ambiguous.keys %]
+      &lt;p&gt;&lt;code&gt;[% field FILTER html %]&lt;/code&gt; matches more than one field:
+        [%+ ambiguous.${field}.join(', ') FILTER html %]&lt;/p&gt;
+    [% END %]
+
+    [% IF unknown.size %]
+      &lt;p&gt;The legal field names are 
+        &lt;a href=&quot;page.cgi?id=quicksearch.html#fields&quot;&gt;listed here&lt;/a&gt;.&lt;/p&gt;
+    [% END %]
+
</ins><span class="cx">   [% ELSIF error == &quot;reassign_to_empty&quot; %]
</span><span class="cx">     [% title = &quot;Illegal Reassignment&quot; %]
</span><span class="cx">     To reassign [% terms.abug %], you must provide an address for
</span><span class="lines">@@ -1386,10 +1495,24 @@
</span><span class="cx">     To file this [% terms.bug %], you must first choose a component.
</span><span class="cx">     If necessary, just guess.
</span><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;relationship_loop_single&quot; %]
+    [% title = &quot;Relationship Loop Detected&quot; %]
+    [% field_descs.$field_name FILTER html %]
+    for [% terms.bug %] [%+ bug_id FILTER html %]
+    has a circular dependency on [% terms.bug %] [%+ dep_id FILTER html %].
+
+  [% ELSIF error == &quot;request_queue_group_invalid&quot; %]
+    The group field &lt;em&gt;[% group FILTER html %]&lt;/em&gt; is invalid.
+
</ins><span class="cx">   [% ELSIF error == &quot;require_new_password&quot; %]
</span><span class="cx">     [% title = &quot;New Password Needed&quot; %]
</span><span class="cx">     You cannot change your password without choosing a new one.
</span><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;required_field&quot; %]
+    [% title = &quot;Field Must Be Set&quot; %]
+    A value must be set for the '[% field_descs.${field.name} FILTER html %]'
+    field.
+
</ins><span class="cx">   [% ELSIF error == &quot;require_summary&quot; %]
</span><span class="cx">     [% title = &quot;Summary Needed&quot; %]
</span><span class="cx">     You must enter a summary for this [% terms.bug %].
</span><span class="lines">@@ -1415,6 +1538,16 @@
</span><span class="cx">     and the &quot;matches&quot; search can only be used with the &quot;content&quot;
</span><span class="cx">     field.
</span><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;search_field_operator_invalid&quot; %]
+    [% terms.Bugzilla %] does not support using the 
+    &quot;[%+ field_descs.$field FILTER html %]&quot; ([% field FILTER html %])
+    field with the &quot;[% search_descs.$operator FILTER html %]&quot; 
+    ([% operator FILTER html %]) search type.
+
+  [% ELSIF error == &quot;see_also_self_reference&quot; %]
+    You cannot put this [% terms.bug %] into its own
+    [%+ field_descs.see_also FILTER html %] field.
+
</ins><span class="cx">   [% ELSIF error == &quot;series_already_exists&quot; %]
</span><span class="cx">     [% title = &quot;Series Already Exists&quot; %]
</span><span class="cx">     [% docslinks = {'reporting.html' =&gt; 'Reporting'} %]
</span><span class="lines">@@ -1423,36 +1556,33 @@
</span><span class="cx">       [%+ series.name FILTER html %]&lt;/em&gt;
</span><span class="cx">       already exists.
</span><span class="cx">     
</span><del>-  [% ELSIF error == &quot;sidebar_supports_mozilla_only&quot; %]
-    Sorry - sidebar.cgi currently only supports Mozilla based web browsers.
-    &lt;a href=&quot;http://www.mozilla.org&quot;&gt;Upgrade today&lt;/a&gt;. :-)
-
</del><span class="cx">   [% ELSIF error == &quot;still_unresolved_bugs&quot; %]
</span><del>-    [% IF dependency_count == 1 %]
-      [% terms.Bug %]# &lt;a href=&quot;show_bug.cgi?id=[% dependencies.0.bug_id FILTER none %]&quot;&gt;[% dependencies.0.bug_id FILTER none %]&lt;/a&gt;
-      still has [% dependencies.0.dependencies FILTER html %] unresolved
-      [% IF dependencies.0.dependencies == 1 %]
-        dependency
-      [% ELSE %]
-        dependencies
-      [% END %]. Show
-      &lt;a href=&quot;showdependencytree.cgi?id=[% dependencies.0.bug_id FILTER none %]&amp;amp;hide_resolved=1&quot;&gt;Dependency
-      Tree&lt;/a&gt;.
</del><ins>+    [% title = &quot;Unresolved Dependencies&quot; %]
+    [% terms.Bug %] [%+ bug_id FILTER bug_link(bug_id) FILTER none %]
+    has [% dep_count FILTER none %] unresolved
+    [% IF dep_count == 1 %]
+      dependency
</ins><span class="cx">     [% ELSE %]
</span><del>-      There are [% dependency_count FILTER none %] open [% terms.bugs %] which
-      have unresolved dependencies.
-      &lt;br&gt;
-      [% FOREACH bug = dependencies %]
-        [% terms.Bug %]# &lt;a href=&quot;show_bug.cgi?id=[% bug.bug_id FILTER none %]&quot;&gt;[% bug.bug_id FILTER none %]&lt;/a&gt;
-        has [% bug.dependencies FILTER html %] open
-        [% IF bug.dependencies == 1 %]
-          dependency.
-        [% ELSE %]
-          dependencies.
-        [% END %]
-        (&lt;a href=&quot;showdependencytree.cgi?id=[% bug.bug_id FILTER none %]&amp;amp;hide_resolved=1&quot;&gt;Dependency
-        Tree&lt;/a&gt;)&lt;br&gt;
-      [% END %]
</del><ins>+      dependencies
+    [% END %].
+    They must either be resolved or removed from the
+    &quot;[% field_descs.dependson FILTER html %]&quot; field before you can resolve
+    this [% terms.bug %] as [% display_value(&quot;resolution&quot;, &quot;FIXED&quot;) FILTER html %].
+
+  [% ELSIF error == &quot;sudo_invalid_cookie&quot; %]
+    [% title = &quot;Invalid Sudo Cookie&quot; %]
+    Your sudo cookie is invalid. Either it expired or you didn't start
+    a sudo session correctly. Refresh the page or load another page
+    to continue what you are doing as yourself.
+
+  [% ELSIF error == &quot;sudo_illegal_action&quot; %]
+    [% title = &quot;Impersonation Not Authorized&quot; %]
+    [% IF NOT sudoer.in_group(&quot;bz_sudoers&quot;) %]
+      You are not allowed to impersonate users.
+    [% ELSIF target_user AND target_user.in_group(&quot;bz_sudo_protect&quot;) %]
+      You are not allowed to impersonate [% target_user.identity FILTER html %].
+    [% ELSE %]
+      The user you tried to impersonate doesn't exist.
</ins><span class="cx">     [% END %]
</span><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;sudo_in_progress&quot; %]
</span><span class="lines">@@ -1463,36 +1593,26 @@
</span><span class="cx">   [% ELSIF error == &quot;sudo_password_required&quot; %]
</span><span class="cx">     [% title = &quot;Password Required&quot; %]
</span><span class="cx">     Your [% terms.Bugzilla %] password is required to begin a sudo 
</span><del>-    session. Please &lt;a href=&quot;relogin.cgi?action=prepare-sudo&amp;target_login=
-    [%- target_login FILTER html %]&amp;reason=
-    [%- reason FILTER html %]&quot;&gt;go back&lt;/a&gt; and enter your password.
</del><ins>+    session. Please &lt;a href=&quot;relogin.cgi?action=prepare-sudo&amp;amp;target_login=
+    [%- target_login FILTER uri %]&amp;amp;reason=
+    [%- reason FILTER uri %]&quot;&gt;go back&lt;/a&gt; and enter your password.
</ins><span class="cx">     
</span><span class="cx">   [% ELSIF error == &quot;sudo_preparation_required&quot; %]
</span><span class="cx">     [% title = &quot;Preparation Required&quot; %]
</span><span class="cx">     You may not start a sudo session directly.  Please
</span><del>-    &lt;a href=&quot;relogin.cgi?action=prepare-sudo&amp;target_login=
-    [%- target_login FILTER html %]&amp;reason=
-    [%- reason FILTER html %]&quot;&gt;start your session normally&lt;/a&gt;.
</del><ins>+    &lt;a href=&quot;relogin.cgi?action=prepare-sudo&amp;amp;target_login=
+    [%- target_login FILTER uri %]&amp;amp;reason=
+    [%- reason FILTER uri %]&quot;&gt;start your session normally&lt;/a&gt;.
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;sudo_protected&quot; %]
</span><span class="cx">     [% title = &quot;User Protected&quot; %]
</span><span class="cx">     The user [% login FILTER html %] may not be impersonated by sudoers.
</span><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;too_many_votes_for_bug&quot; %]
-    [% title = &quot;Illegal Vote&quot; %]
-    [% admindocslinks = {'voting.html' =&gt; 'Setting up the voting feature'} %]
-    You may only use at most [% max FILTER html %] votes for a single
-    [%+ terms.bug %] in the
-    &lt;tt&gt;[% product FILTER html %]&lt;/tt&gt; product, but you are trying to
-    use [% votes FILTER html %].
</del><ins>+  [% ELSIF error == &quot;tag_name_too_long&quot; %]
+    [% title = &quot;Tag Name Too Long&quot; %]
+    The tag name must be less than [% constants.MAX_LEN_QUERY_NAME FILTER html %]
+    characters long.
</ins><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;too_many_votes_for_product&quot; %]
-    [% title = &quot;Illegal Vote&quot; %]
-    [% admindocslinks = {'voting.html' =&gt; 'Setting up the voting feature'} %]
-    You tried to use [% votes FILTER html %] votes in the
-    &lt;tt&gt;[% product FILTER html %]&lt;/tt&gt; product, which exceeds the maximum of
-    [%+ max FILTER html %] votes for this product.
-
</del><span class="cx">   [% ELSIF error == &quot;token_does_not_exist&quot; %]
</span><span class="cx">     [% title = &quot;Token Does Not Exist&quot; %]
</span><span class="cx">     The token you submitted does not exist, has expired, or has
</span><span class="lines">@@ -1508,10 +1628,12 @@
</span><span class="cx">     [% END %]
</span><span class="cx">     token too recently to request another. Please wait a while and try again.
</span><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;unknown_keyword&quot; %]
-    [% title = &quot;Unknown Keyword&quot; %]
-    &lt;code&gt;[% keyword FILTER html %]&lt;/code&gt; is not a known keyword.
-    The legal keyword names are &lt;a href=&quot;describekeywords.cgi&quot;&gt;listed here&lt;/a&gt;.
</del><ins>+  [% ELSIF error == &quot;unknown_action&quot; %]
+    [% IF action %]
+       Unknown action [% action FILTER html %]!
+    [% ELSE %]
+       I could not figure out what you wanted to do.
+    [% END %]
</ins><span class="cx"> 
</span><span class="cx">   [% ELSIF error == &quot;unknown_tab&quot; %]
</span><span class="cx">     [% title = &quot;Unknown Tab&quot; %]
</span><span class="lines">@@ -1533,10 +1655,6 @@
</span><span class="cx">     version! You must reassign those [% terms.bugs %] to another version
</span><span class="cx">     before you can delete this one.
</span><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;version_not_specified&quot; %]
-    [% title = &quot;No Version Specified&quot; %]
-    No version specified when trying to edit versions.
-
</del><span class="cx">   [% ELSIF error == &quot;users_deletion_disabled&quot; %]
</span><span class="cx">     [% title = &quot;Deletion not activated&quot; %]
</span><span class="cx">     [% admindocslinks = {'useradmin.html' =&gt; 'User administration'} %]
</span><span class="lines">@@ -1553,6 +1671,16 @@
</span><span class="cx">     for at least one component.
</span><span class="cx">     For this reason, you cannot delete the account at this time.
</span><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;user_access_by_id_denied&quot; %]
+    [% title = &quot;User Access By Id Denied&quot; %]
+    Logged-out users cannot use the &quot;ids&quot; argument to this function
+    to access any user information.
+
+  [% ELSIF error == &quot;user_access_by_match_denied&quot; %]
+    [% title = &quot;User-Matching Denied&quot; %]
+    Logged-out users cannot use the &quot;match&quot; argument to this function
+    to access any user information.
+
</ins><span class="cx">   [% ELSIF error == &quot;user_login_required&quot; %]
</span><span class="cx">     [% title = &quot;Login Name Required&quot; %]
</span><span class="cx">     [% admindocslinks = {'useradmin.html' =&gt; 'User administration'} %]
</span><span class="lines">@@ -1563,11 +1691,17 @@
</span><span class="cx">     &lt;tt&gt;[% name FILTER html %]&lt;/tt&gt; does not exist or you are not allowed 
</span><span class="cx">     to see that user.
</span><span class="cx"> 
</span><del>-  [% ELSIF error == &quot;votes_must_be_nonnegative&quot; %]
-    [% title = &quot;Votes Must Be Non-negative&quot; %]
-    [% admindocslinks = {'voting.html' =&gt; 'Setting up the voting feature'} %]
-    Only use non-negative numbers for your [% terms.bug %] votes.
</del><ins>+  [% ELSIF error == &quot;user_match_too_many&quot; %]
+    [% title = &quot;No Conclusive Match&quot; %]
+    [% terms.Bugzilla %] cannot make a conclusive match for one or more
+    of the names and/or email addresses you entered for
+    the [% fields.join(', ') FILTER html %] field(s).
</ins><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;user_not_insider&quot; %]
+    [% title = &quot;User Not In Insidergroup&quot; %]
+    Sorry, but you are not allowed to (un)mark comments or attachments
+    as private.
+
</ins><span class="cx">   [% ELSIF error == &quot;wrong_token_for_cancelling_email_change&quot; %]
</span><span class="cx">     [% title = &quot;Wrong Token&quot; %]
</span><span class="cx">     That token cannot be used to cancel an email address change.
</span><span class="lines">@@ -1584,6 +1718,16 @@
</span><span class="cx">     [% title = &quot;Wrong Token&quot; %]
</span><span class="cx">     That token cannot be used to create a user account.
</span><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;xmlrpc_invalid_value&quot; %]
+    &quot;[% value FILTER html %]&quot; is not a valid value for a
+    &amp;lt;[% type FILTER html %]&amp;gt; field. (See the XML-RPC specification
+    for details.)
+
+  [% ELSIF error == &quot;xmlrpc_illegal_content_type&quot; %]
+    When using XML-RPC, you cannot send data as
+    [%+ content_type FILTER html %]. Only text/xml 
+    and application/xml are allowed.
+
</ins><span class="cx">   [% ELSIF error == &quot;zero_length_file&quot; %]
</span><span class="cx">     [% title = &quot;File Is Empty&quot; %]
</span><span class="cx">     The file you are trying to attach is empty, does not exist, or you don't
</span><span class="lines">@@ -1593,6 +1737,14 @@
</span><span class="cx">     [% title = &quot;Illegal User ID&quot; %]
</span><span class="cx">     User ID '[% userid FILTER html %]' is not valid integer.
</span><span class="cx"> 
</span><ins>+  [% ELSIF error == &quot;extern_id_exists&quot; %]
+    [% title = &quot;Account Already Exists&quot; %]
+    There is already an account
+    [% IF existing_login_name %]
+      ([% existing_login_name FILTER html %])
+    [% END %]
+    with the External Login ID &quot;[% extern_id FILTER html %]&quot;.
+
</ins><span class="cx">   [% ELSE %]
</span><span class="cx"> 
</span><span class="cx">     [%# Try to find hooked error messages %]
</span><span class="lines">@@ -1653,11 +1805,11 @@
</span><span class="cx">   &lt;p&gt;  
</span><span class="cx">     Alternatively, you can    
</span><span class="cx">     &lt;a href=&quot;buglist.cgi?cmdtype=dorem&amp;amp;remaction=forget&amp;amp;namedcmd=
</span><del>-                  [% namedcmd FILTER url_quote %]&quot;&gt;forget&lt;/a&gt;
</del><ins>+                  [% namedcmd FILTER uri %]&quot;&gt;forget&lt;/a&gt;
</ins><span class="cx">                   
</span><span class="cx">     [% FOREACH q = Bugzilla.user.queries %]
</span><span class="cx">       [% IF q.name == namedcmd %]
</span><del>-        or &lt;a href=&quot;query.cgi?[% q.url FILTER html %]&quot;&gt;edit&lt;/a&gt;
</del><ins>+        or &lt;a href=&quot;query.cgi?[% q.url FILTER uri %]&quot;&gt;edit&lt;/a&gt;
</ins><span class="cx">       [% END %]
</span><span class="cx">     [% END %]
</span><span class="cx">     
</span><span class="lines">@@ -1668,8 +1820,14 @@
</span><span class="cx"> [% PROCESS global/footer.html.tmpl %]
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK object_name %]
</span><del>-  [% IF class == &quot;Bugzilla::User&quot; %]
</del><ins>+  [% IF class == &quot;Bugzilla::Attachment&quot; %]
+    attachment
+  [% ELSIF class == &quot;Bugzilla::User&quot; %]
</ins><span class="cx">     user
</span><ins>+  [% ELSIF class == &quot;Bugzilla::Classification&quot; %]
+    classification
+  [% ELSIF class == &quot;Bugzilla::Product&quot; %]
+    product
</ins><span class="cx">   [% ELSIF class == &quot;Bugzilla::Component&quot; %]
</span><span class="cx">     component
</span><span class="cx">   [% ELSIF class == &quot;Bugzilla::Version&quot; %]
</span><span class="lines">@@ -1678,5 +1836,23 @@
</span><span class="cx">     milestone
</span><span class="cx">   [% ELSIF class == &quot;Bugzilla::Status&quot; %]
</span><span class="cx">     status
</span><ins>+  [% ELSIF class == &quot;Bugzilla::Flag&quot; %]
+    flag
+  [% ELSIF class == &quot;Bugzilla::FlagType&quot; %]
+    flagtype
+  [% ELSIF class == &quot;Bugzilla::Field&quot; %]
+    field
+  [% ELSIF class == &quot;Bugzilla::Group&quot; %]
+    group
+  [% ELSIF class == &quot;Bugzilla::Keyword&quot; %]
+    keyword
+  [% ELSIF class == &quot;Bugzilla::Search::Recent&quot; %]
+    recent search
+  [% ELSIF class == &quot;Bugzilla::Search::Saved&quot; %]
+    saved search
+  [% ELSIF ( matches = class.match('^Bugzilla::Field::Choice::(.+)') ) %]
+    [% SET field_name = matches.0 %]
+    [% field_descs.$field_name FILTER html %]
</ins><span class="cx">   [% END %]
</span><ins>+  [% Hook.process('end_object_name', 'global/user-error.html.tmpl') %]
</ins><span class="cx"> [% END %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultglobaluserhtmltmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/global/user.html.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/global/user.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/global/user.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,39 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Daniel Brooks.
+  # Portions created by the Initial Developer are Copyright (C) 2007
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s): 
+  #   Daniel Brooks &lt;db48x@db48x.net&gt;
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[%# INTERFACE:
+  # who: A Bugzilla::User object that we are going to represent.
+  #%]
+
+&lt;span class=&quot;vcard&quot;&gt;
+  [% FILTER collapse %]
+    [% IF user.id %]
+      &lt;a class=&quot;email&quot; href=&quot;mailto:[% who.email FILTER html %]&quot;
+         title=&quot;[% who.identity FILTER html %]&quot;&gt;
+    [%- END -%]
+    [% IF who.name %]
+       &lt;span class=&quot;fn&quot;&gt;[% who.name FILTER html %]&lt;/span&gt;
+    [% ELSE %]
+      [% who.login FILTER email FILTER html %]
+    [% END %]
+    [% '&lt;/a&gt;' IF user.id %]
+  [% END %]
+&lt;/span&gt;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultglobaluserselecthtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/global/userselect.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/global/userselect.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/global/userselect.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -12,32 +12,42 @@
</span><span class="cx">   #
</span><span class="cx">   # Contributor(s): Byron Jones &lt;bugzilla@glob.com.au&gt;
</span><span class="cx">   #                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
</span><ins>+  #                 Guy Pyrzak &lt;guy.pyrzak@gmail.com&gt;
+  #                 Reed Loden &lt;reed@reedloden.com&gt;
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [%# INTERFACE:
</span><span class="cx">   # name: mandatory; field name
</span><span class="cx">   # id: optional; field id
</span><span class="cx">   # value: optional; default field value/selection
</span><ins>+  # classes: optional; an array of classes to be added
</ins><span class="cx">   # onchange: optional; onchange attribute value
</span><span class="cx">   # disabled: optional; if true, the field is disabled
</span><span class="cx">   # accesskey: optional, input only; accesskey attribute value
</span><span class="cx">   # size: optional, input only; size attribute value
</span><del>-  # emptyok: optional, select only;  if true, prepend menu option to start of select
</del><ins>+  # emptyok: optional, select only; if true, prepend menu option for &quot;&quot; to start of select
+  # hyphenok: optional, select only; if true, prepend menu option for &quot;-&quot; to start of select
</ins><span class="cx">   # multiple: optional, do multiselect box, value is size (height) of box
</span><span class="cx">   # custom_userlist: optional, specify a limited list of users to use
</span><ins>+  # field_title: optional, extra information to display as a tooltip
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [% IF Param(&quot;usemenuforusers&quot;) %]
</span><span class="cx"> &lt;select name=&quot;[% name FILTER html %]&quot;
</span><span class="cx">   [% IF id %] id=&quot;[% id FILTER html %]&quot; [% END %]
</span><ins>+  [% IF classes %] class=&quot;[% classes.join(' ') FILTER html %]&quot; [% END %]
</ins><span class="cx">   [% IF onchange %] onchange=&quot;[% onchange FILTER html %]&quot; [% END %]
</span><span class="cx">   [% IF disabled %] disabled=&quot;[% disabled FILTER html %]&quot; [% END %]
</span><span class="cx">   [% IF accesskey %] accesskey=&quot;[% accesskey FILTER html %]&quot; [% END %]
</span><span class="cx">   [% IF multiple %] multiple=&quot;multiple&quot; size=&quot;[% multiple FILTER html %]&quot; [% END %]
</span><ins>+  [% IF field_title %] title=&quot;[% field_title FILTER html %]&quot; [% END %]
</ins><span class="cx"> &gt;
</span><span class="cx">   [% IF emptyok %]
</span><span class="cx">     &lt;option value=&quot;&quot;&gt;&lt;/option&gt;
</span><span class="cx">   [% END %]
</span><ins>+  [% IF hyphenok %]
+    &lt;option value=&quot;-&quot;&gt;-&lt;/option&gt;
+  [% END %]
</ins><span class="cx"> 
</span><span class="cx">   [% UNLESS custom_userlist %]
</span><span class="cx">     [% custom_userlist = user.get_userlist %]
</span><span class="lines">@@ -69,15 +79,31 @@
</span><span class="cx">   [% END %]
</span><span class="cx"> &lt;/select&gt;
</span><span class="cx"> [% ELSE %]
</span><del>-&lt;input
-  name=&quot;[% name FILTER html %]&quot;
-  value=&quot;[% value FILTER html %]&quot;
-  [% IF onchange %] onchange=&quot;[% onchange FILTER html %]&quot; [% END %]
-  [% IF disabled %] disabled=&quot;[% disabled FILTER html %]&quot; [% END %]
-  [% IF accesskey %] accesskey=&quot;[% accesskey FILTER html %]&quot; [% END %]
-  [% IF size %] size=&quot;[% size FILTER html %]&quot; [% END %]
-  [% IF id %] id=&quot;[% id FILTER html %]&quot; [% END %]
-&gt;
</del><ins>+  [% IF feature_enabled('jsonrpc') &amp;&amp; Param('ajax_user_autocompletion') &amp;&amp; id %]
+    &lt;div id=&quot;[% id FILTER html %]_autocomplete&quot; 
+         [% IF classes %] class=&quot;[% classes.join(' ') FILTER html %]&quot; [% END %]&gt;
+  [% END %]  
+  &lt;input
+    name=&quot;[% name FILTER html %]&quot;
+    value=&quot;[% value FILTER html %]&quot;
+    [% IF classes %] class=&quot;[% classes.join(' ') FILTER html %]&quot; [% END %]
+    [% IF onchange %] onchange=&quot;[% onchange FILTER html %]&quot; [% END %]
+    [% IF disabled %] disabled=&quot;[% disabled FILTER html %]&quot; [% END %]
+    [% IF accesskey %] accesskey=&quot;[% accesskey FILTER html %]&quot; [% END %]
+    [% IF field_title %] title=&quot;[% field_title FILTER html %]&quot; [% END %]
+    [% IF size %] size=&quot;[% size FILTER html %]&quot; [% END %]
+    [% IF id %] id=&quot;[% id FILTER html %]&quot; [% END %]
+  &gt;
+  [% IF feature_enabled('jsonrpc') &amp;&amp; Param('ajax_user_autocompletion') &amp;&amp; id %]
+    &lt;div id=&quot;[% id FILTER html %]_autocomplete_container&quot;&gt;&lt;/div&gt;
+    &lt;/div&gt;  
+    &lt;script type=&quot;text/javascript&quot;&gt;
+      if( typeof(YAHOO.bugzilla.userAutocomplete) !== 'undefined' 
+          &amp;&amp; YAHOO.bugzilla.userAutocomplete != null){
+        YAHOO.bugzilla.userAutocomplete.init( &quot;[% id FILTER js %]&quot;, 
+                    &quot;[% id FILTER js %]_autocomplete_container&quot;
+                    [% IF multiple %], true[% END%]);        
+      }
+    &lt;/script&gt;
+  [% END %]
</ins><span class="cx"> [% END %]
</span><del>-
-
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultglobalvaluedescsjstmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/global/value-descs.js.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/global/value-descs.js.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/global/value-descs.js.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,33 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2010
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s): 
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[% PROCESS &quot;global/value-descs.none.tmpl&quot; %]
+
+BUGZILLA.value_descs = {
+  [% FOREACH vd_field = value_descs.keys %]
+    [% vd_field FILTER js %]: {
+      [% FOREACH vd_value = value_descs.${vd_field}.keys %]
+        '[% vd_value FILTER js %]':
+        '[% value_descs.${vd_field}.${vd_value} FILTER js %]'
+        [%~ ',' UNLESS loop.last %]
+      [% END %]
+    }[% ',' UNLESS loop.last %]
+  [% END %]
+};
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultglobalvaluedescsnonetmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/global/value-descs.none.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/global/value-descs.none.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/global/value-descs.none.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,36 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is BugzillaSource, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2011 
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s):
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[%# You can use this hash to localize (translate) the values displayed
+  # for drop-down and multiple-select fields. Lines starting with &quot;#&quot;
+  # are comments.
+  #%]
+[% value_descs = {
+  &quot;bug_status&quot; =&gt; {
+    # &quot;UNCONFIRMED&quot; =&gt; &quot;UNCO&quot;,
+    # &quot;CONFIRMED&quot;   =&gt; &quot;ITSABUG&quot;,
+  },
+
+  &quot;resolution&quot; =&gt; {
+    &quot;&quot;        =&gt; &quot;---&quot;,
+    # &quot;FIXED&quot;      =&gt; &quot;NO LONGER AN ISSUE&quot;,
+    # &quot;WORKSFORME&quot; =&gt; &quot;NOTMYPROBLEM!&quot;,
+  },
+} %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultglobalvariablesnonetmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/global/variables.none.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/global/variables.none.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/global/variables.none.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -32,6 +32,7 @@
</span><span class="cx">   &quot;Bug&quot; =&gt; &quot;Bug&quot;,
</span><span class="cx">   &quot;abug&quot; =&gt; &quot;a bug&quot;,
</span><span class="cx">   &quot;Abug&quot; =&gt; &quot;A bug&quot;,
</span><ins>+  &quot;aBug&quot; =&gt; &quot;a Bug&quot;,
</ins><span class="cx">   &quot;ABug&quot; =&gt; &quot;A Bug&quot;,
</span><span class="cx">   &quot;bugs&quot; =&gt; &quot;bugs&quot;,
</span><span class="cx">   &quot;Bugs&quot; =&gt; &quot;Bugs&quot;,
</span><span class="lines">@@ -39,3 +40,5 @@
</span><span class="cx">   &quot;Bugzilla&quot; =&gt; &quot;Bugzilla&quot;
</span><span class="cx">   }
</span><span class="cx"> %]
</span><ins>+
+[% Hook.process(&quot;end&quot;) %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultindexhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/index.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/index.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/index.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -19,6 +19,7 @@
</span><span class="cx">   # Contributor(s): Terry Weissman &lt;terry@mozilla.org&gt;
</span><span class="cx">   #                 Jacob Steenhagen &lt;jake@bugzilla.org&gt;
</span><span class="cx">   #                 Vitaly Harisov  &lt;vitaly@rathedg.com&gt;
</span><ins>+  #                 Guy Pyrzak &lt;guy.pyrzak@gmail.com&gt;
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [%# INTERFACE:
</span><span class="lines">@@ -33,27 +34,43 @@
</span><span class="cx">    header = &quot;Main Page&quot; 
</span><span class="cx">    header_addl_info = &quot;version $constants.BUGZILLA_VERSION&quot;
</span><span class="cx">    style_urls = [ 'skins/standard/index.css' ]
</span><del>-   onload = 'document.forms[\'f\'].quicksearch.focus();'
</del><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> &lt;script type=&quot;text/javascript&quot;&gt;
</span><span class="cx"> &lt;!--
</span><del>-function addSidebar() {
-  if ((typeof window.sidebar == &quot;object&quot;) &amp;&amp; (typeof window.sidebar.addPanel == &quot;function&quot;))
-  {
-    var sidebarname=window.location.host;
-    if (!/bug/i.test(sidebarname))
-      sidebarname=&quot;[% terms.Bugzilla %] &quot;+sidebarname;
-    window.sidebar.addPanel (sidebarname, &quot;[% urlbase FILTER html %]sidebar.cgi&quot;, &quot;&quot;);
</del><ins>+function onLoadActions() {
+  quicksearchHelpText('quicksearch_main', 'show');
+  if( window.external.AddSearchProvider ){
+    YAHOO.util.Dom.removeClass('quicksearch_plugin', 'bz_default_hidden');
</ins><span class="cx">   }
</span><del>-  else
-  {
-    var rv = window.confirm (&quot;Your browser does not support the sidebar extension.  &quot; + &quot;Would you like to upgrade now?&quot;);
-    if (rv)
-      document.location.href = &quot;http://www.mozilla.org/&quot;;
</del><ins>+  document.getElementById('quicksearch_top').focus();
+}
+var quicksearch_message = &quot;Enter [% terms.abug %] # or some search terms&quot;;
+
+function checkQuicksearch( form ) {
+  if (form.quicksearch.value == '' || form.quicksearch.value == quicksearch_message ) { 
+    alert('Please enter one or more search terms first.');
+    return false; 
</ins><span class="cx">   }
</span><ins>+  return true;         
</ins><span class="cx"> }
</span><ins>+
+function quicksearchHelpText(el_id, action){
+  var el = document.getElementById(el_id);
+  if ( action == &quot;show&quot;) {
+    if( el.value == &quot;&quot; ) {
+      el.value = quicksearch_message
+      YAHOO.util.Dom.addClass(el, &quot;quicksearch_help_text&quot;);
+    }
+  } else {
+    if( el.value == quicksearch_message ) {
+      el.value = &quot;&quot;;
+      YAHOO.util.Dom.removeClass(el, &quot;quicksearch_help_text&quot;);
+    }
+  }
+}
+YAHOO.util.Event.onDOMReady(onLoadActions);
</ins><span class="cx"> //--&gt;
</span><span class="cx"> &lt;/script&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -73,86 +90,103 @@
</span><span class="cx"> 
</span><span class="cx">       &lt;p class=&quot;notice&quot;&gt;This message is only shown to logged in users with admin privs.
</span><span class="cx">       You can configure this notification from the
</span><del>-      &lt;a href=&quot;editparams.cgi?section=core#upgrade_notification&quot;&gt;Parameters&lt;/a&gt; page.&lt;/p&gt;
-    [% ELSIF release.error == &quot;missing_package&quot; %]
-      &lt;p&gt;Missing package '[% release.package FILTER html %]'. This package is required to
-      &lt;a href=&quot;editparams.cgi?section=core#upgrade_notification&quot;&gt;notify you about new releases&lt;/a&gt;.&lt;/p&gt;
</del><ins>+      &lt;a href=&quot;editparams.cgi?section=general#upgrade_notification_desc&quot;&gt;Parameters&lt;/a&gt; page.&lt;/p&gt;
</ins><span class="cx">     [% ELSIF release.error == &quot;cannot_download&quot; %]
</span><del>-      &lt;p&gt;The local XML file '[% release.xml_file FILTER html %]' cannot be created.
-      Please make sure the web server can write in this directory and that you can access
</del><ins>+      &lt;p&gt;The remote file &lt;a href=&quot;[% constants.REMOTE_FILE FILTER html %]&quot;&gt;
+      [%~ constants.REMOTE_FILE FILTER html %]&lt;/a&gt; cannot be downloaded
+      (reason: [% release.reason FILTER html %]).&lt;br&gt;
+      Either the remote server is temporarily unavailable, or your web server cannot access
</ins><span class="cx">       the web. If you are behind a proxy, set the
</span><del>-      &lt;a href=&quot;editparams.cgi?section=core#proxy_url&quot;&gt;proxy_url&lt;/a&gt; parameter correctly.&lt;/p&gt;
</del><ins>+      &lt;a href=&quot;editparams.cgi?section=advanced#proxy_url_desc&quot;&gt;proxy_url&lt;/a&gt; parameter correctly.&lt;/p&gt;
+    [% ELSIF release.error == &quot;no_write&quot; %]
+      &lt;p&gt;The local XML file '[% constants.LOCAL_FILE FILTER html %]' cannot be created
+      (reason: [% release.reason FILTER html %]).&lt;br&gt;
+      Please make sure the web server can write into this directory.
</ins><span class="cx">     [% ELSIF release.error == &quot;no_update&quot; %]
</span><del>-      &lt;p&gt;The local XML file '[% release.xml_file FILTER html %]' cannot be updated.
</del><ins>+      &lt;p&gt;The local XML file '[% constants.LOCAL_FILE FILTER html %]' cannot be updated.
</ins><span class="cx">       Please make sure the web server can edit this file.&lt;/p&gt;
</span><span class="cx">     [% ELSIF release.error == &quot;no_access&quot; %]
</span><del>-      &lt;p&gt;The local XML file '[% release.xml_file FILTER html %]' cannot be read.
</del><ins>+      &lt;p&gt;The local XML file '[% constants.LOCAL_FILE FILTER html %]' cannot be read.
</ins><span class="cx">       Please make sure this file has the correct rights set on it.&lt;/p&gt;
</span><span class="cx">     [% ELSIF release.error == &quot;corrupted&quot; %]
</span><del>-      &lt;p&gt;The local XML file '[% release.xml_file FILTER html %]' has an invalid XML format.
</del><ins>+      &lt;p&gt;The local XML file '[% constants.LOCAL_FILE FILTER html %]' has an invalid XML format.
</ins><span class="cx">       Please delete it and try accessing this page again.&lt;/p&gt;
</span><span class="cx">     [% ELSIF release.error == &quot;unknown_parameter&quot; %]
</span><span class="cx">       &lt;p&gt;'[% Param(&quot;upgrade_notification&quot;) FILTER html %]' is not a valid notification
</span><span class="cx">       parameter. Please check this parameter in the
</span><del>-      &lt;a href=&quot;editparams.cgi?section=core#upgrade_notification&quot;&gt;Parameters&lt;/a&gt; page.&lt;/p&gt;
</del><ins>+      &lt;a href=&quot;editparams.cgi?section=general#upgrade_notification_desc&quot;&gt;Parameters&lt;/a&gt; page.&lt;/p&gt;
</ins><span class="cx">     [% END %]
</span><span class="cx">   &lt;/div&gt;
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> &lt;div id=&quot;page-index&quot;&gt;
</span><del>-  &lt;div class=&quot;intro&quot;&gt;&lt;/div&gt;
</del><ins>+  &lt;table&gt;
+    &lt;tr&gt;
+      &lt;td&gt;
+        &lt;h1 id=&quot;welcome&quot;&gt; Welcome to [% terms.Bugzilla %]&lt;/h1&gt;
+        &lt;div class=&quot;intro&quot;&gt;[% Hook.process('intro') %]&lt;/div&gt;
</ins><span class="cx"> 
</span><del>-  &lt;p&gt;Welcome to [% terms.Bugzilla %]. To see what's new in this version
-    of [% terms.Bugzilla %], see the 
-    &lt;a href=&quot;page.cgi?id=release-notes.html&quot;&gt;release notes&lt;/a&gt;!
-    You may also want to read the 
-    &lt;a href=&quot;[% docs_urlbase FILTER html %]using.html&quot;&gt;
-    [%- terms.Bugzilla %] User's Guide&lt;/a&gt; to find out more about 
-    [%+ terms.Bugzilla %] and how to use it.&lt;/p&gt;
</del><ins>+        &lt;div class=&quot;bz_common_actions&quot;&gt;
+          &lt;ul&gt;
+            &lt;li&gt;
+              &lt;a id=&quot;enter_bug&quot; href=&quot;enter_bug.cgi&quot;&gt;&lt;span&gt;File
+              [%= terms.aBug %]&lt;/span&gt;&lt;/a&gt;
+            &lt;/li&gt;
+            &lt;li&gt;
+              &lt;a id=&quot;query&quot; href=&quot;query.cgi&quot;&gt;&lt;span&gt;Search&lt;/span&gt;&lt;/a&gt;
+            &lt;/li&gt;
+            &lt;li&gt;
+              &lt;a id=&quot;account&quot;
+                 [% IF user.id %]
+                   href=&quot;userprefs.cgi&quot;&gt;&lt;span&gt;User Preferences&lt;/span&gt;&lt;/a&gt;
+                 [% ELSIF Param('createemailregexp')
+                          &amp;&amp; user.authorizer.user_can_create_account 
+                 %]
+                   href=&quot;createaccount.cgi&quot;&gt;&lt;span&gt;Open a New Account&lt;/span&gt;&lt;/a&gt;
+                 [% ELSE %]
+                   href=&quot;?GoAheadAndLogIn=1&quot;&gt;&lt;span&gt;Log In&lt;/span&gt;&lt;/a&gt;
+                 [% END %]
+            &lt;/li&gt;
+          &lt;/ul&gt;
+        &lt;/div&gt;
</ins><span class="cx"> 
</span><del>-  &lt;p&gt;Most common actions:&lt;/p&gt;
-  &lt;ul&gt;
-    &lt;li id=&quot;query&quot;&gt;&lt;a href=&quot;query.cgi&quot;&gt;Search existing [% terms.bug %] reports&lt;/a&gt;&lt;/li&gt;
-    &lt;li id=&quot;enter-bug&quot;&gt;&lt;a href=&quot;enter_bug.cgi&quot;&gt;Enter a new [% terms.bug %] report&lt;/a&gt;&lt;/li&gt;
-    &lt;li id=&quot;report&quot;&gt;&lt;a href=&quot;report.cgi&quot;&gt;Summary reports and charts&lt;/a&gt;&lt;/li&gt;
-[% IF user.id %]
-    &lt;li id=&quot;userprefs&quot;&gt;&lt;a href=&quot;userprefs.cgi&quot;&gt;Change password or user preferences&lt;/a&gt;&lt;/li&gt;
-  [% IF user.authorizer.can_logout %]
-    &lt;li id=&quot;logout&quot;&gt;&lt;a href=&quot;relogin.cgi&quot;&gt;Log out [% user.login FILTER html %]&lt;/a&gt;&lt;/li&gt;
-  [% END %]
-[% ELSIF user.authorizer.can_login %]
-  &lt;/ul&gt;
-    [% PROCESS &quot;account/auth/login-small.html.tmpl&quot; %]
-  &lt;ul&gt;
-  [% IF Param('createemailregexp') &amp;&amp; user.authorizer.user_can_create_account %]
-    &lt;li id=&quot;account&quot;&gt;&lt;a href=&quot;createaccount.cgi&quot;&gt;Open a new [% terms.Bugzilla %] account&lt;/a&gt;&lt;/li&gt;
-  [% END %]
-[% END %]
-    &lt;li id=&quot;sidebar&quot;&gt;&lt;a href=&quot;javascript:addSidebar()&quot;&gt;Add to Sidebar&lt;/a&gt; (requires a Mozilla browser like Mozilla Firefox)&lt;/li&gt;
-    &lt;li id=&quot;quick_search_plugin&quot;&gt;
-      &lt;a href=&quot;javascript:window.external.AddSearchProvider('[% urlbase FILTER html %]search_plugin.cgi')&quot;&gt;Install
-      the Quick Search plugin&lt;/a&gt; (requires Firefox 2 or Internet Explorer 7)
-    &lt;/li&gt;
-
-
-    [%# List items of links to more things users can do on this installation. %]
-    [% Hook.process(&quot;links&quot;) %]
-
-  &lt;/ul&gt;
-
-  &lt;form id=&quot;f&quot; name=&quot;f&quot; action=&quot;buglist.cgi&quot; method=&quot;get&quot;
-        onsubmit=&quot;if (this.quicksearch.value == '')
-                  { alert('Please enter one or more search terms first.');
-                    return false; } return true;&quot;&gt;
-  &lt;div&gt;
-    &lt;p&gt;Enter [% terms.abug %] # or some search terms:&lt;/p&gt;
-    &lt;input id=&quot;quicksearch&quot; type=&quot;text&quot; name=&quot;quicksearch&quot;&gt;
-    &lt;input id=&quot;find&quot; type=&quot;submit&quot; value=&quot;Find&quot;&gt;
-    &lt;a href=&quot;page.cgi?id=quicksearch.html&quot;&gt;[Help]&lt;/a&gt;
-  &lt;/div&gt;
-  &lt;/form&gt;
-
-  &lt;div class=&quot;outro&quot;&gt;&lt;/div&gt;
</del><ins>+        &lt;form id=&quot;quicksearchForm&quot; name=&quot;quicksearchForm&quot; action=&quot;buglist.cgi&quot;
+              onsubmit=&quot;return checkQuicksearch(this);&quot;&gt;
+          &lt;div&gt;
+            &lt;input id=&quot;quicksearch_main&quot; type=&quot;text&quot; name=&quot;quicksearch&quot;
+              title=&quot;Quick Search&quot; 
+              onfocus=&quot;quicksearchHelpText(this.id, 'hide');&quot;
+              onblur=&quot;quicksearchHelpText(this.id, 'show');&quot;
+            &gt;
+            &lt;input id=&quot;find&quot; type=&quot;submit&quot; value=&quot;Quick Search&quot;&gt;
+            &lt;ul class=&quot;additional_links&quot; id=&quot;quicksearch_links&quot;&gt;
+              &lt;li&gt;
+                &lt;a href=&quot;page.cgi?id=quicksearch.html&quot;&gt;Quick Search help&lt;/a&gt;
+              &lt;/li&gt;
+              &lt;li class=&quot;bz_default_hidden&quot; id=&quot;quicksearch_plugin&quot;&gt;
+                |
+                &lt;a href=&quot;javascript:window.external.AddSearchProvider('[% urlbase FILTER html %]search_plugin.cgi')&quot;&gt;
+                 Install the Quick Search plugin
+                &lt;/a&gt;
+              &lt;/li&gt;
+            &lt;/ul&gt;
+            &lt;ul class=&quot;additional_links&quot;&gt;
+              &lt;li&gt;
+                &lt;a href=&quot;[% docs_urlbase FILTER html %]using.html&quot;&gt;
+                  [%- terms.Bugzilla %] User's Guide&lt;/a&gt;
+              &lt;/li&gt;
+              &lt;li&gt;
+                |
+                &lt;a href=&quot;page.cgi?id=release-notes.html&quot;&gt;Release Notes&lt;/a&gt;
+              &lt;/li&gt;
+              [% Hook.process('additional_links') %]
+            &lt;/ul&gt;
+          &lt;/div&gt;
+        &lt;/form&gt;
+        &lt;div class=&quot;outro&quot;&gt;[% Hook.process('outro') %]&lt;/div&gt;
+      &lt;/td&gt;
+    &lt;/tr&gt;
+  &lt;/table&gt;
</ins><span class="cx"> &lt;/div&gt;
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/footer.html.tmpl %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultlistchangecolumnshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/list/change-columns.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/list/change-columns.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/list/change-columns.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -16,12 +16,15 @@
</span><span class="cx">   # Rights Reserved.
</span><span class="cx">   #
</span><span class="cx">   # Contributor(s): Dave Lawrence &lt;dkl@redhat.com&gt;
</span><ins>+  #                 Pascal Held &lt;paheld@gmail.com&gt;
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/header.html.tmpl
</span><span class="cx">   title = &quot;Change Columns&quot;
</span><ins>+  javascript_urls = &quot;js/change-columns.js&quot;
+  onload = &quot;initChangeColumns()&quot;
</ins><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> &lt;p&gt;
</span><span class="lines">@@ -31,21 +34,76 @@
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS &quot;global/field-descs.none.tmpl&quot; %]
</span><span class="cx"> [% field_descs.short_short_desc     = &quot;Summary (first 60 characters)&quot; %]
</span><del>-[% field_descs.short_desc           = &quot;Full Summary&quot; %]
-[% field_descs.assigned_to_realname = &quot;Assignee Realname&quot; %]
-[% field_descs.reporter_realname    = &quot;Reporter Realname&quot; %]
-[% field_descs.qa_contact_realname  = &quot;QA Contact Realname&quot; %]
</del><ins>+[% field_descs.short_desc           = &quot;Summary (Full)&quot; %]
+[% field_descs.assigned_to_realname = &quot;$field_descs.assigned_to Real Name&quot; %]
+[% field_descs.reporter_realname    = &quot;$field_descs.reporter Real Name&quot; %]
+[% field_descs.qa_contact_realname  = &quot;$field_descs.qa_contact Real Name&quot; %]
</ins><span class="cx"> 
</span><del>-&lt;form action=&quot;colchange.cgi&quot;&gt;
</del><ins>+[%# Create a mapping of field descriptions to field names, so that
+  # the &quot;Available Columns&quot; list can be sorted alphabetically by
+  # field description.
+  #%]
+[% SET available_columns = {} %]
+[% FOREACH column = columns.keys %]
+  [% NEXT IF collist.contains(column) %]
+  [%# We lowecase the keys so that the sort happens case-insensitively. %]
+  [% SET column_desc = field_descs.$column || column FILTER lower %]
+  [% available_columns.$column_desc = column %]
+[% END %]
+
+&lt;form name=&quot;changecolumns&quot; action=&quot;colchange.cgi&quot; onsubmit=&quot;change_submit();&quot;&gt;
</ins><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;rememberedquery&quot; value=&quot;[% buffer FILTER html %]&quot;&gt;
</span><del>-  [% FOREACH column = masterlist %]
-    &lt;input type=&quot;checkbox&quot; id=&quot;[% column %]&quot; name=&quot;column_[% column %]&quot;
-      [%+ &quot;checked='checked'&quot; IF lsearch(collist, column) != -1 %]&gt;
-    &lt;label for=&quot;[% column %]&quot;&gt;
-      [% (field_descs.${column} || column) FILTER html %]
-    &lt;/label&gt;
-    &lt;br&gt;
-  [% END %]
</del><ins>+    &lt;table&gt;
+      &lt;tr&gt;
+        &lt;th&gt;&lt;div id=&quot;avail_header&quot; class=&quot;bz_default_hidden&quot;&gt;Available Columns&lt;/div&gt;&lt;/th&gt;
+        &lt;th&gt;&lt;/th&gt;
+        &lt;th colspan=&quot;2&quot;&gt;Selected Columns&lt;/th&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;
+          &lt;select name=&quot;available_columns&quot; id=&quot;available_columns&quot; 
+                  size=&quot;15&quot; multiple=&quot;multiple&quot; onchange=&quot;updateView();&quot;
+                  class=&quot;bz_default_hidden&quot;&gt; 
+          &lt;/select&gt;
+        &lt;/td&gt;
+        &lt;td&gt;
+          &lt;button type=&quot;button&quot; id=&quot;select_button&quot; name=&quot;select&quot;
+                  class=&quot;bz_default_hidden arrow_button&quot;
+                  onclick=&quot;move_select()&quot;&gt;&amp;rarr;&lt;/button&gt;
+          &lt;br&gt;&lt;br&gt;
+          &lt;button type=&quot;button&quot; id=&quot;deselect_button&quot; name=&quot;deselect&quot;
+                  class=&quot;bz_default_hidden arrow_button&quot;
+                  onclick=&quot;move_deselect()&quot;&gt;&amp;larr;&lt;/button&gt;
+        &lt;/td&gt;
+        &lt;td&gt;
+          &lt;select name=&quot;selected_columns&quot; id=&quot;selected_columns&quot; 
+                  size=&quot;15&quot; multiple=&quot;multiple&quot; onchange=&quot;updateView();&quot;&gt;
+            [% FOREACH column = collist %]
+                &lt;option value=&quot;[% column FILTER html %]&quot; selected=&quot;selected&quot;&gt;
+                [% (field_descs.${column} || column) FILTER html %]
+              &lt;/option&gt;
+            [% END %]
+            [% FOREACH key = available_columns.keys.sort %]
+              [% SET column = available_columns.$key %]
+              &lt;option value=&quot;[% column FILTER html %]&quot;&gt;
+                [%# Don't display the lower-cased column description,
+                  # display the correct-case one. %]
+                [% (field_descs.$column || column) FILTER html %]
+              &lt;/option&gt;
+            [% END %]
+          &lt;/select&gt;
+        &lt;/td&gt;
+        &lt;td&gt;
+          &lt;button type=&quot;button&quot; id=&quot;up_button&quot; name=&quot;up&quot;
+                  class=&quot;bz_default_hidden arrow_button&quot;
+                  onclick=&quot;move_up()&quot;&gt;&amp;uarr;&lt;/button&gt;
+          &lt;br&gt;&lt;br&gt;
+          &lt;button type=&quot;button&quot; id=&quot;down_button&quot; name=&quot;down&quot;
+                  class=&quot;bz_default_hidden arrow_button&quot;
+                  onclick=&quot;move_down()&quot;&gt;&amp;darr;&lt;/button&gt;
+        &lt;/td&gt;
+      &lt;/tr&gt;
+    &lt;/table&gt;
</ins><span class="cx"> 
</span><span class="cx">   &lt;p&gt;
</span><span class="cx">     &lt;input id=&quot;nosplitheader&quot; type=&quot;radio&quot; name=&quot;splitheader&quot; value=&quot;0&quot;
</span><span class="lines">@@ -66,11 +124,16 @@
</span><span class="cx">     &lt;p&gt;
</span><span class="cx">       &lt;input type=&quot;hidden&quot; name=&quot;saved_search&quot;
</span><span class="cx">              value=&quot;[% saved_search.id FILTER html%]&quot; &gt;
</span><ins>+      &lt;input type=&quot;hidden&quot; name=&quot;token&quot;
+             value=&quot;[% issue_hash_token([saved_search.id, saved_search.name]) FILTER html %]&quot;&gt;
</ins><span class="cx">       &lt;input type=&quot;checkbox&quot; id=&quot;save_columns_for_search&quot; checked=&quot;checked&quot; 
</span><span class="cx">              name=&quot;save_columns_for_search&quot; value=&quot;1&quot;&gt;
</span><span class="cx">       &lt;label for=&quot;save_columns_for_search&quot;&gt;Save this column list only 
</span><span class="cx">         for search '[% saved_search.name FILTER html %]'&lt;/label&gt;
</span><span class="cx">     &lt;/p&gt;
</span><ins>+  [% ELSE %]
+    &lt;input type=&quot;hidden&quot; name=&quot;token&quot;
+           value=&quot;[% issue_hash_token(['default-list']) FILTER html %]&quot;&gt;
</ins><span class="cx">   [% END %]
</span><span class="cx"> 
</span><span class="cx">   &lt;p&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultlisteditmultiplehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/list/edit-multiple.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/list/edit-multiple.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/list/edit-multiple.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -19,6 +19,7 @@
</span><span class="cx">   #                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
</span><span class="cx">   #                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
</span><span class="cx">   #                 Guy Pyrzak &lt;guy.pyrzak@gmail.com&gt;
</span><ins>+  #                 Reed Loden &lt;reed@reedloden.com&gt;
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="lines">@@ -28,12 +29,15 @@
</span><span class="cx"> &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% token FILTER html %]&quot;&gt;
</span><span class="cx"> 
</span><span class="cx"> &lt;script type=&quot;text/javascript&quot;&gt;
</span><del>-  var numelements = document.forms.changeform.elements.length;
</del><span class="cx">   function SetCheckboxes(value) {
</span><del>-      var item;
-      for (var i=0 ; i&lt;numelements ; i++) {
-          item = document.forms.changeform.elements[i];
-          item.checked = value;
</del><ins>+      var elements = document.forms.changeform.getElementsByTagName('input'),
+          numelements = elements.length,
+          item, i;
+      for (i = 0; i &lt; numelements; i++) {
+          item = elements[i];
+          if (item.type === 'checkbox' &amp;&amp; item.name.match(/^id_/)) {
+            item.checked = value;
+          }
</ins><span class="cx">       }
</span><span class="cx">   }
</span><span class="cx">   document.write(' &lt;input type=&quot;button&quot; name=&quot;uncheck_all&quot; value=&quot;Uncheck All&quot; onclick=&quot;SetCheckboxes(false);&quot;&gt;');
</span><span class="lines">@@ -137,7 +141,7 @@
</span><span class="cx">     &lt;th&gt;&lt;label for=&quot;bug_status&quot;&gt;Status:&lt;/label&gt;&lt;/th&gt;
</span><span class="cx">     &lt;td colspan=&quot;3&quot;&gt;[% PROCESS status_section %]&lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><del>-  [% IF user.in_group(Param(&quot;timetrackinggroup&quot;)) %]
</del><ins>+  [% IF user.is_timetracker %]
</ins><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th&gt;&lt;label for=&quot;estimated_time&quot;&gt;Estimated Hours:&lt;/label&gt;&lt;/th&gt;
</span><span class="cx">       &lt;td&gt;
</span><span class="lines">@@ -146,13 +150,9 @@
</span><span class="cx">                value=&quot;[% dontchange FILTER html %]&quot;
</span><span class="cx">                size=&quot;6&quot;&gt;
</span><span class="cx">       &lt;/td&gt;
</span><del>-      &lt;th&gt;&lt;label for=&quot;deadline&quot;&gt;Deadline (YYYY-MM-DD):&lt;/label&gt;&lt;/th&gt;
-      &lt;td&gt;
-        &lt;input id=&quot;deadline&quot;
-               name=&quot;deadline&quot;
-               value=&quot;[% dontchange FILTER html %]&quot;
-               size=&quot;10&quot;&gt;
-      &lt;/td&gt;
</del><ins>+      [% PROCESS bug/field.html.tmpl 
+          field = bug_fields.deadline, value = dontchange
+          editable = 1, allow_dont_change = 1 %]
</ins><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th&gt;&lt;label for=&quot;remaining_time&quot;&gt;Remaining Hours:&lt;/label&gt;&lt;/th&gt;
</span><span class="lines">@@ -174,7 +174,7 @@
</span><span class="cx">            id =&gt; &quot;assigned_to&quot;
</span><span class="cx">            name =&gt; &quot;assigned_to&quot;
</span><span class="cx">            value =&gt; dontchange
</span><del>-           size =&gt; 32
</del><ins>+           size =&gt; 40
</ins><span class="cx">       %]
</span><span class="cx">       &lt;input type=&quot;checkbox&quot; id=&quot;set_default_assignee&quot; name=&quot;set_default_assignee&quot; value=&quot;1&quot;&gt;
</span><span class="cx">       &lt;label for=&quot;set_default_assignee&quot;&gt;Reset Assignee to default&lt;/label&gt;
</span><span class="lines">@@ -189,7 +189,7 @@
</span><span class="cx">              id =&gt; &quot;qa_contact&quot;
</span><span class="cx">              name =&gt; &quot;qa_contact&quot;
</span><span class="cx">              value =&gt; dontchange
</span><del>-             size =&gt; 32
</del><ins>+             size =&gt; 40
</ins><span class="cx">         %]
</span><span class="cx">         &lt;input type=&quot;checkbox&quot; id=&quot;set_default_qa_contact&quot; name=&quot;set_default_qa_contact&quot; value=&quot;1&quot;&gt;
</span><span class="cx">         &lt;label for=&quot;set_default_qa_contact&quot;&gt;Reset QA Contact to default&lt;/label&gt;
</span><span class="lines">@@ -201,7 +201,13 @@
</span><span class="cx"> 
</span><span class="cx">     &lt;th&gt;&lt;label for=&quot;masscc&quot;&gt;CC List:&lt;/label&gt;&lt;/th&gt;
</span><span class="cx">     &lt;td colspan=&quot;3&quot;&gt;
</span><del>-      &lt;input id=&quot;masscc&quot; name=&quot;masscc&quot; size=&quot;32&quot;&gt;
</del><ins>+      [% INCLUDE global/userselect.html.tmpl
+           id =&gt; &quot;masscc&quot;
+           name =&gt; &quot;masscc&quot;
+           value =&gt; &quot;&quot;
+           size =&gt; 40
+           multiple =&gt; 5
+      %]
</ins><span class="cx">       &lt;select name=&quot;ccaction&quot;&gt;
</span><span class="cx">         &lt;option value=&quot;add&quot;&gt;Add these to the CC List&lt;/option&gt;
</span><span class="cx">         &lt;option value=&quot;remove&quot;&gt;Remove these from the CC List&lt;/option&gt;
</span><span class="lines">@@ -213,23 +219,55 @@
</span><span class="cx">   [% IF use_keywords %]
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx"> 
</span><del>-      &lt;th&gt;
-        &lt;label for=&quot;keywords&quot;&gt;
-          &lt;a href=&quot;describekeywords.cgi&quot;&gt;Keywords&lt;/a&gt;:
-        &lt;/label&gt;
-      &lt;/th&gt;
</del><ins>+      [% INCLUDE &quot;bug/field-label.html.tmpl&quot;
+         field = bug_fields.keywords, editable = 1
+         desc_url = &quot;describekeywords.cgi&quot;
+      %]
</ins><span class="cx">       &lt;td colspan=&quot;3&quot;&gt;
</span><del>-        &lt;input id=&quot;keywords&quot; name=&quot;keywords&quot; size=&quot;32&quot;&gt;
</del><ins>+        [% INCLUDE bug/field.html.tmpl
+           field = bug_fields.keywords, editable = 1, value = keywords
+           no_tds = 1
+        %]
</ins><span class="cx">         &lt;select name=&quot;keywordaction&quot;&gt;
</span><span class="cx">           &lt;option value=&quot;add&quot;&gt;Add these keywords&lt;/option&gt;
</span><del>-          &lt;option value=&quot;delete&quot;&gt;Delete these keywords&lt;/option&gt;
-          &lt;option value=&quot;makeexact&quot;&gt;Make the keywords be exactly this list&lt;/option&gt;
</del><ins>+          &lt;option value=&quot;remove&quot;&gt;Delete these keywords&lt;/option&gt;
+          &lt;option value=&quot;set&quot;&gt;Make the keywords be exactly this list&lt;/option&gt;
</ins><span class="cx">         &lt;/select&gt;
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">   [% END %]
</span><span class="cx"> 
</span><ins>+  &lt;tr&gt;
+    &lt;th&gt;
+      &lt;label for=&quot;dependson&quot;&gt;
+          Depends On:
+      &lt;/label&gt;
+    &lt;/th&gt;
+    &lt;td colspan=&quot;3&quot;&gt;
+      &lt;input id=&quot;dependson&quot; name=&quot;dependson&quot; size=&quot;40&quot;&gt;
+      &lt;select name=&quot;dependson_action&quot;&gt;
+          &lt;option value=&quot;add&quot;&gt;Add these IDs&lt;/option&gt;
+          &lt;option value=&quot;remove&quot;&gt;Delete these IDs&lt;/option&gt;
+      &lt;/select&gt;
+    &lt;/td&gt;
+  &lt;/tr&gt;
+
+  &lt;tr&gt;
+    &lt;th&gt;
+      &lt;label for=&quot;blocked&quot;&gt;
+          Blocks:
+      &lt;/label&gt;
+    &lt;/th&gt;
+    &lt;td colspan=&quot;3&quot;&gt;
+      &lt;input id=&quot;blocked&quot; name=&quot;blocked&quot; size=&quot;40&quot;&gt;
+      &lt;select name=&quot;blocked_action&quot;&gt;
+          &lt;option value=&quot;add&quot;&gt;Add these IDs&lt;/option&gt;
+          &lt;option value=&quot;remove&quot;&gt;Delete these IDs&lt;/option&gt;
+      &lt;/select&gt;
+    &lt;/td&gt;
+  &lt;/tr&gt;
+
</ins><span class="cx">   [% IF Param('usestatuswhiteboard') %]
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;td align=&quot;right&quot;&gt;
</span><span class="lines">@@ -243,6 +281,8 @@
</span><span class="cx">   [% END %]
</span><span class="cx"> 
</span><span class="cx">   [% USE Bugzilla %]
</span><ins>+  [%# Show all legal values and all fields, ignoring visibility controls. %]
+  [% bug = 0 %]
</ins><span class="cx">   [% FOREACH field = Bugzilla.active_custom_fields %]
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       [% PROCESS bug/field.html.tmpl value = dontchange
</span><span class="lines">@@ -255,7 +295,17 @@
</span><span class="cx"> 
</span><span class="cx"> &lt;/table&gt;
</span><span class="cx"> 
</span><del>-&lt;b&gt;&lt;label for=&quot;comment&quot;&gt;Additional Comments:&lt;/label&gt;&lt;/b&gt;&lt;br&gt;
</del><ins>+&lt;b&gt;&lt;label for=&quot;comment&quot;&gt;Additional Comments:&lt;/label&gt;&lt;/b&gt;
+[% IF user.is_insider %]
+  &lt;input type=&quot;checkbox&quot; name=&quot;comment_is_private&quot; value=&quot;1&quot;
+         id=&quot;newcommentprivacy&quot;
+         onClick=&quot;updateCommentTagControl(this, form)&quot;/&gt;
+   &lt;label for=&quot;newcommentprivacy&quot;&gt;
+     Make comment private (visible only to members of the
+     &lt;strong&gt;[% Param('insidergroup') FILTER html %]&lt;/strong&gt; group)
+   &lt;/label&gt;
+[% END %]
+&lt;br&gt;
</ins><span class="cx"> [% INCLUDE global/textarea.html.tmpl
</span><span class="cx">   name    = 'comment'
</span><span class="cx">   id      = 'comment'
</span><span class="lines">@@ -264,12 +314,22 @@
</span><span class="cx">   cols    = constants.COMMENT_COLS
</span><span class="cx"> %]&lt;br&gt;
</span><span class="cx"> 
</span><ins>+[% Hook.process('before_groups') %]
+
</ins><span class="cx"> [% IF groups.size &gt; 0 %]
</span><span class="cx"> 
</span><ins>+  &lt;script type=&quot;text/javascript&quot;&gt;
+    function turn_off(myself, id) {
+        var other_checkbox = document.getElementById(id);
+        if (myself.checked &amp;&amp; other_checkbox) {
+            other_checkbox.checked = false;
+        }
+    }
+  &lt;/script&gt;
+
</ins><span class="cx">   &lt;b&gt;Groups:&lt;/b&gt;&lt;br&gt;
</span><span class="cx">   &lt;table border=&quot;1&quot;&gt;
</span><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;th&gt;Don't&lt;br&gt;change&lt;br&gt;this group&lt;br&gt;restriction&lt;/th&gt;
</del><span class="cx">       &lt;th&gt;Remove&lt;br&gt;[% terms.bugs %]&lt;br&gt;from this&lt;br&gt;group&lt;/th&gt;
</span><span class="cx">       &lt;th&gt;Add&lt;br&gt;[% terms.bugs %]&lt;br&gt;to this&lt;br&gt;group&lt;/th&gt;
</span><span class="cx">       &lt;th&gt;Group Name:&lt;/th&gt;
</span><span class="lines">@@ -278,14 +338,17 @@
</span><span class="cx">     [% FOREACH group = groups %]
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;td align=&quot;center&quot;&gt;
</span><del>-        &lt;input type=&quot;radio&quot; name=&quot;bit-[% group.id %]&quot; value=&quot;-1&quot; checked=&quot;checked&quot;&gt;
</del><ins>+        &lt;input type=&quot;checkbox&quot; name=&quot;defined_groups&quot; 
+               id=&quot;defined_group_[% group.id %]&quot;
+               value=&quot;[% group.name FILTER html %]&quot;
+               onchange=&quot;turn_off(this, 'group_[% group.id %]')&quot;&gt;
</ins><span class="cx">       &lt;/td&gt;
</span><del>-      &lt;td align=&quot;center&quot;&gt;
-        &lt;input type=&quot;radio&quot; name=&quot;bit-[% group.id %]&quot; value=&quot;0&quot;&gt;
-      &lt;/td&gt;
</del><span class="cx">       [% IF group.is_active %]
</span><span class="cx">         &lt;td align=&quot;center&quot;&gt;
</span><del>-          &lt;input type=&quot;radio&quot; name=&quot;bit-[% group.id %]&quot; value=&quot;1&quot;&gt;
</del><ins>+          &lt;input type=&quot;checkbox&quot; name=&quot;groups&quot; 
+                 id=&quot;group_[% group.id FILTER html %]&quot;
+                 value=&quot;[% group.name FILTER html %]&quot;
+                 onchange=&quot;turn_off(this, 'defined_group_[% group.id %]')&quot;&gt;
</ins><span class="cx">         &lt;/td&gt;
</span><span class="cx">       [% ELSE %]
</span><span class="cx">         &lt;td&gt;&amp;nbsp;&lt;/td&gt;
</span><span class="lines">@@ -308,12 +371,11 @@
</span><span class="cx">   [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% END %]
</span><ins>+
+[%+ Hook.process('after_groups') %]
+
</ins><span class="cx"> &lt;input type=&quot;submit&quot; id=&quot;commit&quot; value=&quot;Commit&quot;&gt;
</span><span class="cx"> 
</span><del>-[% IF Param('move-enabled') &amp;&amp; user.is_mover %]
-  &lt;input type=&quot;submit&quot; name=&quot;action&quot; id=&quot;action&quot; value=&quot;[% Param('move-button-text') %]&quot;&gt;
-[% END %]
-
</del><span class="cx"> [%############################################################################%]
</span><span class="cx"> [%# Select Menu Block                                                        #%]
</span><span class="cx"> [%############################################################################%]
</span><span class="lines">@@ -325,7 +387,7 @@
</span><span class="cx">     &lt;/option&gt;
</span><span class="cx">     [% FOREACH menuitem = menuitems %]
</span><span class="cx">       [% IF property %][% menuitem = menuitem.$property %][% END %]
</span><del>-      &lt;option value=&quot;[% menuitem FILTER html %]&quot;&gt;[% menuitem FILTER html %]&lt;/option&gt;
</del><ins>+      &lt;option value=&quot;[% menuitem FILTER html %]&quot;&gt;[% display_value(menuname, menuitem) FILTER html %]&lt;/option&gt;
</ins><span class="cx">     [% END %]
</span><span class="cx">   &lt;/select&gt;
</span><span class="cx"> [% END %]
</span><span class="lines">@@ -344,7 +406,7 @@
</span><span class="cx">   
</span><span class="cx">     [% FOREACH bug_status = new_bug_statuses %]
</span><span class="cx">       &lt;option value=&quot;[% bug_status.name FILTER html %]&quot;&gt;
</span><del>-        [% get_status(bug_status.name) FILTER html %]
</del><ins>+        [% display_value(&quot;bug_status&quot;, bug_status.name) FILTER html %]
</ins><span class="cx">       &lt;/option&gt;
</span><span class="cx">       [% IF !bug_status.is_open %]
</span><span class="cx">         [% filtered_status =  bug_status.name FILTER js %]
</span><span class="lines">@@ -365,7 +427,7 @@
</span><span class="cx">     [% FOREACH r = resolutions %]
</span><span class="cx">       [% NEXT IF !r %]
</span><span class="cx">       [% NEXT IF r == &quot;DUPLICATE&quot; || r == &quot;MOVED&quot; %]
</span><del>-      &lt;option value=&quot;[% r FILTER html %]&quot;&gt;[% get_resolution(r) FILTER html %]&lt;/option&gt;
</del><ins>+      &lt;option value=&quot;[% r FILTER html %]&quot;&gt;[% display_value(&quot;resolution&quot;, r) FILTER html %]&lt;/option&gt;
</ins><span class="cx">     [% END %]
</span><span class="cx">   &lt;/select&gt;
</span><span class="cx">   &lt;/span&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultlistlistsimplehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/list/list-simple.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/list/list-simple.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/list/list-simple.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -39,7 +39,8 @@
</span><span class="cx">   &lt;head&gt;
</span><span class="cx">     &lt;title&gt;[% title FILTER html %]&lt;/title&gt;
</span><span class="cx">     &lt;base href=&quot;[% urlbase FILTER html %]&quot;&gt;
</span><del>-    &lt;link href=&quot;skins/standard/buglist.css&quot; rel=&quot;stylesheet&quot; type=&quot;text/css&quot;&gt;
</del><ins>+    &lt;link href=&quot;[% 'skins/standard/buglist.css' FILTER mtime %]&quot; 
+          rel=&quot;stylesheet&quot; type=&quot;text/css&quot;&gt;
</ins><span class="cx">   &lt;/head&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;body&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultlistlistatomtmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/list/list.atom.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/list/list.atom.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/list/list.atom.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -23,8 +23,7 @@
</span><span class="cx">   # This is a template for generating an Atom representation of a buglist. 
</span><span class="cx">   #%]
</span><span class="cx"> 
</span><del>-[% PROCESS global/variables.none.tmpl %]
-[% USE date %]
</del><ins>+[% PROCESS &quot;global/field-descs.none.tmpl&quot; %]
</ins><span class="cx"> 
</span><span class="cx"> [% DEFAULT title = &quot;$terms.Bugzilla $terms.Bugs&quot; %]
</span><span class="cx"> 
</span><span class="lines">@@ -37,9 +36,8 @@
</span><span class="cx">   &lt;link rel=&quot;self&quot; type=&quot;application/atom+xml&quot;
</span><span class="cx">         href=&quot;[% urlbase FILTER html %]buglist.cgi?
</span><span class="cx">         [%- urlquerypart FILTER xml %]&quot;/&gt;
</span><del>-  &lt;updated&gt;[% date.format(format=&gt;&quot;%Y-%m-%dT%H:%M:%SZ&quot;,
-              time=&gt;bugs.nsort('changedtime').last.changedtime,
-              gmt=&gt;1) FILTER xml %]&lt;/updated&gt;
</del><ins>+  &lt;updated&gt;[% bugs.sort('changedtime').last.changedtime FILTER time(&quot;%Y-%m-%dT%H:%M:%SZ&quot;, &quot;UTC&quot;)
+    FILTER xml %]&lt;/updated&gt;
</ins><span class="cx">   &lt;id&gt;[% urlbase FILTER html %]buglist.cgi?[% urlquerypart FILTER xml %]&lt;/id&gt;
</span><span class="cx"> 
</span><span class="cx">   [% FOREACH bug = bugs %]
</span><span class="lines">@@ -50,10 +48,9 @@
</span><span class="cx">           [%- bug.bug_id FILTER xml %]&quot;/&gt;
</span><span class="cx">     &lt;id&gt;[% urlbase FILTER xml %]show_bug.cgi?id=[% bug.bug_id FILTER xml %]&lt;/id&gt;
</span><span class="cx">     &lt;author&gt;
</span><del>-      &lt;name&gt;[% bug.reporter_realname FILTER xml %]&lt;/name&gt;
</del><ins>+      &lt;name&gt;[% bug.reporter_realname ? bug.reporter_realname : bug.reporter FILTER xml %]&lt;/name&gt;
</ins><span class="cx">     &lt;/author&gt;
</span><del>-    &lt;updated&gt;[% date.format(format=&gt;&quot;%Y-%m-%dT%H:%M:%SZ&quot;,time=&gt;bug.changedtime,
-                gmt=&gt;1) FILTER xml %]&lt;/updated&gt; 
</del><ins>+    &lt;updated&gt;[% bug.changedtime FILTER time(&quot;%Y-%m-%dT%H:%M:%SZ&quot;, &quot;UTC&quot;) FILTER xml %]&lt;/updated&gt;
</ins><span class="cx">     &lt;summary type=&quot;html&quot;&gt;
</span><span class="cx">       [%# Filter out the entire block, so that we don't need to escape the html code out %]
</span><span class="cx">       [% FILTER xml %]
</span><span class="lines">@@ -68,22 +65,22 @@
</span><span class="cx">         &lt;td&gt;[% bug.component FILTER html %]&lt;/td&gt;
</span><span class="cx">       &lt;/tr&gt;&lt;tr class=&quot;bz_feed_assignee&quot;&gt;
</span><span class="cx">         &lt;td&gt;[% columns.assigned_to_realname.title FILTER html %]&lt;/td&gt;
</span><del>-        &lt;td&gt;[% bug.assigned_to_realname FILTER html %]&lt;/td&gt;
</del><ins>+        &lt;td&gt;[% bug.assigned_to_realname ? bug.assigned_to_realname : bug.assigned_to FILTER html %]&lt;/td&gt;
</ins><span class="cx">       &lt;/tr&gt;&lt;tr class=&quot;bz_feed_reporter&quot;&gt;
</span><span class="cx">         &lt;td&gt;[% columns.reporter_realname.title FILTER html %]&lt;/td&gt;
</span><del>-        &lt;td&gt;[% bug.reporter_realname FILTER html %]&lt;/td&gt;
</del><ins>+        &lt;td&gt;[% bug.reporter_realname ? bug.reporter_realname : bug.reporter FILTER html %]&lt;/td&gt;
</ins><span class="cx">       &lt;/tr&gt;&lt;tr class=&quot;bz_feed_bug_status&quot;&gt;
</span><span class="cx">         &lt;td&gt;[% columns.bug_status.title FILTER html %]&lt;/td&gt;
</span><del>-        &lt;td&gt;[% bug.bug_status FILTER html %]&lt;/td&gt;
</del><ins>+        &lt;td&gt;[% display_value(&quot;bug_status&quot;, bug.bug_status) FILTER html %]&lt;/td&gt;
</ins><span class="cx">       &lt;/tr&gt;&lt;tr class=&quot;bz_feed_resolution&quot;&gt;
</span><span class="cx">         &lt;td&gt;[% columns.resolution.title FILTER html %] &lt;/td&gt;
</span><del>-        &lt;td&gt;[% bug.resolution FILTER html %]&lt;/td&gt;
</del><ins>+        &lt;td&gt;[% display_value(&quot;resolution&quot;, bug.resolution) FILTER html %]&lt;/td&gt;
</ins><span class="cx">       &lt;/tr&gt;&lt;tr class=&quot;bz_feed_priority&quot;&gt;
</span><span class="cx">         &lt;td&gt;[% columns.priority.title FILTER html %]&lt;/td&gt;
</span><del>-        &lt;td&gt;[% bug.priority FILTER html %]&lt;/td&gt;
</del><ins>+        &lt;td&gt;[% display_value(&quot;priority&quot;, bug.priority) FILTER html %]&lt;/td&gt;
</ins><span class="cx">       &lt;/tr&gt;&lt;tr class=&quot;bz_feed_severity&quot;&gt;
</span><span class="cx">         &lt;td&gt;[% columns.bug_severity.title FILTER html %] &lt;/td&gt;
</span><del>-        &lt;td&gt;[% bug.bug_severity FILTER html %]&lt;/td&gt;
</del><ins>+        &lt;td&gt;[% display_value(&quot;bug_severity&quot;, bug.bug_severity) FILTER html %]&lt;/td&gt;
</ins><span class="cx">       [% IF Param(&quot;usetargetmilestone&quot;) %]
</span><span class="cx">       &lt;/tr&gt;&lt;tr class=&quot;bz_feed_target_milestone&quot;&gt;
</span><span class="cx">         &lt;td&gt;[% columns.target_milestone.title FILTER html %]&lt;/td&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultlistlistcsvtmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/list/list.csv.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/list/list.csv.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/list/list.csv.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -17,16 +17,23 @@
</span><span class="cx">   #
</span><span class="cx">   # Contributor(s): Myk Melez &lt;myk@mozilla.org&gt;
</span><span class="cx">   #                 Gervase Markham &lt;gerv@gerv.net&gt;
</span><ins>+  #                 miketosh
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS &quot;global/field-descs.none.tmpl&quot; %]
</span><del>-[% USE date %]
</del><span class="cx"> 
</span><span class="cx"> [% colsepchar = user.settings.csv_colsepchar.value %]
</span><span class="cx"> 
</span><del>-bug_id
-[% FOREACH column = displaycolumns %]
-  [% colsepchar %][% column FILTER csv %]
</del><ins>+[% IF human %]
+  [% field_descs.bug_id FILTER csv %]
+  [% FOREACH column = displaycolumns %]
+    [% colsepchar %][% field_descs.$column FILTER csv %]
+  [% END %]
+[% ELSE %]
+  bug_id
+  [% FOREACH column = displaycolumns %]
+    [% colsepchar %][% column FILTER csv %]
+  [% END %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% FOREACH bug = bugs %]
</span><span class="lines">@@ -35,11 +42,11 @@
</span><span class="cx">       [% colsepchar %]
</span><span class="cx">       [% IF column == &quot;opendate&quot; OR column == &quot;changeddate&quot; %]
</span><span class="cx">         [% rawcolumn = column.replace(&quot;date&quot;, &quot;time&quot;) %]
</span><del>-        [% bug.$column = date.format(bug.$rawcolumn, &quot;%Y-%m-%d %H:%M:%S&quot;) %]
</del><ins>+        [% bug.$column = bug.$rawcolumn FILTER time(&quot;%Y-%m-%d %H:%M:%S&quot;) %]
</ins><span class="cx">       [% ELSIF column == 'bug_status' %]
</span><del>-        [% bug.$column = get_status(bug.$column) %]
</del><ins>+        [% bug.$column = display_value(&quot;bug_status&quot;, bug.$column) %]
</ins><span class="cx">       [% ELSIF column == 'resolution' %]
</span><del>-        [%- bug.$column = get_resolution(bug.$column) %]
</del><ins>+        [%- bug.$column = display_value(&quot;resolution&quot;, bug.$column) %]
</ins><span class="cx">       [% END %]
</span><span class="cx">       [% bug.$column FILTER csv %]
</span><span class="cx">     [% END %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultlistlisthtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/list/list.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/list/list.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/list/list.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -28,14 +28,14 @@
</span><span class="cx"> [%# Template Initialization                                                  #%]
</span><span class="cx"> [%############################################################################%]
</span><span class="cx"> 
</span><del>-[% PROCESS global/variables.none.tmpl %]
</del><ins>+[% PROCESS &quot;global/field-descs.none.tmpl&quot; %]
</ins><span class="cx"> 
</span><span class="cx"> [% title = &quot;$terms.Bug List&quot; %]
</span><span class="cx"> [% IF searchname || defaultsavename %]
</span><span class="cx">   [% title = title _ &quot;: &quot; _ (searchname OR defaultsavename) FILTER html %]
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><del>-[% qorder = order FILTER url_quote IF order %]
</del><ins>+[% qorder = order FILTER uri IF order %]
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> [%############################################################################%]
</span><span class="lines">@@ -46,34 +46,28 @@
</span><span class="cx">   title = title
</span><span class="cx">   style = style
</span><span class="cx">   atomlink = &quot;buglist.cgi?$urlquerypart&amp;title=$title&amp;ctype=atom&quot; 
</span><del>-  javascript_urls = [ &quot;js/util.js&quot;, &quot;js/field.js&quot;,
-                      &quot;js/yui/yahoo-dom-event.js&quot;, &quot;js/yui/calendar.js&quot; ]
-  style_urls = [ &quot;skins/standard/buglist.css&quot;, &quot;skins/standard/yui/calendar.css&quot; ]
</del><ins>+  yui = [ 'autocomplete', 'calendar' ]
+  javascript_urls = [ &quot;js/util.js&quot;, &quot;js/field.js&quot; ]
+  style_urls = [ &quot;skins/standard/buglist.css&quot; ]
</ins><span class="cx">   doc_section = &quot;query.html#list&quot;
</span><span class="cx"> %]
</span><span class="cx"> 
</span><del>-&lt;div class=&quot;bz_query_head&quot; align=&quot;center&quot;&gt;
</del><ins>+&lt;div class=&quot;bz_query_head&quot;&gt;
</ins><span class="cx">   &lt;span class=&quot;bz_query_timestamp&quot;&gt;
</span><del>-    [% IF Param('timezone') %]
-      &lt;b&gt;[% time2str(&quot;%a %b %e %Y %T %Z&quot;, currenttime, Param('timezone')) %]&lt;/b&gt;&lt;br&gt;
-    [% ELSE %]
-      &lt;b&gt;[% time2str(&quot;%a %b %e %Y %T&quot;, currenttime) %]&lt;/b&gt;&lt;br&gt;
-    [% END %]
</del><ins>+    [% currenttime FILTER time('%a %b %e %Y %T %Z') FILTER html %]&lt;br&gt;
</ins><span class="cx">   &lt;/span&gt;
</span><span class="cx"> 
</span><span class="cx">   [% IF debug %]
</span><del>-    &lt;p class=&quot;bz_query_debug&quot;&gt;
-      [% FOREACH debugline = debugdata %]
-        [% debugline FILTER html %]&lt;br&gt;
-      [% END %]
-    &lt;/p&gt;
</del><span class="cx">     &lt;p class=&quot;bz_query&quot;&gt;[% query FILTER html %]&lt;/p&gt;
</span><ins>+    [% IF query_explain.defined %]
+      &lt;pre class=&quot;bz_query_explain&quot;&gt;[% query_explain FILTER html %]&lt;/pre&gt;
+    [% END %]
</ins><span class="cx">   [% END %]
</span><span class="cx"> 
</span><span class="cx">   [% IF user.settings.display_quips.value == 'on' %]
</span><span class="cx">     [% DEFAULT quip = &quot;$terms.Bugzilla would like to put a random quip here, but no one has entered any.&quot; %]
</span><span class="cx">     &lt;span class=&quot;bz_quip&quot;&gt;
</span><del>-      &lt;a href=&quot;quips.cgi&quot;&gt;&lt;i&gt;[% quip FILTER html %]&lt;/i&gt;&lt;/a&gt;
</del><ins>+      &lt;a href=&quot;quips.cgi&quot;&gt;&lt;em&gt;[% quip FILTER html %]&lt;/em&gt;&lt;/a&gt;
</ins><span class="cx">     &lt;/span&gt;
</span><span class="cx">   [% END %]
</span><span class="cx"> 
</span><span class="lines">@@ -86,6 +80,29 @@
</span><span class="cx">   &lt;/h2&gt;
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><ins>+[% SET shown_types = [
+  'notequals', 'regexp', 'notregexp', 'lessthan', 'lessthaneq', 
+  'greaterthan', 'greaterthaneq', 'changedbefore', 'changedafter', 
+  'changedfrom', 'changedto', 'changedby', 'notsubstring', 'nowords',
+  'nowordssubstr', 'notmatches',
+] %]
+&lt;ul class=&quot;search_description&quot;&gt;
+[% FOREACH desc_item = search_description %]
+  &lt;li&gt;
+    &lt;strong&gt;[% field_descs.${desc_item.field} FILTER html %]:&lt;/strong&gt;
+    [% IF shown_types.contains(desc_item.type) || debug %]
+      ([% search_descs.${desc_item.type} FILTER html %])
+    [% END %]
+    [% FOREACH val IN desc_item.value.split(',') %]
+      [%+ display_value(desc_item.field, val) FILTER html %][% ',' UNLESS loop.last %]
+    [% END %]
+    [% IF debug %]
+      (&lt;code&gt;[% desc_item.term FILTER html %]&lt;/code&gt;)
+   [% END %]
+  &lt;/li&gt;
+[% END %]
+&lt;/ul&gt;
+
</ins><span class="cx"> &lt;hr&gt;
</span><span class="cx"> 
</span><span class="cx"> [%############################################################################%]
</span><span class="lines">@@ -93,9 +110,7 @@
</span><span class="cx"> [%############################################################################%]
</span><span class="cx"> 
</span><span class="cx"> [% IF bugs.size &gt; 9 %]
</span><del>-  &lt;span class=&quot;bz_result_count&quot;&gt;
-    [% bugs.size %] [%+ terms.bugs %] found.
-  &lt;/span&gt;
</del><ins>+  [% PROCESS num_results %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [%############################################################################%]
</span><span class="lines">@@ -117,16 +132,20 @@
</span><span class="cx"> [%# Succeeding Status Line                                                   #%]
</span><span class="cx"> [%############################################################################%]
</span><span class="cx"> 
</span><del>-&lt;span class=&quot;bz_result_count&quot;&gt;
-  [% IF bugs.size == 0 %]
-    [% terms.zeroSearchResults %].
-  [% ELSIF bugs.size == 1 %]
-    One [% terms.bug %] found.
-  [% ELSE %]
-    [% bugs.size %] [%+ terms.bugs %] found.
-  [% END %]
-&lt;/span&gt;
</del><ins>+[% PROCESS num_results %]
</ins><span class="cx"> 
</span><ins>+[% IF bugs.size == 0 %]
+  &lt;ul class=&quot;zero_result_links&quot;&gt;
+    &lt;li&gt;[% PROCESS enter_bug_link %]&lt;/li&gt;
+    [% IF one_product.defined %]
+      &lt;li&gt;&lt;a href=&quot;enter_bug.cgi&quot;&gt;File a new [% terms.bug %] in a
+        different product&lt;/a&gt;&lt;/li&gt;
+    [% END %]
+    &lt;li&gt;&lt;a href=&quot;[% PROCESS edit_search_url %]&quot;&gt;Edit this search&lt;/a&gt;&lt;/li&gt;
+    &lt;li&gt;&lt;a href=&quot;query.cgi&quot;&gt;Start a new search&lt;/a&gt;&lt;/li&gt;
+  &lt;/ul&gt;
+[% END %]
+
</ins><span class="cx"> &lt;br&gt;
</span><span class="cx"> 
</span><span class="cx"> [%############################################################################%]
</span><span class="lines">@@ -163,11 +182,19 @@
</span><span class="cx">             &lt;input type=&quot;submit&quot; value=&quot;XML&quot; id=&quot;xml&quot;&gt;
</span><span class="cx">         &lt;/form&gt;
</span><span class="cx"> 
</span><del>-        [% IF user.in_group(Param('timetrackinggroup')) %]
</del><ins>+        [% IF user.is_timetracker %]
</ins><span class="cx">           &lt;form method=&quot;post&quot; action=&quot;summarize_time.cgi&quot;&gt;
</span><span class="cx">             &lt;input type=&quot;hidden&quot; name=&quot;id&quot; value=&quot;[% buglist_joined FILTER html %]&quot;&gt;
</span><span class="cx">             &lt;input type=&quot;submit&quot; id=&quot;timesummary&quot; value=&quot;Time Summary&quot;&gt;
</span><span class="cx">           &lt;/form&gt;
</span><ins>+          [% IF time_summary_limited %]
+            &lt;small&gt;
+              Time Summary will only include the [% terms.bugs %] shown above. In order to
+              to see a time summary for all [% terms.bugs %] found by the search, you can
+              &lt;a href=&quot;buglist.cgi?[% urlquerypart FILTER html %]
+                       [%- &quot;&amp;order=$qorder&quot; FILTER html IF order %]&amp;limit=0&quot;&gt;
+                Show all search results&lt;/a&gt;.&lt;/small&gt;
+          [% END %]
</ins><span class="cx">         [% END %]
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">       
</span><span class="lines">@@ -175,7 +202,7 @@
</span><span class="cx">       
</span><span class="cx">       &lt;td valign=&quot;middle&quot; class=&quot;bz_query_links&quot;&gt;
</span><span class="cx">         &lt;a href=&quot;buglist.cgi?
</span><del>-        [% urlquerypart FILTER html %]&amp;amp;ctype=csv&quot;&gt;CSV&lt;/a&gt; |
</del><ins>+        [% urlquerypart FILTER html %]&amp;amp;ctype=csv&amp;amp;human=1&quot;&gt;CSV&lt;/a&gt; |
</ins><span class="cx">         &lt;a href=&quot;buglist.cgi?
</span><span class="cx">         [% urlquerypart FILTER html %]&amp;amp;title=
</span><span class="cx">         [%- title FILTER html %]&amp;amp;ctype=atom&quot;&gt;Feed&lt;/a&gt; |
</span><span class="lines">@@ -183,7 +210,7 @@
</span><span class="cx">         [% urlquerypart FILTER html %]&amp;amp;ctype=ics&quot;&gt;iCalendar&lt;/a&gt; |
</span><span class="cx">         &lt;a href=&quot;colchange.cgi?
</span><span class="cx">         [% urlquerypart FILTER html %]&amp;amp;query_based_on=
</span><del>-          [% defaultsavename OR searchname FILTER url_quote %]&quot;&gt;Change&amp;nbsp;Columns&lt;/a&gt; |
</del><ins>+          [% defaultsavename OR searchname FILTER uri %]&quot;&gt;Change&amp;nbsp;Columns&lt;/a&gt; |
</ins><span class="cx"> 
</span><span class="cx">         [% IF bugs.size &gt; 1 &amp;&amp; caneditbugs &amp;&amp; !dotweak %]
</span><span class="cx">           &lt;a href=&quot;buglist.cgi?[% urlquerypart FILTER html %]
</span><span class="lines">@@ -192,7 +219,7 @@
</span><span class="cx">           |
</span><span class="cx">         [% END %]
</span><span class="cx"> 
</span><del>-        [% IF bugowners %]
</del><ins>+        [% IF bugowners &amp;&amp; user.id %]
</ins><span class="cx">           &lt;a href=&quot;mailto:
</span><span class="cx">             [% bugowners FILTER html %]&quot;&gt;Send&amp;nbsp;Mail&amp;nbsp;to&amp;nbsp;[% terms.Bug %]&amp;nbsp;Assignees&lt;/a&gt; |
</span><span class="cx">         [% END %]
</span><span class="lines">@@ -203,19 +230,15 @@
</span><span class="cx">     [% END %]
</span><span class="cx">     
</span><span class="cx">     &lt;td valign=&quot;middle&quot; class=&quot;bz_query_edit&quot;&gt;
</span><del>-      [% editqueryname = searchname OR defaultsavename OR '' %]
-      &lt;a href=&quot;query.cgi?[% urlquerypart FILTER html %]
-      [% IF editqueryname != '' %]&amp;amp;known_name=
-        [% editqueryname FILTER url_quote %]
-      [% END %]&quot;&gt;Edit&amp;nbsp;Search&lt;/a&gt;
</del><ins>+      &lt;a href=&quot;[% PROCESS edit_search_url %]&quot;&gt;Edit&amp;nbsp;Search&lt;/a&gt;
</ins><span class="cx">     &lt;/td&gt;
</span><span class="cx">       
</span><span class="cx">     [% IF searchtype == &quot;saved&quot; %]
</span><span class="cx">       &lt;td valign=&quot;middle&quot; nowrap=&quot;nowrap&quot; class=&quot;bz_query_forget&quot;&gt;
</span><span class="cx">         |
</span><span class="cx">         &lt;a href=&quot;buglist.cgi?cmdtype=dorem&amp;amp;remaction=forget&amp;amp;namedcmd=
</span><del>-                [% searchname FILTER url_quote %]&amp;amp;token=
-                [% issue_hash_token([search_id, searchname]) FILTER url_quote %]&quot;&gt;
</del><ins>+                [% searchname FILTER uri %]&amp;amp;token=
+                [% issue_hash_token([search_id, searchname]) FILTER uri %]&quot;&gt;
</ins><span class="cx">           Forget&amp;nbsp;Search&amp;nbsp;'[% searchname FILTER html %]'&lt;/a&gt;
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">     [% ELSE %]
</span><span class="lines">@@ -228,18 +251,18 @@
</span><span class="cx">                  value=&quot;[% urlquerypart FILTER html %][% &quot;&amp;order=$qorder&quot; FILTER html IF order %]&quot;&gt;
</span><span class="cx">           &lt;input type=&quot;hidden&quot; name=&quot;cmdtype&quot; value=&quot;doit&quot;&gt;
</span><span class="cx">           &lt;input type=&quot;hidden&quot; name=&quot;remtype&quot; value=&quot;asnamed&quot;&gt;
</span><ins>+          &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% issue_hash_token(['savedsearch']) FILTER html %]&quot;&gt;
</ins><span class="cx">           &lt;input type=&quot;text&quot; id=&quot;save_newqueryname&quot; name=&quot;newqueryname&quot; size=&quot;20&quot;
</span><del>-                 value=&quot;[% defaultsavename FILTER html %]&quot;&gt; 
</del><ins>+                 title=&quot;New query name&quot; value=&quot;[% defaultsavename FILTER html %]&quot;&gt; 
</ins><span class="cx">         &lt;/form&gt; 
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">     [% END %]  
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> &lt;/table&gt;
</span><span class="cx"> 
</span><del>-[% IF cgi.param('product').size == 1 &amp;&amp; cgi.param('product') != &quot;&quot; %]
</del><ins>+[% IF one_product.defined &amp;&amp; bugs.size %]
</ins><span class="cx">   &lt;p class=&quot;bz_query_single_product&quot;&gt;
</span><del>-    &lt;a href=&quot;enter_bug.cgi?product=[% cgi.param('product') FILTER url_quote %]&quot;&gt;File
-      a new [% terms.bug %] in the &quot;[% cgi.param('product') FILTER html %]&quot; product&lt;/a&gt;
</del><ins>+    [% PROCESS enter_bug_link %]
</ins><span class="cx">   &lt;/p&gt;
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="lines">@@ -248,3 +271,44 @@
</span><span class="cx"> [%############################################################################%]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/footer.html.tmpl %]
</span><ins>+
+[%##########%]
+[%# Blocks #%]
+[%##########%]
+
+[% BLOCK edit_search_url %]
+  [% editqueryname = searchname OR defaultsavename OR '' %]
+  query.cgi?[% urlquerypart FILTER html %]
+    [%- IF editqueryname != '' %]&amp;amp;known_name=
+      [%- editqueryname FILTER uri %]
+    [% END %]
+[% END %]
+
+[% BLOCK enter_bug_link %]
+  &lt;a href=&quot;enter_bug.cgi
+           [%- IF one_product.defined %]?product=
+             [%- one_product.name FILTER uri %][% END %]&quot;&gt;File
+    a new [% terms.bug %]
+   [% IF one_product.defined %]
+     in the &quot;[% one_product.name FILTER html %]&quot; product
+   [% END %]&lt;/a&gt;
+[% END %]
+
+[% BLOCK num_results %]
+  &lt;span class=&quot;bz_result_count&quot;&gt;
+    [% IF bugs.size == 0 %]
+      &lt;span class=&quot;zero_results&quot;&gt;[% terms.zeroSearchResults %].&lt;/span&gt;
+    [% ELSIF default_limited AND bugs.size &gt;= Param('default_search_limit') %]
+      This result was limited to [% Param('default_search_limit') FILTER html %]
+      [%+ terms.bugs %].
+      &lt;a href=&quot;buglist.cgi?[% urlquerypart FILTER html %]
+              [%- &quot;&amp;order=$qorder&quot; FILTER html IF order %]&amp;limit=0&quot;&gt;See
+        all search results for this query&lt;/a&gt;.
+      [% time_summary_limited = 1 %]
+    [% ELSIF bugs.size == 1 %]
+      One [% terms.bug %] found.
+    [% ELSE %]
+      [% bugs.size %] [%+ terms.bugs %] found.
+    [% END %]
+  &lt;/span&gt;
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultlistlisticstmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/list/list.ics.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/list/list.ics.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/list/list.ics.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -30,8 +30,9 @@
</span><span class="cx"> [%+ PROCESS ics_url base_url=urlbase bug_id=bug.bug_id +%]
</span><span class="cx"> [%+ PROCESS ics_status bug_status = bug.bug_status +%]
</span><span class="cx"> [%+ PROCESS ics_dtstamp +%]
</span><ins>+[%+ ics_priorities.${bug.priority} FILTER ics('PRIORITY') +%]
</ins><span class="cx"> [% IF bug.changeddate %]
</span><del>-[%+ time2str(&quot;%Y%m%dT%H%M%SZ&quot;, bug.changedtime, &quot;UTC&quot;) FILTER ics('LAST-MODIFIED') +%]
</del><ins>+[%+ bug.changedtime FILTER time(&quot;%Y%m%dT%H%M%SZ&quot;, &quot;UTC&quot;) FILTER ics('LAST-MODIFIED') +%]
</ins><span class="cx"> [% END %]
</span><span class="cx"> [% IF bug.percentage_complete %]
</span><span class="cx"> [%+ bug.percentage_complete FILTER format('%d') FILTER ics('PERCENT-COMPLETE') +%]
</span><span class="lines">@@ -57,19 +58,19 @@
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK ics_uid %]
</span><del>-  [% &quot;${bug_id}@${base_url}&quot; FILTER url_quote FILTER ics('UID') %]
</del><ins>+  [% &quot;${bug_id}@${base_url}&quot; FILTER uri FILTER ics('UID') %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK ics_url %]
</span><del>-  [% &quot;${base_url}show_bug.cgi?id=${bug_id}&quot; FILTER url_quote FILTER ics('URL;VALUE=URI') %]
</del><ins>+  [% &quot;${base_url}show_bug.cgi?id=${bug_id}&quot; FILTER uri FILTER ics('URL;VALUE=URI') %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK ics_dtstart %]
</span><del>-  [% time2str(&quot;%Y%m%dT%H%M%SZ&quot;, bug.opentime, &quot;UTC&quot;) FILTER ics('DTSTART') %]
</del><ins>+  [% bug.opentime FILTER time(&quot;%Y%m%dT%H%M%SZ&quot;, &quot;UTC&quot;) FILTER ics('DTSTART') %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK ics_dtstamp %]
</span><del>-  [% time2str(&quot;%Y%m%dT%H%M%SZ&quot;, currenttime, &quot;UTC&quot;) FILTER ics('DTSTAMP') %]
</del><ins>+  [% currenttime FILTER time(&quot;%Y%m%dT%H%M%SZ&quot;, &quot;UTC&quot;) FILTER ics('DTSTAMP') %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK ics_status %]
</span><span class="lines">@@ -81,7 +82,7 @@
</span><span class="cx">     [% END %]
</span><span class="cx">   [% END %]
</span><span class="cx">   [% IF NOT status %]
</span><del>-    [% IF bug_status == 'ASSIGNED' %]
</del><ins>+    [% IF bug_status == 'IN_PROGRESS' || bug_status == 'ASSIGNED' %]
</ins><span class="cx">       [% status = 'IN-PROGRESS' %]
</span><span class="cx">     [% ELSE %]
</span><span class="cx">       [% status = 'NEEDS-ACTION' %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultlistlistjstmpl"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/template/en/default/list/list.js.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/list/list.js.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/list/list.js.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,37 +0,0 @@
</span><del>-[%# The contents of this file are subject to the Mozilla Public
-  # License Version 1.1 (the &quot;License&quot;); you may not use this file
-  # except in compliance with the License. You may obtain a copy of
-  # the License at http://www.mozilla.org/MPL/
-  #
-  # Software distributed under the License is distributed on an &quot;AS
-  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
-  # implied. See the License for the specific language governing
-  # rights and limitations under the License.
-  #
-  # The Original Code is the Bugzilla Bug Tracking System.
-  #
-  # The Initial Developer of the Original Code is Netscape Communications
-  # Corporation. Portions created by Netscape are
-  # Copyright (C) 1998 Netscape Communications Corporation. All
-  # Rights Reserved.
-  #
-  # Contributor(s): Gervase Markham &lt;gerv@gerv.net&gt;
-  #%]
-
-// Note: only publicly-accessible bugs (those not in any group) will be
-// listed when using this JavaScript format. This is to prevent malicious
-// sites stealing information about secure bugs.
-  
-bugs = new Array; 
-
-[% FOREACH bug = bugs %]
-  bugs[[% bug.bug_id %]] = [ 
-    [% FOREACH column = displaycolumns %]
-      &quot;[%- bug.$column FILTER js -%]&quot;[% &quot;,&quot; UNLESS loop.last %]
-    [% END %]
-  ];
-[% END %]
-
-if (window.buglistCallback) {
-  buglistCallback(bugs);
-}
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultlistlistrdftmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/list/list.rdf.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/list/list.rdf.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/list/list.rdf.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -27,6 +27,7 @@
</span><span class="cx"> 
</span><span class="cx"> &lt;bz:result rdf:about=&quot;[% urlbase FILTER xml %]buglist.cgi?[% urlquerypart FILTER html %]&quot;&gt;
</span><span class="cx">   &lt;bz:installation rdf:resource=&quot;[% urlbase FILTER xml %]&quot; /&gt;
</span><ins>+  &lt;bz:query_timestamp&gt;[% currenttime FILTER time('%Y-%m-%d %T %Z') FILTER html %]&lt;/bz:query_timestamp&gt;
</ins><span class="cx">   &lt;bz:bugs&gt;
</span><span class="cx">     &lt;Seq&gt;
</span><span class="cx">     [% FOREACH bug = bugs %]
</span><span class="lines">@@ -37,7 +38,7 @@
</span><span class="cx">           &lt;bz:id nc:parseType=&quot;Integer&quot;&gt;[% bug.bug_id %]&lt;/bz:id&gt;
</span><span class="cx">         
</span><span class="cx">         [% FOREACH column = displaycolumns %]
</span><del>-          &lt;bz:[% column %][% ' nc:parseType=&quot;Integer&quot;' IF column == &quot;votes&quot; %]&gt;[% bug.$column FILTER html %]&lt;/bz:[% column %]&gt;
</del><ins>+          &lt;bz:[% column %]&gt;[% bug.$column FILTER html %]&lt;/bz:[% column %]&gt;
</ins><span class="cx">         [% END %]
</span><span class="cx">         
</span><span class="cx">         &lt;/bz:bug&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultlistquipshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/list/quips.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/list/quips.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/list/quips.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -37,7 +37,7 @@
</span><span class="cx">   &lt;p&gt;
</span><span class="cx">     &lt;font color=&quot;red&quot;&gt;
</span><span class="cx">       Your quip '&lt;tt&gt;[% added_quip FILTER html %]&lt;/tt&gt;' has been added.
</span><del>-      [% IF Param(&quot;quip_list_entry_control&quot;) == &quot;moderated&quot; AND !user.groups.admin %]
</del><ins>+      [% IF Param(&quot;quip_list_entry_control&quot;) == &quot;moderated&quot; AND !user.in_group('bz_quip_moderators') %]
</ins><span class="cx">         It will be used as soon as it gets approved.
</span><span class="cx">       [% END %]
</span><span class="cx">     &lt;/font&gt;
</span><span class="lines">@@ -66,13 +66,15 @@
</span><span class="cx">   &lt;p&gt;
</span><span class="cx">     You can extend the quip list. Type in something clever or funny or boring
</span><span class="cx">     (but not obscene or offensive, please) and bonk on the button.
</span><del>-    [% IF Param(&quot;quip_list_entry_control&quot;) == &quot;moderated&quot; AND !user.groups.admin %]
</del><ins>+    [% IF Param(&quot;quip_list_entry_control&quot;) == &quot;moderated&quot; AND !user.in_group('bz_quip_moderators') %]
</ins><span class="cx">       Note that your quip has to be approved before it is used.
</span><span class="cx">     [% END %]
</span><span class="cx">   &lt;/p&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;form method=&quot;post&quot; action=&quot;quips.cgi&quot;&gt;
</span><span class="cx">     &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;add&quot;&gt;
</span><ins>+    &lt;input type=&quot;hidden&quot; name=&quot;token&quot;
+           value=&quot;[% issue_hash_token(['create-quips']) FILTER html %]&quot;&gt;
</ins><span class="cx">     &lt;input size=&quot;80&quot; name=&quot;quip&quot;&gt;
</span><span class="cx">     &lt;p&gt;
</span><span class="cx">       &lt;input type=&quot;submit&quot; id=&quot;add&quot; value=&quot;Add This Quip&quot;&gt;
</span><span class="lines">@@ -84,7 +86,7 @@
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% IF show_quips %]
</span><del>-  [% IF !user.in_group('admin') %]
</del><ins>+  [% IF !user.in_group('bz_quip_moderators') %]
</ins><span class="cx">     &lt;h2&gt;
</span><span class="cx">       Existing quips:
</span><span class="cx">     &lt;/h2&gt;
</span><span class="lines">@@ -103,6 +105,8 @@
</span><span class="cx">     &lt;/p&gt;
</span><span class="cx">     &lt;form name=&quot;editform&quot; method=&quot;post&quot; action=&quot;quips.cgi&quot;&gt;
</span><span class="cx">       &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;approve&quot;&gt;
</span><ins>+      &lt;input type=&quot;hidden&quot; name=&quot;token&quot;
+             value=&quot;[% issue_hash_token(['approve-quips']) FILTER html %]&quot;&gt;
</ins><span class="cx">       &lt;table border=&quot;1&quot;&gt;
</span><span class="cx">         &lt;thead&gt;&lt;tr&gt;
</span><span class="cx">           &lt;th&gt;Quip&lt;/th&gt;
</span><span class="lines">@@ -119,7 +123,8 @@
</span><span class="cx">               [% &quot;Unknown&quot; IF NOT users.$userid %]
</span><span class="cx">             &lt;/td&gt;
</span><span class="cx">             &lt;td&gt;
</span><del>-              &lt;a href=&quot;quips.cgi?action=delete&amp;amp;quipid=[% quipid FILTER url_quote %]&quot;&gt;
</del><ins>+              &lt;a href=&quot;quips.cgi?action=delete&amp;amp;quipid=[% quipid FILTER uri %]&amp;amp;token=
+                 [%- issue_hash_token(['quips', quipid]) FILTER uri %]&quot;&gt;
</ins><span class="cx">                 Delete
</span><span class="cx">               &lt;/a&gt;
</span><span class="cx">             &lt;/td&gt;
</span><span class="lines">@@ -158,7 +163,7 @@
</span><span class="cx">   &lt;p&gt;
</span><span class="cx">     Those who like their wisdom in large doses can
</span><span class="cx">     &lt;a href=&quot;quips.cgi?action=show&quot;&gt;view
</span><del>-    [% IF user.in_group('admin') %]
</del><ins>+    [% IF user.in_group('bz_quip_moderators') %]
</ins><span class="cx">       and edit
</span><span class="cx">     [% END %]
</span><span class="cx">     the whole quip list&lt;/a&gt;.
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultlisttablehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/list/table.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/list/table.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/list/table.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -16,12 +16,17 @@
</span><span class="cx">   # Rights Reserved.
</span><span class="cx">   #
</span><span class="cx">   # Contributor(s): Myk Melez &lt;myk@mozilla.org&gt;
</span><ins>+  #                 Jesse Clark &lt;jjclark1982@gmail.com&gt;
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [%############################################################################%]
</span><span class="cx"> [%# Initialization                                                           #%]
</span><span class="cx"> [%############################################################################%]
</span><span class="cx"> 
</span><ins>+[%# Don't display the table or do any processing if there are no bugs 
+  # to display %]
+[% RETURN IF !bugs.size %]
+
</ins><span class="cx"> [%# Columns whose titles or values should be abbreviated to make the list
</span><span class="cx">   # more compact.  For columns whose titles should be abbreviated,
</span><span class="cx">   # the shortened title is included.  For columns whose values should be
</span><span class="lines">@@ -40,7 +45,7 @@
</span><span class="cx"> [% abbrev = 
</span><span class="cx">   {
</span><span class="cx">     &quot;bug_severity&quot;         =&gt; { maxlength =&gt; 3 , title =&gt; &quot;Sev&quot; } , 
</span><del>-    &quot;priority&quot;             =&gt; { maxlength =&gt; 3 , title =&gt; &quot;Pri&quot; } , 
</del><ins>+    &quot;priority&quot;             =&gt; { maxlength =&gt; 7 , title =&gt; &quot;Pri&quot; } , 
</ins><span class="cx">     &quot;rep_platform&quot;         =&gt; { maxlength =&gt; 3 , title =&gt; &quot;Plt&quot; } , 
</span><span class="cx">     &quot;bug_status&quot;           =&gt; { maxlength =&gt; 4 } , 
</span><span class="cx">     &quot;assigned_to&quot;          =&gt; { maxlength =&gt; 30 , ellipsis =&gt; &quot;...&quot; } , 
</span><span class="lines">@@ -54,46 +59,40 @@
</span><span class="cx">     &quot;short_short_desc&quot;  =&gt; { maxlength =&gt; 60 , ellipsis =&gt; &quot;...&quot; , wrap =&gt; 1 } ,
</span><span class="cx">     &quot;status_whiteboard&quot; =&gt; { title =&gt; &quot;Whiteboard&quot; , wrap =&gt; 1 } , 
</span><span class="cx">     &quot;keywords&quot;          =&gt; { wrap =&gt; 1 } ,
</span><ins>+    &quot;flagtypes.name&quot;    =&gt; { wrap =&gt; 1 } ,
</ins><span class="cx">     &quot;component&quot;         =&gt; { maxlength =&gt; 8 , title =&gt; &quot;Comp&quot; } , 
</span><span class="cx">     &quot;product&quot;           =&gt; { maxlength =&gt; 8 } , 
</span><span class="cx">     &quot;version&quot;           =&gt; { maxlength =&gt; 5 , title =&gt; &quot;Vers&quot; } , 
</span><span class="cx">     &quot;op_sys&quot;            =&gt; { maxlength =&gt; 4 } , 
</span><ins>+    &quot;bug_file_loc&quot;      =&gt; { maxlength =&gt; 30 } , 
</ins><span class="cx">     &quot;target_milestone&quot;  =&gt; { title =&gt; &quot;TargetM&quot; } , 
</span><ins>+    &quot;longdescs.count&quot;   =&gt; { title =&gt; &quot;# Comments&quot; },
</ins><span class="cx">     &quot;percentage_complete&quot; =&gt; { format_value =&gt; &quot;%d %%&quot; } , 
</span><span class="cx">   }
</span><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS bug/time.html.tmpl %]
</span><span class="cx"> 
</span><ins>+[% Hook.process(&quot;before_table&quot;) %]
+
</ins><span class="cx"> [%############################################################################%]
</span><span class="cx"> [%# Table Header                                                             #%]
</span><span class="cx"> [%############################################################################%]
</span><span class="cx"> 
</span><span class="cx"> [% tableheader = BLOCK %]
</span><span class="cx">   &lt;table class=&quot;bz_buglist&quot; cellspacing=&quot;0&quot; cellpadding=&quot;4&quot; width=&quot;100%&quot;&gt;
</span><del>-    &lt;colgroup&gt;
</del><ins>+    &lt;tr class=&quot;bz_buglist_header bz_first_buglist_header&quot;&gt;
</ins><span class="cx">       [% IF dotweak %]
</span><del>-        &lt;col class=&quot;bz_checkbox_column&quot;&gt;
-      [% END %]
-      &lt;col class=&quot;bz_id_column&quot;&gt;
-      [% FOREACH id = displaycolumns %]
-      &lt;col class=&quot;bz_[% id FILTER css_class_quote %]_column&quot;&gt;
-      [% END %]
-    &lt;/colgroup&gt;
-
-    &lt;tr class=&quot;bz_buglist_header bz_first_buglist_header&quot; align=&quot;left&quot;&gt;
-      [% IF dotweak %]
</del><span class="cx">       &lt;th&gt;&amp;nbsp;&lt;/th&gt;
</span><span class="cx">       [% END %]
</span><span class="cx">       &lt;th colspan=&quot;[% splitheader ? 2 : 1 %]&quot; class=&quot;first-child&quot;&gt;
</span><del>-        [% desc = '' %]
-        [% IF (om = order.match(&quot;^bugs\.bug_id( desc)?&quot;)) %]
-          [% desc = ' desc' IF NOT om.0 %]
-        [% END %]
</del><span class="cx">         &lt;a href=&quot;buglist.cgi?
</span><del>-                  [% urlquerypart FILTER html %]&amp;amp;order=bugs.bug_id[% desc FILTER url_quote %]
</del><ins>+                  [% urlquerypart FILTER html %]&amp;amp;order=
+                  [% PROCESS new_order id='bug_id' %]
</ins><span class="cx">                   [%-#%]&amp;amp;query_based_on=
</span><del>-                  [% defaultsavename OR searchname FILTER url_quote %]&quot;&gt;ID&lt;/a&gt;
</del><ins>+                  [% defaultsavename OR searchname FILTER uri %]&quot;&gt;ID
+          [% PROCESS order_arrow id='bug_id' ~%]
+        &lt;/a&gt;
</ins><span class="cx">       &lt;/th&gt;
</span><span class="cx"> 
</span><span class="cx">       [% IF splitheader %]
</span><span class="lines">@@ -104,7 +103,7 @@
</span><span class="cx">           [% PROCESS columnheader %]
</span><span class="cx">         [% END %]
</span><span class="cx"> 
</span><del>-        &lt;/tr&gt;&lt;tr class=&quot;bz_buglist_header&quot; align=&quot;left&quot;&gt;
</del><ins>+        &lt;/tr&gt;&lt;tr class=&quot;bz_buglist_header&quot;&gt;
</ins><span class="cx">         [% IF dotweak %]
</span><span class="cx">           &lt;th&gt;&amp;nbsp;&lt;/th&gt;
</span><span class="cx">         [% END %]
</span><span class="lines">@@ -130,42 +129,49 @@
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK columnheader %]
</span><span class="cx">   &lt;th colspan=&quot;[% splitheader ? 2 : 1 %]&quot;&gt;
</span><del>-    [% IF column.name.match('\s+AS\s+') %]
-      [%# For aliased columns, use their ID for sorting. %]
-      [% column.sortalias = id %]
-    [% ELSE %]
-      [%# Other columns may sort on their name directly. %]
-      [% column.sortalias = column.name %]
-    [% END %]
-    [% desc = '' %]
-    [% IF (om = order.match(&quot;$column.sortalias( desc)?&quot;)) %]
-      [% desc = ' desc' IF NOT om.0 %]
-    [% END %]
-    [% order = order.remove(&quot;$column.sortalias( desc)?,?&quot;) %]
</del><span class="cx">     &lt;a href=&quot;buglist.cgi?[% urlquerypart FILTER html %]&amp;amp;order=
</span><del>-      [% column.sortalias FILTER url_quote %][% desc FILTER url_quote %]
-      [% &quot;,$order&quot; FILTER url_quote IF order %]
</del><ins>+      [% PROCESS new_order %]
</ins><span class="cx">       [%-#%]&amp;amp;query_based_on=
</span><del>-      [% defaultsavename OR searchname FILTER url_quote %]&quot;&gt;
-        [%- abbrev.$id.title || field_descs.$id || column.title -%]&lt;/a&gt;
</del><ins>+      [% defaultsavename OR searchname FILTER uri %]&quot;&gt;
+        [%- abbrev.$id.title || field_descs.$id || column.title -%]
+        [% PROCESS order_arrow ~%]
+    &lt;/a&gt;
</ins><span class="cx">   &lt;/th&gt;
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><ins>+[% BLOCK new_order %]
+  [% desc = '' %]
+  [% IF (om = order.match(&quot;\\b$id( DESC)?&quot;)) %]
+    [% desc = ' DESC' IF NOT om.0 %]
+  [% END %]
+  [% id _ desc FILTER uri %]
+  [% IF id != 'bug_id' AND order %]
+    [% ',' _ order.remove(&quot;\\b$id( DESC)?(,\\s*|\$)&quot;) FILTER uri %]
+  [% END %]
+[% END %]
</ins><span class="cx"> 
</span><ins>+[% BLOCK order_arrow %]
+  [% IF order.match(&quot;^$id DESC&quot;) %]
+    &lt;span class=&quot;bz_sort_order_primary&quot;&gt;&amp;#x25BC;&lt;/span&gt;
+  [% ELSIF order.match(&quot;^$id(,\\s*|\$)&quot;) %]
+    &lt;span class=&quot;bz_sort_order_primary&quot;&gt;&amp;#x25B2;&lt;/span&gt;
+  [% ELSIF order.match(&quot;\\b$id DESC&quot;) %]
+    &lt;span class=&quot;bz_sort_order_secondary&quot;&gt;&amp;#x25BC;&lt;/span&gt;
+  [% ELSIF order.match(&quot;\\b$id(,\\s*|\$)&quot;) %]
+    &lt;span class=&quot;bz_sort_order_secondary&quot;&gt;&amp;#x25B2;&lt;/span&gt;
+  [% END %]
+[% END %]
+
</ins><span class="cx"> [%############################################################################%]
</span><span class="cx"> [%# Bug Table                                                                #%]
</span><span class="cx"> [%############################################################################%]
</span><span class="cx"> 
</span><ins>+[% tableheader %]
+
</ins><span class="cx"> [% FOREACH bug = bugs %]
</span><span class="cx">   [% count = loop.count() %]
</span><del>-  [% FLUSH IF count % 10 == 1 %]
</del><span class="cx"> 
</span><del>-  [%# At the beginning of every hundred bugs in the list, start a new table. %]
-  [% IF count % 100 == 1 %]
-    [% tableheader %]
-  [% END %]
-
-  &lt;tr class=&quot;bz_bugitem
</del><ins>+  &lt;tr id=&quot;b[% bug.bug_id %]&quot; class=&quot;bz_bugitem
</ins><span class="cx">              bz_[% bug.bug_severity FILTER css_class_quote -%]
</span><span class="cx">              bz_[% bug.priority FILTER css_class_quote -%]
</span><span class="cx">              bz_[% bug.bug_status FILTER css_class_quote -%]
</span><span class="lines">@@ -176,41 +182,83 @@
</span><span class="cx">              &quot;&gt;
</span><span class="cx"> 
</span><span class="cx">     [% IF dotweak %]
</span><del>-    &lt;td&gt;
</del><ins>+    &lt;td class=&quot;bz_checkbox_column&quot;&gt;
</ins><span class="cx">       &lt;input type=&quot;checkbox&quot; name=&quot;id_[% bug.bug_id %]&quot;&gt;
</span><span class="cx">     &lt;/td&gt;
</span><span class="cx">     [% END %]
</span><del>-    &lt;td class=&quot;first-child&quot;&gt;
-      &lt;a name=&quot;b[% bug.bug_id %]&quot;
-         href=&quot;show_bug.cgi?id=[% bug.bug_id %]&quot;&gt;[% bug.bug_id %]&lt;/a&gt;
</del><ins>+    &lt;td class=&quot;first-child bz_id_column&quot;&gt;
+      &lt;a href=&quot;show_bug.cgi?id=[% bug.bug_id %]&quot;&gt;[% bug.bug_id %]&lt;/a&gt;
</ins><span class="cx">       &lt;span style=&quot;display: none&quot;&gt;[%+ '[SEC]' IF bug.secure_mode %]&lt;/span&gt;
</span><span class="cx">     &lt;/td&gt;
</span><span class="cx"> 
</span><span class="cx">     [% FOREACH column = displaycolumns %]
</span><del>-    &lt;td [% 'style=&quot;white-space: nowrap&quot;' IF NOT abbrev.$column.wrap %]&gt;
</del><ins>+    &lt;td [% 'style=&quot;white-space: nowrap&quot;' IF NOT abbrev.$column.wrap %]
+        class=&quot;bz_[% column FILTER css_class_quote %]_column&quot;&gt;
+      [% IF abbrev.$column.maxlength %]
+        &lt;span title=&quot;[%- display_value(column, bug.$column) FILTER html %]&quot;&gt;
+      [% END %]
</ins><span class="cx">       [% IF abbrev.$column.format_value %] 
</span><span class="cx">         [%- bug.$column FILTER format(abbrev.$column.format_value) FILTER html -%] 
</span><span class="cx">       [% ELSIF column == 'actual_time' ||
</span><span class="cx">                column == 'remaining_time' ||
</span><span class="cx">                column == 'estimated_time' %]
</span><span class="cx">         [% PROCESS formattimeunit time_unit=bug.$column %] 
</span><del>-      [% ELSIF column == 'bug_status' %]
-        [%- get_status(bug.$column).truncate(abbrev.$column.maxlength, abbrev.$column.ellipsis) FILTER html %]
-      [% ELSIF column == 'resolution' %]
-        [%- get_resolution(bug.$column).truncate(abbrev.$column.maxlength, abbrev.$column.ellipsis) FILTER html %]
</del><ins>+      [%# Display the login name of the user if their real name is empty. %]
+      [% ELSIF column.match('_realname$') &amp;&amp; bug.$column == '' %]
+        [% SET login_column = column.remove('_realname$') %]
+        [% bug.${login_column}.truncate(abbrev.$column.maxlength, 
+                                        abbrev.$column.ellipsis) FILTER html %]
+      [% ELSIF column == 'short_desc' || column == &quot;short_short_desc&quot; %]
+        &lt;a href=&quot;show_bug.cgi?id=[% bug.bug_id FILTER html %]&quot;&gt;
+          [%- bug.$column.truncate(abbrev.$column.maxlength, abbrev.$column.ellipsis) FILTER html -%]
+        &lt;/a&gt;
</ins><span class="cx">       [% ELSE %]
</span><del>-        [%- bug.$column.truncate(abbrev.$column.maxlength, abbrev.$column.ellipsis) FILTER html -%]
</del><ins>+        [%- display_value(column, bug.$column).truncate(abbrev.$column.maxlength, abbrev.$column.ellipsis) FILTER html -%]
</ins><span class="cx">       [% END %]
</span><ins>+      [% IF abbrev.$column.maxlength %]
+        &lt;/span&gt;
+      [% END %]
</ins><span class="cx">     &lt;/td&gt;
</span><span class="cx">     [% END %]
</span><span class="cx"> 
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> 
</span><del>-  [%# At the end of every hundred bugs in the list, or at the end of the list,
-    # end the current table. 
-    #%]
-  [% IF loop.last() || loop.count() % 100 == 0 %]
-    &lt;/table&gt;
</del><ins>+  [% IF loop.last() &amp;&amp; time_info.time_present == 1 %]
+    [% PROCESS time_summary_line %]
</ins><span class="cx">   [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% END %]
</span><ins>+
+&lt;/table&gt;
+
+[% BLOCK time_summary_line %]
+  &lt;tr class=&quot;bz_time_summary_line&quot;&gt;
+    [% columns_to_span = 1 %]  [%# bugID %]
+    [% IF dotweak %]
+      [% columns_to_span = columns_to_span + 1 %]
+    [% END %]
+    [% FOREACH column = displaycolumns %]
+      [% IF column == 'actual_time' ||
+            column == 'remaining_time' ||
+            column == 'estimated_time' ||
+            column == 'percentage_complete' %]
+        [% IF columns_to_span &gt; 0 %]
+          &lt;td class=&quot;bz_total bz_total_label&quot; colspan=&quot;
+              [%- columns_to_span FILTER html %]&quot;&gt;&lt;b&gt;Totals&lt;/b&gt;&lt;/td&gt;
+          [% columns_to_span = 0 %]
+        [% END %]
+        [% IF column == 'percentage_complete' %]
+          &lt;td class=&quot;bz_total&quot;&gt;[% time_info.percentage_complete
+              FILTER format(abbrev.$column.format_value) FILTER html %]&lt;/td&gt;
+        [% ELSE %]
+          &lt;td class=&quot;bz_total&quot;&gt;
+            [%- PROCESS formattimeunit time_unit=time_info.$column %]&lt;/td&gt;
+        [% END %]
+      [% ELSIF columns_to_span == 0 %] [%# A column following the first total %]
+        &lt;td class=&quot;bz_total&quot;&gt;&amp;nbsp;&lt;/td&gt;
+      [% ELSE %] [%# We haven't gotten to a time column yet, keep computing span %]
+        [% columns_to_span = columns_to_span + 1 %]
+      [% END %]
+    [% END %]
+  &lt;/tr&gt;
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultpagesbugwritinghtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/pages/bug-writing.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/pages/bug-writing.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/pages/bug-writing.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -78,8 +78,8 @@
</span><span class="cx">           it?
</span><span class="cx">     (e.g. Linux, Windows XP, Mac OS X.)&lt;br&gt;
</span><span class="cx">     If you know the [% terms.bug %] happens on more than one type of 
</span><del>-    operating system, choose &quot;All&quot;. 
-    If your OS isn't listed, choose Other.&lt;/p&gt;
</del><ins>+    operating system, choose &lt;em&gt;[% display_value(&quot;op_sys&quot;, &quot;All&quot;) FILTER html %]&lt;/em&gt;. 
+    If your OS isn't listed, choose &lt;em&gt;[% display_value(&quot;op_sys&quot;, &quot;Other&quot;) FILTER html %]&lt;/em&gt;.&lt;/p&gt;
</ins><span class="cx"> 
</span><span class="cx">     &lt;p&gt;&lt;b&gt;Summary:&lt;/b&gt; How would you describe the [% terms.bug %], in 
</span><span class="cx">     approximately 60 or fewer characters?&lt;br&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultpagesfieldshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/pages/fields.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/pages/fields.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/pages/fields.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -19,300 +19,220 @@
</span><span class="cx">   #                 Gervase Markham &lt;gerv@gerv.net&gt;
</span><span class="cx">   #%]
</span><span class="cx"> 
</span><del>-[% PROCESS global/variables.none.tmpl %]
</del><span class="cx"> [% PROCESS &quot;global/field-descs.none.tmpl&quot; %]
</span><del>-[% INCLUDE global/header.html.tmpl title = &quot;A $terms.Bug's Life Cycle&quot; %]
</del><ins>+[% PROCESS global/header.html.tmpl 
+  title = &quot;$terms.Bug Fields&quot; 
+  style_urls = ['skins/standard/page.css']
+%]
</ins><span class="cx"> 
</span><del>-&lt;p&gt;
-The &lt;b&gt;status&lt;/b&gt; and &lt;b&gt;resolution&lt;/b&gt; fields define and track the life
-cycle of [% terms.abug %].  
-&lt;/p&gt;
</del><ins>+&lt;p&gt;This page describes the various fields that you see 
+  on [% terms.abug %].&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;a name=&quot;status&quot;&gt;&lt;/a&gt;
-&lt;a name=&quot;resolution&quot;&gt;&lt;/a&gt;
-
-&lt;table border=&quot;1&quot; cellpadding=&quot;4&quot;&gt;
-  &lt;tr align=&quot;center&quot; valign=&quot;top&quot;&gt;
-    &lt;td width=&quot;50%&quot;&gt;
-      &lt;h1&gt;STATUS&lt;/h1&gt;
</del><ins>+&lt;table class=&quot;field_value_explanation&quot;&gt;
+  &lt;thead&gt;
+  &lt;tr&gt;
+    &lt;td id=&quot;bug_status&quot;&gt;
+      &lt;h2&gt;[% field_descs.bug_status FILTER upper FILTER html %]&lt;/h2&gt;
</ins><span class="cx">     &lt;/td&gt;
</span><span class="cx"> 
</span><del>-    &lt;td&gt;
-      &lt;h1&gt;RESOLUTION&lt;/h1&gt;
</del><ins>+    &lt;td id=&quot;resolution&quot;&gt;
+      &lt;h2&gt;[% field_descs.resolution FILTER upper FILTER html %]&lt;/h2&gt;
</ins><span class="cx">     &lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> 
</span><del>-  &lt;tr valign=&quot;top&quot;&gt;
-    &lt;td&gt;The &lt;b&gt;status&lt;/b&gt; field indicates the general health of a 
-    [% terms.bug %]. Only certain status transitions are allowed.&lt;/td&gt;
</del><ins>+  &lt;tr&gt;
+    &lt;td&gt;The [% field_descs.bug_status FILTER html %] field indicates the 
+      current state of a [% terms.bug %]. Only certain status transitions
+      are allowed.&lt;/td&gt;
</ins><span class="cx"> 
</span><del>-    &lt;td&gt;The &lt;b&gt;resolution&lt;/b&gt; field indicates what happened to this
-    [%+ terms.bug %].&lt;/td&gt;
</del><ins>+    &lt;td&gt;The [% field_descs.resolution FILTER html %] field indicates what
+      happened to this [%+ terms.bug %].&lt;/td&gt;
</ins><span class="cx">   &lt;/tr&gt;
</span><ins>+  &lt;/thead&gt;
</ins><span class="cx"> 
</span><del>-  &lt;tr valign=&quot;top&quot;&gt;
</del><ins>+  &lt;tbody&gt;
+  &lt;tr class=&quot;header_row&quot;&gt;
+    &lt;td colspan=&quot;2&quot;&gt;Open [% terms.Bugs %]&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
</ins><span class="cx">     &lt;td&gt;
</span><span class="cx">       &lt;dl&gt;
</span><del>-        &lt;dt&gt;
-          &lt;b&gt;[% get_status(&quot;UNCONFIRMED&quot;) FILTER html %]&lt;/b&gt;
</del><ins>+        &lt;dt class=&quot;unconfirmed&quot;&gt;
+          [% display_value(&quot;bug_status&quot;, &quot;UNCONFIRMED&quot;) FILTER html %]
</ins><span class="cx">         &lt;/dt&gt;
</span><del>-        &lt;dd&gt;
</del><ins>+        &lt;dd class=&quot;unconfirmed&quot;&gt;
</ins><span class="cx">           This [% terms.bug %] has recently been added to the database. 
</span><del>-          Nobody has validated that this [% terms.bug %] is true. Users
</del><ins>+          Nobody has confirmed that this [% terms.bug %] is valid. Users
</ins><span class="cx">           who have the &quot;canconfirm&quot; permission set may confirm
</span><del>-          this [% terms.bug %], changing its state to [% get_status(&quot;NEW&quot;) FILTER html %]. Or, it may be
-          directly resolved and marked [% get_status(&quot;RESOLVED&quot;) FILTER html %].
</del><ins>+          this [% terms.bug %], changing its state to 
+          &lt;b&gt;[% display_value(&quot;bug_status&quot;, &quot;CONFIRMED&quot;) FILTER html %]&lt;/b&gt;. 
+          Or, it may be directly resolved and marked
+          &lt;b&gt;[% display_value(&quot;bug_status&quot;, &quot;RESOLVED&quot;) FILTER html %]&lt;/b&gt;.
</ins><span class="cx">         &lt;/dd&gt;
</span><span class="cx"> 
</span><del>-        &lt;dt&gt;
-          &lt;b&gt;[% get_status(&quot;NEW&quot;) FILTER html %]&lt;/b&gt;
</del><ins>+        &lt;dt class=&quot;confirmed&quot;&gt;
+          [% display_value(&quot;bug_status&quot;, &quot;CONFIRMED&quot;) FILTER html %]
</ins><span class="cx">         &lt;/dt&gt;
</span><del>-        &lt;dd&gt;
-          This [% terms.bug %] has recently been added to the assignee's
-          list of [% terms.bugs %] and must be processed. [% terms.Bugs %] in
-          this state may be accepted, and become &lt;b&gt;[% get_status(&quot;ASSIGNED&quot;) FILTER html %]&lt;/b&gt;, passed
-          on to someone else, and remain &lt;b&gt;[% get_status(&quot;NEW&quot;) FILTER html %]&lt;/b&gt;, or resolved and marked
-          &lt;b&gt;[% get_status(&quot;RESOLVED&quot;) FILTER html %]&lt;/b&gt;.
</del><ins>+        &lt;dd class=&quot;confirmed&quot;&gt;
+          This [% terms.bug %] is valid and has recently been filed.
+          [%+ terms.Bugs %] in this state become 
+          &lt;b&gt;[% display_value(&quot;bug_status&quot;, &quot;IN_PROGRESS&quot;) FILTER html %]&lt;/b&gt;
+          when somebody is working on them, or become resolved and marked
+          &lt;b&gt;[% display_value(&quot;bug_status&quot;, &quot;RESOLVED&quot;) FILTER html %]&lt;/b&gt;.
</ins><span class="cx">         &lt;/dd&gt;
</span><span class="cx"> 
</span><del>-        &lt;dt&gt;
-          &lt;b&gt;[% get_status(&quot;ASSIGNED&quot;) FILTER html %]&lt;/b&gt;
</del><ins>+        &lt;dt class=&quot;in_progress&quot;&gt;
+          [% display_value(&quot;bug_status&quot;, &quot;IN_PROGRESS&quot;) FILTER html %]
</ins><span class="cx">         &lt;/dt&gt;
</span><del>-        &lt;dd&gt;
-          This [% terms.bug %] is not yet resolved, but is assigned to the 
-          proper person. From here [% terms.bugs %] can be given to another 
-          person and become &lt;b&gt;[% get_status(&quot;NEW&quot;) FILTER html %]&lt;/b&gt;, or
-          resolved and become &lt;b&gt;[% get_status(&quot;RESOLVED&quot;) FILTER html %]&lt;/b&gt;.
</del><ins>+        &lt;dd class=&quot;in_progress&quot;&gt;
+          This [% terms.bug %] is not yet resolved, but is assigned to the
+          proper person who is working on the [% terms.bug %]. From here,
+          [%+ terms.bugs %] can be given to another person and become
+          &lt;b&gt;[% display_value(&quot;bug_status&quot;, &quot;CONFIRMED&quot;) FILTER html %]&lt;/b&gt;, or
+          resolved and become 
+          &lt;b&gt;[% display_value(&quot;bug_status&quot;, &quot;RESOLVED&quot;) FILTER html %]&lt;/b&gt;.
</ins><span class="cx">         &lt;/dd&gt;
</span><del>-
-        &lt;dt&gt;
-          &lt;b&gt;[% get_status(&quot;REOPENED&quot;) FILTER html %]&lt;/b&gt;
-        &lt;/dt&gt;
-        &lt;dd&gt;
-          This [% terms.bug %] was once resolved, but the resolution was 
-          deemed incorrect. For example, a &lt;b&gt;[% get_resolution(&quot;WORKSFORME&quot;) FILTER html %]&lt;/b&gt; [% terms.bug %] is
-          &lt;b&gt;[% get_status(&quot;REOPENED&quot;) FILTER html %]&lt;/b&gt; when more information shows up and
-          the [% terms.bug %] is now reproducible. From here [% terms.bugs %] are
-          either marked &lt;b&gt;[% get_status(&quot;ASSIGNED&quot;) FILTER html %]&lt;/b&gt; or
-          &lt;b&gt;[% get_status(&quot;RESOLVED&quot;) FILTER html %]&lt;/b&gt;.
-        &lt;/dd&gt;
</del><ins>+        
+        [% Hook.process('open-status') %]
</ins><span class="cx">       &lt;/dl&gt;
</span><span class="cx">     &lt;/td&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;td&gt;
</span><del>-      &lt;dl&gt;
-        &lt;dd&gt;
-          No resolution yet. All [% terms.bugs %] which are in one of 
-          these &quot;open&quot; states have the resolution set to blank. All 
-          other [% terms.bugs %] will be marked with one of the following 
-          resolutions.
-        &lt;/dd&gt;
-      &lt;/dl&gt;
</del><ins>+      No resolution yet. All [% terms.bugs %] which are in one of
+      these &quot;open&quot; states have no resolution set.
</ins><span class="cx">     &lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> 
</span><del>-  &lt;tr valign=&quot;top&quot;&gt;
</del><ins>+  &lt;tr class=&quot;header_row&quot;&gt;
+    &lt;td colspan=&quot;2&quot;&gt;Closed [% terms.Bugs %]&lt;/td&gt;
+  &lt;/tr&gt;
+
+  &lt;tr&gt;
</ins><span class="cx">     &lt;td&gt;
</span><span class="cx">       &lt;dl&gt;
</span><del>-        &lt;dt&gt;
-          &lt;b&gt;[% get_status(&quot;RESOLVED&quot;) FILTER html %]&lt;/b&gt;
</del><ins>+        &lt;dt class=&quot;resolved&quot;&gt;
+          [% display_value(&quot;bug_status&quot;, &quot;RESOLVED&quot;) FILTER html %]
</ins><span class="cx">         &lt;/dt&gt;
</span><del>-        &lt;dd&gt;
-          A resolution has been taken, and it is awaiting verification by
-          QA. From here [% terms.bugs %] are either re-opened and become 
-          &lt;b&gt;[% get_status(&quot;REOPENED&quot;) FILTER html %]&lt;/b&gt;, are marked
-          &lt;b&gt;[% get_status(&quot;VERIFIED&quot;) FILTER html %]&lt;/b&gt;, or are closed for
-          good and marked &lt;b&gt;[% get_status(&quot;CLOSED&quot;) FILTER html %]&lt;/b&gt;.
</del><ins>+        &lt;dd class=&quot;resolved&quot;&gt;
+          A resolution has been performed, and it is awaiting verification by
+          QA. From here [% terms.bugs %] are either reopened and given some
+          open status, or are verified by QA and marked
+          &lt;b&gt;[% display_value(&quot;bug_status&quot;, &quot;VERIFIED&quot;) FILTER html %]&lt;/b&gt;.
</ins><span class="cx">         &lt;/dd&gt;
</span><span class="cx"> 
</span><del>-        &lt;dt&gt;
-          &lt;b&gt;[% get_status(&quot;VERIFIED&quot;) FILTER html %]&lt;/b&gt;
</del><ins>+        &lt;dt class=&quot;verified&quot;&gt;
+          [% display_value(&quot;bug_status&quot;, &quot;VERIFIED&quot;) FILTER html %]
</ins><span class="cx">         &lt;/dt&gt;
</span><del>-        &lt;dd&gt;
-          QA has looked at the [% terms.bug %] and the resolution and 
-          agrees that the appropriate resolution has been taken. [% terms.Bugs %] remain
-          in this state until the product they were reported
-          against actually ships, at which point they become
-          &lt;b&gt;[% get_status(&quot;CLOSED&quot;) FILTER html %]&lt;/b&gt;.
</del><ins>+        &lt;dd class=&quot;verified&quot;&gt;
+          QA has looked at the [% terms.bug %] and the resolution and
+          agrees that the appropriate resolution has been taken. This is
+          the final status for [% terms.bugs %].
</ins><span class="cx">         &lt;/dd&gt;
</span><del>-
-        &lt;dt&gt;
-          &lt;b&gt;[% get_status(&quot;CLOSED&quot;) FILTER html %]&lt;/b&gt;
-        &lt;/dt&gt;
-        &lt;dd&gt;
-          The [% terms.bug %] is considered dead, the resolution is correct. 
-          Any zombie [% terms.bugs %] who choose to walk the earth again must 
-          do so by becoming &lt;b&gt;[% get_status(&quot;REOPENED&quot;) FILTER html %]&lt;/b&gt;.
-        &lt;/dd&gt;
</del><ins>+        
+        [% Hook.process('closed-status') %]
</ins><span class="cx">       &lt;/dl&gt;
</span><span class="cx">     &lt;/td&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;td&gt;
</span><span class="cx">       &lt;dl&gt;
</span><del>-        &lt;dt&gt;
-          &lt;b&gt;[% get_resolution(&quot;FIXED&quot;) FILTER html %]&lt;/b&gt;
</del><ins>+        &lt;dt class=&quot;fixed&quot;&gt;
+          [% display_value(&quot;resolution&quot;, &quot;FIXED&quot;) FILTER html %]
</ins><span class="cx">         &lt;/dt&gt;
</span><del>-        &lt;dd&gt;
</del><ins>+        &lt;dd class=&quot;fixed&quot;&gt;
</ins><span class="cx">           A fix for this [% terms.bug %] is checked into the tree and 
</span><span class="cx">           tested.
</span><span class="cx">         &lt;/dd&gt;
</span><span class="cx"> 
</span><del>-        &lt;dt&gt;
-          &lt;b&gt;[% get_resolution(&quot;INVALID&quot;) FILTER html %]&lt;/b&gt;
</del><ins>+        &lt;dt class=&quot;invalid&quot;&gt;
+          [% display_value(&quot;resolution&quot;, &quot;INVALID&quot;) FILTER html %]
</ins><span class="cx">         &lt;/dt&gt;
</span><del>-        &lt;dd&gt;
</del><ins>+        &lt;dd class=&quot;invalid&quot;&gt;
</ins><span class="cx">           The problem described is not [% terms.abug %].
</span><span class="cx">         &lt;/dd&gt;
</span><span class="cx"> 
</span><del>-        &lt;dt&gt;
-          &lt;b&gt;[% get_resolution(&quot;WONTFIX&quot;) FILTER html %]&lt;/b&gt;
</del><ins>+        &lt;dt class=&quot;wontfix&quot;&gt;
+          [% display_value(&quot;resolution&quot;, &quot;WONTFIX&quot;) FILTER html %]
</ins><span class="cx">         &lt;/dt&gt;
</span><del>-        &lt;dd&gt;
</del><ins>+        &lt;dd class=&quot;wontfix&quot;&gt;
</ins><span class="cx">           The problem described is [% terms.abug %] which will never be 
</span><span class="cx">           fixed.
</span><span class="cx">         &lt;/dd&gt;
</span><span class="cx"> 
</span><del>-        &lt;dt&gt;
-         &lt;b&gt;[% get_resolution(&quot;DUPLICATE&quot;) FILTER html %]&lt;/b&gt;
</del><ins>+        &lt;dt class=&quot;duplicate&quot;&gt;
+         [% display_value(&quot;resolution&quot;, &quot;DUPLICATE&quot;) FILTER html %]
</ins><span class="cx">         &lt;/dt&gt;
</span><del>-        &lt;dd&gt;
</del><ins>+        &lt;dd class=&quot;duplicate&quot;&gt;
</ins><span class="cx">           The problem is a duplicate of an existing [% terms.bug %].
</span><del>-          Marking [% terms.abug %] duplicate requires the [% terms.bug %]#
-          of the duplicating [% terms.bug %] and will at least put
-          that [% terms.bug %] number in the description field.
</del><ins>+          When [% terms.abug %] is marked as a
+          &lt;b&gt;[% display_value(&quot;resolution&quot;, &quot;DUPLICATE&quot;) FILTER html %]&lt;/b&gt;,
+          you will see which [% terms.bug %] it is a duplicate of,
+          next to the resolution.
</ins><span class="cx">         &lt;/dd&gt;
</span><span class="cx"> 
</span><del>-        &lt;dt&gt;
-          &lt;b&gt;[% get_resolution(&quot;WORKSFORME&quot;) FILTER html %]&lt;/b&gt;
</del><ins>+        &lt;dt class=&quot;worksforme&quot;&gt;
+          [% display_value(&quot;resolution&quot;, &quot;WORKSFORME&quot;) FILTER html %]
</ins><span class="cx">         &lt;/dt&gt;
</span><del>-        &lt;dd&gt;
</del><ins>+        &lt;dd class=&quot;worksforme&quot;&gt;
</ins><span class="cx">           All attempts at reproducing this [% terms.bug %] were futile, 
</span><span class="cx">           and reading the code produces no clues as to why the described
</span><span class="cx">           behavior would occur. If more information appears later,
</span><span class="cx">           the [% terms.bug %] can be reopened.
</span><span class="cx">         &lt;/dd&gt;
</span><del>-
-        &lt;dt&gt;
-          &lt;b&gt;[% get_resolution(&quot;MOVED&quot;) FILTER html %]&lt;/b&gt;
-        &lt;/dt&gt;
-        &lt;dd&gt;
-          The problem was specific to a related product 
-          whose [% terms.bugs %] are tracked in
-          another [% terms.bug %] database.
-          The [% terms.bug %] has been moved to that database.
-        &lt;/dd&gt;
</del><ins>+        
+        [% Hook.process('resolution') %]
</ins><span class="cx">       &lt;/dl&gt;
</span><span class="cx">     &lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><ins>+  &lt;/tbody&gt;
</ins><span class="cx"> &lt;/table&gt;
</span><span class="cx"> 
</span><del>-&lt;h2&gt;&lt;a name=&quot;importance&quot;&gt;Importance&lt;/h2&gt;
-The importance of [% terms.abug %] is described as the combination of
-its &lt;a href=&quot;#priority&quot;&gt;priority&lt;/a&gt; and &lt;a href=&quot;#bug_severity&quot;&gt;severity&lt;/a&gt;,
-as described below.
</del><ins>+&lt;h2&gt;Other Fields&lt;/h2&gt;
</ins><span class="cx"> 
</span><del>-&lt;h2&gt;&lt;a name=&quot;priority&quot;&gt;Priority&lt;/a&gt;&lt;/h2&gt;
-This field describes the importance and order in which [% terms.abug %]
-should be fixed. This field is utilized by the
-programmers/engineers to prioritize their work to be done. The
-available priorities range from &lt;b&gt;P1&lt;/b&gt; (most important) to
-&lt;b&gt;P5&lt;/b&gt; (least important).
</del><ins>+[% SET field_help_map = {} %]
+[% FOREACH field = bug_fields.keys %]
+  [% SET field_desc = field_descs.$field %]
+  [% field_help_map.$field_desc = { help  =&gt; help_html.$field, 
+                                    field =&gt; field } %]
+[% END %]
</ins><span class="cx"> 
</span><del>-&lt;h2&gt;&lt;a name=&quot;bug_severity&quot;&gt;Severity&lt;/a&gt;&lt;/h2&gt;
-This field describes the impact of [% terms.abug %]. 
</del><ins>+[%# These are fields that don't need to be documented, either because
+  # they have docs somewhere else in the UI, or they don't show up on bugs. 
+  # %]
+[% SET skip_fields = [ 
+  'days_elapsed', 
+  'everconfirmed',
+  'reporter_accessible',
+  'cclist_accessible',
+  'bug_group',
+  'commenter',
+  'owner_idle_time',
+  'bug_status',
+  'resolution',
+] %]
</ins><span class="cx"> 
</span><del>-&lt;table&gt;
-  &lt;tr&gt;
-    &lt;th&gt;Blocker&lt;/th&gt;
</del><ins>+&lt;dl class=&quot;field_descriptions&quot;&gt;
+[% FOREACH field_desc = field_help_map.keys.sort %]
+  [% SET field = field_help_map.${field_desc}.field %]
+  [% SET field_object = bug_fields.$field %]
</ins><span class="cx"> 
</span><del>-    &lt;td&gt;Blocks development and/or testing work&lt;/td&gt;
-  &lt;/tr&gt;
</del><ins>+  [% NEXT IF field_object.obsolete %]
+  [% NEXT IF !user.is_timetracker AND field_object.is_timetracking %]
</ins><span class="cx"> 
</span><del>-  &lt;tr&gt;
-    &lt;th&gt;Critical&lt;/th&gt;
</del><ins>+  [% NEXT IF field == 'status_whiteboard' AND !Param('usestatuswhiteboard') %]
+  [% NEXT IF field == 'target_milestone' AND !Param('usetargetmilestone') %]
+  [% NEXT IF field == 'alias' AND !Param('usebugaliases') %]
</ins><span class="cx"> 
</span><del>-    &lt;td&gt;crashes, loss of data, severe memory leak&lt;/td&gt;
-  &lt;/tr&gt;
</del><ins>+  [%# For now we don't have help for attachment fields and so on. %]
+  [% NEXT IF field.match('\.') %]
</ins><span class="cx"> 
</span><del>-  &lt;tr&gt;
-    &lt;th&gt;Major&lt;/th&gt;
</del><ins>+  [% NEXT IF skip_fields.contains(field) %]
</ins><span class="cx"> 
</span><del>-    &lt;td&gt;major loss of function&lt;/td&gt;
-  &lt;/tr&gt;
</del><ins>+  &lt;dt id=&quot;[% field FILTER html %]&quot;&gt;[% field_desc FILTER html %]&lt;/dt&gt;
+    &lt;dd&gt;
+      [% SET help_text = field_help_map.${field_desc}.help %]
+      [% help_text FILTER none %]
+    &lt;/dd&gt;
+[% END %]
+&lt;/dl&gt;
</ins><span class="cx"> 
</span><del>-  &lt;tr&gt;
-    &lt;th&gt;Normal&lt;/th&gt;
-
-    &lt;td&gt;regular issue, some loss of functionality under specific circumstances&lt;/td&gt;
-  &lt;/tr&gt;
-
-
-  &lt;tr&gt;
-    &lt;th&gt;Minor&lt;/th&gt;
-
-    &lt;td&gt;minor loss of function, or other problem where easy
-    workaround is present&lt;/td&gt;
-  &lt;/tr&gt;
-
-  &lt;tr&gt;
-    &lt;th&gt;Trivial&lt;/th&gt;
-
-    &lt;td&gt;cosmetic problem like misspelled words or misaligned
-    text&lt;/td&gt;
-  &lt;/tr&gt;
-
-  &lt;tr&gt;
-    &lt;th&gt;Enhancement&lt;/th&gt;
-
-    &lt;td&gt;Request for enhancement&lt;/td&gt;
-&lt;/table&gt;
-
-&lt;h2&gt;&lt;a name=&quot;rep_platform&quot;&gt;Platform&lt;/a&gt;&lt;/h2&gt;
-This is the hardware platform against which the [% terms.bug %] was
-reported. Legal platforms include: 
-
-&lt;ul&gt;
-  &lt;li&gt;All (happens on all platforms; cross-platform [% terms.bug %])&lt;/li&gt;
-
-  &lt;li&gt;Macintosh&lt;/li&gt;
-
-  &lt;li&gt;PC&lt;/li&gt;
-&lt;/ul&gt;
-&lt;b&gt;Note:&lt;/b&gt; When searching, selecting the option &quot;All&quot; does not 
-select [% terms.bugs %]
-assigned against any platform. It merely selects [% terms.bugs %] that are
-marked as occurring on all platforms, i.e. are designated &quot;All&quot;. 
-
-&lt;h2&gt;&lt;a name=&quot;op_sys&quot;&gt;Operating System&lt;/a&gt;&lt;/h2&gt;
-This is the operating system against which the [% terms.bug %] was
-reported. Legal operating systems include: 
-
-&lt;ul&gt;
-  &lt;li&gt;All (happens on all operating systems; cross-platform
-  [% terms.bug %])&lt;/li&gt;
-
-  &lt;li&gt;Windows&lt;/li&gt;
-
-  &lt;li&gt;Mac OS&lt;/li&gt;
-
-  &lt;li&gt;Linux&lt;/li&gt;
-&lt;/ul&gt;
-Sometimes the operating system implies the platform, but not
-always. For example, Linux can run on PC and Macintosh and
-others. 
-
-&lt;h2&gt;&lt;a name=&quot;assigned_to&quot;&gt;Assigned To&lt;/a&gt;&lt;/h2&gt;
-
-&lt;p&gt;
-This is the person in charge of resolving the [% terms.bug %]. Every time
-this field changes, the status changes to &lt;b&gt;[% get_status(&quot;NEW&quot;) FILTER html %]&lt;/b&gt; to make it
-easy to see which new [% terms.bugs %] have appeared on a person's list.&lt;/p&gt;
-
-&lt;p&gt;
-The default status for queries is set to [% get_status(&quot;NEW&quot;) FILTER html %],
-[%+ get_status(&quot;ASSIGNED&quot;) FILTER html %] and [% get_status(&quot;REOPENED&quot;) FILTER html %].
-When searching for [% terms.bugs %] that have been resolved or
-verified, remember to set the status field appropriately. 
-&lt;/p&gt;
-
-[% INCLUDE global/footer.html.tmpl %]
</del><ins>+[% PROCESS global/footer.html.tmpl %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultpageslinkedhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/pages/linked.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/pages/linked.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/pages/linked.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -31,7 +31,7 @@
</span><span class="cx"> 
</span><span class="cx"> &lt;p&gt;
</span><span class="cx"> &lt;pre class=&quot;bz_comment_text&quot;&gt;
</span><del>-[%- cgi.param(&quot;text&quot;) FILTER wrap_comment FILTER quoteUrls FILTER html -%]
</del><ins>+[%- cgi.param(&quot;text&quot;) FILTER quoteUrls FILTER html -%]
</ins><span class="cx"> &lt;/pre&gt;
</span><span class="cx"> &lt;/p&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -46,7 +46,7 @@
</span><span class="cx"> 
</span><span class="cx"> &lt;p&gt;
</span><span class="cx"> &lt;pre class=&quot;bz_comment_text&quot;&gt;
</span><del>-[%- cgi.param(&quot;text&quot;) FILTER wrap_comment FILTER quoteUrls -%]
</del><ins>+[%- cgi.param(&quot;text&quot;) FILTER quoteUrls -%]
</ins><span class="cx"> &lt;/pre&gt;
</span><span class="cx"> &lt;/p&gt;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultpagesquicksearchhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/pages/quicksearch.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/pages/quicksearch.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/pages/quicksearch.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -10,180 +10,332 @@
</span><span class="cx">   #
</span><span class="cx">   # The Original Code is the Bugzilla Bug Tracking System.
</span><span class="cx">   #
</span><del>-  # Contributor(s): N.N.
-  #                 Marc Schumann &lt;wurblzap@gmail.com&gt;
</del><ins>+  # The Initial Developer of the Original Code is Everything Solved, Inc.
+  # Portions created by the Initial Developer are Copyright (C) 2009
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s):
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><del>-[% PROCESS global/variables.none.tmpl %]
</del><ins>+[% PROCESS &quot;global/field-descs.none.tmpl&quot; %]
</ins><span class="cx"> 
</span><span class="cx"> [% INCLUDE global/header.html.tmpl
</span><span class="cx">    title  = &quot;$terms.Bugzilla QuickSearch&quot;,
</span><del>-   style  = 'ul {margin-bottom: 2ex}
-             ul li {margin-top: 2ex}
-             ul li ul li {margin-top: 0}'
</del><ins>+   style_urls = ['skins/standard/page.css']         
</ins><span class="cx">    onload = 'document.forms[\'f\'].quicksearch.focus()'
</span><span class="cx">  %]
</span><span class="cx"> 
</span><del>-&lt;p style=&quot;font-size: 80%&quot;&gt;
-  If you are already familiar with the original
-  &lt;a href=&quot;query.cgi&quot;&gt;[% terms.Bugzilla %] Search Form&lt;/a&gt;,
-  you may prefer &lt;a href=&quot;page.cgi?id=quicksearchhack.html&quot;&gt;this form&lt;/a&gt;.
-&lt;/p&gt;
</del><ins>+[% USE Bugzilla %]
</ins><span class="cx"> 
</span><del>-&lt;p&gt;
-  Type in one or more words (or word fragments) to search for:
-&lt;/p&gt;
</del><ins>+&lt;p&gt;Type in one or more words (or pieces of words) to search for:&lt;/p&gt;
</ins><span class="cx"> 
</span><span class="cx"> &lt;form name=&quot;f&quot; action=&quot;buglist.cgi&quot; method=&quot;get&quot;
</span><span class="cx">       onsubmit=&quot;if (this.quicksearch.value == '')
</span><span class="cx">                 { alert('Please enter one or more search terms first.');
</span><span class="cx">                   return false; } return true;&quot;&gt;
</span><span class="cx">   &lt;input type=&quot;text&quot; size=&quot;40&quot; name=&quot;quicksearch&quot;&gt;
</span><del>-  &lt;input type=&quot;submit&quot; value=&quot;Find&quot; id=&quot;find&quot;&gt;
</del><ins>+  &lt;input type=&quot;submit&quot; value=&quot;Search&quot; id=&quot;find&quot;&gt;
</ins><span class="cx"> &lt;/form&gt;
</span><span class="cx"> 
</span><del>-&lt;h2&gt;Getting Started&lt;/h2&gt;
</del><ins>+&lt;ul&gt;
+  &lt;li&gt;&lt;a href=&quot;#basics&quot;&gt;The Basics&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#basic_examples&quot;&gt;Examples of Simple Queries&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#fields&quot;&gt;Fields You Can Search On&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#advanced_features&quot;&gt;Advanced Features&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#shortcuts&quot;&gt;Advanced Shortcuts&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#advanced_examples&quot;&gt;Examples of Complex Queries&lt;/a&gt;&lt;/li&gt;
+&lt;/ul&gt;
</ins><span class="cx"> 
</span><del>-&lt;ul&gt;
-  &lt;li&gt;
-    This is &lt;strong&gt;case-insensitive&lt;/strong&gt; search:&lt;br /&gt;
-    &lt;ul&gt;
-      &lt;li&gt;&lt;tt&gt;table&lt;/tt&gt;, &lt;tt&gt;Table&lt;/tt&gt; and &lt;tt&gt;TABLE&lt;/tt&gt; are all the same.&lt;/li&gt;
-    &lt;/ul&gt;
</del><ins>+&lt;h2 id=&quot;basics&quot;&gt;The Basics&lt;/h2&gt;
+
+&lt;ul class=&quot;qs_help&quot;&gt;
+  &lt;li&gt;If you just put a word or series of words in the search box, 
+    [%+ terms.Bugzilla %] will search the 
+    [%+ field_descs.product FILTER html %],
+    [%+ field_descs.component FILTER html %], 
+    [%+ IF use_keywords %][%+ field_descs.keywords FILTER html %],[% END %]
+    [%+ IF Param('usebugaliases') %][% field_descs.alias FILTER html %],[% END %]
+    [%+ field_descs.short_desc FILTER html %], 
+    [%+ IF Param('usestatuswhiteboard') %][% field_descs.status_whiteboard FILTER html %],[% END %]
+    and [% field_descs.longdesc FILTER html %] fields for your word or words.&lt;/li&gt;
+
+  &lt;li&gt;Typing just a &lt;strong&gt;number&lt;/strong&gt; in the search box will take
+    you directly to the [% terms.bug %] with that ID. 
+    [% IF Param('usebugaliases') %]
+      Also, just typing the &lt;strong&gt;alias&lt;/strong&gt; of [% terms.abug %]
+      will take you to that [% terms.bug %].
+    [% END %]
</ins><span class="cx">   &lt;/li&gt;
</span><del>-  &lt;li&gt;
-    This is &lt;strong&gt;all words as substrings&lt;/strong&gt;
-    search.&lt;br /&gt;
-    Therefore you should &lt;strong&gt;use stems&lt;/strong&gt; to get better results:
-    &lt;ul&gt;
-      &lt;li&gt;
-        Use &lt;tt&gt;localiz&lt;/tt&gt; instead of &lt;tt&gt;localize&lt;/tt&gt; or
-        &lt;tt&gt;localization&lt;/tt&gt;.
-      &lt;/li&gt;
-     &lt;li&gt;
-       Use &lt;tt&gt;bookmark&lt;/tt&gt; instead of &lt;tt&gt;bookmarks&lt;/tt&gt; or
-       &lt;tt&gt;bookmarking&lt;/tt&gt;.
-     &lt;/li&gt;
-   &lt;/ul&gt;
-  &lt;/li&gt;
</del><ins>+
+  &lt;li&gt;Adding more terms &lt;strong&gt;narrows down&lt;/strong&gt; the search, it does not
+     expand it. (In other words, [% terms.Bugzilla %] searches for 
+     [%+ terms.bugs %] that match &lt;em&gt;all&lt;/em&gt; your criteria, not
+     [%+ terms.bugs %] that match &lt;em&gt;any&lt;/em&gt; of your criteria.)&lt;/li&gt;
+
+  &lt;li&gt;Searching is &lt;strong&gt;case-insensitive&lt;/strong&gt;. So &lt;kbd&gt;table&lt;/kbd&gt;,
+    &lt;kbd&gt;Table&lt;/kbd&gt;, and &lt;kbd&gt;TABLE&lt;/kbd&gt; are all the same.&lt;/li&gt;
+
+  &lt;li&gt;[% terms.Bugzilla %] does not just search for the exact word you put in,
+    but also for any word that &lt;strong&gt;contains&lt;/strong&gt; that word.
+    So, for example, searching for &quot;cat&quot; would also find [% terms.bugs %]
+    that contain it as part of other words&amp;mdash;for example, [% terms.abug %]
+    mentioning &quot;&lt;strong&gt;cat&lt;/strong&gt;ch&quot; or &quot;certifi&lt;strong&gt;cat&lt;/strong&gt;e&quot;. It
+    will not find partial words in the [% field_descs.longdesc FILTER html %]
+    or [% field_descs.keywords FILTER html %] fields,
+    though&amp;mdash;only full words are matched, there.&lt;/li&gt;
+
+  &lt;li&gt;By default, only &lt;strong&gt;open&lt;/strong&gt; [% terms.bugs %] are
+    searched. If you want to know how to also search closed [% terms.bugs %],
+    see the &lt;a href=&quot;#shortcuts&quot;&gt;Advanced Shortcuts&lt;/a&gt; section.&lt;/li&gt;
+
+  &lt;li&gt;If you want to search &lt;strong&gt;specific fields&lt;/strong&gt;, you do it like
+    &lt;kbd&gt;field:value&lt;/kbd&gt;, where &lt;kbd&gt;field&lt;/kbd&gt; is one of the 
+    &lt;a href=&quot;#fields&quot;&gt;field names&lt;/a&gt; lower down in this
+    document and &lt;kbd&gt;value&lt;/kbd&gt; is the value you want to search for
+    in that field. If you put commas in the &lt;kbd&gt;value&lt;/kbd&gt;, then it is
+    interpreted as a list of values, and [% terms.bugs %] that match
+    &lt;em&gt;any&lt;/em&gt; of those values will be searched for.&lt;/li&gt;
</ins><span class="cx"> &lt;/ul&gt;
</span><span class="cx"> 
</span><del>-&lt;h2&gt;&lt;a name=&quot;features&quot;&gt;Features&lt;/a&gt;&lt;/h2&gt;
</del><ins>+&lt;h2 id=&quot;basic_examples&quot;&gt;Examples of Simple Queries&lt;/h2&gt;
</ins><span class="cx"> 
</span><del>-&lt;ul&gt;
-  &lt;li&gt;
-    Boolean operations: &amp;ldquo;&lt;tt&gt;-foo&lt;/tt&gt;&amp;rdquo;&amp;nbsp;(NOT),
-    &amp;ldquo;&lt;tt&gt;foo&amp;nbsp;bar&lt;/tt&gt;&amp;rdquo;&amp;nbsp;(AND),
-    &amp;ldquo;&lt;tt&gt;foo|bar&lt;/tt&gt;&amp;rdquo;&amp;nbsp;(OR).
</del><ins>+&lt;p&gt;Here are some examples of how to write some simple queries.
+  &lt;a href=&quot;#advanced_examples&quot;&gt;Examples for more complex queries&lt;/a&gt; can be
+  found lower in this page.&lt;/p&gt;
+
+&lt;ul class=&quot;qs_help&quot;&gt;
+  &lt;li&gt;All open [% terms.bugs %] where userA@company.com is in the CC list
+    (no need to mention open [% terms.bugs %], this is the default):&lt;br&gt;
+    &lt;kbd&gt;cc:userA@company.com&lt;/kbd&gt;&lt;/li&gt;
+  &lt;li&gt;All unconfirmed [% terms.bugs %] in product productA (putting the
+    [%+ terms.bug %] status at the first position make it being automagically
+    considered as [% terms.abug %] status):&lt;br&gt;
+    &lt;kbd&gt;UNCONFIRMED product:productA&lt;/kbd&gt;
+  &lt;li&gt;All open and closed [% terms.bugs %] reported by userB@company.com
+    (we must specify ALL as the first word, else only open [% terms.bugs %]
+    are taken into account):&lt;br&gt;
+    &lt;kbd&gt;ALL reporter:userB@company.com&lt;/kbd&gt;
+  &lt;li&gt;All open [% terms.bugs %] with severity blocker or critical with the
+    target milestone set to 2.5:&lt;br&gt;
+    &lt;kbd&gt;severity:blocker,critical milestone:2.5&lt;/kbd&gt;
+  &lt;li&gt;All open [% terms.bugs %] in the component Research &amp; Development
+    with priority P1 or P2 (we must use quotes for the component as its name
+    contains whitespaces):&lt;br&gt;
+    &lt;kbd&gt;component:&quot;Research &amp; Development&quot; priority:P1,P2&lt;/kbd&gt;&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h2 id=&quot;fields&quot;&gt;Fields You Can Search On&lt;/h2&gt;
+
+&lt;p&gt;You can specify any of these fields like &lt;kbd&gt;field:value&lt;/kbd&gt;
+  in the search box, to search on them. You can also abbreviate
+  the field name, as long as your abbreviation matches only one field name.
+  So, for example, searching on &lt;kbd&gt;stat:VERIFIED&lt;/kbd&gt; will find all
+  [%+ terms.bugs %] in the &lt;kbd&gt;VERIFIED&lt;/kbd&gt; status. Some fields have
+  multiple names, and you can use any of those names to search for them.&lt;/p&gt;
+
+[% IF Bugzilla.active_custom_fields.size %]
+  [% SET first_field = Bugzilla.active_custom_fields.0 %]
+  &lt;p&gt;For custom fields, they can be used and abbreviated
+    based on the part of their name &lt;em&gt;after&lt;/em&gt; the &lt;kbd&gt;cf_&lt;/kbd&gt;
+    if you'd like, in addition to their standard name starting with
+    &lt;kbd&gt;cf_&lt;/kbd&gt;. So for example, 
+    &lt;kbd&gt;[% first_field.name FILTER html %]&lt;/kbd&gt; can be
+    referred to as 
+    &lt;kbd&gt;[% first_field.name.replace('^cf_') FILTER html %]&lt;/kbd&gt;,
+    also. However, if this causes a conflict between the standard
+    [%+ terms.Bugzilla %] field names and the custom field names, the
+    standard field names always take precedence.&lt;/p&gt;
+[% END %]
+
+[% SET field_table = {} %]
+[% FOREACH field = quicksearch_field_names.keys %]
+  [% description = field_descs.$field %]
+  [% field_table.$description = quicksearch_field_names.${field} %]
+[% END %]
+
+
+&lt;table cellspacing=&quot;0&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; class=&quot;qs_fields&quot;&gt;
+  &lt;thead&gt;
+    &lt;tr&gt;
+      &lt;th class=&quot;field_name&quot;&gt;Field&lt;/th&gt;
+      &lt;th class=&quot;field_nickname&quot;&gt;Field Name(s) For Search&lt;/th&gt;
+    &lt;/tr&gt;
+  &lt;/thead&gt;
+  &lt;tbody&gt;
+    [% FOREACH desc = field_table.keys.sort %]
+      &lt;tr&gt;
+        &lt;td class=&quot;field_name&quot;&gt;[% desc FILTER html %]&lt;/td&gt;
+        &lt;td class=&quot;field_nickname&quot;&gt;
+          [% FOREACH nickname = field_table.$desc %]
+            &lt;kbd&gt;[% nickname FILTER html %]&lt;/kbd&gt;
+            [% &quot;,&amp;nbsp; &quot; UNLESS loop.last %]
+          [% END %]
+      &lt;/tr&gt;
+    [% END %]
+  &lt;/tbody&gt;
+&lt;/table&gt;
+
+&lt;h2 id=&quot;advanced_features&quot;&gt;Advanced Features&lt;/h2&gt;
+
+&lt;ul class=&quot;qs_help&quot;&gt;
+  &lt;li&gt;If you want to search for a &lt;strong&gt;phrase&lt;/strong&gt; or something that
+    contains spaces, commas, colons or quotes, you must put it in quotes, like:
+    &lt;kbd&gt;&quot;yes, this is a phrase&quot;&lt;/kbd&gt;. You must also use quotes to search for
+    characters that would otherwise be interpreted specially by quicksearch.
+    For example, &lt;kbd&gt;&quot;this|that&quot;&lt;/kbd&gt; would search for the literal string
+    &lt;em&gt;this|that&lt;/em&gt; and would not be parsed as &lt;kbd&gt;&quot;this OR that&quot;&lt;/kbd&gt;.
+    Also, &lt;kbd&gt;&quot;-field:value&quot;&lt;/kbd&gt; would search for the literal phrase
+    &lt;em&gt;-field:value&lt;/em&gt; and would not be parsed as
+    &lt;kbd&gt;&quot;NOT field:value&quot;&lt;/kbd&gt;.&lt;/li&gt;
+
+  &lt;li&gt;You can use &lt;strong&gt;AND&lt;/strong&gt;, &lt;strong&gt;NOT&lt;/strong&gt;,
+    and &lt;strong&gt;OR&lt;/strong&gt; in searches. 
+
+    You can also use &lt;kbd&gt;-&lt;/kbd&gt; to mean &quot;NOT&quot;, and &lt;kbd&gt;|&lt;/kbd&gt; to mean &quot;OR&quot;.
+    There is no special character for &quot;AND&quot;, because by default any search
+    terms that are separated by a space are joined by an &quot;AND&quot;.
+    Examples:
</ins><span class="cx">     &lt;ul&gt;
</span><span class="cx">       &lt;li&gt;
</span><del>-        &lt;strong&gt;NOT&lt;/strong&gt;:&lt;br /&gt;
-        Use &lt;tt&gt;&lt;b&gt;-&lt;/b&gt;&lt;i&gt;foo&lt;/i&gt;&lt;/tt&gt; to exclude [% terms.bugs %]
-        with &lt;tt&gt;&lt;i&gt;foo&lt;/i&gt;&lt;/tt&gt; in the summary.
</del><ins>+        &lt;strong&gt;NOT&lt;/strong&gt;:&lt;br&gt;
+        Use &lt;kbd&gt;&lt;strong&gt;-&lt;/strong&gt;&lt;em&gt;summary:foo&lt;/em&gt;&lt;/kbd&gt; to exclude 
+        [%+ terms.bugs %] with &lt;kbd&gt;foo&lt;/kbd&gt; in the summary.&lt;br&gt;
+        &lt;kbd&gt;&lt;em&gt;NOT summary:foo&lt;/em&gt;&lt;/kbd&gt; would have the same effect.
</ins><span class="cx">       &lt;/li&gt;
</span><span class="cx">       &lt;li&gt;
</span><del>-        &lt;strong&gt;AND&lt;/strong&gt;:&lt;br /&gt;
-        Space-separated words are treated as a conjunction.
</del><ins>+        &lt;strong&gt;AND&lt;/strong&gt;:&lt;br&gt;
+        &lt;kbd&gt;&lt;em&gt;foo bar&lt;/em&gt;&lt;/kbd&gt; searches for [% terms.bugs %] that contains
+        both &lt;kbd&gt;foo&lt;/kbd&gt; and &lt;kbd&gt;bar&lt;/kbd&gt;.&lt;br&gt;
+        &lt;kbd&gt;&lt;em&gt;foo AND bar&lt;/em&gt;&lt;/kbd&gt; would have the same effect.
</ins><span class="cx">       &lt;/li&gt;
</span><span class="cx">       &lt;li&gt;
</span><del>-        &lt;strong&gt;OR&lt;/strong&gt;:&lt;br /&gt;
-        Within a word, &quot;|&quot;-separated parts denote alternatives.
</del><ins>+        &lt;strong&gt;OR&lt;/strong&gt;:&lt;br&gt;
+        &lt;kbd&gt;&lt;em&gt;foo&lt;strong&gt;|&lt;/strong&gt;bar&lt;/em&gt;&lt;/kbd&gt; would search
+        for [% terms.bugs %] that contain &lt;kbd&gt;foo&lt;/kbd&gt; OR &lt;kbd&gt;bar&lt;/kbd&gt;.&lt;br&gt;
+        &lt;kbd&gt;&lt;em&gt;foo OR bar&lt;/em&gt;&lt;/kbd&gt; would have the same effect.&lt;br&gt;
</ins><span class="cx">       &lt;/li&gt;
</span><del>-      &lt;li&gt;
-        Besides &quot;|&quot;, a comma can be used to separate alternatives.
-      &lt;/li&gt;
-      &lt;li&gt;
-        OR has higher precedence than AND; AND is the top level operation.
-      &lt;/li&gt;
</del><span class="cx">     &lt;/ul&gt;
</span><del>-    &lt;i&gt;Example:&lt;/i&gt;
-    &lt;tt&gt;url,location bar,field -focus&lt;/tt&gt; means
-    (&lt;tt&gt;url&lt;/tt&gt; OR &lt;tt&gt;location&lt;/tt&gt;) AND (&lt;tt&gt;bar&lt;/tt&gt; OR &lt;tt&gt;field&lt;/tt&gt;)
-    AND (NOT &lt;tt&gt;focus&lt;/tt&gt;)
-  &lt;/li&gt;
-  &lt;li&gt;
-    Use &lt;tt&gt;+foo&lt;/tt&gt; to search for [% terms.bugs %] where the
-    &lt;strong&gt;summary&lt;/strong&gt; contains &lt;tt&gt;foo&lt;/tt&gt; as a
-    &lt;strong&gt;substring&lt;/strong&gt;.&lt;br/&gt;
-    Use &lt;tt&gt;#foo&lt;/tt&gt; to search for [% terms.bugs %] where the
-    &lt;strong&gt;summary&lt;/strong&gt; contains the &lt;strong&gt;word&lt;/strong&gt; &lt;tt&gt;foo&lt;/tt&gt;.
-    &lt;ul&gt;
-      &lt;li&gt;
-        &lt;tt&gt;+brow&lt;/tt&gt; does not find all [% terms.bugs %] in the
-        &lt;tt&gt;Browser&lt;/tt&gt; product.
-      &lt;/li&gt;
-      &lt;li&gt;
-        &lt;tt&gt;#title&lt;/tt&gt; does not find [% terms.bugs %] with &lt;tt&gt;titlebar&lt;/tt&gt;
-        or &lt;tt&gt;titled&lt;/tt&gt;.
-      &lt;/li&gt;
-    &lt;/ul&gt;
-    Phrases with special chars (space, comma, +, -, #, &amp;hellip;) can be
-    &lt;strong&gt;quoted&lt;/strong&gt;:
-    &lt;ul&gt;
-      &lt;li&gt;
-        &lt;tt&gt;&quot;lock icon&quot;&lt;/tt&gt;
-      &lt;/li&gt;
-    &lt;/ul&gt;
-  &lt;/li&gt;
-  &lt;li&gt;
-    &lt;strong&gt;Open vs. Resolved [% terms.Bugs %]&lt;/strong&gt;:&lt;br /&gt;
-    By default, only open (i.e. unresolved) [% terms.bugs %] are shown.
-    Use &lt;tt&gt;+DUP&lt;/tt&gt; as first word in your search to include duplicate
-    [%+ terms.bugs %] in your search,
-    &lt;tt&gt;FIXED&lt;/tt&gt; to search for fixed [%+ terms.bugs %] only,
-    or &lt;tt&gt;ALL&lt;/tt&gt; to search all [% terms.bugs %],
-    regardless of status or resolution.
-    Searching for duplicates is recommended if you can't find an open
-    [%+ terms.bug %] directly.
-    &lt;ul&gt;
-      &lt;li&gt;
-        &lt;tt&gt;+DUP,FIXED table border&lt;/tt&gt;
-      &lt;/li&gt;
-      &lt;li&gt;
-        &lt;tt&gt;ALL mouse wheel&lt;/tt&gt;
-      &lt;/li&gt;
-    &lt;/ul&gt;
-  &lt;/li&gt;
-  &lt;li&gt;
-    &lt;strong&gt;Focus the Search with Products &amp;amp;
-    Components&lt;/strong&gt;:&lt;br /&gt;
-    To search for [% terms.bugs %] in product &quot;Foo Bar&quot; only, add
-    &lt;tt&gt;:foo&lt;/tt&gt; or &lt;tt&gt;:bar&lt;/tt&gt; or both to your search.
-    You can do this with any substring of a
-    &lt;a href=&quot;describecomponents.cgi&quot;&gt;product or component&lt;/a&gt; to focus the
-    search.
-  &lt;/li&gt;
-&lt;/ul&gt;
</del><span class="cx"> 
</span><del>-&lt;h2&gt;More Tips&lt;/h2&gt;
</del><ins>+    &lt;p&gt;You cannot use | nor OR to enumerate possible values for a given field.
+      You must use commas instead. So &lt;kbd&gt;field:value1,value2&lt;/kbd&gt; does what
+      you expect, but &lt;kbd&gt;field:value1|value2&lt;/kbd&gt; would be treated as
+      &lt;kbd&gt;field:value1 OR value2&lt;/kbd&gt;, which means value2 is not bound to
+      the given field.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;ul&gt;
-  &lt;li&gt;
-    You can also use this tool to &lt;strong&gt;lookup&lt;/strong&gt; a [% terms.bug %] by
-    its number:&lt;br /&gt;
-    &lt;ul&gt;
-      &lt;li&gt;&lt;tt&gt;12345&lt;/tt&gt;&lt;/li&gt;
-    &lt;/ul&gt;
</del><ins>+    &lt;p&gt;OR has higher precedence than AND; AND is the top level operation.
+      For example:&lt;/p&gt;
+    &lt;p&gt;Searching for &lt;em&gt;&lt;kbd&gt;url|location bar|field -focus&lt;/kbd&gt;&lt;/em&gt; means
+      (&lt;kbd&gt;url&lt;/kbd&gt; OR &lt;kbd&gt;location&lt;/kbd&gt;) AND (&lt;kbd&gt;bar&lt;/kbd&gt; OR 
+      &lt;kbd&gt;field&lt;/kbd&gt;) AND (NOT &lt;kbd&gt;focus&lt;/kbd&gt;)&lt;/p&gt;
</ins><span class="cx">   &lt;/li&gt;
</span><del>-  &lt;li&gt;
-    A comma-separated list of [% terms.bug %] numbers gives you a list of these
-    [%+ terms.bugs %]:&lt;br /&gt;
-    &lt;ul&gt;
-      &lt;li&gt;&lt;tt&gt;12345,23456,34567&lt;/tt&gt;&lt;/li&gt;
-    &lt;/ul&gt;
-  &lt;/li&gt;
</del><span class="cx"> &lt;/ul&gt;
</span><span class="cx"> 
</span><del>-&lt;p&gt;
-  By default, the following fields are searched: Summary, Keywords, Product,
-  Component, Status Whiteboard. If a word looks like a part of a URL, that field
-  is included in the search, too.
-&lt;/p&gt;
-&lt;hr&gt;
</del><ins>+&lt;h2 id=&quot;shortcuts&quot;&gt;Advanced Shortcuts&lt;/h2&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;
-  Use the powerful &lt;a href=&quot;query.cgi&quot;&gt;[% terms.Bugzilla %] Search Form&lt;/a&gt;
-  for advanced queries.
-&lt;/p&gt;
</del><ins>+&lt;p&gt;In addition to using &lt;a href=&quot;#fields&quot;&gt;field names&lt;/a&gt; to search
+  specific fields, there are certain characters or words that you can
+  use as a &quot;shortcut&quot; for searching certain fields:&lt;/p&gt;
</ins><span class="cx"> 
</span><ins>+&lt;table cellspacing=&quot;0&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; class=&quot;qs_fields&quot;&gt;
+  &lt;thead&gt;
+    &lt;tr&gt;
+      &lt;th class=&quot;field_name&quot;&gt;Field&lt;/th&gt;
+      &lt;th class=&quot;field_nickname&quot;&gt;Shortcut(s)&lt;/th&gt;
+    &lt;/tr&gt;
+  &lt;/thead&gt;
+  &lt;tbody&gt;
+    &lt;tr&gt;
+      &lt;td class=&quot;field_name&quot;&gt;[% field_descs.bug_status FILTER html %]&lt;/td&gt;
+      &lt;td class=&quot;field_nickname&quot;&gt;
+        Make the &lt;strong&gt;first word&lt;/strong&gt; of your search the name of any
+        status, or even an abbreviation of any status, and [% terms.bugs %]
+        in that status will be searched. &lt;strong&gt;&lt;kbd&gt;ALL&lt;/kbd&gt;&lt;/strong&gt;
+        is a special shortcut that means &quot;all statuses&quot;.
+        &lt;strong&gt;&lt;kbd&gt;OPEN&lt;/kbd&gt;&lt;/strong&gt; is a special shortcut that means
+        &quot;all open statuses&quot;.
+      &lt;/td&gt;
+    &lt;/tr&gt;
+    &lt;tr&gt;
+      &lt;td class=&quot;field_name&quot;&gt;[% field_descs.resolution FILTER html %]&lt;/td&gt;
+      &lt;td class=&quot;field_nickname&quot;&gt;
+        Make the &lt;strong&gt;first word&lt;/strong&gt; of your search the name of any
+        resolution, or even an abbreviation of any resolution, and 
+        [%+ terms.bugs %] with that resolution will be searched. For example,
+        making &lt;kbd&gt;FIX&lt;/kbd&gt; the first word of your search will find all
+        [%+ terms.bugs %] with a resolution of &lt;kbd&gt;FIXED&lt;/kbd&gt; .
+    &lt;/tr&gt;
+    &lt;tr&gt;
+      &lt;td class=&quot;field_name&quot;&gt;[% field_descs.priority FILTER html %]&lt;/td&gt;
+      &lt;td class=&quot;field_nickname&quot;&gt;&quot;&lt;strong&gt;P1&lt;/strong&gt;&quot; (as a word anywhere in
+        the search) means &quot;find [% terms.bugs %] with the highest priority. 
+        &quot;P2&quot; means the second-highest priority, and so on.
+        &lt;p&gt;Searching for &quot;&lt;strong&gt;P1-3&lt;/strong&gt;&quot; will find [% terms.bugs %] in
+        any of the three highest priorities, and so on.&lt;/p&gt;
+      &lt;/td&gt;
+    &lt;/tr&gt;
+    &lt;tr&gt;
+      &lt;td class=&quot;field_name&quot;&gt;[% field_descs.assigned_to FILTER html %]&lt;/td&gt;
+      &lt;td class=&quot;field_nickname&quot;&gt;&lt;strong&gt;@&lt;/strong&gt;&lt;em&gt;value&lt;/em&gt;&lt;/td&gt;
+    &lt;/tr&gt;
+    &lt;tr&gt;
+      &lt;td class=&quot;field_name&quot;&gt;[% field_descs.product FILTER html %] or
+        [%+ field_descs.component FILTER html %]&lt;/td&gt;
+      &lt;td class=&quot;field_nickname&quot;&gt;&lt;strong&gt;:&lt;/strong&gt;&lt;em&gt;value&lt;/em&gt;&lt;/td&gt;
+    &lt;/tr&gt;
+    [% IF use_keywords %]
+      &lt;tr&gt;
+        &lt;td class=&quot;field_name&quot;&gt;[% field_descs.keywords FILTER html %]&lt;/td&gt;
+        &lt;td class=&quot;field_nickname&quot;&gt;&lt;strong&gt;!&lt;/strong&gt;&lt;em&gt;value&lt;/em&gt;&lt;/td&gt;
+      &lt;/tr&gt;
+    [% END %]
+    &lt;tr&gt;
+      [% SET key = &quot;flagtypes.name&quot; %]
+      &lt;td class=&quot;field_name&quot;&gt;[% field_descs.$key FILTER html %]&lt;/td&gt;
+      &lt;td class=&quot;field_nickname&quot;&gt;
+        &lt;em&gt;flag&lt;/em&gt;&lt;strong&gt;?&lt;/strong&gt;&lt;em&gt;requestee&lt;/em&gt;
+      &lt;/td&gt;
+    &lt;/tr&gt;
+    &lt;tr&gt;
+      &lt;td class=&quot;field_name&quot;&gt;[% field_descs.longdesc FILTER html %]
+        or [% field_descs.short_desc FILTER html %]&lt;/td&gt;
+      &lt;td class=&quot;field_nickname&quot;&gt;
+        &lt;strong&gt;#&lt;/strong&gt;&lt;em&gt;value&lt;/em&gt;
+      &lt;/td&gt;
+    &lt;/tr&gt;
+    [% IF Param('usestatuswhiteboard') %]
+      &lt;tr&gt;
+        &lt;td class=&quot;field_name&quot;&gt;[% field_descs.short_desc FILTER html %]
+          or [% field_descs.status_whiteboard FILTER html %]&lt;/td&gt;
+        &lt;td class=&quot;field_nickname&quot;&gt;&lt;strong&gt;[&lt;/strong&gt;&lt;em&gt;value&lt;/em&gt;&lt;/td&gt;
+      &lt;/tr&gt;
+    [% END %]
+  &lt;/tbody&gt;
+&lt;/table&gt;
+
+&lt;h2 id=&quot;advanced_examples&quot;&gt;Examples of Complex Queries&lt;/h2&gt;
+
+&lt;p&gt;It is pretty easy to write rather complex queries without too much effort.
+  For very complex queries, you have to use the
+  &lt;a href=&quot;query.cgi?format=advanced&quot;&gt;Advanced Search&lt;/a&gt; form.&lt;/p&gt;
+
+&lt;ul class=&quot;qs_help&quot;&gt;
+  &lt;li&gt;All [% terms.bugs %] reported by userA@company.com or assigned to him
+    (the initial @ is a shortcut for the assignee, see the
+    &lt;a href=&quot;#shortcuts&quot;&gt;Advanced Shortcuts&lt;/a&gt; section above):&lt;br&gt;
+    &lt;kbd&gt;ALL @userA@company.com OR reporter:userA@company.com&lt;/kbd&gt;&lt;/li&gt;
+  &lt;li&gt;All open [% terms.bugs %] in product productA with either severity
+    blocker, critical or major, or with priority P1, or with the blocker+
+    flag set, and which are neither assigned to userB@company.com nor to
+    userC@company.com (we make the assumption that there are only two users
+    matching userB and userC, else we would write the whole login name):&lt;br&gt;
+    &lt;kbd&gt;:productA sev:blocker,critical,major OR pri:P1 OR flag:blocker+ -assign:userB,userC&lt;/kbd&gt;&lt;/li&gt;
+  &lt;li&gt;All FIXED [% terms.bugs %] with the blocker+ flag set, but without
+    the approval+ nor approval? flags set:&lt;br&gt;
+    &lt;kbd&gt;FIXED flag:blocker+ -flag:approval+ -flag:approval?&lt;/kbd&gt;&lt;/li&gt;
+  &lt;li&gt;[% terms.Bugs %] with &lt;em&gt;That's a &quot;unusual&quot; issue&lt;/em&gt; in the
+    [%+ terms.bug %] summary (double quotes are escaped using &lt;em&gt;\&quot;&lt;/em&gt;):&lt;br&gt;
+    &lt;kbd&gt;summary:&quot;That's a \&quot;unusual\&quot; issue&quot;&lt;/kbd&gt;&lt;/li&gt;
+&lt;/ul&gt;
+
</ins><span class="cx"> [% PROCESS global/footer.html.tmpl %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultpagesquicksearchhackhtmltmpl"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/template/en/default/pages/quicksearchhack.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/pages/quicksearchhack.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/pages/quicksearchhack.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,387 +0,0 @@
</span><del>-[%# The contents of this file are subject to the Mozilla Public
-  # License Version 1.1 (the &quot;License&quot;); you may not use this file
-  # except in compliance with the License. You may obtain a copy of
-  # the License at http://www.mozilla.org/MPL/
-  #
-  # Software distributed under the License is distributed on an &quot;AS
-  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
-  # implied. See the License for the specific language governing
-  # rights and limitations under the License.
-  #
-  # The Original Code is the Bugzilla Bug Tracking System.
-  #
-  # Contributor(s): N.N.
-  #                 Marc Schumann &lt;wurblzap@gmail.com&gt;
-  #%]
-
-[% PROCESS global/variables.none.tmpl %]
-
-[% INCLUDE global/header.html.tmpl
-   title  = &quot;$terms.Bugzilla QuickSearch (for Hackers)&quot;,
-   style  = 'th {text-align: left}'
-   onload = 'document.forms[\'f\'].quicksearch.focus()'
- %]
-
-&lt;p&gt;
-  Type in one or more words (or word fragments) to search for:
-&lt;/p&gt;
-
-&lt;form name=&quot;f&quot; action=&quot;buglist.cgi&quot; method=&quot;get&quot;
-      onsubmit=&quot;if (this.quicksearch.value == '')
-                { alert('Please enter one or more search terms first.');
-                  return false; } return true;&quot;&gt;
-  &lt;input type=&quot;text&quot; size=&quot;40&quot; name=&quot;quicksearch&quot;&gt;
-  &lt;input type=&quot;submit&quot; value=&quot;Find&quot; id=&quot;find&quot;&gt;
-  &lt;input type=&quot;submit&quot; name=&quot;load&quot; value=&quot;Load Search Form&quot; id=&quot;load&quot;&gt;
-&lt;/form&gt;
-
-&lt;p&gt;
-  This is a case-insensitive &amp;ldquo;all words as substrings&amp;rdquo; search;
-  words are separated by spaces.
-  By default, the following fields are relevant: Summary, Keywords,
-  Product, Component, Status Whiteboard.
-  If a word looks like a part of a URL, that field is included in the search,
-  too.
-&lt;/p&gt;
-&lt;p&gt;
-  The generic format for a &amp;ldquo;word&amp;rdquo; is
-  &lt;tt&gt;field1,&amp;hellip;,fieldN:value1,&amp;hellip;,valueM&lt;/tt&gt;.
-  A [% terms.bug %] qualifies if at least one of the values occurs as a
-  substring in at least one of the fields.
-  For example, &lt;tt&gt;assignee,reporter,qa:ibm,sun&lt;/tt&gt; will give you
-  [%+ terms.bugs %] where the assignee, reporter, or qa contact has a login
-  that contains &lt;tt&gt;ibm&lt;/tt&gt; or &lt;tt&gt;sun&lt;/tt&gt;.
-  If only &lt;tt&gt;value1,&amp;hellip;,valueM&lt;/tt&gt; is given, the prefix (roughly) defaults to
-  &lt;tt&gt;summary,keywords,product,component,statuswhiteboard:&lt;/tt&gt; as noted above.
-  You can use &lt;tt&gt;-&lt;i&gt;word&lt;/i&gt;&lt;/tt&gt; to express the logical negation of
-  &lt;tt&gt;&lt;i&gt;word&lt;/i&gt;&lt;/tt&gt;.
-&lt;/p&gt;
-&lt;p&gt;
-  Here is a complete listing of available fields (the Shortcut column is just
-  for access speed):
-&lt;/p&gt;
-
-&lt;table border=&quot;1&quot;&gt;
-&lt;thead&gt;
-&lt;tr&gt;
-  &lt;th&gt;Searched by default&lt;/th&gt;
-  &lt;th&gt;Shortcut&lt;/th&gt;
-  &lt;th&gt;Field Name&lt;/th&gt;
-  &lt;th&gt;Aliases&lt;/th&gt;
-  &lt;th&gt;Description&lt;/th&gt;
-&lt;/tr&gt;
-&lt;/thead&gt;
-
-&lt;!-- Status, Resolution, Platform, OS, Priority, Severity --&gt;
-
-&lt;tr&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td rowspan=&quot;2&quot;&gt;
-    &lt;tt&gt;UNCO,NEW,&amp;hellip;,CLOS,&lt;br&gt;FIX,DUP,&amp;hellip;&lt;i&gt;(as first word)&lt;/i&gt;&lt;/tt&gt;
-  &lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;status&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;
-    &lt;a href=&quot;page.cgi?id=fields.html#status&quot;&gt;Status&lt;/a&gt;
-    &lt;i&gt;(&amp;ldquo;bug_status&amp;rdquo;)&lt;/i&gt;
-  &lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;resolution&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&lt;a href=&quot;page.cgi?id=fields.html#resolution&quot;&gt;Resolution&lt;/a&gt;&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&lt;i&gt;as-is&lt;/i&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;platform&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;
-    &lt;a href=&quot;page.cgi?id=fields.html#rep_platform&quot;&gt;Platform&lt;/a&gt;
-    &lt;i&gt;(&amp;ldquo;rep_platform&amp;rdquo;)&lt;/i&gt;
-  &lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;os&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;opsys&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;
-    &lt;a href=&quot;page.cgi?id=fields.html#op_sys&quot;&gt;OS&lt;/a&gt;
-    &lt;i&gt;(&amp;ldquo;op_sys&amp;rdquo;)&lt;/i&gt;
-  &lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;p1,p2&lt;/tt&gt; &lt;i&gt;or&lt;/i&gt; &lt;tt&gt;p1-2&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;priority&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;pri&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;a href=&quot;page.cgi?id=fields.html#priority&quot;&gt;Priority&lt;/a&gt;&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;blo,cri,&amp;hellip;,enh&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;severity&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;sev&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;
-    &lt;a href=&quot;page.cgi?id=fields.html#bug_severity&quot;&gt;Severity&lt;/a&gt;
-    &lt;i&gt;(&amp;ldquo;bug_severity&amp;rdquo;)&lt;/i&gt;
-  &lt;/td&gt;
-&lt;/tr&gt;
-
-&lt;!-- People: AssignedTo, Reporter, QA Contact, CC, Added comment --&gt;
-&lt;!-- Added comment is missing!!!! --&gt;
-
-&lt;tr&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&lt;b&gt;@&lt;/b&gt;&lt;i&gt;assignee&lt;/i&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;assignedto&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;assignee&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;
-    &lt;a href=&quot;page.cgi?id=fields.html#assigned_to&quot;&gt;Assignee&lt;/a&gt;
-    &lt;i&gt;(&amp;ldquo;assigned_to&amp;rdquo;)&lt;/i&gt;
-  &lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;reporter&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;rep&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;Reporter (login)&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;qa&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;qacontact&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;QA Contact (login) &lt;i&gt;(&amp;ldquo;qa_contact&amp;rdquo;)&lt;/i&gt;&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;cc&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;CC (login)&lt;/td&gt;
-&lt;/tr&gt;
-
-&lt;!-- Product, Version, Component, Target Milestone --&gt;
-
-&lt;tr&gt;
-  &lt;td&gt;&lt;i&gt;yes&lt;/i&gt;&lt;/td&gt;
-  &lt;td rowspan=&quot;2&quot;&gt;&lt;b&gt;:&lt;/b&gt;&lt;i&gt;area&lt;/i&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;product&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;prod&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;Product (enum)&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&lt;i&gt;yes&lt;/i&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;component&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;comp&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;a href=&quot;describecomponents.cgi&quot;&gt;Component&lt;/a&gt;&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;version&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;ver&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;Version (enum)&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;milestone&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;target, targetmilestone&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;Target Milestone &lt;i&gt;(&amp;ldquo;target_milestone&amp;rdquo;)&lt;/i&gt;&lt;/td&gt;
-&lt;/tr&gt;
-
-&lt;!-- Summary, Description, URL, Status whiteboard, Keywords --&gt;
-
-&lt;tr&gt;
-  &lt;td&gt;&lt;i&gt;yes&lt;/i&gt;&lt;/td&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;summary&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;shortdesc&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;
-    [% terms.Bug %] Summary (short text)
-    &lt;i&gt;(&amp;ldquo;short_desc&amp;rdquo;)&lt;/i&gt;
-  &lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;description&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;desc, longdesc&lt;!--, comment--&gt;&lt;/tt&gt;&lt;/td&gt;
-  &lt;!-- reserve &quot;comment&quot; for &quot;added comment&quot; login search?! --&gt;
-  &lt;td&gt;[% terms.Bug %] Description / Comments (long text)&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&lt;i&gt;depends&lt;/i&gt;&lt;/td&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;url&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;URL &lt;i&gt;(&amp;ldquo;bug_file_loc&amp;rdquo;)&lt;/i&gt;&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&lt;i&gt;yes&lt;/i&gt;&lt;/td&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;statuswhiteboard&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;sw, whiteboard&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;Status Whiteboard &lt;i&gt;(&amp;ldquo;status_whiteboard&amp;rdquo;)&lt;/i&gt;&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&lt;i&gt;yes&lt;/i&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;b&gt;!&lt;/b&gt;&lt;i&gt;keyword&lt;/i&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;keywords&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;kw&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;a href=&quot;describekeywords.cgi&quot;&gt;Keywords&lt;/a&gt;&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;group&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;Group&lt;/td&gt;
-&lt;/tr&gt;
-
-&lt;!-- Flags --&gt;
-
-&lt;tr&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td rowspan=&quot;2&quot;&gt;&lt;i&gt;flag&lt;/i&gt;&lt;b&gt;?&lt;/b&gt;&lt;i&gt;requestee&lt;/i&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;flag&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;Flag name and status (+, - or ?)&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;requestee&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;req&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;Flag requestee (login)&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;setter&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;set&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;Flag setter (login)&lt;/td&gt;
-&lt;/tr&gt;
-
-&lt;!-- Attachments --&gt;
-
-&lt;tr&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;attachmentdesc&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;attachdesc&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;
-    Attachment Description
-    &lt;i&gt;(&amp;ldquo;attachments.description&amp;rdquo;)&lt;/i&gt;
-  &lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;attachmentdata&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;attachdata&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;Attachment Data &lt;i&gt;(&amp;ldquo;attach_data.thedata&amp;rdquo;)&lt;/i&gt;&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;attachmentmimetype&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;attachmimetype&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;Attachment mime-type &lt;i&gt;(&amp;ldquo;attachments.mimetype&amp;rdquo;)&lt;/i&gt;&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;&lt;tt&gt;votes&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&amp;nbsp;&lt;/td&gt;
-  &lt;td&gt;
-    Number of votes&lt;br&gt;
-    (votes:&lt;i&gt;N&lt;/i&gt; and votes&amp;gt;=&lt;i&gt;N&lt;/i&gt; mean &quot;at least N votes&quot;,
-    votes&amp;gt;&lt;i&gt;N&lt;/i&gt; means &quot;more than N votes&quot;)
-  &lt;/td&gt;
-&lt;/tr&gt;
-&lt;/table&gt;
-
-&lt;p&gt;
-  Examples for some useful abbreviations:
-&lt;/p&gt;
-&lt;table border=&quot;1&quot;&gt;
-&lt;thead&gt;
-&lt;tr&gt;
-  &lt;th&gt;Syntax&lt;/th&gt;
-  &lt;th&gt;Semantics and Examples&lt;/th&gt;
-&lt;/tr&gt;
-&lt;/thead&gt;
-
-&lt;!--
-&lt;tr&gt;
-  &lt;td&gt;&lt;i&gt;STAT&lt;/i&gt; &lt;i&gt;(as first word)&lt;/i&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;b&gt;status,resolution:&lt;/b&gt; &lt;i&gt;STAT&lt;/i&gt;&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&lt;tt&gt;ALL&lt;/tt&gt; &lt;i&gt;(as first word)&lt;/i&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;i&gt;include all resolved [% terms.bugs %] in your search&lt;/i&gt;&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&lt;tt&gt;+DUP,FIXED&lt;/tt&gt; &lt;i&gt;(as first word)&lt;/i&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;i&gt;include DUPLICATE and FIXED [% terms.bugs %] in your search&lt;/i&gt;&lt;/td&gt;
-&lt;/tr&gt;
---&gt;
-
-&lt;tr&gt;
-  &lt;td&gt;&lt;b&gt;:&lt;/b&gt;&lt;i&gt;area&lt;/i&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;b&gt;product,component:&lt;/b&gt;&lt;i&gt;area&lt;/i&gt;&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&lt;i&gt;sev&lt;/i&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;b&gt;severity:&lt;/b&gt;&lt;i&gt;sev&lt;/i&gt;&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&lt;tt&gt;blo,cri,maj&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;i&gt;severe [% terms.bugs %]&lt;/i&gt;&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&lt;tt&gt;enh&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;i&gt;enhancement requests&lt;/i&gt;&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&lt;b&gt;p&lt;/b&gt;&lt;i&gt;level&lt;/i&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;b&gt;priority:&lt;/b&gt;&lt;i&gt;level&lt;/i&gt;&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&lt;tt&gt;p1&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;i&gt;very high-priority [% terms.bugs %]&lt;/i&gt;&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&lt;tt&gt;p1-2&lt;/tt&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;i&gt;high-priority [% terms.bugs %]&lt;/i&gt;&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&lt;b&gt;@&lt;/b&gt;&lt;i&gt;assignee&lt;/i&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;b&gt;assignedto:&lt;/b&gt;&lt;i&gt;assignee&lt;/i&gt;&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&lt;b&gt;!&lt;/b&gt;&lt;i&gt;keyword&lt;/i&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;b&gt;keywords:&lt;/b&gt;&lt;i&gt;keyword&lt;/i&gt;&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-  &lt;td&gt;&lt;i&gt;flag&lt;/i&gt;&lt;b&gt;?&lt;/b&gt;&lt;i&gt;requestee&lt;/i&gt;&lt;/td&gt;
-  &lt;td&gt;&lt;b&gt;flag:&lt;/b&gt;&lt;i&gt;flag?&lt;/i&gt; &lt;b&gt;requestee:&lt;/b&gt;&lt;i&gt;requestee&lt;/i&gt;&lt;/td&gt;
-&lt;/tr&gt;
-&lt;/table&gt;
-
-&lt;p&gt;
-  More information can be found in the
-  &lt;a href=&quot;page.cgi?id=quicksearch.html#features&quot;&gt;&amp;ldquo;Features&amp;rdquo;&lt;/a&gt;
-  section on the &lt;a href=&quot;page.cgi?id=quicksearch.html&quot;&gt;introductory page&lt;/a&gt;.
-&lt;/p&gt;
-
-[% PROCESS global/footer.html.tmpl %]
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultpagesreleasenoteshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/pages/release-notes.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/pages/release-notes.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/pages/release-notes.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -15,1345 +15,1221 @@
</span><span class="cx">   # Everything Solved. All Rights Reserved.
</span><span class="cx">   #
</span><span class="cx">   # Contributor(s): Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
</span><ins>+  #                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><ins>+[% SET title = &quot;$terms.Bugzilla 4.2 Release Notes&quot; %]
</ins><span class="cx"> [% INCLUDE global/header.html.tmpl 
</span><del>-  title = &quot;$terms.Bugzilla 3.2.3 Release Notes&quot; 
-  style_urls = ['skins/standard/release-notes.css'] 
</del><ins>+  title = title
+  style_urls = ['skins/standard/page.css'] 
</ins><span class="cx"> %]
</span><span class="cx"> 
</span><del>-&lt;h2&gt;Table of Contents&lt;/h2&gt;
</del><ins>+&lt;h1&gt;[% title FILTER html %]&lt;/h1&gt;
</ins><span class="cx"> 
</span><span class="cx"> &lt;ul class=&quot;bz_toc&quot;&gt;
</span><del>-  &lt;li&gt;&lt;a href=&quot;#v32_introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v32_point&quot;&gt;Updates In This 3.2.x Release&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v32_security&quot;&gt;Security Fixes In This 3.2.x Release&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v32_req&quot;&gt;Minimum Requirements&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v32_feat&quot;&gt;New Features and Improvements&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v32_issues&quot;&gt;Outstanding Issues&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v32_upgrading&quot;&gt;How to Upgrade From An Older Version&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v32_code_changes&quot;&gt;Code Changes Which May Affect 
-    Customizations&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v32_previous&quot;&gt;Release Notes for Previous Versions&lt;/a&gt;&lt;/li&gt;
</del><ins>+  &lt;li&gt;&lt;a href=&quot;#v42_introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v42_point&quot;&gt;Updates in this 4.2.x Release&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v42_req&quot;&gt;Minimum Requirements&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v42_feat&quot;&gt;New Features and Improvements&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v42_issues&quot;&gt;Outstanding Issues&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v42_code_changes&quot;&gt;Code Changes Which May Affect
+    Customizations and Extensions&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v42_previous&quot;&gt;Release Notes for Previous Versions&lt;/a&gt;&lt;/li&gt;
</ins><span class="cx"> &lt;/ul&gt;
</span><span class="cx"> 
</span><del>-&lt;h2&gt;&lt;a name=&quot;v32_introduction&quot;&gt;&lt;/a&gt;Introduction&lt;/h2&gt;
</del><ins>+&lt;h2 id=&quot;v42_introduction&quot;&gt;Introduction&lt;/h2&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;Welcome to [% terms.Bugzilla %] 3.2! This is our first major feature
-  release since [% terms.Bugzilla %] 3.0, and it brings a lot of great
-  improvements and polish to the [% terms.Bugzilla %] experience.&lt;/p&gt;
</del><ins>+&lt;p&gt;Welcome to [% terms.Bugzilla %] 4.2! It has been almost a year since we
+  released [% terms.Bugzilla %] 4.0 on February 2011, and this new major
+  release comes with several new features and improvements. This release
+  contains major improvements to search, support for SQLite, improved
+  WebServices, and lots of other enhancements.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;If you're upgrading, make sure to read &lt;a href=&quot;#v32_upgrading&quot;&gt;How to
-  Upgrade From An Older Version&lt;/a&gt;. If you are upgrading from a release
-  before 3.0, make sure to read the release notes for all the 
-  &lt;a href=&quot;#v32_previous&quot;&gt;previous versions&lt;/a&gt; in between your version
-  and this one, &lt;strong&gt;particularly the &quot;Notes For Upgraders&quot; section of each
-  version's release notes&lt;/strong&gt;.&lt;/p&gt;
</del><ins>+&lt;p&gt;If you are upgrading from a release before 4.0, make sure to read the
+  release notes for all the &lt;a href=&quot;#v42_previous&quot;&gt;previous versions&lt;/a&gt;
+  in between your version and this one, &lt;strong&gt;particularly the Upgrading
+  section of each version's release notes&lt;/strong&gt;.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;h2&gt;&lt;a name=&quot;v32_point&quot;&gt;Updates in this 3.2.x Release&lt;/a&gt;&lt;/h2&gt;
</del><ins>+&lt;h2 id=&quot;v42_point&quot;&gt;Updates in this 4.2.x Release&lt;/h2&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;This section describes what's changed in the most recent b&lt;!-- --&gt;ug-fix
-  releases of [% terms.Bugzilla %] after 3.2. We only list the
-  most important fixes in each release. If you want a detailed list of
-  &lt;em&gt;everything&lt;/em&gt; that's changed in each version, you should use our
-  &lt;a href=&quot;http://www.bugzilla.org/status/changes.html&quot;&gt;Change Log 
-  Page&lt;/a&gt;.&lt;/p&gt;
</del><ins>+&lt;h3&gt;4.2.1&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;3.2.3&lt;/h3&gt;
-
-&lt;ul&gt;
-  &lt;li&gt;[% terms.Bugzilla %] is now compatible with MySQL 5.1.x versions 5.1.31
-    and greater.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=480001&quot;&gt;[% terms.Bug %] 480001&lt;/a&gt;)&lt;/li&gt;
-  &lt;li&gt;On Windows, [% terms.Bugzilla %] sometimes would send mangled emails 
-    (that would often fail to send).
-  (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=467920&quot;&gt;[% terms.Bug %] 467920&lt;/a&gt;)&lt;/li&gt;
-  &lt;li&gt;&lt;code&gt;recode.pl&lt;/code&gt; would sometimes crash when trying to convert
-    databases from older versions of [% terms.Bugzilla %].
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=431201&quot;&gt;[% terms.Bug %] 431201&lt;/a&gt;)&lt;/li&gt;
-  &lt;li&gt;Running a saved search with Unicode characters in its name would
-    cause [% terms.Bugzilla %] to crash.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=477513&quot;&gt;[% terms.Bug %] 477513&lt;/a&gt;)&lt;/li&gt;
-  &lt;li&gt;[% terms.Bugzilla %] clients like Mylyn can now update [% terms.bugs %]
-    again (the [% terms.bug %] XML format now contains a &quot;token&quot; element that
-    can be used when updating a bug).
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=476678&quot;&gt;[% terms.Bug %] 476678&lt;/a&gt;)&lt;/li&gt;
-  &lt;li&gt;For installations using the &lt;code&gt;shadowdb&lt;/code&gt; parameter, 
-    [% terms.Bugzilla %] was accidentally writing to the &quot;tokens&quot; table
-    in the shadow database (instead of the master database) when using the
-    &quot;Change Several [% terms.Bugs %] at Once&quot; page.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=476943&quot;&gt;[% terms.Bug  %] 476943&lt;/a&gt;)&lt;/li&gt;
-&lt;/ul&gt;
-
-&lt;p&gt;This release also contains a security fix. See the
-  &lt;a href=&quot;#v32_security&quot;&gt;Security Fixes Section&lt;/a&gt; for details.&lt;/p&gt;
-
-&lt;h3&gt;3.2.2&lt;/h3&gt;
-
-&lt;p&gt;This release fixes one security issue that is critical for installations
-  running 3.2.1 under mod_perl. See the 
-  &lt;a href=&quot;http://www.bugzilla.org/security/3.0.7/&quot;&gt;Security Advisory&lt;/a&gt;
</del><ins>+&lt;p&gt;This release fixes two security issues. See the
+  &lt;a href=&quot;http://www.bugzilla.org/security/3.6.8/&quot;&gt;Security Advisory&lt;/a&gt;
</ins><span class="cx">   for details.&lt;/p&gt;
</span><span class="cx"> 
</span><del>-&lt;h3&gt;3.2.1&lt;/h3&gt;
</del><ins>+&lt;p&gt;In addition, the following important fixes/changes have been made in this
+  release:&lt;/p&gt;
</ins><span class="cx"> 
</span><span class="cx"> &lt;ul&gt;
</span><del>-  &lt;li&gt;Attachments, charts, and graphs would sometimes be garbled on Windows.
-  (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=464992&quot;&gt;[% terms.Bug %] 464992&lt;/a&gt;)&lt;/li&gt;
-
-  &lt;li&gt;Saving changes to parameters would sometimes fail silently (particularly
-    on Windows when the web server didn't have the right permissions to
-    update the &lt;code&gt;params&lt;/code&gt; file). [% terms.Bugzilla %] will now
-    throw an error in this case, telling you what is wrong.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=347707&quot;&gt;[% terms.Bug %] 347707&lt;/a&gt;)&lt;/li&gt;
-
-  &lt;li&gt;If you were using the &lt;code&gt;usemenuforusers&lt;/code&gt; parameter,
-    and [% terms.abug %] was assigned to (or had a QA Contact of) a disabled
-    user, that field would be reset to the first user in the list when
-    updating [% terms.abug %].
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=465589&quot;&gt;[% terms.Bug %] 465589&lt;/a&gt;)&lt;/li&gt;
-
-  &lt;li&gt;If you were using the &lt;code&gt;PROJECT&lt;/code&gt; environment variable
-    to have multiple [% terms.Bugzilla %] installations using one codebase,
-    project-specific templates were being ignored. 
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=467324&quot;&gt;[% terms.Bug %] 467324&lt;/a&gt;)&lt;/li&gt;
-
-  &lt;li&gt;Some versions of the SOAP::Lite Perl module had a b[% %]ug that caused
-    [%+ terms.Bugzilla %]'s XML-RPC service to break. 
-    &lt;code&gt;checksetup.pl&lt;/code&gt; now checks for these bad versions and 
-    will reject them.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=468009&quot;&gt;[% terms.Bug %] 468009&lt;/a&gt;)&lt;/li&gt;
-
-  &lt;li&gt;The font sizes in various places were too small, when using the
-    Classic skin.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=469136&quot;&gt;[% terms.Bug %] 469136&lt;/a&gt;)&lt;/li&gt;
</del><ins>+  &lt;li&gt;Due to a regression introduced when fixing CVE-2012-0453, if an XML-RPC
+    client sets the charset as part of its Content-Type header, we were
+    incorrectly rejecting the request. The header is now correctly parsed.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=731219&quot;&gt;[% terms.Bug %] 731219&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;Email notifications about status changes in blockers were incorrectly
+    formatted. Several pieces of text were missing in the emails.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=731586&quot;&gt;[% terms.Bug %] 731586&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;Many [% terms.bugs %] related to the searching system have been fixed.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/buglist.cgi?bug_id=58179,715270,730984,731163,737436,745320&quot;&gt;
+    [% terms.Bugs %] 58179, 715270, 730984, 731163, 737436 and 745320&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;When using the QuickSearch box, complex queries are now parsed correctly.
+    It also behaves correctly with non-ASCII characters (such as Ã©, Ã¤, Ã¼, etc.).
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/buglist.cgi?bug_id=554819,663377,730207&quot;&gt;
+    [% terms.Bugs %] 554819, 663377 and 730207&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;The 'take' link besides the assignee field now works correctly when
+    the &lt;kbd&gt;usemenuforusers&lt;/kbd&gt; parameter is turned on.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=734997&quot;&gt;[% terms.Bug %] 734997&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;URLs in the 'Total' row at the bottom of tabular reports were broken
+    when JavaScript was enabled and a user field was used for the vertical
+    axis.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=731323&quot;&gt;[% terms.Bug %] 731323&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;Some performance problems have been fixed for installations with many
+    products, components or versions.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/buglist.cgi?bug_id=695514,731055&quot;&gt;
+    [% terms.Bugs %] 695514 and 731055&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;A new hook named &lt;kbd&gt;buglist_column_joins&lt;/kbd&gt; has been added to let
+    extensions alter the &lt;kbd&gt;Bugzilla::Search::COLUMN_JOINS&lt;/kbd&gt; hash.
+    Now more fields can be displayed as columns in buglists, in combination
+    with the already existing &lt;kbd&gt;buglist_columns&lt;/kbd&gt; hook.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=743991&quot;&gt;[% terms.Bug %] 743991&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;A new hook named &lt;kbd&gt;error_catch&lt;/kbd&gt; has been added to let extensions
+    alter the way errors are thrown.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=745197&quot;&gt;[% terms.Bug %] 745197&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;A new hook named &lt;kbd&gt;admin_editusers_action&lt;/kbd&gt; has been added to let
+    extensions alter the behavior of &lt;kbd&gt;editusers.cgi&lt;/kbd&gt;. This lets you add
+    new features to this script very easily.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=730794&quot;&gt;[% terms.Bug %] 730794&lt;/a&gt;)&lt;/li&gt;
</ins><span class="cx"> &lt;/ul&gt;
</span><span class="cx"> 
</span><del>-&lt;h2&gt;&lt;a name=&quot;v32_security&quot;&gt;Security Fixes In This 3.2.x Release&lt;/a&gt;&lt;/h2&gt;
</del><ins>+&lt;h2 id=&quot;v42_req&quot;&gt;Minimum Requirements&lt;/h2&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;3.2.3&lt;/h3&gt;
-
-&lt;p&gt;This release fixes one security issue related to attachments. See the
-  &lt;a href=&quot;http://www.bugzilla.org/security/3.2.2/&quot;&gt;Security Advisory&lt;/a&gt;
-  for details.&lt;/p&gt;
-
-&lt;h3&gt;3.2.2&lt;/h3&gt;
-
-&lt;p&gt;This release fixes one security issue that is critical for installations
-  running 3.2.1 under mod_perl. See the 
-  &lt;a href=&quot;http://www.bugzilla.org/security/3.0.7/&quot;&gt;Security Advisory&lt;/a&gt; 
-  for details.&lt;/p&gt;
-
-&lt;h3&gt;3.2.1&lt;/h3&gt;
-
-&lt;p&gt;This release contains several security fixes. One fix may break any
-  automated scripts you have that are loading &lt;kbd&gt;process_bug.cgi&lt;/kbd&gt;
-  directly. We recommend that you read the entire 
-  &lt;a href=&quot;http://www.bugzilla.org/security/2.22.6/&quot;&gt;Security Advisory&lt;/a&gt;
-  for this release.&lt;/p&gt;
-
-&lt;h2&gt;&lt;a name=&quot;v32_req&quot;&gt;&lt;/a&gt;Minimum Requirements&lt;/h2&gt;
-
-&lt;p&gt;Any requirements that are new since 3.0.5 will look like
</del><ins>+&lt;p&gt;Any requirements that are new since 4.0.2 will look like
</ins><span class="cx">   &lt;span class=&quot;req_new&quot;&gt;this&lt;/span&gt;.&lt;/p&gt;
</span><span class="cx"> 
</span><span class="cx"> &lt;ul&gt;
</span><del>-  &lt;li&gt;&lt;a href=&quot;#v32_req_perl&quot;&gt;Perl&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v32_req_mysql&quot;&gt;For MySQL Users&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v32_req_pg&quot;&gt;For PostgreSQL Users&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v32_req_oracle&quot;&gt;For Oracle Users&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v32_req_modules&quot;&gt;Required Perl Modules&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v32_req_optional_mod&quot;&gt;Optional Perl
-    Modules&lt;/a&gt;&lt;/li&gt;
</del><ins>+  &lt;li&gt;&lt;a href=&quot;#v42_req_perl&quot;&gt;Perl&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v42_req_mysql&quot;&gt;For MySQL Users&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v42_req_pg&quot;&gt;For PostgreSQL Users&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v42_req_oracle&quot;&gt;For Oracle Users&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v42_req_sqlite&quot;&gt;For SQLite Users&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v42_req_modules&quot;&gt;Required Perl Modules&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v42_req_optional_mod&quot;&gt;Optional Perl Modules&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v42_req_apache&quot;&gt;Optional Apache Modules&lt;/a&gt;&lt;/li&gt;
</ins><span class="cx"> &lt;/ul&gt;
</span><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v32_req_perl&quot;&gt;&lt;/a&gt;Perl&lt;/h3&gt;
</del><ins>+&lt;h3 id=&quot;v42_req_perl&quot;&gt;Perl&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;Perl &lt;span class=&quot;req_new&quot;&gt;v&lt;strong&gt;5.8.1&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
</del><ins>+&lt;p&gt;Perl v5.8.1&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-[% INCLUDE db_req db='mysql' dbd_new = 1 %]
</del><ins>+[% INCLUDE db_req db='mysql' db_new =&gt; 1 dbd_new =&gt; 1 %]
</ins><span class="cx"> 
</span><del>-[% INCLUDE db_req db='pg' %]
</del><ins>+[% INCLUDE db_req db='pg' db_new =&gt; 1 %]
</ins><span class="cx"> 
</span><span class="cx"> [% INCLUDE db_req db='oracle' %]
</span><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v32_req_modules&quot;&gt;&lt;/a&gt;Required Perl Modules&lt;/h3&gt;
</del><ins>+[% INCLUDE db_req db='sqlite' %]
</ins><span class="cx"> 
</span><del>-[% INCLUDE req_table reqs = REQUIRED_MODULES 
-                     new = []
-                     updated = ['Template-Toolkit', 'Email-MIME',
-                                'Email-MIME-Modifier', 'CGI.pm'] %]
</del><ins>+&lt;h3 id=&quot;v42_req_modules&quot;&gt;Required Perl Modules&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v32_req_optional_mod&quot;&gt;&lt;/a&gt;Optional Perl Modules&lt;/h3&gt;
</del><ins>+[% INCLUDE req_table reqs = REQUIRED_MODULES
+                     new = ['Math-Random-ISAAC']
+                     updated = ['URI'] %]
</ins><span class="cx"> 
</span><ins>+&lt;h3 id=&quot;v42_req_optional_mod&quot;&gt;Optional Perl Modules&lt;/h3&gt;
+
</ins><span class="cx"> &lt;p&gt;The following perl modules, if installed, enable various
</span><span class="cx">   features of [% terms.Bugzilla %]:&lt;/p&gt;
</span><span class="cx"> 
</span><span class="cx"> [% INCLUDE req_table reqs = OPTIONAL_MODULES
</span><del>-                     new  = ['Authen-SASL', 'RadiusPerl']
-                     updated = []
</del><ins>+                     new  = ['Encode', 'Encode-Detect']
+                     updated = ['PatchReader', 'Apache-SizeLimit']
</ins><span class="cx">                      include_feature = 1 %]
</span><span class="cx"> 
</span><del>-&lt;h2&gt;&lt;a name=&quot;v32_feat&quot;&gt;&lt;/a&gt;New Features and Improvements&lt;/h2&gt;
</del><ins>+&lt;h3 id=&quot;v42_req_apache&quot;&gt;Optional Apache Modules&lt;/h3&gt;
</ins><span class="cx"> 
</span><ins>+&lt;p&gt;If you are using Apache as your webserver, [% terms.Bugzilla %] can
+  take advantage of some Apache features if you have the below Apache
+  modules installed and enabled. Currently,
+  &lt;a href=&quot;#v40_feat_js_css_update&quot;&gt;certain [% terms.Bugzilla %] features&lt;/a&gt;
+  are enabled only if you have all of the following modules installed
+  and enabled:&lt;/p&gt;
+
</ins><span class="cx"> &lt;ul&gt;
</span><del>-  &lt;li&gt;&lt;a href=&quot;#v32_feat_ui&quot;&gt;Major UI Improvements&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v32_feat_skin&quot;&gt;New Default Skin: Dusk&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v32_feat_status&quot;&gt;Custom Status Workflow&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v32_feat_fields&quot;&gt;New Custom Field Types&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v32_feat_install&quot;&gt;Easier Installation&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v32_feat_oracle&quot;&gt;Experimental Oracle Support&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v32_feat_utf8&quot;&gt;Improved UTF-8 Support&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v32_feat_grcons&quot;&gt;Group Icons&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v32_feat_other&quot;&gt;Other Enhancements and Changes&lt;/a&gt;&lt;/li&gt;
</del><ins>+  &lt;li&gt;mod_headers&lt;/li&gt;
+  &lt;li&gt;mod_expires&lt;/li&gt;
+  &lt;li&gt;mod_env&lt;/li&gt;
</ins><span class="cx"> &lt;/ul&gt;
</span><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v32_feat_ui&quot;&gt;&lt;/a&gt;Major UI Improvements&lt;/h3&gt;
</del><ins>+&lt;p&gt;On most systems (but not on Windows), &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; is able to
+  tell whether or not you have these modules installed, and it will tell
+  you.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;[% terms.Bugzilla %] 3.2 has had some UI assistance from the NASA
-  Human-Computer Interaction department and the new 
-  &lt;a href=&quot;http://wiki.mozilla.org/Bugzilla:UE&quot;&gt;[% terms.Bugzilla %]
-  User Interface Team&lt;/a&gt;.&lt;/p&gt;
</del><span class="cx"> 
</span><del>-&lt;p&gt;In particular, you will notice a massively redesigned [% terms.bug %]
-  editing form, in addition to our &lt;a href=&quot;#v32_feat_skin&quot;&gt;new skin&lt;/a&gt;.&lt;/p&gt;
</del><ins>+&lt;h2 id=&quot;v42_feat&quot;&gt;New Features and Improvements&lt;/h2&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v32_feat_skin&quot;&gt;&lt;/a&gt;New Default Skin: Dusk&lt;/h3&gt;
-
-&lt;p&gt;[% terms.Bugzilla %] 3.2 now ships with a skin called &quot;Dusk&quot; that is
-  a bit more colorful than old default &quot;Classic&quot; skin.&lt;/p&gt;
-
-&lt;p&gt;Upgrading installations will still default to the &quot;Classic&quot; 
-  skin--administrators can change the default in the Default Preferences
-  control panel. Users can also choose to use the old skin in their
-  Preferences (or using the View :: Page Style menu in Firefox).&lt;/p&gt;
-
-&lt;p&gt;The changes that [% terms.Bugzilla %] required for Dusk made
-  [%+ terms.Bugzilla %] much easier to skin. See the
-  &lt;a href=&quot;http://wiki.mozilla.org/Bugzilla:Addons#Skins&quot;&gt;Addons page&lt;/a&gt;
-  for additional skins, or try making your own!&lt;/p&gt;
-
-&lt;h3&gt;&lt;a name=&quot;v32_feat_status&quot;&gt;&lt;/a&gt;Custom Status Workflow&lt;/h3&gt;
-
-&lt;p&gt;You can now customize the list of statuses in [% terms.Bugzilla %],
-  and transitions between them.&lt;/p&gt;
-
-&lt;p&gt;You can also specify that a comment must be made on certain transitions.&lt;/p&gt;
-
-&lt;h3&gt;&lt;a name=&quot;v32_feat_fields&quot;&gt;&lt;/a&gt;New Custom Field Types&lt;/h3&gt;
-
-&lt;p&gt;[% terms.Bugzilla %] 3.2 has support for three new types of
-  custom fields:&lt;/p&gt;
-
</del><span class="cx"> &lt;ul&gt;
</span><del>-  &lt;li&gt;Large Text: Adds a multi-line textbox to your [% terms.bugs %].&lt;/li&gt;
-  &lt;li&gt;Multiple Selection Box: Adds a box that allows you to choose
-    multiple items from a list.&lt;/li&gt;
-  &lt;li&gt;Date/Time: Displays a date and time, along with a JavaScript
-    calendar popup to make picking a date easier.&lt;/li&gt;
</del><ins>+  &lt;li&gt;&lt;a href=&quot;#v42_feat_sqlite&quot;&gt;Experimental SQLite Support&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v42_feat_attach&quot;&gt;Creating an Attachment by Pasting Text Into
+    a Text Field&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v42_feat_email&quot;&gt;HTML [% terms.Bug %]mail&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v42_feat_search&quot;&gt;Improved Searching System&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v42_feat_product&quot;&gt;Disabling Old Components, Versions and Milestones&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v42_feat_custom&quot;&gt;Displaying a Custom Field Value Based on Multiple
+    Values of Another Field&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v42_feat_audit&quot;&gt;Auditing of All Changes Within [% terms.Bugzilla %]&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v42_feat_wai&quot;&gt;Accessibility Improvements&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v42_feat_other&quot;&gt;Other Enhancements and Changes&lt;/a&gt;&lt;/li&gt;
</ins><span class="cx"> &lt;/ul&gt;
</span><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v32_feat_install&quot;&gt;&lt;/a&gt;Easier Installation&lt;/h3&gt;
</del><ins>+&lt;h3 id=&quot;v42_feat_sqlite&quot;&gt;Experimental SQLite Support&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;[% terms.Bugzilla %] now comes with a script called 
-  &lt;kbd&gt;install-module.pl&lt;/kbd&gt; that can automatically download
-  and install all of the required Perl modules for [% terms.Bugzilla %].
-  It stores them in a directory inside your [% terms.Bugzilla %]
-  installation, so you can use it even if you don't have administrator-level
-  access to your machine, and without modifying your main Perl install.&lt;/p&gt;
</del><ins>+&lt;p&gt;SQLite is now supported by [% terms.Bugzilla %] and becomes the 4th supported
+  database besides MySQL, PostgreSQL and Oracle. SQLite support must be considered
+  as experimental, at least till the next major release.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;&lt;kbd&gt;checksetup.pl&lt;/kbd&gt; will print out instructions for using
-  &lt;kbd&gt;install-module.pl&lt;/kbd&gt;, or you can read its
-  &lt;a href=&quot;[% docs_urlbase FILTER html %]api/install-module.html&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
</del><ins>+&lt;p&gt;Note that use of SQLite is only recommended for small installations. Larger
+  installations should use MySQL, PostgreSQL, or Oracle.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v32_feat_oracle&quot;&gt;&lt;/a&gt;Experimental Oracle Support&lt;/h3&gt;
</del><ins>+&lt;h3 id=&quot;v42_feat_attach&quot;&gt;Creating an Attachment by Pasting Text Into a Text Field&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;[% terms.Bugzilla %] 3.2 contains experimental support for using 
-  Oracle as its database. Some features of [% terms.Bugzilla %] are known 
-  to be broken on Oracle, but hopefully will be working by our next major
-  release.&lt;/p&gt;
</del><ins>+&lt;p&gt;You can now create a new attachment simply by pasting some text into a text
+  field, in addition to the normal upload process for attachments.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;The [% terms.Bugzilla %] Project, as an open-source project, of course
-  does not recommend the use of proprietary database solutions. However,
-  if your organization requires that you use Oracle, this will allow
-  you to use [% terms.Bugzilla %]!&lt;/p&gt;
</del><ins>+&lt;h3 id=&quot;v42_feat_email&quot;&gt;HTML [% terms.Bug %]mail&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;The [% terms.Bugzilla %] Project thanks Oracle Corp. for their extensive
-  development contributions to [% terms.Bugzilla %] which allowed this to 
-  happen!&lt;/p&gt;
</del><ins>+&lt;p&gt;By default, [% terms.bug %]mails (email notifications about changes to
+  [%+ terms.bugs %]) are now sent in an HTML format that is more readable than
+  the old text format. Those who prefer the old text format can still choose it
+  in their Preferences, however.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v32_feat_utf8&quot;&gt;&lt;/a&gt;Improved UTF-8 Support&lt;/h3&gt;
</del><ins>+&lt;h3 id=&quot;v42_feat_search&quot;&gt;Improved Searching System&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;[% terms.Bugzilla %] 3.2 now has advanced UTF-8 support in its code,
-  including correct handling for truncating and wrapping multi-byte
-  languages. Major issues with multi-byte or unusual languages
-  are now resolved, and [% terms.Bugzilla %] should now be usable
-  by users in every country with little (or at least much less)
-  customization.&lt;/p&gt;
</del><ins>+&lt;p&gt;The Custom Search section in the Advanced Search page has been redesigned
+  to work in a more sensible way. Complex queries are easier to build and have
+  more sensible results, as they are built using a more intuitive logic.
+  Some very complicated queries are still impossible to generate, though.
+  Things should improve in future releases.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v32_feat_grcons&quot;&gt;&lt;/a&gt;Group Icons&lt;/a&gt;&lt;/h3&gt;
</del><ins>+&lt;h3 id=&quot;v42_feat_product&quot;&gt;Disabling Old Components, Versions and Milestones&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;Administrators can now specify that users who are in certain groups
-  should have an icon appear next to their name whenever they comment.
-  This is particularly useful for distinguishing developers from 
-  [%+ terms.bug %] reporters.&lt;/p&gt;
</del><ins>+&lt;p&gt;Older components, versions and milestones can now be disabled. [% terms.Bugs %]
+  already using them are not affected, but these values will no longer be
+  available for new [% terms.bugs %].&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v32_feat_other&quot;&gt;&lt;/a&gt;Other Enhancements and Changes&lt;/h3&gt;
</del><ins>+&lt;h3 id=&quot;v42_feat_custom&quot;&gt;Displaying a Custom Field Value Based on Multiple Values
+  of Another Field&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;These are either minor enhancements, or enhancements that have
-  very short descriptions. Some of these are very useful, though!&lt;/p&gt;
</del><ins>+&lt;p&gt;A custom field can now be displayed based on multiple values of another field.
+  (For example, one custom field could now appear in multiple products.)
+  Previously, you could only display a custom field based on a single value of
+  another field.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;h4&gt;Enhancements For Users&lt;/h4&gt;
</del><ins>+&lt;h3 id=&quot;v42_feat_audit&quot;&gt;Auditing of All Changes Within [% terms.Bugzilla %]&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;ul&gt;
-  &lt;li&gt;&lt;strong&gt;[% terms.Bugs %]&lt;/strong&gt;: You can now reassign
-    [%+ terms.abug %] at the same time as you are changing its status.&lt;/li&gt;
-  &lt;li&gt;&lt;strong&gt;[% terms.Bugs %]&lt;/strong&gt;: When entering [% terms.abug %], 
-    you will now see the description of a component when you select it.&lt;/li&gt;
-  &lt;li&gt;&lt;strong&gt;[% terms.Bugs %]&lt;/strong&gt;: The [% terms.bug %] view now 
-    contains some &lt;a href=&quot;http://microformats.org/about/&quot;&gt;Microformats&lt;/a&gt;,
-    most notably for users' names and email addresses.&lt;/li&gt;
-  &lt;li&gt;&lt;strong&gt;[% terms.Bugs %]&lt;/strong&gt;: You can now remove a QA Contact
-    from [% terms.abug %] simply by clearing the QA Contact field.&lt;/li&gt;
-  &lt;li&gt;&lt;strong&gt;[% terms.Bugs %]&lt;/strong&gt;: There is now a user preference 
-    that will allow you to exclude the quoted text when replying 
-    to comments.&lt;/li&gt;
-  &lt;li&gt;&lt;strong&gt;[% terms.Bugs %]&lt;/strong&gt;: You can now expand or collapse
-    individual comments in the [% terms.bug %] view.&lt;/li&gt;
</del><ins>+&lt;p&gt;Most changes made through the admin interface are now logged to the database,
+  in the &lt;kbd&gt;audit_log&lt;/kbd&gt; table. There is no UI to access this table yet,
+  but developers are free to create their own tools to track changes made into
+  their installation. This is only a first step, and improvements are expected
+  in future releases.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-  &lt;li&gt;&lt;strong&gt;Attachments&lt;/strong&gt;: There is now &quot;mid-air collision&quot; 
-      protection when editing attachments.&lt;/li&gt;
-  &lt;li&gt;&lt;strong&gt;Attachments&lt;/strong&gt;: Patches in the Diff Viewer now show 
-    line numbers (&lt;a href=&quot;https://bugzilla.mozilla.org/attachment.cgi?id=327546&quot;&gt;Example&lt;/a&gt;).&lt;/li&gt;
-  &lt;li&gt;&lt;strong&gt;Attachments&lt;/strong&gt;: After creating or updating an attachment,
-    you will be immediately shown the [% terms.bug %] that the attachment
-    is on.&lt;/li&gt;
</del><ins>+&lt;h3 id=&quot;v42_feat_wai&quot;&gt;Accessibility Improvements&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-  &lt;li&gt;&lt;strong&gt;Search&lt;/strong&gt;: You can now reverse the sort of 
-    [%+ terms.abug %] list by clicking on a column header again.&lt;/li&gt;
-  &lt;li&gt;&lt;strong&gt;Search&lt;/strong&gt;: Atom feeds of [% terms.bug %] lists now
-    contain more fields.&lt;/li&gt;
-  &lt;li&gt;&lt;strong&gt;Search&lt;/strong&gt;: QuickSearch now supports searching flags
-    and groups. It also now includes the OS field in the list of fields
-    it searches by default.&lt;/li&gt;
-  &lt;li&gt;&lt;strong&gt;Search&lt;/strong&gt;: &quot;Help&quot; text can now appear on query.cgi 
-    for Internet Explorer and other non-Firefox browsers. (It always
-    could appear for Firefox.)&lt;/li&gt;
</del><ins>+&lt;p&gt;A project has started thanks to Francisco Donalisio from IBM to make
+  [%+ terms.Bugzilla %] compliant with the W3C Web Accessibility Initiative
+  standards. A lot more work still needs to be done, but we expect a much
+  better compatibility for the next major release.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-  &lt;li&gt;[% terms.Bugzilla %] now ships with an icon that will show
-    up next to the URL in most browsers. If you want to replace it,
-    it's in &lt;kbd&gt;images/favicon.ico&lt;/kbd&gt;.&lt;/li&gt;
</del><ins>+&lt;h3 id=&quot;v42_feat_other&quot;&gt;Other Enhancements and Changes&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-  &lt;li&gt;You can now set the Deadline when using &quot;Change Several 
-    [%+ terms.Bugs %] At Once&quot;&lt;/li&gt;
-  &lt;li&gt;&lt;strong&gt;Saved Searches&lt;/strong&gt; now save their column list, so if 
-    you customize the list of columns and save your search, it will 
-    always contain those columns.&lt;/li&gt;
-  &lt;li&gt;&lt;strong&gt;Saved Searches&lt;/strong&gt;: When you share a search, you can
-    now see how many users have subscribed to it, on 
-    &lt;kbd&gt;userprefs.cgi&lt;/kbd&gt;.&lt;/li&gt;
-  &lt;li&gt;&lt;strong&gt;Saved Searches&lt;/strong&gt;: You can now see what group a 
-    shared search was shared to, on the list of available shared searches
-    in &lt;kbd&gt;userprefs.cgi&lt;/kbd&gt;.&lt;/li&gt;
-  &lt;li&gt;&lt;strong&gt;Flags&lt;/strong&gt;: If your installation uses drop-down user 
-    lists, the flag requestee box will now contain only users who are 
-    actually allowed to take requests.&lt;/li&gt;
-  &lt;li&gt;&lt;strong&gt;Flags&lt;/strong&gt;: If somebody makes a request to you, and you
-    change the requestee to somebody else, the requester is no longer set
-    to you. In other words, you can &quot;redirect&quot; requests and maintain the
-    original requester.&lt;/li&gt;
-  &lt;li&gt;&lt;strong&gt;Flags&lt;/strong&gt;: Emails about flags now will thread properly
-    in email clients to be a part of [% terms.abug %]'s thread.&lt;/li&gt;
-  &lt;li&gt;When using &lt;kbd&gt;email_in.pl&lt;/kbd&gt;, you can now add users to the CC
-    list by just using &lt;kbd&gt;@cc&lt;/kbd&gt; as the field name.&lt;/li&gt;
-  &lt;li&gt;Many pages (particularly administrative pages) now contain links to
-    the relevant section of the [% terms.Bugzilla %] Guide, so you can read 
-    the documentation for that page.&lt;/li&gt;
-  &lt;li&gt;Dependency Graphs should render more quickly, as they now (by default)
-    only include the same [% terms.bugs %] that you'd see in the dependency
-    tree.&lt;/li&gt;
-&lt;/ul&gt;
</del><ins>+&lt;h4&gt;Enhancements for Users&lt;/h4&gt;
</ins><span class="cx"> 
</span><del>-&lt;h4&gt;Enhancements For Administrators&lt;/h4&gt;
-
</del><span class="cx"> &lt;ul&gt;
</span><del>-  &lt;li&gt;&lt;strong&gt;Admin UI&lt;/strong&gt;: Instead of having the Administration 
-    Control Panel links in the footer, there is now just one link called 
-   &quot;Administration&quot; that takes you to a page that links to all the
-    administrative controls for [% terms.Bugzilla %].&lt;/li&gt;
-  &lt;li&gt;&lt;strong&gt;Admin UI&lt;/strong&gt;: Administrative pages no longer display
-    confirmation pages, instead they redirect you to some useful page 
-    and display a message about what changed.&lt;/li&gt;
-  &lt;li&gt;&lt;strong&gt;Admin UI&lt;/strong&gt;: The interface for editing group 
-     inheritance in &lt;kbd&gt;editgroups.cgi&lt;/kbd&gt; is much clearer now.&lt;/li&gt;
-  &lt;li&gt;&lt;strong&gt;Admin UI&lt;/strong&gt;: When editing a user, you can now see 
-    all the components where that user is the Default Assignee or Default
-    QA Contact.&lt;/li&gt;
</del><ins>+  &lt;li&gt;&lt;strong&gt;[% terms.Bugs %]:&lt;/strong&gt; Users without editbugs privileges can
+    no longer remove other users from the CC list of [% terms.bugs %].&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;[% terms.Bugs %]:&lt;/strong&gt; Local [% terms.bug %] IDs are now valid
+    in the See Also field. Adding such an ID will also add a reciprocal link in
+    the other [% terms.bug %].&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;[% terms.Bugs %]:&lt;/strong&gt; After editing [% terms.abug %] or an
+    attachment, the URL is automatically changed to &lt;kbd&gt;show_bug.cgi&lt;/kbd&gt;
+    instead of &lt;kbd&gt;post_bug.cgi&lt;/kbd&gt;, &lt;kbd&gt;process_bug.cgi&lt;/kbd&gt; or
+    &lt;kbd&gt;attachment.cgi&lt;/kbd&gt; so that reloading the page (for instance when
+    restarting the web browser) displays the right page. This feature is supported
+    by Firefox, Chrome and Safari, but not by Internet Explorer 9.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;[% terms.Bugs %]:&lt;/strong&gt; Inactive accounts are no longer
+    displayed in user fields when user-autocompletion is enabled.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;[% terms.Bugs %]:&lt;/strong&gt; User-autocompletion is now much faster
+    on installations with many user accounts.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;[% terms.Bugs %]:&lt;/strong&gt; The See Also field now accepts URLs
+    pointing to MantisBT, Trac, JIRA and the sourceforge.net b[%%]ug trackers.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;[% terms.Bugs %]:&lt;/strong&gt; Displaying [% terms.abug %] with many
+    dependencies is now much faster.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Attachments:&lt;/strong&gt; The encoding of text files can be automatically
+    detected when uploading them as attachments.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Attachments:&lt;/strong&gt; Clickjacking could possibly occur in an attachment 
+    Details page if a user attached a specially formatted HTML file. To fix this 
+    potential problem, the Details page always displays the HTML source instead and 
+    users can see rendered page by clicking on View.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Flags:&lt;/strong&gt; Changing the requestee of a flag no longer changes
+    the requester.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Reports:&lt;/strong&gt; If JavaScript is enabled in your web browser,
+    tabular reports are now sortable based on any displayed column.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Dependency graphs:&lt;/strong&gt; The &lt;em&gt;Show every [% terms.bug %] in
+    the system with dependencies&lt;/em&gt; option has been removed.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Searches:&lt;/strong&gt; The columns displayed by default in
+    [%+ terms.bug %]lists have changed. These columns are now displayed by default
+    unless otherwise specified:&lt;br&gt;
+    &lt;kbd&gt;product | component | assignee | [% terms.bug %] status | resolution |
+    [%+ terms.bug %] summary | last change date&lt;/kbd&gt;&lt;br&gt;
+    This means that the priority, severity and operating system columns are no
+    longer displayed by default.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Searches:&lt;/strong&gt; [% terms.Bug %]lists will now only display the
+    first 500 [% terms.bugs %] by default. It is still possible to display the
+    whole list, though.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Searches:&lt;/strong&gt; When using relative dates and times, &lt;kbd&gt;-1w&lt;/kbd&gt;
+    is now a synonym for &lt;kbd&gt;-7d&lt;/kbd&gt; and means exactly 7 days. Previously,
+    &lt;kbd&gt;-1w&lt;/kbd&gt; meant the beginning of the week, which was confusing some users.
+    The same confusion existed for &lt;kbd&gt;-1d&lt;/kbd&gt; which was different from
+    &lt;kbd&gt;-24h&lt;/kbd&gt;, and for &lt;kbd&gt;-1m&lt;/kbd&gt; which was different from &lt;kbd&gt;-30d&lt;/kbd&gt;.
+    Now if you really want the beginning of the day, week or month, you must use
+    &lt;kbd&gt;-1ds&lt;/kbd&gt;, &lt;kbd&gt;-1ws&lt;/kbd&gt;, and &lt;kbd&gt;-1ms&lt;/kbd&gt; respectively, where
+    &quot;s&quot; means &quot;start of&quot;. This change will affect existing saved searches using
+    relative dates.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Searches:&lt;/strong&gt; A new &lt;em&gt;Include fulltext when performing quick
+    searches&lt;/em&gt; user preference has been added which permits users to include
+    or exclude comments when using quicksearches.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Searches:&lt;/strong&gt; It is now possible to query for [% terms.bugs %]
+    based on personal tags in the Custom Search section in the Advanced Search
+    page.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Email notifications: &lt;/strong&gt; The date and time of comments are no
+    longer displayed in the comment header in [% terms.bug%]mails. This information
+    is already available in the email header itself.&lt;/li&gt;
+&lt;/ul&gt;
</ins><span class="cx"> 
</span><del>-  &lt;li&gt;&lt;strong&gt;Email&lt;/strong&gt;: For installations that use SMTP to send 
-    mail (as opposed to Sendmail), [%+ terms.Bugzilla %] now supports
-    SMTP Authentication, so that it can log in to your mail server 
-    before sending messages.&lt;/li&gt;
-  &lt;li&gt;&lt;strong&gt;Email&lt;/strong&gt;: Using the &quot;Test&quot; mail delivery method now
-     creates a valid mbox file to make testing easier.&lt;/li&gt;
</del><ins>+&lt;h4&gt;Enhancements for Administrators and Developers&lt;/h4&gt;
</ins><span class="cx"> 
</span><del>-  &lt;li&gt;&lt;strong&gt;Authentication&lt;/strong&gt;: [% terms.Bugzilla %] now correctly 
-    handles LDAP records which contain multiple email addresses. (The first
-    email address in the list that is a valid [% terms.Bugzilla %] account 
-    will be used, or if this is a new user, the first email address in 
-    the list will be used.)&lt;/li&gt;
-  &lt;li&gt;&lt;strong&gt;Authentication&lt;/strong&gt;: [% terms.Bugzilla %] can now take 
-    a list of LDAP servers to try in order until it gets a successful
-    connection.&lt;/li&gt;
-  &lt;li&gt;&lt;strong&gt;Authentication&lt;/strong&gt;: [% terms.Bugzilla %] now supports 
-    RADIUS authentication.&lt;/li&gt;
-
-  &lt;li&gt;&lt;strong&gt;Security&lt;/strong&gt;: The login cookie is now created as 
-    &quot;HTTPOnly&quot; so that it can't be read by possibly malicious scripts. 
-    Also, if SSL is enabled on your installation, the login cookie is
-    now only sent over SSL connections.&lt;/li&gt;
-  &lt;li&gt;&lt;strong&gt;Security&lt;/strong&gt;: The &lt;code&gt;ssl&lt;/code&gt; parameter now protects
-    every page a logged-in user accesses, when set to &quot;authenticated sessions.&quot;
-    Also, SSL is now enforced appropriately in the WebServices interface when
-    the parameter is set.&lt;/li&gt;
-
-  &lt;li&gt;&lt;strong&gt;Database&lt;/strong&gt;: [% terms.Bugzilla %] now uses transactions in 
-    the database instead of table locks. This should generally improve
-    performance with many concurrent users. It also means if there is
-    an unexpected error in the middle of a page, all database changes made
-    during that page will be rolled back.&lt;/li&gt;
-  &lt;li&gt;&lt;strong&gt;Database&lt;/strong&gt;: You no longer have to set 
-    &lt;code&gt;max_packet_size&lt;/code&gt; in MySQL to add large attachments. However,
-    you may need to set it manually if you restore a mysqldump into your
-    database.&lt;/li&gt;
-
-  &lt;li&gt;New WebService functions:
-    &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/WebService/Bug.html&quot;&gt;B&lt;!-- --&gt;ug.add_comment&lt;/a&gt;
-    and &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/WebService/Bugzilla.html&quot;&gt;Bugzilla.extensions&lt;/a&gt;.&lt;/li&gt;
-
-  &lt;li&gt;You can now delete custom fields, but only if they have never been
-    set on any [% terms.bug %].&lt;/li&gt;
-  &lt;li&gt;There is now a &lt;kbd&gt;--reset-password&lt;/kbd&gt; argument to 
-    &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; that allows you to reset a user's password
-    from the command line.&lt;/li&gt;
-  &lt;li&gt;There is now a script called &lt;kbd&gt;sanitycheck.pl&lt;/kbd&gt; that you can
-    run from the command line. It works just like &lt;kbd&gt;sanitycheck.cgi&lt;/kbd&gt;.
-    By default, it only outputs anything if there's an error, so it's
-    ideal for administrators who want to run it nightly in a cron job.&lt;/li&gt;
-  &lt;li&gt;The &lt;kbd&gt;strict_isolation&lt;/kbd&gt; parameter now prevents you from setting
-    users who cannot see [% terms.abug %] as a CC, Assignee, or QA
-    Contact. Previously it only prevented you from adding users who
-    could not &lt;em&gt;edit&lt;/em&gt; the [% terms.bug %].&lt;/li&gt;
-  &lt;li&gt;Extensions can now add their own headers to the HTML &amp;lt;head&amp;gt;
-    for things like custom CSS and so on.&lt;/li&gt;
-  &lt;li&gt;&lt;kbd&gt;sanitycheck.cgi&lt;/kbd&gt; has been templatized, meaning that the
-    entire [% terms.Bugzilla %] UI is now contained in templates.&lt;/li&gt;
-  &lt;li&gt;When setting the &lt;kbd&gt;sslbase&lt;/kbd&gt; parameter, you can now specify
-    a port number in the URL.&lt;/li&gt;
-  &lt;li&gt;When importing [% terms.bugs %] using &lt;kbd&gt;importxml.pl&lt;/kbd&gt;,
-    attachments will have their actual creator set as their creator,
-    instead of the person who exported the [% terms.bug %] from the other
-    system.&lt;/li&gt;
-  &lt;li&gt;The voting system is off by default in new installs. This is to
-    prepare for the fact that it will be moved into an extension at
-    some point in the future.&lt;/li&gt;
-  &lt;li&gt;The &lt;code&gt;shutdownhtml&lt;/code&gt; parameter now works even when 
-    [% terms.Bugzilla %]'s database server is down.&lt;/li&gt;
</del><ins>+&lt;ul&gt;
+  &lt;li&gt;&lt;strong&gt;Installation:&lt;/strong&gt; &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; is now much quieter
+    when creating a new database.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Security:&lt;/strong&gt; [% terms.Bugzilla %] 4.0 is using
+    &lt;kbd&gt;Math::Random::Secure&lt;/kbd&gt; to generate cryptographically secure
+    pseudorandom numbers, but it appeared that installing this Perl module from
+    CPAN caused a lot of trouble for some people due to its numerous dependencies.
+    So the RNG code has been rewritten to only depend on &lt;kbd&gt;Math::Random::ISAAC&lt;/kbd&gt;,
+    which was already in use in previous versions of [% terms.Bugzilla %].&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Security:&lt;/strong&gt; &lt;kbd&gt;X-Frame-Options = SAMEORIGIN&lt;/kbd&gt; is now
+    passed to all page headers (except when viewing attachments, as they can be
+    on a different host) to protect users from framing and subsequent possible
+    clickjacking problems.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Configuration:&lt;/strong&gt; A new parameter &lt;em&gt;password_complexity&lt;/em&gt;
+    has been added (default: no_constraints) which allows admins to force users
+    to use passwords with a higher complexity, such as a combination of uppercase
+    and lowercase letters, numbers and special characters, or a subset of them.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Configuration:&lt;/strong&gt; A new parameter &lt;em&gt;search_allow_no_criteria&lt;/em&gt;
+    has been added (default: on) which allows admins to forbid queries with no
+    criteria. This is particularly useful for large installations with several
+    tens of thousands [% terms.bugs %] where returning all [% terms.bugs %]
+    doesn't make sense and would have a performance impact on the database.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Configuration:&lt;/strong&gt; A new parameter &lt;em&gt;default_search_limit&lt;/em&gt;
+    has been added (default: 500) which limits the number of [% terms.bugs %]
+    displayed by default in a [% terms.bug%]list. The user can ask to see a larger
+    list, though.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Configuration:&lt;/strong&gt; A new parameter &lt;em&gt;max_search_results&lt;/em&gt;
+    has been added (default: 10000) which limits the number of [% terms.bugs %]
+    a user can request at once in a [% terms.bug%]list. This is a hard limit and
+    a user cannot bypass this value.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Configuration:&lt;/strong&gt; A new parameter &lt;em&gt;ajax_user_autocompletion&lt;/em&gt;
+    has been added (default: on) to allow administrators to disable auto-completion
+    when typing characters in user fields. This parameter should only be disabled
+    if your installation is unable to support the load generated by this feature.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Configuration:&lt;/strong&gt; The &lt;em&gt;config_modify_panels&lt;/em&gt; hook now
+    lets you add additional parameters to existing parameters panels.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Flags:&lt;/strong&gt; Users with local editcomponents privileges can now
+    edit flag types for products they can administer.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Quips:&lt;/strong&gt; A new system group &lt;em&gt;bz_quip_moderators&lt;/em&gt; has
+    been created to moderate quips. Till now, you had to be in the &lt;em&gt;admin&lt;/em&gt;
+    group to do that.&lt;/li&gt;
+  &lt;li&gt;&lt;kbd&gt;importxml.pl&lt;/kbd&gt; now inserts each comment separately into the imported
+    [%+ terms.bug %] instead of concatenating them all into a single comment.&lt;/li&gt;
+  &lt;li&gt;&lt;kbd&gt;email_in.pl&lt;/kbd&gt; now ignores auto-submitted incoming emails (for
+    instance, all these &quot;out of office&quot; emails).&lt;/li&gt;
+  &lt;li&gt;New code hooks: email_in_before_parse, email_in_after_parse,
+    install_filesystem, install_update_db_fielddefs, job_map, object_end_of_create,
+    quicksearch_map, user_preferences.&lt;/li&gt;
</ins><span class="cx"> &lt;/ul&gt;
</span><span class="cx"> 
</span><del>-&lt;h3&gt;Enhancements for Localizers (or Localized Installations)&lt;/h3&gt;
</del><ins>+&lt;h4&gt;WebService Changes&lt;/h4&gt;
</ins><span class="cx"> 
</span><span class="cx"> &lt;ul&gt;
</span><del>-  &lt;li&gt;The documentation can now be localized--in other words, you can have
-    documentation installed for multiple languages at once and
-    [%+ terms.Bugzilla %] will link to the correct language in its internal
-    documentation links.&lt;/li&gt;
-  &lt;li&gt;[% terms.Bugzilla %] no longer uses the &lt;kbd&gt;languages&lt;/kbd&gt; parameter.
-    Instead it reads the &lt;kbd&gt;template/&lt;/kbd&gt; directory to see which
-    languages are available.&lt;/li&gt;
-  &lt;li&gt;Some of the messages printed by &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; can now
-    be localized. See &lt;kbd&gt;template/en/default/setup/strings.txt.pl&lt;/kbd&gt;.
</del><ins>+  &lt;li&gt;Two new methods have been added: &lt;kbd&gt;Product.create&lt;/kbd&gt; and
+    &lt;kbd&gt;Group.create&lt;/kbd&gt;.&lt;/li&gt;
+  &lt;li&gt;&lt;kbd&gt;B[%%]ug.update&lt;/kbd&gt; no longer throws an error when passing an empty
+    string to &lt;kbd&gt;see_also&lt;/kbd&gt;. It now simply ignores this empty value.&lt;/li&gt;
+  &lt;li&gt;&lt;kbd&gt;Product.get&lt;/kbd&gt; now also returns data about the classification it
+    belongs to as well as its components, milestones and versions. It also
+    returns the &lt;kbd&gt;default_milestone&lt;/kbd&gt; and &lt;kbd&gt;has_unconfirmed&lt;/kbd&gt;
+    attributes.&lt;/li&gt;
+  &lt;li&gt;In &lt;kbd&gt;B[%%]ug.fields&lt;/kbd&gt;, the &lt;kbd&gt;sortkey&lt;/kbd&gt; attribute used in
+    &lt;kbd&gt;values&lt;/kbd&gt; has been renamed to &lt;kbd&gt;sort_key&lt;/kbd&gt;.&lt;/li&gt;
+  &lt;li&gt;In &lt;kbd&gt;B[%%]ug.attachments&lt;/kbd&gt; and &lt;kbd&gt;B[%%]ug.add_attachment&lt;/kbd&gt;,
+    the &lt;kbd&gt;is_url&lt;/kbd&gt; attribute no longer exists.&lt;/li&gt;
</ins><span class="cx"> &lt;/ul&gt;
</span><span class="cx"> 
</span><del>-&lt;h2&gt;&lt;a name=&quot;v32_issues&quot;&gt;&lt;/a&gt;Outstanding Issues&lt;/h2&gt;
</del><span class="cx"> 
</span><ins>+&lt;h2 id=&quot;v42_issues&quot;&gt;Outstanding Issues&lt;/h2&gt;
+
</ins><span class="cx"> &lt;ul&gt;
</span><del>-  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=423439&quot;&gt;
-    [%- terms.Bug %] 423439&lt;/a&gt;: Tabs in comments will be converted
-    to four spaces, due to a b&lt;!-- --&gt;ug in Perl as of Perl 5.8.8.&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=69621&quot;&gt;
-    [%- terms.Bug %] 69621&lt;/a&gt;: If you rename or remove a keyword that is
-    in use on [% terms.bugs %], you will need to rebuild the &quot;keyword cache&quot;
-    by running &lt;a href=&quot;sanitycheck.cgi&quot;&gt;sanitycheck.cgi&lt;/a&gt; and choosing 
-    the option to rebuild the cache when it asks. Otherwise keywords may 
-    not show up properly in search results.&lt;/li&gt;
</del><span class="cx">   &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=89822&quot;&gt;
</span><del>-    [%- terms.Bug %] 89822&lt;/a&gt;: When changing multiple [% terms.bugs %] at 
</del><ins>+    [%- terms.Bug %] 89822&lt;/a&gt;: When changing multiple [% terms.bugs %] at
</ins><span class="cx">     the same time, there is no &quot;mid-air collision&quot; protection.&lt;/li&gt;
</span><span class="cx">   &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=276230&quot;&gt;
</span><del>-    [%- terms.Bug %] 276230&lt;/a&gt;: The support for restricting access to 
-    particular Categories of New Charts is not complete. You should treat 
-    the 'chartgroup' Param as the only access mechanism available.&lt;br&gt;
-    However, charts migrated from Old Charts will be restricted to 
-    the groups that are marked MANDATORY for the corresponding Product.
-    There is currently no way to change this restriction, and the 
-    groupings will not be updated if the group configuration
-    for the Product changes.&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=370370&quot;&gt;
-    [%- terms.Bug %] 370370&lt;/a&gt;: mod_perl support is currently not
-    working on Windows machines.&lt;/li&gt;
</del><ins>+    [%- terms.Bug %] 276230&lt;/a&gt;: The support for restricting access to
+    particular Categories of New Charts is not complete. You should treat the
+    &lt;em&gt;chartgroup&lt;/em&gt; parameter as the only access mechanism available.&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=584742&quot;&gt;
+    [%- terms.Bug %] 584742&lt;/a&gt;: When viewing [% terms.abug %], WebKit-based
+    browsers can automatically reset a field's selected value when the field
+    has disabled values.&lt;/li&gt;
</ins><span class="cx"> &lt;/ul&gt;
</span><span class="cx"> 
</span><del>-&lt;h2&gt;&lt;a name=&quot;v32_upgrading&quot;&gt;&lt;/a&gt;How to Upgrade From An Older Version&lt;/h2&gt;
</del><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v32_upgrading_notes&quot;&gt;&lt;/a&gt;Notes For Upgraders&lt;/h3&gt;
</del><ins>+&lt;h2 id=&quot;v42_code_changes&quot;&gt;Code Changes Which May Affect Customizations and Extensions&lt;/h2&gt;
</ins><span class="cx"> 
</span><span class="cx"> &lt;ul&gt;
</span><del>-  &lt;li&gt;If you upgrade by CVS, the &lt;kbd&gt;extensions&lt;/kbd&gt; and 
-    &lt;kbd&gt;skins/contrib&lt;/kbd&gt; directories are now in CVS instead of
-    being created by &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; If you do a &lt;kbd&gt;cvs update&lt;/kbd&gt;
-    from 3.0, you will be told that your directories are &quot;in the way&quot; and
-    you should delete (or move) them and then do &lt;kbd&gt;cvs update&lt;/kbd&gt;
-    again. Also, the &lt;kbd&gt;docs&lt;/kbd&gt; directory has been restructured
-    and after you &lt;kbd&gt;cvs update&lt;/kbd&gt; you can delete the &lt;kbd&gt;docs/html&lt;/kbd&gt;,
-    &lt;kbd&gt;docs/pdf&lt;/kbd&gt;, &lt;kbd&gt;docs/txt&lt;/kbd&gt;, and &lt;kbd&gt;docs/xml&lt;/kbd&gt;
-    directories.&lt;/li&gt;
-  &lt;li&gt;If you are using MySQL, you should know that [% terms.Bugzilla %]
-    now uses InnoDB for all tables. &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; will convert
-    your tables automatically, but if you have InnoDB disabled,
-    the upgrade will not be able to complete (and &lt;kbd&gt;checksetup.pl&lt;/kbd&gt;
-    will tell you so).&lt;/li&gt;
-
-  &lt;li&gt;&lt;strong&gt;You should also read the 
-    &lt;a href=&quot;#v30_upgrading_notes&quot;&gt;[% terms.Bugzilla %] 3.0 Notes For Upgraders
-    section&lt;/a&gt; of the 
-    &lt;a href=&quot;#v32_previous&quot;&gt;previous release notes&lt;/a&gt; if you are upgrading
-    from a version before 3.0.&lt;/strong&gt;&lt;/li&gt;
</del><ins>+  &lt;li&gt;The &lt;kbd&gt;email/newchangedmail.txt.tmpl&lt;/kbd&gt; template is now fully templatized,
+    meaning that the diff table displaying changes in [% terms.bug %] fields is
+    now generated in the template itself. This means [% terms.bug %]mails are now
+    fully localizable.&lt;/li&gt;
+  &lt;li&gt;The bugmail_recipients hook has been modified to pass &lt;kbd&gt;diffs&lt;/kbd&gt; with
+    changes made to the [% terms.bug %] as well as &lt;kbd&gt;users&lt;/kbd&gt; including
+    recipients of the email notification.&lt;/li&gt;
+  &lt;li&gt;YUI has been upgraded to 2.9.0.&lt;/li&gt;
+  &lt;li&gt;Due to the major code refactor of &lt;kbd&gt;B[%%]ugzilla/Search.pm&lt;/kbd&gt;, any
+    customization made against this file will probably need to be rewritten.&lt;/li&gt;
+  &lt;li&gt;The [% terms.Bugzilla %]-specific &lt;kbd&gt;url_quote&lt;/kbd&gt; filter used in templates
+    has been removed and replaced by the &lt;kbd&gt;uri&lt;/kbd&gt; filter from Template::Toolkit
+    as they are now similar.&lt;/li&gt;
+  &lt;li&gt;&lt;kbd&gt;long_list.cgi&lt;/kbd&gt;, &lt;kbd&gt;showattachment.cgi&lt;/kbd&gt; and &lt;kbd&gt;xml.cgi&lt;/kbd&gt;
+    have been removed from the codebase. As &lt;a href=&quot;#v40_code_changes&quot;&gt;announced&lt;/a&gt;
+    in the release notes of [% terms.Bugzilla %] 4.0, these scripts were deprecated
+    since [% terms.Bugzilla %] 2.19.&lt;/li&gt;
+  &lt;li&gt;&lt;kbd&gt;sidebar.cgi&lt;/kbd&gt; has been removed, because Gecko-based browsers no
+    longer support remote XUL, and its popularity is very low.&lt;/li&gt;
+  &lt;li&gt;&lt;kbd&gt;contrib/yp_nomail.sh&lt;/kbd&gt; has been removed. This script is no longer
+    useful since [% terms.Bugzilla %] 3.0.&lt;/li&gt;
+  &lt;li&gt;&lt;kbd&gt;contrib/bugzilla_ldapsync.rb&lt;/kbd&gt; has been removed. This script didn't
+    work for a long time.&lt;/li&gt;
</ins><span class="cx"> &lt;/ul&gt;
</span><span class="cx"> 
</span><del>-&lt;h3&gt;Steps For Upgrading&lt;/h3&gt;
</del><span class="cx"> 
</span><del>-&lt;p&gt;Once you have read the notes above, see the
-  &lt;a href=&quot;[% docs_urlbase FILTER html %]upgrade.html&quot;&gt;Upgrading 
-  documentation&lt;/a&gt; for instructions on how to upgrade.&lt;/p&gt;
</del><ins>+&lt;h1 id=&quot;v42_previous&quot;&gt;[% terms.Bugzilla %] 4.0 Release Notes&lt;/h1&gt;
</ins><span class="cx"> 
</span><del>-&lt;h2&gt;&lt;a name=&quot;v32_code_changes&quot;&gt;&lt;/a&gt;Code Changes Which May Affect 
-  Customizations&lt;/h2&gt;
-
-&lt;ul&gt;
-  &lt;li&gt;&lt;a href=&quot;#v32_code_hooks&quot;&gt;More Hooks!&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v32_code_search&quot;&gt;Search.pm Rearchitecture&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v32_code_lib&quot;&gt;lib Directory&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v32_code_other&quot;&gt;Other Changes&lt;/a&gt;&lt;/li&gt;
</del><ins>+&lt;ul class=&quot;bz_toc&quot;&gt;
+  &lt;li&gt;&lt;a href=&quot;#v40_introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v40_point&quot;&gt;Updates in this 4.0.x Release&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v40_req&quot;&gt;Minimum Requirements&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v40_feat&quot;&gt;New Features and Improvements&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v40_issues&quot;&gt;Outstanding Issues&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v40_upgrading&quot;&gt;Notes On Upgrading From a Previous Version&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v40_code_changes&quot;&gt;Code Changes Which May Affect 
+    Customizations and Extensions&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v40_previous&quot;&gt;Release Notes for Previous Versions&lt;/a&gt;&lt;/li&gt;
</ins><span class="cx"> &lt;/ul&gt;
</span><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v32_code_hooks&quot;&gt;&lt;/a&gt;More Hooks!&lt;/h3&gt;
</del><ins>+&lt;h2 id=&quot;v40_introduction&quot;&gt;Introduction&lt;/h2&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;There are more code hooks in 3.2 than there were in 3.0. See the
-  documentation of &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/Hook.html&quot;&gt;Bugzilla::Hook&lt;/a&gt;
-  for more details.&lt;/p&gt;
</del><ins>+&lt;p&gt;This is [% terms.Bugzilla %] 4.0! Since 3.6 (our previous major
+  release) we've come a long way, and we've come even further compared to
+  3.0 in 2007! Since [% terms.Bugzilla %] 3.0, almost every major user
+  interface in [% terms.Bugzilla %] has been redesigned, the WebServices have
+  evolved enormously, there's a great new Extensions system, and there
+  are hundreds of other new features. With the major redesigns that come
+  particularly in this release compared to 3.6, we felt that it was time to
+  call this release 4.0.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v32_code_search&quot;&gt;&lt;/a&gt;Search.pm Rearchitecture&lt;/h3&gt;
</del><ins>+&lt;p&gt;It's not just major WebService and UI enhancements that are new in
+  [%+ terms.Bugzilla %] 4.0&amp;mdash;there are many other exciting new features,
+  including automatic duplicate detection, enhanced custom field
+  functionality, autocomplete for users, search improvements, and much
+  more. Overall, 4.0 is far and away the best version of [% terms.Bugzilla %]
+  we've ever released.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;&lt;kbd&gt;Bugzilla/Search.pm&lt;/kbd&gt; has been heavily modified, to be much
-  easier to read and use. It contains mostly the same code as it did in
-  3.0, but it has been moved around and reorganized significantly.&lt;/p&gt;
</del><ins>+&lt;p&gt;If you're upgrading, make sure to read &lt;a href=&quot;#v40_upgrading&quot;&gt;Notes
+  On Upgrading From a Previous Version&lt;/a&gt;. If you are upgrading from a release
+  before 3.6, make sure to read the release notes for all the 
+  &lt;a href=&quot;#v40_previous&quot;&gt;previous versions&lt;/a&gt; in between your version
+  and this one, &lt;strong&gt;particularly the Upgrading section of each
+  version's release notes&lt;/strong&gt;.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v32_code_lib&quot;&gt;&lt;/a&gt;lib Directory&lt;/h3&gt;
</del><ins>+&lt;p&gt;We would like to thank
+  &lt;a href=&quot;http://www.itasoftware.com/&quot;&gt;ITA Software&lt;/a&gt;,
+  the &lt;a href=&quot;http://www.ibm.com/linux/ltc/&quot;&gt;IBM Linux Technology Center&lt;/a&gt;,
+  and &lt;a href=&quot;http://www.redhat.com/&quot;&gt;Red Hat&lt;/a&gt; for funding the development
+  of certain features and improvements in this release of
+  [%+ terms.Bugzilla %].&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;As part of implementing &lt;a href=&quot;#v32_feat_install&quot;&gt;install-module.pl&lt;/a&gt;,
-  [%+ terms.Bugzilla %] was given a local &lt;kbd&gt;lib&lt;/kbd&gt; directory which
-  it searches for modules, in addition to the standard system path.&lt;/p&gt;
</del><ins>+&lt;h2 id=&quot;v40_point&quot;&gt;Updates in this 4.0.x Release&lt;/h2&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;This means that all [% terms.Bugzilla %] scripts now start with
-  &lt;code&gt;use lib qw(. lib);&lt;/code&gt; as one of the first lines.&lt;/p&gt;
</del><ins>+&lt;h3&gt;4.0.2&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v32_code_other&quot;&gt;&lt;/a&gt;Other Changes&lt;/h3&gt;
</del><ins>+&lt;p&gt;This release fixes several security issues. See the
+  &lt;a href=&quot;http://www.bugzilla.org/security/3.4.11/&quot;&gt;Security Advisory&lt;/a&gt;
+  for details.&lt;/p&gt;
</ins><span class="cx"> 
</span><ins>+&lt;p&gt;In addition, the following important fixes/changes have been made in this
+  release:&lt;/p&gt;
+
</ins><span class="cx"> &lt;ul&gt;
</span><del>-  &lt;li&gt;You should now be using &lt;code&gt;get_status('NEW')&lt;/code&gt; instead of
-    &lt;code&gt;status_descs.NEW&lt;/code&gt; in templates.&lt;/li&gt;
-  &lt;li&gt;The &lt;code&gt;[&amp;#37;# version = 1.0 &amp;#37;]&lt;/code&gt; comment at the top of every
-    template file has been removed.&lt;/li&gt;
</del><ins>+  &lt;li&gt;The &lt;kbd&gt;B[% %]ug.create&lt;/kbd&gt; WebService method now throws an error if you
+    pass a group name which doesn't exist. In [% terms.Bugzilla %] 4.0 and 4.0.1,
+    this group name was silently ignored, leaving your [% terms.bug %] unsecure
+    if no other group applied.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=653341&quot;&gt;[% terms.Bug %] 653341&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;Moving several [% terms.bugs %] at once into another product displayed the
+    same confirmation page again and again, and changes were never committed
+    (regressed in 4.0).
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=663208&quot;&gt;[% terms.Bug %] 663208&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;Marking [% terms.abug %] as a duplicate now works in Internet Explorer 9.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=656769&quot;&gt;[% terms.Bug %] 656769&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;&lt;kbd&gt;importxml.pl&lt;/kbd&gt; no longer crashes when importing keywords (regressed
+    in 4.0).
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=657707&quot;&gt;[% terms.Bug %] 657707&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;Data entered while reporting a new [% terms.bug %] could be lost if you had
+    to click the &quot;Back&quot; button of your web browser.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=652427&quot;&gt;[% terms.Bug %] 652427&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;WebServices methods will return undefined [% terms.bug %] fields as undefined
+    instead of as an empty string. This change is consistent with how
+    [%+ terms.Bugzilla %] 4.2 behaves.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=657561&quot;&gt;[% terms.Bug %] 657561&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;The XML-RPC interface now works with SOAP::Lite 0.711 and 0.712 under mod_perl.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=600810&quot;&gt;[% terms.Bug %] 600810&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;LWP 6.00 and newer require Perl 5.8.8 and above. When installing this module
+    using &lt;kbd&gt;install-module.pl&lt;/kbd&gt; on a Perl installation older than 5.8.8,
+    LWP 5.837 will be installed instead.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=655912&quot;&gt;[% terms.Bug %] 655912&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;Viewing [% terms.abug %] report should be significantly faster when your
+    installation has many custom fields.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=634812&quot;&gt;[% terms.Bug %] 634812&lt;/a&gt;)&lt;/li&gt;
</ins><span class="cx"> &lt;/ul&gt;
</span><span class="cx"> 
</span><del>-&lt;h2&gt;&lt;a name=&quot;v32_previous&quot;&gt;&lt;/a&gt;Release Notes For Previous Versions&lt;/h2&gt;
</del><ins>+&lt;h3&gt;4.0.1&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;h1&gt;[% terms.Bugzilla %] 3.0.x Release Notes&lt;/h1&gt;
-
-&lt;h2&gt;Table of Contents&lt;/h2&gt;
-
-&lt;ul class=&quot;bz_toc&quot;&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_point&quot;&gt;Updates In This 3.0.x Release&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_req&quot;&gt;Minimum Requirements&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_feat&quot;&gt;New Features and Improvements&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_issues&quot;&gt;Outstanding Issues&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_security&quot;&gt;Security Fixes In This Release&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_upgrading&quot;&gt;How to Upgrade From An Older Version&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_code_changes&quot;&gt;Code Changes Which May Affect 
-    Customizations&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_previous&quot;&gt;Release Notes for Previous Versions&lt;/a&gt;&lt;/li&gt;
-&lt;/ul&gt;
-
-&lt;h2&gt;&lt;a name=&quot;v30_introduction&quot;&gt;&lt;/a&gt;Introduction&lt;/h2&gt;
-
-&lt;p&gt;Welcome to [% terms.Bugzilla %] 3.0! It's been over eight years since
-  we released [% terms.Bugzilla %] 2.0, and everything has changed since
-  then. Even just since our previous release, [% terms.Bugzilla %] 2.22,
-  we've added a &lt;em&gt;lot&lt;/em&gt; of new features. So enjoy the release, we're
-  happy to bring it to you.&lt;/p&gt;
-
-&lt;p&gt;If you're upgrading, make sure to read &lt;a href=&quot;#v30_upgrading&quot;&gt;How to
-  Upgrade From An Older Version&lt;/a&gt;. If you are upgrading from a release
-  before 2.22, make sure to read the release notes for all the 
-  &lt;a href=&quot;#v30_previous&quot;&gt;previous versions&lt;/a&gt; in between your version 
-  and this one.&lt;/p&gt;
-
-&lt;h2&gt;&lt;a name=&quot;v30_point&quot;&gt;Updates in this 3.0.x Release&lt;/a&gt;&lt;/h2&gt;
-
-&lt;p&gt;This section describes what's changed in the most recent b&lt;!-- --&gt;ug-fix
-  releases of [% terms.Bugzilla %] after 3.0. We only list the
-  most important fixes in each release. If you want a detailed list of
-  &lt;em&gt;everything&lt;/em&gt; that's changed in each version, you should use our
-  &lt;a href=&quot;http://www.bugzilla.org/status/changes.html&quot;&gt;Change Log Page&lt;/a&gt;.&lt;/p&gt;
-
-&lt;h3&gt;3.0.6&lt;/h3&gt;
-
</del><span class="cx"> &lt;ul&gt;
</span><del>-  &lt;li&gt;Before 3.0.6, unexpected fatal WebService errors would result in
-    a &lt;code&gt;faultCode&lt;/code&gt; that was a string instead of a number.
-   (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=446327&quot;&gt;[% terms.Bug %] 446327&lt;/a&gt;)&lt;/li&gt;
-  &lt;li&gt;If you created a product or component with the same name as one you
-    previously deleted, it would fail with an error about the series table.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=247936&quot;&gt;[% terms.Bug %] 247936&lt;/a&gt;)&lt;/li&gt;
</del><ins>+  &lt;li&gt;During installation, the CPAN module Math::Random::Secure would
+    sometimes fail to install properly and give an error about
+    &lt;kbd&gt;Math::Random::Secure::irand&lt;/kbd&gt;. Now, when using
+    &lt;kbd&gt;install-module.pl&lt;/kbd&gt; to install Math::Random::Secure, this
+    will no longer happen. If you are currently experiencing this b[% %]ug
+    and it prevented you from installing 4.0, remove Math::Random::Secure
+    from your &lt;kbd&gt;lib/&lt;/kbd&gt; directory, like:
+    &lt;p&gt;&lt;kbd&gt;rm -rf lib/Math/Random/Secure*&lt;/kbd&gt;&lt;/p&gt;
+    &lt;p&gt;(&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=646578&quot;&gt;[% terms.Bug %] 646578&lt;/a&gt;)&lt;/p&gt;&lt;/li&gt;
+  &lt;li&gt;The &quot;Remember values as bookmarkable template&quot; button on the
+    [%+ terms.bug %] entry page will now work even when some required fields
+    are empty. 
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=640719&quot;&gt;[% terms.Bug %] 640719&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;Email notifications about dependencies and flags had the wrong
+    timestamp.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=643910&quot;&gt;[% terms.Bug %] 643910&lt;/a&gt;
+    and  (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=652165&quot;&gt;[% terms.Bug %] 652165&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;You can now select &quot;UTC&quot; as a valid timezone in General Preferences.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=646209&quot;&gt;[% terms.Bug %] 646209&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;Automatic duplicate detection now works on PostgreSQL (although
+    it is not as high-quality as on other DB platforms). 
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=634144&quot;&gt;[% terms.Bug %] 634144&lt;/a&gt;)&lt;/li&gt;
+   &lt;li&gt;Autcomplete for users now works even if you are using the
+     &quot;emailsuffix&quot; option.
+     (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=641519&quot;&gt;[% terms.Bug %] 641519&lt;/a&gt;)&lt;/li&gt;
+   &lt;li&gt;Javascript errors during series creation in New Charts have been
+     fixed.
+     (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=644285&quot;&gt;[% terms.Bug %] 644285&lt;/a&gt;)&lt;/li&gt;
+    &lt;li&gt;The &quot;Show Votes&quot; page now works, for installations using the Voting
+      extension.
+      (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=652381&quot;&gt;[% terms.Bug %] 652381&lt;/a&gt;)&lt;/li&gt; 
</ins><span class="cx"> &lt;/ul&gt;
</span><span class="cx"> 
</span><del>-&lt;p&gt;See also the &lt;a href=&quot;#v30_security&quot;&gt;Security Advisory&lt;/a&gt; section for
-  information about a security issue fixed in this release.&lt;/p&gt;
</del><ins>+&lt;h2 id=&quot;v40_req&quot;&gt;Minimum Requirements&lt;/h2&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;3.0.5&lt;/h3&gt;
</del><ins>+&lt;p&gt;Any requirements that are new since 3.6.3 will look like
+  &lt;span class=&quot;req_new&quot;&gt;this&lt;/span&gt;.&lt;/p&gt;
</ins><span class="cx"> 
</span><span class="cx"> &lt;ul&gt;
</span><del>-  &lt;li&gt;If you don't have permission to set a flag, it will now appear
-    unchangeable in the UI.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=433851&quot;&gt;[% terms.Bug %] 433851&lt;/a&gt;)&lt;/li&gt;
-  &lt;li&gt;If you were running mod_perl, [% terms.Bugzilla %] was not correctly
-    closing its connections to the database since 3.0.3, and so sometimes
-    the DB would run out of connections.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=441592&quot;&gt;[% terms.Bug %] 441592&lt;/a&gt;)&lt;/li&gt;
-  &lt;li&gt;The installation script is now clear about exactly which 
-    &lt;code&gt;Email::&lt;/code&gt; modules are required in Perl, thus avoiding the
-    problem where emails show up with a body like 
-    &lt;samp&gt;SCALAR(0xBF126795)&lt;/samp&gt;.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=441541&quot;&gt;[% terms.Bug %] 441541&lt;/a&gt;)&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;[% docs_urlbase FILTER html %]api/email_in.html&quot;&gt;email_in.pl&lt;/a&gt;
-    is no longer case-sensitive for values of &lt;kbd&gt;@product&lt;/kbd&gt;.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=365697&quot;&gt;[% terms.Bug %] 365697&lt;/a&gt;)&lt;/li&gt;
</del><ins>+  &lt;li&gt;&lt;a href=&quot;#v40_req_perl&quot;&gt;Perl&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v40_req_mysql&quot;&gt;For MySQL Users&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v40_req_pg&quot;&gt;For PostgreSQL Users&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v40_req_oracle&quot;&gt;For Oracle Users&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v40_req_modules&quot;&gt;Required Perl Modules&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v40_req_optional_mod&quot;&gt;Optional Perl Modules&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v40_req_apache&quot;&gt;Optional Apache Modules&lt;/a&gt;&lt;/li&gt;
</ins><span class="cx"> &lt;/ul&gt;
</span><span class="cx"> 
</span><del>-&lt;p&gt;See also the &lt;a href=&quot;#v30_security&quot;&gt;Security Advisory&lt;/a&gt; section for
-  information about security issues fixed in this release.&lt;/p&gt;
</del><ins>+&lt;h3 id=&quot;v40_req_perl&quot;&gt;Perl&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;3.0.4&lt;/h3&gt;
</del><ins>+&lt;p&gt;Perl v5.8.1&lt;/p&gt;
+&lt;h3 id=&quot;v40_req_mysql&quot;&gt;For MySQL Users&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;ul&gt;
-  &lt;li&gt;[% terms.Bugzilla %] administrators were not being correctly notified
-    about new releases.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=414726&quot;&gt;[% terms.Bug %] 414726&lt;/a&gt;)&lt;/li&gt;
</del><ins>+  &lt;ul&gt;
+    &lt;li&gt;MySQL v4.1.2&lt;/li&gt;
+    &lt;li&gt;&lt;strong&gt;perl module:&lt;/strong&gt; DBD::mysql v4.00&lt;/li&gt;
+  &lt;/ul&gt;
</ins><span class="cx"> 
</span><del>-  &lt;li&gt;There could be extra whitespace in email subject lines.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=411544&quot;&gt;[% terms.Bug %] 411544&lt;/a&gt;)&lt;/li&gt;
</del><ins>+&lt;h3 id=&quot;v40_req_pg&quot;&gt;For PostgreSQL Users&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-  &lt;li&gt;The priority, severity, OS, and platform fields were always required by
-    the &lt;kbd&gt;B&lt;!-- --&gt;ug.create&lt;/kbd&gt; WebService function, even if they had
-    defaults specified.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=384009&quot;&gt;[% terms.Bug %] 384009&lt;/a&gt;)&lt;/li&gt;
</del><ins>+  &lt;ul&gt;
+    &lt;li&gt;PostgreSQL v8.00.0000&lt;/li&gt;
+    &lt;li&gt;&lt;strong&gt;perl module:&lt;/strong&gt; DBD::Pg v1.45&lt;/li&gt;
+  &lt;/ul&gt;
</ins><span class="cx"> 
</span><del>-  &lt;li&gt;Better threading of [% terms.bug %]mail in some email clients.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=376453&quot;&gt;[% terms.Bug %] 376453&lt;/a&gt;)&lt;/li&gt;
</del><ins>+&lt;h3 id=&quot;v40_req_oracle&quot;&gt;For Oracle Users&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-  &lt;li&gt;There were many fixes to the Inbound Email Interface 
-    (&lt;kbd&gt;email_in.pl&lt;/kbd&gt;).
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=92274&quot;&gt;[% terms.Bug %] 92274&lt;/a&gt;,
-     &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=377025&quot;&gt;[% terms.Bug %] 377025&lt;/a&gt;,
-     &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=412943&quot;&gt;[% terms.Bug %] 412943&lt;/a&gt;,
-     &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=413672&quot;&gt;[% terms.Bug %] 413672&lt;/a&gt;, and
-     &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=431721&quot;&gt;[% terms.Bug %] 431721&lt;/a&gt;)&lt;/li&gt;
</del><ins>+  &lt;ul&gt;
+    &lt;li&gt;Oracle v10.02.0&lt;/li&gt;
+    &lt;li&gt;&lt;strong&gt;perl module:&lt;/strong&gt; DBD::Oracle v1.19&lt;/li&gt;
+  &lt;/ul&gt;
</ins><span class="cx"> 
</span><del>-  &lt;li&gt;checksetup.pl now handles UTF-8 conversion more reliably during upgrades.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=374951&quot;&gt;[% terms.Bug %] 374951&lt;/a&gt;)&lt;/li&gt;
</del><ins>+&lt;h3 id=&quot;v40_req_modules&quot;&gt;Required Perl Modules&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-  &lt;li&gt;Comments written in CJK languages are now correctly word-wrapped.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=388723&quot;&gt;[% terms.Bug %] 388723&lt;/a&gt;)&lt;/li&gt;
</del><ins>+  &lt;table cellspacing=&quot;0&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; class=&quot;req_table&quot;&gt;
+    &lt;tbody&gt;
+      &lt;tr&gt;
+        &lt;th&gt;Module&lt;/th&gt;&lt;th&gt;Version&lt;/th&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;CGI&lt;/td&gt;
+        &lt;td class=&quot;req_new&quot;&gt;3.51&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;Digest::SHA&lt;/td&gt;
+        &lt;td&gt;(Any)&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;Date::Format&lt;/td&gt;
+        &lt;td&gt;2.21&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;DateTime&lt;/td&gt;
+        &lt;td&gt;0.28&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;DateTime::TimeZone&lt;/td&gt;
+        &lt;td&gt;0.71&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;DBI&lt;/td&gt;
+        &lt;td&gt;1.41&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;Template&lt;/td&gt;
+        &lt;td&gt;2.22&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;Email::Send&lt;/td&gt;
+        &lt;td&gt;2.00&lt;/td&gt;
+      &lt;/tr&gt;
</ins><span class="cx"> 
</span><del>-  &lt;li&gt;All emails will now be sent in the correct language, when the user
-    has chosen a language for emails.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=405946&quot;&gt;[% terms.Bug %] 405946&lt;/a&gt;)
</del><ins>+      &lt;tr&gt;
+        &lt;td&gt;Email::MIME&lt;/td&gt;
+        &lt;td class=&quot;req_new&quot;&gt;1.904&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;URI&lt;/td&gt;
+        &lt;td&gt;(Any)&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td class=&quot;req_new&quot;&gt;List::MoreUtils&lt;/td&gt;
+        &lt;td class=&quot;req_new&quot;&gt;0.22&lt;/td&gt;
+      &lt;/tr&gt;
+    &lt;/tbody&gt;
+  &lt;/table&gt;
</ins><span class="cx"> 
</span><del>-  &lt;li&gt;On Windows, temporary files created when uploading attachments are now
-    correctly deleted when the upload is complete.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=414002&quot;&gt;[% terms.Bug %] 414002&lt;/a&gt;)&lt;/li&gt;
</del><ins>+&lt;h3 id=&quot;v40_req_optional_mod&quot;&gt;Optional Perl Modules&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-  &lt;li&gt;&lt;kbd&gt;checksetup.pl&lt;/kbd&gt; now prints correct installation instructions
-    for Windows users using Perl 5.10.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=414430&quot;&gt;[% terms.Bug %] 414430&lt;/a&gt;)
-&lt;/ul&gt;
</del><ins>+&lt;p&gt;The following perl modules, if installed, enable various
+  features of [% terms.Bugzilla %]:&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;See also the &lt;a href=&quot;#v30_security&quot;&gt;Security Advisory&lt;/a&gt; section for
-  information about security issues fixed in this release.&lt;/p&gt;
</del><ins>+  &lt;table cellspacing=&quot;0&quot; cellpadding=&quot;0&quot; border=&quot;0&quot; class=&quot;req_table&quot;&gt;
+    &lt;tbody&gt;
+      &lt;tr&gt;
+        &lt;th&gt;Module&lt;/th&gt;&lt;th&gt;Version&lt;/th&gt;&lt;th&gt;Enables Feature&lt;/th&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;GD&lt;/td&gt;
+        &lt;td&gt;1.20&lt;/td&gt;
+        &lt;td&gt;Graphical Reports, New Charts, Old Charts&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;Chart::Lines&lt;/td&gt;
+        &lt;td&gt;2.1&lt;/td&gt;
+        &lt;td&gt;New Charts, Old Charts&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;Template::Plugin::GD::Image&lt;/td&gt;
+        &lt;td&gt;(Any)&lt;/td&gt;
+        &lt;td&gt;Graphical Reports&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;GD::Text&lt;/td&gt;
+        &lt;td&gt;(Any)&lt;/td&gt;
+        &lt;td&gt;Graphical Reports&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;GD::Graph&lt;/td&gt;
+        &lt;td&gt;(Any)&lt;/td&gt;
+        &lt;td&gt;Graphical Reports&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;MIME::Parser&lt;/td&gt;
+        &lt;td&gt;5.406&lt;/td&gt;
+        &lt;td&gt;Move [% terms.Bugs %] Between Installations&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;LWP::UserAgent&lt;/td&gt;
+        &lt;td&gt;(Any)&lt;/td&gt;
+        &lt;td&gt;Automatic Update Notifications&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;XML::Twig&lt;/td&gt;
+        &lt;td&gt;(Any)&lt;/td&gt;
+        &lt;td&gt;Move [% terms.Bugs %] Between Installations, Automatic Update
+          Notifications&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;PatchReader&lt;/td&gt;
+        &lt;td&gt;0.9.4&lt;/td&gt;
+        &lt;td&gt;Patch Viewer&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;Net::LDAP&lt;/td&gt;
+        &lt;td&gt;(Any)&lt;/td&gt;
+        &lt;td&gt;LDAP Authentication&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;Authen::SASL&lt;/td&gt;
+        &lt;td&gt;(Any)&lt;/td&gt;
+        &lt;td&gt;SMTP Authentication&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;Authen::Radius&lt;/td&gt;
+        &lt;td&gt;(Any)&lt;/td&gt;
+        &lt;td&gt;RADIUS Authentication&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;SOAP::Lite&lt;/td&gt;
+        &lt;td class=&quot;req_new&quot;&gt;0.712&lt;/td&gt;
+        &lt;td&gt;XML-RPC Interface&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;JSON::RPC&lt;/td&gt;
+        &lt;td&gt;(Any)&lt;/td&gt;
+        &lt;td&gt;JSON-RPC Interface&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td class=&quot;req_new&quot;&gt;JSON::XS&lt;/td&gt;
+        &lt;td class=&quot;req_new&quot;&gt;2.0&lt;/td&gt;
+        &lt;td&gt;Make JSON-RPC Faster&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;Test::Taint&lt;/td&gt;
+        &lt;td&gt;(Any)&lt;/td&gt;
+        &lt;td&gt;JSON-RPC Interface, XML-RPC Interface&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;HTML::Parser&lt;/td&gt;
+        &lt;td&gt;3.40&lt;/td&gt;
+        &lt;td&gt;More HTML in Product/Group Descriptions&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;HTML::Scrubber&lt;/td&gt;
+        &lt;td&gt;(Any)&lt;/td&gt;
+        &lt;td&gt;More HTML in Product/Group Descriptions&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;Email::MIME::Attachment::Stripper&lt;/td&gt;
+        &lt;td&gt;(Any)&lt;/td&gt;
+        &lt;td&gt;Inbound Email&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;Email::Reply&lt;/td&gt;
+        &lt;td&gt;(Any)&lt;/td&gt;
+        &lt;td&gt;Inbound Email&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;TheSchwartz&lt;/td&gt;
+        &lt;td&gt;(Any)&lt;/td&gt;
+        &lt;td&gt;Mail Queueing&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;Daemon::Generic&lt;/td&gt;
+        &lt;td&gt;(Any)&lt;/td&gt;
+        &lt;td&gt;Mail Queueing&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;mod_perl2&lt;/td&gt;
+        &lt;td&gt;1.999022&lt;/td&gt;
+        &lt;td&gt;mod_perl&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td&gt;Apache2::SizeLimit&lt;/td&gt;
+        &lt;td class=&quot;req_new&quot;&gt;0.93&lt;/td&gt;
+        &lt;td&gt;mod_perl&lt;/td&gt;
+      &lt;/tr&gt;
+      &lt;tr&gt;
+        &lt;td class=&quot;req_new&quot;&gt;Math::Random::Secure&lt;/td&gt;
+        &lt;td class=&quot;req_new&quot;&gt;0.05&lt;/td&gt;
+        &lt;td&gt;Improve cookie and token security&lt;/td&gt;
+      &lt;/tr&gt;
+    &lt;/tbody&gt;
+  &lt;/table&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;3.0.3&lt;/h3&gt;
</del><ins>+&lt;h3 id=&quot;v40_req_apache&quot;&gt;Optional Apache Modules&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;ul&gt;
-  &lt;li&gt;mod_perl no longer compiles [% terms.Bugzilla %]'s code for each Apache
-    process individually. It now compiles code only once and shares it among
-    each Apache process. This greatly improves performance and highly 
-    decreases the memory footprint.
-   (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=398241&quot;&gt;[% terms.Bug %] 398241&lt;/a&gt;)&lt;/li&gt;
</del><ins>+&lt;p&gt;If you are using Apache as your webserver, [% terms.Bugzilla %] can
+  now take advantage of some Apache features if you have the below Apache
+  modules installed and enabled. Currently,
+  &lt;a href=&quot;#v40_feat_js_css_update&quot;&gt;certain [% terms.Bugzilla %] features&lt;/a&gt;
+  are enabled only if you have all of the following modules installed
+  and enabled:&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-  &lt;li&gt;You can now search for '---' (without quotes) in versions and milestones.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=362436&quot;&gt;[% terms.Bug %] 362436&lt;/a&gt;)&lt;/li&gt;
-
-  &lt;li&gt;[% terms.Bugzilla %] should no longer break lines unnecessarily in 
-    email subjects. This was causing trouble with some email clients.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=374424&quot;&gt;[% terms.Bug %] 374424&lt;/a&gt;)&lt;/li&gt;
-
-  &lt;li&gt;If you had selected &quot;I'm added to or removed from this capacity&quot; option
-    for the &quot;CC&quot; role in your email preferences, you wouldn't get mail when
-    more than one person was added to the CC list at once.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=394796&quot;&gt;[% terms.Bug %] 394796&lt;/a&gt;)&lt;/li&gt;
-
-  &lt;li&gt;Deleting a user account no longer deletes whines from another user who
-    has the deleted account as addressee. The schedule is simply removed, 
-    but the whine itself is left intact.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=395924&quot;&gt;[% terms.Bug %] 395924&lt;/a&gt;)&lt;/li&gt;
-
-  &lt;li&gt;&lt;kbd&gt;contrib/merge-users.pl&lt;/kbd&gt; now correctly merges all required
-    fields when merging two user accounts.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=400160&quot;&gt;[% terms.Bug %] 400160&lt;/a&gt;)&lt;/li&gt;
-
-  &lt;li&gt;[% terms.Bugzilla %] no longer requires Apache::DBI to run under 
-    mod_perl. It caused troubles such as lost connections with the DB and
-    didn't give any important performance gain.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=408766&quot;&gt;[% terms.Bug %] 408766&lt;/a&gt;)&lt;/li&gt;
-&lt;/ul&gt;
-
-&lt;h3&gt;3.0.2&lt;/h3&gt;
-
</del><span class="cx"> &lt;ul&gt;
</span><del>-  &lt;li&gt;[% terms.Bugzilla %] should now work on Perl 5.9.5 (and thus the
-    upcoming Perl 5.10.0).
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=390442&quot;&gt;[% terms.Bug %] 390442&lt;/a&gt;)&lt;/li&gt;
</del><ins>+  &lt;li&gt;mod_headers&lt;/li&gt;
+  &lt;li&gt;mod_expires&lt;/li&gt;
+  &lt;li&gt;mod_env&lt;/li&gt;
</ins><span class="cx"> &lt;/ul&gt;
</span><span class="cx"> 
</span><del>-&lt;p&gt;See also the &lt;a href=&quot;#v30_security&quot;&gt;Security Advisory&lt;/a&gt; section for
-  information about an important security issue fixed in this release.&lt;/p&gt;
</del><ins>+&lt;p&gt;On most systems (but not on Windows), &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; is able to
+  tell whether or not you have these modules installed, and it will tell
+  you.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;3.0.1&lt;/h3&gt;
</del><ins>+&lt;h2 id=&quot;v40_feat&quot;&gt;New Features and Improvements&lt;/h2&gt;
</ins><span class="cx"> 
</span><span class="cx"> &lt;ul&gt;
</span><del>-  &lt;li&gt;For users of Firefox 2, the &lt;code&gt;show_bug.cgi&lt;/code&gt; user interface
-    should no longer &quot;collapse&quot; after you modify [% terms.abug %].
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=370739&quot;&gt;[% terms.Bug %] 370739&lt;/a&gt;)&lt;/li&gt;
-  &lt;li&gt;If you can bless a group, and you share a saved search with that
-    group, it will no longer automatically appear in all of that group's
-    footers unless you specifically request that it automatically appear
-    in their footers.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=365890&quot;&gt;[% terms.Bug %] 365890&lt;/a&gt;)&lt;/li&gt;
-  &lt;li&gt;There is now a parameter to allow users to perform searches without
-    any search terms. (In other words, to search for just a Product
-    and Status on the Simple Search page.) The parameter is called
-    &lt;code&gt;specific_search_allow_empty_words&lt;/code&gt;.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=385910&quot;&gt;[% terms.Bug %] 385910&lt;/a&gt;)&lt;/li&gt;
-  &lt;li&gt;If you attach a file that has a MIME-type of &lt;code&gt;text/x-patch&lt;/code&gt;
-    or &lt;code&gt;text/x-diff&lt;/code&gt;, it will automatically be treated as a 
-    patch by [% terms.Bugzilla %].
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=365756&quot;&gt;[% terms.Bug %] 365756&lt;/a&gt;)&lt;/li&gt;
-  &lt;li&gt;Dependency Graphs now work correctly on all mod_perl installations.
-    There should now be no remaining signficant problems with running
-    [%+ terms.Bugzilla %] under mod_perl.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=370398&quot;&gt;[% terms.Bug %] 370398&lt;/a&gt;)&lt;/li&gt;
-  &lt;li&gt;If moving [% terms.abug %] between products would remove groups
-    from the [% terms.bug %], you are now warned.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=303183&quot;&gt;[% terms.Bug %] 303183&lt;/a&gt;)&lt;/li&gt;
-  &lt;li&gt;On IIS, whenever [% terms.Bugzilla %] threw a warning, it would
-    actually appear on the web page. Now warnings are suppressed,
-    unless you have a file in the &lt;code&gt;data&lt;/code&gt; directory called
-    &lt;code&gt;errorlog&lt;/code&gt;, in which case warnings will be printed there.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=390148&quot;&gt;[% terms.Bug %] 390148&lt;/a&gt;)&lt;/li&gt;
-  &lt;li&gt;If you used &lt;kbd&gt;email_in.pl&lt;/kbd&gt; to edit [% terms.abug %] that was
-    protected by groups, all of the groups would be cleared.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=385453&quot;&gt;[% terms.Bug %] 385453&lt;/a&gt;)&lt;/li&gt;
-  &lt;li&gt;PostgreSQL users: New Charts were failing to collect data over time.
-    They will now start collecting data correctly.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=257351&quot;&gt;[% terms.Bug %] 257351&lt;/a&gt;)&lt;/li&gt;
-  &lt;li&gt;Some flag mails didn't specify who the requestee was. 
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=379787&quot;&gt;[% terms.Bug %] 379787&lt;/a&gt;)&lt;/li&gt;
-  &lt;li&gt;Instead of throwing real errors, &lt;kbd&gt;collectstats.pl&lt;/kbd&gt; would
-    just say that it couldn't find &lt;code&gt;ThrowUserError&lt;/code&gt;.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=380709&quot;&gt;[% terms.Bug %] 380709&lt;/a&gt;)&lt;/li&gt;
-  &lt;li&gt;Logging into [% terms.Bugzilla %] from the home page works again
-    with IIS5. 
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=364008&quot;&gt;[% terms.Bug %] 364008&lt;/a&gt;)&lt;/li&gt;
-  &lt;li&gt;If you were using SMTP for sending email, sometimes emails would
-    be missing the &lt;code&gt;Date&lt;/code&gt; header.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=304999&quot;&gt;[% terms.Bug %] 304999&lt;/a&gt;).&lt;/li&gt;
-  &lt;li&gt;In the XML-RPC WebService, &lt;code&gt;B&lt;!-- --&gt;ug.legal_values&lt;/code&gt; now
-    correctly returns values for custom fields if you request values 
-    for custom fields.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=381737&quot;&gt;[% terms.Bug %] 381737&lt;/a&gt;)&lt;/li&gt;
-  &lt;li&gt;The &quot;[% terms.Bug %]-Writing Guidelines&quot; page has been shortened
-    and re-written.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=378590&quot;&gt;[% terms.Bug %] 378590&lt;/a&gt;)&lt;/li&gt;
-  &lt;li&gt;If your &lt;code&gt;urlbase&lt;/code&gt; parameter included a port number,
-    like &lt;code&gt;www.domain.com:8080&lt;/code&gt;, SMTP might have failed.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=384501&quot;&gt;[% terms.Bug %] 384501&lt;/a&gt;)&lt;/li&gt;
-  &lt;li&gt;For SMTP users, there is a new parameter, &lt;code&gt;smtp_debug&lt;/code&gt;.
-    Turning on this parameter will log the full information about
-    every SMTP session to your web server's error log, to help with
-    debugging issues with SMTP.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=384497&quot;&gt;[% terms.Bug %] 384497&lt;/a&gt;)&lt;/li&gt;
-  &lt;li&gt;If you are a &quot;global watcher&quot; (you get all mails from every 
-    [% terms.bug %]), you can now see that in your Email Preferences.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=365302&quot;&gt;[% terms.Bug %] 365302&lt;/a&gt;)&lt;/li&gt;
-  &lt;li&gt;The Status and Resolution of [% terms.bugs %] are now correctly
-    localized in CSV search results.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=389517&quot;&gt;[% terms.Bug %] 389517&lt;/a&gt;)&lt;/li&gt;
-  &lt;li&gt;The &quot;Subject&quot; line of an email was being mangled if it contained
-    non-Latin characters.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=387860&quot;&gt;[% terms.Bug %] 387860&lt;/a&gt;)&lt;/li&gt;
-  &lt;li&gt;Editing the &quot;languages&quot; parameter using &lt;kbd&gt;editparams.cgi&lt;/kbd&gt; would
-    sometimes fail, causing [% terms.Bugzilla %] to throw an error.
-    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=335354&quot;&gt;[% terms.Bug %] 335354&lt;/a&gt;)&lt;/li&gt;
</del><ins>+  &lt;li&gt;&lt;a href=&quot;#v40_feat_dup&quot;&gt;Automatic Duplicate Detection When Filing
+    [%+ terms.Bugs %]&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v40_feat_search_ui&quot;&gt;New Advanced Search UI&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v40_feat_attach_ui&quot;&gt;New Attachment Details UI&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v40_feat_autocomplete&quot;&gt;Autocomplete for Users and
+    Keywords&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v40_feat_ui&quot;&gt;General Usability Improvements&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v40_feat_workflow&quot;&gt;New Default Status Workflow&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v40_feat_lists&quot;&gt;&quot;Last Search&quot; Now Remembers Multiple
+    Searches&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v40_feat_jsonp&quot;&gt;Cross-Domain WebServices with JSONP&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v40_feat_ws&quot;&gt;Major WebService Enhancements&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v40_feat_mandatory&quot;&gt;Mandatory Custom Fields&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v40_feat_vot_ext&quot;&gt;Voting Is Now An Extension&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v40_feat_js_css_update&quot;&gt;Users Get New CSS and Javascript
+    Automatically&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v40_feat_hooks&quot;&gt;Many New Hooks&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v40_feat_apache_config&quot;&gt;New Apache Configuration&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v40_feat_other&quot;&gt;Other Enhancements and Changes&lt;/a&gt;&lt;/li&gt;
</ins><span class="cx"> &lt;/ul&gt;
</span><span class="cx"> 
</span><del>-&lt;h2&gt;&lt;a name=&quot;v30_req&quot;&gt;&lt;/a&gt;Minimum Requirements&lt;/h2&gt;
</del><ins>+&lt;h3 id=&quot;v40_feat_dup&quot;&gt;Automatic Duplicate Detection When Filing
+  [%+ terms.Bugs %]&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;Any requirements that are new since 2.22 will look like
-  &lt;span class=&quot;req_new&quot;&gt;this&lt;/span&gt;.&lt;/p&gt;
</del><ins>+&lt;p&gt;When filing [% terms.abug %], as soon as you start typing in the summary
+  field, [% terms.Bugzilla %] will suggest possible duplicates of the
+  [%+ terms.bug %] you are filing.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;ul&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_req_perl&quot;&gt;Perl&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_req_mysql&quot;&gt;For MySQL Users&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_req_pg&quot;&gt;For PostgreSQL Users&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_req_modules&quot;&gt;Required Perl Modules&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_req_optional_mod&quot;&gt;Optional Perl
-    Modules&lt;/a&gt;&lt;/li&gt;
-&lt;/ul&gt;
</del><ins>+&lt;p&gt;In order for this feature to work, all pre-requisites for JSON-RPC
+  support must be installed on your [% terms.Bugzilla %]. It will be
+  much faster on installations that run under mod_perl than it will
+  be on other installations.&lt;/p&gt;
</ins><span class="cx"> 
</span><ins>+&lt;h3 id=&quot;v40_feat_search_ui&quot;&gt;New Advanced Search UI&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v30_req_perl&quot;&gt;&lt;/a&gt;Perl&lt;/h3&gt;
</del><ins>+&lt;p&gt;Thanks to the UI work of &lt;a href=&quot;http://guy-pyrzak.blogspot.com/&quot;&gt;Guy
+  Pyrzak&lt;/a&gt;, the Advanced Search UI has been completely redesigned.
+  It is now much simpler, and far more approachable for new users, while
+  still retaining all of the features that power users are used to.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;ul&gt;
-  &lt;li&gt;Perl &lt;span class=&quot;req_new&quot;&gt;v&lt;strong&gt;5.8.0&lt;/strong&gt;&lt;/span&gt; (non-Windows 
-    platforms)&lt;/li&gt;
-  &lt;li&gt;Perl v&lt;strong&gt;5.8.1&lt;/strong&gt; (Windows platforms)&lt;/li&gt;
-&lt;/ul&gt;
</del><ins>+&lt;h3 id=&quot;v40_feat_attach_ui&quot;&gt;New Attachment Details UI&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v30_req_mysql&quot;&gt;&lt;/a&gt;For MySQL Users&lt;/h3&gt;
</del><ins>+&lt;p&gt;The UI used for editing attachment details has been completely
+  redesigned, allowing for a normally-size comment box to be used
+  when commenting on attachments, and allowing nearly the entire screen
+  width to be used when doing code reviews or editing an attachment as
+  a comment.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;ul&gt;
-  &lt;li&gt;MySQL v4.1.2&lt;/li&gt;
-  &lt;li&gt;&lt;strong&gt;perl module:&lt;/strong&gt; DBD::mysql v2.9003&lt;/li&gt;
-&lt;/ul&gt;
</del><ins>+&lt;p&gt;Thanks to &lt;a href=&quot;http://guy-pyrzak.blogspot.com/&quot;&gt;Guy Pyrzak&lt;/a&gt; for
+  his excellent work on this UI redesign.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v30_req_pg&quot;&gt;&lt;/a&gt;For PostgreSQL Users&lt;/h3&gt;
</del><ins>+&lt;h3 id=&quot;v40_feat_autocomplete&quot;&gt;Autocomplete for Users and Keywords&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;ul&gt;
-  &lt;li&gt;PostgreSQL v8.00.0000&lt;/li&gt;
-  &lt;li&gt;&lt;strong&gt;perl module:&lt;/strong&gt; DBD::Pg v1.45&lt;/li&gt;
-&lt;/ul&gt;
</del><ins>+&lt;p&gt;Once you type at least three characters in any field that can contain a user
+  (including the [% field_descs.cc FILTER html %],
+  [%+ field_descs.qa_contact FILTER html %], or
+  [%+ field_descs.assigned_to FILTER html %] fields), a list will appear
+  containing all of the users whose real names or usernames match what you are
+  typing. Your [% terms.Bugzilla %] must have all of the optional Perl
+  modules required for JSON-RPC support installed, though, in order for
+  this feature to work. Also, this feature will be &lt;strong&gt;much&lt;/strong&gt;
+  faster on installations that run under mod_perl than it will be on
+  other installations.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v30_req_modules&quot;&gt;&lt;/a&gt;Required Perl Modules&lt;/h3&gt;
</del><ins>+&lt;p&gt;There is also a similar autocomplete for the Keywords field. The
+  Keywords autocomplete does not require JSON-RPC.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;table class=&quot;req_table&quot; border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
-  &lt;tr&gt;
-    &lt;th&gt;Module&lt;/th&gt; &lt;th&gt;Version&lt;/th&gt;
-  &lt;/tr&gt;
-    &lt;tr&gt;&lt;td&gt;CGI&lt;/td&gt; &lt;td&gt;2.93&lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td&gt;Date::Format&lt;/td&gt; &lt;td&gt;2.21&lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td&gt;DBI&lt;/td&gt; 
-    &lt;td class=&quot;req_new&quot;&gt;1.41&lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td&gt;File::Spec&lt;/td&gt; &lt;td&gt;0.84&lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td&gt;Template&lt;/td&gt; &lt;td&gt;2.12&lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td class=&quot;req_new&quot;&gt;Email::Send&lt;/td&gt; 
-    &lt;td class=&quot;req_new&quot;&gt;2.00&lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td&gt;Email::MIME&lt;/td&gt; 
-    &lt;td&gt;1.861&lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td class=&quot;req_new&quot;&gt;Email::MIME::Modifier&lt;/td&gt; 
-    &lt;td class=&quot;req_new&quot;&gt;1.442&lt;/td&gt;
-  &lt;/tr&gt;
-&lt;/table&gt;
</del><ins>+&lt;h3 id=&quot;v40_feat_ui&quot;&gt;General Usability Improvements&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v30_req_optional_mod&quot;&gt;&lt;/a&gt;Optional Perl Modules&lt;/h3&gt;
</del><ins>+&lt;p&gt;In addition to the enhancements listed above, there have been
+  &lt;strong&gt;many&lt;/strong&gt; improvements made across the [% terms.Bugzilla %]
+  user interface. For a list of specific enhancements that were significant,
+  see the &lt;a href=&quot;#v40_feat_other&quot;&gt;Other Enhancements and Changes&lt;/a&gt;
+  section.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;The following perl modules, if installed, enable various
-  features of [% terms.Bugzilla %]:&lt;/p&gt;
</del><ins>+&lt;h3 id=&quot;v40_feat_workflow&quot;&gt;New Default Status Workflow&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;table class=&quot;req_table&quot; border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
-  &lt;tr&gt;
-    &lt;th&gt;Module&lt;/th&gt; &lt;th&gt;Version&lt;/th&gt;
-    &lt;th&gt;Enables Feature&lt;/th&gt;
-  &lt;/tr&gt;
-   &lt;tr&gt;
-     &lt;td class=&quot;req_new&quot;&gt;LWP::UserAgent&lt;/td&gt; 
-     &lt;td class=&quot;req_new&quot;&gt;(Any)&lt;/td&gt; 
-     &lt;td&gt;Automatic Update Notifications&lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td&gt;Template::Plugin::GD::Image&lt;/td&gt; 
-    &lt;td&gt;(Any)&lt;/td&gt; 
-    &lt;td&gt;Graphical Reports&lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td&gt;GD::Graph&lt;/td&gt; 
-    &lt;td&gt;(Any)&lt;/td&gt; 
-    &lt;td&gt;Graphical Reports&lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td&gt;GD::Text&lt;/td&gt; 
-    &lt;td&gt;(Any)&lt;/td&gt; 
-    &lt;td&gt;Graphical Reports&lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td&gt;GD&lt;/td&gt; 
-    &lt;td&gt;1.20&lt;/td&gt; 
-    &lt;td&gt;Graphical Reports, New Charts, Old Charts&lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td class=&quot;req_new&quot;&gt;Email::MIME::Attachment::Stripper&lt;/td&gt; 
-    &lt;td class=&quot;req_new&quot;&gt;(Any)&lt;/td&gt; 
-    &lt;td&gt;Inbound Email&lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td class=&quot;req_new&quot;&gt;Email::Reply&lt;/td&gt; 
-    &lt;td class=&quot;req_new&quot;&gt;(Any)&lt;/td&gt; 
-    &lt;td&gt;Inbound Email&lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td&gt;Net::LDAP&lt;/td&gt; 
-    &lt;td&gt;(Any)&lt;/td&gt; 
-    &lt;td&gt;LDAP Authentication&lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td&gt;HTML::Parser&lt;/td&gt; 
-    &lt;td&gt;3.40&lt;/td&gt; 
-    &lt;td&gt;More HTML in Product/Group Descriptions&lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td&gt;HTML::Scrubber&lt;/td&gt; 
-    &lt;td&gt;(Any)&lt;/td&gt; 
-    &lt;td&gt;More HTML in Product/Group Descriptions&lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td&gt;XML::Twig&lt;/td&gt; 
-    &lt;td&gt;(Any)&lt;/td&gt; 
-    &lt;td&gt;Move [% terms.Bugs %] Between Installations&lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td&gt;MIME::Parser&lt;/td&gt; 
-    &lt;td&gt;5.406&lt;/td&gt; 
-    &lt;td&gt;Move [% terms.Bugs %] Between Installations&lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td&gt;Chart::Base&lt;/td&gt; 
-    &lt;td&gt;1.0&lt;/td&gt; 
-    &lt;td&gt;New Charts, Old Charts&lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td&gt;Image::Magick&lt;/td&gt; 
-    &lt;td&gt;(Any)&lt;/td&gt; 
-    &lt;td&gt;Optionally Convert BMP Attachments to PNGs&lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td&gt;PatchReader&lt;/td&gt; 
-    &lt;td&gt;0.9.4&lt;/td&gt; 
-    &lt;td&gt;Patch Viewer&lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td class=&quot;req_new&quot;&gt;SOAP::Lite&lt;/td&gt; 
-    &lt;td class=&quot;req_new&quot;&gt;(Any)&lt;/td&gt; 
-    &lt;td&gt;XML-RPC Interface&lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td class=&quot;req_new&quot;&gt;mod_perl2&lt;/td&gt; 
-    &lt;td class=&quot;req_new&quot;&gt;1.999022&lt;/td&gt; 
-    &lt;td&gt;mod_perl&lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td&gt; CGI&lt;/td&gt; 
-    &lt;td&gt;3.11&lt;/td&gt; 
-    &lt;td&gt;mod_perl&lt;/td&gt;
-  &lt;/tr&gt;
-&lt;/table&gt;
</del><ins>+&lt;p&gt;For new installations of [% terms.Bugzilla %], the default set of
+  statuses will now be:&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;h2&gt;&lt;a name=&quot;v30_feat&quot;&gt;&lt;/a&gt;New Features and Improvements&lt;/h2&gt;
-
</del><span class="cx"> &lt;ul&gt;
</span><del>-  &lt;li&gt;&lt;a href=&quot;#v30_feat_cf&quot;&gt;Custom Fields&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_feat_mp&quot;&gt;mod_perl Support&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_feat_sq&quot;&gt;Shared Saved Searches&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;
-    &lt;a href=&quot;#v30_feat_afn&quot;&gt;Attachments and Flags on New [% terms.Bugs %]&lt;/a&gt;
-  &lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_feat_cr&quot;&gt;Custom Resolutions&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_feat_ppp&quot;&gt;Per-Product Permissions&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_feat_ui&quot;&gt;User Interface Improvements&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_feat_xml&quot;&gt;XML-RPC Interface&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_feat_skin&quot;&gt;Skins&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_feat_sbu&quot;&gt;Unchangeable Fields Appear 
-    Unchangeable&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_feat_et&quot;&gt;All Emails in Templates&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_feat_df&quot;&gt;No More Double-Filed [% terms.Bugs %]&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_feat_cc&quot;&gt;Default CC List for Components&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_feat_emi&quot;&gt;File/Modify [% terms.Bugs %] By Email&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_feat_gw&quot;&gt;Users Who Get All [% terms.Bug %] 
-    Notifications&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_feat_utf8&quot;&gt;Improved UTF-8 Support&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_feat_upda&quot;&gt;Automatic Update Notification&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_feat_welc&quot;&gt;Welcome Page for New Installs&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_feat_other&quot;&gt;Other Enhancements and Changes&lt;/a&gt;&lt;/li&gt;
</del><ins>+  &lt;li&gt;UNCONFIRMED&lt;/li&gt;
+  &lt;li&gt;CONFIRMED&lt;/li&gt;
+  &lt;li&gt;IN_PROGRESS&lt;/li&gt;
+  &lt;li&gt;RESOLVED&lt;/li&gt;
+  &lt;li&gt;VERIFIED&lt;/li&gt;
</ins><span class="cx"> &lt;/ul&gt;
</span><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v30_feat_cf&quot;&gt;&lt;/a&gt;Custom Fields&lt;/h3&gt;
</del><ins>+&lt;p&gt;And the UNCONFIRMED status will be enabled by default in all products.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;[% terms.Bugzilla %] now includes very basic support for custom fields.&lt;/p&gt;
</del><ins>+&lt;p&gt;On upgrade, existing installations will not be affected--you will retain
+  your existing status workflow. However, we strongly recommend that you
+  update your existing workflow to the new one, using a special tool
+  we've included, &lt;kbd&gt;contrib/convert-workflow.pl&lt;/kbd&gt;, which you
+  can run after you use &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; to upgrade. The
+  &lt;kbd&gt;whineatnews.pl&lt;/kbd&gt; and &lt;kbd&gt;bugzilla-submit&lt;/kbd&gt; scripts
+  will probably not work properly if you continue to use the old workflow
+  (though most other parts of [% terms.Bugzilla %] will still function
+  normally).&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;Users in the &lt;kbd&gt;admin&lt;/kbd&gt; group can add plain-text or drop-down
-  custom fields. You can edit the values available for drop-down fields
-  using the &amp;quot;Field Values&amp;quot; control panel.&lt;/p&gt;
</del><ins>+&lt;p&gt;For more information about the workflow and our rationale for changing
+  it, see the
+  &lt;a href=&quot;http://bugzillaupdate.wordpress.com/2010/07/06/bugzilla-4-0-has-a-new-default-status-workflow/&quot;&gt;blog
+  post about it&lt;/a&gt; and the
+  &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=486292&quot;&gt;[% terms.bug %]
+  where the change was made&lt;/a&gt;.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;Don't add too many custom fields! It can make [% terms.Bugzilla %]
-  very difficult to use. Try your best to get along with the default
-  fields, and then if you find that you can't live without custom fields
-  after a few weeks of using [% terms.Bugzilla %], only then should you
-  start your custom fields.&lt;/p&gt;
</del><ins>+&lt;h3 id=&quot;v40_feat_lists&quot;&gt;&quot;Last Search&quot; Now Remembers Multiple Searches&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v30_feat_mp&quot;&gt;&lt;/a&gt;mod_perl Support&lt;/h3&gt;
</del><ins>+&lt;p&gt;At the top of every [% terms.bug %] in [% terms.Bugzilla %], there are
+  links that look like: &quot;First&quot;, &quot;Last&quot;, &quot;Prev&quot;, &quot;Next&quot;, and
+  &quot;Show last search results&quot;. In earlier versions of [% terms.Bugzilla %],
+  if you did two separate searches in separate windows, these links would
+  only work for the &lt;em&gt;last&lt;/em&gt; search you did. Now, [% terms.Bugzilla %]
+  will &quot;remember&quot; which search result you came from and give you the right
+  &quot;last search results&quot; or &quot;next [% terms.bug %]&quot; from &lt;em&gt;that&lt;/em&gt; list,
+  instead of always using your most recent search.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;[% terms.Bugzilla %] 3.0 supports mod_perl, which allows for extremely
-  enhanced page-load performance. mod_perl trades memory usage for performance,
-  allowing near-instantaneous page loads, but using much more memory.&lt;/p&gt;
</del><ins>+&lt;p&gt;There are still some situations where [% terms.Bugzilla %] will have to
+  &quot;guess&quot; which search you are trying to navigate through, but it does its
+  best to get it right.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;If you want to enable mod_perl for your [% terms.Bugzilla %], we recommend
-  a minimum of 1.5GB of RAM, and for a site with heavy traffic, 4GB to 8GB.&lt;/p&gt;
</del><ins>+&lt;h3 id=&quot;v40_feat_jsonp&quot;&gt;Cross-Domain WebServices with JSONP&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;If performance isn't that critical on your installation, you don't
-  have the memory, or you are running some other web server than
-  Apache, [% terms.Bugzilla %] still runs perfectly as a normal CGI
-  application, as well.&lt;/p&gt;
</del><ins>+&lt;p&gt;[% terms.Bugzilla %] now supports making WebService calls from
+  another domain, inside of a web browser, thanks to support for
+  &lt;a href=&quot;http://bob.pythonmac.org/archives/2005/12/05/remote-json-jsonp/&quot;&gt;JSONP&lt;/a&gt;.
+  This will allow for web &quot;mash-ups&quot; to use [% terms.Bugzilla %] data.
+  When using JSONP, you may only call functions that &lt;em&gt;get&lt;/em&gt; data, 
+  you may not call functions that &lt;em&gt;change&lt;/em&gt; data.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v30_feat_sq&quot;&gt;&lt;/a&gt;Shared Saved Searches&lt;/h3&gt;
</del><ins>+&lt;p&gt;For more details, see the
+  &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/WebService/Server/JSONRPC.html#JSONP&quot;&gt;JSONP
+  section&lt;/a&gt; of the JSON-RPC WebService documentation.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;Users can now choose to &amp;quot;share&amp;quot; their saved searches
-  with a certain group. That group will then be able to 
-  &amp;quot;subscribe&amp;quot; to those searches, and have them appear
-  in their footer.&lt;/p&gt;
</del><ins>+&lt;h3 id=&quot;v40_feat_ws&quot;&gt;Major WebService Enhancements&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;If the sharer can &amp;quot;bless&amp;quot; the group he's sharing to,
-  (that is, if he can add users to that group), it's considered
-  that he's a manager of that group, and his queries show up
-  automatically in that group's footer (although they can
-  unsubscribe from any particular search, if they want.)&lt;/p&gt;
</del><ins>+&lt;p&gt;The WebService has been expanded considerably. The WebService should now be
+  able to do everything with [% terms.bugs %] that you can do via the
+  web interface, including updating [% terms.bugs %], adding attachments,
+  and getting attachment data. For specifics, see the
+  &lt;a href=&quot;#v40_feat_ws_changes&quot;&gt;WebService Changes&lt;/a&gt; section of these
+  release notes.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;In order to allow a user to share their queries, they also
-  have to be a member of the group specified in the 
-  &lt;code&gt;querysharegroup&lt;/code&gt; parameter.&lt;/p&gt;
</del><ins>+&lt;h3 id=&quot;v40_feat_mandatory&quot;&gt;Mandatory Custom Fields&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;Users can control their shared and subscribed queries from
-  the &amp;quot;Preferences&amp;quot; screen.&lt;/p&gt;
</del><ins>+&lt;p&gt;You can now specify that certain custom fields are &quot;mandatory&quot;,
+  meaning that they must have a value when [% terms.abug %] is filed,
+  and they can never be empty after that.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v30_feat_afn&quot;&gt;&lt;/a&gt;Attachments and Flags on New 
-  [% terms.Bugs %]&lt;/h3&gt;
</del><ins>+&lt;h3 id=&quot;v40_feat_vot_ext&quot;&gt;Voting Is Now An Extension&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;You can now add an attachment while you are filing a new 
-  [% terms.bug %].&lt;/p&gt;
</del><ins>+&lt;p&gt;All of the code for voting in [% terms.Bugzilla %] has been moved
+  into an extension, called &quot;Voting&quot;, in the &lt;kbd&gt;extensions/Voting/&lt;/kbd&gt;
+  directory. To enable it, you must remove the &lt;kbd&gt;disabled&lt;/kbd&gt; file
+  from that directory, and run &lt;kbd&gt;checksetup.pl&lt;/kbd&gt;.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;You can also set flags on the [% terms.bug %] and on attachments, while
-  filing a new [% terms.bug %].&lt;/p&gt;
</del><ins>+&lt;p&gt;In a future version of [% terms.Bugzilla %], the Voting extension will
+  be moved outside of the [% terms.Bugzilla %] core code, so we are looking
+  for somebody who has an interest in the Voting system and would like to
+  maintain it as a separate extension. There are many enhancement requests
+  that have been made against the Voting system, and the best way for those
+  to get addressed is for somebody to step up and offer to maintain the
+  system outside of [% terms.Bugzilla %]'s core code.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v30_feat_cr&quot;&gt;&lt;/a&gt;Custom Resolutions&lt;/h3&gt;
</del><ins>+&lt;h3 id=&quot;v40_feat_js_css_update&quot;&gt;Users Get New CSS and Javascript
+  Automatically&lt;/h3&gt;
+  
+&lt;p&gt;In past versions of [% terms.Bugzilla %], if you changed
+  [%+ terms.Bugzilla %]'s CSS or Javascript files, then every user of
+  [%+ terms.Bugzilla %] would have to clear their cache in order to get
+  the updated files. Now, if you are using Apache as your webserver and
+  you have the &lt;a href=&quot;#v40_req_apache&quot;&gt;optional Apache modules&lt;/a&gt;
+  installed and enabled, users will automatically get every new version of
+  [%+ terms.Bugzilla %]'s Javascript and CSS without having to clear
+  their caches.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;You can now customize the list of resolutions available
-  in [% terms.Bugzilla %], including renaming the default resolutions.&lt;/p&gt;
</del><ins>+&lt;p&gt;This feature also gives a slight performance speedup to
+  [%+ terms.Bugzilla %] in some cases, and so we recommend that all
+  administrators install and enable the optional Apache modules if possible.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;The resolutions &lt;code&gt;FIXED&lt;/code&gt;, &lt;code&gt;DUPLICATE&lt;/code&gt;
-  and &lt;code&gt;MOVED&lt;/code&gt; have a special meaning to [% terms.Bugzilla %],
-  though, and cannot be renamed or deleted.&lt;/p&gt;
</del><ins>+&lt;h3 id=&quot;v40_feat_hooks&quot;&gt;Many New Hooks&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v30_feat_ppp&quot;&gt;&lt;/a&gt;Per-Product Permissions&lt;/h3&gt;
</del><ins>+&lt;p&gt;Many new code hooks have been added for use by Extensions,
+  in [% terms.Bugzilla %] 4.0. Now Extensions can access and modify
+  nearly every part of [% terms.Bugzilla %].&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;You can now grant users &lt;kbd&gt;editbugs&lt;/kbd&gt; and &lt;kbd&gt;canconfirm&lt;/kbd&gt;
-  for only certain products. You can also grant users &lt;kbd&gt;editcomponents&lt;/kbd&gt;
-  on a product, which means they will be able to edit that product
-  including adding/removing components and other product-specific
-  controls.&lt;/p&gt;
</del><ins>+&lt;h3 id=&quot;v40_feat_apache_config&quot;&gt;New Apache Configuration&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v30_feat_ui&quot;&gt;&lt;/a&gt;User Interface Improvements&lt;/h3&gt;
</del><ins>+&lt;p&gt;If you run [% terms.Bugzilla %] under Apache (as most people do),
+  you most likely require a &lt;strong&gt;new Apache configuration&lt;/strong&gt; 
+  for this version of [% terms.Bugzilla %]. See the 
+  &lt;a href=&quot;#v40_upgrading&quot;&gt;Notes On Upgrading From a Previous Version&lt;/a&gt;
+  section for details.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;There has been some work on the user interface for [% terms.Bugzilla %] 3.0,
-  including:&lt;/p&gt;
</del><ins>+&lt;h3 id=&quot;v40_feat_other&quot;&gt;Other Enhancements and Changes&lt;/h3&gt;
</ins><span class="cx"> 
</span><ins>+&lt;h4&gt;Enhancements for Users&lt;/h4&gt;
+
</ins><span class="cx"> &lt;ul&gt;
</span><del>-  &lt;li&gt;There is now navigation and a search box a the &lt;em&gt;top&lt;/em&gt; of
-    each page, in addition to the bar at the bottom of the page.&lt;/li&gt;
-  &lt;li&gt;A re-designed &amp;quot;Format for Printing&amp;quot; page for 
-    [% terms.bugs %].&lt;/li&gt;
-  &lt;li&gt;The layout of &lt;kbd&gt;show_bug.cgi&lt;/kbd&gt; (the [% terms.bug %] editing 
-    page) has been changed, and the attachment table has been redesigned.&lt;/li&gt;
</del><ins>+  &lt;li&gt;Now, everywhere in [% terms.Bugzilla %] where you can enter a date,
+    there is a Calendar widget where you can select the date on a
+    calendar.&lt;/li&gt;
+  &lt;li&gt;The big icons on the front page have been replaced with much nicer
+    icons, thanks to Jon Pink of &lt;a href=&quot;http://www.jpink.co.uk/&quot;&gt;J.&amp;nbsp;Pink&amp;nbsp;Design&lt;/a&gt;!&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;[% terms.Bugs %]:&lt;/strong&gt; When filing [% terms.bugs %],
+    you will now be warned if you forgot to fill in any mandatory fields,
+    &lt;em&gt;before&lt;/em&gt; the page is submitted.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;[% terms.Bugs %]:&lt;/strong&gt; When filing [% terms.abug %],
+    you can hover your mouse over any of the field labels on the page
+    to get a brief description of what that field is and what its purpose
+    is.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;[% terms.Bugs %]:&lt;/strong&gt; When adding Hours Worked to [% terms.abug %],
+    you are no longer required to comment.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;[% terms.Bugs %]:&lt;/strong&gt; There is now a user preference
+    for whether the comment box appears above or below the existing
+    comments.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;[% terms.Bugs %]:&lt;/strong&gt; [% terms.Bugzilla %] will now
+    send an email for every comment that you mark or un-mark as being
+    private. (Previous versions of [% terms.Bugzilla %] did not send emails
+    to users about this change.) The state of comments being made private
+    is also now stored in [% terms.abug %]'s history.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;[% terms.Bugs %]:&lt;/strong&gt; The box to &quot;Add [% terms.Bug %] URLs&quot;
+    in the See Also field is now hidden behind an &quot;(add)&quot; link that you
+    have to click to see the box.&lt;/li&gt;
+  
+  &lt;li&gt;&lt;strong&gt;Searches:&lt;/strong&gt; You can now properly search for field values
+    that have commas in their name, when using the Advanced Search form.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Searches:&lt;/strong&gt; The &quot;URL&quot; field can now be shown as a column
+    in search results.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Searches:&lt;/strong&gt; When viewing a search result, you can now
+    click on the Summary of the [% terms.bug %] in order to go to the
+    [%+ terms.bug %]-view page, in addition to being able to click on the
+    [%+ terms.bug %] ID.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Searches:&lt;/strong&gt; When doing a search using the &quot;quicksearch&quot;
+    box in the header or footer, the box will still contain what you searched
+    for when viewing the search results page.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Searches:&lt;/strong&gt; Multi-select custom fields can now be
+    shown as columns in the search results.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Searches:&lt;/strong&gt; When using the Boolean Charts (now called
+    &quot;Custom Search&quot;), if you specify both a criterion for an attachment
+    and a criteron for a flag, then only [% terms.bugs %] that have
+    attachments with that flag will be found.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Searches:&lt;/strong&gt; If you hover your mouse over the field labels
+    on the Advanced Search page, you will get a description of what that
+    field is.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Searches:&lt;/strong&gt; When searching via a saved search, if you
+    accidentally click on &quot;Forget Search&quot;, there is a link to undo it.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Searches:&lt;/strong&gt; When using the Boolean Charts (now called
+    &quot;Custom Search&quot;), you can search for values &quot;greater than or equal to&quot;
+    or &quot;less than or equal to&quot; some value.&lt;/li&gt;
+  
+  &lt;li&gt;&lt;strong&gt;Flags:&lt;/strong&gt; If you hover your mouse over the name of
+    a flag setter when viewing [% terms.abug %], you can see that
+    flag setter's full name and complete username.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Flags:&lt;/strong&gt; When setting a flag on [% terms.abug %],
+    the box for entering a requestee does not appear until you set the flag
+    to &quot;?&quot;, now.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Flags:&lt;/strong&gt; On the &quot;My Requests&quot; page, [% terms.bugs %]
+    that are restricted to certain groups now properly have the &quot;padlock&quot;
+    icon shown next to them to indicate that they may contain confidential
+    information.&lt;/li&gt;
+  
+  &lt;li&gt;When using the Reports interface, you can now choose many more fields
+    as the X, Y, or Z axis of a report, including custom fields.&lt;/li&gt;
+  &lt;li&gt;[% terms.Bugzilla %] now prevents
+    Internet Explorer 8 and later from attempting to render
+    &lt;kbd&gt;text/plain&lt;/kbd&gt; attachments as HTML.&lt;/li&gt;
+  &lt;li&gt;If you receive a Whine mail that is empty, there will now be a brief
+    message explaining that your search found no results.&lt;/li&gt;
+  &lt;li&gt;The &lt;a href=&quot;page.cgi?id=fields.html&quot;&gt;Field Help Page&lt;/a&gt; now
+    contains a description of every single field that can be on
+    [%+ terms.abug %] in [% terms.Bugzilla %].&lt;/li&gt;
</ins><span class="cx"> &lt;/ul&gt;
</span><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v30_feat_xml&quot;&gt;&lt;/a&gt;XML-RPC Interface&lt;/h3&gt;
</del><ins>+&lt;h4&gt;Enhancements for Administrators and Developers&lt;/h4&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;[% terms.Bugzilla %] now has a Web Services interface using the XML-RPC
-  protocol. It can be accessed by external applications by going
-  to the &lt;kbd&gt;xmlrpc.cgi&lt;/kbd&gt; on your installation.&lt;/p&gt;
-
-&lt;p&gt;Documentation can be found in the 
-  &lt;a href=&quot;[% docs_urlbase FILTER html %]api/&quot;&gt;[% terms.Bugzilla %] 
-  API Docs&lt;/a&gt;, in the various &lt;kbd&gt;Bugzilla::WebService&lt;/kbd&gt; modules.&lt;/p&gt;
-
-&lt;h3&gt;&lt;a name=&quot;v30_feat_skin&quot;&gt;&lt;/a&gt;Skins&lt;/h3&gt;
-
-&lt;p&gt;[% terms.Bugzilla %] can have multiple &amp;quot;skins&amp;quot; installed,
-  and users can pick between them. To write a skin, you just have to
-  write several CSS files. See the &lt;a href=&quot;[% docs_urlbase FILTER html %]cust-skins.html&quot;&gt;Custom
-  Skins Documentation&lt;/a&gt; for more details.&lt;/p&gt;
-
-&lt;p&gt;We currently don't have any alternate skins shipping with
-  [% terms.Bugzilla %]. If you write an alternate skin, please
-  let us know!&lt;/p&gt;
-
-&lt;h3&gt;&lt;a name=&quot;v30_feat_sbu&quot;&gt;&lt;/a&gt;Unchangeable Fields Appear
-  Unchangeable&lt;/h3&gt;
-
-&lt;p&gt;As long as you are logged in, when viewing [% terms.abug %], if you 
-  cannot change a field, it will not look like you can change it. That 
-  is, the value will just appear as plain text.&lt;/p&gt;
-
-&lt;h3&gt;&lt;a name=&quot;v30_feat_et&quot;&gt;&lt;/a&gt;All Emails in Templates&lt;/h3&gt;
-
-&lt;p&gt;All outbound emails are now controlled by the templating system.
-  What used to be the &lt;code&gt;passwordmail&lt;/code&gt;, &lt;code&gt;whinemail&lt;/code&gt;,
-  &lt;code&gt;newchangedmail&lt;/code&gt; and &lt;code&gt;voteremovedmail&lt;/code&gt;
-  parameters are now all templates in the &lt;kbd&gt;template/&lt;/kbd&gt; directory.&lt;/p&gt;
-
-&lt;p&gt;This means that it's now much easier to customize your outbound
-  emails, and it's also possible for localizers to have more
-  localized emails as part of their language packs, if they want.&lt;/p&gt;
-
-&lt;p&gt;We also added a &lt;code&gt;mailfrom&lt;/code&gt; parameter to let you set
-  who shows up in the &lt;code&gt;From&lt;/code&gt; field on all emails that
-  [%+ terms.Bugzilla %] sends.&lt;/p&gt;
-
-&lt;h3&gt;&lt;a name=&quot;v30_feat_df&quot;&gt;&lt;/a&gt;No More Double-Filed [% terms.Bugs %]&lt;/h3&gt;
-
-&lt;p&gt;Users of [% terms.Bugzilla %] will sometimes accidentally submit 
-  [% terms.abug %] twice, either by going back in their web browser, 
-  or just by refreshing a page. In the past, this could file the same 
-  [% terms.bug %] twice (or even three times) in a row, irritating 
-  developers and confusing users.&lt;/p&gt;
-
-&lt;p&gt;Now, if you try to submit [% terms.abug %] twice from the same screen 
-  (by going back or by refreshing the page), [% terms.Bugzilla %] will warn 
-  you about what you're doing, before it actually submits the duplicate
-  [%+ terms.bug %].&lt;/p&gt;
-
-&lt;h3&gt;&lt;a name=&quot;v30_feat_cc&quot;&gt;&lt;/a&gt;Default CC List for Components&lt;/h3&gt;
-
-&lt;p&gt;You can specify a list of users who will &lt;em&gt;always&lt;/em&gt; be added to
-  the CC list of new [% terms.bugs %] in a component.&lt;/p&gt;
-
-&lt;h3&gt;&lt;a name=&quot;v30_feat_emi&quot;&gt;&lt;/a&gt;File/Modify [% terms.Bugs %] By Email&lt;/h3&gt;
-
-&lt;p&gt;You can now file or modify [% terms.bugs %] via email. Previous versions
-  of [% terms.Bugzilla %] included this feature only as an
-  unsupported add-on, but it is now an official interface to
-  [%+ terms.Bugzilla %].&lt;/p&gt;
-
-&lt;p&gt;For more details see the &lt;a href=&quot;[% docs_urlbase FILTER html %]api/email_in.html&quot;&gt;documentation
-  for email_in.pl&lt;/a&gt;.&lt;/p&gt;
-
-&lt;h3&gt;&lt;a name=&quot;v30_feat_gw&quot;&gt;&lt;/a&gt;Users Who Get All [% terms.Bug %] 
-  Notifications&lt;/h3&gt;
-
-&lt;p&gt;There is now a parameter called &lt;kbd&gt;globalwatchers&lt;/kbd&gt;. This
-  is a comma-separated list of [% terms.Bugzilla %] users who will
-  get all [% terms.bug %] notifications generated by [% terms.Bugzilla %].&lt;/p&gt;
-
-&lt;p&gt;Group controls still apply, though, so users who can't see [% terms.abug %]
-  still won't get notifications about that [% terms.bug %].&lt;/p&gt;
-
-&lt;h3&gt;&lt;a name=&quot;v30_feat_utf8&quot;&gt;&lt;/a&gt;Improved UTF-8 Support&lt;/h3&gt;
-
-&lt;p&gt;[% terms.Bugzilla %] users running MySQL should now have excellent
-  UTF-8 support if they turn on the &lt;kbd&gt;utf8&lt;/kbd&gt; parameter. (New
-  installs have this parameter on by default.) [% terms.Bugzilla %]
-  now correctly supports searching and sorting in non-English languages,
-  including multi-bytes languages such as Chinese.&lt;/p&gt;
-
-&lt;h3&gt;&lt;a name=&quot;v30_feat_upda&quot;&gt;&lt;/a&gt;Automatic Update Notification&lt;/h3&gt;
-
-&lt;p&gt;If you belong to the &lt;kbd&gt;admin&lt;/kbd&gt; group, you will be notified
-  when you log in if there is a new release of [% terms.Bugzilla %]
-  available to download.&lt;/p&gt;
-
-&lt;p&gt;You can control these notifications by changing the 
-  &lt;kbd&gt;upgrade_notification&lt;/kbd&gt; parameter.&lt;/p&gt;
-
-&lt;p&gt;If your [% terms.Bugzilla %] installation is on a machine that needs to go
-  through a proxy to access the web, you may also have to set the
-  &lt;kbd&gt;proxy_url&lt;/kbd&gt; parameter.&lt;/p&gt;
-
-&lt;h3&gt;&lt;a name=&quot;v30_feat_welc&quot;&gt;&lt;/a&gt;Welcome Page for New Installs&lt;/h3&gt;
-
-&lt;p&gt;When you log in for the first time on a brand-new [% terms.Bugzilla %]
-  installation, you will be presented with a page that describes
-  where you should go from here, and what parameters you should set.&lt;/p&gt;
-
-&lt;h3&gt;&lt;a name=&quot;v30_feat_qs&quot;&gt;&lt;/a&gt;QuickSearch Plugin for IE7 and Firefox 2&lt;/h3&gt;
-
-&lt;p&gt;Firefox 2 users and Internet Explorer 7 users will be presented
-  with the option to add [% terms.Bugzilla %] to their search bar.
-  This uses the 
-  &lt;a href=&quot;page.cgi?id=quicksearch.html&quot;&gt;QuickSearch syntax&lt;/a&gt;.&lt;/p&gt;
-
-&lt;h3&gt;&lt;a name=&quot;v30_feat_other&quot;&gt;&lt;/a&gt;Other Enhancements and Changes&lt;/h3&gt;
-
-&lt;p&gt;These are either minor enhancements, or enhancements that have
-  very short descriptions. Some of these are very useful, though!&lt;/p&gt;
-
-&lt;h4&gt;Enhancements That Affect [% terms.Bugzilla %] Users&lt;/h4&gt;
-
</del><span class="cx"> &lt;ul&gt;
</span><del>-  &lt;li&gt;In comments, quoted text (lines that start with &lt;kbd&gt;&amp;gt;&lt;/kbd&gt;)
-    will be a different color from normal text.&lt;/li&gt;
-  &lt;li&gt;There is now a user preference that will add you to the CC list
-    of any [% terms.bug %] you modify. Note that it's &lt;strong&gt;on&lt;/strong&gt; 
-    by default.&lt;/li&gt;
-  &lt;li&gt;[% terms.Bugs %] can now be filed with an initial state of 
-    &lt;kbd&gt;ASSIGNED&lt;/kbd&gt;, if you are in the &lt;kbd&gt;editbugs&lt;/kbd&gt; group.&lt;/li&gt;
-  &lt;li&gt;By default, comment fields will zoom large when you are typing in them,
-    and become small when you move out of them. You can disable this
-    in your user preferences.&lt;/li&gt;
-  &lt;li&gt;You can hide obsolete attachments on [% terms.abug %] by clicking
-    &amp;quot;Hide Obsolete&amp;quot; at the bottom of the attachment table.&lt;/li&gt;
-  &lt;li&gt;If [% terms.abug %] has flags set, and you move it to a different 
-    product that has flags with the same name, the flags will be 
-    preserved.&lt;/li&gt;
-  &lt;li&gt;You now can't request a flag to be set by somebody who can't set it
-    ([% terms.Bugzilla %] will throw an error if you try).&lt;/li&gt;
-  &lt;li&gt;Many new headers have been added to outbound [% terms.Bugzilla %]
-    [%+ terms.bug %] emails: &lt;code&gt;X-Bugzilla-Status&lt;/code&gt;,
-    &lt;code&gt;X-Bugzilla-Priority&lt;/code&gt;, &lt;code&gt;X-Bugzilla-Assigned-To&lt;/code&gt;,
-    &lt;code&gt;X-Bugzilla-Target-Milestone&lt;/code&gt;, and 
-    &lt;code&gt;X-Bugzilla-Changed-Fields&lt;/code&gt;, &lt;code&gt;X-Bugzilla-Who&lt;/code&gt;.
-    You can look at an email to get an idea of what they contain.&lt;/li&gt;
-  &lt;li&gt;In addition to the old &lt;code&gt;X-Bugzilla-Reason&lt;/code&gt; email header
-    which tells you why you got an email, if you got an email because
-    you were watching somebody, there is now an 
-    &lt;code&gt;X-Bugzilla-Watch-Reason&lt;/code&gt; header that tells you who you
-    were watching and what role they had.&lt;/li&gt;
-  &lt;li&gt;If you hover your mouse over a full URL (like 
-    &lt;code&gt;http://bugs.mycompany.com/show_bug.cgi?id=1212&lt;/code&gt;) that 
-    links to [% terms.abug %], you will see the title of the 
-    [%+ terms.bug %]. Of course, this only works for [% terms.bugs %] in your
-    [%+ terms.Bugzilla %] installation.&lt;/li&gt;
-  &lt;li&gt;If your installation has user watching enabled, you will now see
-    the users that you can remove from your watch-list as a multi-select
-    box, much like the current CC list. (Previously it was just a text
-    box.)&lt;/li&gt;
-  &lt;li&gt;When a user creates their own account in [% terms.Bugzilla %], the 
-    account is now not actually created until they verify their email
-    address by clicking on a link that is emailed to them.&lt;/li&gt;
-  &lt;li&gt;You can change [% terms.abug %]'s resolution without reopening it.&lt;/li&gt;
-  &lt;li&gt;When you view the dependency tree on [% terms.abug %], resolved 
-    [%+ terms.bugs %] will be hidden by default. (In previous versions,
-    resolved [% terms.bugs %] were shown by default.)&lt;/li&gt;
-  &lt;li&gt;When viewing [% terms.bug %] activity, fields that hold [% terms.bug %] 
-    numbers (such as &amp;quot;Blocks&amp;quot;) will have the [% terms.bug %] numbers
-    displayed as links to those [% terms.bugs %].&lt;/li&gt;
-  &lt;li&gt;When viewing the &amp;quot;Keywords&amp;quot; field in [% terms.abug %] list,
-    it will be sorted alphabetically, so you can sanely sort a list on
-    that field.&lt;/li&gt;
-  &lt;li&gt;In most places, the Version field is now sorted using a version-sort
-    (so 1.10 is greater than 1.2) instead of an alphabetical sort.&lt;/li&gt;
-  &lt;li&gt;Options for flags will only appear if you can set them. So, for
-    example, if you can't grant &lt;kbd&gt;+&lt;/kbd&gt; on a flag, that option
-    won't appear for you.&lt;/li&gt;
-  &lt;li&gt;You can limit the product-related output of &lt;kbd&gt;config.cgi&lt;/kbd&gt;
-    by specifying a &lt;kbd&gt;product=&lt;/kbd&gt; URL argument, containing the name
-    of a product. You can specify the argument more than once for multiple
-    products.&lt;/li&gt;
-  &lt;li&gt;You can now search the boolean charts on whether or not a comment
-    is private.&lt;/li&gt;
</del><ins>+  &lt;li&gt;The system for moving [% terms.bugs %] between installations has been
+    moved into an extension called &lt;kbd&gt;OldBugMove&lt;/kbd&gt;. This system was used
+    by very few [% terms.Bugzilla %] installations--if you aren't certain
+    whether or not you are using it, you're not using it. To enable the system,
+    you have to remove the file &lt;kbd&gt;extensions/OldBugMove/disabled&lt;/kbd&gt;
+    and then run &lt;kbd&gt;checksetup.pl&lt;/kbd&gt;. In a future version of [% terms.Bugzilla %],
+    this extension may be moved outside of the core [% terms.Bugzilla %] code,
+    so if you are interested in maintaining it, please let us know.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Custom Fields: &lt;/strong&gt; &quot;[% terms.Bug %] ID&quot; custom fields can
+    now represent relationships between [% terms.bugs %], similarly to how the
+    [%+ field_descs.blocked FILTER html %] and
+    [%+ field_descs.dependson FILTER html %] fields work now.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Custom Fields:&lt;/strong&gt; You can now restrict the visibility
+    of custom fields and their values to a specific Component or
+    Classification.&lt;/li&gt;
+  &lt;li&gt;The &quot;keyword cache&quot; has been removed. When you edit keywords, you no
+    longer will have to &quot;rebuild the keyword cache&quot; after you are done.&lt;/li&gt;
+  &lt;li&gt;Running &lt;kbd&gt;./collectstats.pl --regenerate&lt;/kbd&gt; will now take
+    minutes or hours, instead of days.&lt;/li&gt;
+  &lt;li&gt;When using &lt;kbd&gt;email_in.pl&lt;/kbd&gt;, there are two new switches,
+    &lt;kbd&gt;--default&lt;/kbd&gt; and &lt;kbd&gt;--override&lt;/kbd&gt;, which allow you to
+    specify certain default values or override specified values for
+    &lt;kbd&gt;@field&lt;/kbd&gt; values sent in emails. (This also allows you to specify
+    defaults for everything so that people do not have to specify any field
+    values when filing [% terms.abug %] via email.)&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Installation:&lt;/strong&gt; If you are using a localized version of
+    [%+ terms.Bugzilla %] and your terminal does not understand Unicode,
+    &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; will now attempt to output its messages in your
+    terminal's character set.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Installation:&lt;/strong&gt; [% terms.Bugzilla %] no longer needs empty
+    &quot;placeholder&quot; CSS in the &lt;kbd&gt;skins/custom&lt;/kbd&gt; directory and other
+    directories. When you update, &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; will remove these.
+    This also significantly reduces the number of HTTP requests required to
+    load a page for the first time in [% terms.Bugzilla %].&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Installation:&lt;/strong&gt; For Windows users, [% terms.Bugzilla %]
+    now supports Strawberry Perl fully.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Installation:&lt;/strong&gt; Now, whenever &lt;kbd&gt;checksetup.pl&lt;/kbd&gt;
+    throws an error, it will be printed in the color red, to make it
+    obvious that something is wrong.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Installation:&lt;/strong&gt; Some actions of &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; were
+    silent, in the past. Now, &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; will print a message for
+    almost anything it does.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Installation:&lt;/strong&gt; The process of adding foreign keys
+    to a table is now much faster. This will particularly improve the speed
+    of upgrading from [% terms.Bugzilla %] 3.4 or earlier.&lt;/li&gt;
+  &lt;li&gt;If you are using &lt;kbd&gt;jobqueue.pl&lt;/kbd&gt; and email gets heavily delayed
+    for some reason, those emails will now have a Date header reflecting the
+    time they were &lt;em&gt;supposed&lt;/em&gt; to be sent, instead of when they actually
+    &lt;em&gt;were&lt;/em&gt; sent.&lt;/li&gt;
+  &lt;li&gt;&lt;kbd&gt;./jobqueue.pl install&lt;/kbd&gt; now works on SuSE Linux.&lt;/li&gt;
+  &lt;li&gt;[% terms.Bugzilla %] now runs much better in Apache's suexec mode
+    than it used to. As part of this, &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; sets
+    much stricter permissions on all the files in [% terms.Bugzilla %]
+    than it used to. In particular, any files that [% terms.Bugzilla %]
+    does not know about will not be readable by the webserver.&lt;/li&gt;
+  &lt;li&gt;The &lt;kbd&gt;sendmailnow&lt;/kbd&gt; parameter has been removed, as it was
+    not necessary for any modern version of Sendmail or other Mail Transfer
+    Agent.&lt;/li&gt;
+  &lt;li&gt;When editing a user via the Users administration panel, you can now
+    see if they are a Default CC on any component.&lt;/li&gt;
+  &lt;li&gt;For new installations of [% terms.Bugzilla %], all users will be
+    able to see and use the Whining system by default.&lt;/li&gt;
+  &lt;li&gt;When you are using SSL with [% terms.Bugzilla %], you can now
+    turn on the &lt;kbd&gt;strict_transport_security&lt;/kbd&gt; parameter to
+    send the
+    &lt;a href=&quot;https://developer.mozilla.org/en/Security/HTTP_Strict_Transport_Security&quot;&gt;Strict-Transport-Security&lt;/a&gt;
+    header with every HTTPS connection, for additional security.&lt;/li&gt;
+  &lt;li&gt;New code hooks (see their documentation in
+    &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/Hook.html&quot;&gt;Bugzilla::Hook&lt;/a&gt;):
+    bug_check_can_change_field, search_operator_field_override,
+    bugmail_relationships, object_columns, object_update_columns,
+    and object_validators. The colchange_columns hook has been removed,
+    as it is no longer necessary (buglist_columns will be used for data
+    about which columns can be on the [% terms.bug %] list).&lt;/li&gt;
+  &lt;li&gt;When [% terms.Bugzilla %] throws certain types of errors, it will
+    now include a &quot;traceback&quot; of where exactly the error occurred in the
+    code, to help administrators and developers debug problems.&lt;/li&gt;
+  &lt;li&gt;There is now a test, &lt;kbd&gt;xt/search.t&lt;/kbd&gt;, that assures that all
+    of the functionality of &lt;kbd&gt;Bugzilla::Search&lt;/kbd&gt; is working properly.
+    If you customize the search functionality of [% terms.Bugzilla %],
+    you may wish to run this test to assure that your changes are correct.
+    You can see more information about running this test by doing
+    &lt;kbd&gt;perldoc xt/search.t&lt;/kbd&gt; at the command line.&lt;/li&gt;
+  &lt;li&gt;[% terms.Bugzilla %] now sends the
+    &lt;a href=&quot;https://developer.mozilla.org/en/the_x-frame-options_response_header&quot;&gt;&lt;code&gt;X-Frame-Options: SAMEORIGIN&lt;/code&gt;&lt;/a&gt; header
+    with every page request in order to prevent &quot;clickjacking&quot; attacks. Note
+    that this prevents other domains from displaying [% terms.Bugzilla %]
+    in an HTML frame.&lt;/li&gt; 
</ins><span class="cx"> &lt;/ul&gt;
</span><span class="cx"> 
</span><del>-&lt;h4&gt;Enhancements For Administrators&lt;/h4&gt;
</del><ins>+&lt;h4 id=&quot;v40_feat_ws_changes&quot;&gt;WebService Changes&lt;/h4&gt;
</ins><span class="cx"> 
</span><span class="cx"> &lt;ul&gt;
</span><del>-  &lt;li&gt;Administrators can now delete attachments, making them disappear
-    entirely from [% terms.Bugzilla %].&lt;/li&gt;
-  &lt;li&gt;&lt;kbd&gt;sanitycheck.cgi&lt;/kbd&gt; can now only be accessed by users
-    in the &lt;kbd&gt;editcomponents&lt;/kbd&gt; group.&lt;/li&gt;
-  &lt;li&gt;The &amp;quot;Field Values&amp;quot; control panel can now only be accessed
-    by users in the &lt;kbd&gt;admin&lt;/kbd&gt; group. (Previously it was accessible
-    to anybody in the &lt;kbd&gt;editcomponents&lt;/kbd&gt; group.)&lt;/li&gt;
-  &lt;li&gt;There is a new parameter &lt;kbd&gt;announcehtml&lt;/kbd&gt;, that will allow
-    you to enter some HTML that will be displayed at the top of every
-    page, as an announcement.&lt;/li&gt;
-  &lt;li&gt;The &lt;kbd&gt;loginnetmask&lt;/kbd&gt; parameter now defaults to 0 for new
-    installations, meaning that as long as somebody has the right
-    login cookie, they can log in from any IP address. This makes
-    life a lot easier for dial-up users or other users whose IP
-    changes a lot. This could be done because the login cookie is now
-    very random, and thus secure.&lt;/li&gt;
-  &lt;li&gt;Classifications now have sortkeys, so they can be sorted in an
-    order that isn't alphabetical.&lt;/li&gt;
-  &lt;li&gt;Authentication now supports LDAP over SSL (LDAPS) or TLS (using
-    the STARTLS command) in addition to plain LDAP.&lt;/li&gt;
-  &lt;li&gt;LDAP users can have their LDAP username be their email address,
-    instead of having the LDAP &lt;kbd&gt;mail&lt;/kbd&gt; attribute be their
-    email address. You may wish to set the &lt;kbd&gt;emailsuffix&lt;/kbd&gt;
-    parameter if you do this.&lt;/li&gt;
-  &lt;li&gt;Administrators can now see what has changed in a user account,
-    when using the &amp;quot;Users&amp;quot; control panel.&lt;/li&gt;
-  &lt;li&gt;&lt;code&gt;REMIND&lt;/code&gt; and &lt;code&gt;LATER&lt;/code&gt; are no longer part
-    of the default list of resolutions. Upgrading installations will
-    not be affected--they will still have these resolutions.&lt;/li&gt;
-  &lt;li&gt;&lt;kbd&gt;editbugs&lt;/kbd&gt; is now the default for the &lt;kbd&gt;timetrackinggroup&lt;/kbd&gt;
-    parameter, meaning that time-tracking will be on by default in a new
-    installation.&lt;/li&gt;
</del><ins>+  &lt;li&gt;You can now call some JSON-RPC methods using HTTP GET, in addition to
+    using HTTP POST. See the 
+    &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/WebService/Server/JSONRPC.html#Connecting_via_GET&quot;&gt;JSON-RPC
+    documentation&lt;/a&gt; for details.&lt;/li&gt;
+  &lt;li&gt;You can now update existing [% terms.bugs %] using the
+    &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/WebService/Bug.html#update&quot;&gt;B[% %]ug.update&lt;/a&gt;
+    function.&lt;/li&gt;
+  &lt;li&gt;You can now add attachments to [% terms.bugs %] using the
+    &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/WebService/Bug.html#add_attachment&quot;&gt;B[% %]ug.add_attachment&lt;/a&gt;
+    function.&lt;/li&gt;
+  &lt;li&gt;The &lt;kbd&gt;B[% %]ug.get&lt;/kbd&gt; function now returns all of [% terms.abug %]'s
+    information other than comments and attachments.&lt;/li&gt;
+  &lt;li&gt;&lt;kbd&gt;B[% %]ug.get&lt;/kbd&gt; no longer returns the &lt;kbd&gt;internals&lt;/kbd&gt; hash.&lt;/li&gt;
+  &lt;li&gt;The &lt;kbd&gt;B[% %]ug.attachments&lt;/kbd&gt; function now also returns attachment
+    data.&lt;/li&gt;
+  &lt;li&gt;The following functions now support the &lt;kbd&gt;include_fields&lt;/kbd&gt;
+    and &lt;kbd&gt;exclude_fields&lt;/kbd&gt; arguments: &lt;kbd&gt;B[% %]ug.get&lt;/kbd&gt;,
+    &lt;kbd&gt;B[% %]ug.search&lt;/kbd&gt;, and &lt;kbd&gt;B[% %]ug.attachments&lt;/kbd&gt;. Also,
+    server-side performance of the WebService is actually increased when
+    using these arguments, now, as [% terms.Bugzilla %] will no longer
+    get data from the database for fields you haven't asked for.&lt;/li&gt;
+  &lt;li&gt;You can now mark the initial description of [% terms.abug %] as
+    private when filing [% terms.abug %] via the &lt;kbd&gt;B[% %]ug.create&lt;/kbd&gt;
+    function.&lt;/li&gt;
+  &lt;li&gt;You can now specify groups to put [% terms.abug %] in, in the
+    &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/WebService/Bug.html#create&quot;&gt;B[% %]ug.create&lt;/a&gt;
+    function. (This also means that you can specify groups when filing
+    [%+ terms.abug %] via email_in.pl.)&lt;/li&gt;
+  &lt;li&gt;The &lt;kbd&gt;User.get&lt;/kbd&gt; function now accepts &lt;kbd&gt;groups&lt;/kbd&gt;
+    and &lt;kbd&gt;group_ids&lt;/kbd&gt; arguments, to limit the returned values to
+    only users in the specified groups.&lt;/li&gt;
+  &lt;li&gt;There is a new, undocumented B[% %]ug.possible_duplicates
+    function that helps implement the automatic duplicate detection
+    system. Because this function is not documented, its API may change
+    between releases of [% terms.Bugzilla %].&lt;/li&gt;
+  &lt;li&gt;You can no longer search using the &lt;kbd&gt;votes&lt;/kbd&gt; argument in
+    &lt;kbd&gt;B[% %]ug.search&lt;/kbd&gt;.&lt;/li&gt;
+  &lt;li&gt;&lt;kbd&gt;B[% %]ug.attachments&lt;/kbd&gt; now returns the attachment's description
+    using the name &quot;summary&quot; instead of the name &quot;description&quot;, to be
+    consistent with the fact that [% terms.bug %] summaries are called
+    &quot;summary&quot;. The value is still &lt;em&gt;also&lt;/em&gt; returned as &quot;description&quot;,
+    for backwards compatibility, but this backwards compatibility will go
+    away in [% terms.Bugzilla %] 5.0.&lt;/li&gt;
+  &lt;li&gt;In the return values of various &lt;kbd&gt;B[% %]ug&lt;/kbd&gt; functions, the author
+    of comments, [% terms.bugs %], and attachments is now called &quot;creator&quot;,
+    instead of sometimes being called &quot;reporter&quot;, &quot;author&quot;, or &quot;attacher&quot;.
+    The old names are retained for backwards-compatibility, and will stay
+    around until [% terms.Bugzilla %] 5.0.&lt;/li&gt;
</ins><span class="cx"> &lt;/ul&gt;
</span><span class="cx"> 
</span><del>-&lt;h2&gt;&lt;a name=&quot;v30_issues&quot;&gt;&lt;/a&gt;Outstanding Issues&lt;/h2&gt;
</del><ins>+&lt;h2 id=&quot;v40_issues&quot;&gt;Outstanding Issues&lt;/h2&gt;
</ins><span class="cx"> 
</span><span class="cx"> &lt;ul&gt;
</span><del>-  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=69621&quot;&gt;
-    [%- terms.Bug %] 69621&lt;/a&gt;: If you rename or remove a keyword that is
-    in use on [% terms.bugs %], you will need to rebuild the &quot;keyword cache&quot;
-    by running &lt;a href=&quot;sanitycheck.cgi&quot;&gt;sanitycheck.cgi&lt;/a&gt; and choosing 
-    the option to rebuild the cache when it asks. Otherwise keywords may 
-    not show up properly in search results.&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=99215&quot;&gt;
-    [%- terms.Bug %] 99215&lt;/a&gt;: Flags are not protected by &quot;mid-air 
-    collision&quot; detection. Nor are any attachment changes.&lt;/li&gt;
</del><ins>+  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=423439&quot;&gt;
+    [%- terms.Bug %] 423439&lt;/a&gt;: Tabs in comments will be converted
+    to four spaces, due to a b&lt;!-- --&gt;ug in Perl as of Perl 5.8.8.&lt;/li&gt;
</ins><span class="cx">   &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=89822&quot;&gt;
</span><span class="cx">     [%- terms.Bug %] 89822&lt;/a&gt;: When changing multiple [% terms.bugs %] at 
</span><span class="cx">     the same time, there is no &quot;mid-air collision&quot; protection.&lt;/li&gt;
</span><span class="lines">@@ -1366,268 +1242,136 @@
</span><span class="cx">     There is currently no way to change this restriction, and the 
</span><span class="cx">     groupings will not be updated if the group configuration
</span><span class="cx">     for the Product changes.&lt;/li&gt;
</span><del>-  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=370370&quot;&gt;
-    [%- terms.Bug %] 370370&lt;/a&gt;: mod_perl support is currently not
-    working on Windows machines.&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=361149&quot;&gt;
-    [%- terms.Bug %] 361149&lt;/a&gt;: If you are using Perl 5.8.0, you may
-    get a lot of warnings in your Apache error_log about &quot;deprecated
-    pseudo-hashes.&quot; These are harmless--they are a b[%# fool test %]ug in 
-    Perl 5.8.0. Perl 5.8.1 and later do not have this problem.&lt;/li&gt;
-  &lt;li&gt;[% terms.Bugzilla %] 3.0rc1 allowed custom field column names in 
-    the database to be mixed-case. [% terms.Bugzilla %] 3.0 only allows
-    lowercase column names. It will fix any column names that you have
-    made mixed-case, but if you have custom fields that previously were
-    mixed-case in any Saved Search, you will have to re-create that Saved
-    Search yourself.&lt;/li&gt;
</del><span class="cx"> &lt;/ul&gt;
</span><span class="cx"> 
</span><del>-&lt;h2&gt;&lt;a name=&quot;v30_security&quot;&gt;&lt;/a&gt;Security Updates in This Release&lt;/h2&gt;
</del><ins>+&lt;h2 id=&quot;v40_upgrading&quot;&gt;Notes On Upgrading From a Previous Version&lt;/h2&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;3.0.6&lt;/h3&gt;
</del><ins>+&lt;h3&gt;IMPORTANT: Apache Configuration Change&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;[% terms.Bugzilla %] contains a minor security fix. For details, see the
-  &lt;a href=&quot;http://www.bugzilla.org/security/2.20.6/&quot;&gt;Security Advisory&lt;/a&gt;.&lt;/p&gt;
</del><ins>+&lt;h4&gt;mod_cgi&lt;/h4&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;3.0.5&lt;/h3&gt;
</del><ins>+&lt;p&gt;If you run [% terms.Bugzilla %] under mod_cgi (this is the most common
+  configuration, involving a &amp;lt;Directory&amp;gt; block in your Apache config
+  file), you will need to update the configuration of Apache for 
+  [%+ terms.Bugzilla %]. In particular, this line in the [% terms.Bugzilla %]
+  &lt;kbd&gt;&amp;lt;Directory&amp;gt;&lt;/kbd&gt; block:&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;[% terms.Bugzilla %] contains one security fix for 
-  &lt;a href=&quot;[% docs_urlbase FILTER html %]api/importxml.html&quot;&gt;importxml.pl&lt;/a&gt;.
-  For details, see the 
-  &lt;a href=&quot;http://www.bugzilla.org/security/2.22.4/&quot;&gt;Security Advisory&lt;/a&gt;.&lt;/p&gt;
</del><ins>+&lt;blockquote&gt;&lt;code&gt;AllowOverride Limit&lt;/code&gt;&lt;/blockquote&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;3.0.4&lt;/h3&gt;
</del><ins>+&lt;p&gt;needs to become:&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;[% terms.Bugzilla %] 3.0.4 contains three security fixes.
-  For details, see the
-  &lt;a href=&quot;http://www.bugzilla.org/security/2.20.5/&quot;&gt;Security Advisory&lt;/a&gt;.&lt;/p&gt;
-&lt;/p&gt;
</del><ins>+&lt;blockquote&gt;&lt;code&gt;AllowOverride Limit FileInfo Indexes&lt;/code&gt;&lt;/blockquote&gt;

+&lt;p&gt;For full details on how to configure Apache for [% terms.Bugzilla %],
+  see the
+  &lt;a href=&quot;[% docs_urlbase FILTER html %]configuration.html#http-apache&quot;&gt;Configuration&lt;/a&gt;
+  section of the [% terms.Bugzilla %] Guide.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;3.0.3&lt;/h3&gt;
</del><ins>+&lt;h4&gt;mod_perl&lt;/h4&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;No security fixes in this release.&lt;/p&gt;
</del><ins>+&lt;p&gt;If your [% terms.Bugzilla %] runs under mod_perl, the required Apache
+  configuration is now simpler. The line that used to look like:&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;3.0.2&lt;/h3&gt;
</del><ins>+&lt;blockquote&gt;&lt;code&gt;PerlSwitches -w -T -I/var/www/html/bugzilla 
+    -I/var/www/html/bugzilla/lib&lt;/code&gt;&lt;/blockquote&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;[% terms.Bugzilla %] 3.0.1 had an important security fix that is
-  critical for public installations with &quot;requirelogin&quot; turned on.
-  For details, see the
-  &lt;a href=&quot;http://www.bugzilla.org/security/3.0.1/&quot;&gt;Security Advisory&lt;/a&gt;&lt;/p&gt;
</del><ins>+&lt;p&gt;Now should be only:&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;3.0.1&lt;/h3&gt;
</del><ins>+&lt;blockquote&gt;&lt;code&gt;PerlSwitches -w -T&lt;/code&gt;&lt;/blockquote&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;[% terms.Bugzilla %] 3.0 had three security issues that have been
-  fixed in this release: one minor information leak, one hole only
-  exploitable by an admin or using &lt;code&gt;email_in.pl&lt;/code&gt;, and one in an
-  uncommonly-used template. For details, see the 
-  &lt;a href=&quot;http://www.bugzilla.org/security/2.20.4/&quot;&gt;Security Advisory&lt;/a&gt;.&lt;/p&gt;
</del><ins>+&lt;p&gt;The &lt;code&gt;PerlConfigRequire&lt;/code&gt; line should stay the same, however.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;h2&gt;&lt;a name=&quot;v30_upgrading&quot;&gt;&lt;/a&gt;How to Upgrade From An Older Version&lt;/h2&gt;
</del><ins>+&lt;h3&gt;New .htaccess file&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v30_upgrading_notes&quot;&gt;&lt;/a&gt;Notes For Upgraders&lt;/h3&gt;
</del><ins>+&lt;p&gt;In previous versions of [% terms.Bugzilla %], there was a file
+  in [% terms.Bugzilla %]'s root directory called &quot;.htaccess&quot; that was
+  generated by &lt;kbd&gt;checksetup.pl&lt;/kbd&gt;. This file is now shipped with
+  [%+ terms.Bugzilla %] instead of being generated during installation.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;ul&gt;
-  &lt;li&gt;If you upgrade by CVS, there are several .cvsignore files
-    that are now in CVS instead of being locally created by 
-    &lt;kbd&gt;checksetup.pl&lt;/kbd&gt;. This means that you will have to
-    delete those files when CVS tells you there's a conflict, and
-    then run &lt;kbd&gt;cvs update&lt;/kbd&gt; again.&lt;/li&gt;
-  &lt;li&gt;In this version of [% terms.Bugzilla %], the Summary field
-    is now limited to 255 characters. When you upgrade, any Summary
-    longer than that will be truncated, and the old summary will be
-    preserved in a comment.&lt;/li&gt;
-  &lt;li&gt;If you have the &lt;kbd&gt;utf8&lt;/kbd&gt; parameter turned on, at some
-    point you will have to convert your database. &lt;kbd&gt;checksetup.pl&lt;/kbd&gt;
-    will tell you when this is, and it will give you certain instructions
-    at that time, that you have to follow before you can complete
-    the upgrade. Don't do the conversion yourself manually--follow
-    the instructions of checksetup.pl.&lt;/li&gt;
-  &lt;li&gt;If you ever ran 2.23.3, 2.23.4, or 3.0rc1, you will have to run
-    &lt;kbd&gt;./collectstats.pl --regenerate&lt;/kbd&gt; at the command line, because
-    the data for your Old Charts is corrupted. This can take several days,
-    so you may only want to run it if you use Old Charts.&lt;/li&gt;
-  &lt;li&gt;You should also read the Outstanding Issues sections of
-    &lt;a href=&quot;#v30_previous&quot;&gt;older release notes&lt;/a&gt; if you are upgrading
-    from a version lower than 2.22.&lt;/li&gt;
-&lt;/ul&gt;
</del><ins>+&lt;p&gt;If you update via CVS or bzr, you will get a message that your existing
+  .htaccess file conflicts with the new one. You must
+  &lt;strong&gt;remove your existing .htaccess file&lt;/strong&gt; and use the new one
+  instead. Continuing to use your old .htaccess file will cause certain new
+  features of [% terms.Bugzilla %] to not work properly, and may also lead
+  to security issues for your system in the future.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;Steps For Upgrading&lt;/h3&gt;
</del><ins>+&lt;h2 id=&quot;v40_code_changes&quot;&gt;Code Changes Which May Affect Customizations and
+  Extensions&lt;/h2&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;Once you have read the notes above, see the 
-  &lt;a href=&quot;[% docs_urlbase FILTER html %]upgrade.html&quot;&gt;Upgrading 
-  documentation&lt;/a&gt; for instructions on how to upgrade.&lt;/p&gt;
-
-&lt;h2&gt;&lt;a name=&quot;v30_code_changes&quot;&gt;&lt;/a&gt;Code Changes Which May Affect 
-  Customizations&lt;/h2&gt;
-
</del><span class="cx"> &lt;ul&gt;
</span><del>-  &lt;li&gt;&lt;a href=&quot;#v30_code_loc&quot;&gt;&lt;strong&gt;Packagers:&lt;/strong&gt; Location
-    Variables Have Moved&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_code_hooks&quot;&gt;Hooks!&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_code_api&quot;&gt;API Documentation&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_code_globals&quot;&gt;Elimination of globals.pl&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_code_scope&quot;&gt;Cleaned Up Variable Scoping Issues&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_code_sql&quot;&gt;No More SendSQL&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_code_auth&quot;&gt;Auth Re-write&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_code_obj&quot;&gt;Bugzilla::Object&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_code_req&quot;&gt;Bugzilla-&amp;gt;request_cache&lt;/a&gt;&lt;/li&gt;
-  &lt;li&gt;&lt;a href=&quot;#v30_code_other&quot;&gt;Other Changes&lt;/a&gt;&lt;/li&gt;
</del><ins>+  &lt;li&gt;In Extensions, if you want to serve files to the user via the web,
+    they must now be in a &lt;kbd&gt;web/&lt;/kbd&gt; subdirectory of your Extension.
+    (For example, &lt;kbd&gt;extensions/Foo/web/&lt;/kbd&gt;). &lt;kbd&gt;checksetup.pl&lt;/kbd&gt;
+    sets permissions on extensions much more strictly now, and files in
+    other locations (such as your base &lt;kbd&gt;extensions/Foo/&lt;/kbd&gt; directory)
+    will no longer be available to [% terms.Bugzilla %] users via the web
+    under certain configurations.&lt;/li&gt;
+  &lt;li&gt;Previous versions of [% terms.Bugzilla %] used to allow putting a
+    single file into the &quot;skins&quot; directory and having that be an entire
+    skin. That is no longer allowed, and on upgrade, &lt;kbd&gt;checksetup.pl&lt;/kbd&gt;
+    will convert any such skins into a directory with a single
+    &lt;kbd&gt;global.css&lt;/kbd&gt; file in them.&lt;/li&gt;
+  &lt;li&gt;When updating [% terms.bugs %], you should now use
+    &lt;code&gt;$bug-&amp;gt;set_all&lt;/code&gt; instead of using the individual
+    &lt;kbd&gt;set_&lt;/kbd&gt; methods. In particular, &lt;kbd&gt;set_all&lt;/kbd&gt; is now the
+    &lt;em&gt;only&lt;/em&gt; way to set the product of [% terms.abug %]. See
+    &lt;kbd&gt;process_bug.cgi&lt;/kbd&gt; for an example of how &lt;kbd&gt;set_all&lt;/kbd&gt;
+    should be used.&lt;/li&gt;
+  &lt;li&gt;You should not insert &amp;lt;script&amp;gt; tags and &amp;lt;link&amp;gt; CSS tags
+    into HTML anymore, in Extensions or in your customizations. Instead,
+    you should push new values into the &lt;kbd&gt;style_urls&lt;/kbd&gt; or
+    &lt;kbd&gt;javascript_urls&lt;/kbd&gt; parameters. If you have to insert manual
+    tags for some reason, be sure to call &quot;FILTER mtime&quot; on the URL. (Search
+    for other uses of &quot;FILTER mtime&quot; in the templates to see how it is
+    used.)&lt;/li&gt;
+  &lt;li&gt;When calling &lt;kbd&gt;Bugzilla::BugMail::Send&lt;/kbd&gt;, the &quot;changer&quot;
+    argument must now be a &lt;kbd&gt;Bugzilla::User&lt;/kbd&gt; object, not just
+    a login name. The &quot;owner&quot; and &quot;qacontact&quot; arguments are still
+    just login names.&lt;/li&gt;
+  &lt;li&gt;When creating a new subclass of Bugzilla::Object, you should no
+    longer use &lt;kbd&gt;UPDATE_VALIDATORS&lt;/kbd&gt;. Also, in most cases you will
+    no longer need to override &lt;kbd&gt;run_create_validators&lt;/kbd&gt;. Instead,
+    there is a new constant called
+    &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/Object.html#VALIDATOR_DEPENDENCIES&quot;&gt;VALIDATOR_DEPENDENCIES&lt;/a&gt;,
+    that specifies that certain fields have to be validated before other fields.
+    Then, all validators receive each already-validated value in a hash
+    as their fourth argument, so each validator can know the other values
+    that were passed in, while an object is being created. For an example of
+    how to use &lt;kbd&gt;VALIDATOR_DEPENDENCIES&lt;/kbd&gt;, see
+    &lt;kbd&gt;Bugzilla/Field.pm&lt;/kbd&gt;.&lt;/li&gt;
+  &lt;li&gt;In previous versions of [% terms.Bugzilla %], you had to call
+    &lt;code&gt;Bugzilla-&amp;gt;template_inner(&quot;&quot;)&lt;/code&gt; after any time
+    that you called &lt;kbd&gt;template_inner&lt;/kbd&gt; for a specific language.
+    It is no longer necessary to do this second &lt;kbd&gt;template_inner&lt;/kbd&gt;
+    call.&lt;/li&gt;
+  &lt;li&gt;&lt;kbd&gt;post_bug.cgi&lt;/kbd&gt; and &lt;kbd&gt;Bugzilla::Bug-&amp;gt;create&lt;/kbd&gt; now take
+    the &lt;em&gt;names&lt;/em&gt; of groups instead of group ids.&lt;/li&gt;
+  &lt;li&gt;Bugzilla::Bugmail now uses Bugzilla::Bug objects internally instead of
+    a lot of direct SQL.&lt;/li&gt;
+  &lt;li&gt;For sending changes about [% terms.bugs %], there is now a method
+    called &lt;kbd&gt;send_changes&lt;/kbd&gt; that you can call on Bugzilla::Bug
+    objects. For an example of its use, see &lt;kbd&gt;process_bug.cgi&lt;/kbd&gt;.&lt;/li&gt;
+  &lt;li&gt;The &lt;kbd&gt;Bugzilla::Search&lt;/kbd&gt; class has been refactored, and should
+    now be easier to customize.&lt;/li&gt;
+  &lt;li&gt;The &lt;kbd&gt;Bugzilla::Util::lsearch&lt;/kbd&gt; function is gone. Use
+    &lt;kbd&gt;firstidx&lt;/kbd&gt; from &lt;kbd&gt;List::MoreUtils&lt;/kbd&gt;, instead.&lt;/li&gt;
+  &lt;li&gt;[% terms.Bugzilla %] now includes YUI 2.8.2.&lt;/li&gt;
+  &lt;li&gt;&lt;kbd&gt;long_list.cgi&lt;/kbd&gt;, &lt;kbd&gt;showattachment.cgi&lt;/kbd&gt; and
+    &lt;kbd&gt;xml.cgi&lt;/kbd&gt; are deprecated scripts which are no longer actively
+    used since [% terms.Bugzilla %] 2.19. These scripts will be removed in
+    [%+ terms.Bugzilla %] 4.2.&lt;/li&gt;
</ins><span class="cx"> &lt;/ul&gt;
</span><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;v30_code_loc&quot;&gt;&lt;/a&gt;&lt;strong&gt;Packagers:&lt;/strong&gt; Location
-    Variables Have Moved&lt;/h3&gt;
</del><ins>+&lt;h2 id=&quot;v40_previous&quot;&gt;Release Notes For Previous Versions&lt;/h2&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;In previous versions of [% terms.Bugzilla %], &lt;kbd&gt;Bugzilla::Config&lt;/kbd&gt;
-  held all the paths for different things, such as the path to localconfig
-  and the path to the &lt;kbd&gt;data/&lt;/kbd&gt; directory.&lt;/p&gt;
</del><ins>+&lt;p&gt;&lt;a href=&quot;page.cgi?id=release-notes3.html&quot;&gt;Release Notes for
+  [%+ terms.Bugzilla %] 3.x and Earlier&lt;/a&gt;&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;p&gt;Now, all of this data is stored in a subroutine,
-  &lt;kbd&gt;Bugzilla::Constants::bz_locations&lt;/kbd&gt;.&lt;/p&gt;
-
-&lt;p&gt;Also, note that for mod_perl, &lt;kbd&gt;bz_locations&lt;/kbd&gt; must return
-  &lt;em&gt;absolute&lt;/em&gt; (not relative) paths. There is already code in that
-  subroutine to help you with this.&lt;/p&gt;
-
-&lt;h3&gt;&lt;a name=&quot;v30_code_hooks&quot;&gt;&lt;/a&gt;Hooks!&lt;/h3&gt;
-
-&lt;p&gt;[% terms.Bugzilla %] now supports a code hook mechanism. See the 
-  documentation for 
-  &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/Hook.html&quot;&gt;Bugzilla::Hook&lt;/a&gt;
-  for more details.&lt;/p&gt;
-
-&lt;p&gt;This gives [% terms.Bugzilla %] very advanced plugin support. You can
-  hook templates, hook code, add new parameters, and use the XML-RPC
-  interface. So we'd like to see some [% terms.Bugzilla %] plugins
-  written! Let us know on the &lt;a href=&quot;http://bugzilla.org/cgi-bin/mj_wwwusr?func=lists-long-full&amp;amp;extra=developers&quot;&gt;developers&amp;#64;bugzilla.org&lt;/a&gt;
-  mailing list if you write a plugin.&lt;/p&gt;
-
-&lt;p&gt;If you need more hooks, please 
-  &lt;a href=&quot;http://www.bugzilla.org/developers/reporting_bugs.html&quot;&gt;File a
-  bug&lt;/a&gt;!&lt;/p&gt;
-
-&lt;h3&gt;&lt;a name=&quot;v30_code_api&quot;&gt;&lt;/a&gt;API Documentation&lt;/h3&gt;
-
-&lt;p&gt;[% terms.Bugzilla %] now ships with all of its perldoc built
-  as HTML. Go ahead and read the
-  &lt;a href=&quot;[% docs_urlbase FILTER html %]api/&quot;&gt;API Documentation&lt;/a&gt;
-  for all of the [% terms.Bugzilla %] modules now! Even scripts like
-  &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; have HTML documentation.&lt;/p&gt;
-
-&lt;h3&gt;&lt;a name=&quot;v30_code_globals&quot;&gt;&lt;/a&gt;Elimination of globals.pl&lt;/h3&gt;
-
-&lt;p&gt;The old file &lt;kbd&gt;globals.pl&lt;/kbd&gt; has been eliminated.
-  Its code is now in various modules. Each function went to the module
-  that was appropriate for it.&lt;/p&gt;
-
-&lt;p&gt;Usually we filed [% terms.abug %] in 
-  &lt;a href=&quot;https://bugzilla.mozilla.org&quot;&gt;bugzilla.mozilla.org&lt;/a&gt; for
-  each function we moved. You can search there for the old name of
-  the function, and that should get you the information about what
-  it's called now and where it lives.&lt;/p&gt;
-
-&lt;h3&gt;&lt;a name=&quot;v30_code_scope&quot;&gt;&lt;/a&gt;Cleaned Up Variable Scoping Issues&lt;/h3&gt;
-
-&lt;p&gt;In normal perl, you can have code like this:&lt;/p&gt;
-&lt;pre&gt;my $var = 0;
-sub y { $var++ }&lt;/pre&gt;
-
-&lt;p&gt;However, under mod_perl that doesn't work. So variables are no
-  longer &amp;quot;shared&amp;quot; with subroutines--instead all variables
-  that a subroutine needs must be declared inside the subroutine itself.&lt;/p&gt;
-
-&lt;h3&gt;&lt;a name=&quot;v30_code_sql&quot;&gt;&lt;/a&gt;No More SendSQL&lt;/h3&gt;
-
-&lt;p&gt;The old &lt;kbd&gt;SendSQL&lt;/kbd&gt; function and all of its companions are
-  &lt;strong&gt;gone&lt;/strong&gt;. Instead, we now use DBI for all database
-  interaction.&lt;/p&gt;
-
-&lt;p&gt;For more information about how to use 
-  &lt;a href=&quot;http://search.cpan.org/perldoc?DBI&quot;&gt;DBI&lt;/a&gt; with 
-  [% terms.Bugzilla %], see the 
-  &lt;a href=&quot;http://www.bugzilla.org/docs/developer.html#sql-sendreceive&quot;&gt;Developer's
-  Guide Section About DBI&lt;/a&gt;&lt;/p&gt;
-
-&lt;h3&gt;&lt;a name=&quot;v30_code_auth&quot;&gt;&lt;/a&gt;Auth Re-write&lt;/h3&gt;
-
-&lt;p&gt;The &lt;kbd&gt;Bugzilla::Auth&lt;/kbd&gt; family of modules have been completely
-  re-written. For details on how the new structure of authentication,
-  read the 
-  &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/Auth.html&quot;&gt;Bugzilla::Auth
-  API docs&lt;/a&gt;.&lt;/p&gt;
-
-&lt;p&gt;It should be very easy to write new authentication plugins, now.&lt;/p&gt;
-
-&lt;h3&gt;&lt;a name=&quot;v30_code_obj&quot;&gt;&lt;/a&gt;Bugzilla::Object&lt;/h3&gt;
-
-&lt;p&gt;There is a new base class for most of our objects, 
-  &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/Object.html&quot;&gt;Bugzilla::Object&lt;/a&gt;.
-  It makes it really easy to create new objects based on things that are 
-  in the database.&lt;/p&gt;
-
-&lt;h3&gt;&lt;a name=&quot;v30_code_req&quot;&gt;&lt;/a&gt;Bugzilla-&amp;gt;request-cache&lt;/h3&gt;
-
-&lt;p&gt;&lt;kbd&gt;Bugzilla.pm&lt;/kbd&gt; used to cache things like the database
-  connection in package-global variables (like &lt;kbd&gt;$_dbh&lt;/kbd&gt;).
-  That doesn't work in mod_perl, so instead now there's a hash
-  that can be accessed through &lt;code&gt;Bugzilla-&amp;gt;request_cache&lt;/code&gt;
-  to store things for the rest of the current page request.&lt;/p&gt;
-
-&lt;p&gt;You shouldn't access &lt;code&gt;Bugzilla-&amp;gt;request_cache&lt;/code&gt; directly,
-  but you should use it inside of &lt;kbd&gt;Bugzilla.pm&lt;/kbd&gt; if you modify
-  that. The only time you should be accessing it directly is if you need
-  to reset one of the caches. Hash keys are always named after the function
-  that they cache, so to reset the template object, you'd do:
-  &lt;code&gt;delete Bugzilla-&amp;gt;request_cache-&amp;gt;{template};&lt;/code&gt;.&lt;/p&gt;
-
-&lt;h3&gt;&lt;a name=&quot;v30_code_other&quot;&gt;&lt;/a&gt;Other Changes&lt;/h3&gt;
-
-&lt;ul&gt;
-  &lt;li&gt;&lt;code&gt;checksetup.pl&lt;/code&gt; has been completely re-written, and most
-    of its code moved into modules in the &lt;kbd&gt;Bugzilla::Install&lt;/kbd&gt;
-    namespace. See the
-    &lt;a href=&quot;[% docs_urlbase FILTER html %]api/checksetup.html&quot;&gt;checksetup
-    documentation&lt;/a&gt; and &lt;a href=&quot;https://bugzilla.mozilla.org/showdependencytree.cgi?id=277502&amp;amp;hide_resolved=0&quot;&gt;[% terms.Bugzilla %]
-   [%+ terms.bug %] 277502&lt;/a&gt; for details.&lt;/li&gt;
-  &lt;li&gt;Instead of &lt;kbd&gt;UserInGroup()&lt;/kbd&gt;, all of [% terms.Bugzilla %] now 
-    uses &lt;kbd&gt;Bugzilla-&amp;gt;user-&amp;gt;in_group&lt;/kbd&gt;&lt;/li&gt;
-  &lt;li&gt;mod_perl doesn't like dependency loops in modules, so we now have
-    a test for that detects dependency loops in modules when you run
-   &lt;kbd&gt;runtests.pl&lt;/kbd&gt;.&lt;/li&gt;
-  &lt;li&gt;&lt;kbd&gt;globals.pl&lt;/kbd&gt; used to modify the environment variables,
-    like &lt;kbd&gt;PATH&lt;/kbd&gt;. That now happens in &lt;kbd&gt;Bugzilla.pm&lt;/kbd&gt;.&lt;/li&gt;
-  &lt;li&gt;Templates can now link to the documentation more easily.
-    See the &lt;kbd&gt;global/code-error.html.tmpl&lt;/kbd&gt; and
-    &lt;kbd&gt;global/user-error.html.tmpl&lt;/kbd&gt; templates for examples.
-    (Search for &amp;quot;docslinks.&amp;quot;)&lt;/li&gt;
-  &lt;li&gt;Parameters are accessed through &lt;kbd&gt;Bugzilla-&amp;gt;params&lt;/kbd&gt;
-    instead of using the &lt;kbd&gt;Param()&lt;/kbd&gt; function, now.&lt;/li&gt;
-  &lt;li&gt;The variables from the &lt;kbd&gt;localconfig&lt;/kbd&gt; file are accessed
-    through the &lt;code&gt;Bugzilla-&amp;gt;localconfig&lt;/code&gt; hash instead of through
-    &lt;kbd&gt;Bugzilla::Config&lt;/kbd&gt;.&lt;/li&gt;
-  &lt;li&gt;&lt;kbd&gt;Bugzilla::BugMail::MessageToMTA()&lt;/kbd&gt; has moved into its
-    own module, along with other mail-handling code, called
-    &lt;kbd&gt;Bugzilla::Mailer&lt;/kbd&gt;&lt;/li&gt;
-  &lt;li&gt;The &lt;kbd&gt;CheckCanChangeField()&lt;/kbd&gt; subroutine in 
-    &lt;kbd&gt;process_bug.cgi&lt;/kbd&gt; has been moved to &lt;kbd&gt;Bugzilla::Bug&lt;/kbd&gt;,
-    and is now a method of [% terms.abug %] object.&lt;/li&gt;
-  &lt;li&gt;The code that used to be in the &lt;kbd&gt;global/banner.html.tmpl&lt;/kbd&gt;
-    template is now in &lt;kbd&gt;global/header.html.tmpl&lt;/kbd&gt;. The banner
-    still exists, but the file is empty.&lt;/li&gt;
-&lt;/ul&gt;
-
-&lt;h2&gt;&lt;a name=&quot;v30_previous&quot;&gt;&lt;/a&gt;Release Notes For Previous Versions&lt;/h2&gt;
-
-&lt;p&gt;Release notes for versions of [% terms.Bugzilla %] for versions
-  prior to 3.0 are only available in text format: 
-  &lt;a href=&quot;[% docs_urlbase FILTER remove('html/$') FILTER html %]rel_notes.txt&quot;&gt;Release Notes for [% terms.Bugzilla %] 2.22
-  and Earlier&lt;/a&gt;.&lt;/p&gt;
-
</del><span class="cx"> [% INCLUDE global/footer.html.tmpl %]
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK db_req %]
</span><span class="cx">   [% SET m = DB_MODULE.$db %]
</span><del>-  &lt;h3&gt;&lt;a name=&quot;v32_req_[% db FILTER html %]&quot;&gt;&lt;/a&gt;For [% m.name FILTER html %] 
-    Users&lt;/h3&gt;
</del><ins>+  &lt;h3 id=&quot;v42_req_[% db FILTER html %]&quot;&gt;For [% m.name FILTER html %] Users&lt;/h3&gt;
</ins><span class="cx"> 
</span><span class="cx">   &lt;ul&gt;
</span><span class="cx">     &lt;li&gt;[% m.name FILTER html %]
</span><span class="lines">@@ -1652,10 +1396,10 @@
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     [% FOREACH req = reqs %]
</span><span class="cx">       &lt;tr&gt;
</span><del>-        &lt;td [% 'class=&quot;req_new&quot;' IF new.contains(req.package) %]&gt;
</del><ins>+        &lt;td [% ' class=&quot;req_new&quot;' IF new.contains(req.package) %]&gt;
</ins><span class="cx">           [%- req.module FILTER html %]&lt;/td&gt; 
</span><del>-        &lt;td [% 'class=&quot;req_new&quot;' IF updated.contains(req.package) 
-                                    OR new.contains(req.package) %]&gt;
</del><ins>+        &lt;td [% ' class=&quot;req_new&quot;' IF updated.contains(req.package) 
+                                     OR new.contains(req.package) %]&gt;
</ins><span class="cx">           [%- IF req.version == 0 %]
</span><span class="cx">             (Any)
</span><span class="cx">           [% ELSE %]
</span><span class="lines">@@ -1663,7 +1407,7 @@
</span><span class="cx">           [% END %]
</span><span class="cx">         &lt;/td&gt;
</span><span class="cx">         [% IF include_feature %] 
</span><del>-          &lt;td&gt;[% req.feature FILTER html %]&lt;/td&gt;
</del><ins>+          &lt;td&gt;[% req.feature.join(', ') FILTER html %]&lt;/td&gt;
</ins><span class="cx">         [% END %]
</span><span class="cx">       &lt;/tr&gt;
</span><span class="cx">     [% END %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultpagesreleasenotes3htmltmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/pages/release-notes3.html.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/pages/release-notes3.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/pages/release-notes3.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,3483 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Everything Solved.
+  # Portions created by Everything Solved are Copyright (C) 2006
+  # Everything Solved. All Rights Reserved.
+  #
+  # Contributor(s): Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[% PROCESS global/variables.none.tmpl %]
+[% SET title = &quot;$terms.Bugzilla 3.6 Release Notes&quot; %]
+[% INCLUDE global/header.html.tmpl 
+  title = title
+  style_urls = ['skins/standard/page.css'] 
+%]
+
+&lt;h3&gt;Release Notes For Newer Versions&lt;/h3&gt;
+
+&lt;p&gt;Release notes for versions of [% terms.Bugzilla %] of the 4.x series are
+  available &lt;a href=&quot;page.cgi?id=release-notes.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
+
+&lt;h1&gt;[% title FILTER html %]&lt;/h1&gt;
+
+&lt;ul class=&quot;bz_toc&quot;&gt;
+  &lt;li&gt;&lt;a href=&quot;#v36_introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v36_point&quot;&gt;Updates in this 3.6.x Release&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v36_req&quot;&gt;Minimum Requirements&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v36_feat&quot;&gt;New Features and Improvements&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v36_issues&quot;&gt;Outstanding Issues&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v36_upgrading&quot;&gt;Notes On Upgrading From a Previous Version&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v36_code_changes&quot;&gt;Code Changes Which May Affect 
+    Customizations&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v36_previous&quot;&gt;Release Notes for Previous Versions&lt;/a&gt;&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h2 id=&quot;v36_introduction&quot;&gt;Introduction&lt;/h2&gt;
+
+&lt;p&gt;Welcome to [% terms.Bugzilla %] 3.6! The focus of the 3.6 release is
+  on improving usability and &quot;polishing up&quot; all our features (by adding
+  some pieces that were &quot;missing&quot; or always wanted), although we
+  also have a few great new features for you, as well!&lt;/p&gt;
+
+&lt;p&gt;If you're upgrading, make sure to read &lt;a href=&quot;#v36_upgrading&quot;&gt;Notes
+  On Upgrading From a Previous Version&lt;/a&gt;. If you are upgrading from a release
+  before 3.4, make sure to read the release notes for all the 
+  &lt;a href=&quot;#v36_previous&quot;&gt;previous versions&lt;/a&gt; in between your version
+  and this one, &lt;strong&gt;particularly the Upgrading section of each
+  version's release notes&lt;/strong&gt;.&lt;/p&gt;
+
+&lt;p&gt;We would like to thank &lt;a href=&quot;http://www.canonical.com/&quot;&gt;Canonical
+  Ltd.&lt;/a&gt;, &lt;a href=&quot;http://www.itasoftware.com/&quot;&gt;ITA Software&lt;/a&gt;,
+  the &lt;a href=&quot;http://www.ibm.com/linux/ltc/&quot;&gt;IBM Linux Technology Center&lt;/a&gt;,
+  &lt;a href=&quot;http://www.redhat.com/&quot;&gt;Red Hat&lt;/a&gt;, and 
+  &lt;a href=&quot;http://www.novell.com/&quot;&gt;Novell&lt;/a&gt; for funding the development
+  of various features and improvements in this release of
+  [%+ terms.Bugzilla %].&lt;/p&gt;
+
+&lt;h2 id=&quot;v36_point&quot;&gt;Updates in this 3.6.x Release&lt;/h2&gt;
+
+&lt;h3&gt;3.6.2&lt;/h3&gt;
+
+&lt;p&gt;This release fixes various security issues. See the
+  &lt;a href=&quot;http://www.bugzilla.org/security/3.2.7/&quot;&gt;Security Advisory&lt;/a&gt;
+  for details.&lt;/p&gt;
+
+&lt;p&gt;In addition, the following important fixes/changes have been made in
+  this release:&lt;/p&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;[% terms.Bugzilla %] installations running on older versions of IIS
+    will no longer experience the &quot;Undef to trick_taint&quot; errors that would
+    sometimes occur.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=521416&quot;&gt;[% terms.Bug %] 521416&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;Email notifications were missing the dates that comments were made.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=578003&quot;&gt;[% terms.Bug %] 578003&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;Putting a phrase in quotes in the Quicksearch box now works properly,
+    again.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=578494&quot;&gt;[% terms.Bug %] 578494&lt;/a&gt;
+    and &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=553884&quot;&gt;[% terms.Bug %] 553884&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;Quicksearch was usually (incorrectly) being limited to 200 results.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=581622&quot;&gt;[% terms.Bug %] 581622&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;On Windows, &lt;kbd&gt;install-module.pl&lt;/kbd&gt; can now properly install
+    DateTime and certain other Perl modules that didn't install properly
+    before.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=576105&quot;&gt;[% terms.Bug %] 576105&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;Searching &quot;keywords&quot; for &quot;contains none of the words&quot; or &quot;does not
+    match regular expression&quot; now works properly.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=562014&quot;&gt;[% terms.Bug %] 562014&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;Doing &lt;kbd&gt;collectstats.pl --regenerate&lt;/kbd&gt; now works on installations
+    using PostgreSQL.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=577058&quot;&gt;[% terms.Bug %] 577058&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;The &quot;Field Values&quot; administrative control panel was sometimes denying
+    admins the ability to delete field values when there was no reason
+    to deny the deletion.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=577054&quot;&gt;[% terms.Bug %] 577054&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;Eliminate the &quot;uninitialized value&quot; warnings that would happen when
+    editing a product's components.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=576911&quot;&gt;[% terms.Bug %] 576911&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;The updating of bugs_fulltext that happens during 
+    &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; for upgrades to 3.6 should now be MUCH faster.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=577754&quot;&gt;[% terms.Bug %] 577754&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;&lt;kbd&gt;email_in.pl&lt;/kbd&gt; was not allowing the setting of time-tracking
+    fields via inbound emails.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=583622&quot;&gt;[% terms.Bug %] 583622&lt;/a&gt;)
+  &lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h3&gt;3.6.1&lt;/h3&gt;
+
+&lt;p&gt;This release fixes two security issues. See the
+  &lt;a href=&quot;http://www.bugzilla.org/security/3.2.6/&quot;&gt;Security Advisory&lt;/a&gt;
+  for details.&lt;/p&gt;
+
+&lt;p&gt;In addition, the following important fixes/changes have been made in
+  this release:&lt;/p&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;Using the &quot;Change Columns&quot; page would sometimes result in a
+    plain-text page instead of HTML.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=376044&quot;&gt;[% terms.Bug %] 376044&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;Extensions that have only templates and no code are now working.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=562551&quot;&gt;[% terms.Bug %] 562551&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;&lt;kbd&gt;install-module.pl&lt;/kbd&gt; has been fixed so that it installs
+    modules properly on both new and old versions of Perl.
+     (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=560318&quot;&gt;[% terms.Bug %] 560318&lt;/a&gt;
+     and &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=560330&quot;&gt;[% terms.Bug %] 560330&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;It is now possible to upgrade from 3.4 to 3.6 when using Oracle.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=561379&quot;&gt;[% terms.Bug %] 561379&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;Editing a field value's name (using the Field Values admin control
+    panel) wasn't working if the value was set as the default for that
+    field.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=561296&quot;&gt;[% terms.Bug %] 561296&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;If you had the &lt;kbd&gt;noresolveonopenblockers&lt;/kbd&gt; parameter set,
+    [%+ terms.bugs %] couldn't be edited at all if they were marked FIXED
+    and had any open blockers. (The parameter is only supposed to prevent
+    &lt;em&gt;changing&lt;/em&gt; [% terms.bugs %] to FIXED, not modifying already-FIXED
+    [%+ terms.bugs %].)
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=565314&quot;&gt;[% terms.Bug %] 565314&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;Some minor issues with Perl 5.12 were fixed (mostly warnings that Perl
+    5.12 was throwing). [% terms.Bugzilla %] now supports Perl 5.12.&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h2 id=&quot;v36_req&quot;&gt;Minimum Requirements&lt;/h2&gt;
+
+&lt;p&gt;Any requirements that are new since 3.4.5 will look like
+  &lt;span class=&quot;req_new&quot;&gt;this&lt;/span&gt;.&lt;/p&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;&lt;a href=&quot;#v36_req_perl&quot;&gt;Perl&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v36_req_mysql&quot;&gt;For MySQL Users&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v36_req_pg&quot;&gt;For PostgreSQL Users&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v36_req_oracle&quot;&gt;For Oracle Users&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v36_req_modules&quot;&gt;Required Perl Modules&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v36_req_optional_mod&quot;&gt;Optional Perl Modules&lt;/a&gt;&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h3 id=&quot;v36_req_perl&quot;&gt;Perl&lt;/h3&gt; 

+&lt;p&gt;Perl v5.8.1&lt;/p&gt;
+
+&lt;h3 id=&quot;v36_req_mysql&quot;&gt;For MySQL Users&lt;/h3&gt; 

+  &lt;ul&gt; 
+    &lt;li&gt;MySQL
+       v4.1.2
+       &lt;/li&gt; 
+    &lt;li&gt;&lt;strong&gt;perl module:&lt;/strong&gt; 
+      DBD::mysql v4.00&lt;/li&gt; 
+  &lt;/ul&gt;
+  
+&lt;h3 id=&quot;v36_req_pg&quot;&gt;For PostgreSQL Users&lt;/h3&gt; 

+  &lt;ul&gt; 
+    &lt;li&gt;PostgreSQL
+       v8.00.0000
+       &lt;/li&gt; 
+    &lt;li&gt;&lt;strong&gt;perl module:&lt;/strong&gt; 
+      DBD::Pg v1.45&lt;/li&gt; 
+  &lt;/ul&gt; 
+&lt;h3 id=&quot;v36_req_oracle&quot;&gt;For Oracle Users&lt;/h3&gt; 

+  &lt;ul&gt; 
+    &lt;li&gt;Oracle
+       v10.02.0
+       &lt;/li&gt; 
+    &lt;li&gt;&lt;strong&gt;perl module:&lt;/strong&gt; 
+      DBD::Oracle v1.19&lt;/li&gt; 
+  &lt;/ul&gt; 

+&lt;h3 id=&quot;v36_req_modules&quot;&gt;Required Perl Modules&lt;/h3&gt;
+
+&lt;table class=&quot;req_table&quot; border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt; 
+    &lt;tr&gt; 
+      &lt;th&gt;Module&lt;/th&gt; &lt;th&gt;Version&lt;/th&gt; 
+    &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;CGI&lt;/td&gt; 
+        &lt;td &gt;3.21
+        &lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;Digest::SHA&lt;/td&gt; 
+        &lt;td &gt; 
+            (Any)
+        &lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;Date::Format&lt;/td&gt; 
+        &lt;td &gt;2.21
+        &lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;DateTime&lt;/td&gt; 
+        &lt;td &gt;0.28
+        &lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;DateTime::TimeZone&lt;/td&gt; 
+        &lt;td &gt;0.71
+        &lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;DBI&lt;/td&gt; 
+        &lt;td &gt;1.41
+        &lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;Template&lt;/td&gt; 
+        &lt;td &gt;2.22
+        &lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;Email::Send&lt;/td&gt; 
+        &lt;td &gt;2.00
+        &lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;Email::MIME&lt;/td&gt; 
+        &lt;td &gt;1.861
+        &lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;Email::MIME::Encodings&lt;/td&gt; 
+        &lt;td &gt;1.313
+        &lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;Email::MIME::Modifier&lt;/td&gt; 
+        &lt;td &gt;1.442
+        &lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;URI&lt;/td&gt; 
+        &lt;td &gt; 
+            (Any)
+        &lt;/td&gt; 
+      &lt;/tr&gt; 
+&lt;/table&gt; 

+&lt;h3 id=&quot;v36_req_optional_mod&quot;&gt;Optional Perl Modules&lt;/h3&gt; 

+&lt;p&gt;The following perl modules, if installed, enable various
+  features of [% terms.Bugzilla %]:&lt;/p&gt;
+
+&lt;table class=&quot;req_table&quot; border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt; 
+    &lt;tr&gt; 
+      &lt;th&gt;Module&lt;/th&gt; &lt;th&gt;Version&lt;/th&gt; 
+        &lt;th&gt;Enables Feature&lt;/th&gt; 
+    &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;GD&lt;/td&gt; 
+        &lt;td &gt;1.20
+        &lt;/td&gt; 
+          &lt;td&gt;Graphical Reports, New Charts, Old Charts&lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;Chart::Lines&lt;/td&gt; 
+        &lt;td  class=&quot;req_new&quot;&gt;2.1
+        &lt;/td&gt; 
+          &lt;td&gt;New Charts, Old Charts&lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;Template::Plugin::GD::Image&lt;/td&gt; 
+        &lt;td &gt; 
+            (Any)
+        &lt;/td&gt; 
+          &lt;td&gt;Graphical Reports&lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;GD::Text&lt;/td&gt; 
+        &lt;td &gt; 
+            (Any)
+        &lt;/td&gt; 
+          &lt;td&gt;Graphical Reports&lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;GD::Graph&lt;/td&gt; 
+        &lt;td &gt; 
+            (Any)
+        &lt;/td&gt; 
+          &lt;td&gt;Graphical Reports&lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;XML::Twig&lt;/td&gt; 
+        &lt;td &gt; 
+            (Any)
+        &lt;/td&gt; 
+          &lt;td&gt;Move [% terms.Bugs %] Between Installations,
+          Automatic Update Notifications&lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;MIME::Parser&lt;/td&gt; 
+        &lt;td &gt;5.406
+        &lt;/td&gt; 
+          &lt;td&gt;Move [% terms.Bugs %] Between Installations&lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;LWP::UserAgent&lt;/td&gt; 
+        &lt;td &gt; 
+            (Any)
+        &lt;/td&gt; 
+          &lt;td&gt;Automatic Update Notifications&lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;PatchReader&lt;/td&gt; 
+        &lt;td &gt;0.9.4
+        &lt;/td&gt; 
+          &lt;td&gt;Patch Viewer&lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;Net::LDAP&lt;/td&gt; 
+        &lt;td &gt; 
+            (Any)
+        &lt;/td&gt; 
+          &lt;td&gt;LDAP Authentication&lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;Authen::SASL&lt;/td&gt; 
+        &lt;td &gt; 
+            (Any)
+        &lt;/td&gt; 
+          &lt;td&gt;SMTP Authentication&lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;Authen::Radius&lt;/td&gt; 
+        &lt;td &gt; 
+            (Any)
+        &lt;/td&gt; 
+          &lt;td&gt;RADIUS Authentication&lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;SOAP::Lite&lt;/td&gt; 
+        &lt;td &gt;0.710.06
+        &lt;/td&gt; 
+          &lt;td&gt;XML-RPC Interface&lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td  class=&quot;req_new&quot;&gt;JSON::RPC&lt;/td&gt; 
+        &lt;td  class=&quot;req_new&quot;&gt; 
+            (Any)
+        &lt;/td&gt; 
+          &lt;td&gt;JSON-RPC Interface&lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td  class=&quot;req_new&quot;&gt;Test::Taint&lt;/td&gt; 
+        &lt;td  class=&quot;req_new&quot;&gt; 
+            (Any)
+        &lt;/td&gt; 
+          &lt;td&gt;JSON-RPC Interface, XML-RPC Interface&lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;HTML::Parser&lt;/td&gt; 
+        &lt;td &gt;3.40
+        &lt;/td&gt; 
+          &lt;td&gt;More HTML in Product/Group Descriptions&lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;HTML::Scrubber&lt;/td&gt; 
+        &lt;td &gt; 
+            (Any)
+        &lt;/td&gt; 
+          &lt;td&gt;More HTML in Product/Group Descriptions&lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;Email::MIME::Attachment::Stripper&lt;/td&gt; 
+        &lt;td &gt; 
+            (Any)
+        &lt;/td&gt; 
+          &lt;td&gt;Inbound Email&lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;Email::Reply&lt;/td&gt; 
+        &lt;td &gt; 
+            (Any)
+        &lt;/td&gt; 
+          &lt;td&gt;Inbound Email&lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;TheSchwartz&lt;/td&gt; 
+        &lt;td &gt; 
+            (Any)
+        &lt;/td&gt; 
+          &lt;td&gt;Mail Queueing&lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;Daemon::Generic&lt;/td&gt; 
+        &lt;td &gt; 
+            (Any)
+        &lt;/td&gt; 
+          &lt;td&gt;Mail Queueing&lt;/td&gt; 
+      &lt;/tr&gt; 
+      &lt;tr&gt; 
+        &lt;td &gt;mod_perl2&lt;/td&gt; 
+        &lt;td &gt;1.999022
+        &lt;/td&gt; 
+          &lt;td&gt;mod_perl&lt;/td&gt; 
+      &lt;/tr&gt; 
+&lt;/table&gt; 
+
+&lt;h2 id=&quot;v36_feat&quot;&gt;New Features and Improvements&lt;/h2&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;&lt;a href=&quot;#v36_feat_usability&quot;&gt;General Usability Improvements&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v36_feat_extensions&quot;&gt;New Extensions System&lt;/a&gt;&lt;/li&gt;  
+  &lt;li&gt;&lt;a href=&quot;#v36_feat_qs&quot;&gt;Improved Quicksearch&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v36_feat_browse&quot;&gt;Simple &quot;Browse&quot; Interface&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v36_feat_suexec&quot;&gt;SUExec Support&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v36_feat_mpwindows&quot;&gt;Experimental mod_perl Support on Windows&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v36_email_attachments&quot;&gt;Send Attachments by Email&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v36_feat_jsonrpc&quot;&gt;JSON-RPC Interface&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v36_feat_migrate&quot;&gt;Migration From Other [% terms.Bug %]-Trackers&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v36_feat_other&quot;&gt;Other Enhancements and Changes&lt;/a&gt;&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h3 id=&quot;v36_feat_usability&quot;&gt;General Usability Improvements&lt;/h3&gt;
+
+&lt;p&gt;A &lt;a href=&quot;https://wiki.mozilla.org/Bugzilla:CMU_HCI_Research_2008&quot;&gt;scientific
+  usability study&lt;/a&gt; was done on [% terms.Bugzilla %] by researchers
+  from Carnegie-Mellon University. As a result of this study,
+  &lt;a href=&quot;https://bugzilla.mozilla.org/showdependencytree.cgi?id=490786&amp;amp;hide_resolved=0&quot;&gt;several
+  usability issues&lt;/a&gt; were prioritized to be fixed, based on specific data
+  from the study.&lt;/p&gt;
+
+&lt;p&gt;As a result, you will see many small improvements in [% terms.Bugzilla %]'s
+  usability, such as using Javascript to validate certain forms before
+  they are submitted, standardizing the words that we use in the user interface,
+  being clearer about what [% terms.Bugzilla %] needs from the user,
+  and other changes, all of which are also listed individually in this New
+  Features section.&lt;/p&gt;
+
+&lt;p&gt;Work continues on improving usability for the next release of
+  [%+ terms.Bugzilla %], but the results of the research have already
+  had an impact on this 3.6 release.&lt;/p&gt;
+
+&lt;h3 id=&quot;v36_feat_extensions&quot;&gt;New Extensions System&lt;/h3&gt;
+
+&lt;p&gt;[% terms.Bugzilla %] has a brand-new Extensions system. The system is
+  consistent, fast, and
+  &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/Extension.html&quot;&gt;fully
+  documented&lt;/a&gt;. It makes it possible to easily extend [% terms.Bugzilla %]'s
+  code and user interface to add new features or change existing features.
+  There's even
+  &lt;a href=&quot;[% docs_urlbase FILTER html %]api/extensions/create.html&quot;&gt;a
+  script&lt;/a&gt; that will create the basic layout of an extension for you, to
+  help you get started. For more information about the new system, see the
+  &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/Extension.html&quot;&gt;Extensions
+  documentation&lt;/a&gt;.&lt;/p&gt;
+
+&lt;p&gt;If you had written any extensions using [% terms.Bugzilla %]'s previous
+  extensions system, there is
+  &lt;a href=&quot;[% docs_urlbase FILTER html %]api/contrib/extension-convert.html&quot;&gt;a
+  script to help convert old extensions into the new format&lt;/a&gt;.&lt;/p&gt;
+
+&lt;h3 id=&quot;v36_feat_qs&quot;&gt;Improved Quicksearch&lt;/h3&gt;
+
+&lt;p&gt;The &quot;quicksearch&quot; box that appears on the front page of
+  [%+ terms.Bugzilla %] and in the header/footer of every page
+  is now simplified and made more powerful. There is a
+  &lt;kbd&gt;[?]&lt;/kbd&gt; link next to the box that will take you to
+  the simplified &lt;a href=&quot;page.cgi?id=quicksearch.html&quot;&gt;Quicksearch Help&lt;/a&gt;,
+  which describes every single feature of the system in a simple layout,
+  including new features such as the ability to use partial field names
+  when searching.&lt;/p&gt;
+
+&lt;p&gt;Quicksearch should also be much faster than it was before, particularly
+  on large installations.&lt;/p&gt;
+
+&lt;p&gt;Note that in order to implement the new quicksearch, certain old
+  and rarely-used features had to be removed:
+
+&lt;ul&gt;
+  &lt;li&gt;&lt;b&gt;+&lt;/b&gt; as a prefix to mean &quot;search additional resolutions&quot;, and
+    &lt;b&gt;+&lt;/b&gt; as a prefix to mean &quot;search just the summary&quot;. You can
+    instead use &lt;kbd&gt;summary:&lt;/kbd&gt; to explicitly search summaries.&lt;/li&gt;
+  &lt;li&gt;Searching the Severity field if you type something that matches
+    the first few characters of a severity. You can explicitly search
+    the Severity field if you want to find [% terms.bugs %] by severity.&lt;/li&gt;
+  &lt;li&gt;Searching the Priority field if you typed something that exactly
+    matched the name of a priority. You can explicitly search the
+    Priority field if you want to find [% terms.bugs %] by priority.&lt;/li&gt;
+  &lt;li&gt;Searching the Platform and OS fields if you typed in one of a
+    certain hard-coded list of strings (like &quot;pc&quot;, &quot;windows&quot;, etc.).
+    You can explicitly search these fields, instead, if you want to
+    find [% terms.bugs %] with a specific Platform or OS set.&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h3 id=&quot;v36_feat_browse&quot;&gt;Simple &quot;Browse&quot; Interface&lt;/h3&gt;
+
+&lt;p&gt;There is now a &quot;Browse&quot; link in the header of each [% terms.Bugzilla %]
+  page that presents a very basic interface that allows users to simply
+  browse through all open [% terms.bugs %] in particular components.&lt;/p&gt;
+
+&lt;h3 id=&quot;v36_feat_suexec&quot;&gt;SUExec Support&lt;/h3&gt;
+
+&lt;p&gt;[% terms.Bugzilla %] can now be run in Apache's &quot;SUExec&quot; mode,
+  which is what control panel software like cPanel and Plesk use
+  (so [% terms.Bugzilla %] should now be much easier to install
+  on shared hosting). SUExec support shows up as an option
+  in the &lt;kbd&gt;localconfig&lt;/kbd&gt; file during installation.&lt;/p&gt;
+
+&lt;h3 id=&quot;v36_feat_mpwindows&quot;&gt;Experimental mod_perl Support on Windows&lt;/h3&gt;
+
+&lt;p&gt;There is now experimental support for running [% terms.Bugzilla %]
+  under mod_perl on Windows, for a significant performance enhancement
+  (in exchange for using more memory).&lt;/p&gt;
+
+&lt;h3 id=&quot;v36_email_attachments&quot;&gt;Send Attachments by Email&lt;/h3&gt;
+
+&lt;p&gt;The &lt;a href=&quot;[% docs_urlbase FILTER html %]api/email_in.html&quot;&gt;email_in&lt;/a&gt;
+  script now supports attaching multiple attachments to [% terms.abug %]
+  by email, both when filing and when updating [% terms.abug %].&lt;/p&gt;
+
+&lt;h3 id=&quot;v36_feat_jsonrpc&quot;&gt;JSON-RPC Interface&lt;/h3&gt;
+
+&lt;p&gt;[% terms.Bugzilla %] now has support for the
+  &lt;a href=&quot;http://json-rpc.org/&quot;&gt;JSON-RPC&lt;/a&gt; WebServices protocol via
+  &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/WebService/Server/JSONRPC.html&quot;&gt;jsonrpc.cgi&lt;/a&gt;.
+  The JSON-RPC interface is experimental in this release--if you want any
+  fundamental changes in how it works,
+  &lt;a href=&quot;http://www.bugzilla.org/developers/reporting_bugs.html&quot;&gt;let us
+  know&lt;/a&gt;, for the next release of [% terms.Bugzilla %].&lt;/p&gt;
+
+&lt;h3 id=&quot;v36_feat_migrate&quot;&gt;Migration From Other [% terms.Bug %]-Trackers&lt;/h3&gt;
+
+&lt;p&gt;[% terms.Bugzilla %] 3.6 comes with a new script,
+  &lt;a href=&quot;[% docs_urlbase FILTER html %]api/migrate.html&quot;&gt;migrate.pl&lt;/a&gt;,
+  which allows migration from other [% terms.bug %]-tracking systems.
+  Among the various features of the migration system are:&lt;/p&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;It is non-destructive--you can migrate into an existing
+    [%+ terms.Bugzilla %] installation without destroying any data
+    in the installation.&lt;/li&gt;
+  &lt;li&gt;It has a &quot;dry-run&quot; mode so you can test your migration
+    before actually running it.&lt;/li&gt;
+  &lt;li&gt;It is relatively easy to write new migrators for new systems,
+    if you know Perl. The basic migration framework does most of the work
+    for you, you just have to provide it with the data from your
+    [%+ terms.bug %]-tracker. See the
+    &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/Migrate.html&quot;&gt;Bugzilla::Migrate&lt;/a&gt;
+    documentation and see our current migrator,
+    &lt;kbd&gt;Bugzilla/Migrate/GNATS.pm&lt;/kbd&gt; for information on how to make your
+    own migrator.&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;p&gt;The first migrator that has been implemented is for the GNATS
+  [%+ terms.bug %]-tracking system. We'd love to see migrators for
+  other systems! If you want to contribute a new migrator, see our
+  &lt;a href=&quot;http://wiki.mozilla.org/Bugzilla:Developers&quot;&gt;development
+  process&lt;/a&gt; for details on how to get code into [% terms.Bugzilla %].&lt;/p&gt;
+
+&lt;p&gt;Thanks to &lt;a href=&quot;http://lambdares.com/&quot;&gt;Lambda Research&lt;/a&gt; for
+  funding the initial development of this feature.&lt;/p&gt;
+
+&lt;h3 id=&quot;v36_feat_other&quot;&gt;Other Enhancements and Changes&lt;/h3&gt;
+
+&lt;h4&gt;Enhancements for Users&lt;/h4&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;&lt;b&gt;[% terms.Bug %] Filing:&lt;/b&gt; When filing [% terms.abug %],
+    [%+ terms.Bugzilla %] now visually indicates which fields are
+    mandatory.&lt;/li&gt;
+  &lt;li&gt;&lt;b&gt;[% terms.Bug %] Filing:&lt;/b&gt; &quot;Bookmarkable templates&quot; now
+    support the &quot;alias&quot; and &quot;estimated hours&quot; fields.&lt;/li&gt;
+  
+  &lt;li&gt;&lt;b&gt;[% terms.Bug %] Editing:&lt;/b&gt; In previous versions of
+    [%+ terms.Bugzilla %], if you added a private comment to [% terms.abug %],
+    then &lt;em&gt;none&lt;/em&gt; of the changes that you made at that time were
+    sent to users who couldn't see the private comment. Now, for users
+    who can't see private comments, public changes are sent, but the private
+    comment is excluded from their email notification.&lt;/li&gt;
+  &lt;li&gt;&lt;b&gt;[% terms.Bug %] Editing:&lt;/b&gt; The controls for groups now
+    appear to the right of the attachment and time-tracking tables,
+    when editing [% terms.abug %].&lt;/li&gt;
+  &lt;li&gt;&lt;b&gt;[% terms.Bug %] Editing:&lt;/b&gt; The &quot;Collapse All Comments&quot;
+    and &quot;Expand All Comments&quot; links now appear to the right of the
+    comment list instead of above it.&lt;/li&gt;
+  &lt;li&gt;&lt;b&gt;[% terms.Bug %] Editing:&lt;/b&gt; The See Also field now supports
+    URLs for Google Code Issues and the Debian B[% %]ug-Tracking System.&lt;/li&gt;
+  &lt;li&gt;&lt;b&gt;[% terms.Bug %] Editing:&lt;/b&gt; There have been significant performance
+    improvements in &lt;kbd&gt;show_bug.cgi&lt;/kbd&gt; (the script that displays the
+    [% terms.bug %]-editing form), particularly for [% terms.bugs %] that
+    have lots of comments or attachments.&lt;/li&gt;
+
+  &lt;li&gt;&lt;b&gt;Attachments:&lt;/b&gt; The &quot;Details&quot; page of an attachment
+    now displays itself as uneditable if you can't edit the fields
+    there.&lt;/li&gt;
+  &lt;li&gt;&lt;b&gt;Attachments:&lt;/b&gt; We now make sure that there is
+    a Description specified for an attachment, using JavaScript, before
+    the form is submitted.&lt;/li&gt;
+  &lt;li&gt;&lt;b&gt;Attachments:&lt;/b&gt; There is now a link back to the [% terms.bug %]
+    at the bottom of the &quot;Details&quot; page for an attachment.&lt;/li&gt;
+  &lt;li&gt;&lt;b&gt;Attachments:&lt;/b&gt; When you click on an &quot;attachment 12345&quot; link
+    in a comment, if the attachment is a patch, you will now see the
+    formatted &quot;Diff&quot; view instead of the raw patch.&lt;/li&gt;
+  &lt;li&gt;&lt;b&gt;Attachments&lt;/b&gt;: For text attachments, we now let the browser 
+    auto-detect the character encoding, instead of forcing the browser to
+    always assume the attachment is in UTF-8.&lt;/li&gt;
+  
+  &lt;li&gt;&lt;b&gt;Search:&lt;/b&gt; You can now display [% terms.bug %] flags as a column
+    in search results.&lt;/li&gt;
+  &lt;li&gt;&lt;b&gt;Search:&lt;/b&gt; When viewing search results, you can see which columns are
+    being sorted on, and which direction the sort is on, as indicated
+    by arrows next to the column headers.&lt;/li&gt;
+  &lt;li&gt;&lt;b&gt;Search:&lt;/b&gt; You can now search the Deadline field using relative
+    dates (like &quot;1d&quot;, &quot;2w&quot;, etc.).&lt;/li&gt;
+  &lt;li&gt;&lt;b&gt;Search:&lt;/b&gt; The iCalendar format of search results now includes
+    a PRIORITY field.&lt;/li&gt;
+  &lt;li&gt;&lt;b&gt;Search:&lt;/b&gt; It is no longer an error to enter an invalid search
+    order in a search URL--[% terms.Bugzilla %] will simply warn you that
+    some of your order options are invalid.&lt;/li&gt;
+  &lt;li&gt;&lt;b&gt;Search:&lt;/b&gt; When there are no search results, some helpful
+    links are displayed, offering actions you might want to take.&lt;/li&gt;
+  &lt;li&gt;&lt;b&gt;Search:&lt;/b&gt; For those who like to make their own
+    &lt;kbd&gt;buglist.cgi&lt;/kbd&gt; URLs (and for people working on customizations),
+    &lt;kbd&gt;buglist.cgi&lt;/kbd&gt; now accepts nearly every valid field in
+    [%+ terms.Bugzilla %] as a direct URL parameter, like
+    &lt;kbd&gt;&amp;amp;field=value&lt;/kbd&gt;.&lt;/li&gt;
+  
+  &lt;li&gt;&lt;b&gt;Requests:&lt;/b&gt; When viewing the &quot;My Requests&quot; page, you can now
+    see the lists as a normal search result by clicking a link at the
+    bottom of each table.&lt;/li&gt;
+  &lt;li&gt;&lt;b&gt;Requests:&lt;/b&gt; When viewing the &quot;My Requests&quot; page, if you are
+    using Classifications, the Product drop-down will be grouped by
+    Classification.&lt;/li&gt;
+
+  &lt;li&gt;&lt;b&gt;Inbound Email:&lt;/b&gt; When filing [% terms.abug %] by email, if the
+    product that you are filing the [% terms.bug %] into has some groups
+    set as Default for you, the [% terms.bug %] will now be placed into those
+    groups automatically.&lt;/li&gt;
+  &lt;li&gt;&lt;b&gt;Inbound Email:&lt;/b&gt; The field names that can be used when creating
+    [%+ terms.bugs %] by email now exactly matches the set of valid parameters
+    to the
+    &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/WebService/Bug.html#create&quot;&gt;B[% %]ug.create
+    WebService function&lt;/a&gt;. You can still use most of the old field names
+    that 3.4 and earlier used for inbound emails, though, for
+    backwards-compatibility.&lt;/li&gt;
+
+  &lt;li&gt;If there are multiple languages available for your
+    [%+ terms.Bugzilla %], you can now select what language you want
+    [%+ terms.Bugzilla %] displayed in using links at the top of every
+    page.&lt;/li&gt;
+  &lt;li&gt;When creating a new account, you will be automatically logged in
+    after setting your password.&lt;/li&gt;
+  &lt;li&gt;There is no longer a maximum password length for accounts.&lt;/li&gt;
+  &lt;li&gt;In the Dusk skin, it's now easier to see links.&lt;/li&gt;
+  &lt;li&gt;In the Whining system, you can now choose to receive emails even
+    if there are no [% terms.bugs %] that match your searches.&lt;/li&gt;
+  &lt;li&gt;The arrows in dependency graphs now point the other way, so that
+    [%+ terms.bugs %] point at their dependencies.&lt;/li&gt;
+  
+  &lt;li&gt;&lt;b&gt;New Charts:&lt;/b&gt; You can now convert an existing Saved Search
+    into a data series for New Charts.&lt;/li&gt;
+  &lt;li&gt;&lt;b&gt;New Charts:&lt;/b&gt; There is now an interface that allows you to
+    delete data series.&lt;/li&gt;
+  &lt;li&gt;&lt;b&gt;New Charts:&lt;/b&gt; When deleting a product, you now have the option
+    to delete the data series that are associated with that product.&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h4&gt;Enhancements for Administrators and Developers&lt;/h4&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;Depending on how your workflow is set up, it is now possible to
+    have both UNCONFIRMED and REOPENED show up as status choices for
+    a closed [% terms.bug %]. If you only want one or the other to
+    show up, you should edit your status workflow appropriately
+    (possibly by removing or disabling the REOPENED status).&lt;/li&gt;
+  &lt;li&gt;You can now &quot;disable&quot; field values so that they don't show
+    up as choices on [% terms.abug %] unless they are already set as
+    the value for that [% terms.bug %]. This doesn't work for the
+    per-product field values (component, target_milestone, and version)
+    yet, though.&lt;/li&gt;
+  &lt;li&gt;Users are now locked out of their accounts for 30 minutes after
+    trying five bad passwords in a row during login. Every time a
+    user is locked out like this, the user in the &quot;maintainer&quot; parameter
+    will get an email.&lt;/li&gt;
+  &lt;li&gt;The minimum length allowed for a password is now 6 characters.&lt;/li&gt;
+  &lt;li&gt;The &lt;kbd&gt;UNCONFIRMED&lt;/kbd&gt; status being enabled in a product
+    is now unrelated to the voting parameters. Instead, there is a checkbox
+    to enable the &lt;kbd&gt;UNCONFIRMED&lt;/kbd&gt; status in a product.&lt;/li&gt;
+  &lt;li&gt;Information about duplicates is now stored in the database instead
+    of being stored in the &lt;kbd&gt;data/&lt;/kbd&gt; directory. On large installations
+    this could save several hundred megabytes of disk space.&lt;/li&gt;
+
+  &lt;li&gt;&lt;b&gt;Installation:&lt;/b&gt; When installing [% terms.Bugzilla %], the
+    &quot;maintainer&quot; parameter will be automatically set to the administrator
+    that was created by &lt;kbd&gt;checksetup.pl&lt;/kbd&gt;.&lt;/li&gt;
+  &lt;li&gt;&lt;b&gt;Installation:&lt;/b&gt; &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; now prints out
+    certain errors in a special color so that you know that something
+    needs to be done.&lt;/li&gt;
+  &lt;li&gt;&lt;b&gt;Installation:&lt;/b&gt; &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; is now &lt;em&gt;much&lt;/em&gt;
+    faster at upgrading installations, particularly older installations.
+    Also, it's been made faster to run for the case where it's not
+    doing an upgrade.&lt;/li&gt;
+  &lt;li&gt;&lt;b&gt;Installation:&lt;/b&gt; If you install [% terms.Bugzilla %] using the
+    tarball, the &lt;kbd&gt;CGI.pm&lt;/kbd&gt; module from CPAN is now included in
+    the &lt;kbd&gt;lib/&lt;/kbd&gt; dir. If you would rather use the CGI.pm from your
+    global Perl installation, you can delete &lt;kbd&gt;CGI.pm&lt;/kbd&gt; and the
+    &lt;kbd&gt;CGI&lt;/kbd&gt; directory from the &lt;kbd&gt;lib/&lt;/kbd&gt; directory.&lt;/li&gt;
+  
+  &lt;li&gt;When editing a group, you can now specify that members of a group
+    are allowed to grant others membership in that group itself.&lt;/li&gt;
+  &lt;li&gt;The ability to compress BMP attachments to PNGs is now an Extension.
+    To enable the feature, remove the file
+    &lt;kbd&gt;extensions/BmpConvert/disabled&lt;/kbd&gt; and then run &lt;kbd&gt;checksetup.pl&lt;/kbd&gt;.&lt;/li&gt;
+  &lt;li&gt;The default list of values for the Priority field are now clear English
+    words instead of P1, P2, etc.&lt;/li&gt;
+  &lt;li&gt;There is now a system in place so that all field values can be
+    localized. See the &lt;kbd&gt;value_descs&lt;/kbd&gt; variable in
+    &lt;kbd&gt;template/en/default/global/field-descs.none.tmpl&lt;/kbd&gt;.&lt;/li&gt;
+  &lt;li&gt;&lt;kbd&gt;config.cgi&lt;/kbd&gt; now returns an ETag header and understands
+    the If-None-Match header in HTTP requests.&lt;/li&gt;
+  &lt;li&gt;The XML format of &lt;kbd&gt;show_bug.cgi&lt;/kbd&gt; now returns more information:
+    the numeric id of each comment, whether an attachment is a URL,
+    the modification time of an attachment, the numeric id of a flag,
+    and the numeric id of a flag's type.&lt;/li&gt;
+  
+  &lt;li&gt;&lt;b&gt;Parameters:&lt;/b&gt; Parameters that aren't actually required are no longer
+    in the &quot;Required&quot; section of the Parameters page. Instead, some are in the
+    new &quot;General&quot; section, and some are in the new &quot;Advanced&quot; section.&lt;/li&gt;
+  &lt;li&gt;&lt;b&gt;Parameters:&lt;/b&gt; The old &lt;kbd&gt;ssl&lt;/kbd&gt; parameter has been
+    changed to &lt;kbd&gt;ssl_redirect&lt;/kbd&gt;, and can only be turned &quot;on&quot; or &quot;off&quot;.
+    If &quot;on&quot;, then all users will be forcibly redirected to SSL whenever
+    they access [% terms.Bugzilla %]. When the parameter is off,
+    no SSL-related redirects will occur (even if the user directly
+    accesses [% terms.Bugzilla %] via SSL, they will &lt;em&gt;not&lt;/em&gt; be
+    redirected to a non-SSL page).&lt;/li&gt;
+  &lt;li&gt;&lt;b&gt;Parameters:&lt;/b&gt; In the Advanced parameters, there is a new parameter,
+    &lt;kbd&gt;inbound_proxies&lt;/kbd&gt;. If your [% terms.Bugzilla %] is behind a
+    proxy, you should set this parameter to the IP address of that proxy.
+    Then, [% terms.Bugzilla %] will &quot;believe&quot; any &quot;X-Forwarded-For&quot;
+    header sent from that proxy, and correctly use the X-Forwarded-For
+    as the end user's IP, instead of believing that all traffic is coming
+    from the proxy.&lt;/li&gt;
+    
+  &lt;li&gt;&lt;b&gt;Removed Parameter:&lt;/b&gt; The &lt;kbd&gt;loginnetmask&lt;/kbd&gt; parameter has
+    been removed. Since [% terms.Bugzilla %] sends secure cookies, it's no
+    longer necessary to always restrict logins to a specific IP or block
+    of addresses.&lt;/li&gt;
+  &lt;li&gt;&lt;b&gt;Removed Parameter:&lt;/b&gt; The &lt;kbd&gt;quicksearch_comment_cutoff&lt;/kbd&gt;
+    parameter is gone. Quicksearch now always searches comments; however, it
+    uses a much faster algorithm to do it.&lt;/li&gt;
+  &lt;li&gt;&lt;b&gt;Removed Parameter:&lt;/b&gt; The &lt;kbd&gt;usermatchmode&lt;/kbd&gt; parameter has
+    been removed. User-matching is now &lt;em&gt;always&lt;/em&gt; done.&lt;/li&gt;
+  &lt;li&gt;&lt;b&gt;Removed Parameter:&lt;/b&gt; The &lt;kbd&gt;useentrygroupdefault&lt;/kbd&gt; parameter
+    has been removed. [% terms.Bugzilla %] now always behaves as though
+    that parameter were off.&lt;/li&gt;
+  &lt;li&gt;The &lt;kbd&gt;t/001compile.t&lt;/kbd&gt; test should now always pass, no matter
+    what configuration of optional modules you do or don't have installed.&lt;/li&gt;
+  &lt;li&gt;New script: &lt;kbd&gt;contrib/console.pl&lt;/kbd&gt;, which allows you to have
+    a &quot;command line&quot; into [% terms.Bugzilla %] by inputting Perl code
+    or using a few custom commands.&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h4&gt;WebService Changes&lt;/h4&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;The WebService now returns all dates and times in the UTC timezone.
+    &lt;kbd&gt;B[% %]ugzilla.time&lt;/kbd&gt; now acts as though the [% terms.Bugzilla %]
+    server were in the UTC timezone, always. If you want to write clients
+    that are compatible across all [% terms.Bugzilla %] versions,
+    check the timezone from &lt;kbd&gt;B[% %]ugzilla.timezone&lt;/kbd&gt; or
+    &lt;kbd&gt;B[% %]ugzilla.time&lt;/kbd&gt;, and always input times in that timezone
+    and expect times to be returned in that format.&lt;/li&gt;
+  &lt;li&gt;You can now log in by passing &lt;kbd&gt;Bugzilla_login&lt;/kbd&gt; and
+    &lt;kbd&gt;Bugzilla_password&lt;/kbd&gt; as arguments to any WebService function.
+    See the
+    &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/WebService.html#LOGGING_IN&quot;&gt;Bugzilla::WebService&lt;/a&gt;
+    documentation for details.&lt;/li&gt;
+  &lt;li&gt;New Method:
+    &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/WebService/Bug.html#attachments&quot;&gt;B[% %]ug.attachments&lt;/a&gt;
+    which allows getting information about attachments.&lt;/li&gt;
+  &lt;li&gt;New Method:
+    &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/WebService/Bug.html#fields&quot;&gt;B[% %]ug.fields&lt;/a&gt;,
+    which gets information about all the fields that [% terms.abug %] can have
+    in [% terms.Bugzilla %], include custom fields and legal values for
+    all fields. The &lt;kbd&gt;B[% %]ug.legal_values&lt;/kbd&gt; method is now deprecated.&lt;/li&gt;
+  &lt;li&gt;In the &lt;kbd&gt;B[% %]ug.add_comment&lt;/kbd&gt; method, the &quot;private&quot; parameter
+    has been renamed to &quot;is_private&quot; (for consistency with other methods).
+    You can still use &quot;private&quot;, though, for backwards-compatibility.&lt;/li&gt;
+  &lt;li&gt;The WebService now has Perl's &quot;taint mode&quot; turned on. This means that
+    it validates all data passed in before sending it to the database.
+    Also, all parameter names are validated, and if you pass in a parameter
+    whose name contains anything other than letters, numbers, or underscores,
+    that parameter will be ignored. Mostly this just affects
+    customizers--[% terms.Bugzilla %]'s WebService is not functionally
+    affected by these changes.&lt;/li&gt;
+  &lt;li&gt;In previous versions of [% terms.Bugzilla %], error messages were
+    sent word-wrapped to the client, from the WebService. Error messages
+    are now sent as one unbroken line.&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h2 id=&quot;v36_issues&quot;&gt;Outstanding Issues&lt;/h2&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=423439&quot;&gt;
+    [%- terms.Bug %] 423439&lt;/a&gt;: Tabs in comments will be converted
+    to four spaces, due to a b&lt;!-- --&gt;ug in Perl as of Perl 5.8.8.&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=69621&quot;&gt;
+    [%- terms.Bug %] 69621&lt;/a&gt;: If you rename or remove a keyword that is
+    in use on [% terms.bugs %], you will need to rebuild the &quot;keyword cache&quot;
+    by running &lt;a href=&quot;sanitycheck.cgi&quot;&gt;sanitycheck.cgi&lt;/a&gt; and choosing 
+    the option to rebuild the cache when it asks. Otherwise keywords may 
+    not show up properly in search results.&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=89822&quot;&gt;
+    [%- terms.Bug %] 89822&lt;/a&gt;: When changing multiple [% terms.bugs %] at 
+    the same time, there is no &quot;mid-air collision&quot; protection.&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=276230&quot;&gt;
+    [%- terms.Bug %] 276230&lt;/a&gt;: The support for restricting access to 
+    particular Categories of New Charts is not complete. You should treat 
+    the 'chartgroup' Param as the only access mechanism available.&lt;br&gt;
+    However, charts migrated from Old Charts will be restricted to 
+    the groups that are marked MANDATORY for the corresponding Product.
+    There is currently no way to change this restriction, and the 
+    groupings will not be updated if the group configuration
+    for the Product changes.&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h2 id=&quot;v36_upgrading&quot;&gt;Notes On Upgrading From a Previous Version&lt;/h2&gt;
+
+&lt;p&gt;When upgrading to 3.6, &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; will create foreign keys
+  for many columns in the database. Before doing this, it will check the
+  database for consistency. If there are an unresolvable consistency
+  problems, it will tell you what table and column in the database contain
+  the bad values, and which values are bad. If you don't know what else to do,
+  you can always delete the database records which contain the bad values by
+  logging in to your database and running the following command:&lt;/p&gt;
+
+&lt;p&gt;&lt;code&gt;DELETE FROM &lt;var&gt;table&lt;/var&gt; WHERE &lt;var&gt;column&lt;/var&gt; IN 
+  (&lt;var&gt;1, 2, 3, 4&lt;/var&gt;)&lt;/code&gt;&lt;/p&gt;
+
+&lt;p&gt;Just replace &quot;table&quot; and &quot;column&quot; with the name of the table 
+  and column that &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; mentions, and &quot;1, 2, 3, 4&quot;
+  with the invalid values that &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; prints out.&lt;/p&gt;
+
+&lt;p&gt;Remember that you should always back up your database before doing
+  an upgrade.&lt;/p&gt;
+
+&lt;h2 id=&quot;v36_code_changes&quot;&gt;Code Changes Which May Affect Customizations&lt;/h2&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;There is no longer a SendBugMail method in the templates, and bugmail
+    is no longer sent by processing a template. Instead, it is sent
+    by using &lt;kbd&gt;Bugzilla::BugMail::Send&lt;/kbd&gt;.&lt;/li&gt;
+  &lt;li&gt;Comments are now represented as a
+    &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/Comment.html&quot;&gt;Bugzilla::Comment&lt;/a&gt;
+    object instead of just being hashes.&lt;/li&gt;
+  &lt;li&gt;In previous versions of [% terms.Bugzilla %], the template for displaying
+    [%+ terms.abug %] required a lot of extra variables that are now global
+    template variables instead.&lt;/li&gt;
+  &lt;li&gt;You can now check if optional modules are installed by using
+    &lt;kbd&gt;Bugzilla-&amp;gt;feature&lt;/kbd&gt; in Perl code or
+    &lt;kbd&gt;feature_enabled&lt;/kbd&gt; in template code.&lt;/li&gt;
+  &lt;li&gt;All of the various template header information required to display
+    the [% terms.bug %] form is now in one template,
+    &lt;kbd&gt;template/en/default/bug/show-header.html.tmpl&lt;/kbd&gt;.&lt;/li&gt;
+  &lt;li&gt;You should now use &lt;kbd&gt;display_value&lt;/kbd&gt; instead of
+    &lt;kbd&gt;get_status&lt;/kbd&gt; or &lt;kbd&gt;get_resolution&lt;/kbd&gt; in templates.
+    &lt;kbd&gt;display_value&lt;/kbd&gt; should be used anywhere that a
+    &amp;lt;select&amp;gt;-type field has its values displayed.&lt;/li&gt;
+&lt;/ul&gt;
+
+
+&lt;h1 id=&quot;v36_previous&quot;&gt;[% terms.Bugzilla %] 3.4 Release Notes&lt;/h1&gt;
+
+&lt;ul class=&quot;bz_toc&quot;&gt;
+  &lt;li&gt;&lt;a href=&quot;#v34_introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v34_point&quot;&gt;Updates in this 3.4.x Release&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v34_req&quot;&gt;Minimum Requirements&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v34_feat&quot;&gt;New Features and Improvements&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v34_issues&quot;&gt;Outstanding Issues&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v34_upgrading&quot;&gt;Notes On Upgrading From a Previous Version&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v34_code_changes&quot;&gt;Code Changes Which May Affect 
+    Customizations&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v34_previous&quot;&gt;Release Notes for Previous Versions&lt;/a&gt;&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h2 id=&quot;v34_introduction&quot;&gt;Introduction&lt;/h2&gt;
+
+&lt;p&gt;This is [% terms.Bugzilla %] 3.4! [% terms.Bugzilla %] 3.4 brings a lot
+  of great enhancements for [% terms.Bugzilla %] over previous versions,
+  with various improvements to the user interface, lots of interesting new
+  features, and many long-standing requests finally being addressed.&lt;/p&gt;
+
+&lt;p&gt;If you're upgrading, make sure to read &lt;a href=&quot;#v34_upgrading&quot;&gt;Notes
+  On Upgrading From a Previous Version&lt;/a&gt;. If you are upgrading from a release
+  before 3.2, make sure to read the release notes for all the 
+  &lt;a href=&quot;#v34_previous&quot;&gt;previous versions&lt;/a&gt; in between your version
+  and this one, &lt;strong&gt;particularly the Upgrading section of each
+  version's release notes&lt;/strong&gt;.&lt;/p&gt;
+
+&lt;p&gt;We would like to thank &lt;a href=&quot;http://www.canonical.com/&quot;&gt;Canonical
+  Ltd.&lt;/a&gt; for funding development of one new feature, and NASA for funding
+  development of several new features through the
+  &lt;a href=&quot;http://www.sjsufoundation.org/&quot;&gt;San Jose State University
+  Foundation&lt;/a&gt;.&lt;/p&gt;
+
+&lt;h2 id=&quot;v34_point&quot;&gt;Updates In This 3.4.x Release&lt;/h2&gt;
+
+&lt;h3&gt;3.4.6&lt;/h3&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;When doing a search that involves &quot;not equals&quot; or &quot;does not contain the
+    string&quot; or similar &quot;negative&quot; search types, the search description that
+    appears at the top of the resulting [% terms.bug %] list will indicate
+    that the search was of that type.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=474738&quot;&gt;[% terms.Bug %] 474738&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;In Internet Explorer, users couldn't easily mark a RESOLVED DUPLICATE
+    [%+ terms.bug %] as REOPENED, due to a JavaScript error.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=546719&quot;&gt;[% terms.Bug %] 546719&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;If you use a &quot;bookmarkable template&quot; to pre-fill forms on
+    the [% terms.bug %]-filing page, and you have custom fields
+    that are only supposed to appear (or only supposed to have certain
+    values) based on the values of other fields, those custom fields will
+    now work properly.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=538211&quot;&gt;[% terms.Bug %] 538211&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;If you have a custom field that's only supposed to appear when
+    a [% terms.bug %]'s resolution is FIXED, it will now behave properly
+    on the [% terms.bug %]-editing form when a user sets the [% terms.bug %]'s
+    status to RESOLVED.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=520993&quot;&gt;[% terms.Bug %] 520993&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;If you are logged-out and using &lt;kbd&gt;request.cgi&lt;/kbd&gt;, the Requester
+    and Requestee fields no longer respect the &lt;kbd&gt;usermatching&lt;/kbd&gt;
+    parameter--they always require full usernames.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=533018&quot;&gt;[% terms.Bug %] 533018&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;If you tried to do a search with too many terms (resulting in a URL
+    that was longer than about 7000 characters), Apache would return a 
+    500 error instead of your search results.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=513989&quot;&gt;[% terms.Bug %] 513989&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;[% terms.Bugzilla %] would sometimes lose fields from your sort order
+    when you added new fields to your sort order.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=470214&quot;&gt;[% terms.Bug %] 470214&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;The Atom format of search results would sometimes be missing the
+    Reporter or Assignee field for some [% terms.bugs %].
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=537834&quot;&gt;[% terms.Bug %] 537834&lt;/a&gt;)
+  &lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h3&gt;3.4.5&lt;/h3&gt;
+
+&lt;p&gt;This release contains fixes for multiple security issues. See the
+  &lt;a href=&quot;http://www.bugzilla.org/security/3.0.10/&quot;&gt;Security Advisory&lt;/a&gt;
+  for details.&lt;/p&gt;
+
+&lt;p&gt;In addition, the following important fixes/changes have been made in
+  this release:&lt;/p&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;Whining was failing if jobqueue.pl was enabled.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=530270&quot;&gt;[% terms.Bug %] 530270&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;The Assignee field was empty in Whine mails.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=511216&quot;&gt;[% terms.Bug %] 511216&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;Administrators can now successfully create user accounts using 
+    editusers.cgi when using the &quot;Env&quot; authentication method.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=483987&quot;&gt;[% terms.Bug %] 483987&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;[% terms.Bug %]mail now uses the timezone of the recipient of the email,
+    when displaying the time a comment was made, instead of the timezone of the
+    person who made the change.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=534587&quot;&gt;[% terms.Bug %] 534587&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;&quot;[% terms.bug %] 1234&quot; in comments sometimes would not become a link if
+    word-wrapping happened between &quot;[% terms.bug %]&quot; and the number.
+   (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=514703&quot;&gt;[% terms.Bug %] 514703&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;Running &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; on Windows will no longer pop up an error box
+    about OCI.dll.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=480968&quot;&gt;[% terms.Bug %] 480968&lt;/a&gt;)
+  &lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h3&gt;3.4.4&lt;/h3&gt;
+
+&lt;p&gt;This release contains a fix for a security issue. See the
+  &lt;a href=&quot;http://www.bugzilla.org/security/3.4.3/&quot;&gt;Security Advisory&lt;/a&gt;
+  for details.&lt;/p&gt;
+
+&lt;p&gt;Additionally, this release fixes a few minor [% terms.bugs %].&lt;/p&gt;
+
+&lt;h3&gt;3.4.3&lt;/h3&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;[% terms.Bugzilla %] installations running under mod_perl were leaking
+    about 512K of RAM per page load.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=517793&quot;&gt;[% terms.Bug %] 517793&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;Attachments with Unicode characters in their names were being downloaded
+    with mangled names. 
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=328628&quot;&gt;[% terms.Bug %] 328628&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;Creating custom fields with Unicode in their database column name
+    is now no longer allowed, as it would break [% terms.Bugzilla %]. If you
+    created such a custom field, you should delete it by first marking it 
+    obsolete and then clicking &quot;Delete&quot; in the custom field list, using
+    &lt;a href=&quot;editfields.cgi&quot;&gt;editfields.cgi&lt;/a&gt;.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=525025&quot;&gt;[% terms.Bug %] 525025&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;Clicking &quot;submit only my comment&quot; on the &quot;mid-air collisions&quot; page
+    was leading to a &quot;Suspicious Action&quot; warning.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=514378&quot;&gt;[% terms.Bug %] 514378&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;The XML format of [% terms.abug %] accidentally contained the
+    word-wrapped content of comments instead of the unwrapped content.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=509152&quot;&gt;[% terms.Bug %] 509152&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;You can now do &lt;kbd&gt;./install-module.pl --shell&lt;/kbd&gt; to get a CPAN
+    shell using the configuration of 
+    &lt;a href=&quot;[% docs_urlbase FILTER html %]api/install-module.html&quot;&gt;install-module.pl&lt;/a&gt;,
+    which allows you to do more advanced Perl module installation tasks.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=445875&quot;&gt;[% terms.Bug %] 445875&lt;/a&gt;)
+  &lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h3&gt;3.4.2&lt;/h3&gt;
+
+&lt;p&gt;This release contains fixes for multiple security issues, one of which
+  is highly critical. See the 
+  &lt;a href=&quot;http://www.bugzilla.org/security/3.0.8/&quot;&gt;Security Advisory&lt;/a&gt;
+  for details.&lt;/p&gt;
+
+&lt;p&gt;In addition, the following important fixes/changes have been made in
+  this release:&lt;/p&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;Upgrades from older releases were sometimes failing during UTF-8 
+    conversion with a foreign key error. 
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=508181&quot;&gt;[% terms.Bug %] 508181&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;Sorting [% terms.bug %] lists on certain fields would result in an error.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=510944&quot;&gt;[% terms.Bug %] 510944&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;[% terms.Bug %] update emails had two or three blank lines at the top
+    and between the various sections of the email. There is now only one
+    blank line in each of those places, making these emails more compact.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=73330&quot;&gt;[% terms.Bug %] 73330&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;[% terms.Bug %] email notifications for new [% terms.bugs %] incorrectly
+    had a line saying that the description was &quot;Comment 0&quot;.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=510798&quot;&gt;[% terms.Bug %] 510798&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;Running &lt;kbd&gt;./collectstats.pl --regenerate&lt;/kbd&gt; is now much faster,
+    on the order of 20x or 100x faster.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=286625&quot;&gt;[% terms.Bug %] 286625&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;For users of RHEL, CentOS, Fedora, etc. jobqueue.pl can now automatically
+    be installed as a daemon by running &lt;kbd&gt;./jobqueue.pl install&lt;/kbd&gt;
+    as root. 
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=475403&quot;&gt;[% terms.Bug %] 475403&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;XML-RPC interface responses had an incorrect Content-Length header
+    and would sometimes be truncated, if they contained certain UTF-8
+    characters.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=486306&quot;&gt;[% terms.Bug %] 486306&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;Users who didn't have access to the time-tracking fields would get an
+    empty [% terms.bug %] update email when the time-tracking fields were
+    changed.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=509035&quot;&gt;[% terms.Bug %] 509035&lt;/a&gt;)
+  &lt;/li&gt;
+  &lt;li&gt;In the New Charts, non-public series now no longer show up as selectable
+    if you cannot access them.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=389396&quot;&gt;[% terms.Bug %] 389396&lt;/a&gt;)
+  &lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h3&gt;3.4.1&lt;/h3&gt;
+
+&lt;p&gt;This release contains an important security fix. See the
+  &lt;a href=&quot;http://www.bugzilla.org/security/3.4/&quot;&gt;Security Advisory&lt;/a&gt;
+  for details.&lt;/p&gt;
+
+&lt;h2 id=&quot;v34_req&quot;&gt;Minimum Requirements&lt;/h2&gt;
+
+&lt;p&gt;Any requirements that are new since 3.2.3 will look like
+  &lt;span class=&quot;req_new&quot;&gt;this&lt;/span&gt;.&lt;/p&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;&lt;a href=&quot;#v34_req_perl&quot;&gt;Perl&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v34_req_mysql&quot;&gt;For MySQL Users&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v34_req_pg&quot;&gt;For PostgreSQL Users&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v34_req_oracle&quot;&gt;For Oracle Users&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v34_req_modules&quot;&gt;Required Perl Modules&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v34_req_optional_mod&quot;&gt;Optional Perl Modules&lt;/a&gt;&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h3 id=&quot;v34_req_perl&quot;&gt;Perl&lt;/h3&gt;
+
+&lt;p&gt;Perl v5.8.1&lt;/p&gt;
+
+&lt;h3 id=&quot;v34_req_mysql&quot;&gt;For MySQL Users&lt;/h3&gt; 

+&lt;ul&gt; 
+  &lt;li&gt;MySQL v4.1.2&lt;/li&gt; 
+  &lt;li&gt;&lt;strong&gt;perl module:&lt;/strong&gt; DBD::mysql v4.00&lt;/li&gt; 
+&lt;/ul&gt;
+
+&lt;h3 id=&quot;v34_req_pg&quot;&gt;For PostgreSQL Users&lt;/h3&gt; 

+&lt;ul&gt; 
+  &lt;li&gt;PostgreSQL v8.00.0000&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;perl module:&lt;/strong&gt; DBD::Pg v1.45&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h3 id=&quot;v34_req_oracle&quot;&gt;For Oracle Users&lt;/h3&gt;

+&lt;ul&gt; 
+  &lt;li&gt;Oracle v10.02.0&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;perl module:&lt;/strong&gt; DBD::Oracle v1.19&lt;/li&gt;
+&lt;/ul&gt; 

+&lt;h3 id=&quot;v34_req_modules&quot;&gt;Required Perl Modules&lt;/h3&gt;
+
+&lt;table class=&quot;req_table&quot; border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt; 
+  &lt;tr&gt; 
+    &lt;th&gt;Module&lt;/th&gt; &lt;th&gt;Version&lt;/th&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td&gt;CGI&lt;/td&gt; 
+    &lt;td&gt;3.21&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td class=&quot;req_new&quot;&gt;Digest::SHA&lt;/td&gt; 
+    &lt;td class=&quot;req_new&quot;&gt; (Any)&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td&gt;Date::Format&lt;/td&gt; 
+    &lt;td&gt;2.21&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td class=&quot;req_new&quot;&gt;DateTime&lt;/td&gt; 
+    &lt;td class=&quot;req_new&quot;&gt;0.28&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td class=&quot;req_new&quot;&gt;DateTime::TimeZone&lt;/td&gt; 
+    &lt;td class=&quot;req_new&quot;&gt;0.71&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td&gt;DBI&lt;/td&gt; 
+    &lt;td&gt;1.41&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td&gt;Template&lt;/td&gt; 
+    &lt;td class=&quot;req_new&quot;&gt;2.22&lt;/td&gt; 
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td&gt;Email::Send&lt;/td&gt; 
+    &lt;td&gt;2.00&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td&gt;Email::MIME&lt;/td&gt; 
+    &lt;td&gt;1.861&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td&gt;Email::MIME::Encodings&lt;/td&gt; 
+    &lt;td&gt;1.313&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td&gt;Email::MIME::Modifier&lt;/td&gt; 
+    &lt;td&gt;1.442&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td class=&quot;req_new&quot;&gt;URI&lt;/td&gt; 
+    &lt;td class=&quot;req_new&quot;&gt;(Any)&lt;/td&gt; 
+  &lt;/tr&gt; 
+&lt;/table&gt; 

+&lt;h3 id=&quot;v34_req_optional_mod&quot;&gt;Optional Perl Modules&lt;/h3&gt; 

+&lt;p&gt;The following perl modules, if installed, enable various
+  features of [% terms.Bugzilla %]:&lt;/p&gt;
+
+&lt;table class=&quot;req_table&quot; border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt; 
+  &lt;tr&gt; 
+    &lt;th&gt;Module&lt;/th&gt;
+    &lt;th&gt;Version&lt;/th&gt; 
+    &lt;th&gt;Enables Feature&lt;/th&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td&gt;LWP::UserAgent&lt;/td&gt; 
+    &lt;td&gt;(Any)&lt;/td&gt; 
+    &lt;td&gt;Automatic Update Notifications&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td&gt;Template::Plugin::GD::Image&lt;/td&gt; 
+    &lt;td&gt;(Any)&lt;/td&gt; 
+    &lt;td&gt;Graphical Reports&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td&gt;GD::Text&lt;/td&gt; 
+    &lt;td&gt;(Any)&lt;/td&gt; 
+    &lt;td&gt;Graphical Reports&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td&gt;GD::Graph&lt;/td&gt; 
+    &lt;td&gt;(Any)&lt;/td&gt; 
+    &lt;td&gt;Graphical Reports&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td&gt;GD&lt;/td&gt; 
+    &lt;td&gt;1.20&lt;/td&gt; 
+    &lt;td&gt;Graphical Reports, New Charts, Old Charts&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td&gt;Email::MIME::Attachment::Stripper&lt;/td&gt; 
+    &lt;td&gt;(Any)&lt;/td&gt; 
+    &lt;td&gt;Inbound Email&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td&gt;Email::Reply&lt;/td&gt; 
+    &lt;td&gt;(Any)&lt;/td&gt; 
+    &lt;td&gt;Inbound Email&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td&gt;Net::LDAP&lt;/td&gt; 
+    &lt;td&gt;(Any)&lt;/td&gt; 
+    &lt;td&gt;LDAP Authentication&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td class=&quot;req_new&quot;&gt;TheSchwartz&lt;/td&gt; 
+    &lt;td class=&quot;req_new&quot;&gt;(Any)&lt;/td&gt; 
+    &lt;td&gt;Mail Queueing&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td class=&quot;req_new&quot;&gt;Daemon::Generic&lt;/td&gt; 
+    &lt;td class=&quot;req_new&quot;&gt;(Any)&lt;/td&gt; 
+    &lt;td&gt;Mail Queueing&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td&gt;HTML::Parser&lt;/td&gt; 
+    &lt;td&gt;3.40&lt;/td&gt; 
+    &lt;td&gt;More HTML in Product/Group Descriptions&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td&gt;HTML::Scrubber&lt;/td&gt; 
+    &lt;td&gt;(Any)&lt;/td&gt; 
+    &lt;td&gt;More HTML in Product/Group Descriptions&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td&gt;XML::Twig&lt;/td&gt; 
+    &lt;td&gt;(Any)&lt;/td&gt; 
+    &lt;td&gt;Move [% terms.Bugs %] Between Installations&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td&gt;MIME::Parser&lt;/td&gt; 
+    &lt;td&gt;5.406&lt;/td&gt; 
+    &lt;td&gt;Move [% terms.Bugs %] Between Installations&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td&gt;Chart::Base&lt;/td&gt; 
+    &lt;td&gt;1.0&lt;/td&gt; 
+    &lt;td&gt;New Charts, Old Charts&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td&gt;Image::Magick&lt;/td&gt; 
+    &lt;td&gt;(Any)&lt;/td&gt; 
+    &lt;td&gt;Optionally Convert BMP Attachments to PNGs&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td&gt;PatchReader&lt;/td&gt; 
+    &lt;td&gt;0.9.4&lt;/td&gt; 
+    &lt;td&gt;Patch Viewer&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td&gt;Authen::Radius&lt;/td&gt; 
+    &lt;td&gt;(Any)&lt;/td&gt; 
+    &lt;td&gt;RADIUS Authentication&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td&gt;Authen::SASL&lt;/td&gt; 
+    &lt;td&gt;(Any)&lt;/td&gt; 
+    &lt;td&gt;SMTP Authentication&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td&gt;SOAP::Lite&lt;/td&gt; 
+    &lt;td&gt;0.710.06&lt;/td&gt; 
+    &lt;td&gt;XML-RPC Interface&lt;/td&gt; 
+  &lt;/tr&gt; 
+  &lt;tr&gt; 
+    &lt;td&gt;mod_perl2&lt;/td&gt; 
+    &lt;td&gt;1.999022&lt;/td&gt; 
+    &lt;td&gt;mod_perl&lt;/td&gt; 
+  &lt;/tr&gt; 
+&lt;/table&gt; 
+
+&lt;h2 id=&quot;v34_feat&quot;&gt;New Features and Improvements&lt;/h2&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;&lt;a href=&quot;#v34_feat_enter&quot;&gt;Simple [% terms.Bug %] Filing&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v34_feat_index&quot;&gt;New Home Page&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v34_feat_spam&quot;&gt;Email Addresses Hidden From Logged-Out 
+    Users&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v34_feat_urls&quot;&gt;Shorter Search URLs&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v34_feat_async&quot;&gt;Asynchronous Email Sending&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v34_feat_tz&quot;&gt;Dates and Times Displayed In User's Time
+    Zone&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v34_feat_vis&quot;&gt;Custom Fields That Only Appear When
+    Another Field Has a Particular Value&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v34_feat_vals&quot;&gt;Custom Fields Whose List of Values
+    Change Depending on the Value of Another Field&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v34_feat_bugid&quot;&gt;New Custom Field Type: 
+    [%+ terms.Bug %] ID&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v34_feat_see&quot;&gt;&quot;See Also&quot; Field&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v34_feat_cols&quot;&gt;Re-order Columns in Search Results&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v34_feat_desc&quot;&gt;Search Descriptions&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v34_feat_other&quot;&gt;Other Enhancements and Changes&lt;/a&gt;&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h3 id=&quot;v34_feat_enter&quot;&gt;Simple [% terms.Bug %] Filing&lt;/h3&gt;
+
+&lt;p&gt;When entering a new [% terms.bug %], the vast majority of fields are
+  now hidden by default, which enormously simplifies the bug-filing form. 
+  You can click &quot;Show Advanced Fields&quot; to show all the fields, if you want
+  them. [%+ terms.Bugzilla %] remembers whether you last used the &quot;Advanced&quot;
+  or &quot;Simple&quot; version of the [% terms.bug %]-entry form, and will display the
+  same version to you again next time you file [% terms.abug %].&lt;/p&gt;
+
+&lt;h3 id=&quot;v34_feat_index&quot;&gt;New Home Page&lt;/h3&gt;
+
+&lt;p&gt;[% terms.Bugzilla %]'s front page has been redesigned to be better at
+  guiding new users into the activities that they most commonly want to
+  do. Further enhancements to the home page are coming in future versions
+  of [% terms.Bugzilla %].&lt;/p&gt;
+
+&lt;h3 id=&quot;v34_feat_spam&quot;&gt;Email Addresses Hidden From Logged-Out Users&lt;/h3&gt;
+
+&lt;p&gt;To help prevent spam to [% terms.Bugzilla %] users, all email addresses
+  stored in [% terms.Bugzilla %] are now displayed only if you are logged in.
+  If you are logged out, only the part before the &quot;@&quot; of the email address is
+  displayed. This includes [% terms.bug %] lists, viewing [% terms.bugs %], the
+  XML format of [% terms.abug %], and any other place in the web interface that
+  an email address could appear.&lt;/p&gt;
+
+&lt;p&gt;Email addresses are not filtered out of [% terms.bug %] comments.
+  The WebService still returns full email addresses, even if you are logged
+  out.&lt;/p&gt;
+
+&lt;h3 id=&quot;v34_feat_urls&quot;&gt;Shorter Search URLs&lt;/h3&gt;
+
+&lt;p&gt;When submitting a search, all the unused fields are now stripped from
+  the URL, so search URLs are much more meaningful, and much shorter.&lt;/p&gt;
+
+&lt;h3 id=&quot;v34_feat_async&quot;&gt;Asynchronous Email Sending&lt;/h3&gt;
+
+&lt;p&gt;The largest performance problem in former versions of [% terms.Bugzilla %]
+  was that when updating [% terms.bugs %], email would be sent immediately
+  to every user who needed to be notified, and &lt;kbd&gt;process_bug.cgi&lt;/kbd&gt;
+  would wait for the emails to be sent before continuing.&lt;/p&gt;
+
+&lt;p&gt;Now [% terms.Bugzilla %] is capable of queueing emails to be sent
+  while [% terms.abug %] is being updated, and sending them in the
+  background. This requires the administrator to run a daemon
+  that comes with [% terms.Bugzilla %], named
+  &lt;a href=&quot;[% docs_urlbase FILTER html %]api/jobqueue.html&quot;&gt;jobqueue.pl&lt;/a&gt;,
+  and to enable the &lt;a href=&quot;editparams.cgi?section=mta#use_mailer_queue&quot;&gt;
+  use_mailer_queue&lt;/a&gt; parameter.&lt;/p&gt;
+
+&lt;p&gt;Using the background email-sending daemon instead of sending mail directly
+  should result in a very large speed-up for updating [% terms.bugs %],
+  particularly on larger installations.&lt;/p&gt;
+
+&lt;h3 id=&quot;v34_feat_tz&quot;&gt;Dates and Times Displayed In User's Time Zone&lt;/h3&gt;
+
+&lt;p&gt;Users can now select what time zone they are in and [% terms.Bugzilla %]
+  will adjust displayed times to be correct for their time zone. However,
+  times the user inputs are unfortunately still in [% terms.Bugzilla %]'s
+  time zone.&lt;/p&gt;
+
+&lt;h3 id=&quot;v34_feat_vis&quot;&gt;Custom Fields That Only Appear When Another Field
+    Has a Particular Value&lt;/h3&gt;
+
+&lt;p&gt;When creating a new custom field (or updating the definition of
+  an existing custom field), you can now say that &quot;this field only
+  appears when field X has value Y&quot;. (In the future, you will be able
+  to select multiple values for &quot;Y&quot;, so a field will appear when any
+  one of those values is selected.)&lt;/p&gt;
+
+&lt;p&gt;This feature only hides fields--it doesn't make their values go away.
+  So [% terms.bugs %] will still show up in searches for that field's
+  value, but the field won't appear in the user interface.&lt;/p&gt;
+
+&lt;p&gt;This is a good way of making Product-specific fields.&lt;/p&gt;
+
+&lt;h3 id=&quot;v34_feat_vals&quot;&gt;Custom Fields Whose List of Values Change
+    Depending on the Value of Another Field&lt;/h3&gt;
+
+&lt;p&gt;When creating a drop-down or multiple-selection custom field, you can
+  now specify that another field &quot;controls the values&quot; of this field.
+  Then, when adding values to this field, you can say that a particular
+  value only appears when the other field is set to a particular
+  value.&lt;/p&gt;
+
+&lt;p&gt;Here's an example: Let's say that we create a field called &quot;Colors&quot;,
+  and we make the Product field &quot;control the values&quot; for Colors. Then we
+  add Blue, Red, Black, and Yellow as legal values for the &quot;Colors&quot; field.
+  Now we can say that &quot;Blue&quot; and &quot;Red&quot; only appear as valid choices in 
+  Product A, &quot;Yellow&quot; only appears in Product B, but &quot;Black&quot; &lt;em&gt;always&lt;/em&gt;
+  appears.&lt;/p&gt;
+
+&lt;p&gt;One thing to note is that this feature only controls what values appear in
+  the &lt;em&gt;user interface&lt;/em&gt;. [% terms.Bugzilla %] itself will still accept
+  any combination of values as valid, in the backend.&lt;/p&gt;
+
+&lt;h3 id=&quot;v34_feat_bugid&quot;&gt;New Custom Field Type: [% terms.Bug %] ID&lt;/h3&gt;
+
+&lt;p&gt;You can now create a custom field that holds a reference to a single
+  valid [% terms.bug %] ID. In the future this will be enhanced to allow
+  [%+ terms.bugs %] to refer to each other via this field.&lt;/p&gt;
+
+&lt;h3 id=&quot;v34_feat_see&quot;&gt;&quot;See Also&quot; Field&lt;/h3&gt;
+
+&lt;p&gt;We have added a new standard field called &quot;See Also&quot; to 
+  [%+ terms.Bugzilla %]. In this field, you can put URLs to multiple 
+  [%+ terms.bugs %] in any [% terms.Bugzilla %] installation, to indicate
+  that those [% terms.bugs %] are related to this one. It also supports
+  adding URLs to [% terms.bugs %] in 
+  &lt;a href=&quot;http://launchpad.net/&quot;&gt;Launchpad&lt;/a&gt;.&lt;/p&gt;
+
+&lt;p&gt;Right now, the field just validates the URLs and then displays them, but
+  in the future, it will grab information from the other installation about
+  the [% terms.bug %] and display it here, and possibly even update the
+  other installation.&lt;/p&gt;
+
+&lt;p&gt;If your installation does not need this field, you can hide it by disabling
+  the &lt;a href=&quot;editparams.cgi?section=bugfields#use_see_also&quot;&gt;use_see_also
+  parameter&lt;/a&gt;.&lt;/p&gt;
+
+&lt;h3 id=&quot;v34_feat_cols&quot;&gt;Re-order Columns in Search Results&lt;/h3&gt;
+
+&lt;p&gt;There is a new interface for choosing what columns appear in search
+  results, which allows you to change the order in which columns appear
+  from left to right when viewing the [% terms.bug %] list.&lt;/p&gt;
+
+&lt;h3 id=&quot;v34_feat_desc&quot;&gt;Search Descriptions&lt;/h3&gt;
+
+&lt;p&gt;When displaying search results, [% terms.Bugzilla %] will now show
+  a brief description of what you searched for, at the top of the
+  [%+ terms.bug %] list.&lt;/p&gt;
+
+&lt;h3 id=&quot;v34_feat_other&quot;&gt;Other Enhancements and Changes&lt;/h3&gt;
+
+&lt;h4&gt;Enhancements for Users&lt;/h4&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;You can now log in from every page, using the login form that appears
+    in the header or footer when you click &quot;Log In&quot;.&lt;/li&gt;
+  &lt;li&gt;When viewing [% terms.abug %], obsolete attachments are now
+    hidden from the attachment list by default. You can show them
+    by clicking &quot;Show Obsolete&quot; at the bottom of the attachment list.&lt;/li&gt;
+  &lt;li&gt;In the Email Preferences, you can now choose to get email when
+    a new [% terms.bug %] report is filed and you have a particular 
+    role on it.&lt;/li&gt;
+  &lt;li&gt;When resolving a mid-air collision, you can now choose to submit
+    only your comment.&lt;/li&gt;
+  &lt;li&gt;You can now set the Blocks and Depends On field on the &quot;Change
+    Several [% terms.Bugs %] At Once&quot; page.&lt;/li&gt;
+  &lt;li&gt;If your installation uses the &quot;insidergroup&quot; feature, you can now add
+    private comments on the &quot;Change Several [% terms.Bugs %] At Once&quot; 
+    page.&lt;/li&gt;
+  &lt;li&gt;When viewing a search result, you can now hover over any abbreviated
+    field to see its full value.&lt;/li&gt;
+  &lt;li&gt;When logging out, users are now redirected to the main page of
+    [%+ terms.Bugzilla %] instead of an empty page.&lt;/li&gt;
+  &lt;li&gt;When editing [% terms.abug %], text fields (except the comment box) now
+    grow longer when you widen your browser window.&lt;/li&gt;
+  &lt;li&gt;When viewing [% terms.abug %], the Depends On and Blocks list will
+    display [% terms.abug %]'s alias if it has one, instead of its id.
+    Also, closed [% terms.bugs %] will be sorted to the end of the list.&lt;/li&gt;
+
+  &lt;li&gt;If you use the time-tracking features of [% terms.Bugzilla %], and
+    you enable the time-tracking related columns in a search result,
+    then you will see a summary of the time-tracking data at the
+    bottom of the search result.&lt;/li&gt;
+  &lt;li&gt;For users of time-tracking, the &lt;kbd&gt;summarize_time.cgi&lt;/kbd&gt; page
+    now contains more data.&lt;/li&gt;
+
+  &lt;li&gt;When viewing an attachment's details page while you are logged-out,
+    flags are no longer shown as editable.&lt;/li&gt;
+  &lt;li&gt;Cloning [% terms.abug %] will now retain the &quot;Blocks&quot; and &quot;Depends On&quot;
+    fields from the [% terms.bug %] being cloned.&lt;/li&gt;
+  &lt;li&gt;[% terms.Bug %]mail for new [% terms.bugs %] will now indicate
+    what security groups the [% terms.bug %] has been restricted to.&lt;/li&gt;
+  &lt;li&gt;You can now use any custom drop-down field as an axis for a tabular
+    or graphical report.&lt;/li&gt;
+  &lt;li&gt;The &lt;kbd&gt;X-Bugzilla-Type&lt;/kbd&gt; header in emails sent by 
+    [%+ terms.Bugzilla %] is now &quot;new&quot; for [% terms.bug %]mail sent for
+    newly-filed [% terms.bugs %], and &quot;changed&quot; for emails having to do
+    with updated [% terms.bugs %].&lt;/li&gt;
+  &lt;li&gt;Mails sent by the &quot;Whining&quot; system now contain the header
+    &lt;kbd&gt;X-Bugzilla-Type: whine&lt;/kbd&gt;.&lt;/li&gt;
+  &lt;li&gt;[% terms.bug %]mail now contains a X-Bugzilla-URL header to uniquely
+    identify which [% terms.Bugzilla %] installation the email came from.&lt;/li&gt;
+  &lt;li&gt;If you input an invalid regular expression anywhere in
+    [%+ terms.Bugzilla %], it will now tell you explicitly instead of failing
+    cryptically.&lt;/li&gt;
+  &lt;li&gt;The &lt;kbd&gt;duplicates.xul&lt;/kbd&gt; page (which wasn't used by very many
+    people) is now gone.&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h4&gt;Enhancements for Administrators and Developers&lt;/h4&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;[% terms.Bugzilla %] now uses the SHA-256 algorithm (a variant of 
+    SHA-2) to encrypt passwords in the database, instead of using Unix's
+    &quot;crypt&quot; function. This allows passwords longer than eight characters
+    to actually be effective. Each user's password will be converted to
+    SHA-256 the first time they log in after you upgrade to 
+    [%+ terms.Bugzilla %] 3.4 or later.&lt;/li&gt;
+  &lt;li&gt;If you are using database replication with [% terms.Bugzilla %],
+    many more scripts now take advantage of the read-only slave (the 
+    &quot;shadowdb&quot;). It may be safe to open up &lt;kbd&gt;show_bug.cgi&lt;/kbd&gt;
+    to search-engine indexing by editing your &lt;kbd&gt;robots.txt&lt;/kbd&gt; file,
+    now, if your [% terms.Bugzilla %] is on fast-enough hardware.&lt;/li&gt;
+  &lt;li&gt;The database now uses foreign keys to enforce the validity of
+    relationships between tables. Not every single table has all its 
+    foreign keys yet, but most do.&lt;/li&gt;
+  &lt;li&gt;Various parameters have been removed, in an effort to de-clutter
+    the parameter interface and simplify [% terms.Bugzilla %]'s code.
+    The parameters that were removed were: timezone, supportwatchers,
+    maxpatchsize, commentonclearresolution, commentonreassignbycomponent,
+    showallproducts. They have all been replaced with sensible default
+    behaviors. (For example, user watching is now always enabled.)&lt;/li&gt;
+  &lt;li&gt;When adding &lt;code&gt;&amp;amp;debug=1&lt;/code&gt; to the end of a 
+    &lt;kbd&gt;buglist.cgi&lt;/kbd&gt; URL, [% terms.Bugzilla %] will now also do an
+    EXPLAIN on the query, to help debug performance issues.&lt;/li&gt;
+  &lt;li&gt;When editing flag types in the administrative interface, you can now
+    see how many flags of each type have been set.&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h4&gt;WebService Changes&lt;/h4&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;Various functions have been added to the WebService:
+    &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/WebService/Bug.html#history&quot;&gt;B[% %]ug.history&lt;/a&gt;,
+    &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/WebService/Bug.html#search&quot;&gt;B[% %]ug.search&lt;/a&gt;,
+    &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/WebService/Bug.html#comments&quot;&gt;B[% %]ug.comments&lt;/a&gt;,
+    &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/WebService/Bug.html#update_see_also&quot;&gt;B[% %]ug.update_see_also&lt;/a&gt;,
+    &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/WebService/User.html#get&quot;&gt;User.get&lt;/a&gt;,
+    and &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/WebService/Bugzilla.html#time&quot;&gt;B[% %]ugzilla.time&lt;/a&gt;
+    (&lt;kbd&gt;B[% %]ugzilla.timezone&lt;/kbd&gt; is now deprecated).
+  &lt;/li&gt;
+  &lt;li&gt;For network efficiency, you can now limit which fields are returned 
+    from certain WebService functions, like &lt;kbd&gt;User.get&lt;/kbd&gt;.&lt;/li&gt;
+  &lt;li&gt;There is now a &quot;permissive&quot; argument for the &lt;kbd&gt;B[% %]ug.get&lt;/kbd&gt;
+    WebService function, which causes it not to throw an error when you
+    ask for [% terms.bugs %] you can't see.&lt;/li&gt;
+
+  &lt;li&gt;The &lt;kbd&gt;B[% %]ug.get&lt;/kbd&gt; method now returns many more fields.&lt;/li&gt;
+  &lt;li&gt;The &lt;kbd&gt;B[% %]ug.add_comment&lt;/kbd&gt; method now returns the ID of the comment
+    that was just added.&lt;/li&gt;
+  &lt;li&gt;The &lt;kbd&gt;B[% %]ug.add_comment&lt;/kbd&gt; method will now throw an error if you
+    try to add a private comment but do not have the correct permissions.
+    (In previous versions, it would just silently ignore the &lt;kbd&gt;private&lt;/kbd&gt;
+    argument if you didn't have the correct permissions.)&lt;/li&gt;
+  &lt;li&gt;Many WebService function parameters now take individual values in
+    addition to arrays.&lt;/li&gt;
+  &lt;li&gt;The WebService now validates input types--it makes sure that dates
+    are in the right format, that ints are actually ints, etc. It will throw
+    an error if you send it invalid data. It also accepts empty ints, doubles,
+    and dateTimes, and translates them to &lt;kbd&gt;undef&lt;/kbd&gt;.&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h2 id=&quot;v34_issues&quot;&gt;Outstanding Issues&lt;/h2&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=423439&quot;&gt;
+    [%- terms.Bug %] 423439&lt;/a&gt;: Tabs in comments will be converted
+    to four spaces, due to a b&lt;!-- --&gt;ug in Perl as of Perl 5.8.8.&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=69621&quot;&gt;
+    [%- terms.Bug %] 69621&lt;/a&gt;: If you rename or remove a keyword that is
+    in use on [% terms.bugs %], you will need to rebuild the &quot;keyword cache&quot;
+    by running &lt;a href=&quot;sanitycheck.cgi&quot;&gt;sanitycheck.cgi&lt;/a&gt; and choosing 
+    the option to rebuild the cache when it asks. Otherwise keywords may 
+    not show up properly in search results.&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=89822&quot;&gt;
+    [%- terms.Bug %] 89822&lt;/a&gt;: When changing multiple [% terms.bugs %] at 
+    the same time, there is no &quot;mid-air collision&quot; protection.&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=276230&quot;&gt;
+    [%- terms.Bug %] 276230&lt;/a&gt;: The support for restricting access to 
+    particular Categories of New Charts is not complete. You should treat 
+    the 'chartgroup' Param as the only access mechanism available.&lt;br&gt;
+    However, charts migrated from Old Charts will be restricted to 
+    the groups that are marked MANDATORY for the corresponding Product.
+    There is currently no way to change this restriction, and the 
+    groupings will not be updated if the group configuration
+    for the Product changes.&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=370370&quot;&gt;
+    [%- terms.Bug %] 370370&lt;/a&gt;: mod_perl support is currently not
+    working on Windows machines.&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h2 id=&quot;v34_upgrading&quot;&gt;Notes On Upgrading From a Previous Version&lt;/h2&gt;
+
+&lt;p&gt;When upgrading to 3.4, &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; will create foreign keys
+  for many columns in the database. Before doing this, it will check the
+  database for consistency. If there are an unresolvable consistency
+  problems, it will tell you what table and column in the database contain
+  the bad values, and which values are bad. If you don't know what else to do,
+  you can always delete the database records which contain the bad values by
+  logging in to your database and running the following command:&lt;/p&gt;
+
+&lt;p&gt;&lt;code&gt;DELETE FROM &lt;var&gt;table&lt;/var&gt; WHERE &lt;var&gt;column&lt;/var&gt; IN 
+  (&lt;var&gt;1, 2, 3, 4&lt;/var&gt;)&lt;/code&gt;&lt;/p&gt;
+
+&lt;p&gt;Just replace &quot;table&quot; and &quot;column&quot; with the name of the table 
+  and column that &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; mentions, and &quot;1, 2, 3, 4&quot;
+  with the invalid values that &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; prints out.&lt;/p&gt;
+
+&lt;p&gt;Remember that you should always back up your database before doing
+  an upgrade.&lt;/p&gt;
+
+&lt;h2 id=&quot;v34_code_changes&quot;&gt;Code Changes Which May Affect Customizations&lt;/h2&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;&lt;kbd&gt;checksetup.pl&lt;/kbd&gt; now re-writes the &lt;kbd&gt;localconfig&lt;/kbd&gt;
+    file every time it runs, keeping the current values set (if there
+    are any), but moving any unexpected variables into a file called
+    &lt;kbd&gt;localconfig.old&lt;/kbd&gt;. If you want to continue having custom
+    varibles in &lt;kbd&gt;localconfig&lt;/kbd&gt;, you will have to add them to
+    the &lt;code&gt;LOCALCONFIG_VARS&lt;/code&gt; constant in 
+    &lt;kbd&gt;Bugzilla::Install::Localconfig&lt;/kbd&gt;.&lt;/li&gt;
+  &lt;li&gt;&lt;kbd&gt;Bugzilla::Object-&amp;gt;update()&lt;/kbd&gt; now returns something different
+    in list context than it does in scalar context.&lt;/li&gt;
+  &lt;li&gt;&lt;kbd&gt;Bugzilla::Object-&amp;gt;check()&lt;/kbd&gt; now can take object
+    ids in addition to names. Just pass in &lt;code&gt;{ id =&amp;gt; $some_value
+    }&lt;/code&gt;.&lt;/li&gt;
+  &lt;li&gt;Instead of being defined in &lt;kbd&gt;buglist.cgi&lt;/kbd&gt;, columns for
+    search results are now defined in a subroutine called &lt;code&gt;COLUMNS&lt;/code&gt;
+    in &lt;kbd&gt;Bugzilla::Search&lt;/kbd&gt;. The data now mostly comes from the
+    &lt;kbd&gt;fielddefs&lt;/kbd&gt; table in the database. Search.pm now takes a list
+    of column names from fielddefs for its &lt;kbd&gt;fields&lt;/kbd&gt; argument instead 
+    of literal SQL columns.&lt;/li&gt;
+  &lt;li&gt;&lt;kbd&gt;Bugzilla::Field-&amp;gt;legal_values&lt;/kbd&gt; now returns an array of
+    &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/Field/Choice.html&quot;&gt;Bugzilla::Field::Choice&lt;/a&gt;
+    objects instead of an array of strings. Bugzilla::Field::Choice will be used
+    in more places, in the future.&lt;/li&gt;
+  &lt;li&gt;We now use &lt;kbd&gt;Bugzilla::Bug-&amp;gt;check()&lt;/kbd&gt; instead of 
+    &lt;kbd&gt;ValidateBugId&lt;/kbd&gt;.&lt;/li&gt;
+  &lt;li&gt;The &lt;kbd&gt;groups&lt;/kbd&gt; and &lt;kbd&gt;bless_groups&lt;/kbd&gt; methods in 
+    &lt;kbd&gt;Bugzilla::User&lt;/kbd&gt; now return an arrayref of 
+    &lt;kbd&gt;Bugzilla::Group&lt;/kbd&gt; objects instead of a hashref with
+    group ids and group names.&lt;/li&gt;
+  &lt;li&gt;Standard [% terms.Bugzilla %] drop-down fields now have their type
+    set to &lt;kbd&gt;FIELD_TYPE_SINGLE_SELECT&lt;/kbd&gt; in the fielddefs table.&lt;/li&gt;
+  &lt;li&gt;&lt;kbd&gt;Bugzilla-&amp;gt;usage_mode&lt;/kbd&gt; now defaults to 
+    &lt;kbd&gt;USAGE_MODE_CMDLINE&lt;/kbd&gt; if we are not running inside a web
+    server.&lt;/li&gt;
+  &lt;li&gt;We no longer delete environment variables like &lt;kbd&gt;$ENV{PATH}&lt;/kbd&gt;
+    automatically unless we're actually running in taint mode.&lt;/li&gt;
+  &lt;li&gt;We are now using YUI 2.6.0.&lt;/li&gt;
+  &lt;li&gt;In &lt;a href=&quot;config.cgi?ctype=rdf&quot;&gt;the RDF format of config.cgi&lt;/a&gt;,
+    the &quot;resource&quot; attribute for flags now contains &quot;flag.cgi&quot; instead
+    of &quot;flags.cgi&quot;.&lt;/li&gt;
+&lt;/ul&gt;
+
+
+
+
+
+
+
+&lt;h1 id=&quot;v34_previous&quot;&gt;[% terms.Bugzilla %] 3.2 Release Notes&lt;/h1&gt;
+
+&lt;h2&gt;Table of Contents&lt;/h2&gt;
+
+&lt;ul class=&quot;bz_toc&quot;&gt;
+  &lt;li&gt;&lt;a href=&quot;#v32_introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v32_point&quot;&gt;Updates In This 3.2.x Release&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v32_security&quot;&gt;Security Fixes In This 3.2.x Release&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v32_req&quot;&gt;Minimum Requirements&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v32_feat&quot;&gt;New Features and Improvements&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v32_issues&quot;&gt;Outstanding Issues&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v32_upgrading&quot;&gt;How to Upgrade From An Older Version&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v32_code_changes&quot;&gt;Code Changes Which May Affect 
+    Customizations&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v32_previous&quot;&gt;Release Notes for Previous Versions&lt;/a&gt;&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h2 id=&quot;v32_introduction&quot;&gt;Introduction&lt;/h2&gt;
+
+&lt;p&gt;Welcome to [% terms.Bugzilla %] 3.2! This is our first major feature
+  release since [% terms.Bugzilla %] 3.0, and it brings a lot of great
+  improvements and polish to the [% terms.Bugzilla %] experience.&lt;/p&gt;
+
+&lt;p&gt;If you're upgrading, make sure to read &lt;a href=&quot;#v32_upgrading&quot;&gt;How to
+  Upgrade From An Older Version&lt;/a&gt;. If you are upgrading from a release
+  before 3.0, make sure to read the release notes for all the 
+  &lt;a href=&quot;#v32_previous&quot;&gt;previous versions&lt;/a&gt; in between your version
+  and this one, &lt;strong&gt;particularly the &quot;Notes For Upgraders&quot; section of each
+  version's release notes&lt;/strong&gt;.&lt;/p&gt;
+
+&lt;h2 id=&quot;v32_point&quot;&gt;Updates in this 3.2.x Release&lt;/h2&gt;
+
+&lt;p&gt;This section describes what's changed in the most recent b&lt;!-- --&gt;ug-fix
+  releases of [% terms.Bugzilla %] after 3.2. We only list the
+  most important fixes in each release. If you want a detailed list of
+  &lt;em&gt;everything&lt;/em&gt; that's changed in each version, you should use our
+  &lt;a href=&quot;http://www.bugzilla.org/status/changes.html&quot;&gt;Change Log 
+  Page&lt;/a&gt;.&lt;/p&gt;
+
+&lt;h3&gt;3.2.3&lt;/h3&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;[% terms.Bugzilla %] is now compatible with MySQL 5.1.x versions 5.1.31
+    and greater.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=480001&quot;&gt;[% terms.Bug %] 480001&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;On Windows, [% terms.Bugzilla %] sometimes would send mangled emails 
+    (that would often fail to send).
+  (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=467920&quot;&gt;[% terms.Bug %] 467920&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;&lt;code&gt;recode.pl&lt;/code&gt; would sometimes crash when trying to convert
+    databases from older versions of [% terms.Bugzilla %].
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=431201&quot;&gt;[% terms.Bug %] 431201&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;Running a saved search with Unicode characters in its name would
+    cause [% terms.Bugzilla %] to crash.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=477513&quot;&gt;[% terms.Bug %] 477513&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;[% terms.Bugzilla %] clients like Mylyn can now update [% terms.bugs %]
+    again (the [% terms.bug %] XML format now contains a &quot;token&quot; element that
+    can be used when updating [% terms.abug %]).
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=476678&quot;&gt;[% terms.Bug %] 476678&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;For installations using the &lt;code&gt;shadowdb&lt;/code&gt; parameter, 
+    [%+ terms.Bugzilla %] was accidentally writing to the &quot;tokens&quot; table
+    in the shadow database (instead of the master database) when using the
+    &quot;Change Several [% terms.Bugs %] at Once&quot; page.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=476943&quot;&gt;[% terms.Bug  %] 476943&lt;/a&gt;)&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;p&gt;This release also contains a security fix. See the
+  &lt;a href=&quot;#v32_security&quot;&gt;Security Fixes Section&lt;/a&gt; for details.&lt;/p&gt;
+
+&lt;h3&gt;3.2.2&lt;/h3&gt;
+
+&lt;p&gt;This release fixes one security issue that is critical for installations
+  running 3.2.1 under mod_perl. See the 
+  &lt;a href=&quot;http://www.bugzilla.org/security/3.0.7/&quot;&gt;Security Advisory&lt;/a&gt;
+  for details.&lt;/p&gt;
+
+&lt;h3&gt;3.2.1&lt;/h3&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;Attachments, charts, and graphs would sometimes be garbled on Windows.
+  (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=464992&quot;&gt;[% terms.Bug %] 464992&lt;/a&gt;)&lt;/li&gt;
+
+  &lt;li&gt;Saving changes to parameters would sometimes fail silently (particularly
+    on Windows when the web server didn't have the right permissions to
+    update the &lt;code&gt;params&lt;/code&gt; file). [% terms.Bugzilla %] will now
+    throw an error in this case, telling you what is wrong.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=347707&quot;&gt;[% terms.Bug %] 347707&lt;/a&gt;)&lt;/li&gt;
+
+  &lt;li&gt;If you were using the &lt;code&gt;usemenuforusers&lt;/code&gt; parameter,
+    and [% terms.abug %] was assigned to (or had a QA Contact of) a disabled
+    user, that field would be reset to the first user in the list when
+    updating [% terms.abug %].
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=465589&quot;&gt;[% terms.Bug %] 465589&lt;/a&gt;)&lt;/li&gt;
+
+  &lt;li&gt;If you were using the &lt;code&gt;PROJECT&lt;/code&gt; environment variable
+    to have multiple [% terms.Bugzilla %] installations using one codebase,
+    project-specific templates were being ignored. 
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=467324&quot;&gt;[% terms.Bug %] 467324&lt;/a&gt;)&lt;/li&gt;
+
+  &lt;li&gt;Some versions of the SOAP::Lite Perl module had a b[% %]ug that caused
+    [%+ terms.Bugzilla %]'s XML-RPC service to break. 
+    &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; now checks for these bad versions and 
+    will reject them.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=468009&quot;&gt;[% terms.Bug %] 468009&lt;/a&gt;)&lt;/li&gt;
+
+  &lt;li&gt;The font sizes in various places were too small, when using the
+    Classic skin.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=469136&quot;&gt;[% terms.Bug %] 469136&lt;/a&gt;)&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h2 id=&quot;v32_security&quot;&gt;Security Fixes In This 3.2.x Release&lt;/h2&gt;
+
+&lt;h3&gt;3.2.3&lt;/h3&gt;
+
+&lt;p&gt;This release fixes one security issue related to attachments. See the
+  &lt;a href=&quot;http://www.bugzilla.org/security/3.2.2/&quot;&gt;Security Advisory&lt;/a&gt;
+  for details.&lt;/p&gt;
+
+&lt;h3&gt;3.2.2&lt;/h3&gt;
+
+&lt;p&gt;This release fixes one security issue that is critical for installations
+  running 3.2.1 under mod_perl. See the 
+  &lt;a href=&quot;http://www.bugzilla.org/security/3.0.7/&quot;&gt;Security Advisory&lt;/a&gt; 
+  for details.&lt;/p&gt;
+
+&lt;h3&gt;3.2.1&lt;/h3&gt;
+
+&lt;p&gt;This release contains several security fixes. One fix may break any
+  automated scripts you have that are loading &lt;kbd&gt;process_bug.cgi&lt;/kbd&gt;
+  directly. We recommend that you read the entire 
+  &lt;a href=&quot;http://www.bugzilla.org/security/2.22.6/&quot;&gt;Security Advisory&lt;/a&gt;
+  for this release.&lt;/p&gt;
+
+&lt;h2 id=&quot;v32_req&quot;&gt;Minimum Requirements&lt;/h2&gt;
+
+&lt;p&gt;Any requirements that are new since 3.0.5 will look like
+  &lt;span class=&quot;req_new&quot;&gt;this&lt;/span&gt;.&lt;/p&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;&lt;a href=&quot;#v32_req_perl&quot;&gt;Perl&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v32_req_mysql&quot;&gt;For MySQL Users&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v32_req_pg&quot;&gt;For PostgreSQL Users&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v32_req_oracle&quot;&gt;For Oracle Users&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v32_req_modules&quot;&gt;Required Perl Modules&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v32_req_optional_mod&quot;&gt;Optional Perl
+    Modules&lt;/a&gt;&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h3 id=&quot;v32_req_perl&quot;&gt;Perl&lt;/h3&gt;
+
+&lt;p&gt;Perl &lt;span class=&quot;req_new&quot;&gt;v&lt;strong&gt;5.8.1&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
+
+&lt;h3 id=&quot;v32_req_mysql&quot;&gt;For MySQL Users&lt;/h3&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;MySQL v4.1.2&lt;/li&gt;
+    &lt;li&gt;&lt;strong&gt;perl module:&lt;/strong&gt;
+      DBD::mysql &lt;span class=&quot;req_new&quot;&gt;v4.00&lt;/span&gt;&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h3 id=&quot;v32_req_pg&quot;&gt;For PostgreSQL Users&lt;/h3&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;PostgreSQL v8.00.0000&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;perl module:&lt;/strong&gt; DBD::Pg v1.45&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h3 id=&quot;v32_req_oracle&quot;&gt;Email Addresses Hidden From Logged-Out Users
+    For Oracle Users&lt;/h3&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;Oracle v10.02.0&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;perl module:&lt;/strong&gt; DBD::Oracle v1.19&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h3 id=&quot;v32_req_modules&quot;&gt;Required Perl Modules&lt;/h3&gt;
+
+&lt;table class=&quot;req_table&quot; border=&quot;0&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot;&gt;
+&lt;tr&gt; &lt;th&gt;Module&lt;/th&gt;       &lt;th&gt;Version&lt;/th&gt; &lt;/tr&gt;
+&lt;tr&gt; &lt;td&gt;CGI&lt;/td&gt;          &lt;td class=&quot;req_new&quot;&gt;3.21 (on Perl 5.8.x) 
+                             or 3.33 (on Perl 5.10.x)&lt;/td&gt; &lt;/tr&gt;
+&lt;tr&gt; &lt;td&gt;Date::Format&lt;/td&gt; &lt;td&gt;2.21&lt;/td&gt; &lt;/tr&gt;
+&lt;tr&gt; &lt;td&gt;File::Spec&lt;/td&gt;   &lt;td&gt;0.84&lt;/td&gt; &lt;/tr&gt;
+&lt;tr&gt; &lt;td&gt;DBI&lt;/td&gt;          &lt;td&gt;1.41&lt;/td&gt; &lt;/tr&gt;
+&lt;tr&gt; &lt;td&gt;Template&lt;/td&gt;     &lt;td class=&quot;req_new&quot;&gt;2.15&lt;/td&gt; &lt;/tr&gt;
+&lt;tr&gt; &lt;td&gt;Email::Send&lt;/td&gt;  &lt;td&gt;2.00&lt;/td&gt; &lt;/tr&gt;
+&lt;tr&gt; &lt;td&gt;Email::MIME&lt;/td&gt;  &lt;td class=&quot;req_new&quot;&gt;1.861&lt;/td&gt; &lt;/tr&gt;
+&lt;tr&gt; 
+  &lt;td class=&quot;req_new&quot;&gt;Email::MIME::Encodings&lt;/td&gt; 
+  &lt;td class=&quot;req_new&quot;&gt;1.313&lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+  &lt;td&gt;Email::MIME::Modifier&lt;/td&gt; 
+  &lt;td class=&quot;req_new&quot;&gt;1.442&lt;/td&gt;
+&lt;/tr&gt;
+&lt;/table&gt;
+
+&lt;h3 id=&quot;v32_req_optional_mod&quot;&gt;Optional Perl Modules&lt;/h3&gt;
+
+&lt;p&gt;The following perl modules, if installed, enable various
+  features of [% terms.Bugzilla %]:&lt;/p&gt;
+
+&lt;table class=&quot;req_table&quot; border=&quot;0&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot;&gt;
+&lt;tr&gt; 
+  &lt;th&gt;Module&lt;/th&gt;
+  &lt;th&gt;Version&lt;/th&gt;
+  &lt;th&gt;Enables Feature&lt;/th&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+  &lt;td&gt;LWP::UserAgent&lt;/td&gt;
+  &lt;td&gt;(Any)&lt;/td&gt;
+  &lt;td&gt;Automatic Update Notifications&lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+  &lt;td&gt;Template::Plugin::GD::Image&lt;/td&gt; 
+  &lt;td&gt;(Any)&lt;/td&gt; 
+  &lt;td&gt;Graphical Reports&lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+  &lt;td&gt;GD::Text&lt;/td&gt; 
+  &lt;td&gt;(Any)&lt;/td&gt; 
+  &lt;td&gt;Graphical Reports&lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+  &lt;td&gt;GD::Graph&lt;/td&gt; 
+  &lt;td&gt;(Any)&lt;/td&gt; 
+  &lt;td&gt;Graphical Reports&lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+  &lt;td&gt;GD&lt;/td&gt; 
+  &lt;td&gt;1.20&lt;/td&gt; 
+  &lt;td&gt;Graphical Reports, New Charts, Old Charts&lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+  &lt;td&gt;Email::MIME::Attachment::Stripper&lt;/td&gt; 
+  &lt;td&gt;(Any)&lt;/td&gt; 
+  &lt;td&gt;Inbound Email&lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+  &lt;td&gt;Email::Reply&lt;/td&gt; 
+  &lt;td&gt;(Any)&lt;/td&gt; 
+  &lt;td&gt;Inbound Email&lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+  &lt;td&gt;Net::LDAP&lt;/td&gt; 
+  &lt;td&gt;(Any)&lt;/td&gt; 
+  &lt;td&gt;LDAP Authentication&lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+  &lt;td&gt;HTML::Parser&lt;/td&gt; 
+  &lt;td&gt;3.40&lt;/td&gt; 
+  &lt;td&gt;More HTML in Product/Group Descriptions&lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+  &lt;td&gt;HTML::Scrubber&lt;/td&gt; 
+  &lt;td&gt;(Any)&lt;/td&gt; 
+  &lt;td&gt;More HTML in Product/Group Descriptions&lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+  &lt;td&gt;XML::Twig&lt;/td&gt; 
+  &lt;td&gt;(Any)&lt;/td&gt; 
+  &lt;td&gt;Move [% terms.Bugs %] Between Installations&lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+  &lt;td&gt;MIME::Parser&lt;/td&gt; 
+  &lt;td&gt;5.406&lt;/td&gt; 
+  &lt;td&gt;Move [% terms.Bugs %] Between Installations&lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+  &lt;td&gt;Chart::Base&lt;/td&gt; 
+  &lt;td&gt;1.0&lt;/td&gt; 
+  &lt;td&gt;New Charts, Old Charts&lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+  &lt;td&gt;Image::Magick&lt;/td&gt; 
+  &lt;td&gt;(Any)&lt;/td&gt; 
+  &lt;td&gt;Optionally Convert BMP Attachments to PNGs&lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+  &lt;td&gt;PatchReader&lt;/td&gt; 
+  &lt;td&gt;0.9.4&lt;/td&gt; 
+  &lt;td&gt;Patch Viewer&lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+  &lt;td class=&quot;req_new&quot;&gt;Authen::Radius&lt;/td&gt; 
+  &lt;td class=&quot;req_new&quot;&gt;(Any)&lt;/td&gt; 
+  &lt;td&gt;RADIUS Authentication&lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+  &lt;td class=&quot;req_new&quot;&gt;Authen::SASL&lt;/td&gt; 
+  &lt;td class=&quot;req_new&quot;&gt;(Any)&lt;/td&gt; 
+  &lt;td&gt;SMTP Authentication&lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+  &lt;td&gt;SOAP::Lite&lt;/td&gt; 
+  &lt;td&gt;(Any)&lt;/td&gt; 
+  &lt;td&gt;XML-RPC Interface&lt;/td&gt;
+&lt;/tr&gt;
+&lt;tr&gt;
+  &lt;td&gt;mod_perl2&lt;/td&gt; 
+  &lt;td&gt;1.999022&lt;/td&gt; 
+  &lt;td&gt;mod_perl&lt;/td&gt;
+&lt;/tr&gt;
+&lt;/table&gt;
+
+&lt;h2 id=&quot;v32_feat&quot;&gt;New Features and Improvements&lt;/h2&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;&lt;a href=&quot;#v32_feat_ui&quot;&gt;Major UI Improvements&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v32_feat_skin&quot;&gt;New Default Skin: Dusk&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v32_feat_status&quot;&gt;Custom Status Workflow&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v32_feat_fields&quot;&gt;New Custom Field Types&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v32_feat_install&quot;&gt;Easier Installation&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v32_feat_oracle&quot;&gt;Experimental Oracle Support&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v32_feat_utf8&quot;&gt;Improved UTF-8 Support&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v32_feat_grcons&quot;&gt;Group Icons&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v32_feat_other&quot;&gt;Other Enhancements and Changes&lt;/a&gt;&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h3 id=&quot;v32_feat_ui&quot;&gt;Major UI Improvements&lt;/h3&gt;
+
+&lt;p&gt;[% terms.Bugzilla %] 3.2 has had some UI assistance from the NASA
+  Human-Computer Interaction department and the new 
+  &lt;a href=&quot;http://wiki.mozilla.org/Bugzilla:UE&quot;&gt;[% terms.Bugzilla %]
+  User Interface Team&lt;/a&gt;.&lt;/p&gt;
+
+&lt;p&gt;In particular, you will notice a massively redesigned [% terms.bug %]
+  editing form, in addition to our &lt;a href=&quot;#v32_feat_skin&quot;&gt;new skin&lt;/a&gt;.&lt;/p&gt;
+
+&lt;h3 id=&quot;v32_feat_skin&quot;&gt;New Default Skin: Dusk&lt;/h3&gt;
+
+&lt;p&gt;[% terms.Bugzilla %] 3.2 now ships with a skin called &quot;Dusk&quot; that is
+  a bit more colorful than old default &quot;Classic&quot; skin.&lt;/p&gt;
+
+&lt;p&gt;Upgrading installations will still default to the &quot;Classic&quot; 
+  skin--administrators can change the default in the Default Preferences
+  control panel. Users can also choose to use the old skin in their
+  Preferences (or using the View :: Page Style menu in Firefox).&lt;/p&gt;
+
+&lt;p&gt;The changes that [% terms.Bugzilla %] required for Dusk made
+  [%+ terms.Bugzilla %] much easier to skin. See the
+  &lt;a href=&quot;http://wiki.mozilla.org/Bugzilla:Addons#Skins&quot;&gt;Addons page&lt;/a&gt;
+  for additional skins, or try making your own!&lt;/p&gt;
+
+&lt;h3 id=&quot;v32_feat_status&quot;&gt;Custom Status Workflow&lt;/h3&gt;
+
+&lt;p&gt;You can now customize the list of statuses in [% terms.Bugzilla %],
+  and transitions between them.&lt;/p&gt;
+
+&lt;p&gt;You can also specify that a comment must be made on certain transitions.&lt;/p&gt;
+
+&lt;h3 id=&quot;v32_feat_fields&quot;&gt;New Custom Field Types&lt;/h3&gt;
+
+&lt;p&gt;[% terms.Bugzilla %] 3.2 has support for three new types of
+  custom fields:&lt;/p&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;Large Text: Adds a multi-line textbox to your [% terms.bugs %].&lt;/li&gt;
+  &lt;li&gt;Multiple Selection Box: Adds a box that allows you to choose
+    multiple items from a list.&lt;/li&gt;
+  &lt;li&gt;Date/Time: Displays a date and time, along with a JavaScript
+    calendar popup to make picking a date easier.&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h3 id=&quot;v32_feat_install&quot;&gt;Easier Installation&lt;/h3&gt;
+
+&lt;p&gt;[% terms.Bugzilla %] now comes with a script called 
+  &lt;kbd&gt;install-module.pl&lt;/kbd&gt; that can automatically download
+  and install all of the required Perl modules for [% terms.Bugzilla %].
+  It stores them in a directory inside your [% terms.Bugzilla %]
+  installation, so you can use it even if you don't have administrator-level
+  access to your machine, and without modifying your main Perl install.&lt;/p&gt;
+
+&lt;p&gt;&lt;kbd&gt;checksetup.pl&lt;/kbd&gt; will print out instructions for using
+  &lt;kbd&gt;install-module.pl&lt;/kbd&gt;, or you can read its
+  &lt;a href=&quot;[% docs_urlbase FILTER html %]api/install-module.html&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;
+
+&lt;h3 id=&quot;v32_feat_oracle&quot;&gt;Experimental Oracle Support&lt;/h3&gt;
+
+&lt;p&gt;[% terms.Bugzilla %] 3.2 contains experimental support for using 
+  Oracle as its database. Some features of [% terms.Bugzilla %] are known 
+  to be broken on Oracle, but hopefully will be working by our next major
+  release.&lt;/p&gt;
+
+&lt;p&gt;The [% terms.Bugzilla %] Project, as an open-source project, of course
+  does not recommend the use of proprietary database solutions. However,
+  if your organization requires that you use Oracle, this will allow
+  you to use [% terms.Bugzilla %]!&lt;/p&gt;
+
+&lt;p&gt;The [% terms.Bugzilla %] Project thanks Oracle Corp. for their extensive
+  development contributions to [% terms.Bugzilla %] which allowed this to 
+  happen!&lt;/p&gt;
+
+&lt;h3 id=&quot;v32_feat_utf8&quot;&gt;Improved UTF-8 Support&lt;/h3&gt;
+
+&lt;p&gt;[% terms.Bugzilla %] 3.2 now has advanced UTF-8 support in its code,
+  including correct handling for truncating and wrapping multi-byte
+  languages. Major issues with multi-byte or unusual languages
+  are now resolved, and [% terms.Bugzilla %] should now be usable
+  by users in every country with little (or at least much less)
+  customization.&lt;/p&gt;
+
+&lt;h3 id=&quot;v32_feat_grcons&quot;&gt;Group Icons&lt;/h3&gt;
+
+&lt;p&gt;Administrators can now specify that users who are in certain groups
+  should have an icon appear next to their name whenever they comment.
+  This is particularly useful for distinguishing developers from 
+  [%+ terms.bug %] reporters.&lt;/p&gt;
+
+&lt;h3 id=&quot;v32_feat_other&quot;&gt;Other Enhancements and Changes&lt;/h3&gt;
+
+&lt;p&gt;These are either minor enhancements, or enhancements that have
+  very short descriptions. Some of these are very useful, though!&lt;/p&gt;
+
+&lt;h4&gt;Enhancements For Users&lt;/h4&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;&lt;strong&gt;[% terms.Bugs %]&lt;/strong&gt;: You can now reassign
+    [%+ terms.abug %] at the same time as you are changing its status.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;[% terms.Bugs %]&lt;/strong&gt;: When entering [% terms.abug %], 
+    you will now see the description of a component when you select it.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;[% terms.Bugs %]&lt;/strong&gt;: The [% terms.bug %] view now 
+    contains some &lt;a href=&quot;http://microformats.org/about/&quot;&gt;Microformats&lt;/a&gt;,
+    most notably for users' names and email addresses.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;[% terms.Bugs %]&lt;/strong&gt;: You can now remove a QA Contact
+    from [% terms.abug %] simply by clearing the QA Contact field.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;[% terms.Bugs %]&lt;/strong&gt;: There is now a user preference 
+    that will allow you to exclude the quoted text when replying 
+    to comments.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;[% terms.Bugs %]&lt;/strong&gt;: You can now expand or collapse
+    individual comments in the [% terms.bug %] view.&lt;/li&gt;
+
+  &lt;li&gt;&lt;strong&gt;Attachments&lt;/strong&gt;: There is now &quot;mid-air collision&quot; 
+      protection when editing attachments.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Attachments&lt;/strong&gt;: Patches in the Diff Viewer now show 
+    line numbers (&lt;a href=&quot;https://bugzilla.mozilla.org/attachment.cgi?id=327546&quot;&gt;Example&lt;/a&gt;).&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Attachments&lt;/strong&gt;: After creating or updating an attachment,
+    you will be immediately shown the [% terms.bug %] that the attachment
+    is on.&lt;/li&gt;
+
+  &lt;li&gt;&lt;strong&gt;Search&lt;/strong&gt;: You can now reverse the sort of 
+    [%+ terms.abug %] list by clicking on a column header again.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Search&lt;/strong&gt;: Atom feeds of [% terms.bug %] lists now
+    contain more fields.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Search&lt;/strong&gt;: QuickSearch now supports searching flags
+    and groups. It also now includes the OS field in the list of fields
+    it searches by default.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Search&lt;/strong&gt;: &quot;Help&quot; text can now appear on query.cgi 
+    for Internet Explorer and other non-Firefox browsers. (It always
+    could appear for Firefox.)&lt;/li&gt;
+
+  &lt;li&gt;[% terms.Bugzilla %] now ships with an icon that will show
+    up next to the URL in most browsers. If you want to replace it,
+    it's in &lt;kbd&gt;images/favicon.ico&lt;/kbd&gt;.&lt;/li&gt;
+
+  &lt;li&gt;You can now set the Deadline when using &quot;Change Several 
+    [%+ terms.Bugs %] At Once&quot;&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Saved Searches&lt;/strong&gt; now save their column list, so if 
+    you customize the list of columns and save your search, it will 
+    always contain those columns.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Saved Searches&lt;/strong&gt;: When you share a search, you can
+    now see how many users have subscribed to it, on 
+    &lt;kbd&gt;userprefs.cgi&lt;/kbd&gt;.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Saved Searches&lt;/strong&gt;: You can now see what group a 
+    shared search was shared to, on the list of available shared searches
+    in &lt;kbd&gt;userprefs.cgi&lt;/kbd&gt;.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Flags&lt;/strong&gt;: If your installation uses drop-down user 
+    lists, the flag requestee box will now contain only users who are 
+    actually allowed to take requests.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Flags&lt;/strong&gt;: If somebody makes a request to you, and you
+    change the requestee to somebody else, the requester is no longer set
+    to you. In other words, you can &quot;redirect&quot; requests and maintain the
+    original requester.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Flags&lt;/strong&gt;: Emails about flags now will thread properly
+    in email clients to be a part of [% terms.abug %]'s thread.&lt;/li&gt;
+  &lt;li&gt;When using &lt;kbd&gt;email_in.pl&lt;/kbd&gt;, you can now add users to the CC
+    list by just using &lt;kbd&gt;@cc&lt;/kbd&gt; as the field name.&lt;/li&gt;
+  &lt;li&gt;Many pages (particularly administrative pages) now contain links to
+    the relevant section of the [% terms.Bugzilla %] Guide, so you can read 
+    the documentation for that page.&lt;/li&gt;
+  &lt;li&gt;Dependency Graphs should render more quickly, as they now (by default)
+    only include the same [% terms.bugs %] that you'd see in the dependency
+    tree.&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h4&gt;Enhancements For Administrators&lt;/h4&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;&lt;strong&gt;Admin UI&lt;/strong&gt;: Instead of having the Administration 
+    Control Panel links in the footer, there is now just one link called 
+   &quot;Administration&quot; that takes you to a page that links to all the
+    administrative controls for [% terms.Bugzilla %].&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Admin UI&lt;/strong&gt;: Administrative pages no longer display
+    confirmation pages, instead they redirect you to some useful page 
+    and display a message about what changed.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Admin UI&lt;/strong&gt;: The interface for editing group 
+     inheritance in &lt;kbd&gt;editgroups.cgi&lt;/kbd&gt; is much clearer now.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Admin UI&lt;/strong&gt;: When editing a user, you can now see 
+    all the components where that user is the Default Assignee or Default
+    QA Contact.&lt;/li&gt;
+
+  &lt;li&gt;&lt;strong&gt;Email&lt;/strong&gt;: For installations that use SMTP to send 
+    mail (as opposed to Sendmail), [%+ terms.Bugzilla %] now supports
+    SMTP Authentication, so that it can log in to your mail server 
+    before sending messages.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Email&lt;/strong&gt;: Using the &quot;Test&quot; mail delivery method now
+     creates a valid mbox file to make testing easier.&lt;/li&gt;
+
+  &lt;li&gt;&lt;strong&gt;Authentication&lt;/strong&gt;: [% terms.Bugzilla %] now correctly 
+    handles LDAP records which contain multiple email addresses. (The first
+    email address in the list that is a valid [% terms.Bugzilla %] account 
+    will be used, or if this is a new user, the first email address in 
+    the list will be used.)&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Authentication&lt;/strong&gt;: [% terms.Bugzilla %] can now take 
+    a list of LDAP servers to try in order until it gets a successful
+    connection.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Authentication&lt;/strong&gt;: [% terms.Bugzilla %] now supports 
+    RADIUS authentication.&lt;/li&gt;
+
+  &lt;li&gt;&lt;strong&gt;Security&lt;/strong&gt;: The login cookie is now created as 
+    &quot;HTTPOnly&quot; so that it can't be read by possibly malicious scripts. 
+    Also, if SSL is enabled on your installation, the login cookie is
+    now only sent over SSL connections.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Security&lt;/strong&gt;: The &lt;code&gt;ssl&lt;/code&gt; parameter now protects
+    every page a logged-in user accesses, when set to &quot;authenticated sessions.&quot;
+    Also, SSL is now enforced appropriately in the WebServices interface when
+    the parameter is set.&lt;/li&gt;
+
+  &lt;li&gt;&lt;strong&gt;Database&lt;/strong&gt;: [% terms.Bugzilla %] now uses transactions in 
+    the database instead of table locks. This should generally improve
+    performance with many concurrent users. It also means if there is
+    an unexpected error in the middle of a page, all database changes made
+    during that page will be rolled back.&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;Database&lt;/strong&gt;: You no longer have to set 
+    &lt;code&gt;max_packet_size&lt;/code&gt; in MySQL to add large attachments. However,
+    you may need to set it manually if you restore a mysqldump into your
+    database.&lt;/li&gt;
+
+  &lt;li&gt;New WebService functions:
+    &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/WebService/Bug.html&quot;&gt;B&lt;!-- --&gt;ug.add_comment&lt;/a&gt;
+    and &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/WebService/Bugzilla.html&quot;&gt;Bugzilla.extensions&lt;/a&gt;.&lt;/li&gt;
+
+  &lt;li&gt;You can now delete custom fields, but only if they have never been
+    set on any [% terms.bug %].&lt;/li&gt;
+  &lt;li&gt;There is now a &lt;kbd&gt;--reset-password&lt;/kbd&gt; argument to 
+    &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; that allows you to reset a user's password
+    from the command line.&lt;/li&gt;
+  &lt;li&gt;There is now a script called &lt;kbd&gt;sanitycheck.pl&lt;/kbd&gt; that you can
+    run from the command line. It works just like &lt;kbd&gt;sanitycheck.cgi&lt;/kbd&gt;.
+    By default, it only outputs anything if there's an error, so it's
+    ideal for administrators who want to run it nightly in a cron job.&lt;/li&gt;
+  &lt;li&gt;The &lt;kbd&gt;strict_isolation&lt;/kbd&gt; parameter now prevents you from setting
+    users who cannot see [% terms.abug %] as a CC, Assignee, or QA
+    Contact. Previously it only prevented you from adding users who
+    could not &lt;em&gt;edit&lt;/em&gt; the [% terms.bug %].&lt;/li&gt;
+  &lt;li&gt;Extensions can now add their own headers to the HTML &amp;lt;head&amp;gt;
+    for things like custom CSS and so on.&lt;/li&gt;
+  &lt;li&gt;&lt;kbd&gt;sanitycheck.cgi&lt;/kbd&gt; has been templatized, meaning that the
+    entire [% terms.Bugzilla %] UI is now contained in templates.&lt;/li&gt;
+  &lt;li&gt;When setting the &lt;kbd&gt;sslbase&lt;/kbd&gt; parameter, you can now specify
+    a port number in the URL.&lt;/li&gt;
+  &lt;li&gt;When importing [% terms.bugs %] using &lt;kbd&gt;importxml.pl&lt;/kbd&gt;,
+    attachments will have their actual creator set as their creator,
+    instead of the person who exported the [% terms.bug %] from the other
+    system.&lt;/li&gt;
+  &lt;li&gt;The voting system is off by default in new installs. This is to
+    prepare for the fact that it will be moved into an extension at
+    some point in the future.&lt;/li&gt;
+  &lt;li&gt;The &lt;code&gt;shutdownhtml&lt;/code&gt; parameter now works even when 
+    [%+ terms.Bugzilla %]'s database server is down.&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h3&gt;Enhancements for Localizers (or Localized Installations)&lt;/h3&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;The documentation can now be localized--in other words, you can have
+    documentation installed for multiple languages at once and
+    [%+ terms.Bugzilla %] will link to the correct language in its internal
+    documentation links.&lt;/li&gt;
+  &lt;li&gt;[% terms.Bugzilla %] no longer uses the &lt;kbd&gt;languages&lt;/kbd&gt; parameter.
+    Instead it reads the &lt;kbd&gt;template/&lt;/kbd&gt; directory to see which
+    languages are available.&lt;/li&gt;
+  &lt;li&gt;Some of the messages printed by &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; can now
+    be localized. See &lt;kbd&gt;template/en/default/setup/strings.txt.pl&lt;/kbd&gt;.
+&lt;/ul&gt;
+
+&lt;h2 id=&quot;v32_issues&quot;&gt;Outstanding Issues&lt;/h2&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=423439&quot;&gt;
+    [%- terms.Bug %] 423439&lt;/a&gt;: Tabs in comments will be converted
+    to four spaces, due to a b&lt;!-- --&gt;ug in Perl as of Perl 5.8.8.&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=69621&quot;&gt;
+    [%- terms.Bug %] 69621&lt;/a&gt;: If you rename or remove a keyword that is
+    in use on [% terms.bugs %], you will need to rebuild the &quot;keyword cache&quot;
+    by running &lt;a href=&quot;sanitycheck.cgi&quot;&gt;sanitycheck.cgi&lt;/a&gt; and choosing 
+    the option to rebuild the cache when it asks. Otherwise keywords may 
+    not show up properly in search results.&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=89822&quot;&gt;
+    [%- terms.Bug %] 89822&lt;/a&gt;: When changing multiple [% terms.bugs %] at 
+    the same time, there is no &quot;mid-air collision&quot; protection.&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=276230&quot;&gt;
+    [%- terms.Bug %] 276230&lt;/a&gt;: The support for restricting access to 
+    particular Categories of New Charts is not complete. You should treat 
+    the 'chartgroup' Param as the only access mechanism available.&lt;br&gt;
+    However, charts migrated from Old Charts will be restricted to 
+    the groups that are marked MANDATORY for the corresponding Product.
+    There is currently no way to change this restriction, and the 
+    groupings will not be updated if the group configuration
+    for the Product changes.&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=370370&quot;&gt;
+    [%- terms.Bug %] 370370&lt;/a&gt;: mod_perl support is currently not
+    working on Windows machines.&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h2 id=&quot;v32_upgrading&quot;&gt;How to Upgrade From An Older Version&lt;/h2&gt;
+
+&lt;h3 id=&quot;v32_upgrading_notes&quot;&gt;Notes For Upgraders&lt;/h3&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;If you upgrade by CVS, the &lt;kbd&gt;extensions&lt;/kbd&gt; and 
+    &lt;kbd&gt;skins/contrib&lt;/kbd&gt; directories are now in CVS instead of
+    being created by &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; If you do a &lt;kbd&gt;cvs update&lt;/kbd&gt;
+    from 3.0, you will be told that your directories are &quot;in the way&quot; and
+    you should delete (or move) them and then do &lt;kbd&gt;cvs update&lt;/kbd&gt;
+    again. Also, the &lt;kbd&gt;docs&lt;/kbd&gt; directory has been restructured
+    and after you &lt;kbd&gt;cvs update&lt;/kbd&gt; you can delete the &lt;kbd&gt;docs/html&lt;/kbd&gt;,
+    &lt;kbd&gt;docs/pdf&lt;/kbd&gt;, &lt;kbd&gt;docs/txt&lt;/kbd&gt;, and &lt;kbd&gt;docs/xml&lt;/kbd&gt;
+    directories.&lt;/li&gt;
+  &lt;li&gt;If you are using MySQL, you should know that [% terms.Bugzilla %]
+    now uses InnoDB for all tables. &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; will convert
+    your tables automatically, but if you have InnoDB disabled,
+    the upgrade will not be able to complete (and &lt;kbd&gt;checksetup.pl&lt;/kbd&gt;
+    will tell you so).&lt;/li&gt;
+
+  &lt;li&gt;&lt;strong&gt;You should also read the 
+    &lt;a href=&quot;#v30_upgrading_notes&quot;&gt;[% terms.Bugzilla %] 3.0 Notes For Upgraders
+    section&lt;/a&gt; of the 
+    &lt;a href=&quot;#v32_previous&quot;&gt;previous release notes&lt;/a&gt; if you are upgrading
+    from a version before 3.0.&lt;/strong&gt;&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h3&gt;Steps For Upgrading&lt;/h3&gt;
+
+&lt;p&gt;Once you have read the notes above, see the
+  &lt;a href=&quot;[% docs_urlbase FILTER html %]upgrade.html&quot;&gt;Upgrading 
+  documentation&lt;/a&gt; for instructions on how to upgrade.&lt;/p&gt;
+
+&lt;h2 id=&quot;v32_code_changes&quot;&gt;Code Changes Which May Affect Customizations&lt;/h2&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;&lt;a href=&quot;#v32_code_hooks&quot;&gt;More Hooks!&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v32_code_search&quot;&gt;Search.pm Rearchitecture&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v32_code_lib&quot;&gt;lib Directory&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v32_code_other&quot;&gt;Other Changes&lt;/a&gt;&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h3 id=&quot;v32_code_hooks&quot;&gt;More Hooks!&lt;/h3&gt;
+
+&lt;p&gt;There are more code hooks in 3.2 than there were in 3.0. See the
+  documentation of &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/Hook.html&quot;&gt;Bugzilla::Hook&lt;/a&gt;
+  for more details.&lt;/p&gt;
+
+&lt;h3 id=&quot;v32_code_search&quot;&gt;Search.pm Rearchitecture&lt;/h3&gt;
+
+&lt;p&gt;&lt;kbd&gt;Bugzilla/Search.pm&lt;/kbd&gt; has been heavily modified, to be much
+  easier to read and use. It contains mostly the same code as it did in
+  3.0, but it has been moved around and reorganized significantly.&lt;/p&gt;
+
+&lt;h3 id=&quot;v32_code_lib&quot;&gt;lib Directory&lt;/h3&gt;
+
+&lt;p&gt;As part of implementing &lt;a href=&quot;#v32_feat_install&quot;&gt;install-module.pl&lt;/a&gt;,
+  [%+ terms.Bugzilla %] was given a local &lt;kbd&gt;lib&lt;/kbd&gt; directory which
+  it searches for modules, in addition to the standard system path.&lt;/p&gt;
+
+&lt;p&gt;This means that all [% terms.Bugzilla %] scripts now start with
+  &lt;code&gt;use lib qw(. lib);&lt;/code&gt; as one of the first lines.&lt;/p&gt;
+
+&lt;h3 id=&quot;v32_code_other&quot;&gt;Other Changes&lt;/h3&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;You should now be using &lt;code&gt;get_status('NEW')&lt;/code&gt; instead of
+    &lt;code&gt;status_descs.NEW&lt;/code&gt; in templates.&lt;/li&gt;
+  &lt;li&gt;The &lt;code&gt;[&amp;#37;# version = 1.0 &amp;#37;]&lt;/code&gt; comment at the top of every
+    template file has been removed.&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h1 id=&quot;v32_previous&quot;&gt;[% terms.Bugzilla %] 3.0.x Release Notes&lt;/h1&gt;
+
+&lt;h2&gt;Table of Contents&lt;/h2&gt;
+
+&lt;ul class=&quot;bz_toc&quot;&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_introduction&quot;&gt;Introduction&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_point&quot;&gt;Updates In This 3.0.x Release&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_req&quot;&gt;Minimum Requirements&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_feat&quot;&gt;New Features and Improvements&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_issues&quot;&gt;Outstanding Issues&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_security&quot;&gt;Security Fixes In This Release&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_upgrading&quot;&gt;How to Upgrade From An Older Version&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_code_changes&quot;&gt;Code Changes Which May Affect 
+    Customizations&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_previous&quot;&gt;Release Notes for Previous Versions&lt;/a&gt;&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h2 id=&quot;v30_introduction&quot;&gt;Introduction&lt;/h2&gt;
+
+&lt;p&gt;Welcome to [% terms.Bugzilla %] 3.0! It's been over eight years since
+  we released [% terms.Bugzilla %] 2.0, and everything has changed since
+  then. Even just since our previous release, [% terms.Bugzilla %] 2.22,
+  we've added a &lt;em&gt;lot&lt;/em&gt; of new features. So enjoy the release, we're
+  happy to bring it to you.&lt;/p&gt;
+
+&lt;p&gt;If you're upgrading, make sure to read &lt;a href=&quot;#v30_upgrading&quot;&gt;How to
+  Upgrade From An Older Version&lt;/a&gt;. If you are upgrading from a release
+  before 2.22, make sure to read the release notes for all the 
+  &lt;a href=&quot;#v30_previous&quot;&gt;previous versions&lt;/a&gt; in between your version 
+  and this one.&lt;/p&gt;
+
+&lt;h2 id=&quot;v30_point&quot;&gt;Updates in this 3.0.x Release&lt;/h2&gt;
+
+&lt;p&gt;This section describes what's changed in the most recent b&lt;!-- --&gt;ug-fix
+  releases of [% terms.Bugzilla %] after 3.0. We only list the
+  most important fixes in each release. If you want a detailed list of
+  &lt;em&gt;everything&lt;/em&gt; that's changed in each version, you should use our
+  &lt;a href=&quot;http://www.bugzilla.org/status/changes.html&quot;&gt;Change Log Page&lt;/a&gt;.&lt;/p&gt;
+
+&lt;h3&gt;3.0.6&lt;/h3&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;Before 3.0.6, unexpected fatal WebService errors would result in
+    a &lt;code&gt;faultCode&lt;/code&gt; that was a string instead of a number.
+   (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=446327&quot;&gt;[% terms.Bug %] 446327&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;If you created a product or component with the same name as one you
+    previously deleted, it would fail with an error about the series table.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=247936&quot;&gt;[% terms.Bug %] 247936&lt;/a&gt;)&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;p&gt;See also the &lt;a href=&quot;#v30_security&quot;&gt;Security Advisory&lt;/a&gt; section for
+  information about a security issue fixed in this release.&lt;/p&gt;
+
+&lt;h3&gt;3.0.5&lt;/h3&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;If you don't have permission to set a flag, it will now appear
+    unchangeable in the UI.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=433851&quot;&gt;[% terms.Bug %] 433851&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;If you were running mod_perl, [% terms.Bugzilla %] was not correctly
+    closing its connections to the database since 3.0.3, and so sometimes
+    the DB would run out of connections.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=441592&quot;&gt;[% terms.Bug %] 441592&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;The installation script is now clear about exactly which 
+    &lt;code&gt;Email::&lt;/code&gt; modules are required in Perl, thus avoiding the
+    problem where emails show up with a body like 
+    &lt;samp&gt;SCALAR(0xBF126795)&lt;/samp&gt;.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=441541&quot;&gt;[% terms.Bug %] 441541&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;[% docs_urlbase FILTER html %]api/email_in.html&quot;&gt;email_in.pl&lt;/a&gt;
+    is no longer case-sensitive for values of &lt;kbd&gt;@product&lt;/kbd&gt;.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=365697&quot;&gt;[% terms.Bug %] 365697&lt;/a&gt;)&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;p&gt;See also the &lt;a href=&quot;#v30_security&quot;&gt;Security Advisory&lt;/a&gt; section for
+  information about security issues fixed in this release.&lt;/p&gt;
+
+&lt;h3&gt;3.0.4&lt;/h3&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;[% terms.Bugzilla %] administrators were not being correctly notified
+    about new releases.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=414726&quot;&gt;[% terms.Bug %] 414726&lt;/a&gt;)&lt;/li&gt;
+
+  &lt;li&gt;There could be extra whitespace in email subject lines.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=411544&quot;&gt;[% terms.Bug %] 411544&lt;/a&gt;)&lt;/li&gt;
+
+  &lt;li&gt;The priority, severity, OS, and platform fields were always required by
+    the &lt;kbd&gt;B&lt;!-- --&gt;ug.create&lt;/kbd&gt; WebService function, even if they had
+    defaults specified.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=384009&quot;&gt;[% terms.Bug %] 384009&lt;/a&gt;)&lt;/li&gt;
+
+  &lt;li&gt;Better threading of [% terms.bug %]mail in some email clients.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=376453&quot;&gt;[% terms.Bug %] 376453&lt;/a&gt;)&lt;/li&gt;
+
+  &lt;li&gt;There were many fixes to the Inbound Email Interface 
+    (&lt;kbd&gt;email_in.pl&lt;/kbd&gt;).
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=92274&quot;&gt;[% terms.Bug %] 92274&lt;/a&gt;,
+     &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=377025&quot;&gt;[% terms.Bug %] 377025&lt;/a&gt;,
+     &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=412943&quot;&gt;[% terms.Bug %] 412943&lt;/a&gt;,
+     &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=413672&quot;&gt;[% terms.Bug %] 413672&lt;/a&gt;, and
+     &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=431721&quot;&gt;[% terms.Bug %] 431721&lt;/a&gt;)&lt;/li&gt;
+
+  &lt;li&gt;&lt;kbd&gt;checksetup.pl&lt;/kbd&gt; now handles UTF-8 conversion more reliably during upgrades.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=374951&quot;&gt;[% terms.Bug %] 374951&lt;/a&gt;)&lt;/li&gt;
+
+  &lt;li&gt;Comments written in CJK languages are now correctly word-wrapped.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=388723&quot;&gt;[% terms.Bug %] 388723&lt;/a&gt;)&lt;/li&gt;
+
+  &lt;li&gt;All emails will now be sent in the correct language, when the user
+    has chosen a language for emails.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=405946&quot;&gt;[% terms.Bug %] 405946&lt;/a&gt;)
+
+  &lt;li&gt;On Windows, temporary files created when uploading attachments are now
+    correctly deleted when the upload is complete.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=414002&quot;&gt;[% terms.Bug %] 414002&lt;/a&gt;)&lt;/li&gt;
+
+  &lt;li&gt;&lt;kbd&gt;checksetup.pl&lt;/kbd&gt; now prints correct installation instructions
+    for Windows users using Perl 5.10.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=414430&quot;&gt;[% terms.Bug %] 414430&lt;/a&gt;)
+&lt;/ul&gt;
+
+&lt;p&gt;See also the &lt;a href=&quot;#v30_security&quot;&gt;Security Advisory&lt;/a&gt; section for
+  information about security issues fixed in this release.&lt;/p&gt;
+
+&lt;h3&gt;3.0.3&lt;/h3&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;mod_perl no longer compiles [% terms.Bugzilla %]'s code for each Apache
+    process individually. It now compiles code only once and shares it among
+    each Apache process. This greatly improves performance and highly 
+    decreases the memory footprint.
+   (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=398241&quot;&gt;[% terms.Bug %] 398241&lt;/a&gt;)&lt;/li&gt;
+
+  &lt;li&gt;You can now search for '---' (without quotes) in versions and milestones.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=362436&quot;&gt;[% terms.Bug %] 362436&lt;/a&gt;)&lt;/li&gt;
+
+  &lt;li&gt;[% terms.Bugzilla %] should no longer break lines unnecessarily in 
+    email subjects. This was causing trouble with some email clients.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=374424&quot;&gt;[% terms.Bug %] 374424&lt;/a&gt;)&lt;/li&gt;
+
+  &lt;li&gt;If you had selected &quot;I'm added to or removed from this capacity&quot; option
+    for the &quot;CC&quot; role in your email preferences, you wouldn't get mail when
+    more than one person was added to the CC list at once.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=394796&quot;&gt;[% terms.Bug %] 394796&lt;/a&gt;)&lt;/li&gt;
+
+  &lt;li&gt;Deleting a user account no longer deletes whines from another user who
+    has the deleted account as addressee. The schedule is simply removed, 
+    but the whine itself is left intact.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=395924&quot;&gt;[% terms.Bug %] 395924&lt;/a&gt;)&lt;/li&gt;
+
+  &lt;li&gt;&lt;kbd&gt;contrib/merge-users.pl&lt;/kbd&gt; now correctly merges all required
+    fields when merging two user accounts.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=400160&quot;&gt;[% terms.Bug %] 400160&lt;/a&gt;)&lt;/li&gt;
+
+  &lt;li&gt;[% terms.Bugzilla %] no longer requires Apache::DBI to run under 
+    mod_perl. It caused troubles such as lost connections with the DB and
+    didn't give any important performance gain.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=408766&quot;&gt;[% terms.Bug %] 408766&lt;/a&gt;)&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h3&gt;3.0.2&lt;/h3&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;[% terms.Bugzilla %] should now work on Perl 5.9.5 (and thus the
+    upcoming Perl 5.10.0).
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=390442&quot;&gt;[% terms.Bug %] 390442&lt;/a&gt;)&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;p&gt;See also the &lt;a href=&quot;#v30_security&quot;&gt;Security Advisory&lt;/a&gt; section for
+  information about an important security issue fixed in this release.&lt;/p&gt;
+
+&lt;h3&gt;3.0.1&lt;/h3&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;For users of Firefox 2, the &lt;code&gt;show_bug.cgi&lt;/code&gt; user interface
+    should no longer &quot;collapse&quot; after you modify [% terms.abug %].
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=370739&quot;&gt;[% terms.Bug %] 370739&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;If you can bless a group, and you share a saved search with that
+    group, it will no longer automatically appear in all of that group's
+    footers unless you specifically request that it automatically appear
+    in their footers.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=365890&quot;&gt;[% terms.Bug %] 365890&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;There is now a parameter to allow users to perform searches without
+    any search terms. (In other words, to search for just a Product
+    and Status on the Simple Search page.) The parameter is called
+    &lt;code&gt;specific_search_allow_empty_words&lt;/code&gt;.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=385910&quot;&gt;[% terms.Bug %] 385910&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;If you attach a file that has a MIME-type of &lt;code&gt;text/x-patch&lt;/code&gt;
+    or &lt;code&gt;text/x-diff&lt;/code&gt;, it will automatically be treated as a 
+    patch by [% terms.Bugzilla %].
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=365756&quot;&gt;[% terms.Bug %] 365756&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;Dependency Graphs now work correctly on all mod_perl installations.
+    There should now be no remaining signficant problems with running
+    [%+ terms.Bugzilla %] under mod_perl.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=370398&quot;&gt;[% terms.Bug %] 370398&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;If moving [% terms.abug %] between products would remove groups
+    from the [% terms.bug %], you are now warned.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=303183&quot;&gt;[% terms.Bug %] 303183&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;On IIS, whenever [% terms.Bugzilla %] threw a warning, it would
+    actually appear on the web page. Now warnings are suppressed,
+    unless you have a file in the &lt;code&gt;data&lt;/code&gt; directory called
+    &lt;code&gt;errorlog&lt;/code&gt;, in which case warnings will be printed there.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=390148&quot;&gt;[% terms.Bug %] 390148&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;If you used &lt;kbd&gt;email_in.pl&lt;/kbd&gt; to edit [% terms.abug %] that was
+    protected by groups, all of the groups would be cleared.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=385453&quot;&gt;[% terms.Bug %] 385453&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;PostgreSQL users: New Charts were failing to collect data over time.
+    They will now start collecting data correctly.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=257351&quot;&gt;[% terms.Bug %] 257351&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;Some flag mails didn't specify who the requestee was. 
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=379787&quot;&gt;[% terms.Bug %] 379787&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;Instead of throwing real errors, &lt;kbd&gt;collectstats.pl&lt;/kbd&gt; would
+    just say that it couldn't find &lt;code&gt;ThrowUserError&lt;/code&gt;.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=380709&quot;&gt;[% terms.Bug %] 380709&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;Logging into [% terms.Bugzilla %] from the home page works again
+    with IIS5. 
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=364008&quot;&gt;[% terms.Bug %] 364008&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;If you were using SMTP for sending email, sometimes emails would
+    be missing the &lt;code&gt;Date&lt;/code&gt; header.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=304999&quot;&gt;[% terms.Bug %] 304999&lt;/a&gt;).&lt;/li&gt;
+  &lt;li&gt;In the XML-RPC WebService, &lt;code&gt;B&lt;!-- --&gt;ug.legal_values&lt;/code&gt; now
+    correctly returns values for custom fields if you request values 
+    for custom fields.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=381737&quot;&gt;[% terms.Bug %] 381737&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;The &quot;[% terms.Bug %]-Writing Guidelines&quot; page has been shortened
+    and re-written.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=378590&quot;&gt;[% terms.Bug %] 378590&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;If your &lt;code&gt;urlbase&lt;/code&gt; parameter included a port number,
+    like &lt;code&gt;www.domain.com:8080&lt;/code&gt;, SMTP might have failed.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=384501&quot;&gt;[% terms.Bug %] 384501&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;For SMTP users, there is a new parameter, &lt;code&gt;smtp_debug&lt;/code&gt;.
+    Turning on this parameter will log the full information about
+    every SMTP session to your web server's error log, to help with
+    debugging issues with SMTP.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=384497&quot;&gt;[% terms.Bug %] 384497&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;If you are a &quot;global watcher&quot; (you get all mails from every 
+    [%+ terms.bug %]), you can now see that in your Email Preferences.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=365302&quot;&gt;[% terms.Bug %] 365302&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;The Status and Resolution of [% terms.bugs %] are now correctly
+    localized in CSV search results.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=389517&quot;&gt;[% terms.Bug %] 389517&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;The &quot;Subject&quot; line of an email was being mangled if it contained
+    non-Latin characters.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=387860&quot;&gt;[% terms.Bug %] 387860&lt;/a&gt;)&lt;/li&gt;
+  &lt;li&gt;Editing the &quot;languages&quot; parameter using &lt;kbd&gt;editparams.cgi&lt;/kbd&gt; would
+    sometimes fail, causing [% terms.Bugzilla %] to throw an error.
+    (&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=335354&quot;&gt;[% terms.Bug %] 335354&lt;/a&gt;)&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h2 id=&quot;v30_req&quot;&gt;Minimum Requirements&lt;/h2&gt;
+
+&lt;p&gt;Any requirements that are new since 2.22 will look like
+  &lt;span class=&quot;req_new&quot;&gt;this&lt;/span&gt;.&lt;/p&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_req_perl&quot;&gt;Perl&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_req_mysql&quot;&gt;For MySQL Users&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_req_pg&quot;&gt;For PostgreSQL Users&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_req_modules&quot;&gt;Required Perl Modules&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_req_optional_mod&quot;&gt;Optional Perl
+    Modules&lt;/a&gt;&lt;/li&gt;
+&lt;/ul&gt;
+
+
+&lt;h3 id=&quot;v30_req_perl&quot;&gt;Perl&lt;/h3&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;Perl &lt;span class=&quot;req_new&quot;&gt;v&lt;strong&gt;5.8.0&lt;/strong&gt;&lt;/span&gt; (non-Windows 
+    platforms)&lt;/li&gt;
+  &lt;li&gt;Perl v&lt;strong&gt;5.8.1&lt;/strong&gt; (Windows platforms)&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h3 id=&quot;v30_req_mysql&quot;&gt;For MySQL Users&lt;/h3&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;MySQL &lt;span class=&quot;req_new&quot;&gt;v4.1.2&lt;/span&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;perl module:&lt;/strong&gt; DBD::mysql v2.9003&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h3 id=&quot;v30_req_pg&quot;&gt;For PostgreSQL Users&lt;/h3&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;PostgreSQL v8.00.0000&lt;/li&gt;
+  &lt;li&gt;&lt;strong&gt;perl module:&lt;/strong&gt; DBD::Pg v1.45&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h3 id=&quot;v30_req_modules&quot;&gt;Required Perl Modules&lt;/h3&gt;
+
+&lt;table class=&quot;req_table&quot; border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
+  &lt;tr&gt;
+    &lt;th&gt;Module&lt;/th&gt; &lt;th&gt;Version&lt;/th&gt;
+  &lt;/tr&gt;
+    &lt;tr&gt;&lt;td&gt;CGI&lt;/td&gt; &lt;td&gt;2.93&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td&gt;Date::Format&lt;/td&gt; &lt;td&gt;2.21&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td&gt;DBI&lt;/td&gt; 
+    &lt;td class=&quot;req_new&quot;&gt;1.41&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td&gt;File::Spec&lt;/td&gt; &lt;td&gt;0.84&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td&gt;Template&lt;/td&gt; &lt;td&gt;2.12&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td class=&quot;req_new&quot;&gt;Email::Send&lt;/td&gt; 
+    &lt;td class=&quot;req_new&quot;&gt;2.00&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td&gt;Email::MIME&lt;/td&gt; 
+    &lt;td&gt;1.861&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td class=&quot;req_new&quot;&gt;Email::MIME::Modifier&lt;/td&gt; 
+    &lt;td class=&quot;req_new&quot;&gt;1.442&lt;/td&gt;
+  &lt;/tr&gt;
+&lt;/table&gt;
+
+&lt;h3 id=&quot;v30_req_optional_mod&quot;&gt;Optional Perl Modules&lt;/h3&gt;
+
+&lt;p&gt;The following perl modules, if installed, enable various
+  features of [% terms.Bugzilla %]:&lt;/p&gt;
+
+&lt;table class=&quot;req_table&quot; border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
+  &lt;tr&gt;
+    &lt;th&gt;Module&lt;/th&gt; &lt;th&gt;Version&lt;/th&gt;
+    &lt;th&gt;Enables Feature&lt;/th&gt;
+  &lt;/tr&gt;
+   &lt;tr&gt;
+     &lt;td class=&quot;req_new&quot;&gt;LWP::UserAgent&lt;/td&gt; 
+     &lt;td class=&quot;req_new&quot;&gt;(Any)&lt;/td&gt; 
+     &lt;td&gt;Automatic Update Notifications&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td&gt;Template::Plugin::GD::Image&lt;/td&gt; 
+    &lt;td&gt;(Any)&lt;/td&gt; 
+    &lt;td&gt;Graphical Reports&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td&gt;GD::Graph&lt;/td&gt; 
+    &lt;td&gt;(Any)&lt;/td&gt; 
+    &lt;td&gt;Graphical Reports&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td&gt;GD::Text&lt;/td&gt; 
+    &lt;td&gt;(Any)&lt;/td&gt; 
+    &lt;td&gt;Graphical Reports&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td&gt;GD&lt;/td&gt; 
+    &lt;td&gt;1.20&lt;/td&gt; 
+    &lt;td&gt;Graphical Reports, New Charts, Old Charts&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td class=&quot;req_new&quot;&gt;Email::MIME::Attachment::Stripper&lt;/td&gt; 
+    &lt;td class=&quot;req_new&quot;&gt;(Any)&lt;/td&gt; 
+    &lt;td&gt;Inbound Email&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td class=&quot;req_new&quot;&gt;Email::Reply&lt;/td&gt; 
+    &lt;td class=&quot;req_new&quot;&gt;(Any)&lt;/td&gt; 
+    &lt;td&gt;Inbound Email&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td&gt;Net::LDAP&lt;/td&gt; 
+    &lt;td&gt;(Any)&lt;/td&gt; 
+    &lt;td&gt;LDAP Authentication&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td&gt;HTML::Parser&lt;/td&gt; 
+    &lt;td&gt;3.40&lt;/td&gt; 
+    &lt;td&gt;More HTML in Product/Group Descriptions&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td&gt;HTML::Scrubber&lt;/td&gt; 
+    &lt;td&gt;(Any)&lt;/td&gt; 
+    &lt;td&gt;More HTML in Product/Group Descriptions&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td&gt;XML::Twig&lt;/td&gt; 
+    &lt;td&gt;(Any)&lt;/td&gt; 
+    &lt;td&gt;Move [% terms.Bugs %] Between Installations&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td&gt;MIME::Parser&lt;/td&gt; 
+    &lt;td&gt;5.406&lt;/td&gt; 
+    &lt;td&gt;Move [% terms.Bugs %] Between Installations&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td&gt;Chart::Base&lt;/td&gt; 
+    &lt;td&gt;1.0&lt;/td&gt; 
+    &lt;td&gt;New Charts, Old Charts&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td&gt;Image::Magick&lt;/td&gt; 
+    &lt;td&gt;(Any)&lt;/td&gt; 
+    &lt;td&gt;Optionally Convert BMP Attachments to PNGs&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td&gt;PatchReader&lt;/td&gt; 
+    &lt;td&gt;0.9.4&lt;/td&gt; 
+    &lt;td&gt;Patch Viewer&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td class=&quot;req_new&quot;&gt;SOAP::Lite&lt;/td&gt; 
+    &lt;td class=&quot;req_new&quot;&gt;(Any)&lt;/td&gt; 
+    &lt;td&gt;XML-RPC Interface&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td class=&quot;req_new&quot;&gt;mod_perl2&lt;/td&gt; 
+    &lt;td class=&quot;req_new&quot;&gt;1.999022&lt;/td&gt; 
+    &lt;td&gt;mod_perl&lt;/td&gt;
+  &lt;/tr&gt;
+  &lt;tr&gt;
+    &lt;td&gt; CGI&lt;/td&gt; 
+    &lt;td&gt;3.11&lt;/td&gt; 
+    &lt;td&gt;mod_perl&lt;/td&gt;
+  &lt;/tr&gt;
+&lt;/table&gt;
+
+&lt;h2 id=&quot;v30_feat&quot;&gt;New Features and Improvements&lt;/h2&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_feat_cf&quot;&gt;Custom Fields&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_feat_mp&quot;&gt;mod_perl Support&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_feat_sq&quot;&gt;Shared Saved Searches&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;
+    &lt;a href=&quot;#v30_feat_afn&quot;&gt;Attachments and Flags on New [% terms.Bugs %]&lt;/a&gt;
+  &lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_feat_cr&quot;&gt;Custom Resolutions&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_feat_ppp&quot;&gt;Per-Product Permissions&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_feat_ui&quot;&gt;User Interface Improvements&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_feat_xml&quot;&gt;XML-RPC Interface&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_feat_skin&quot;&gt;Skins&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_feat_sbu&quot;&gt;Unchangeable Fields Appear 
+    Unchangeable&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_feat_et&quot;&gt;All Emails in Templates&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_feat_df&quot;&gt;No More Double-Filed [% terms.Bugs %]&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_feat_cc&quot;&gt;Default CC List for Components&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_feat_emi&quot;&gt;File/Modify [% terms.Bugs %] By Email&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_feat_gw&quot;&gt;Users Who Get All [% terms.Bug %] 
+    Notifications&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_feat_utf8&quot;&gt;Improved UTF-8 Support&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_feat_upda&quot;&gt;Automatic Update Notification&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_feat_welc&quot;&gt;Welcome Page for New Installs&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_feat_other&quot;&gt;Other Enhancements and Changes&lt;/a&gt;&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h3 id=&quot;v30_feat_cf&quot;&gt;Custom Fields&lt;/h3&gt;
+
+&lt;p&gt;[% terms.Bugzilla %] now includes very basic support for custom fields.&lt;/p&gt;
+
+&lt;p&gt;Users in the &lt;kbd&gt;admin&lt;/kbd&gt; group can add plain-text or drop-down
+  custom fields. You can edit the values available for drop-down fields
+  using the &amp;quot;Field Values&amp;quot; control panel.&lt;/p&gt;
+
+&lt;p&gt;Don't add too many custom fields! It can make [% terms.Bugzilla %]
+  very difficult to use. Try your best to get along with the default
+  fields, and then if you find that you can't live without custom fields
+  after a few weeks of using [% terms.Bugzilla %], only then should you
+  start your custom fields.&lt;/p&gt;
+
+&lt;h3 id=&quot;v30_feat_mp&quot;&gt;mod_perl Support&lt;/h3&gt;
+
+&lt;p&gt;[% terms.Bugzilla %] 3.0 supports mod_perl, which allows for extremely
+  enhanced page-load performance. mod_perl trades memory usage for performance,
+  allowing near-instantaneous page loads, but using much more memory.&lt;/p&gt;
+
+&lt;p&gt;If you want to enable mod_perl for your [% terms.Bugzilla %], we recommend
+  a minimum of 1.5GB of RAM, and for a site with heavy traffic, 4GB to 8GB.&lt;/p&gt;
+
+&lt;p&gt;If performance isn't that critical on your installation, you don't
+  have the memory, or you are running some other web server than
+  Apache, [% terms.Bugzilla %] still runs perfectly as a normal CGI
+  application, as well.&lt;/p&gt;
+
+&lt;h3 id=&quot;v30_feat_sq&quot;&gt;Shared Saved Searches&lt;/h3&gt;
+
+&lt;p&gt;Users can now choose to &amp;quot;share&amp;quot; their saved searches
+  with a certain group. That group will then be able to 
+  &amp;quot;subscribe&amp;quot; to those searches, and have them appear
+  in their footer.&lt;/p&gt;
+
+&lt;p&gt;If the sharer can &amp;quot;bless&amp;quot; the group he's sharing to,
+  (that is, if he can add users to that group), it's considered
+  that he's a manager of that group, and his queries show up
+  automatically in that group's footer (although they can
+  unsubscribe from any particular search, if they want.)&lt;/p&gt;
+
+&lt;p&gt;In order to allow a user to share their queries, they also
+  have to be a member of the group specified in the 
+  &lt;code&gt;querysharegroup&lt;/code&gt; parameter.&lt;/p&gt;
+
+&lt;p&gt;Users can control their shared and subscribed queries from
+  the &amp;quot;Preferences&amp;quot; screen.&lt;/p&gt;
+
+&lt;h3 id=&quot;v30_feat_afn&quot;&gt;Attachments and Flags on New [% terms.Bugs %]&lt;/h3&gt;
+
+&lt;p&gt;You can now add an attachment while you are filing a new 
+  [%+ terms.bug %].&lt;/p&gt;
+
+&lt;p&gt;You can also set flags on the [% terms.bug %] and on attachments, while
+  filing a new [% terms.bug %].&lt;/p&gt;
+
+&lt;h3 id=&quot;v30_feat_cr&quot;&gt;Custom Resolutions&lt;/h3&gt;
+
+&lt;p&gt;You can now customize the list of resolutions available
+  in [% terms.Bugzilla %], including renaming the default resolutions.&lt;/p&gt;
+
+&lt;p&gt;The resolutions &lt;code&gt;FIXED&lt;/code&gt;, &lt;code&gt;DUPLICATE&lt;/code&gt;
+  and &lt;code&gt;MOVED&lt;/code&gt; have a special meaning to [% terms.Bugzilla %],
+  though, and cannot be renamed or deleted.&lt;/p&gt;
+
+&lt;h3 id=&quot;v30_feat_ppp&quot;&gt;Per-Product Permissions&lt;/h3&gt;
+
+&lt;p&gt;You can now grant users &lt;kbd&gt;editbugs&lt;/kbd&gt; and &lt;kbd&gt;canconfirm&lt;/kbd&gt;
+  for only certain products. You can also grant users &lt;kbd&gt;editcomponents&lt;/kbd&gt;
+  on a product, which means they will be able to edit that product
+  including adding/removing components and other product-specific
+  controls.&lt;/p&gt;
+
+&lt;h3 id=&quot;v30_feat_ui&quot;&gt;User Interface Improvements&lt;/h3&gt;
+
+&lt;p&gt;There has been some work on the user interface for [% terms.Bugzilla %] 3.0,
+  including:&lt;/p&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;There is now navigation and a search box a the &lt;em&gt;top&lt;/em&gt; of
+    each page, in addition to the bar at the bottom of the page.&lt;/li&gt;
+  &lt;li&gt;A re-designed &amp;quot;Format for Printing&amp;quot; page for 
+    [%+ terms.bugs %].&lt;/li&gt;
+  &lt;li&gt;The layout of &lt;kbd&gt;show_bug.cgi&lt;/kbd&gt; (the [% terms.bug %] editing 
+    page) has been changed, and the attachment table has been redesigned.&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h3 id=&quot;v30_feat_xml&quot;&gt;XML-RPC Interface&lt;/h3&gt;
+
+&lt;p&gt;[% terms.Bugzilla %] now has a Web Services interface using the XML-RPC
+  protocol. It can be accessed by external applications by going
+  to the &lt;kbd&gt;xmlrpc.cgi&lt;/kbd&gt; on your installation.&lt;/p&gt;
+
+&lt;p&gt;Documentation can be found in the 
+  &lt;a href=&quot;[% docs_urlbase FILTER html %]api/&quot;&gt;[% terms.Bugzilla %] 
+  API Docs&lt;/a&gt;, in the various &lt;kbd&gt;Bugzilla::WebService&lt;/kbd&gt; modules.&lt;/p&gt;
+
+&lt;h3 id=&quot;v30_feat_skin&quot;&gt;Skins&lt;/h3&gt;
+
+&lt;p&gt;[% terms.Bugzilla %] can have multiple &amp;quot;skins&amp;quot; installed,
+  and users can pick between them. To write a skin, you just have to
+  write several CSS files. See the &lt;a href=&quot;[% docs_urlbase FILTER html %]cust-skins.html&quot;&gt;Custom
+  Skins Documentation&lt;/a&gt; for more details.&lt;/p&gt;
+
+&lt;p&gt;We currently don't have any alternate skins shipping with
+  [%+ terms.Bugzilla %]. If you write an alternate skin, please
+  let us know!&lt;/p&gt;
+
+&lt;h3 id=&quot;v30_feat_sbu&quot;&gt;Unchangeable Fields Appear Unchangeable&lt;/h3&gt;
+
+&lt;p&gt;As long as you are logged in, when viewing [% terms.abug %], if you 
+  cannot change a field, it will not look like you can change it. That 
+  is, the value will just appear as plain text.&lt;/p&gt;
+
+&lt;h3 id=&quot;v30_feat_et&quot;&gt;All Emails in Templates&lt;/h3&gt;
+
+&lt;p&gt;All outbound emails are now controlled by the templating system.
+  What used to be the &lt;code&gt;passwordmail&lt;/code&gt;, &lt;code&gt;whinemail&lt;/code&gt;,
+  &lt;code&gt;newchangedmail&lt;/code&gt; and &lt;code&gt;voteremovedmail&lt;/code&gt;
+  parameters are now all templates in the &lt;kbd&gt;template/&lt;/kbd&gt; directory.&lt;/p&gt;
+
+&lt;p&gt;This means that it's now much easier to customize your outbound
+  emails, and it's also possible for localizers to have more
+  localized emails as part of their language packs, if they want.&lt;/p&gt;
+
+&lt;p&gt;We also added a &lt;code&gt;mailfrom&lt;/code&gt; parameter to let you set
+  who shows up in the &lt;code&gt;From&lt;/code&gt; field on all emails that
+  [%+ terms.Bugzilla %] sends.&lt;/p&gt;
+
+&lt;h3 id=&quot;v30_feat_df&quot;&gt;No More Double-Filed [% terms.Bugs %]&lt;/h3&gt;
+
+&lt;p&gt;Users of [% terms.Bugzilla %] will sometimes accidentally submit 
+  [%+ terms.abug %] twice, either by going back in their web browser, 
+  or just by refreshing a page. In the past, this could file the same 
+  [%+ terms.bug %] twice (or even three times) in a row, irritating 
+  developers and confusing users.&lt;/p&gt;
+
+&lt;p&gt;Now, if you try to submit [% terms.abug %] twice from the same screen 
+  (by going back or by refreshing the page), [% terms.Bugzilla %] will warn 
+  you about what you're doing, before it actually submits the duplicate
+  [%+ terms.bug %].&lt;/p&gt;
+
+&lt;h3 id=&quot;v30_feat_cc&quot;&gt;Default CC List for Components&lt;/h3&gt;
+
+&lt;p&gt;You can specify a list of users who will &lt;em&gt;always&lt;/em&gt; be added to
+  the CC list of new [% terms.bugs %] in a component.&lt;/p&gt;
+
+&lt;h3 id=&quot;v30_feat_emi&quot;&gt;File/Modify [% terms.Bugs %] By Email&lt;/h3&gt;
+
+&lt;p&gt;You can now file or modify [% terms.bugs %] via email. Previous versions
+  of [% terms.Bugzilla %] included this feature only as an
+  unsupported add-on, but it is now an official interface to
+  [%+ terms.Bugzilla %].&lt;/p&gt;
+
+&lt;p&gt;For more details see the &lt;a href=&quot;[% docs_urlbase FILTER html %]api/email_in.html&quot;&gt;documentation
+  for email_in.pl&lt;/a&gt;.&lt;/p&gt;
+
+&lt;h3 id=&quot;v30_feat_gw&quot;&gt;Users Who Get All [% terms.Bug %] Notifications&lt;/h3&gt;
+
+&lt;p&gt;There is now a parameter called &lt;kbd&gt;globalwatchers&lt;/kbd&gt;. This
+  is a comma-separated list of [% terms.Bugzilla %] users who will
+  get all [% terms.bug %] notifications generated by [% terms.Bugzilla %].&lt;/p&gt;
+
+&lt;p&gt;Group controls still apply, though, so users who can't see [% terms.abug %]
+  still won't get notifications about that [% terms.bug %].&lt;/p&gt;
+
+&lt;h3 id=&quot;v30_feat_utf8&quot;&gt;Improved UTF-8 Support&lt;/h3&gt;
+
+&lt;p&gt;[% terms.Bugzilla %] users running MySQL should now have excellent
+  UTF-8 support if they turn on the &lt;kbd&gt;utf8&lt;/kbd&gt; parameter. (New
+  installs have this parameter on by default.) [% terms.Bugzilla %]
+  now correctly supports searching and sorting in non-English languages,
+  including multi-bytes languages such as Chinese.&lt;/p&gt;
+
+&lt;h3 id=&quot;v30_feat_upda&quot;&gt;Automatic Update Notification&lt;/h3&gt;
+
+&lt;p&gt;If you belong to the &lt;kbd&gt;admin&lt;/kbd&gt; group, you will be notified
+  when you log in if there is a new release of [% terms.Bugzilla %]
+  available to download.&lt;/p&gt;
+
+&lt;p&gt;You can control these notifications by changing the 
+  &lt;kbd&gt;upgrade_notification&lt;/kbd&gt; parameter.&lt;/p&gt;
+
+&lt;p&gt;If your [% terms.Bugzilla %] installation is on a machine that needs to go
+  through a proxy to access the web, you may also have to set the
+  &lt;kbd&gt;proxy_url&lt;/kbd&gt; parameter.&lt;/p&gt;
+
+&lt;h3 id=&quot;v30_feat_welc&quot;&gt;Welcome Page for New Installs&lt;/h3&gt;
+
+&lt;p&gt;When you log in for the first time on a brand-new [% terms.Bugzilla %]
+  installation, you will be presented with a page that describes
+  where you should go from here, and what parameters you should set.&lt;/p&gt;
+
+&lt;h3 id=&quot;v30_feat_qs&quot;&gt;QuickSearch Plugin for IE7 and Firefox 2&lt;/h3&gt;
+
+&lt;p&gt;Firefox 2 users and Internet Explorer 7 users will be presented
+  with the option to add [% terms.Bugzilla %] to their search bar.
+  This uses the 
+  &lt;a href=&quot;page.cgi?id=quicksearch.html&quot;&gt;QuickSearch syntax&lt;/a&gt;.&lt;/p&gt;
+
+&lt;h3 id=&quot;v30_feat_other&quot;&gt;Other Enhancements and Changes&lt;/h3&gt;
+
+&lt;p&gt;These are either minor enhancements, or enhancements that have
+  very short descriptions. Some of these are very useful, though!&lt;/p&gt;
+
+&lt;h4&gt;Enhancements That Affect [% terms.Bugzilla %] Users&lt;/h4&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;In comments, quoted text (lines that start with &lt;kbd&gt;&amp;gt;&lt;/kbd&gt;)
+    will be a different color from normal text.&lt;/li&gt;
+  &lt;li&gt;There is now a user preference that will add you to the CC list
+    of any [% terms.bug %] you modify. Note that it's &lt;strong&gt;on&lt;/strong&gt; 
+    by default.&lt;/li&gt;
+  &lt;li&gt;[% terms.Bugs %] can now be filed with an initial state of 
+    &lt;kbd&gt;ASSIGNED&lt;/kbd&gt;, if you are in the &lt;kbd&gt;editbugs&lt;/kbd&gt; group.&lt;/li&gt;
+  &lt;li&gt;By default, comment fields will zoom large when you are typing in them,
+    and become small when you move out of them. You can disable this
+    in your user preferences.&lt;/li&gt;
+  &lt;li&gt;You can hide obsolete attachments on [% terms.abug %] by clicking
+    &amp;quot;Hide Obsolete&amp;quot; at the bottom of the attachment table.&lt;/li&gt;
+  &lt;li&gt;If [% terms.abug %] has flags set, and you move it to a different 
+    product that has flags with the same name, the flags will be 
+    preserved.&lt;/li&gt;
+  &lt;li&gt;You now can't request a flag to be set by somebody who can't set it
+    ([% terms.Bugzilla %] will throw an error if you try).&lt;/li&gt;
+  &lt;li&gt;Many new headers have been added to outbound [% terms.Bugzilla %]
+    [%+ terms.bug %] emails: &lt;code&gt;X-Bugzilla-Status&lt;/code&gt;,
+    &lt;code&gt;X-Bugzilla-Priority&lt;/code&gt;, &lt;code&gt;X-Bugzilla-Assigned-To&lt;/code&gt;,
+    &lt;code&gt;X-Bugzilla-Target-Milestone&lt;/code&gt;, and 
+    &lt;code&gt;X-Bugzilla-Changed-Fields&lt;/code&gt;, &lt;code&gt;X-Bugzilla-Who&lt;/code&gt;.
+    You can look at an email to get an idea of what they contain.&lt;/li&gt;
+  &lt;li&gt;In addition to the old &lt;code&gt;X-Bugzilla-Reason&lt;/code&gt; email header
+    which tells you why you got an email, if you got an email because
+    you were watching somebody, there is now an 
+    &lt;code&gt;X-Bugzilla-Watch-Reason&lt;/code&gt; header that tells you who you
+    were watching and what role they had.&lt;/li&gt;
+  &lt;li&gt;If you hover your mouse over a full URL (like 
+    &lt;code&gt;http://bugs.mycompany.com/show_bug.cgi?id=1212&lt;/code&gt;) that 
+    links to [% terms.abug %], you will see the title of the 
+    [%+ terms.bug %]. Of course, this only works for [% terms.bugs %] in your
+    [%+ terms.Bugzilla %] installation.&lt;/li&gt;
+  &lt;li&gt;If your installation has user watching enabled, you will now see
+    the users that you can remove from your watch-list as a multi-select
+    box, much like the current CC list. (Previously it was just a text
+    box.)&lt;/li&gt;
+  &lt;li&gt;When a user creates their own account in [% terms.Bugzilla %], the 
+    account is now not actually created until they verify their email
+    address by clicking on a link that is emailed to them.&lt;/li&gt;
+  &lt;li&gt;You can change [% terms.abug %]'s resolution without reopening it.&lt;/li&gt;
+  &lt;li&gt;When you view the dependency tree on [% terms.abug %], resolved 
+    [%+ terms.bugs %] will be hidden by default. (In previous versions,
+    resolved [% terms.bugs %] were shown by default.)&lt;/li&gt;
+  &lt;li&gt;When viewing [% terms.bug %] activity, fields that hold [% terms.bug %] 
+    numbers (such as &amp;quot;Blocks&amp;quot;) will have the [% terms.bug %] numbers
+    displayed as links to those [% terms.bugs %].&lt;/li&gt;
+  &lt;li&gt;When viewing the &amp;quot;Keywords&amp;quot; field in [% terms.abug %] list,
+    it will be sorted alphabetically, so you can sanely sort a list on
+    that field.&lt;/li&gt;
+  &lt;li&gt;In most places, the Version field is now sorted using a version-sort
+    (so 1.10 is greater than 1.2) instead of an alphabetical sort.&lt;/li&gt;
+  &lt;li&gt;Options for flags will only appear if you can set them. So, for
+    example, if you can't grant &lt;kbd&gt;+&lt;/kbd&gt; on a flag, that option
+    won't appear for you.&lt;/li&gt;
+  &lt;li&gt;You can limit the product-related output of &lt;kbd&gt;config.cgi&lt;/kbd&gt;
+    by specifying a &lt;kbd&gt;product=&lt;/kbd&gt; URL argument, containing the name
+    of a product. You can specify the argument more than once for multiple
+    products.&lt;/li&gt;
+  &lt;li&gt;You can now search the boolean charts on whether or not a comment
+    is private.&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h4&gt;Enhancements For Administrators&lt;/h4&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;Administrators can now delete attachments, making them disappear
+    entirely from [% terms.Bugzilla %].&lt;/li&gt;
+  &lt;li&gt;&lt;kbd&gt;sanitycheck.cgi&lt;/kbd&gt; can now only be accessed by users
+    in the &lt;kbd&gt;editcomponents&lt;/kbd&gt; group.&lt;/li&gt;
+  &lt;li&gt;The &amp;quot;Field Values&amp;quot; control panel can now only be accessed
+    by users in the &lt;kbd&gt;admin&lt;/kbd&gt; group. (Previously it was accessible
+    to anybody in the &lt;kbd&gt;editcomponents&lt;/kbd&gt; group.)&lt;/li&gt;
+  &lt;li&gt;There is a new parameter &lt;kbd&gt;announcehtml&lt;/kbd&gt;, that will allow
+    you to enter some HTML that will be displayed at the top of every
+    page, as an announcement.&lt;/li&gt;
+  &lt;li&gt;The &lt;kbd&gt;loginnetmask&lt;/kbd&gt; parameter now defaults to 0 for new
+    installations, meaning that as long as somebody has the right
+    login cookie, they can log in from any IP address. This makes
+    life a lot easier for dial-up users or other users whose IP
+    changes a lot. This could be done because the login cookie is now
+    very random, and thus secure.&lt;/li&gt;
+  &lt;li&gt;Classifications now have sortkeys, so they can be sorted in an
+    order that isn't alphabetical.&lt;/li&gt;
+  &lt;li&gt;Authentication now supports LDAP over SSL (LDAPS) or TLS (using
+    the STARTLS command) in addition to plain LDAP.&lt;/li&gt;
+  &lt;li&gt;LDAP users can have their LDAP username be their email address,
+    instead of having the LDAP &lt;kbd&gt;mail&lt;/kbd&gt; attribute be their
+    email address. You may wish to set the &lt;kbd&gt;emailsuffix&lt;/kbd&gt;
+    parameter if you do this.&lt;/li&gt;
+  &lt;li&gt;Administrators can now see what has changed in a user account,
+    when using the &amp;quot;Users&amp;quot; control panel.&lt;/li&gt;
+  &lt;li&gt;&lt;code&gt;REMIND&lt;/code&gt; and &lt;code&gt;LATER&lt;/code&gt; are no longer part
+    of the default list of resolutions. Upgrading installations will
+    not be affected--they will still have these resolutions.&lt;/li&gt;
+  &lt;li&gt;&lt;kbd&gt;editbugs&lt;/kbd&gt; is now the default for the &lt;kbd&gt;timetrackinggroup&lt;/kbd&gt;
+    parameter, meaning that time-tracking will be on by default in a new
+    installation.&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h2 id=&quot;v30_issues&quot;&gt;Outstanding Issues&lt;/h2&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=69621&quot;&gt;
+    [%- terms.Bug %] 69621&lt;/a&gt;: If you rename or remove a keyword that is
+    in use on [% terms.bugs %], you will need to rebuild the &quot;keyword cache&quot;
+    by running &lt;a href=&quot;sanitycheck.cgi&quot;&gt;sanitycheck.cgi&lt;/a&gt; and choosing 
+    the option to rebuild the cache when it asks. Otherwise keywords may 
+    not show up properly in search results.&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=99215&quot;&gt;
+    [%- terms.Bug %] 99215&lt;/a&gt;: Flags are not protected by &quot;mid-air 
+    collision&quot; detection. Nor are any attachment changes.&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=89822&quot;&gt;
+    [%- terms.Bug %] 89822&lt;/a&gt;: When changing multiple [% terms.bugs %] at 
+    the same time, there is no &quot;mid-air collision&quot; protection.&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=276230&quot;&gt;
+    [%- terms.Bug %] 276230&lt;/a&gt;: The support for restricting access to 
+    particular Categories of New Charts is not complete. You should treat 
+    the 'chartgroup' Param as the only access mechanism available.&lt;br&gt;
+    However, charts migrated from Old Charts will be restricted to 
+    the groups that are marked MANDATORY for the corresponding Product.
+    There is currently no way to change this restriction, and the 
+    groupings will not be updated if the group configuration
+    for the Product changes.&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=370370&quot;&gt;
+    [%- terms.Bug %] 370370&lt;/a&gt;: mod_perl support is currently not
+    working on Windows machines.&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=361149&quot;&gt;
+    [%- terms.Bug %] 361149&lt;/a&gt;: If you are using Perl 5.8.0, you may
+    get a lot of warnings in your Apache error_log about &quot;deprecated
+    pseudo-hashes.&quot; These are harmless--they are a b[%# fool test %]ug in 
+    Perl 5.8.0. Perl 5.8.1 and later do not have this problem.&lt;/li&gt;
+  &lt;li&gt;[% terms.Bugzilla %] 3.0rc1 allowed custom field column names in 
+    the database to be mixed-case. [% terms.Bugzilla %] 3.0 only allows
+    lowercase column names. It will fix any column names that you have
+    made mixed-case, but if you have custom fields that previously were
+    mixed-case in any Saved Search, you will have to re-create that Saved
+    Search yourself.&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h2 id=&quot;v30_security&quot;&gt;Security Updates in This Release&lt;/h2&gt;
+
+&lt;h3&gt;3.0.6&lt;/h3&gt;
+
+&lt;p&gt;[% terms.Bugzilla %] contains a minor security fix. For details, see the
+  &lt;a href=&quot;http://www.bugzilla.org/security/2.20.6/&quot;&gt;Security Advisory&lt;/a&gt;.&lt;/p&gt;
+
+&lt;h3&gt;3.0.5&lt;/h3&gt;
+
+&lt;p&gt;[% terms.Bugzilla %] contains one security fix for 
+  &lt;a href=&quot;[% docs_urlbase FILTER html %]api/importxml.html&quot;&gt;importxml.pl&lt;/a&gt;.
+  For details, see the 
+  &lt;a href=&quot;http://www.bugzilla.org/security/2.22.4/&quot;&gt;Security Advisory&lt;/a&gt;.&lt;/p&gt;
+
+&lt;h3&gt;3.0.4&lt;/h3&gt;
+
+&lt;p&gt;[% terms.Bugzilla %] 3.0.4 contains three security fixes.
+  For details, see the
+  &lt;a href=&quot;http://www.bugzilla.org/security/2.20.5/&quot;&gt;Security Advisory&lt;/a&gt;.&lt;/p&gt;
+
+&lt;h3&gt;3.0.3&lt;/h3&gt;
+
+&lt;p&gt;No security fixes in this release.&lt;/p&gt;
+
+&lt;h3&gt;3.0.2&lt;/h3&gt;
+
+&lt;p&gt;[% terms.Bugzilla %] 3.0.1 had an important security fix that is
+  critical for public installations with &quot;requirelogin&quot; turned on.
+  For details, see the
+  &lt;a href=&quot;http://www.bugzilla.org/security/3.0.1/&quot;&gt;Security Advisory&lt;/a&gt;&lt;/p&gt;
+
+&lt;h3&gt;3.0.1&lt;/h3&gt;
+
+&lt;p&gt;[% terms.Bugzilla %] 3.0 had three security issues that have been
+  fixed in this release: one minor information leak, one hole only
+  exploitable by an admin or using &lt;code&gt;email_in.pl&lt;/code&gt;, and one in an
+  uncommonly-used template. For details, see the 
+  &lt;a href=&quot;http://www.bugzilla.org/security/2.20.4/&quot;&gt;Security Advisory&lt;/a&gt;.&lt;/p&gt;
+
+&lt;h2 id=&quot;v30_upgrading&quot;&gt;How to Upgrade From An Older Version&lt;/h2&gt;
+
+&lt;h3 id=&quot;v30_upgrading_notes&quot;&gt;Notes For Upgraders&lt;/h3&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;If you upgrade by CVS, there are several .cvsignore files
+    that are now in CVS instead of being locally created by 
+    &lt;kbd&gt;checksetup.pl&lt;/kbd&gt;. This means that you will have to
+    delete those files when CVS tells you there's a conflict, and
+    then run &lt;kbd&gt;cvs update&lt;/kbd&gt; again.&lt;/li&gt;
+  &lt;li&gt;In this version of [% terms.Bugzilla %], the Summary field
+    is now limited to 255 characters. When you upgrade, any Summary
+    longer than that will be truncated, and the old summary will be
+    preserved in a comment.&lt;/li&gt;
+  &lt;li&gt;If you have the &lt;kbd&gt;utf8&lt;/kbd&gt; parameter turned on, at some
+    point you will have to convert your database. &lt;kbd&gt;checksetup.pl&lt;/kbd&gt;
+    will tell you when this is, and it will give you certain instructions
+    at that time, that you have to follow before you can complete
+    the upgrade. Don't do the conversion yourself manually--follow
+    the instructions of &lt;kbd&gt;checksetup.pl&lt;/kbd&gt;.&lt;/li&gt;
+  &lt;li&gt;If you ever ran 2.23.3, 2.23.4, or 3.0rc1, you will have to run
+    &lt;kbd&gt;./collectstats.pl --regenerate&lt;/kbd&gt; at the command line, because
+    the data for your Old Charts is corrupted. This can take several days,
+    so you may only want to run it if you use Old Charts.&lt;/li&gt;
+  &lt;li&gt;You should also read the Outstanding Issues sections of
+    &lt;a href=&quot;#v30_previous&quot;&gt;older release notes&lt;/a&gt; if you are upgrading
+    from a version lower than 2.22.&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h3&gt;Steps For Upgrading&lt;/h3&gt;
+
+&lt;p&gt;Once you have read the notes above, see the 
+  &lt;a href=&quot;[% docs_urlbase FILTER html %]upgrade.html&quot;&gt;Upgrading 
+  documentation&lt;/a&gt; for instructions on how to upgrade.&lt;/p&gt;
+
+&lt;h2 id=&quot;v30_code_changes&quot;&gt;Code Changes Which May Affect Customizations&lt;/h2&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_code_loc&quot;&gt;&lt;strong&gt;Packagers:&lt;/strong&gt; Location
+    Variables Have Moved&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_code_hooks&quot;&gt;Hooks!&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_code_api&quot;&gt;API Documentation&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_code_globals&quot;&gt;Elimination of globals.pl&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_code_scope&quot;&gt;Cleaned Up Variable Scoping Issues&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_code_sql&quot;&gt;No More SendSQL&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_code_auth&quot;&gt;Auth Re-write&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_code_obj&quot;&gt;Bugzilla::Object&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_code_req&quot;&gt;Bugzilla-&amp;gt;request_cache&lt;/a&gt;&lt;/li&gt;
+  &lt;li&gt;&lt;a href=&quot;#v30_code_other&quot;&gt;Other Changes&lt;/a&gt;&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h3 id=&quot;v30_code_loc&quot;&gt;&lt;strong&gt;Packagers:&lt;/strong&gt; Location Variables
+    Have Moved&lt;/h3&gt;
+
+&lt;p&gt;In previous versions of [% terms.Bugzilla %], &lt;kbd&gt;Bugzilla::Config&lt;/kbd&gt;
+  held all the paths for different things, such as the path to localconfig
+  and the path to the &lt;kbd&gt;data/&lt;/kbd&gt; directory.&lt;/p&gt;
+
+&lt;p&gt;Now, all of this data is stored in a subroutine,
+  &lt;kbd&gt;Bugzilla::Constants::bz_locations&lt;/kbd&gt;.&lt;/p&gt;
+
+&lt;p&gt;Also, note that for mod_perl, &lt;kbd&gt;bz_locations&lt;/kbd&gt; must return
+  &lt;em&gt;absolute&lt;/em&gt; (not relative) paths. There is already code in that
+  subroutine to help you with this.&lt;/p&gt;
+
+&lt;h3 id=&quot;v30_code_hooks&quot;&gt;Hooks!&lt;/h3&gt;
+
+&lt;p&gt;[% terms.Bugzilla %] now supports a code hook mechanism. See the 
+  documentation for 
+  &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/Hook.html&quot;&gt;Bugzilla::Hook&lt;/a&gt;
+  for more details.&lt;/p&gt;
+
+&lt;p&gt;This gives [% terms.Bugzilla %] very advanced plugin support. You can
+  hook templates, hook code, add new parameters, and use the XML-RPC
+  interface. So we'd like to see some [% terms.Bugzilla %] plugins
+  written! Let us know on the &lt;a href=&quot;http://bugzilla.org/cgi-bin/mj_wwwusr?func=lists-long-full&amp;amp;extra=developers&quot;&gt;developers&amp;#64;bugzilla.org&lt;/a&gt;
+  mailing list if you write a plugin.&lt;/p&gt;
+
+&lt;p&gt;If you need more hooks, please 
+  &lt;a href=&quot;http://www.bugzilla.org/developers/reporting_bugs.html&quot;&gt;File a b&lt;!-- --&gt;ug&lt;/a&gt;!&lt;/p&gt;
+
+&lt;h3 id=&quot;v30_code_api&quot;&gt;API Documentation&lt;/h3&gt;
+
+&lt;p&gt;[% terms.Bugzilla %] now ships with all of its perldoc built
+  as HTML. Go ahead and read the
+  &lt;a href=&quot;[% docs_urlbase FILTER html %]api/&quot;&gt;API Documentation&lt;/a&gt;
+  for all of the [% terms.Bugzilla %] modules now! Even scripts like
+  &lt;kbd&gt;checksetup.pl&lt;/kbd&gt; have HTML documentation.&lt;/p&gt;
+
+&lt;h3 id=&quot;v30_code_globals&quot;&gt;Elimination of globals.pl&lt;/h3&gt;
+
+&lt;p&gt;The old file &lt;kbd&gt;globals.pl&lt;/kbd&gt; has been eliminated.
+  Its code is now in various modules. Each function went to the module
+  that was appropriate for it.&lt;/p&gt;
+
+&lt;p&gt;Usually we filed [% terms.abug %] in 
+  &lt;a href=&quot;https://bugzilla.mozilla.org&quot;&gt;bugzilla.mozilla.org&lt;/a&gt; for
+  each function we moved. You can search there for the old name of
+  the function, and that should get you the information about what
+  it's called now and where it lives.&lt;/p&gt;
+
+&lt;h3 id=&quot;v30_code_scope&quot;&gt;Cleaned Up Variable Scoping Issues&lt;/h3&gt;
+
+&lt;p&gt;In normal perl, you can have code like this:&lt;/p&gt;
+&lt;pre&gt;my $var = 0;
+sub y { $var++ }&lt;/pre&gt;
+
+&lt;p&gt;However, under mod_perl that doesn't work. So variables are no
+  longer &amp;quot;shared&amp;quot; with subroutines--instead all variables
+  that a subroutine needs must be declared inside the subroutine itself.&lt;/p&gt;
+
+&lt;h3 id=&quot;v30_code_sql&quot;&gt;No More SendSQL&lt;/h3&gt;
+
+&lt;p&gt;The old &lt;kbd&gt;SendSQL&lt;/kbd&gt; function and all of its companions are
+  &lt;strong&gt;gone&lt;/strong&gt;. Instead, we now use DBI for all database
+  interaction.&lt;/p&gt;
+
+&lt;p&gt;For more information about how to use 
+  &lt;a href=&quot;http://search.cpan.org/perldoc?DBI&quot;&gt;DBI&lt;/a&gt; with 
+  [%+ terms.Bugzilla %], see the 
+  &lt;a href=&quot;http://www.bugzilla.org/docs/developer.html#sql-sendreceive&quot;&gt;Developer's
+  Guide Section About DBI&lt;/a&gt;&lt;/p&gt;
+
+&lt;h3 id=&quot;v30_code_auth&quot;&gt;Auth Re-write&lt;/h3&gt;
+
+&lt;p&gt;The &lt;kbd&gt;Bugzilla::Auth&lt;/kbd&gt; family of modules have been completely
+  re-written. For details on how the new structure of authentication,
+  read the 
+  &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/Auth.html&quot;&gt;Bugzilla::Auth
+  API docs&lt;/a&gt;.&lt;/p&gt;
+
+&lt;p&gt;It should be very easy to write new authentication plugins, now.&lt;/p&gt;
+
+&lt;h3 id=&quot;v30_code_obj&quot;&gt;Bugzilla::Object&lt;/h3&gt;
+
+&lt;p&gt;There is a new base class for most of our objects, 
+  &lt;a href=&quot;[% docs_urlbase FILTER html %]api/Bugzilla/Object.html&quot;&gt;Bugzilla::Object&lt;/a&gt;.
+  It makes it really easy to create new objects based on things that are 
+  in the database.&lt;/p&gt;
+
+&lt;h3 id=&quot;v30_code_req&quot;&gt;Bugzilla-&amp;gt;request-cache&lt;/h3&gt;
+
+&lt;p&gt;&lt;kbd&gt;Bugzilla.pm&lt;/kbd&gt; used to cache things like the database
+  connection in package-global variables (like &lt;kbd&gt;$_dbh&lt;/kbd&gt;).
+  That doesn't work in mod_perl, so instead now there's a hash
+  that can be accessed through &lt;code&gt;Bugzilla-&amp;gt;request_cache&lt;/code&gt;
+  to store things for the rest of the current page request.&lt;/p&gt;
+
+&lt;p&gt;You shouldn't access &lt;code&gt;Bugzilla-&amp;gt;request_cache&lt;/code&gt; directly,
+  but you should use it inside of &lt;kbd&gt;Bugzilla.pm&lt;/kbd&gt; if you modify
+  that. The only time you should be accessing it directly is if you need
+  to reset one of the caches. Hash keys are always named after the function
+  that they cache, so to reset the template object, you'd do:
+  &lt;code&gt;delete Bugzilla-&amp;gt;request_cache-&amp;gt;{template};&lt;/code&gt;.&lt;/p&gt;
+
+&lt;h3 id=&quot;v30_code_other&quot;&gt;Other Changes&lt;/h3&gt;
+
+&lt;ul&gt;
+  &lt;li&gt;&lt;kbd&gt;checksetup.pl&lt;/kbd&gt; has been completely re-written, and most
+    of its code moved into modules in the &lt;kbd&gt;Bugzilla::Install&lt;/kbd&gt;
+    namespace. See the
+    &lt;a href=&quot;[% docs_urlbase FILTER html %]api/checksetup.html&quot;&gt;checksetup
+    documentation&lt;/a&gt; and &lt;a href=&quot;https://bugzilla.mozilla.org/showdependencytree.cgi?id=277502&amp;amp;hide_resolved=0&quot;&gt;[% terms.Bugzilla %]
+   [%+ terms.bug %] 277502&lt;/a&gt; for details.&lt;/li&gt;
+  &lt;li&gt;Instead of &lt;kbd&gt;UserInGroup()&lt;/kbd&gt;, all of [% terms.Bugzilla %] now 
+    uses &lt;kbd&gt;Bugzilla-&amp;gt;user-&amp;gt;in_group&lt;/kbd&gt;&lt;/li&gt;
+  &lt;li&gt;mod_perl doesn't like dependency loops in modules, so we now have
+    a test for that detects dependency loops in modules when you run
+   &lt;kbd&gt;runtests.pl&lt;/kbd&gt;.&lt;/li&gt;
+  &lt;li&gt;&lt;kbd&gt;globals.pl&lt;/kbd&gt; used to modify the environment variables,
+    like &lt;kbd&gt;PATH&lt;/kbd&gt;. That now happens in &lt;kbd&gt;Bugzilla.pm&lt;/kbd&gt;.&lt;/li&gt;
+  &lt;li&gt;Templates can now link to the documentation more easily.
+    See the &lt;kbd&gt;global/code-error.html.tmpl&lt;/kbd&gt; and
+    &lt;kbd&gt;global/user-error.html.tmpl&lt;/kbd&gt; templates for examples.
+    (Search for &amp;quot;docslinks.&amp;quot;)&lt;/li&gt;
+  &lt;li&gt;Parameters are accessed through &lt;kbd&gt;Bugzilla-&amp;gt;params&lt;/kbd&gt;
+    instead of using the &lt;kbd&gt;Param()&lt;/kbd&gt; function, now.&lt;/li&gt;
+  &lt;li&gt;The variables from the &lt;kbd&gt;localconfig&lt;/kbd&gt; file are accessed
+    through the &lt;code&gt;Bugzilla-&amp;gt;localconfig&lt;/code&gt; hash instead of through
+    &lt;kbd&gt;Bugzilla::Config&lt;/kbd&gt;.&lt;/li&gt;
+  &lt;li&gt;&lt;kbd&gt;Bugzilla::BugMail::MessageToMTA()&lt;/kbd&gt; has moved into its
+    own module, along with other mail-handling code, called
+    &lt;kbd&gt;Bugzilla::Mailer&lt;/kbd&gt;&lt;/li&gt;
+  &lt;li&gt;The &lt;kbd&gt;CheckCanChangeField()&lt;/kbd&gt; subroutine in 
+    &lt;kbd&gt;process_bug.cgi&lt;/kbd&gt; has been moved to &lt;kbd&gt;Bugzilla::Bug&lt;/kbd&gt;,
+    and is now a method of [% terms.abug %] object.&lt;/li&gt;
+  &lt;li&gt;The code that used to be in the &lt;kbd&gt;global/banner.html.tmpl&lt;/kbd&gt;
+    template is now in &lt;kbd&gt;global/header.html.tmpl&lt;/kbd&gt;. The banner
+    still exists, but the file is empty.&lt;/li&gt;
+&lt;/ul&gt;
+
+&lt;h2 id=&quot;v30_previous&quot;&gt;Release Notes For Previous Versions&lt;/h2&gt;
+
+&lt;p&gt;Release notes for versions of [% terms.Bugzilla %] for versions
+  prior to 3.0 are only available in text format: 
+  &lt;a href=&quot;[% docs_urlbase FILTER remove('html/$') FILTER html %]rel_notes.txt&quot;&gt;Release Notes for [% terms.Bugzilla %] 2.22
+  and Earlier&lt;/a&gt;.&lt;/p&gt;
+
+[% INCLUDE global/footer.html.tmpl %]
+
+[% BLOCK db_req %]
+  [% SET m = DB_MODULE.$db %]
+  &lt;h3 id=&quot;v40_req_[% db FILTER html %]&quot;&gt;For [% m.name FILTER html %] Users&lt;/h3&gt;
+
+  &lt;ul&gt;
+    &lt;li&gt;[% m.name FILTER html %]
+       [%+ '&lt;span class=&quot;req_new&quot;&gt;' IF db_new %]v[% m.db_version FILTER html %]
+       [% '&lt;/span&gt;' IF db_new %]
+       &lt;/li&gt;
+    &lt;li&gt;&lt;strong&gt;perl module:&lt;/strong&gt;
+      [%+ m.dbd.module FILTER html %] 
+      [% '&lt;span class=&quot;req_new&quot;&gt;' IF dbd_new %]v[% m.dbd.version FILTER html %]
+      [% '&lt;/span&gt;' IF dbd_new %]&lt;/li&gt;
+  &lt;/ul&gt;
+[% END %]
+
+
+[% BLOCK req_table %]
+  &lt;table class=&quot;req_table&quot; border=&quot;0&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
+    &lt;tr&gt;
+      &lt;th&gt;Module&lt;/th&gt; &lt;th&gt;Version&lt;/th&gt;
+      [% IF include_feature %]
+        &lt;th&gt;Enables Feature&lt;/th&gt;
+      [% END %]
+    &lt;/tr&gt;
+    [% FOREACH req = reqs %]
+      &lt;tr&gt;
+        &lt;td [% ' class=&quot;req_new&quot;' IF new.contains(req.package) %]&gt;
+          [%- req.module FILTER html %]&lt;/td&gt; 
+        &lt;td [% ' class=&quot;req_new&quot;' IF updated.contains(req.package) 
+                                     OR new.contains(req.package) %]&gt;
+          [%- IF req.version == 0 %]
+            (Any)
+          [% ELSE %]
+            [%- req.version FILTER html %]
+          [% END %]
+        &lt;/td&gt;
+        [% IF include_feature %] 
+          &lt;td&gt;[% req.feature.join(', ') FILTER html %]&lt;/td&gt;
+        [% END %]
+      &lt;/tr&gt;
+    [% END %]
+&lt;/table&gt;
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultpagessudohtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/pages/sudo.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/pages/sudo.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/pages/sudo.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -51,14 +51,14 @@
</span><span class="cx"> &lt;/p&gt;
</span><span class="cx"> 
</span><span class="cx"> &lt;p id=&quot;message&quot;&gt;
</span><del>-  [% IF user.groups.bz_sudoers %]
</del><ins>+  [% IF user.in_group('bz_sudoers') %]
</ins><span class="cx">     You are a member of the &lt;b&gt;bz_sudoers&lt;/b&gt; group.  You may use this 
</span><span class="cx">     feature to impersonate others.
</span><span class="cx">   [% ELSE %]
</span><span class="cx">     You are not a member of an appropriate group.  You may not use this 
</span><span class="cx">     feature.
</span><span class="cx">   [% END %]
</span><del>-  [% IF user.groups.bz_sudo_protect %]
</del><ins>+  [% IF user.in_group('bz_sudo_protect') %]
</ins><span class="cx">     &lt;br&gt;
</span><span class="cx">     You are a member of the &lt;b&gt;bz_sudo_protect&lt;/b&gt; group.  Other people will 
</span><span class="cx">     not be able to use this feature to impersonate you.
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultpagesvotinghtmltmpl"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/template/en/default/pages/voting.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/pages/voting.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/pages/voting.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,69 +0,0 @@
</span><del>-[%# The contents of this file are subject to the Mozilla Public
-  # License Version 1.1 (the &quot;License&quot;); you may not use this file
-  # except in compliance with the License. You may obtain a copy of
-  # the License at http://www.mozilla.org/MPL/
-  #
-  # Software distributed under the License is distributed on an &quot;AS
-  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
-  # implied. See the License for the specific language governing
-  # rights and limitations under the License.
-  #
-  # The Original Code is the Bugzilla Bug Tracking System.
-  #
-  # The Initial Developer of the Original Code is Netscape Communications
-  # Corporation. Portions created by Netscape are
-  # Copyright (C) 1998 Netscape Communications Corporation. All
-  # Rights Reserved.
-  #
-  # Contributor(s): Terry Weissman &lt;terry@mozilla.org&gt;
-  #                 Gervase Markham &lt;gerv@gerv.net&gt;
-  #%]
-
-[% PROCESS global/variables.none.tmpl %]
-[% INCLUDE global/header.html.tmpl title = &quot;Voting&quot; %]
-
-&lt;p&gt;[% terms.Bugzilla %] has a &quot;voting&quot; feature. Each product allows users to 
-have a certain number of votes. (Some products may not allow any, which means 
-you can't vote on things in those products at all.) With your vote, you 
-indicate which [% terms.bugs %] you think are the most important and 
-would like to see fixed. Note that voting is nowhere near as effective 
-as providing a fix yourself.&lt;/p&gt;
-
-&lt;p&gt;Depending on how the administrator has configured the relevant product,
-you may be able to vote for the same [% terms.bug %] more than once.
-Remember that you have a limited number of votes. When weighted voting 
-is allowed and a limited number of votes are available to you, you will 
-have to decide whether you want to distribute your votes among a large 
-number of [% terms.bugs %] indicating your minimal interest or focus on 
-a few [% terms.bugs %] indicating your strong support for them.
-&lt;/p&gt;
-
-&lt;p&gt;To look at votes:&lt;/p&gt;
-
-&lt;ul&gt;
-  &lt;li&gt;Go to the query page. Do a normal query, but enter 1 in the &quot;At least
-  ___ votes&quot; field. This will show you items that match your query that
-  have at least one vote.&lt;/li&gt;
-&lt;/ul&gt;
-
-&lt;p&gt;To vote for [% terms.abug %]:&lt;/p&gt;
-
-&lt;ul&gt;
-  &lt;li&gt;Bring up the [% terms.bug %] in question.&lt;/li&gt;
-
-  &lt;li&gt;Click on the &quot;(vote)&quot; link that appears on the right of the &quot;Importance&quot;
-  fields. (If no such link appears, then voting may not be allowed in
-  this [% terms.bug %]'s product.)&lt;/li&gt;
-
-  &lt;li&gt;Indicate how many votes you want to give this [% terms.bug %]. This page 
-  also displays how many votes you've given to other [% terms.bugs %], so you 
-  may rebalance your votes as necessary.&lt;/li&gt;
-&lt;/ul&gt;
-
-&lt;p&gt;You will automatically get email notifying you of any changes that occur
-on [% terms.bugs %] you vote for.&lt;/p&gt;
-
-&lt;p&gt;You may review your votes at any time by clicking on the &quot;&lt;a href=
-&quot;votes.cgi?action=show_user&quot;&gt;My Votes&lt;/a&gt;&quot; link in the page footer.&lt;/p&gt;
-
-[% INCLUDE global/footer.html.tmpl %]
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultreportscharthtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/reports/chart.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/reports/chart.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/reports/chart.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -25,9 +25,11 @@
</span><span class="cx">            height = 350 
</span><span class="cx"> %]
</span><span class="cx"> 
</span><ins>+[% time = time FILTER time('%Y-%m-%d %H:%M:%S') FILTER html %]
+
</ins><span class="cx"> [% PROCESS global/header.html.tmpl 
</span><span class="cx">   title = &quot;Chart&quot;
</span><del>-  header_addl_info = time2str(&quot;%Y-%m-%d %H:%M:%S&quot;, time)
</del><ins>+  header_addl_info = time
</ins><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> &lt;div align=&quot;center&quot;&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultreportscomponentshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/reports/components.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/reports/components.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/reports/components.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -16,17 +16,22 @@
</span><span class="cx">   # Rights Reserved.
</span><span class="cx">   #
</span><span class="cx">   # Contributor(s): Bradley Baetz &lt;bbaetz@student.usyd.edu.au&gt;
</span><ins>+  #                 Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [%# INTERFACE:
</span><del>-  # product: object. The product for which we want to display component descriptions.
</del><ins>+  # product: object. The product for which we want to display component
+  # descriptions.
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [% title = BLOCK %]
</span><span class="cx">   Components for [% product.name FILTER html %]
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><del>-[% PROCESS global/header.html.tmpl title = title %]
</del><ins>+[% PROCESS global/header.html.tmpl 
+  style_urls = [ &quot;skins/standard/reports.css&quot; ]
+  title = title 
+%]
</ins><span class="cx"> 
</span><span class="cx"> [% IF Param(&quot;useqacontact&quot;) %]
</span><span class="cx">   [% numcols = 3 %]
</span><span class="lines">@@ -34,27 +39,39 @@
</span><span class="cx">   [% numcols = 2 %]
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><del>-&lt;p&gt;
-  [% product.description FILTER html_light %]
-&lt;/p&gt;
</del><ins>+&lt;table cellpadding=&quot;0&quot; cellspacing=&quot;0&quot; id=&quot;components_header_table&quot;&gt;
+  &lt;tr&gt;
+    &lt;td class=&quot;instructions&quot;&gt;
+      Select a component to see open [% terms.bugs %] in that component:
+    &lt;/td&gt;
+    &lt;td class=&quot;product_container&quot;&gt;
+      &lt;span class=&quot;product_name&quot;&gt;[% product.name FILTER html %]&lt;/span&gt;
+      &lt;div class=&quot;product_desc&quot;&gt;
+        [% product.description FILTER html_light %]
+      &lt;/div&gt;
+    &lt;/td&gt;
+  &lt;/tr&gt;
+&lt;/table&gt;
</ins><span class="cx"> 
</span><del>-&lt;table&gt;
</del><ins>+&lt;span class=&quot;components_header&quot;&gt;Components&lt;/span&gt;
+
+&lt;table summary=&quot;Components table&quot;
+       class=&quot;component_table&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
+  &lt;thead&gt;
</ins><span class="cx">   &lt;tr&gt;
</span><del>-    &lt;th align=&quot;left&quot;&gt;Component&lt;/th&gt;
-    &lt;th align=&quot;left&quot;&gt;Default Assignee&lt;/th&gt;
</del><ins>+    &lt;th&gt;&amp;nbsp;&lt;/th&gt;
+    &lt;th&gt;Default Assignee&lt;/th&gt;
</ins><span class="cx">     [% IF Param(&quot;useqacontact&quot;) %]
</span><del>-      &lt;th align=&quot;left&quot;&gt;Default QA Contact&lt;/th&gt;
</del><ins>+      &lt;th&gt;Default QA Contact&lt;/th&gt;
</ins><span class="cx">     [% END %]
</span><span class="cx">   &lt;/tr&gt;
</span><ins>+  &lt;/thead&gt;
</ins><span class="cx"> 
</span><ins>+  &lt;tbody&gt;
</ins><span class="cx">   [% FOREACH comp = product.components %]
</span><span class="cx">     [% INCLUDE describe_comp %]
</span><span class="cx">   [% END %]
</span><del>-  &lt;tr&gt;
-    &lt;td colspan=&quot;[% numcols %]&quot;&gt;
-      &lt;hr&gt;
-    &lt;/td&gt;
-  &lt;/tr&gt;
</del><ins>+  &lt;/tbody&gt;
</ins><span class="cx"> &lt;/table&gt;
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/footer.html.tmpl %]
</span><span class="lines">@@ -64,28 +81,24 @@
</span><span class="cx"> [%############################################################################%]
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK describe_comp %]
</span><del>-  &lt;tr&gt;
-    &lt;td colspan=&quot;[% numcols %]&quot;&gt;
-      &lt;hr&gt;
</del><ins>+  &lt;tr id=&quot;[% comp.name FILTER html %]&quot;&gt;
+    &lt;td rowspan=&quot;2&quot; class=&quot;component_name&quot;&gt;
+      &lt;a href=&quot;buglist.cgi?product=
+               [%- product.name FILTER uri %]&amp;amp;component=
+               [%- comp.name FILTER uri %]&amp;amp;resolution=---&quot;&gt;
+      [% comp.name FILTER html %]&lt;/a&gt;
</ins><span class="cx">     &lt;/td&gt;
</span><del>-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td rowspan=&quot;2&quot;&gt;
-      &lt;a name=&quot;[% comp.name FILTER html %]&quot;&gt;[% comp.name FILTER html %]&lt;/a&gt;
</del><ins>+    &lt;td class=&quot;component_assignee&quot;&gt;
+      [% INCLUDE global/user.html.tmpl who = comp.default_assignee %]
</ins><span class="cx">     &lt;/td&gt;
</span><del>-    &lt;td&gt;
-      &lt;a href=&quot;mailto:[% comp.default_assignee.email FILTER html %]&quot;&gt;
-      [% comp.default_assignee.login FILTER html %]&lt;/a&gt;
-    &lt;/td&gt;
</del><span class="cx">     [% IF Param(&quot;useqacontact&quot;) %]
</span><del>-      &lt;td&gt;
-        &lt;a href=&quot;mailto:[% comp.default_qa_contact.email FILTER html %]&quot;&gt;
-        [% comp.default_qa_contact.login FILTER html %]&lt;/a&gt;
</del><ins>+      &lt;td class=&quot;component_qa_contact&quot;&gt;
+        [% INCLUDE global/user.html.tmpl who = comp.default_qa_contact %]
</ins><span class="cx">       &lt;/td&gt;
</span><span class="cx">     [% END %]
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx">   &lt;tr&gt;
</span><del>-    &lt;td colspan=&quot;[% numcols - 1 %]&quot;&gt;
</del><ins>+    &lt;td colspan=&quot;[% numcols - 1 %]&quot; class=&quot;component_description&quot;&gt;
</ins><span class="cx">       [% comp.description FILTER html_light %]
</span><span class="cx">     &lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultreportscreatecharthtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/reports/create-chart.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/reports/create-chart.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/reports/create-chart.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -50,6 +50,7 @@
</span><span class="cx">     i++;
</span><span class="cx">   }
</span><span class="cx"> 
</span><ins>+  namewidget.disabled = false;
</ins><span class="cx">   namewidget.options[0].selected = true;
</span><span class="cx">   
</span><span class="cx">   checkNewState();
</span><span class="lines">@@ -98,23 +99,16 @@
</span><span class="cx">         &lt;td&gt;
</span><span class="cx">           &lt;noscript&gt;
</span><span class="cx">             &lt;input type=&quot;submit&quot; name=&quot;action-assemble&quot; value=&quot;Update --&amp;gt;&quot;
</span><del>-                   id=&quot;action-assemble&quot;&gt;
</del><ins>+                   id=&quot;action-assemble2&quot;&gt;
</ins><span class="cx">           &lt;/noscript&gt;
</span><span class="cx">         &lt;/td&gt;
</span><span class="cx">         
</span><del>-        &lt;td align=&quot;left&quot;&gt;
-          &lt;select name=&quot;name&quot; id=&quot;name&quot; style=&quot;width: 15em&quot;
-                  size=&quot;5&quot; multiple=&quot;multiple&quot;
-                  [%+ &quot;disabled=\&quot;disabled\&quot;&quot; UNLESS name.keys.size %]&gt;
-            [% FOREACH x = name.keys.sort %]
-              &lt;option value=&quot;[% name.$x FILTER html %]&quot;&gt;
-                [% x FILTER html %]&lt;/option&gt;
-            [% END %]
-            [% UNLESS name.keys.size %]
-              &lt;option value=&quot;&quot; disabled=&quot;disabled&quot;&gt;&lt;/option&gt;
-            [% END %]
-          &lt;/select&gt;
-        &lt;/td&gt;
</del><ins>+        [% PROCESS series_select sel = { name =&gt; 'name',
+                                         size =&gt; 5,
+                                         multiple =&gt; 1,
+                                         # We want to use the series ID as value,
+                                         # not its name.
+                                         value_in_hash =&gt; 1 } %]
</ins><span class="cx"> 
</span><span class="cx">         &lt;td align=&quot;center&quot; valign=&quot;middle&quot;&gt; 
</span><span class="cx">           &lt;input type=&quot;submit&quot; name=&quot;action-add&quot; value=&quot;Add To List&quot;
</span><span class="lines">@@ -124,17 +118,9 @@
</span><span class="cx">     [% END %]
</span><span class="cx">   &lt;/table&gt;
</span><span class="cx"> 
</span><del>-  &lt;script type=&quot;text/javascript&quot;&gt;
-    document.chartform.category[0].selected = true;
-    document.chartform.subcategory.disabled = '';
-    document.chartform.name.disabled = '';
-    catSelected();
-    subcatSelected();
-  &lt;/script&gt;
-
</del><span class="cx">   &lt;h3&gt;List Of Data Sets To Plot&lt;/h3&gt;
</span><span class="cx"> 
</span><del>-  [% IF chart.lines.size &gt; 0 %]
</del><ins>+  [% IF chart.lines.size %]
</ins><span class="cx">     &lt;table cellspacing=&quot;2&quot; cellpadding=&quot;2&quot;&gt;
</span><span class="cx">       &lt;tr&gt;
</span><span class="cx">         &lt;th style=&quot;width: 5em;&quot;&gt;Select&lt;/th&gt;
</span><span class="lines">@@ -187,14 +173,16 @@
</span><span class="cx">             &lt;/td&gt;
</span><span class="cx"> 
</span><span class="cx">             &lt;td align=&quot;center&quot;&gt;
</span><del>-              [% IF user.id == series.creator OR user.in_group(&quot;admin&quot;) %]
</del><ins>+              [% IF user.id == series.creator_id OR user.in_group(&quot;admin&quot;) %]
</ins><span class="cx">                &lt;a href=&quot;chart.cgi?action=edit&amp;amp;series_id=
</span><span class="cx">                        [% series.series_id %]&quot;&gt;Edit&lt;/a&gt; |
</span><ins>+               &lt;a href=&quot;chart.cgi?action=confirm-delete&amp;amp;series_id=
+                       [%- series.series_id %]&quot;&gt;Delete&lt;/a&gt; |
</ins><span class="cx">               [% END %]
</span><span class="cx">               &lt;a href=&quot;buglist.cgi?cmdtype=dorem&amp;amp;namedcmd=
</span><del>-                [% series.category FILTER url_quote %]%20/%20
-                [% series.subcategory FILTER url_quote %]%20/%20
-                [% series.name FILTER url_quote -%]&amp;amp;series_id=
</del><ins>+                [% series.category FILTER uri %]%20/%20
+                [% series.subcategory FILTER uri %]%20/%20
+                [% series.name FILTER uri -%]&amp;amp;series_id=
</ins><span class="cx">                 [% series.series_id %]&amp;amp;remaction=runseries&quot;&gt;Run Search&lt;/a&gt;
</span><span class="cx">             &lt;/td&gt;        
</span><span class="cx">           &lt;/tr&gt;
</span><span class="lines">@@ -260,7 +248,23 @@
</span><span class="cx"> &lt;/form&gt;
</span><span class="cx"> 
</span><span class="cx"> [% IF user.in_group('editbugs') %]
</span><del>-  &lt;h3&gt;&lt;a href=&quot;query.cgi?format=create-series&quot;&gt;Create New Data Set&lt;/a&gt;&lt;/h3&gt;
</del><ins>+  &lt;h3&gt;Create New Data Set&lt;/h3&gt;
+  &lt;p&gt;
+    You can either create a new data set based on one of your saved searches
+    or start with a clean slate.
+  &lt;/p&gt;
+
+  &lt;form action=&quot;chart.cgi&quot; id=&quot;create_series&quot; name=&quot;create_series&quot; method=&quot;GET&quot;&gt;
+    &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;convert_search&quot;&gt;
+    &lt;label for=&quot;series_from_search&quot;&gt;Based on:&lt;/label&gt;
+    &lt;select id=&quot;series_from_search&quot; name=&quot;series_from_search&quot;&gt;
+      &lt;option value=&quot;&quot;&gt;(Clean slate)&lt;/option&gt;
+      [% FOREACH q = user.queries %]
+        &lt;option value=&quot;[% q.name FILTER html %]&quot;&gt;[% q.name FILTER html %]&lt;/option&gt;
+      [% END %]
+    &lt;/select&gt;
+    &lt;input id=&quot;submit_create&quot; type=&quot;submit&quot; value=&quot;Create a new data set&quot;&gt;
+  &lt;/form&gt;
</ins><span class="cx"> [% END %]                 
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/footer.html.tmpl %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultreportsdeleteserieshtmltmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/reports/delete-series.html.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/reports/delete-series.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/reports/delete-series.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,59 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Frédéric Buclin.
+  # Portions created by the Initial Developer are Copyright (C) 2009
+  # the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s):
+  #  Frédéric Buclin &lt;LpSolit@gmail.com&gt;
+  #%]
+
+[% series_name = BLOCK %]
+  [% series.category FILTER html %] /
+  [%+ series.subcategory FILTER html %] /
+  [%+ series.name FILTER html %]
+[% END %]
+
+[% PROCESS global/header.html.tmpl title = &quot;Delete Series&quot;
+                                   style_urls = ['skins/standard/admin.css'] %]
+
+&lt;p&gt;
+  You are going to completely remove the &lt;b&gt;[% series_name FILTER none %]&lt;/b&gt; series
+  from the database. All data related to this series will be permanently deleted.
+&lt;/p&gt;
+&lt;p&gt;
+  [% IF series.creator %]
+    This series has been created by &lt;a href=&quot;mailto:[% series.creator.email FILTER html %]&quot;&gt;
+    [% series.creator.email FILTER html %]&lt;/a&gt;
+  [% ELSE %]
+    This series has been automatically created by [% terms.Bugzilla %]
+  [% END %]
+
+  [% IF series.public %]
+    and is public.
+  [% ELSIF series.creator %]
+    and is only visible by this user.
+  [% ELSE %]
+    and cannot be displayed by anybody.
+  [% END %]
+&lt;/p&gt;
+
+&lt;p class=&quot;areyoureallyreallysure&quot;&gt;Are you sure you want to delete this series?&lt;/p&gt;
+
+&lt;p&gt;
+  &lt;a href=&quot;chart.cgi?action=delete&amp;amp;series_id=[% series.series_id FILTER html %]&amp;amp;token=
+           [%- issue_hash_token([series.id, series.name]) FILTER uri %]&quot;&gt;Yes, delete&lt;/a&gt; |
+  &lt;a href=&quot;chart.cgi&quot;&gt;No, go back to the charts page&lt;/a&gt;
+&lt;/p&gt;
+
+[% PROCESS global/footer.html.tmpl %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultreportsduplicatessimplehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/reports/duplicates-simple.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/reports/duplicates-simple.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/reports/duplicates-simple.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -15,7 +15,9 @@
</span><span class="cx">   # Copyright (C) 1998 Netscape Communications Corporation. All
</span><span class="cx">   # Rights Reserved.
</span><span class="cx">   #
</span><del>-  # Contributor(s): Gervase Markham &lt;gerv@gerv.net&gt;
</del><ins>+  # Contributor(s): 
+  #  Gervase Markham &lt;gerv@gerv.net&gt;
+  #  Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [%# INTERFACE:
</span><span class="lines">@@ -24,20 +26,26 @@
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="cx"> 
</span><ins>+&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;
+                      &quot;http://www.w3.org/TR/html4/loose.dtd&quot;&gt;
</ins><span class="cx"> &lt;html&gt;
</span><del>-
-  [% IF product %]
-    [% title = &quot;Most Frequently Reported $terms.Bugs for $product&quot; %]
</del><ins>+  [% IF product.size %]
+    [% title = BLOCK %]
+      Most Frequently Reported [% terms.Bugs %] for [% product.join(', ') FILTER html %]
+    [% END %]
</ins><span class="cx">   [% ELSE %]
</span><span class="cx">     [% title = &quot;Most Frequently Reported $terms.Bugs&quot; %]
</span><span class="cx">   [% END%]
</span><span class="cx"> 
</span><span class="cx">   &lt;head&gt;
</span><span class="cx">     &lt;title&gt;[% title FILTER html %]&lt;/title&gt;
</span><ins>+    &lt;link href=&quot;[% 'skins/standard/global.css' FILTER mtime %]&quot;
+          rel=&quot;stylesheet&quot; type=&quot;text/css&quot;&gt;
+    &lt;link href=&quot;[% 'skins/standard/duplicates.css' FILTER mtime %]&quot;
+          rel=&quot;stylesheet&quot; type=&quot;text/css&quot;&gt;
</ins><span class="cx">   &lt;/head&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;body&gt;
</span><span class="cx">     [% PROCESS &quot;reports/duplicates-table.html.tmpl&quot; %]
</span><span class="cx">   &lt;/body&gt;
</span><del>-
</del><span class="cx"> &lt;/html&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultreportsduplicatestablehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/reports/duplicates-table.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/reports/duplicates-table.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/reports/duplicates-table.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -15,21 +15,16 @@
</span><span class="cx">   # Copyright (C) 1998 Netscape Communications Corporation. All
</span><span class="cx">   # Rights Reserved.
</span><span class="cx">   #
</span><del>-  # Contributor(s): Gervase Markham &lt;gerv@gerv.net&gt;
</del><ins>+  # Contributor(s): 
+  #   Gervase Markham &lt;gerv@gerv.net&gt;
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [%# INTERFACE:
</span><del>-  # bugs: list of hashes. May be empty. Each hash has nine members:
-  #   id: integer. The bug number
</del><ins>+  # bugs: list of hashes. May be empty. Each hash has three members:
+  #   bug: A Bugzilla::Bug object
</ins><span class="cx">   #   count: integer. The number of dupes
</span><span class="cx">   #   delta: integer. The change in count in the last $changedsince days
</span><del>-  #   component: string. The bug's component
-  #   bug_severity: string. The bug's severity.
-  #   op_sys: string. The bug's reported OS.
-  #   target_milestone: string. The bug's TM.
-  #   short_desc: string. The bug's summary.
-  #   bug_status: string. The bug's status.
-  #   resolution: string. The bug's resolution, if any.
</del><span class="cx">   #
</span><span class="cx">   # bug_ids: list of integers. May be empty. The IDs of the bugs in $bugs.
</span><span class="cx">   #
</span><span class="lines">@@ -38,104 +33,89 @@
</span><span class="cx">   # maxrows: integer. Max number of rows to display.
</span><span class="cx">   # changedsince: integer. The number of days ago for the changedsince column.
</span><span class="cx">   # openonly: boolean. True if we are only showing open bugs.
</span><del>-  # query_products: list of strings. Restrict to these products only.
</del><ins>+  # product: array of strings. Restrict to these products only.
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><del>-[% PROCESS global/variables.none.tmpl %]
</del><ins>+[% PROCESS &quot;global/field-descs.none.tmpl&quot; %]
</ins><span class="cx"> 
</span><span class="cx"> [%# *** Column Headers *** %]
</span><span class="cx"> 
</span><del>-[% IF bug_ids.size &gt; 0 %]
-  &lt;table border&gt;
-    &lt;thead&gt;
-      &lt;tr bgcolor=&quot;#CCCCCC&quot;&gt;
-        [% FOREACH column = [ { name =&gt; &quot;id&quot;, description =&gt; &quot;$terms.Bug #&quot; },
-                              { name =&gt; &quot;count&quot;, description =&gt; &quot;Dupe&lt;br&gt;Count&quot; },
-                              { name =&gt; &quot;delta&quot;,
-                                description =&gt; &quot;Change in last&lt;br&gt;$changedsince day(s)&quot; },
-                              { name =&gt; &quot;component&quot;, description =&gt; &quot;Component&quot; },
-                              { name =&gt; &quot;bug_severity&quot;, description =&gt; &quot;Severity&quot; },
-                              { name =&gt; &quot;op_sys&quot;, description =&gt; &quot;Op Sys&quot; },
-                              { name =&gt; &quot;target_milestone&quot;,
-                                description =&gt; &quot;Target&lt;br&gt;Milestone&quot; },
-                              { name =&gt; &quot;short_desc&quot;, description =&gt; &quot;Summary&quot; } ]
-         %]
</del><ins>+[% SET columns = [
+    { name =&gt; &quot;id&quot;, description =&gt; &quot;$terms.Bug #&quot; },
+    { name =&gt; &quot;count&quot;, description =&gt; &quot;Dupe&lt;br&gt;Count&quot; },
+    { name =&gt; &quot;delta&quot;,
+      description =&gt; &quot;Change in last&lt;br&gt;$changedsince day(s)&quot; },
+    { name =&gt; &quot;component&quot;, description =&gt; field_descs.component },
+    { name =&gt; &quot;bug_severity&quot;, description =&gt; field_descs.bug_severity },
+    { name =&gt; &quot;op_sys&quot;, description =&gt; field_descs.op_sys },
+    { name =&gt; &quot;target_milestone&quot;, description =&gt; field_descs.target_milestone },
+    { name =&gt; &quot;short_desc&quot;, description =&gt; field_descs.short_desc },
+] %]
</ins><span class="cx"> 
</span><del>-          [%# Small hack to keep delta column out if we don't need it %]
-          [% NEXT IF column.name == &quot;delta&quot; AND NOT dobefore %]
</del><ins>+[% SET base_args = [] %]
+[% FOREACH param = ['maxrows', 'openonly', 'format', 'sortvisible',
+                    'changedsince', 'product'] 
+%]
+  [% NEXT IF NOT ${param}.defined %]
+  [% FOREACH value = ${param} %]
+    [% filtered_value = value FILTER uri %]
+    [% base_args.push(&quot;$param=$filtered_value&quot;) %]
+  [% END %]
+[% END %]
+[% IF sortvisible %]
+  [% bug_ids_string = bug_ids.nsort.join(',') FILTER uri %]
+  [% base_args.push(&quot;bug_id=$bug_ids_string&quot;) %]
+[% END %]
+[% base_args_string = base_args.join('&amp;amp;') %]
</ins><span class="cx"> 
</span><del>-          &lt;th&gt;
-            [% bug_ids_string = bug_ids.join(',') %]
-            &lt;a href=&quot;duplicates.cgi?sortby=[% column.name %]
-              [% IF sortby == column.name %]
-                [% &quot;&amp;amp;reverse=1&quot; IF NOT reverse %]
-              [% ELSE %]
-                [%-# Some columns start off reversed %]
-                [% &quot;&amp;amp;reverse=1&quot; IF column.name.match('delta|count') %]
-              [% END %]
-              [% IF maxrows %]&amp;amp;maxrows=[% maxrows FILTER html %][% END %]
-              [% IF changedsince %]&amp;amp;changedsince=[% changedsince FILTER html %][% END %]
-              [% &quot;&amp;amp;openonly=1&quot; IF openonly %]
-              [% FOREACH p = query_products %]&amp;amp;product=[% p FILTER html %][% END %]
-              [% IF format %]&amp;amp;format=[% format FILTER html %][% END %]
-              [% IF sortvisible %]&amp;amp;bug_id=[% bug_ids_string FILTER html %]&amp;amp;sortvisible=1[% END %]&quot;&gt;
-              [% column.description %]&lt;/a&gt;
</del><ins>+[% IF bugs.size %]
+  &lt;table id=&quot;duplicates_table&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot;&gt;
+    &lt;thead&gt;
+      &lt;tr&gt;
+        [% FOREACH column = columns %]
+          [% IF column.name == sortby %]
+            [%# We add this to the column object so it doesn't affect future 
+              # iterations of the loop.
+              #%]
+            [% column.reverse_sort = reverse ? 0 : 1 %]
+          [% END %]
+          &lt;th class=&quot;[% column.name FILTER html %]&quot;&gt;
+            &lt;a href=&quot;duplicates.cgi?sortby=[% column.name FILTER uri %]
+                     [% IF column.reverse_sort.defined %]
+                      [%- %]&amp;amp;reverse=[% column.reverse_sort FILTER uri %]
+                     [% END %]
+                     [% IF base_args_string %]
+                       [% &quot;&amp;amp;$base_args_string&quot; FILTER none %]
+                     [% END %]&quot;
+            &gt;[% column.description FILTER none %]&lt;/a&gt;
</ins><span class="cx">           &lt;/th&gt;
</span><span class="cx">         [% END %]
</span><span class="cx">       &lt;/tr&gt;
</span><span class="cx">     &lt;/thead&gt;
</span><span class="cx"> 
</span><del>-    [% IF NOT sortby %]
-      [% sortby = &quot;count&quot;; reverse = &quot;1&quot; %]
-    [% END %]
-
-    [% IF sortby == &quot;id&quot; OR sortby == &quot;count&quot; OR sortby == &quot;delta&quot; %]
-      [%# Numeric sort %]
-      [% sortedbugs = bugs.nsort(sortby) %]
-    [% ELSE %]
-      [% sortedbugs = bugs.sort(sortby) %]
-    [% END %]
-
-    [% IF reverse %]
-      [% bugs = sortedbugs.reverse %]
-    [% ELSE %]
-      [% bugs = sortedbugs %]
-    [% END %]
-
</del><span class="cx">     [%# *** Buglist *** %]
</span><del>-    &lt;tbody&gt;
</del><span class="cx"> 
</span><del>-      [%# We need to keep track of the bug IDs we are actually displaying, because
-        # if the user decides to sort the visible list, we need to know what that
-        # list actually is. %]
-      [% vis_bug_ids = [] %]
-
-      [% FOREACH bug = bugs %]
-        [% LAST IF loop.index() &gt;= maxrows %]
-        [% vis_bug_ids.push(bug.id) %]
-
-        &lt;tr [% &quot;class='resolved'&quot; IF bug.resolution != &quot;&quot; %]&gt;
-          &lt;td&gt;
-            &lt;center&gt;
-              [% bug.id FILTER bug_link(bug.id) FILTER none %]
-            &lt;/center&gt;
</del><ins>+    &lt;tbody&gt;
+      [% FOREACH item = bugs %]
+        [% SET bug = item.bug %]
+        &lt;tr [% &quot; class='resolved'&quot; IF NOT bug.isopened %]&gt;
+          &lt;td class=&quot;id&quot;&gt;
+            [% bug.id FILTER bug_link(bug) FILTER none %]
</ins><span class="cx">           &lt;/td&gt;
</span><del>-
-          &lt;td&gt;
-            &lt;center&gt;
-              [% bug.count %]
-            &lt;/center&gt;
</del><ins>+          &lt;td class=&quot;count&quot;&gt;[% item.count FILTER html %]&lt;/td&gt;
+          &lt;td class=&quot;delta&quot;&gt;[% item.delta FILTER html %]&lt;/td&gt;
+          &lt;td class=&quot;component&quot;&gt;[% bug.component FILTER html %]&lt;/td&gt;
+          &lt;td class=&quot;bug_severity&quot;&gt;
+            [%- display_value('bug_severity', bug.bug_severity) FILTER html %]
</ins><span class="cx">           &lt;/td&gt;
</span><del>-
-          [% IF dobefore %]
-            &lt;td&gt;&lt;center&gt;[% bug.delta %]&lt;/center&gt;&lt;/td&gt;
-          [% END %]
-
-          &lt;td&gt;[% bug.component FILTER html %]&lt;/td&gt;
-          &lt;td&gt;&lt;center&gt;[% bug.bug_severity FILTER html %]&lt;/center&gt;&lt;/td&gt;
-          &lt;td&gt;&lt;center&gt;[% bug.op_sys FILTER html %]&lt;/center&gt;&lt;/td&gt;
-          &lt;td&gt;&lt;center&gt;[% bug.target_milestone FILTER html %]&lt;/center&gt;&lt;/td&gt;
-          &lt;td&gt;[% bug.short_desc FILTER html %]&lt;/td&gt;
</del><ins>+          &lt;td class=&quot;op_sys&quot;&gt;
+            [%- display_value('op_sys', bug.op_sys) FILTER html %]
+          &lt;/td&gt;
+          &lt;td class=&quot;target_milestone&quot;&gt;
+            [% display_value('target_milestone', 
+                             bug.target_milestone) FILTER html %]
+          &lt;/td&gt;
+          &lt;td class=&quot;short_desc&quot;&gt;[% bug.short_desc FILTER html %]&lt;/td&gt;
</ins><span class="cx">         &lt;/tr&gt;
</span><span class="cx">       [% END %]
</span><span class="cx">     &lt;/tbody&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultreportsduplicateshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/reports/duplicates.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/reports/duplicates.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/reports/duplicates.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -19,14 +19,12 @@
</span><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [%# INTERFACE:
</span><del>-  # products: an array of product objects this user can see.
-  #
</del><span class="cx">   # sortby: string. the column on which we are sorting the buglist.
</span><span class="cx">   # reverse: boolean. True if we are reversing the current sort.
</span><span class="cx">   # maxrows: integer. Max number of rows to display.
</span><span class="cx">   # changedsince: integer. The number of days ago for the changedsince column.
</span><span class="cx">   # openonly: boolean. True if we are only showing open bugs.
</span><del>-  # query_products: list of strings. The set of products we check for dups.
</del><ins>+  # product: array of strings. The set of products we check for dups.
</ins><span class="cx">   #
</span><span class="cx">   # Additionally, you need to fulfill the interface to
</span><span class="cx">   # duplicates-table.html.tmpl.
</span><span class="lines">@@ -34,9 +32,10 @@
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="cx"> 
</span><del>-[% IF query_products.size %]
</del><ins>+[% IF product.size %]
</ins><span class="cx">   [% title = BLOCK %]
</span><del>-    Most Frequently Reported [% terms.Bugs %] for [% query_products.join(', ') FILTER html %]
</del><ins>+    Most Frequently Reported [% terms.Bugs %] for 
+    [%+ product.join(', ') FILTER html %]
</ins><span class="cx">   [% END %]
</span><span class="cx"> [% ELSE %]
</span><span class="cx">   [% title = &quot;Most Frequently Reported $terms.Bugs&quot; %]
</span><span class="lines">@@ -44,7 +43,7 @@
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/header.html.tmpl
</span><span class="cx">    title = title
</span><del>-   style = &quot;.resolved { background-color: #d9d9d9; color: #000000; }&quot;
</del><ins>+   style_urls = ['skins/standard/duplicates.css']
</ins><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> &lt;p&gt;
</span><span class="lines">@@ -57,27 +56,26 @@
</span><span class="cx"> 
</span><span class="cx"> [%# *** Parameters *** %]
</span><span class="cx"> 
</span><del>-[% bug_ids_string = vis_bug_ids.join(',') %]
</del><ins>+[% bug_ids_string = bug_ids.join(',') %]
</ins><span class="cx"> 
</span><del>-&lt;h3&gt;&lt;a name=&quot;params&quot;&gt;Change Parameters&lt;/a&gt;&lt;/h3&gt;
</del><ins>+&lt;h3 id=&quot;params&quot;&gt;Change Parameters&lt;/h3&gt;
</ins><span class="cx"> 
</span><span class="cx"> &lt;form method=&quot;get&quot; action=&quot;duplicates.cgi&quot;&gt;
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;sortby&quot; value=&quot;[% sortby FILTER html %]&quot;&gt;
</span><del>-  &lt;input type=&quot;hidden&quot; name=&quot;reverse&quot; value=&quot;[% reverse %]&quot;&gt;
-  &lt;input type=&quot;hidden&quot; name=&quot;bug_id&quot; value=&quot;[% bug_ids_string %]&quot;&gt;
</del><ins>+  &lt;input type=&quot;hidden&quot; name=&quot;reverse&quot; value=&quot;[% reverse FILTER html %]&quot;&gt;
+  &lt;input type=&quot;hidden&quot; name=&quot;bug_id&quot; value=&quot;[% bug_ids_string FILTER html %]&quot;&gt;
</ins><span class="cx">   &lt;table&gt;
</span><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;td&gt;When sorting or restricting,
-          work with:&lt;/td&gt;
</del><ins>+      &lt;td&gt;When sorting or restricting, work with:&lt;/td&gt;
</ins><span class="cx">       &lt;td&gt;
</span><span class="cx">         &lt;input type=&quot;radio&quot; name=&quot;sortvisible&quot; id=&quot;entirelist&quot; value=&quot;0&quot;
</span><del>-          [%+ &quot;checked&quot; IF NOT sortvisible %]&gt;
</del><ins>+          [% ' checked=&quot;checked&quot;' IF NOT sortvisible %]&gt;
</ins><span class="cx">         &lt;label for=&quot;entirelist&quot;&gt;
</span><span class="cx">           entire list
</span><span class="cx">         &lt;/label&gt;
</span><span class="cx">         &lt;br&gt;
</span><span class="cx">         &lt;input type=&quot;radio&quot; name=&quot;sortvisible&quot; id=&quot;visiblelist&quot; value=&quot;1&quot;
</span><del>-          [%+ &quot;checked&quot; IF sortvisible %]&gt;
</del><ins>+          [% ' checked=&quot;checked&quot;' IF sortvisible %]&gt;
</ins><span class="cx">         &lt;label for=&quot;visiblelist&quot;&gt;
</span><span class="cx">           currently visible list
</span><span class="cx">         &lt;/label&gt;
</span><span class="lines">@@ -85,9 +83,9 @@
</span><span class="cx">       &lt;td rowspan=&quot;4&quot; valign=&quot;top&quot;&gt;Restrict to products:&lt;/td&gt;
</span><span class="cx">       &lt;td rowspan=&quot;4&quot; valign=&quot;top&quot;&gt;
</span><span class="cx">         &lt;select name=&quot;product&quot; size=&quot;5&quot; multiple=&quot;multiple&quot;&gt;
</span><del>-          [% FOREACH p = products %]
</del><ins>+          [% FOREACH p = user.get_selectable_products %]
</ins><span class="cx">             &lt;option name=&quot;[% p.name FILTER html %]&quot;
</span><del>-            [% &quot; selected&quot; IF lsearch(query_products, p.name) != -1 %]
</del><ins>+            [% ' selected=&quot;selected&quot;' IF product.contains(p.name) %]
</ins><span class="cx">             &gt;[% p.name FILTER html %]&lt;/option&gt;
</span><span class="cx">           [% END %]
</span><span class="cx">         &lt;/select&gt;
</span><span class="lines">@@ -95,17 +93,21 @@
</span><span class="cx">      &lt;/tr&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;td&gt;Max rows:&lt;/td&gt;
</del><ins>+      &lt;td&gt;&lt;label for=&quot;maxrows&quot;&gt;Max rows:&lt;/label&gt;&lt;/td&gt;
</ins><span class="cx">       &lt;td&gt;
</span><del>-        &lt;input size=&quot;4&quot; name=&quot;maxrows&quot; value=&quot;[% maxrows %]&quot;&gt;
</del><ins>+        &lt;input size=&quot;4&quot; name=&quot;maxrows&quot; id=&quot;maxrows&quot; 
+               value=&quot;[% maxrows FILTER html %]&quot;&gt;
</ins><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;td&gt;Change column is change in the last:&lt;/td&gt;
</del><span class="cx">       &lt;td&gt;
</span><del>-        &lt;input size=&quot;4&quot; name=&quot;changedsince&quot; value=&quot;[% changedsince %]&quot;&gt; days
</del><ins>+        &lt;label for=&quot;changedsince&quot;&gt;Change column is change in the last:&lt;/label&gt;
</ins><span class="cx">       &lt;/td&gt;
</span><ins>+      &lt;td&gt;
+        &lt;input size=&quot;4&quot; name=&quot;changedsince&quot; id=&quot;changedsince&quot;
+               value=&quot;[% changedsince FILTER html %]&quot;&gt; days
+      &lt;/td&gt;
</ins><span class="cx">     &lt;/tr&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;tr&gt;
</span><span class="lines">@@ -116,7 +118,7 @@
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">       &lt;td&gt;
</span><span class="cx">         &lt;input type=&quot;checkbox&quot; name=&quot;openonly&quot; id=&quot;openonly&quot; value=&quot;1&quot;
</span><del>-          [%+ &quot;checked&quot; IF openonly %]&gt;
</del><ins>+          [% ' checked=&quot;checked&quot;' IF openonly %]&gt;
</ins><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -126,28 +128,27 @@
</span><span class="cx"> &lt;/form&gt;
</span><span class="cx"> 
</span><span class="cx"> &lt;form method=&quot;post&quot; action=&quot;buglist.cgi&quot;&gt;
</span><del>-  &lt;input type=&quot;hidden&quot; name=&quot;bug_id&quot; value=&quot;[% bug_ids_string %]&quot;&gt;
-  &lt;input type=&quot;hidden&quot; name=&quot;order&quot; value=&quot;Reuse same sort as last time&quot;&gt;
</del><ins>+  &lt;input type=&quot;hidden&quot; name=&quot;bug_id&quot; value=&quot;[% bug_ids_string FILTER html %]&quot;&gt;
</ins><span class="cx">   Or just give this to me as a &lt;input type=&quot;submit&quot; id=&quot;list&quot; 
</span><del>-                                value=&quot;[% terms.bug %] list&quot;&gt;.
</del><ins>+                                      value=&quot;[% terms.bug %] list&quot;&gt;.
</ins><span class="cx">   (Note: the order may not be the same.)
</span><span class="cx"> &lt;/form&gt;
</span><span class="cx"> 
</span><span class="cx"> &lt;hr&gt;
</span><span class="cx"> 
</span><del>-&lt;b&gt;
-  &lt;a name=&quot;explanation&quot;&gt;What are &quot;Most Frequently Reported [% terms.Bugs %]&quot;?&lt;/a&gt;
-&lt;/b&gt;
</del><ins>+&lt;h3 id=&quot;explanation&quot;&gt;
+  What are &quot;Most Frequently Reported [% terms.Bugs %]&quot;?
+&lt;/h3&gt;
</ins><span class="cx"> 
</span><del>-&lt;blockquote&gt;
-  The Most Frequent [% terms.Bugs %] page lists the known open [% terms.bugs %] which
-  are reported most frequently. It is
-  automatically generated from the [% terms.Bugzilla %] database every 24 hours, by
</del><ins>+&lt;p&gt;
+  The Most Frequent [% terms.Bugs %] page lists the known open 
+  [%+ terms.bugs %] which are reported most frequently,
</ins><span class="cx">   counting the number of direct and indirect duplicates of [% terms.bugs %].
</span><span class="cx">   This information is provided in order to assist in minimizing
</span><del>-  the amount of duplicate [% terms.bugs %] entered into [% terms.Bugzilla %], which
-  saves time for Quality Assurance engineers who have to triage the [% terms.bugs %].
-&lt;/blockquote&gt;
</del><ins>+  the amount of duplicate [% terms.bugs %] entered into [% terms.Bugzilla %],
+  which saves time for Quality Assurance engineers who have to triage
+  the [% terms.bugs %].
+&lt;/p&gt;
</ins><span class="cx"> 
</span><span class="cx"> &lt;b&gt;How do I use this list?&lt;/b&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -166,11 +167,12 @@
</span><span class="cx"> 
</span><span class="cx">   &lt;ul&gt;
</span><span class="cx">     &lt;li&gt;&lt;a href=&quot;query.cgi&quot;&gt;Try and locate a similar [% terms.bug %]&lt;/a&gt;
</span><del>-        that has already been filed.&lt;/li&gt;
</del><ins>+      that has already been filed.&lt;/li&gt;
</ins><span class="cx">     &lt;li&gt;If you find your [% terms.bug %] in [% terms.Bugzilla %],
</span><del>-        feel free to comment with any new or additional data you may have.&lt;/li&gt;
-    &lt;li&gt;If you cannot find your problem already documented in [% terms.Bugzilla %],
-        &lt;a href=&quot;enter_bug.cgi&quot;&gt;file a new [% terms.bug %]&lt;/a&gt;.&lt;/li&gt;
</del><ins>+      feel free to comment with any new or additional data you may have.&lt;/li&gt;
+    &lt;li&gt;If you cannot find your problem already documented in 
+      [%+ terms.Bugzilla %],
+      &lt;a href=&quot;enter_bug.cgi&quot;&gt;file a new [% terms.bug %]&lt;/a&gt;.&lt;/li&gt;
</ins><span class="cx">   &lt;/ul&gt;
</span><span class="cx"> &lt;/ul&gt;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultreportseditserieshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/reports/edit-series.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/reports/edit-series.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/reports/edit-series.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -40,6 +40,8 @@
</span><span class="cx">   [% PROCESS reports/series.html.tmpl 
</span><span class="cx">      button_name = &quot;Change Data Set&quot; %]
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;alter&quot;&gt;
</span><ins>+  &lt;input type=&quot;hidden&quot; name=&quot;token&quot;
+         value=&quot;[% issue_hash_token([default.id, default.name]) FILTER html %]&quot;&gt;
</ins><span class="cx">   
</span><span class="cx">   [% IF default.series_id %]
</span><span class="cx">     &lt;input type=&quot;hidden&quot; name=&quot;series_id&quot; value=&quot;[% default.series_id %]&quot;&gt;
</span><span class="lines">@@ -48,9 +50,9 @@
</span><span class="cx"> 
</span><span class="cx"> &lt;p&gt;
</span><span class="cx">   &lt;b&gt;Creator&lt;/b&gt;: 
</span><del>-  [% IF creator.email %]
-    &lt;a href=&quot;mailto:[% creator.email FILTER html %]&quot;&gt;
-    [% creator.email FILTER html %]&lt;/a&gt;
</del><ins>+  [% IF default.creator %]
+    &lt;a href=&quot;mailto:[% default.creator.email FILTER html %]&quot;&gt;
+    [% default.creator.email FILTER html %]&lt;/a&gt;
</ins><span class="cx">   [% ELSE %]
</span><span class="cx">     (automatically created by [% terms.Bugzilla %])
</span><span class="cx">   [% END %]
</span><span class="lines">@@ -64,9 +66,9 @@
</span><span class="cx">   &lt;a href=&quot;query.cgi?[% default.query FILTER html %]&quot;&gt;View 
</span><span class="cx">     series search parameters&lt;/a&gt; |
</span><span class="cx">   &lt;a href=&quot;buglist.cgi?cmdtype=dorem&amp;amp;namedcmd=
</span><del>-    [% default.category FILTER url_quote %]-
-    [% default.subcategory FILTER url_quote %]-
-    [% default.name FILTER url_quote %]&amp;amp;remaction=runseries&amp;amp;series_id=
</del><ins>+    [% default.category FILTER uri %]-
+    [% default.subcategory FILTER uri %]-
+    [% default.name FILTER uri %]&amp;amp;remaction=runseries&amp;amp;series_id=
</ins><span class="cx">     [% default.series_id %]&quot;&gt;Run series search&lt;/a&gt;
</span><span class="cx"> &lt;/p&gt;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultreportskeywordshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/reports/keywords.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/reports/keywords.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/reports/keywords.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -49,15 +49,14 @@
</span><span class="cx">       &lt;/tr&gt;
</span><span class="cx">   [% END %]
</span><span class="cx"> 
</span><del>-  &lt;tr&gt;
</del><ins>+  &lt;tr id=&quot;[% keyword.name FILTER html %]&quot;&gt;
</ins><span class="cx">     &lt;th&gt;
</span><del>-      &lt;a name=&quot;[% keyword.name FILTER html %]&quot;&gt;
-        [% keyword.name FILTER html %]&lt;/a&gt;
</del><ins>+        [% keyword.name FILTER html %]
</ins><span class="cx">     &lt;/th&gt;
</span><span class="cx">     &lt;td&gt;[% keyword.description FILTER html_light %]&lt;/td&gt;
</span><span class="cx">     &lt;td align=&quot;center&quot;&gt;
</span><span class="cx">       [% IF keyword.bug_count &gt; 0 %]
</span><del>-        &lt;a href=&quot;buglist.cgi?keywords=[% keyword.name FILTER url_quote %]&amp;amp;resolution=---&quot;&gt;
</del><ins>+        &lt;a href=&quot;buglist.cgi?keywords=[% keyword.name FILTER uri %]&amp;amp;resolution=---&quot;&gt;
</ins><span class="cx">           Search&lt;/a&gt;
</span><span class="cx">       [% ELSE %]
</span><span class="cx">         none
</span><span class="lines">@@ -65,7 +64,7 @@
</span><span class="cx">     &lt;/td&gt;
</span><span class="cx">     &lt;td align=&quot;right&quot;&gt;
</span><span class="cx">       [% IF keyword.bug_count &gt; 0 %]
</span><del>-        &lt;a href=&quot;buglist.cgi?keywords=[% keyword.name FILTER url_quote %]&quot;&gt;
</del><ins>+        &lt;a href=&quot;buglist.cgi?keywords=[% keyword.name FILTER uri %]&quot;&gt;
</ins><span class="cx">           [% keyword.bug_count %]&lt;/a&gt;
</span><span class="cx">       [% ELSE %]
</span><span class="cx">         none
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultreportsmenuhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/reports/menu.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/reports/menu.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/reports/menu.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -28,6 +28,7 @@
</span><span class="cx"> [% PROCESS global/header.html.tmpl
</span><span class="cx">   title = &quot;Reporting and Charting Kitchen&quot;
</span><span class="cx">   doc_section = &quot;reporting.html&quot;
</span><ins>+  style_urls = ['skins/standard/reports.css']
</ins><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> &lt;p&gt;
</span><span class="lines">@@ -38,38 +39,51 @@
</span><span class="cx"> &lt;h2&gt;Current State&lt;/h2&gt;
</span><span class="cx"> 
</span><span class="cx"> &lt;ul&gt;
</span><del>-  &lt;li&gt;
</del><ins>+  &lt;li id=&quot;report_search&quot;&gt;
</ins><span class="cx">     &lt;strong&gt;&lt;a href=&quot;query.cgi&quot;&gt;Search&lt;/a&gt;&lt;/strong&gt; -
</span><span class="cx">     list sets of [% terms.bugs %].
</span><span class="cx">   &lt;/li&gt;
</span><del>-  &lt;li&gt;
</del><ins>+  &lt;li id=&quot;report_tabular&quot;&gt;
</ins><span class="cx">     &lt;strong&gt;
</span><span class="cx">       &lt;a href=&quot;query.cgi?format=report-table&quot;&gt;Tabular reports&lt;/a&gt;
</span><span class="cx">     &lt;/strong&gt; -
</span><span class="cx">     tables of [% terms.bug %] counts in 1, 2 or 3 dimensions, as HTML or CSV.
</span><span class="cx">   &lt;/li&gt;
</span><del>-  &lt;li&gt;
-    &lt;strong&gt;
-      &lt;a href=&quot;query.cgi?format=report-graph&quot;&gt;Graphical reports&lt;/a&gt;
-    &lt;/strong&gt; -
-    line graphs, bar and pie charts.
</del><ins>+  [% IF feature_enabled('graphical_reports') %]
+    &lt;li id=&quot;report_graphical&quot;&gt;
+      &lt;strong&gt;
+        &lt;a href=&quot;query.cgi?format=report-graph&quot;&gt;Graphical reports&lt;/a&gt;
+      &lt;/strong&gt; -
+      line graphs, bar and pie charts.
+    &lt;/li&gt;
+  [% END %]
+  &lt;li id=&quot;report_duplicates&quot;&gt;
+    &lt;strong&gt;&lt;a href=&quot;duplicates.cgi&quot;&gt;Duplicates&lt;/a&gt;&lt;/strong&gt; -
+    list of most frequently reported [% terms.bugs %].
</ins><span class="cx">   &lt;/li&gt;
</span><ins>+  [% Hook.process('current_state') %]
</ins><span class="cx"> &lt;/ul&gt;
</span><span class="cx"> 
</span><del>-&lt;h2&gt;Change Over Time&lt;/h2&gt;
</del><ins>+[% IF feature_enabled('new_charts') OR feature_enabled('old_charts') %]
+  &lt;h2&gt;Change Over Time&lt;/h2&gt;
</ins><span class="cx"> 
</span><del>-&lt;ul&gt;
-  &lt;li&gt;
-    &lt;strong&gt;&lt;a href=&quot;reports.cgi&quot;&gt;Old Charts&lt;/a&gt;&lt;/strong&gt; - 
-    plot the status and/or resolution of [% terms.bugs %] against
-    time, for each product in your database.
-  &lt;/li&gt;
-  [% IF user.in_group(Param(&quot;chartgroup&quot;)) %]
-    &lt;li&gt;
-      &lt;strong&gt;&lt;a href=&quot;chart.cgi&quot;&gt;New Charts&lt;/a&gt;&lt;/strong&gt; - 
-      plot any arbitrary search against time. Far more powerful.
-    &lt;/li&gt;
-  [% END %]
-&lt;/ul&gt;
</del><ins>+  &lt;ul&gt;
+    [% IF feature_enabled('old_charts') %]
+      &lt;li id=&quot;old_charts&quot;&gt;
+        &lt;strong&gt;&lt;a href=&quot;reports.cgi&quot;&gt;Old Charts&lt;/a&gt;&lt;/strong&gt; - 
+        plot the status and/or resolution of [% terms.bugs %] against
+        time, for each product in your database.
+      &lt;/li&gt;
+    [% END %]
+    [% IF feature_enabled('new_charts') AND user.in_group(Param(&quot;chartgroup&quot;)) %]
+      &lt;li id=&quot;new_charts&quot;&gt;
+        &lt;strong&gt;&lt;a href=&quot;chart.cgi&quot;&gt;New Charts&lt;/a&gt;&lt;/strong&gt; - 
+        plot any arbitrary search against time. Far more powerful.
+      &lt;/li&gt;
+    [% END %]
+  &lt;/ul&gt;
+[% END %]
</ins><span class="cx"> 
</span><ins>+[% Hook.process('end') %]
+
</ins><span class="cx"> [% PROCESS global/footer.html.tmpl %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultreportsoldchartshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/reports/old-charts.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/reports/old-charts.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/reports/old-charts.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -51,7 +51,7 @@
</span><span class="cx">               [%# We cannot use translated statuses and resolutions from field-descs.none.html
</span><span class="cx">                 # because old charts do not distinguish statuses from resolutions. %]
</span><span class="cx">               [% FOREACH dataset = datasets %]
</span><del>-                &lt;option value=&quot;[% dataset.value FILTER html %]:&quot;
</del><ins>+                &lt;option value=&quot;[% dataset.value FILTER html %]&quot;
</ins><span class="cx">                   [% &quot; selected=\&quot;selected\&quot;&quot; IF dataset.selected %]&gt;
</span><span class="cx">                   [% dataset.value FILTER html %]&lt;/option&gt;
</span><span class="cx">               [% END %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultreportsreportbarpngtmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/reports/report-bar.png.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/reports/report-bar.png.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/reports/report-bar.png.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -26,30 +26,14 @@
</span><span class="cx"> 
</span><span class="cx"> [% col_field_disp = field_descs.$col_field || col_field %]
</span><span class="cx"> 
</span><del>-[% IF col_field == 'bug_status' %]
-  [% FOR i IN [ 0 .. data.0.0.max ] %]
-    [% data.0.0.$i = get_status(data.0.0.$i) %]
-  [% END %]
</del><ins>+[% FOR i IN [ 0 .. data.0.0.max ] %]
+  [% data.0.0.$i = display_value(col_field, data.0.0.$i) %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><del>-[% IF col_field == 'resolution' %]
-  [% FOR i IN [ 0 .. data.0.0.max ] %]
-    [% data.0.0.$i = get_resolution(data.0.0.$i) %]
-  [% END %]
</del><ins>+[% FOR i IN [ 0 .. row_names.max ] %]
+  [% row_names.$i = display_value(row_field, row_names.$i) %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><del>-[% IF row_field == 'bug_status' %]
-  [% FOR i IN [ 0 .. row_names.max ] %]
-    [% row_names.$i = get_status(row_names.$i) %]
-  [% END %]
-[% END %]
-
-[% IF row_field == 'resolution' %]
-  [% FOR i IN [ 0 .. row_names.max ] %]
-    [% row_names.$i = get_resolution(row_names.$i) %]
-  [% END %]
-[% END %]
-
</del><span class="cx"> [% FILTER null;
</span><span class="cx">   USE graph = GD.Graph.bars(width, height);
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultreportsreportlinepngtmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/reports/report-line.png.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/reports/report-line.png.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/reports/report-line.png.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -26,30 +26,14 @@
</span><span class="cx"> 
</span><span class="cx"> [% col_field_disp = field_descs.$col_field || col_field %]
</span><span class="cx"> 
</span><del>-[% IF col_field == 'bug_status' %]
-  [% FOR i IN [ 0 .. data.0.0.max ] %]
-    [% data.0.0.$i = get_status(data.0.0.$i) %]
-  [% END %]
</del><ins>+[% FOR i IN [ 0 .. data.0.0.max ] %]
+  [% data.0.0.$i = display_value(col_field, data.0.0.$i) %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><del>-[% IF col_field == 'resolution' %]
-  [% FOR i IN [ 0 .. data.0.0.max ] %]
-    [% data.0.0.$i = get_resolution(data.0.0.$i) %]
-  [% END %]
</del><ins>+[% FOR i IN [ 0 .. row_names.max ] %]
+  [% row_names.$i = display_value(row_field, row_names.$i) %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><del>-[% IF row_field == 'bug_status' %]
-  [% FOR i IN [ 0 .. row_names.max ] %]
-    [% row_names.$i = get_status(row_names.$i) %]
-  [% END %]
-[% END %]
-
-[% IF row_field == 'resolution' %]
-  [% FOR i IN [ 0 .. row_names.max ] %]
-    [% row_names.$i = get_resolution(row_names.$i) %]
-  [% END %]
-[% END %]
-
</del><span class="cx"> [% IF cumulate %]
</span><span class="cx">   [% USE graph = GD.Graph.area(width, height) %]
</span><span class="cx">   [% graph.set(cumulate =&gt; &quot;true&quot;) %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultreportsreportpiepngtmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/reports/report-pie.png.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/reports/report-pie.png.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/reports/report-pie.png.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -22,18 +22,10 @@
</span><span class="cx"> 
</span><span class="cx"> [% col_field_disp = field_descs.$col_field || col_field %]
</span><span class="cx"> 
</span><del>-[% IF col_field == 'bug_status' %]
-  [% FOR i IN [ 0 .. data.0.0.max ] %]
-    [% data.0.0.$i = get_status(data.0.0.$i) %]
-  [% END %]
</del><ins>+[% FOR i IN [ 0 .. data.0.0.max ] %]
+  [% data.0.0.$i = display_value(col_field, data.0.0.$i) %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><del>-[% IF col_field == 'resolution' %]
-  [% FOR i IN [ 0 .. data.0.0.max ] %]
-    [% data.0.0.$i = get_resolution(data.0.0.$i) %]
-  [% END %]
-[% END %]
-
</del><span class="cx"> [% FILTER null;
</span><span class="cx">   USE graph = GD.Graph.pie(width, height);
</span><span class="cx">     
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultreportsreporttablecsvtmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/reports/report-table.csv.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/reports/report-table.csv.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/reports/report-table.csv.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -30,7 +30,14 @@
</span><span class="cx"> [% row_field_disp = field_descs.$row_field || row_field %]
</span><span class="cx"> 
</span><span class="cx"> [% IF tbl_field %]
</span><del>-  [% tbl_field_disp FILTER csv %]: [% tbl FILTER csv %]
</del><ins>+  [% IF tbl_field == 'assigned_to' OR tbl_field == 'reporter'
+        OR tbl_field == 'qa_contact'
+  %]
+    [% tbl_disp = tbl FILTER email %]
+  [% ELSE %]
+    [% tbl_disp = tbl %]
+  [% END %]
+  [% tbl_field_disp FILTER csv %]: [% tbl_disp FILTER csv %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> [% IF row_field %]
</span><span class="cx">   [% row_field_disp FILTER csv %]
</span><span class="lines">@@ -40,26 +47,14 @@
</span><span class="cx"> [% IF col_field -%]
</span><span class="cx">   [% FOREACH col = col_names -%]
</span><span class="cx">     [% colsepchar %]
</span><del>-    [% IF col_field == 'bug_status' %]
-      [% get_status(col) FILTER csv -%]
-    [% ELSIF col_field == 'resolution' %]
-      [% get_resolution(col) FILTER csv -%]
-    [% ELSE %]
-      [% col FILTER csv -%]
-    [% END %]
</del><ins>+    [% PROCESS value_display value = col field = col_field %]
</ins><span class="cx">   [% END -%]
</span><span class="cx"> [% ELSE -%]
</span><span class="cx">   [% colsepchar %][% num_bugs FILTER csv %]
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% FOREACH row = row_names %]
</span><del>-  [% IF row_field == 'bug_status' %]
-    [% get_status(row) FILTER csv -%]
-  [% ELSIF row_field == 'resolution' %]
-    [% get_resolution(row) FILTER csv -%]
-  [% ELSE %]
-    [% row FILTER csv -%]
-  [% END %]
</del><ins>+  [% PROCESS value_display value = row field = row_field %]
</ins><span class="cx">   [% FOREACH col = col_names %]
</span><span class="cx">     [% colsepchar %]
</span><span class="cx">     [% IF data.$tbl AND data.$tbl.$col AND data.$tbl.$col.$row %]
</span><span class="lines">@@ -70,3 +65,13 @@
</span><span class="cx">   [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% END %]
</span><ins>+
+[% BLOCK value_display %]
+  [% SET disp_value = display_value(field, value) %]
+  [% IF field == 'assigned_to' OR field == 'reporter'
+           OR field == 'qa_contact'
+  %]
+    [% disp_value = value FILTER email %]
+  [% END %]
+  [% disp_value FILTER csv %]
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultreportsreporttablehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/reports/report-table.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/reports/report-table.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/reports/report-table.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -17,6 +17,8 @@
</span><span class="cx">   #
</span><span class="cx">   # Contributor(s): Gervase Markham &lt;gerv@gerv.net&gt;
</span><span class="cx">   #                 &lt;rdean@cambianetworks.com&gt;
</span><ins>+  #                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
+  #                 Guy Pyrzak &lt;guy.parzak@gmail.com&gt;
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [%# INTERFACE:
</span><span class="lines">@@ -34,17 +36,112 @@
</span><span class="cx"> 
</span><span class="cx"> [% col_field_disp = field_descs.$col_field || col_field %]
</span><span class="cx"> [% row_field_disp = field_descs.$row_field || row_field %]
</span><del>-  
</del><ins>+
+[% urlbase = BLOCK %]buglist.cgi?[% buglistbase FILTER html %][% END %]
</ins><span class="cx"> [% IF tbl == &quot;-total-&quot; %]
</span><del>-  [% urlbase = BLOCK %]buglist.cgi?[% buglistbase FILTER html %]
-  [% &quot;&amp;amp;$tbl_vals&quot; IF tbl_vals %][% END %]
-[% ELSE %]
-  [% urlbase = BLOCK %]buglist.cgi?[% buglistbase FILTER html %]&amp;amp;
-  [% tbl_field FILTER url_quote %]=[% tbl FILTER url_quote %][% END %]
</del><ins>+  [% IF tbl_vals %]
+    [% urlbase = urlbase _ &quot;&amp;amp;&quot; _ tbl_vals %]
+  [% END %]
+[% ELSIF tbl_field %]
+  [% urlbase = BLOCK %][% urlbase %]&amp;amp;[% tbl_field FILTER uri %]=[% tbl FILTER uri %][% END %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><ins>+&lt;script type=&quot;text/javascript&quot;&gt;
+YAHOO.util.Event.addListener(window, &quot;load&quot;, function() {
+  this.Linkify = function(elLiner, oRecord, oColumn, oData) {
+    if (oData == 0)
+      elLiner.innerHTML = &quot;.&quot;;
+    else if (oRecord.getData(&quot;row_title&quot;) == &quot;Total&quot;)
+      elLiner.innerHTML = &quot;&lt;a href='[% urlbase %]&amp;amp;[% col_field FILTER js %]=&quot;
+                          + oColumn.field + &quot;[% '&amp;amp;' _ row_vals IF row_vals %]'&gt;&quot;
+                          + oData + &quot;&lt;/a&gt;&quot;;
+    else
+      elLiner.innerHTML = &quot;&lt;a href='[% urlbase %]&amp;amp;[% row_field FILTER js %]=&quot;
+                          + oRecord.getData(&quot;row_title&quot;).replace(/\s+$/,&quot;&quot;)
+                          + &quot;&amp;amp;[% col_field FILTER js %]=&quot; + oColumn.field
+                          + &quot;'&gt;&quot; + oData + &quot;&lt;/a&gt;&quot;;
+  };
+
+  this.LinkifyTotal = function(elLiner, oRecord, oColumn, oData) {
+    if (oData == 0)
+      elLiner.innerHTML = &quot;.&quot;;
+    else if (oRecord.getData(&quot;row_title&quot;) == &quot;Total&quot;)
+      elLiner.innerHTML = &quot;&lt;a href='[% urlbase %][% '&amp;amp;' _ row_vals IF row_vals %]
+                          [%~ '&amp;amp;' _ col_vals IF col_vals %]'&gt;&quot;
+                          + oData + &quot;&lt;/a&gt;&quot;;
+    else
+      elLiner.innerHTML = &quot;&lt;a href='[% urlbase %]&amp;amp;[% row_field FILTER js %]=&quot;
+                          + oRecord.getData(&quot;row_title&quot;).replace(/\s+$/,&quot;&quot;)
+                          + &quot;[% '&amp;amp;' _ col_vals IF col_vals %]'&gt;&quot; + oData + &quot;&lt;/a&gt;&quot;;
+
+    YAHOO.util.Dom.addClass(elLiner.parentNode, &quot;ttotal&quot;);
+  };
+
+  var totalRowFormatter = function( elTr, oRecord ) {
+      if ( oRecord.getData('row_title') == &quot;Total&quot; ) {
+          YAHOO.util.Dom.addClass( elTr, 'ttotal' );
+      }
+      return true;
+  };
+
+  var totalNumberSorter = function( a, b, desc, field ){
+    var a_value = a.getData(field);
+    var b_value = b.getData(field);
+    var a_total_test = a.getData(&quot;row_title&quot;);
+    var b_total_test = b.getData(&quot;row_title&quot;);
+    var comp_result = YAHOO.util.Sort.compare(a_value, b_value, desc);
+    if( a_total_test == &quot;Total&quot; ){
+      comp_result = 1;
+    }else if( b_total_test == &quot;Total&quot; ){
+      comp_result = -1;
+    }
+    return comp_result;
+  };
+
+
+  var myColumnDefs = [
+        {key:&quot;row_title&quot;, label:&quot;&quot;, sortable:true, sortOptions: { sortFunction:totalNumberSorter }},
+        [% FOREACH col = col_names %]
+          {key:&quot;[% col FILTER js %]&quot;, label:&quot;[% display_value(col_field, col) FILTER js %]&quot;, sortable:true,
+           formatter:this.Linkify, sortOptions: { defaultDir: YAHOO.widget.DataTable.CLASS_DESC, sortFunction:totalNumberSorter }},
+        [% END %]
+        {key:&quot;total&quot;, label:&quot;Total&quot;, sortable:true, formatter:this.LinkifyTotal,
+         sortOptions: { defaultDir: YAHOO.widget.DataTable.CLASS_DESC, sortFunction:totalNumberSorter }}
+      ];
+  this.parseString = function(str) {
+    return YAHOO.lang.trim(str);
+  };
+
+  this.parseNumber = function(str) {
+    if (str.match(/^\s*\.\s*$/m))
+      return 0;
+
+    // Do not use &lt;\/a&gt;$. For some reason, IE6 doesn't understand it.
+    // We use [^\d]+$ instead.
+    var res = str.match(/&gt;(\d+)[^\d]+$/m);
+    if (res &amp;&amp; res[1])
+      return parseFloat(res[1]);
+  };
+
+  this.myDataSource = new YAHOO.util.DataSource(YAHOO.util.Dom.get(&quot;tabular_report&quot;));
+  this.myDataSource.responseType = YAHOO.util.DataSource.TYPE_HTMLTABLE;
+  this.myDataSource.responseSchema = {
+    fields: [
+      {key:&quot;row_title&quot;, parser:this.parseString},
+      [% FOREACH col = col_names %]
+        {key:&quot;[% col FILTER js %]&quot;, parser:this.parseNumber},
+      [% END %]
+      {key:&quot;total&quot;, parser:this.parseNumber}
+    ]
+  };
+  this.myDataTable = new YAHOO.widget.DataTable(&quot;tabular_report_container_
+                         [% tbl FILTER js %]&quot;, myColumnDefs, this.myDataSource, 
+                         {formatRow: totalRowFormatter});
+});
+&lt;/script&gt;
+
</ins><span class="cx"> [% IF tbl_field %]
</span><del>-  &lt;h2&gt;[% tbl_disp FILTER html %]&lt;/h2&gt;
</del><ins>+  &lt;h2&gt;[% tbl_disp FILTER email FILTER html %]&lt;/h2&gt;
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> &lt;table&gt;
</span><span class="lines">@@ -67,58 +164,48 @@
</span><span class="cx"> [% col_idx = 0 %]
</span><span class="cx"> [% row_idx = 0 %]
</span><span class="cx"> [% grand_total = 0 %]
</span><del>-
-&lt;table border=&quot;1&quot;&gt;
</del><ins>+&lt;div id=&quot;tabular_report_container_[% tbl FILTER js %]&quot;&gt;
+&lt;table id=&quot;tabular_report&quot; border=&quot;1&quot;&gt;
</ins><span class="cx">   [% IF col_field %]
</span><ins>+    &lt;thead&gt;
</ins><span class="cx">     &lt;tr&gt;
</span><del>-      &lt;td class=&quot;[% classes.$row_idx.$col_idx %]&quot;&gt;
-      &lt;/td&gt;
</del><ins>+      &lt;th class=&quot;[% classes.$row_idx.$col_idx %]&quot;&gt;
+      &lt;/th&gt;
</ins><span class="cx">       [% FOREACH col = col_names %]
</span><span class="cx">         [% col_totals.$col = 0 %]
</span><span class="cx">         [% NEXT IF col == &quot;&quot; %]
</span><span class="cx">         
</span><span class="cx">         [% col_idx = 1 - col_idx %]
</span><del>-        &lt;td class=&quot;[% classes.$row_idx.$col_idx %]&quot;&gt;
-          [% IF col_field == 'bug_status' %]
-            [% get_status(col) FILTER html FILTER replace('^ $','&amp;nbsp;') %]
-          [% ELSIF col_field == 'resolution' %]
-            [% get_resolution(col) FILTER html FILTER replace('^ $','&amp;nbsp;') %]
-          [% ELSE %]
-            [% col FILTER html FILTER replace('^ $','&amp;nbsp;') %]
-          [% END %]
-        &lt;/td&gt;
</del><ins>+        &lt;th class=&quot;[% classes.$row_idx.$col_idx %]&quot;&gt;
+          [% PROCESS value_display value = col field = col_field %]
+        &lt;/th&gt;
</ins><span class="cx">       [% END %]
</span><del>-      &lt;td class=&quot;ttotal&quot;&gt;
</del><ins>+      &lt;th class=&quot;ttotal&quot;&gt;
</ins><span class="cx">         Total
</span><del>-      &lt;/td&gt;
</del><ins>+      &lt;/th&gt;
</ins><span class="cx">     &lt;/tr&gt;
</span><ins>+    &lt;/thead&gt;
</ins><span class="cx">   [% END %]
</span><del>-  
</del><ins>+  &lt;tbody&gt;
</ins><span class="cx">   [% FOREACH row = row_names %]
</span><span class="cx">     [% row_total = 0 %]
</span><span class="cx">     
</span><span class="cx">     [% row_idx = 1 - row_idx %]
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;td class=&quot;[% classes.$row_idx.$col_idx %]&quot; align=&quot;right&quot;&gt;
</span><del>-        [% IF row_field == 'bug_status' %]
-          [% get_status(row) FILTER html FILTER replace('^ $','&amp;nbsp;') %]
-        [% ELSIF row_field == 'resolution' %]
-          [% get_resolution(row) FILTER html FILTER replace('^ $','&amp;nbsp;') %]
-        [% ELSE %]
-          [% row FILTER html FILTER replace('^ $','&amp;nbsp;') %]
-        [% END %]
</del><ins>+        [% PROCESS value_display value = row field = row_field %]
</ins><span class="cx">       &lt;/td&gt;
</span><span class="cx">       [% FOREACH col = col_names %]
</span><span class="cx">         [% row_total = row_total + data.$tbl.$col.$row %]
</span><span class="cx">         [% NEXT IF col == &quot;&quot; %]
</span><del>-        [% col_totals.$col = col_totals.$col + data.$tbl.$col.$row %]
</del><ins>+        [% col_totals.$col = (col_totals.$col || 0) + data.$tbl.$col.$row %]
</ins><span class="cx">         
</span><span class="cx">         [% col_idx = 1 - col_idx %]
</span><span class="cx">         &lt;td class=&quot;[% classes.$row_idx.$col_idx %]&quot; align=&quot;center&quot;&gt;
</span><span class="cx">           [% IF data.$tbl.$col.$row AND data.$tbl.$col.$row &gt; 0 %]
</span><span class="cx">             &lt;a href=&quot;[% urlbase %]&amp;amp;
</span><del>-              [% row_field FILTER url_quote %]=[% row FILTER url_quote %]&amp;amp;
-              [% col_field FILTER url_quote %]=[% col FILTER url_quote %]&quot;&gt;
</del><ins>+              [% row_field FILTER uri %]=[% row FILTER uri %]&amp;amp;
+              [% col_field FILTER uri %]=[% col FILTER uri %]&quot;&gt;
</ins><span class="cx">               [% data.$tbl.$col.$row %]&lt;/a&gt;
</span><span class="cx">           [% ELSE %]
</span><span class="cx">             .
</span><span class="lines">@@ -127,40 +214,50 @@
</span><span class="cx">       [% END %] 
</span><span class="cx">       &lt;td class=&quot;ttotal&quot; align=&quot;right&quot;&gt;
</span><span class="cx">         &lt;a href=&quot;[% urlbase %]&amp;amp;
</span><del>-          [% row_field FILTER url_quote %]=[% row FILTER url_quote %]
</del><ins>+          [% row_field FILTER uri %]=[% row FILTER uri %]
</ins><span class="cx">           [% &quot;&amp;amp;$col_vals&quot; IF col_vals %]&quot;&gt;
</span><span class="cx">         [% row_total %]&lt;/a&gt;
</span><span class="cx">         [% grand_total = grand_total + row_total %]
</span><span class="cx">       &lt;/td&gt;
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">   [% END %]
</span><del>-  
-  &lt;tr&gt;
-    [% row_idx = 1 - row_idx %]
-    &lt;td class=&quot;ttotal&quot;&gt;
-      Total
-    &lt;/td&gt;
-    [% FOREACH col = col_names %]
-      [% NEXT IF col == &quot;&quot; %]
</del><ins>+    &lt;tr&gt;
+      [% row_idx = 1 - row_idx %]
+      &lt;td class=&quot;ttotal&quot;&gt;
+        Total
+      &lt;/td&gt;
+      [% FOREACH col = col_names %]
+        [% NEXT IF col == &quot;&quot; %]
</ins><span class="cx">       
</span><del>-      &lt;td class=&quot;ttotal&quot; align=&quot;center&quot;&gt;
-        &lt;a href=&quot;[% urlbase %]&amp;amp;
-          [% col_field FILTER url_quote %]=[% col FILTER url_quote %]
-          [% &quot;&amp;amp;$row_vals&quot; IF row_vals %]&quot;&gt;
-        [% col_totals.$col %]&lt;/a&gt;
-      &lt;/td&gt; 
-    [% END %]
-    &lt;td class=&quot;ttotal&quot; align=&quot;right&quot;&gt;
-      &lt;strong&gt;
-        &lt;a href=&quot;[% urlbase %]
-          [% &quot;&amp;amp;$row_vals&quot; IF row_vals %]
-          [% &quot;&amp;amp;$col_vals&quot; IF col_vals %]&quot;&gt;[% grand_total %]&lt;/a&gt;
-      &lt;/strong&gt;
</del><ins>+        &lt;td class=&quot;ttotal&quot; align=&quot;center&quot;&gt;
+          &lt;a href=&quot;[% urlbase %]&amp;amp;
+            [% col_field FILTER uri %]=[% col FILTER uri %]
+            [% &quot;&amp;amp;$row_vals&quot; IF row_vals %]&quot;&gt;
+          [% col_totals.$col %]&lt;/a&gt;
+        &lt;/td&gt;
+      [% END %]
+      &lt;td class=&quot;ttotal&quot; align=&quot;right&quot;&gt;
+        &lt;strong&gt;
+          &lt;a href=&quot;[% urlbase %]
+            [% &quot;&amp;amp;$row_vals&quot; IF row_vals %]
+            [% &quot;&amp;amp;$col_vals&quot; IF col_vals %]&quot;&gt;[% grand_total %]&lt;/a&gt;
+        &lt;/strong&gt;
+      &lt;/td&gt;
+    &lt;/tr&gt;
+  &lt;/tbody&gt;
+&lt;/table&gt;
+&lt;/div&gt;
+      
</ins><span class="cx">     &lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> &lt;/table&gt;
</span><span class="cx"> 
</span><del>-      
-    &lt;/td&gt;
-  &lt;/tr&gt;
-&lt;/table&gt;    
</del><ins>+[% BLOCK value_display %]
+  [% SET disp_value = display_value(field, value) %]
+  [% IF field == 'assigned_to' OR field == 'reporter'
+           OR field == 'qa_contact'
+  %]
+    [% disp_value = value FILTER email %]
+  [% END %]
+  [% disp_value FILTER html FILTER replace('^ $','&amp;nbsp;') %]
+[% END %] 
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultreportsreporthtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/reports/report.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/reports/report.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/reports/report.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -66,15 +66,18 @@
</span><span class="cx">   [% col_field_disp FILTER html %]
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><ins>+[% time = time FILTER time('%Y-%m-%d %H:%M:%S') FILTER html %]
+
</ins><span class="cx"> [% PROCESS global/header.html.tmpl 
</span><span class="cx">   style = &quot;
</span><span class="cx">     .t1     { background-color: #ffffff } /* white       */
</span><span class="cx">     .t2     { background-color: #dfefff } /* light blue  */
</span><span class="cx">     .t3     { background-color: #dddddd } /* grey        */
</span><span class="cx">     .t4     { background-color: #c3d3ed } /* darker blue */
</span><del>-    .ttotal { background-color: #cfffdf } /* light green */
</del><ins>+    .ttotal, .ttotal td { background-color: #cfffdf } /* light green */
</ins><span class="cx">   &quot;
</span><del>-  header_addl_info = time2str(&quot;%Y-%m-%d %H:%M:%S&quot;, time)
</del><ins>+  header_addl_info = time
+  yui = ['datatable']
</ins><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> [% IF debug %]
</span><span class="lines">@@ -94,18 +97,18 @@
</span><span class="cx">       [% PROCESS &quot;reports/report-table.html.tmpl&quot; %]
</span><span class="cx">     [% ELSE %]
</span><span class="cx">       [% IF tbl %]
</span><del>-        &lt;h2&gt;[% tbl_disp FILTER html %]&lt;/h2&gt;
</del><ins>+        &lt;h2&gt;[% tbl_disp FILTER email FILTER html %]&lt;/h2&gt;
</ins><span class="cx">       [% END %]
</span><span class="cx">       
</span><span class="cx">       [% imageurl = BLOCK %]report.cgi?[% imagebase FILTER html %]&amp;amp;format=
</span><del>-        [% format FILTER url_quote %]&amp;amp;ctype=png&amp;amp;action=plot&amp;amp;
</del><ins>+        [% format FILTER uri %]&amp;amp;ctype=png&amp;amp;action=plot&amp;amp;
</ins><span class="cx">         [% IF tbl_field %]
</span><span class="cx">           [% IF tbl != &quot;-total-&quot; %]
</span><del>-            [% tbl_field FILTER url_quote %]=[% tbl FILTER url_quote %]&amp;amp;
</del><ins>+            [% tbl_field FILTER uri %]=[% tbl FILTER uri %]&amp;amp;
</ins><span class="cx">           [% ELSE %]
</span><span class="cx">             [% FOREACH tblname = tbl_names %]
</span><span class="cx">               [% IF tblname != &quot;-total-&quot; %]
</span><del>-                [% tbl_field FILTER url_quote %]=[% tblname FILTER url_quote %]&amp;amp;
</del><ins>+                [% tbl_field FILTER uri %]=[% tblname FILTER uri %]&amp;amp;
</ins><span class="cx">               [% END %]
</span><span class="cx">             [% END %]
</span><span class="cx">           [% END %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultreportsseriescommonhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/reports/series-common.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/reports/series-common.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/reports/series-common.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -48,7 +48,6 @@
</span><span class="cx"> [% END %] 
</span><span class="cx"> };
</span><span class="cx"> 
</span><del>-[%# Should attempt to preserve selection across invocations @@@ %]
</del><span class="cx"> [%# This function takes necessary action on selection of a category %]
</span><span class="cx"> function catSelected() {
</span><span class="cx">   var cat = document.chartform.category.value;
</span><span class="lines">@@ -67,7 +66,8 @@
</span><span class="cx">   [% IF newtext %]
</span><span class="cx">     subcatwidget.options[i] = new Option(&quot;[% newtext FILTER js %]&quot;, &quot;&quot;);
</span><span class="cx">   [% END %]  
</span><del>-  
</del><ins>+
+  subcatwidget.disabled = false;
</ins><span class="cx">   subcatwidget.options[0].selected = true;
</span><span class="cx">   
</span><span class="cx">   if (document.chartform.action[1]) {
</span><span class="lines">@@ -100,11 +100,13 @@
</span><span class="cx">   &lt;td align=&quot;left&quot;&gt;
</span><span class="cx">     &lt;select name=&quot;[% sel.name %]&quot; id=&quot;[% sel.name %]&quot;
</span><span class="cx">             size=&quot;[% sel.size %]&quot; style=&quot;width: 15em&quot;
</span><ins>+            [%+ 'multiple=&quot;multiple&quot;' IF sel.multiple %]
</ins><span class="cx">             [%+ &quot;disabled=\&quot;disabled\&quot;&quot; UNLESS ${sel.name}.keys.size || newtext %]
</span><span class="cx">             [%+ &quot;onchange=\&quot;$sel.onchange\&quot;&quot; IF sel.onchange %]&gt;
</span><span class="cx">       [% FOREACH x = ${sel.name}.keys.sort %]
</span><del>-        &lt;option value=&quot;[% x FILTER html %]&quot;
-          [% &quot; selected&quot; IF default.${sel.name} == x %]&gt;
</del><ins>+        [% value = sel.value_in_hash ? ${sel.name}.$x : x %]
+        &lt;option value=&quot;[% value FILTER html %]&quot;
+          [% &quot; selected&quot; IF default.${sel.name} == value %]&gt;
</ins><span class="cx">           [% x FILTER html %]&lt;/option&gt;
</span><span class="cx">       [% END %]
</span><span class="cx">       [% IF newtext %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultrequestemailtxttmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/request/email.txt.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/request/email.txt.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/request/email.txt.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -24,30 +24,34 @@
</span><span class="cx"> 
</span><span class="cx"> [% bugidsummary = bug.bug_id _ ': ' _ bug.short_desc %]
</span><span class="cx"> [% attidsummary = attachment.id _ ': ' _ attachment.description %]
</span><ins>+[% flagtype_name = flag ? flag.type.name : old_flag.type.name %]
</ins><span class="cx"> [% statuses = { '+' =&gt; &quot;granted&quot; , '-' =&gt; 'denied' , 'X' =&gt; &quot;canceled&quot; ,
</span><span class="cx">                 '?' =&gt; &quot;asked&quot; } %]
</span><span class="cx"> 
</span><span class="cx"> [% to_identity = &quot;&quot; %]
</span><span class="cx"> [% on_behalf_of = 0 %]
</span><del>-[% IF flag.status == '?' %]
</del><ins>+[% action = flag.status || 'X' %]
+
+[% IF flag &amp;&amp; flag.status == '?' %]
</ins><span class="cx">   [% subject_status = &quot;requested&quot; %]
</span><del>-  [% IF flag.setter.id == user.id %]
</del><ins>+  [% IF flag.setter_id == user.id %]
</ins><span class="cx">     [% to_identity = flag.requestee.identity _ &quot; for&quot; %]
</span><span class="cx">   [% ELSE %]
</span><span class="cx">     [% on_behalf_of = 1 %]
</span><span class="cx">     [% IF flag.requestee %][% to_identity = &quot; to &quot; _ flag.requestee.identity %][% END %]
</span><span class="cx">   [% END %]
</span><span class="cx"> [% ELSE %]
</span><del>-  [% IF flag.requester %]
-    [% to_identity = flag.requester.identity _ &quot;'s request for&quot; %]
</del><ins>+  [% IF old_flag &amp;&amp; old_flag.status == '?' %]
+    [% to_identity = old_flag.setter.identity _ &quot;'s request for&quot; %]
</ins><span class="cx">   [% END %]
</span><del>-  [% subject_status = statuses.${flag.status} %]
</del><ins>+  [% subject_status = statuses.$action %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> From: [% Param('mailfrom') %]
</span><span class="cx"> To: [% to %]
</span><del>-Subject: [% flag.type.name %] [%+ subject_status %]: [[% terms.Bug %] [%+ bug.bug_id %]] [% bug.short_desc %]
</del><ins>+Subject: [% flagtype_name %] [%+ subject_status %]: [[% terms.Bug %] [%+ bug.bug_id %]] [% bug.short_desc %]
</ins><span class="cx"> [%- IF attachment %] :
</span><del>-  [Attachment [% attachment.id %]] [% attachment.description %][% END %]
</del><ins>+  [Attachment [% attachment.id %]] [% attachment.description FILTER clean_text %][% END %]
+Date: [% date %]
</ins><span class="cx"> X-Bugzilla-Type: request
</span><span class="cx"> [%+ threadingmarker %]
</span><span class="cx"> 
</span><span class="lines">@@ -55,10 +59,10 @@
</span><span class="cx"> [%- FILTER bullet = wrap(80) -%]
</span><span class="cx"> 
</span><span class="cx"> [% IF on_behalf_of %]
</span><del>-[% user.identity %] has reassigned [% flag.setter.identity %]'s request for [% flag.type.name %]
</del><ins>+[% user.identity %] has reassigned [% flag.setter.identity %]'s request for [% flagtype_name %]
</ins><span class="cx"> [% to_identity %]:
</span><span class="cx"> [% ELSE %]
</span><del>-[% user.identity %] has [% statuses.${flag.status} %] [%+ to_identity %] [%+ flag.type.name %]:
</del><ins>+[% user.identity %] has [% statuses.$action %] [%+ to_identity %] [%+ flagtype_name %]:
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% terms.Bug %] [%+ bugidsummary %]
</span><span class="lines">@@ -71,10 +75,14 @@
</span><span class="cx"> [%- END %]
</span><span class="cx"> [%+ urlbase %]attachment.cgi?id=[% attachment.id %]&amp;action=edit
</span><span class="cx"> [%- END %]
</span><ins>+
+[%- Hook.process('after_summary') -%]
+
</ins><span class="cx"> [%- FILTER bullet = wrap(80) %]
</span><span class="cx"> 
</span><span class="cx"> [% USE Bugzilla %]
</span><del>-[% IF Bugzilla.cgi.param(&quot;comment&quot;) &amp;&amp; Bugzilla.cgi.param(&quot;comment&quot;).length &gt; 0 %]
</del><ins>+[%-# .defined is necessary to avoid a taint issue in Perl &lt; 5.10.1, see bug 509794. %]
+[% IF Bugzilla.cgi.param(&quot;comment&quot;).defined &amp;&amp; Bugzilla.cgi.param(&quot;comment&quot;).length &gt; 0 %]
</ins><span class="cx"> ------- Additional Comments from [% user.identity %]
</span><span class="cx"> [%+ Bugzilla.cgi.param(&quot;comment&quot;) %]
</span><span class="cx"> [% END %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultrequestqueuehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/request/queue.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/request/queue.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/request/queue.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -23,18 +23,43 @@
</span><span class="cx"> [% USE Bugzilla %]
</span><span class="cx"> [% cgi = Bugzilla.cgi %]
</span><span class="cx"> 
</span><del>-[% PROCESS &quot;global/js-products.html.tmpl&quot; %]
-
</del><span class="cx"> [% PROCESS global/header.html.tmpl
</span><span class="cx">   title=&quot;Request Queue&quot;
</span><span class="cx">   style = &quot;
</span><span class="cx">     table.requests th { text-align: left; }
</span><span class="cx">     table#filtering th { text-align: right; }
</span><span class="cx">   &quot;
</span><del>-  onload=&quot;var f = document.forms[0]; selectProduct(f.product, f.component, null, null, 'Any');&quot;
-  javascript_urls=[&quot;js/productform.js&quot;]
</del><ins>+  onload=&quot;var f = document.request_form; selectProduct(f.product, f.component, null, null, 'Any');&quot;
+  javascript_urls=[&quot;js/productform.js&quot;, &quot;js/field.js&quot;]
+  style_urls = ['skins/standard/buglist.css']
+  yui = ['autocomplete']
</ins><span class="cx"> %]
</span><span class="cx"> 
</span><ins>+&lt;script type=&quot;text/javascript&quot;&gt;
+  var useclassification = false; // No classification level in use
+  var first_load = true; // Is this the first time we load the page?
+  var last_sel = []; // Caches last selection
+  var cpts = new Array();
+  [% n = 1 %]
+  [% IF Param('useclassification') %]
+    [% FOREACH clas = user.get_selectable_classifications %]
+      [% FOREACH prod = user.get_selectable_products(clas.id) %]
+        [%+ PROCESS js_comp %]
+      [% END %]
+    [% END %]
+  [% ELSE %]
+    [% FOREACH prod = user.get_selectable_products %]
+      [%+ PROCESS js_comp %]
+    [% END %]
+  [% END %]
+&lt;/script&gt;
+
+[% BLOCK js_comp %]
+  cpts['[% n %]'] = [
+    [%- FOREACH comp = prod.components %]'[% comp.name FILTER js %]'[% &quot;, &quot; UNLESS loop.last %] [%- END -%]];
+  [% n = n+1 %]
+[% END %]
+
</ins><span class="cx"> &lt;p&gt;
</span><span class="cx"> When you are logged in, only requests made by you or addressed to you
</span><span class="cx"> are shown by default.  You can change the criteria using the form below.
</span><span class="lines">@@ -42,22 +67,44 @@
</span><span class="cx"> to some group are shown by default.
</span><span class="cx"> &lt;/p&gt;
</span><span class="cx"> 
</span><del>-&lt;form action=&quot;request.cgi&quot; method=&quot;get&quot;&gt;
</del><ins>+&lt;form id=&quot;request_form&quot; name=&quot;request_form&quot; action=&quot;request.cgi&quot; method=&quot;get&quot;&gt;
</ins><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;queue&quot;&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;table id=&quot;filtering&quot;&gt;
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th&gt;Requester:&lt;/th&gt;
</span><del>-      &lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;requester&quot; value=&quot;[% cgi.param('requester') FILTER html %]&quot; size=&quot;20&quot; 
-           title=&quot;Requester's email address&quot;&gt;&lt;/td&gt;
</del><ins>+      &lt;td&gt;
+        [% INCLUDE global/userselect.html.tmpl
+           id =&gt; &quot;requester&quot;
+           name =&gt; &quot;requester&quot;
+           value =&gt; cgi.param('requester')
+           size =&gt; 20
+           emptyok =&gt; 1
+           field_title =&gt; &quot;Requester's email address&quot;
+        %]
+      &lt;/td&gt;
</ins><span class="cx">       &lt;th&gt;Product:&lt;/th&gt;
</span><span class="cx">       &lt;td&gt;
</span><span class="cx">         &lt;select name=&quot;product&quot; onchange=&quot;selectProduct(this, this.form.component, null, null, 'Any');&quot;&gt;
</span><span class="cx">           &lt;option value=&quot;&quot;&gt;Any&lt;/option&gt;
</span><del>-          [% FOREACH prod = products %]
-            &lt;option value=&quot;[% prod.name FILTER html %]&quot;
-                    [% &quot;selected&quot; IF cgi.param('product') == prod.name %]&gt;
-              [% prod.name FILTER html %]&lt;/option&gt;
</del><ins>+          [% IF Param('useclassification') %]
+            [% FOREACH c = user.get_selectable_classifications %]
+              &lt;optgroup label=&quot;[% c.name FILTER html %]&quot;&gt;
+                [% FOREACH p = user.get_selectable_products(c.id) %]
+                  &lt;option value=&quot;[% p.name FILTER html %]&quot;
+                    [% &quot; selected&quot; IF cgi.param('product') == p.name %]&gt;
+                    [% p.name FILTER html %]
+                  &lt;/option&gt;
+                [% END %]
+              &lt;/optgroup&gt;
+            [% END %]
+          [% ELSE %]
+            [% FOREACH p = user.get_selectable_products %]
+              &lt;option value=&quot;[% p.name FILTER html %]&quot;
+                [% &quot; selected&quot; IF cgi.param('product') == p.name %]&gt;
+                [% p.name FILTER html %]
+              &lt;/option&gt;
+            [% END %]
</ins><span class="cx">           [% END %]
</span><span class="cx">         &lt;/select&gt;
</span><span class="cx">       &lt;/td&gt;
</span><span class="lines">@@ -83,8 +130,17 @@
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       &lt;th&gt;Requestee:&lt;/th&gt;
</span><del>-      &lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;requestee&quot; value=&quot;[% cgi.param('requestee') FILTER html %]&quot; size=&quot;20&quot; 
-           title=&quot;Requestee's email address or &amp;quot;-&amp;quot; (hyphen) for requests with no requestee&quot;&gt;&lt;/td&gt;
</del><ins>+      &lt;td&gt;
+        [% INCLUDE global/userselect.html.tmpl
+           id =&gt; &quot;requestee&quot;
+           name =&gt; &quot;requestee&quot;
+           value =&gt; cgi.param('requestee')
+           size =&gt; 20
+           emptyok =&gt; 1
+           hyphenok =&gt; 1
+           field_title =&gt; &quot;Requestee's email address or \&quot;-\&quot; (hyphen) for requests with no requestee&quot;
+        %]
+      &lt;/td&gt;
</ins><span class="cx">       &lt;th&gt;Component:&lt;/th&gt;
</span><span class="cx">       &lt;td&gt;
</span><span class="cx">         &lt;select name=&quot;component&quot;&gt;
</span><span class="lines">@@ -136,28 +192,32 @@
</span><span class="cx">   &lt;/p&gt;
</span><span class="cx"> [% ELSE %]
</span><span class="cx">   [% FOREACH request = requests %]
</span><del>-    [% IF loop.first %] [% PROCESS start_new_table %] [% END %]
-    [% IF request.$group_field != group_value %]
</del><ins>+    [% IF request.$group_field != group_value || loop.first %]
</ins><span class="cx">       [% group_value = request.$group_field %]
</span><del>-      [% UNLESS loop.first %]
-        &lt;/table&gt;
-        [% PROCESS start_new_table %]
-      [% END %]
</del><ins>+      [% PROCESS display_buglist UNLESS loop.first %]
+      [% PROCESS start_new_table %]
</ins><span class="cx">     [% END %]
</span><ins>+    [% buglist.${request.bug_id} = 1 %]
</ins><span class="cx">     &lt;tr&gt;
</span><span class="cx">       [% FOREACH column = display_columns %]
</span><span class="cx">         [% NEXT IF column == group_field || excluded_columns.contains(column) %]
</span><del>-        &lt;td&gt;[% PROCESS &quot;display_$column&quot; %]&lt;/td&gt;
</del><ins>+        &lt;td&gt;
+          [% PROCESS &quot;display_$column&quot; %]
+          [% Hook.process('after_column') %]
+        &lt;/td&gt;
</ins><span class="cx">       [% END %]
</span><span class="cx">     &lt;/tr&gt;
</span><span class="cx">   [% END %]
</span><del>-  &lt;/table&gt;
</del><ins>+  [% PROCESS display_buglist %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/footer.html.tmpl %]
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK start_new_table %]
</span><del>-  &lt;h3&gt;[% column_headers.$group_field %]: [% (request.$group_field || &quot;None&quot;) FILTER html %]&lt;/h3&gt;
</del><ins>+  [% buglist = {} %]
+
+  &lt;h3&gt;[% column_headers.$group_field %]: 
+    [%+ (request.$group_field || &quot;None&quot;) FILTER email FILTER html %]&lt;/h3&gt;
</ins><span class="cx">   &lt;table class=&quot;requests&quot; cellspacing=&quot;0&quot; cellpadding=&quot;4&quot; border=&quot;1&quot;&gt;
</span><span class="cx">     &lt;tr&gt;
</span><span class="cx">       [% FOREACH column = display_columns %]
</span><span class="lines">@@ -176,7 +236,8 @@
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK display_bug %]
</span><del>-  &lt;a href=&quot;show_bug.cgi?id=[% request.bug_id %]&quot;&gt;
</del><ins>+  &lt;a href=&quot;show_bug.cgi?id=[% request.bug_id %]&quot;
+     [%- ' class=&quot;bz_secure&quot;' IF request.restricted %]&gt;
</ins><span class="cx">     [% request.bug_id %]: [%+ request.bug_summary FILTER html %]&lt;/a&gt;
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="lines">@@ -190,14 +251,21 @@
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK display_requestee %]
</span><del>-  [% request.requestee FILTER html %]
</del><ins>+  [% request.requestee FILTER email FILTER html %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK display_requester %]
</span><del>-  [% request.requester FILTER html %]
</del><ins>+  [% request.requester FILTER email FILTER html %]
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK display_created %]
</span><span class="cx">   [% request.created FILTER time %]
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><ins>+[% BLOCK display_buglist %]
+  &lt;/table&gt;
+  [% NEXT UNLESS buglist.keys.size %]
+  &lt;a href=&quot;buglist.cgi?bug_id=
+           [%- buglist.keys.nsort.join(&quot;,&quot;) FILTER html %]&quot;&gt;(view as
+  [%+ terms.bug %] list)&lt;/a&gt;
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultsearchbooleanchartshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/search/boolean-charts.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/search/boolean-charts.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/search/boolean-charts.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -17,119 +17,176 @@
</span><span class="cx">   #
</span><span class="cx">   # Contributor(s): Gervase Markham &lt;gerv@gerv.net&gt;
</span><span class="cx">   #%]
</span><ins>+
+[% PROCESS &quot;global/field-descs.none.tmpl&quot; %]
</ins><span class="cx">   
</span><span class="cx"> [% types = [
</span><del>-  { name =&gt; &quot;noop&quot;, description =&gt; &quot;---&quot; },
-  { name =&gt; &quot;equals&quot;, description =&gt; &quot;is equal to&quot; },
-  { name =&gt; &quot;notequals&quot;, description =&gt; &quot;is not equal to&quot; },
-  { name =&gt; &quot;anyexact&quot;, description =&gt; &quot;is equal to any of the strings&quot; },
-  { name =&gt; &quot;substring&quot;, description =&gt; &quot;contains the string&quot; },
-  { name =&gt; &quot;casesubstring&quot;, description =&gt; &quot;contains the string (exact case)&quot; },
-  { name =&gt; &quot;notsubstring&quot;, description =&gt; &quot;does not contain the string&quot; },
-  { name =&gt; &quot;anywordssubstr&quot;, description =&gt; &quot;contains any of the strings&quot; },
-  { name =&gt; &quot;allwordssubstr&quot;, description =&gt; &quot;contains all of the strings&quot; },
-  { name =&gt; &quot;nowordssubstr&quot;, description =&gt; &quot;contains none of the strings&quot; },
-  { name =&gt; &quot;regexp&quot;, description =&gt; &quot;contains regexp&quot; },
-  { name =&gt; &quot;notregexp&quot;, description =&gt; &quot;does not contain regexp&quot; },
-  { name =&gt; &quot;lessthan&quot;, description =&gt; &quot;is less than&quot; },
-  { name =&gt; &quot;greaterthan&quot;, description =&gt; &quot;is greater than&quot; },
-  { name =&gt; &quot;anywords&quot;, description =&gt; &quot;contains any of the words&quot; },
-  { name =&gt; &quot;allwords&quot;, description =&gt; &quot;contains all of the words&quot; },
-  { name =&gt; &quot;nowords&quot;, description =&gt; &quot;contains none of the words&quot; },
-  { name =&gt; &quot;changedbefore&quot;, description =&gt; &quot;changed before&quot; },
-  { name =&gt; &quot;changedafter&quot;, description =&gt; &quot;changed after&quot; },
-  { name =&gt; &quot;changedfrom&quot;, description =&gt; &quot;changed from&quot; },
-  { name =&gt; &quot;changedto&quot;, description =&gt; &quot;changed to&quot; },
-  { name =&gt; &quot;changedby&quot;, description =&gt; &quot;changed by&quot; },
-  { name =&gt; &quot;matches&quot;, description =&gt; &quot;matches&quot; } ] %]
</del><ins>+  &quot;noop&quot;,
+  &quot;equals&quot;,
+  &quot;notequals&quot;,
+  &quot;anyexact&quot;,
+  &quot;substring&quot;,
+  &quot;casesubstring&quot;,
+  &quot;notsubstring&quot;,
+  &quot;anywordssubstr&quot;,
+  &quot;allwordssubstr&quot;,
+  &quot;nowordssubstr&quot;,
+  &quot;regexp&quot;,
+  &quot;notregexp&quot;,
+  &quot;lessthan&quot;,
+  &quot;lessthaneq&quot;,
+  &quot;greaterthan&quot;,
+  &quot;greaterthaneq&quot;,
+  &quot;anywords&quot;,
+  &quot;allwords&quot;,
+  &quot;nowords&quot;,
+  &quot;changedbefore&quot;,
+  &quot;changedafter&quot;,
+  &quot;changedfrom&quot;,
+  &quot;changedto&quot;,
+  &quot;changedby&quot;,
+  &quot;matches&quot;,
+  &quot;notmatches&quot;,
+] %]
</ins><span class="cx"> 
</span><del>-  &lt;p&gt;
-    &lt;strong&gt;
-      &lt;a name=&quot;chart&quot;&gt;Advanced Searching Using Boolean Charts&lt;/a&gt;:
-    &lt;/strong&gt;
-  &lt;/p&gt;
</del><ins>+&lt;div class=&quot;bz_section_title&quot; id=&quot;custom_search_filter&quot;&gt;
+  &lt;div id=&quot;custom_search_query_controller&quot; class=&quot;arrow&quot;&gt;&amp;#9660;&lt;/div&gt;
+  &lt;a id=&quot;chart&quot; href=&quot;javascript:TUI_toggle_class('custom_search_query')&quot; &gt;
+    Custom Search&lt;/a&gt; &lt;span class=&quot;section_help&quot;&gt;Didn't find what 
+      you're looking for above? This area allows for ANDs, ORs, 
+      and other more complex searches.&lt;/span&gt;
+&lt;/div&gt;
+&lt;div id=&quot;custom_search_filter_section&quot; 
+     class=&quot;bz_search_section custom_search_query&quot;&gt;
+  [% SET indent_level = 0 %]
+  [% SET cond_num = 0 %]
+  [% FOREACH condition = default.custom_search %]
+    [% SET cond_num = loop.count - 1 %]
+    [% PROCESS one_condition with_buttons = 0 %]
+  [% END %]
+  [% PROCESS one_condition
+    with_buttons = 1
+    condition = { f =&gt; 'noop' }
+    cond_num = cond_num + 1 %]
+  &lt;script type=&quot;text/javascript&quot;&gt;
+    TUI_alternates['custom_search_query'] = '&amp;#9658;';
+    TUI_hide_default('custom_search_query');
+    TUI_alternates['custom_search_advanced'] = &quot;Show Advanced Features&quot;;
+    TUI_hide_default('custom_search_advanced');
+  &lt;/script&gt;
+  &lt;script type=&quot;text/javascript&quot; src=&quot;[% 'js/custom-search.js' FILTER mtime %]&quot;&gt;&lt;/script&gt;
+  &lt;script type=&quot;text/javascript&quot; src=&quot;[% 'js/history.js/native.history.js' FILTER mtime %]&quot;&gt;&lt;/script&gt;
+  &lt;script type=&quot;text/javascript&quot;&gt;
+    redirect_html4_browsers();
+  &lt;/script&gt;
+&lt;/div&gt;
</ins><span class="cx"> 
</span><del>-[%# Whoever wrote the original version of boolean charts had a seriously twisted mind %]
</del><span class="cx"> 
</span><del>-[% jsmagic = &quot;onclick=\&quot;this.form.action='query.cgi#chart'; this.form.method='POST'; return 1;\&quot;&quot; %]
</del><ins>+[% BLOCK one_condition %]
+  [%# Skip any conditions that don't have a field defined. %]
+  [% RETURN IF !condition.f %]
+  
+  [% IF !top_level_any_shown %]
+    [% INCLUDE any_all_select
+      name = &quot;j_top&quot; selected = default.j_top.0
+      with_advanced_link = 1 %]
+    [% top_level_any_shown = 1 %]
+  [% END %]
</ins><span class="cx"> 
</span><del>-[% FOREACH chart = default.charts %]
-  [% chartnum = loop.count - 1 %]
-  &lt;table&gt;
-    &lt;tr&gt;
-      &lt;td&gt;
-        &lt;input type=&quot;checkbox&quot; id=&quot;negate[% chartnum FILTER html %]&quot;
-             name=&quot;negate[% chartnum FILTER html %]&quot; value=&quot;1&quot;
-            [%+ &quot;checked&quot; IF chart.negate %]&gt;
-        &lt;label for=&quot;negate[% chartnum FILTER html %]&quot;&gt;
-          Not (negate this whole chart)
-        &lt;/label&gt;
-      &lt;/td&gt;
-    &lt;/tr&gt;
-  [% FOREACH row = chart.rows %]
-    [% rownum = loop.count - 1 %]
-    &lt;tr&gt;
-    [% FOREACH col = row %]
-      [% colnum = loop.count - 1 %]
-      &lt;td&gt;
-        &lt;select name=&quot;[% &quot;field${chartnum}-${rownum}-${colnum}&quot; %]&quot;&gt;
-          [% FOREACH field = fields %]
-            &lt;option value=&quot;[% field.name %]&quot; [% &quot;selected&quot; IF field.name == col.field %]&gt;
-              [% field_descs.${field.name} || field.description FILTER html %]
-            &lt;/option&gt;
-          [% END %]
-        &lt;/select&gt;
</del><ins>+  [% IF condition.f == &quot;CP&quot; %]
+    [% indent_level = indent_level - 1 %]
+  [% END %]
</ins><span class="cx"> 
</span><del>-        &lt;select name=&quot;[% &quot;type${chartnum}-${rownum}-${colnum}&quot; %]&quot;&gt;
-          [% FOREACH type = types %]
-            &lt;option value=&quot;[% type.name %]&quot;
-              [%- &quot; selected&quot; IF type.name == col.type %]&gt;[% type.description %]&lt;/option&gt;
-          [% END %]
-        &lt;/select&gt;
</del><ins>+  &lt;div class=&quot;custom_search_condition&quot;
+       [% ' style=&quot;margin-left: ' _ (indent_level * 2) _ 'em&quot;' IF indent_level %]
+       [% ' id=&quot;custom_search_last_row&quot;' IF with_buttons %]&gt;
+    
+    [% IF previous_condition.f == &quot;OP&quot; %]
+      [% INCLUDE any_all_select
+        name = &quot;j&quot; _ (cond_num - 1) 
+        selected = previous_condition.j %]
+    [% END %]
</ins><span class="cx"> 
</span><del>-        &lt;input name=&quot;[% &quot;value${chartnum}-${rownum}-${colnum}&quot; %]&quot; 
-               value=&quot;[% col.value FILTER html %]&quot;&gt; 
-      &lt;/td&gt;
-      
-      [% UNLESS loop.last %]
-        &lt;td align=&quot;center&quot;&gt; 
-          Or 
-        &lt;/td&gt;    
-      &lt;/tr&gt;
-      &lt;tr&gt;
-      [% ELSE %]
-        &lt;td&gt;
-          [% newor = colnum + 1 %]
-          &lt;input type=&quot;submit&quot; value=&quot;Or&quot; [% jsmagic %]
-                 name=&quot;cmd-add[% &quot;${chartnum}-${rownum}-${newor}&quot; %]&quot;
-                 id=&quot;cmd-add[% &quot;${chartnum}-${rownum}-${newor}&quot; %]&quot;&gt;
-        &lt;/td&gt;
-      [% END %]
-      
</del><ins>+    [% IF with_buttons %]
+      &lt;button id=&quot;op_button&quot; type=&quot;button&quot; class=&quot;custom_search_advanced&quot;
+              title=&quot;Start a new group of criteria, including this row&quot;
+              onclick=&quot;custom_search_open_paren()&quot;&gt;(&lt;/button&gt;
</ins><span class="cx">     [% END %]
</span><del>-    &lt;/tr&gt;
</del><ins>+
+    [% UNLESS condition.f == &quot;CP&quot; %]
+      [%# This only gets hidden via custom_search_advanced if it isn't set. %]
+      &lt;span id=&quot;custom_search_not_container_[% cond_num FILTER html %]&quot;
+            class=&quot;custom_search_not_container
+                   [%- ' custom_search_advanced' UNLESS condition.n %]&quot;
+            title=&quot;Search for the opposite of the criteria here&quot;&gt;
+        &lt;input type=&quot;checkbox&quot; id=&quot;n[% cond_num FILTER html %]&quot;
+               class=&quot;custom_search_form_field&quot;
+               name=&quot;n[% cond_num FILTER html %]&quot; value=&quot;1&quot;
+               onclick=&quot;custom_search_not_changed([% cond_num FILTER js %])&quot;
+               [% ' checked=&quot;checked&quot;' IF condition.n %]&gt;
+        &lt;label for=&quot;n[% cond_num FILTER html %]&quot;&gt;Not&lt;/label&gt;
+      &lt;/span&gt;
+    [% END %]
+
+    [% IF condition.f == &quot;OP&quot; %]
+      &lt;input type=&quot;hidden&quot; name=&quot;f[% cond_num FILTER html %]&quot;
+             id=&quot;f[% cond_num FILTER html %]&quot; value=&quot;OP&quot;&gt;
+      (
+      [% indent_level = indent_level + 1 %]
+    [% ELSIF condition.f == &quot;CP&quot; %]
+      &lt;input type=&quot;hidden&quot; name=&quot;f[% cond_num FILTER html %]&quot; value=&quot;CP&quot;&gt;
+      )
+    [% ELSE %]
+      &lt;select name=&quot;f[% cond_num FILTER html %]&quot; title=&quot;Field&quot;
+              id=&quot;f[% cond_num FILTER html %]&quot;
+              onchange=&quot;fix_query_string(this)&quot;
+              class=&quot;custom_search_form_field&quot;&gt;
+        [% FOREACH field = fields %]
+          &lt;option value=&quot;[% field.name FILTER html %]&quot;
+                  [%~ ' selected=&quot;selected&quot;' IF field.name == condition.f %]&gt;
+            [% field_descs.${field.name} || field.description FILTER html %]
+          &lt;/option&gt;
+        [% END %]
+      &lt;/select&gt;
</ins><span class="cx">     
</span><del>-    [% UNLESS loop.last %]
-    &lt;tr&gt;
-      &lt;td&gt;And&lt;/td&gt;
-    &lt;/tr&gt;    
-    [% ELSE %]
-    &lt;tr&gt;
-      &lt;td&gt;
-        [% newand = rownum + 1; newchart = chartnum + 1 %]
-        &lt;input type=&quot;submit&quot; value=&quot;And&quot; [% jsmagic %]
-               name=&quot;cmd-add[% &quot;${chartnum}-${newand}-0&quot; %]&quot;
-               id=&quot;cmd-add[% &quot;${chartnum}-${newand}-0&quot; %]&quot;&gt;
-        &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
-        &lt;input type=&quot;submit&quot; value=&quot;Add another boolean chart&quot; [% jsmagic %]
-               name=&quot;cmd-add[% newchart %]-0-0&quot;
-               id=&quot;cmd-add[% newchart %]-0-0&quot;&gt;
-        &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;
-      &lt;/td&gt;
-    &lt;/tr&gt;   
</del><ins>+      [% INCLUDE &quot;search/type-select.html.tmpl&quot;
+         name = &quot;o${cond_num}&quot;, class = &quot;custom_search_form_field&quot;
+         types = types, selected = condition.o %]
+    
+      &lt;input name=&quot;v[% cond_num FILTER html %]&quot; title=&quot;Value&quot;
+             class=&quot;custom_search_form_field&quot;
+             onchange=&quot;fix_query_string(this)&quot;
+             value=&quot;[% condition.v FILTER html %]&quot;&gt;
</ins><span class="cx">     [% END %]
</span><span class="cx">     
</span><del>-  [% END %]
-  &lt;/table&gt;
-  &lt;hr&gt;
</del><ins>+    [% IF with_buttons %]
+      &lt;button class=&quot;custom_search_add_button&quot; type=&quot;button&quot;
+              id=&quot;add_button&quot; title=&quot;Add a new row&quot;
+              onclick=&quot;custom_search_new_row()&quot;&gt;+&lt;/button&gt;
+      &lt;span id=&quot;cp_container&quot; [% ' class=&quot;bz_default_hidden&quot;' IF !indent_level %]&gt;
+        &lt;button id=&quot;cp_button&quot; type=&quot;button&quot;
+                title=&quot;End this group of criteria&quot;
+                onclick=&quot;custom_search_close_paren()&quot;&gt;)&lt;/button&gt;
+      &lt;/span&gt;
+    [% END %]
+  &lt;/div&gt;
+  
+  [% previous_condition = condition %]
</ins><span class="cx"> [% END %]
</span><ins>+
+[% BLOCK any_all_select %]
+  &lt;div class=&quot;any_all_select&quot;&gt;
+    &lt;select name=&quot;[% name FILTER html %]&quot; id=&quot;[% name FILTER html %]&quot;
+            onchange=&quot;fix_query_string(this)&quot;&gt;
+      &lt;option value=&quot;AND&quot;&gt;Match ALL of the following:&lt;/option&gt;
+      &lt;option value=&quot;OR&quot; [% ' selected=&quot;selected&quot;' IF selected == &quot;OR&quot; %]&gt;
+        Match ANY of the following:&lt;/option&gt;
+    &lt;/select&gt;
+    [% IF with_advanced_link %]
+      &lt;a id=&quot;custom_search_advanced_controller&quot;
+         href=&quot;javascript:TUI_toggle_class('custom_search_advanced')&quot;&gt;
+        Hide Advanced Features
+      &lt;/a&gt;
+    [% END %]
+  &lt;/div&gt;
+[% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultsearchfieldhtmltmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/search/field.html.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/search/field.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/search/field.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,142 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is Guy Pyrzak
+  # Portions created by the Initial Developer are Copyright (C) 2010 the
+  # Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s): Guy Pyrzak &lt;guy.pyrzak@gmail.com&gt;
+  #                 Reed Loden &lt;reed@reedloden.com&gt;
+  #
+  #%]
+[%# INTERFACE:
+  #   field: a Bugzilla::Field object
+  #   value: the value or values that should be used to prepopulate the field
+  #   accesskey: the access key used to access the field more quickly
+  #   onchange: js to run when the change event fires on the field
+  #   type_selected: used by the free text to indicate which type of text
+  #                  search was selected for a particular field
+  #%]
+  
+[% SWITCH field.type %]
+  [% CASE [ constants.FIELD_TYPE_FREETEXT,
+            constants.FIELD_TYPE_TEXTAREA, 
+            constants.FIELD_TYPE_UNKNOWN ] %]
+    [% INCLUDE &quot;bug/field-label.html.tmpl&quot;
+      field = field
+      tag_name = &quot;span&quot;
+      editable = 1
+    %]
+    [% INCLUDE &quot;search/type-select.html.tmpl&quot;
+       name = field.name _ &quot;_type&quot;,
+       types = types, 
+       selected = type_selected
+    %]    
+    &lt;input name=&quot;[% field.name FILTER html %]&quot; 
+           id=&quot;[% field.name FILTER html %]&quot; size=&quot;40&quot;
+           [% IF onchange %] onchange=&quot;[% onchange FILTER html %]&quot;[% END %]
+           value=&quot;[% value FILTER html %]&quot;&gt;              
+  [% CASE constants.FIELD_TYPE_KEYWORDS %]
+    [% INCLUDE &quot;bug/field-label.html.tmpl&quot;
+      field = field
+      tag_name = &quot;span&quot;
+      editable = 1
+    %]
+    [% INCLUDE &quot;search/type-select.html.tmpl&quot;
+       name = field.name _ &quot;_type&quot;,
+       types = types, 
+       selected = type_selected
+    %]
+    &lt;div id=&quot;keyword_container&quot;&gt;
+       &lt;input name=&quot;[% field.name FILTER html %]&quot; 
+              id=&quot;[% field.name FILTER html %]&quot; size=&quot;40&quot;
+              [% IF onchange %] onchange=&quot;[% onchange FILTER html %]&quot;[% END %]
+              value=&quot;[% value FILTER html %]&quot;&gt;
+       &lt;div id=&quot;keyword_autocomplete&quot;&gt;&lt;/div&gt;
+    &lt;/div&gt;
+    &lt;script type=&quot;text/javascript&quot; defer=&quot;defer&quot;&gt;
+      YAHOO.bugzilla.keyword_array = [
+        [%- FOREACH keyword = all_keywords %]
+          [%-# %]&quot;[% keyword.name FILTER js %]&quot;
+          [%- &quot;,&quot; IF NOT loop.last %][% END %]];
+      YAHOO.bugzilla.keywordAutocomplete.init('[% field.name FILTER js %]',
+                                              'keyword_autocomplete');
+    &lt;/script&gt;
+  [% CASE constants.FIELD_TYPE_DATETIME %]
+    [% INCLUDE &quot;bug/field-label.html.tmpl&quot;
+      field = field
+      tag_name = &quot;span&quot;
+      editable = 1
+    %]
+    from &lt;input name=&quot;[% field.name FILTER html %]from&quot; 
+                id=&quot;[% field.name FILTER html %]&quot; 
+                size=&quot;10&quot; maxlength=&quot;10&quot;
+                value=&quot;[% value.0 FILTER html %]&quot; 
+                onchange=&quot;updateCalendarFromField(this);[% onchange FILTER html %]&quot;&gt;
+         &lt;button type=&quot;button&quot; class=&quot;calendar_button&quot;
+                        id=&quot;button_calendar_[% field.name FILTER html %]&quot;
+                        onclick=&quot;showCalendar('[% field.name FILTER js %]')&quot;&gt;
+           &lt;span&gt;Calendar&lt;/span&gt;
+         &lt;/button&gt;
+         &lt;span id=&quot;con_calendar_[% field.name FILTER html %]&quot;&gt;&lt;/span&gt;               
+    to &lt;input name=&quot;[% field.name FILTER html %]to&quot; 
+              id=&quot;[% field.name FILTER html %]to&quot; size=&quot;10&quot; maxlength=&quot;10&quot;
+              value=&quot;[% value.1 FILTER html %]&quot; 
+              onchange=&quot;updateCalendarFromField(this);[% onchange FILTER html %]&quot;&gt;
+       &lt;button type=&quot;button&quot; class=&quot;calendar_button&quot;
+                      id=&quot;button_calendar_[% field.name FILTER html %]to&quot;
+                      onclick=&quot;showCalendar('[% field.name FILTER js %]to')&quot;&gt;
+         &lt;span&gt;Calendar&lt;/span&gt;
+       &lt;/button&gt;
+    &lt;small&gt;(YYYY-MM-DD or relative dates)&lt;/small&gt;
+    
+    &lt;span id=&quot;con_calendar_[% field.name FILTER html %]to&quot;&gt;&lt;/span&gt;
+    &lt;script type=&quot;text/javascript&quot;&gt;
+      createCalendar('[% field.name FILTER js %]');
+      createCalendar('[% field.name FILTER js %]to');
+    &lt;/script&gt;
+  [% CASE [ constants.FIELD_TYPE_SINGLE_SELECT, 
+            constants.FIELD_TYPE_MULTI_SELECT ] %]
+    &lt;div id=&quot;container_[% field.name FILTER html %]&quot; class=&quot;search_field_grid&quot;&gt;      
+      [% INCLUDE &quot;bug/field-label.html.tmpl&quot;
+        field = field
+        editable = 1
+        tag_name = &quot;span&quot;
+      %]
+      &lt;select name=&quot;[% field.name FILTER html%]&quot; 
+              id=&quot;[% field.name FILTER html %]&quot; 
+        [% IF onchange %] onchange=&quot;[% onchange FILTER html %]&quot;[% END %]
+        multiple=&quot;multiple&quot; size=&quot;7&quot;&gt;
+        [% legal_values = ${field.name} %]
+        [% IF field.name == &quot;component&quot; %]
+          [% legal_values = ${&quot;component_&quot;} %]
+        [% END %]
+        [% FOREACH current_value = legal_values %]
+          [% IF current_value.id %]
+            [%# current_value is a hash instead of a value which 
+                only applies for Resolution really, everywhere else current_value
+                is just the value %]
+            [% v = current_value.name OR '---' -%]
+            &lt;option value=&quot;[% v FILTER html %]&quot;
+              [% ' selected=&quot;selected&quot;' IF value.contains( v ) %]&gt;
+              [% display_value(field.name, current_value.name) FILTER html %]
+            &lt;/option&gt;
+          [% ELSE %]
+            &lt;option value=&quot;[% current_value OR '---' FILTER html %]&quot;
+              [% ' selected=&quot;selected&quot;' IF value.contains( current_value ) %]&gt;
+              [% display_value(field.name, current_value) FILTER html %]
+            &lt;/option&gt;
+          [% END %]
+        [% END %]
+      &lt;/select&gt;
+    &lt;/div&gt;
+  [% END %]
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultsearchformhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/search/form.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/search/form.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/search/form.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -18,8 +18,11 @@
</span><span class="cx">   # Contributor(s): Chris Lahey &lt;clahey@ximian.com&gt; [javascript fixes]
</span><span class="cx">   #                 Christian Reis &lt;kiko@async.com.br&gt; [javascript rewrite]
</span><span class="cx">   #                 Gervase Markham &lt;gerv@gerv.net&gt;
</span><ins>+  #                 Guy Pyrzak &lt;guy.pyrzak@gmail.com&gt;
</ins><span class="cx">   #%]
</span><span class="cx"> 
</span><ins>+[% PROCESS &quot;global/field-descs.none.tmpl&quot; %]
+
</ins><span class="cx"> &lt;script type=&quot;text/javascript&quot;&gt;
</span><span class="cx"> 
</span><span class="cx"> var first_load = true;         [%# is this the first time we load the page? %]
</span><span class="lines">@@ -101,414 +104,232 @@
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+// Hide the Advanced Fields by default, unless the user has a cookie
+// that specifies otherwise.
+// &amp;#9656; and &amp;#9662; are both utf8 escaped characters for right 
+//    and down facing arrows respectivly.
+TUI_alternates['history_query'] = '&amp;#9658;';
+TUI_alternates['people_query'] = '&amp;#9658;';
+TUI_alternates['information_query'] = '&amp;#9658;';
+
+TUI_hide_default('history_query');
+TUI_hide_default('people_query');
+TUI_hide_default('information_query');
</ins><span class="cx"> &lt;/script&gt;
</span><span class="cx"> 
</span><ins>+[% query_types = [
+  &quot;allwordssubstr&quot;,
+  &quot;anywordssubstr&quot;,
+  &quot;substring&quot;,
+  &quot;casesubstring&quot;,
+  &quot;allwords&quot;,
+  &quot;anywords&quot;,
+  &quot;regexp&quot;,
+  &quot;notregexp&quot;,
+] %]
</ins><span class="cx"> 
</span><del>-[% PROCESS global/variables.none.tmpl %]
-
-[% query_variants = [
-  { value =&gt; &quot;allwordssubstr&quot;, description =&gt; &quot;contains all of the words/strings&quot; },
-  { value =&gt; &quot;anywordssubstr&quot;, description =&gt; &quot;contains any of the words/strings&quot; },
-  { value =&gt; &quot;substring&quot;, description =&gt; &quot;contains the string&quot; },
-  { value =&gt; &quot;casesubstring&quot;, description =&gt; &quot;contains the string (exact case)&quot; },
-  { value =&gt; &quot;allwords&quot;, description =&gt; &quot;contains all of the words&quot; },
-  { value =&gt; &quot;anywords&quot;, description =&gt; &quot;contains any of the words&quot; },
-  { value =&gt; &quot;regexp&quot;, description =&gt; &quot;matches the regexp&quot; },
-  { value =&gt; &quot;notregexp&quot;, description =&gt; &quot;doesn't match the regexp&quot; } ] %]
-
-[% PROCESS &quot;global/field-descs.none.tmpl&quot; %]
-
</del><span class="cx"> [%# If we resubmit to ourselves, we need to know if we are using a format. %]
</span><span class="cx"> [% thisformat = query_format != '' ? query_format : format %]
</span><span class="cx"> &lt;input type=&quot;hidden&quot; name=&quot;query_format&quot; value=&quot;[% thisformat FILTER html %]&quot;&gt;
</span><span class="cx"> 
</span><span class="cx"> [%# *** Summary *** %]
</span><span class="cx"> 
</span><del>-&lt;table&gt;
-  &lt;tr&gt;
-    &lt;th align=&quot;right&quot;&gt;
-      &lt;label for=&quot;short_desc&quot; accesskey=&quot;s&quot;&gt;&lt;u&gt;S&lt;/u&gt;ummary&lt;/label&gt;:
-    &lt;/th&gt;
-    &lt;td&gt;
-      &lt;select name=&quot;short_desc_type&quot;&gt;
-      [% FOREACH qv = query_variants %]
-        &lt;option value=&quot;[% qv.value %]&quot;
-          [% &quot; selected&quot; IF default.short_desc_type.0 == qv.value %]&gt;[% qv.description %]&lt;/option&gt;
-      [% END %]
-      &lt;/select&gt;
-    &lt;/td&gt;
-    &lt;td&gt;
-      &lt;input name=&quot;short_desc&quot; id=&quot;short_desc&quot; size=&quot;40&quot;
-             value=&quot;[% default.short_desc.0 FILTER html %]&quot;&gt;
</del><ins>+  &lt;div class=&quot;search_field_row&quot; id=&quot;summary_field&quot;&gt;
+      [% INCLUDE &quot;search/field.html.tmpl&quot;
+         field = bug_fields.short_desc
+         types = query_types
+         value = default.short_desc.0
+         type_selected = default.short_desc_type.0 
+         accesskey = &quot;s&quot;
+         %]
</ins><span class="cx">       &lt;script type=&quot;text/javascript&quot;&gt; &lt;!--
</span><span class="cx">           document.forms[queryform].short_desc.focus(); 
</span><span class="cx">       // --&gt;
</span><span class="cx">       &lt;/script&gt;
</span><del>-    &lt;/td&gt;
-    &lt;td&gt;
</del><ins>+
</ins><span class="cx">       [% IF button_name %]
</span><span class="cx">         &lt;input type=&quot;submit&quot; id=&quot;[% button_name FILTER css_class_quote %]_top&quot;
</span><span class="cx">                value=&quot;[% button_name FILTER html %]&quot;&gt;
</span><span class="cx">       [% END %]
</span><del>-    &lt;/td&gt;
-  &lt;/tr&gt;
</del><ins>+  &lt;/div&gt;
</ins><span class="cx"> 
</span><del>-[%# *** Classification Product Component Version Target *** %]
-  &lt;tr&gt;
-    &lt;td colspan=&quot;4&quot;&gt;
-      &lt;table&gt;
-        &lt;tr&gt;
-        [% IF Param('useclassification') %]
-          &lt;td valign=&quot;top&quot;&gt;
-            &lt;table&gt;
-              &lt;tr valign=&quot;bottom&quot;&gt;
-                &lt;th align=&quot;left&quot;&gt;
-                  &lt;label for=&quot;classification&quot;&gt;Classification&lt;/label&gt;:
-                &lt;/th&gt;
-              &lt;/tr&gt;
-              &lt;tr valign=&quot;top&quot;&gt;
-                &lt;td align=&quot;left&quot;&gt;
-                  &lt;select name=&quot;classification&quot; multiple=&quot;multiple&quot; size=&quot;5&quot; id=&quot;classification&quot;
-                          onchange=&quot;doOnSelectProduct(1);&quot;&gt;
-                    [% FOREACH cat = classification %]
-                      &lt;option value=&quot;[% cat.name FILTER html %]&quot;
-                        [% &quot; selected&quot; IF lsearch(default.classification, cat.name) != -1 %]&gt;
-                        [% cat.name FILTER html %]
-                      &lt;/option&gt;
-                    [% END %]
-                  &lt;/select&gt;
-                &lt;/td&gt;
-              &lt;/tr&gt;
-            &lt;/table&gt;
-          &lt;/td&gt;
-        [% END %]
-          &lt;td valign=&quot;top&quot;&gt;
-            &lt;table&gt;
-              &lt;tr valign=&quot;bottom&quot;&gt;
-                &lt;th align=&quot;left&quot;&gt;
-                  &lt;label for=&quot;product&quot; accesskey=&quot;p&quot;&gt;&lt;u&gt;P&lt;/u&gt;roduct&lt;/label&gt;:
-                &lt;/th&gt;
-              &lt;/tr&gt;
-              &lt;tr valign=&quot;top&quot;&gt;
-                [%# Can't use the select block here because of the onChange %]
-                &lt;td align=&quot;left&quot;&gt;
-                  &lt;select name=&quot;product&quot; multiple=&quot;multiple&quot; size=&quot;5&quot; id=&quot;product&quot;
-                          onchange=&quot;doOnSelectProduct(2);&quot;&gt;
-                    [% FOREACH p = product %]
-                      [% IF p.components.size %]
-                      &lt;option value=&quot;[% p.name FILTER html %]&quot;
-                        [% &quot; selected&quot; IF lsearch(default.product, p.name) != -1 %]&gt;
-                        [% p.name FILTER html %]&lt;/option&gt;
-                      [% END %]
-                    [% END %]
-                  &lt;/select&gt;
-                &lt;/td&gt;
-              &lt;/tr&gt;
-            &lt;/table&gt;
-          &lt;/td&gt;
-          &lt;td valign=&quot;top&quot;&gt;
-            &lt;table&gt;
-              &lt;tr valign=&quot;bottom&quot;&gt;
-                &lt;th align=&quot;left&quot;&gt;
-                  &lt;label for=&quot;component&quot; accesskey=&quot;m&quot;&gt;&lt;a href=&quot;describecomponents.cgi&quot;&gt;Co&lt;u&gt;m&lt;/u&gt;ponent&lt;/a&gt;&lt;/label&gt;:
-                &lt;/th&gt;
-              &lt;/tr&gt;
-              &lt;tr valign=&quot;top&quot;&gt;
-                [%# Can't use the select block here because 'component' is a toolkit
-                    reserved word - we use 'component_' instead. %]
-                &lt;td align=&quot;left&quot;&gt;
-                  &lt;select name=&quot;component&quot; id=&quot;component&quot;
-                          multiple=&quot;multiple&quot; size=&quot;5&quot;&gt;
-                    [% FOREACH c = component_ %]
-                      &lt;option value=&quot;[% c FILTER html %]&quot;
-                        [% &quot; selected&quot; IF lsearch(default.component, c) != -1 %]&gt;
-                        [% c FILTER html %]&lt;/option&gt;
-                    [% END %]
-                  &lt;/select&gt;
-                &lt;/td&gt;
-              &lt;/tr&gt;
-            &lt;/table&gt;
-          &lt;/td&gt;
-          &lt;td valign=&quot;top&quot;&gt;
-            &lt;table&gt;
-              &lt;tr valign=&quot;bottom&quot;&gt;
-                &lt;th align=&quot;left&quot;&gt;
-                  &lt;label for=&quot;version&quot;&gt;Version&lt;/label&gt;:
-                &lt;/th&gt;
-              &lt;/tr&gt;
-              &lt;tr valign=&quot;top&quot;&gt;
-                [% PROCESS select sel = { name =&gt; 'version',
-                                          size =&gt; 5 } %]
-              &lt;/tr&gt;
-            &lt;/table&gt;
-          &lt;/td&gt;
-        [% IF Param('usetargetmilestone') %]
-          &lt;td valign=&quot;top&quot;&gt;
-            &lt;table&gt;
-              &lt;tr valign=&quot;bottom&quot;&gt;
-                &lt;th align=&quot;left&quot;&gt;
-                  &lt;label for=&quot;target_milestone&quot;&gt;Target&lt;/label&gt;:
-                &lt;/th&gt;
-              &lt;/tr&gt;
-              &lt;tr valign=&quot;top&quot;&gt;
-                [% PROCESS select sel = { name =&gt; 'target_milestone',
-                                          size =&gt; 5 } %]
-              &lt;/tr&gt;
-            &lt;/table&gt;
-          &lt;/td&gt;
-        [% END %]
-        &lt;/tr&gt;
-      &lt;/table&gt;
-    &lt;/td&gt;
-  &lt;/tr&gt;
</del><ins>+[%# *** Classification Product Component *** %]
+  
+[% Hook.process('before_selects_top') %]
+[% IF Param('useclassification') %]
+      [% fake_classfication = { name =&gt; bug_fields.classification.name,
+                                type =&gt; constants.FIELD_TYPE_SINGLE_SELECT } %]
+      [% INCLUDE &quot;search/field.html.tmpl&quot; 
+            field =&gt; fake_classfication
+            accesskey =&gt; &quot;c&quot;
+            onchange =&gt; &quot;doOnSelectProduct(1);&quot; 
+            value =&gt; default.classification
+      %]          
+[% END %]
</ins><span class="cx"> 
</span><del>-[%# *** Comment URL Whiteboard Keywords *** %]
</del><ins>+[% INCLUDE &quot;search/field.html.tmpl&quot; 
+      field =&gt; bug_fields.product
+      accesskey =&gt; &quot;p&quot;
+      onchange =&gt; &quot;doOnSelectProduct(2);&quot; 
+      value =&gt; default.product
+%]
+[% INCLUDE &quot;search/field.html.tmpl&quot; 
+      field =&gt; bug_fields.component
+      accesskey =&gt; &quot;m&quot;
+      value =&gt; default.component
+%]
+[% INCLUDE &quot;search/field.html.tmpl&quot; 
+      field =&gt; bug_fields.bug_status
+      accesskey =&gt; &quot;a&quot;
+      value =&gt; default.bug_status
+%]
+[% INCLUDE &quot;search/field.html.tmpl&quot; 
+      field =&gt; bug_fields.resolution
+      accesskey =&gt; &quot;r&quot; 
+      value =&gt; default.resolution
+%]
</ins><span class="cx"> 
</span><del>-  [% FOREACH field = [
-    { name =&gt; &quot;long_desc&quot;, description =&gt; &quot;A&amp;nbsp;&lt;u&gt;C&lt;/u&gt;omment&quot;,
-      accesskey =&gt; 'c' },
-    { name =&gt; &quot;bug_file_loc&quot;, description =&gt; &quot;The&amp;nbsp;&lt;u&gt;U&lt;/u&gt;RL&quot;,
-      accesskey =&gt; 'u' },
-    { name =&gt; &quot;status_whiteboard&quot;, description =&gt; &quot;&lt;u&gt;W&lt;/u&gt;hiteboard&quot;,
-      accesskey =&gt; 'w' } ] %]
</del><ins>+[% Hook.process('after_selects_top') %]
</ins><span class="cx"> 
</span><del>-    [% UNLESS field.name == 'status_whiteboard' AND NOT Param('usestatuswhiteboard') %]
-    &lt;tr&gt;
-      &lt;th align=&quot;right&quot;&gt;
-        &lt;label for=&quot;[% field.name %]&quot; accesskey=&quot;[% field.accesskey %]&quot;&gt;[% field.description %]&lt;/label&gt;:
-      &lt;/th&gt;
-      &lt;td&gt;
-        &lt;select name=&quot;[% field.name %]_type&quot;&gt;
-        [% FOREACH qv = query_variants %]
-          [% type = &quot;${field.name}_type&quot; %]
-          &lt;option value=&quot;[% qv.value %]&quot;
-            [% &quot; selected&quot; IF default.$type.0 == qv.value %]&gt;[% qv.description %]&lt;/option&gt;
-        [% END %]
-        &lt;/select&gt;
-      &lt;/td&gt;
-      &lt;td&gt;&lt;input name=&quot;[% field.name %]&quot; id=&quot;[% field.name %]&quot; size=&quot;40&quot;
-                 value=&quot;[% default.${field.name}.0 FILTER html %]&quot;&gt;
-      &lt;/td&gt;
-      &lt;td&gt;&lt;/td&gt;
-    &lt;/tr&gt;
-    [% END %]
</del><ins>+&lt;div id=&quot;detailed_information&quot; class=&quot;bz_section_title&quot;&gt;
+  &lt;div id=&quot;information_query_controller&quot; class=&quot;arrow&quot;&gt;&amp;#9660;&lt;/div&gt;
+  &lt;a href=&quot;javascript:TUI_toggle_class('information_query')&quot;&gt;
+    Detailed [% terms.Bug %] Information
+  &lt;/a&gt;
+  &lt;span class=&quot;section_help&quot;&gt;Narrow results by the following fields: 
+    [%+ field_descs.longdesc FILTER html %]s, [%+ field_descs.bug_file_loc FILTER html %], 
+    [% IF Param('usestatuswhiteboard') %] [%+ field_descs.status_whiteboard FILTER html %], [%+ END %]
+    [% IF use_keywords %] [%+ field_descs.keywords FILTER html %], [%+ END %]
+    [% IF user.is_timetracker %] [%+ field_descs.deadline FILTER html %], [%+ END %]
+    [% terms.Bug %] Numbers, [%+ field_descs.version FILTER html %], 
+    [% IF Param('usetargetmilestone') %] [%+ field_descs.target_milestone FILTER html %], [%+ END %]
+    [% field_descs.bug_severity FILTER html %], [%+ field_descs.priority FILTER html %], [%+ field_descs.rep_platform FILTER html %], 
+    [%+ field_descs.op_sys FILTER html %]
+  &lt;/span&gt;
+&lt;/div&gt;
+[%# *** Comment URL Whiteboard Keywords *** %]
+&lt;div id=&quot;detailed_information_section&quot; class=&quot;bz_search_section information_query&quot;&gt;
+  [% SET freetext_fields = [
+    { field =&gt; bug_fields.longdesc, accesskey =&gt; 'c' },
+    { field =&gt; bug_fields.bug_file_loc, accesskey =&gt; 'u' },
+    { field =&gt; bug_fields.status_whiteboard, accesskey =&gt; 'w' },
+    { field =&gt; bug_fields.keywords, accesskey =&gt; 'k', 
+      qtypes =&gt; ['allwords', 'anywords', 'nowords', 'regexp', 'notregexp'] }   
+  ] %]
+  [% Hook.process('before_freetext_fields') %]
+  
+  [%# loop through a bunch of free text fields and print out their text stuff %]
+  [% FOREACH field_container = freetext_fields %]
+    [% NEXT IF field_container.field.name == 'status_whiteboard' 
+               AND NOT Param('usestatuswhiteboard') 
+    %]
+    [% NEXT IF field_container.field.name == 'keywords' 
+               AND NOT use_keywords
+    %]
+    &lt;div class=&quot;search_field_row&quot;&gt;
+      [% type = field_container.field.name _ &quot;_type&quot; %]
+      [% INCLUDE &quot;search/field.html.tmpl&quot; 
+          field =&gt; field_container.field
+          types =&gt; field_container.qtypes || query_types
+          accesskey =&gt; field_container.accesskey
+          value =&gt; default.${field_container.field.name}.0
+          type_selected =&gt; default.$type.0
+      %]
+    &lt;/div&gt;
</ins><span class="cx">   [% END %]
</span><span class="cx"> 
</span><del>-  [% IF have_keywords %]
-    &lt;tr&gt;
-      &lt;th align=&quot;right&quot;&gt;
-        &lt;label for=&quot;keywords&quot; accesskey=&quot;k&quot;&gt;&lt;a href=&quot;describekeywords.cgi&quot;&gt;&lt;u&gt;K&lt;/u&gt;eywords&lt;/a&gt;&lt;/label&gt;:
-      &lt;/th&gt;
-      &lt;td&gt;
-        &lt;select name=&quot;keywords_type&quot;&gt;
-        [% FOREACH qv = [
-          { name =&gt; &quot;allwords&quot;, description =&gt; &quot;contains all of the keywords&quot; },
-          { name =&gt; &quot;anywords&quot;, description =&gt; &quot;contains any of the keywords&quot; },
-          { name =&gt; &quot;nowords&quot;,  description =&gt; &quot;contains none of the keywords&quot; } ] %]
-
-          &lt;option value=&quot;[% qv.name %]&quot;
-            [% &quot; selected&quot; IF default.keywords_type.0 == qv.name %]&gt;
-            [% qv.description %]&lt;/option&gt;
-        [% END %]
-        &lt;/select&gt;
-      &lt;/td&gt;
-      &lt;td&gt;
-        &lt;input name=&quot;keywords&quot; id=&quot;keywords&quot; size=&quot;40&quot;
-               value=&quot;[% default.keywords.0 FILTER html %]&quot;&gt;
-      &lt;/td&gt;
-    &lt;/tr&gt;
-  [% END %]
-
</del><span class="cx">   [%# Deadline %]
</span><del>-  [% IF user.in_group(Param(&quot;timetrackinggroup&quot;)) %]
-    &lt;tr&gt;
-      &lt;th align=&quot;right&quot;&gt;
-        &lt;label for=&quot;deadlinefrom&quot; accesskey=&quot;l&quot;&gt;Dead&lt;u&gt;l&lt;/u&gt;ine&lt;/label&gt;:
-      &lt;/th&gt;
-      &lt;td&gt;
-        from &lt;input name=&quot;deadlinefrom&quot; id=&quot;deadlinefrom&quot; size=&quot;10&quot; maxlength=&quot;10&quot;
-                    value=&quot;[% default.deadlinefrom.0 FILTER html %]&quot;&gt;
-        to &lt;input name=&quot;deadlineto&quot; size=&quot;10&quot; maxlength=&quot;10&quot;
-                  value=&quot;[% default.deadlineto.0 FILTER html %]&quot;&gt;
-      &lt;/td&gt;
-      &lt;td&gt;
-        &lt;small&gt;(YYYY-MM-DD)&lt;/small&gt;
-      &lt;/td&gt;
-    &lt;/tr&gt;
</del><ins>+  [% IF user.is_timetracker %]
+    &lt;div class=&quot;search_field_row&quot;&gt;
+        [% INCLUDE &quot;search/field.html.tmpl&quot; 
+                    field = bug_fields.deadline 
+                    accesskey = &quot;l&quot;
+                    value = [ default.deadlinefrom.0, default.deadlineto.0  ]
+        %]
+    &lt;/div&gt;
</ins><span class="cx">   [% END %]
</span><del>-  
-&lt;/table&gt;
</del><span class="cx"> 
</span><del>-&lt;hr&gt;
</del><ins>+  &lt;div class=&quot;search_field_row&quot;&gt;
+    &lt;span class=&quot;field_label&quot;&gt;&lt;label for=&quot;bug_id&quot;&gt;[% terms.Bugs %] numbered&lt;/label&gt;&lt;/span&gt;
+    &lt;div id=&quot;bug_id_container&quot; &gt;
+      &lt;input type=&quot;text&quot; name=&quot;bug_id&quot; id=&quot;bug_id&quot;
+           value=&quot;[% default.bug_id.0 FILTER html %]&quot; size=&quot;20&quot;&gt;
+           &lt;div class=&quot;field_help&quot;&gt;(comma-separated list)&lt;/div&gt;
+    &lt;/div&gt;
+    should be 
+    &lt;select name=&quot;bug_id_type&quot; id=&quot;bug_id_type&quot;&gt;
+      &lt;option value=&quot;anyexact&quot;[% &quot; selected&quot; IF default.bug_id_type.0 == &quot;anyexact&quot; %]&gt;only included in&lt;/option&gt;
+      &lt;option value=&quot;nowords&quot;[% &quot; selected&quot; IF default.bug_id_type.0 == &quot;nowords&quot; %]&gt;excluded from&lt;/option&gt;
+    &lt;/select&gt; the results
+  &lt;/div&gt;
</ins><span class="cx"> 
</span><del>-[%# *** Status Resolution Severity Priority Hardware OS *** %]
-
-&lt;table&gt;
-  &lt;tr&gt;
-    &lt;td&gt;
-      &lt;table&gt;
-        &lt;tr&gt;
-          &lt;th align=&quot;left&quot;&gt;
-            &lt;label for=&quot;bug_status&quot; accesskey=&quot;a&quot;&gt;St&lt;u&gt;a&lt;/u&gt;tus&lt;/label&gt;:
-          &lt;/th&gt;
-        &lt;/tr&gt;
-        &lt;tr valign=&quot;top&quot;&gt;
-          [% PROCESS select sel = { name =&gt; 'bug_status',
-                                    size =&gt; 7 } %]
-        &lt;/tr&gt;
-      &lt;/table&gt;
-    &lt;/td&gt;
-    &lt;td&gt;
-      &lt;table&gt;
-        &lt;tr&gt;
-          &lt;th align=&quot;left&quot;&gt;
-            &lt;label for=&quot;resolution&quot; accesskey=&quot;r&quot;&gt;&lt;u&gt;R&lt;/u&gt;esolution&lt;/label&gt;:
-          &lt;/th&gt;
-        &lt;/tr&gt;
-        &lt;tr valign=&quot;top&quot;&gt;
-          [% PROCESS select sel = { name =&gt; 'resolution',
-                                    size =&gt; 7 } %]
-        &lt;/tr&gt;
-      &lt;/table&gt;
-    &lt;/td&gt;
-    &lt;td&gt;
-      &lt;table&gt;
-        &lt;tr&gt;
-          &lt;th align=&quot;left&quot;&gt;
-            &lt;label for=&quot;bug_severity&quot;&gt;Severity&lt;/label&gt;:
-          &lt;/th&gt;
-        &lt;/tr&gt;
-        &lt;tr valign=&quot;top&quot;&gt;
-          [% PROCESS select sel = { name =&gt; 'bug_severity',
-                                    size =&gt; 7 }%]
-        &lt;/tr&gt;
-      &lt;/table&gt;
-    &lt;/td&gt;
-    &lt;td&gt;
-      &lt;table&gt;
-        &lt;tr&gt;
-          &lt;th align=&quot;left&quot;&gt;
-            &lt;label for=&quot;priority&quot; accesskey=&quot;i&quot;&gt;Pr&lt;u&gt;i&lt;/u&gt;ority&lt;/label&gt;:
-          &lt;/th&gt;
-        &lt;/tr&gt;
-        &lt;tr valign=&quot;top&quot;&gt;
-          [% PROCESS select sel = { name =&gt; 'priority',
-                                    size =&gt; 7 } %]
-        &lt;/tr&gt;
-      &lt;/table&gt;
-    &lt;/td&gt;
-    &lt;td&gt;
-      &lt;table&gt;
-        &lt;tr&gt;
-          &lt;th align=&quot;left&quot;&gt;
-            &lt;label for=&quot;rep_platform&quot; accesskey=&quot;h&quot;&gt;&lt;u&gt;H&lt;/u&gt;ardware&lt;/label&gt;:
-          &lt;/th&gt;
-        &lt;/tr&gt;
-        &lt;tr valign=&quot;top&quot;&gt;
-          [% PROCESS select sel = { name =&gt; 'rep_platform',
-                                    size =&gt; 7 } %]
-        &lt;/tr&gt;
-      &lt;/table&gt;
-    &lt;/td&gt;
-    &lt;td&gt;
-      &lt;table&gt;
-        &lt;tr&gt;
-          &lt;th align=&quot;left&quot;&gt;
-            &lt;label for=&quot;op_sys&quot; accesskey=&quot;o&quot;&gt;&lt;u&gt;O&lt;/u&gt;S&lt;/label&gt;:
-          &lt;/th&gt;
-        &lt;/tr&gt;
-        &lt;tr valign=&quot;top&quot;&gt;
-          [% PROCESS select sel = { name =&gt; 'op_sys',
-                                    size =&gt; 7 } %]
-        &lt;/tr&gt;
-      &lt;/table&gt;
-    &lt;/td&gt;
-  &lt;/tr&gt;
-&lt;/table&gt;
-
-[%# *** Email Numbering Votes *** %]
-
-&lt;table&gt;
-  &lt;tr&gt;
-    &lt;td&gt;
-      &lt;fieldset&gt;
-        &lt;legend&gt;
-          &lt;strong&gt;
-            [% IF Param('usevotes') %]
-              Email Addresses, [% terms.Bug %] Numbers, and Votes
-            [% ELSE %]
-              Email Addresses and [% terms.Bug %] Numbers
-            [% END %]
-          &lt;/strong&gt;
-        &lt;/legend&gt;
-
-
-&lt;table&gt;
-  &lt;tr&gt;
-  [% FOREACH n = [1, 2] %]
-    &lt;td&gt;
-
-
-&lt;table cellspacing=&quot;0&quot; cellpadding=&quot;0&quot;&gt;
-  &lt;tr&gt;
-    &lt;td&gt;
</del><ins>+  [% Hook.process('after_freetext_fields') %]
+  
+  [%# *** Status Resolution Severity Priority Hardware OS *** %]
+  &lt;div&gt;
+    [% Hook.process('before_selects_bottom') %]
+    [% fake_version_field = { name =&gt; bug_fields.version.name,
+                              type =&gt; constants.FIELD_TYPE_SINGLE_SELECT }%]
+    [% INCLUDE &quot;search/field.html.tmpl&quot; 
+          field =&gt; fake_version_field
+          value =&gt; default.version
+    %]                              
+    [% IF Param('usetargetmilestone') %]
+        [% fake_target_milestone_field = { name =&gt; bug_fields.target_milestone.name , 
+                                           type =&gt; constants.FIELD_TYPE_SINGLE_SELECT } %]
+        [% INCLUDE &quot;search/field.html.tmpl&quot; 
+              field =&gt; fake_target_milestone_field
+              value =&gt; default.target_milestone
+        %]
+    [% END %]
+    [% INCLUDE &quot;search/field.html.tmpl&quot; 
+          field =&gt; bug_fields.bug_severity
+          accesskey=&gt; &quot;v&quot; 
+          value =&gt; default.bug_severity
+    %]
+    [% INCLUDE &quot;search/field.html.tmpl&quot; 
+         field =&gt; bug_fields.priority
+         accesskey =&gt; &quot;i&quot;
+         value =&gt; default.priority
+    %]    
+    [% INCLUDE &quot;search/field.html.tmpl&quot; 
+        field =&gt; bug_fields.rep_platform 
+        accesskey =&gt;&quot;h&quot;
+        value =&gt; default.rep_platform
+    %]               
+    [% INCLUDE &quot;search/field.html.tmpl&quot; 
+        field =&gt; bug_fields.op_sys 
+        accesskey =&gt;&quot;o&quot;
+        value =&gt; default.op_sys
+    %]               
+    [% Hook.process('after_selects_bottom') %]
+  &lt;/div&gt;
+&lt;/div&gt;
+[%# *** Email Numbering *** %]
+  &lt;div class=&quot;bz_section_title&quot; id=&quot;people_filter&quot;&gt;
+    &lt;div id=&quot;people_query_controller&quot; class=&quot;arrow&quot;&gt;&amp;#9660;&lt;/div&gt;
+    &lt;a href=&quot;javascript:TUI_toggle_class('people_query')&quot;&gt;Search By People&lt;/a&gt;
+    &lt;span&gt;Narrow results to a role (i.e. [% field_descs.assigned_to FILTER html %],
+      [%+ field_descs.reporter FILTER html %], [% field_descs.commenter FILTER html %],
+      etc.) a person has on [% terms.abug %]
+    &lt;/span&gt;
+  &lt;/div&gt;
+  &lt;div id=&quot;people_filter_section&quot; class=&quot;bz_search_section people_query&quot;&gt;
+  [% FOREACH n = [1, 2, 3] %]
+    &lt;div class=&quot;search_email_fields&quot;&gt;
</ins><span class="cx">       Any of:
</span><del>-    &lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td&gt;
-      &lt;input type=&quot;checkbox&quot; name=&quot;emailassigned_to[% n %]&quot;
-             id=&quot;emailassigned_to[% n %]&quot; value=&quot;1&quot;
-             [% &quot; checked&quot; IF default.emailassigned_to.$n %]&gt;
-      &lt;label for=&quot;emailassigned_to[% n %]&quot;&gt;
-        the [% terms.bug %] assignee
-      &lt;/label&gt;
-    &lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td&gt;
-      &lt;input type=&quot;checkbox&quot; name=&quot;emailreporter[% n %]&quot;
-             id=&quot;emailreporter[% n %]&quot; value=&quot;1&quot;
-             [% &quot; checked&quot; IF default.emailreporter.$n %]&gt;
-      &lt;label for=&quot;emailreporter[% n %]&quot;&gt;
-        the reporter
-      &lt;/label&gt;
-    &lt;/td&gt;
-  &lt;/tr&gt;
-  [% IF Param('useqacontact') %]
-  &lt;tr&gt;
-    &lt;td&gt;
-      &lt;input type=&quot;checkbox&quot; name=&quot;emailqa_contact[% n %]&quot;
-             id=&quot;emailqa_contact[% n %]&quot; value=&quot;1&quot;
-             [% &quot; checked&quot; IF default.emailqa_contact.$n %]&gt;
-      &lt;label for=&quot;emailqa_contact[% n %]&quot;&gt;
-        the QA contact
-      &lt;/label&gt;
-    &lt;/td&gt;
-  &lt;/tr&gt;
-  [% END %]
-  &lt;tr&gt;
-    &lt;td&gt;
-      &lt;input type=&quot;checkbox&quot; name=&quot;emailcc[% n %]&quot;
-             id=&quot;emailcc[% n %]&quot; value=&quot;1&quot;
-             [% &quot; checked&quot; IF default.emailcc.$n %]&gt;
-      &lt;label for=&quot;emailcc[% n %]&quot;&gt;
-        a CC list member
-      &lt;/label&gt;
-    &lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td&gt;
-        &lt;input type=&quot;checkbox&quot; name=&quot;emaillongdesc[% n %]&quot;
-               id=&quot;emaillongdesc[% n %]&quot; value=&quot;1&quot;
-               [% &quot; checked&quot; IF default.emaillongdesc.$n %]&gt;
-      &lt;label for=&quot;emaillongdesc[% n %]&quot;&gt;
-        a commenter
-      &lt;/label&gt;
-    &lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td&gt;
</del><ins>+      [% PROCESS role_types field = { count =&gt; n, name =&gt; &quot;emailassigned_to&quot;,
+                  label=&gt; &quot;the ${terms.Bug} ${field_descs.assigned_to}&quot; } %]
+      [% PROCESS role_types field = { count =&gt; n, name =&gt; &quot;emailreporter&quot;,
+                  label=&gt; &quot;the ${field_descs.reporter}&quot; } %]    
+      [% IF Param('useqacontact') %]
+          [% PROCESS role_types field = { count =&gt; n, name =&gt; &quot;emailqa_contact&quot;, 
+                  label=&gt; &quot;the ${field_descs.qa_contact}&quot; } %]
+      [% END %]
+      [% PROCESS role_types field = { count =&gt; n, name =&gt; &quot;emailcc&quot;, 
+                  label=&gt; &quot;a ${field_descs.cc} list member&quot; } %]
+      [% PROCESS role_types field = { count =&gt; n, name =&gt; &quot;emaillongdesc&quot;, 
+                  label=&gt; &quot; a ${field_descs.commenter}&quot; } %]
</ins><span class="cx">       &lt;select name=&quot;emailtype[% n %]&quot;&gt;
</span><span class="cx">       [% FOREACH qv = [
</span><span class="cx">         { name =&gt; &quot;substring&quot;, description =&gt; &quot;contains&quot; },
</span><span class="lines">@@ -516,129 +337,88 @@
</span><span class="cx">         { name =&gt; &quot;notequals&quot;, description =&gt; &quot;is not&quot; },
</span><span class="cx">         { name =&gt; &quot;regexp&quot;, description =&gt; &quot;matches regexp&quot; },
</span><span class="cx">         { name =&gt; &quot;notregexp&quot;, description =&gt; &quot;doesn't match regexp&quot; } ] %]
</span><del>-
</del><span class="cx">         &lt;option value=&quot;[% qv.name %]&quot;
</span><span class="cx">           [% &quot; selected&quot; IF default.emailtype.$n == qv.name %]&gt;[% qv.description %]&lt;/option&gt;
</span><span class="cx">       [% END %]
</span><span class="cx">       &lt;/select&gt;
</span><del>-    &lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td&gt;
-      &lt;input name=&quot;email[% n %]&quot; size=&quot;25&quot; value=&quot;[% default.email.$n FILTER html %]&quot;&gt;
-    &lt;/td&gt;
-  &lt;/tr&gt;
-&lt;/table&gt;
-
-
-    &lt;/td&gt;
</del><ins>+      [% IF feature_enabled('jsonrpc') %]
+        &lt;div id=&quot;email[% n %]_autocomplete&quot;&gt;
+      [% END %]
+      &lt;input name=&quot;email[% n %]&quot; class=&quot;email&quot; id=&quot;email[% n %]&quot; 
+             value=&quot;[% default.email.$n FILTER html %]&quot;&gt;
+      [% IF feature_enabled('jsonrpc') %]
+        &lt;div id=&quot;email[% n %]_autocomplete_container&quot;&gt;&lt;/div&gt;
+        &lt;/div&gt;
+        &lt;script type=&quot;text/javascript&quot;&gt;
+          YAHOO.bugzilla.userAutocomplete.init( &quot;email[% n %]&quot;, 
+                    &quot;email[% n %]_autocomplete_container&quot;);
+        &lt;/script&gt;
+      [% END %]
+    &lt;/div&gt;
</ins><span class="cx">   [% END %]
</span><del>-  &lt;/tr&gt;
-&lt;/table&gt;
-&lt;hr&gt;
-&lt;table&gt;
-  &lt;tr&gt;
-    &lt;td&gt;
-      &lt;select name=&quot;bugidtype&quot;&gt;
-        &lt;option value=&quot;include&quot;[% &quot; selected&quot; IF default.bugidtype.0 == &quot;include&quot; %]&gt;Only include&lt;/option&gt;
-        &lt;option value=&quot;exclude&quot;[% &quot; selected&quot; IF default.bugidtype.0 == &quot;exclude&quot; %]&gt;Exclude&lt;/option&gt;
-      &lt;/select&gt;
-      &lt;label for=&quot;bug_id&quot;&gt;[% terms.bugs %] numbered&lt;/label&gt;:
-    &lt;/td&gt;
-    &lt;td&gt;
-      &lt;input type=&quot;text&quot; name=&quot;bug_id&quot; id=&quot;bug_id&quot;
-             value=&quot;[% default.bug_id.0 FILTER html %]&quot; size=&quot;20&quot;&gt;
-    &lt;/td&gt;
-  &lt;/tr&gt;
-  &lt;tr&gt;
-    &lt;td&gt;&lt;/td&gt;
-    &lt;td&gt;(comma-separated list)&lt;/td&gt;
-  &lt;/tr&gt;
-  [% IF Param('usevotes') %]
-    &lt;tr&gt;
-      &lt;td align=&quot;right&quot;&gt;
-        &lt;label for=&quot;votes&quot;&gt;Only [% terms.bugs %] with at least&lt;/label&gt;:
-      &lt;/td&gt;
-      &lt;td&gt;
-        &lt;input name=&quot;votes&quot; id=&quot;votes&quot; size=&quot;3&quot;
-               value=&quot;[% default.votes.0 FILTER html %]&quot;&gt;
-        votes
-      &lt;/td&gt;
-    &lt;/tr&gt;
-  [% END %]
-&lt;/table&gt;
-
-
-      &lt;/fieldset&gt;
-    &lt;/td&gt;
-   
</del><ins>+   [% Hook.process('email_numbering_end') %]
+   &lt;/div&gt;
</ins><span class="cx"> [%# *** Bug Changes *** %]
</span><del>-
-    &lt;td valign=&quot;top&quot;&gt;
-      &lt;fieldset&gt;
-        &lt;legend&gt;&lt;strong&gt;[% terms.Bug %] Changes&lt;/strong&gt;&lt;/legend&gt;
-
-
-&lt;dl class=&quot;bug_changes&quot;&gt;
-  &lt;dt&gt;
-    &lt;label for=&quot;chfieldfrom&quot;&gt;Only [% terms.bugs %] changed between&lt;/label&gt;:
-  &lt;/dt&gt;
-  &lt;dd&gt;
-    &lt;input name=&quot;chfieldfrom&quot; id=&quot;chfieldfrom&quot;
-           size=&quot;10&quot; value=&quot;[% default.chfieldfrom.0 FILTER html %]&quot;&gt;
-    and &lt;input name=&quot;chfieldto&quot; size=&quot;10&quot; value=&quot;[% default.chfieldto.0 FILTER html %]&quot;&gt;
-    &lt;br&gt;(YYYY-MM-DD or relative dates)
-  &lt;/dd&gt;
-  &lt;dt&gt;
-    &lt;label for=&quot;chfield&quot;&gt;where one or more of the following changed&lt;/label&gt;:
-  &lt;/dt&gt;
-  &lt;dd&gt;
</del><ins>+&lt;div class=&quot;bz_section_title&quot; id=&quot;history_filter&quot;&gt;
+  &lt;div id=&quot;history_query_controller&quot; class=&quot;arrow&quot;&gt;&amp;#9660;&lt;/div&gt;
+  &lt;a href=&quot;javascript:TUI_toggle_class('history_query')&quot; &gt;Search By Change History&lt;/a&gt;
+  &lt;span&gt;Narrow results to how fields have changed during a specific time period&lt;/span&gt;
+&lt;/div&gt;
+&lt;ul class=&quot;bug_changes bz_search_section history_query&quot; id=&quot;history_filter_section&quot; &gt;
+  &lt;li&gt;
+    &lt;label for=&quot;chfield&quot;&gt;where ANY of the fields:&lt;/label&gt;
</ins><span class="cx">     [%# Create array, so we can sort it by description #%]
</span><span class="cx">     [% chfields = [] %]
</span><span class="cx">     [% FOREACH field = chfield %]
</span><span class="cx">       [% chfields.push({value =&gt; field, desc =&gt; (field_descs.$field || field) }) %]
</span><span class="cx">     [% END %]
</span><del>-
</del><span class="cx">     &lt;select name=&quot;chfield&quot; id=&quot;chfield&quot; multiple=&quot;multiple&quot; size=&quot;4&quot;&gt;
</span><span class="cx">     [% FOREACH field = chfields.sort('desc') %]
</span><span class="cx">       &lt;option value=&quot;[% field.value FILTER html %]&quot;
</span><del>-        [% &quot; selected&quot; IF lsearch(default.chfield, field.value) != -1 %]&gt;
</del><ins>+        [% &quot; selected&quot; IF default.chfield.contains(field.value) %]&gt;
</ins><span class="cx">         [% field.desc FILTER html %]&lt;/option&gt;
</span><span class="cx">     [% END %]
</span><span class="cx">     &lt;/select&gt;
</span><del>-  &lt;/dd&gt;
-  &lt;dt&gt;and &lt;label for=&quot;chfieldvalue&quot;&gt;the new value was&lt;/label&gt;:&lt;/dt&gt;
-  &lt;dd&gt;
</del><ins>+  &lt;/li&gt;
+  &lt;li&gt;
+    &lt;label for=&quot;chfieldvalue&quot;&gt;[% search_descs.changedto FILTER html %]:&lt;/label&gt;
</ins><span class="cx">     &lt;input name=&quot;chfieldvalue&quot; id=&quot;chfieldvalue&quot;
</span><span class="cx">            size=&quot;20&quot; value=&quot;[% default.chfieldvalue.0 FILTER html %]&quot;&gt;
</span><del>-  &lt;/dd&gt;
-&lt;/dl&gt;
</del><ins>+  &lt;/li&gt;
+  &lt;li&gt;
+    &lt;label for=&quot;chfieldfrom&quot;&gt;between:&lt;/label&gt;
+    &lt;input name=&quot;chfieldfrom&quot; id=&quot;chfieldfrom&quot; size=&quot;10&quot; 
+           value=&quot;[% default.chfieldfrom.0 FILTER html %]&quot; onchange=&quot;updateCalendarFromField(this)&quot;&gt; 
+           &lt;button type=&quot;button&quot; class=&quot;calendar_button&quot;
+                          id=&quot;button_calendar_chfieldfrom&quot;
+                          onclick=&quot;showCalendar('chfieldfrom')&quot;&gt;&lt;span&gt;Calendar&lt;/span&gt;&lt;/button&gt;
+           and 
+           &lt;div id=&quot;con_calendar_chfieldfrom&quot;&gt;&lt;/div&gt;
+          &lt;input name=&quot;chfieldto&quot; size=&quot;10&quot; id=&quot;chfieldto&quot; 
+                 value=&quot;[% default.chfieldto.0 || &quot;Now&quot; FILTER html %]&quot; 
+                 onchange=&quot;updateCalendarFromField(this)&quot;&gt;
+          &lt;button type=&quot;button&quot; class=&quot;calendar_button&quot;
+                         id=&quot;button_calendar_chfieldto&quot;
+                         onclick=&quot;showCalendar('chfieldto')&quot;&gt;&lt;span&gt;Calendar&lt;/span&gt;&lt;/button&gt;
+          &lt;div id=&quot;con_calendar_chfieldto&quot;&gt;&lt;/div&gt;
+    (YYYY-MM-DD or relative dates)
+    &lt;script type=&quot;text/javascript&quot;&gt;
+      createCalendar('chfieldfrom');
+      createCalendar('chfieldto');
+    &lt;/script&gt;
+  &lt;/li&gt;    
+&lt;/ul&gt;
</ins><span class="cx"> 
</span><del>-       &lt;/fieldset&gt;
-     &lt;/td&gt;
-  &lt;/tr&gt;
-&lt;/table&gt;
-
</del><span class="cx"> [%############################################################################%]
</span><del>-[%# Block for SELECT fields                                                  #%]
</del><ins>+[%# Block for email role type use to select which email to search through    #%]
</ins><span class="cx"> [%############################################################################%]
</span><del>-
-[% BLOCK select %]
-  &lt;td align=&quot;left&quot;&gt;
-    &lt;select name=&quot;[% sel.name %]&quot; id=&quot;[% sel.name %]&quot;
-            multiple=&quot;multiple&quot; size=&quot;[% sel.size %]&quot;&gt;
-      [% FOREACH name = ${sel.name} %]
-        &lt;option value=&quot;[% name FILTER html %]&quot;
-          [% &quot; selected&quot; IF lsearch(default.${sel.name}, name) != -1 %]&gt;
-          [% IF sel.name == &quot;bug_status&quot; %]
-            [% get_status(name) FILTER html %]
-          [% ELSIF sel.name == &quot;resolution&quot; %]
-            [% get_resolution(name) FILTER html %]
-          [% ELSE %]
-            [% name FILTER html %]
-          [% END %]
-        &lt;/option&gt;
-      [% END %]
-    &lt;/select&gt;
-  &lt;/td&gt;
</del><ins>+[% BLOCK role_types %]
+  &lt;div class=&quot;role_type&quot;&gt;
+    &lt;input type=&quot;checkbox&quot; name=&quot;[% field.name _ field.count FILTER html %]&quot;
+           id=&quot;[% field.name _ field.count FILTER html %]&quot; value=&quot;1&quot;
+           [% &quot; checked&quot; IF default.${field.name}.${field.count} %]&gt;
+    &lt;label for=&quot;[% field.name _ field.count FILTER html%]&quot;&gt;
+      [% field.label FILTER html%]
+    &lt;/label&gt;
+  &lt;/div&gt;
</ins><span class="cx"> [% END %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultsearchknobhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/search/knob.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/search/knob.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/search/knob.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -62,6 +62,10 @@
</span><span class="cx">     [%# The name of the existing query will be passed to buglist.cgi. %]
</span><span class="cx">     &lt;input type=&quot;hidden&quot; name=&quot;query_based_on&quot; value=&quot;[% known_name FILTER html %]&quot;&gt;
</span><span class="cx">   [% END %]
</span><ins>+  [%# Preserve any custom column list that might be set. %]
+  [% IF columnlist %]
+    &lt;input type=&quot;hidden&quot; name=&quot;columnlist&quot; value=&quot;[% columnlist FILTER html %]&quot;&gt;
+  [% END %]
</ins><span class="cx"> &lt;/p&gt;
</span><span class="cx"> 
</span><span class="cx"> &lt;p&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultsearchsearchadvancedhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/search/search-advanced.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/search/search-advanced.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/search/search-advanced.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -36,10 +36,11 @@
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/header.html.tmpl
</span><span class="cx">   title = &quot;Search for $terms.bugs&quot;
</span><del>-  onload = &quot;doOnSelectProduct(0); enableHelp();&quot;
</del><ins>+  onload = &quot;doOnSelectProduct(0);&quot;
</ins><span class="cx">   javascript = js_data
</span><del>-  javascript_urls = [ &quot;js/productform.js&quot; &quot;js/util.js&quot; &quot;js/help.js&quot; ]
-  style_urls = [ &quot;skins/standard/help.css&quot; ]
</del><ins>+  yui = [ 'autocomplete', 'calendar' ]
+  javascript_urls = [ &quot;js/productform.js&quot;, &quot;js/util.js&quot;, &quot;js/TUI.js&quot;, &quot;js/field.js&quot;]
+  style_urls = [ &quot;skins/standard/search_form.css&quot; ]
</ins><span class="cx">   doc_section = &quot;query.html&quot;
</span><span class="cx">   style = &quot;dl.bug_changes dt {
</span><span class="cx">              margin-top: 15px;
</span><span class="lines">@@ -50,30 +51,16 @@
</span><span class="cx"> 
</span><span class="cx"> [% button_name = &quot;Search&quot; %]
</span><span class="cx"> 
</span><del>-[%# The decent help requires Javascript %]
-&lt;script type=&quot;text/javascript&quot;&gt; &lt;!--
-[% IF NOT cgi.param(&quot;help&quot;) %]
-  document.write(&quot;&lt;p&gt;&lt;a href='query.cgi?help=1&amp;amp;format=advanced'&gt;Give me some help&lt;\/a&gt; (reloads page).&lt;\/p&gt;&quot;);
-[% ELSE %]
-  [% PROCESS &quot;search/search-help.html.tmpl&quot; %]
-  if (generateHelp())
-    document.write(&quot;&lt;p&gt;For help, mouse over the page elements.&lt;\/p&gt;&quot;);
-  else
-    document.write(&quot;&lt;p&gt;Help initialization failed, no help available.&lt;\/p&gt;&quot;);
-[% END %]
-// --&gt;
-&lt;/script&gt;
</del><ins>+&lt;p id=&quot;search_help&quot;&gt;Hover your mouse over each field label to get help for that field.&lt;/p&gt;
</ins><span class="cx"> 
</span><del>-&lt;form method=&quot;get&quot; action=&quot;buglist.cgi&quot; name=&quot;queryform&quot;&gt;
</del><ins>+&lt;form method=&quot;post&quot; action=&quot;buglist.cgi&quot; name=&quot;queryform&quot; id=&quot;queryform&quot;&gt;
</ins><span class="cx"> 
</span><span class="cx"> [% PROCESS search/form.html.tmpl %]
</span><span class="cx"> 
</span><del>-[% PROCESS search/knob.html.tmpl %]
-
-&lt;hr&gt;
-
</del><span class="cx"> [% PROCESS &quot;search/boolean-charts.html.tmpl&quot; %]
</span><span class="cx"> 
</span><ins>+[% PROCESS search/knob.html.tmpl %]
+
</ins><span class="cx"> &lt;/form&gt;
</span><span class="cx"> 
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultsearchsearchcreateserieshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/search/search-create-series.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/search/search-create-series.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/search/search-create-series.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -33,8 +33,10 @@
</span><span class="cx"> [% PROCESS global/header.html.tmpl 
</span><span class="cx">   title = &quot;Create New Data Set&quot;
</span><span class="cx">   onload = &quot;doOnSelectProduct(0);&quot;
</span><ins>+  yui = [ 'autocomplete', 'calendar' ]
</ins><span class="cx">   javascript = js_data 
</span><del>-  javascript_urls = [ &quot;js/productform.js&quot; ]
</del><ins>+  javascript_urls = [ &quot;js/util.js&quot;, &quot;js/productform.js&quot;, &quot;js/TUI.js&quot;, &quot;js/field.js&quot; ]
+  style_urls = [ &quot;skins/standard/search_form.css&quot; ]
</ins><span class="cx">   doc_section = &quot;reporting.html#charts-new-series&quot;
</span><span class="cx"> %]
</span><span class="cx"> 
</span><span class="lines">@@ -43,7 +45,7 @@
</span><span class="cx"> [% PROCESS search/form.html.tmpl %]
</span><span class="cx"> 
</span><span class="cx"> &lt;p&gt;
</span><del>-  &lt;input type=&quot;submit&quot; name=&quot;action-search&quot; value=&quot;Run Search&quot;&gt;
</del><ins>+  &lt;input type=&quot;submit&quot; id=&quot;action-search&quot; name=&quot;action-search&quot; value=&quot;Run Search&quot;&gt;
</ins><span class="cx">   to see which [% terms.bugs %] would be included in this data set.
</span><span class="cx"> &lt;/p&gt;
</span><span class="cx">     
</span><span class="lines">@@ -52,6 +54,7 @@
</span><span class="cx"> [% PROCESS reports/series.html.tmpl 
</span><span class="cx">    button_name = &quot;Create Data Set&quot; %]
</span><span class="cx">   &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;create&quot;&gt;
</span><ins>+  &lt;input type=&quot;hidden&quot; name=&quot;token&quot; value=&quot;[% issue_hash_token(['create-series']) FILTER html %]&quot;&gt;
</ins><span class="cx"> 
</span><span class="cx"> &lt;script type=&quot;text/javascript&quot;&gt;
</span><span class="cx">   document.chartform.category[0].selected = true;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultsearchsearchhelphtmltmpl"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/template/en/default/search/search-help.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/search/search-help.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/search/search-help.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,107 +0,0 @@
</span><del>-[%# The contents of this file are subject to the Mozilla Public
-  # License Version 1.1 (the &quot;License&quot;); you may not use this file
-  # except in compliance with the License. You may obtain a copy of
-  # the License at http://www.mozilla.org/MPL/
-  #
-  # Software distributed under the License is distributed on an &quot;AS
-  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
-  # implied. See the License for the specific language governing
-  # rights and limitations under the License.
-  #
-  # The Original Code is the Bugzilla Bug Tracking System.
-  #
-  # The Initial Developer of the Original Code is Netscape Communications
-  # Corporation. Portions created by Netscape are
-  # Copyright (C) 1998 Netscape Communications Corporation. All
-  # Rights Reserved.
-  #
-  # Contributor(s): Gervase Markham &lt;gerv@gerv.net&gt;
-  #%]
-  
-[% help_html = [ 
-{ id =&gt; &quot;short_desc_type&quot;, 
-  html =&gt; &quot;The type of summary search you would like&quot; },   
-{ id =&gt; &quot;short_desc&quot;, 
-  html =&gt; &quot;The $terms.bug summary is a short sentence which succinctly  
-           describes &lt;br&gt; what the $terms.bug is about.&quot; },   
-{ id =&gt; &quot;classification&quot;, 
-  html =&gt; &quot;$terms.Bugs are categorised into Classifications, Products and Components. classifications is the&lt;br&gt;
-           top-level categorisation.&quot; },   
-{ id =&gt; &quot;product&quot;, 
-  html =&gt; Param('useclassification') ?
-       &quot;$terms.Bugs are categorised into Products and Components. Select a Classification to narrow down this list&quot; :
-       &quot;$terms.Bugs are categorised into Products and Components. Product is 
-           the&lt;br&gt;top-level categorisation.&quot; },   
-{ id =&gt; &quot;component&quot;, 
-  html =&gt; &quot;Components are second-level categories; each belongs to a&lt;br&gt; 
-           particular Product. Select a Product to narrow down this list.&quot; },   
-{ id =&gt; &quot;version&quot;, 
-  html =&gt; &quot;The version field defines the version of the software the 
-           $terms.bug&lt;br&gt;was found in.&quot; },   
-{ id =&gt; &quot;target_milestone&quot;, 
-  html =&gt; &quot;The target_milestone field is used to define when the engineer&lt;br&gt;
-           the $terms.bug is assigned to expects to fix it.&quot; },   
-{ id =&gt; &quot;long_desc&quot;, 
-  html =&gt; &quot;$terms.Bugs have comments added to them by $terms.Bugzilla users.  
-           You can&lt;br&gt;search for some text in those comments.&quot; },   
-{ id =&gt; &quot;long_desc_type&quot;, 
-  html =&gt; &quot;The type of comment search you would like&quot; },   
-{ id =&gt; &quot;bug_file_loc&quot;, 
-  html =&gt; &quot;$terms.Bugs can have a URL associated with them - for example, a 
-           pointer&lt;br&gt;to a web site where the problem is seen.&quot; },   
-{ id =&gt; &quot;bug_file_loc_type&quot;, 
-  html =&gt; &quot;The type of URL search you would like&quot; },   
-{ id =&gt; &quot;status_whiteboard&quot;, 
-  html =&gt; &quot;Each $terms.bug has a free-form single line text entry box for 
-           adding&lt;br&gt;tags and status information.&quot; },   
-{ id =&gt; &quot;status_whiteboard_type&quot;, 
-  html =&gt; &quot;The type of whiteboard search you would like&quot; },   
-{ id =&gt; &quot;keywords&quot;, 
-  html =&gt; &quot;You can add keywords from a defined list to $terms.bugs, in order 
-           to&lt;br&gt;tag and group them.&quot; },   
-{ id =&gt; &quot;keywords_type&quot;, 
-  html =&gt; &quot;The type of keyword search you would like&quot; },   
-{ id =&gt; &quot;bug_status&quot;, 
-  html =&gt; &quot;$terms.Abug may be in any of a number of states.&quot; },
-{ id =&gt; &quot;resolution&quot;, 
-  html =&gt; &quot;If $terms.abug is in a resolved state, then one of these reasons
-           will&lt;br&gt;be given for its resolution.&quot; },   
-{ id =&gt; &quot;bug_severity&quot;, 
-  html =&gt; &quot;How severe the $terms.bug is, or whether it's an enhancement.&quot; },   
-{ id =&gt; &quot;priority&quot;, 
-  html =&gt; &quot;Engineers prioritize their $terms.bugs using this field.&quot; },   
-{ id =&gt; &quot;rep_platform&quot;, 
-  html =&gt; &quot;The hardware platform the $terms.bug was observed on.&quot; },   
-{ id =&gt; &quot;op_sys&quot;, 
-  html =&gt; &quot;The operating system the $terms.bug was observed on.&quot; },   
-{ id =&gt; &quot;email1&quot;, 
-  html =&gt; &quot;Every $terms.bug has people associated with it in different 
-           roles.&lt;br&gt;Here, you can search on what people are in what role.&quot; },
-{ id =&gt; &quot;email2&quot;, 
-  html =&gt; &quot;Every $terms.bug has people associated with it in different 
-           roles.&lt;br&gt;Here, you can search on what people are in what role.&quot; },
-{ id =&gt; &quot;bug_id&quot;, 
-  html =&gt; &quot;You can limit your search to a specific set of $terms.bugs .&quot; },   
-{ id =&gt; &quot;votes&quot;, 
-  html =&gt; &quot;Some $terms.bugs can be voted for, and you can limit your search to 
-           $terms.bugs&lt;br&gt;with more than a certain number of votes.&quot; },   
-{ id =&gt; &quot;chfield&quot;, 
-  html =&gt; &quot;You can search for specific types of change - this field define &lt;br&gt;
-           which field you are interested in changes for.&quot; },   
-{ id =&gt; &quot;chfieldfrom&quot;, 
-  html =&gt; &quot;Specify the start and end dates either in YYYY-MM-DD format&lt;br&gt;
-           (optionally followed by HH:mm, in 24 hour clock), or in relative&lt;br&gt;
-           dates such as 1h, 2d, 3w, 4m, 5y, which respectively mean one hour,&lt;br&gt;
-           two days, three weeks, four months, or five years ago. 0d is last&lt;br&gt;
-           midnight, and 0h, 0w, 0m, 0y is the beginning of this hour, week,&lt;br&gt;
-           month, or year.&quot; },
-{ id =&gt; &quot;chfieldto&quot;, 
-  html =&gt; &quot;Specify the start and end dates either in YYYY-MM-DD format&lt;br&gt;
-           (optionally followed by HH:mm, in 24 hour clock), or in relative&lt;br&gt;
-           dates such as 1h, 2d, 3w, 4m, 5y, which respectively mean one hour,&lt;br&gt;
-           two days, three weeks, four months, or five years ago. 0d is last&lt;br&gt;
-           midnight, and 0h, 0w, 0m, 0y is the beginning of this hour, week,&lt;br&gt;
-           month, or year.&quot; },
-{ id =&gt; &quot;chfieldvalue&quot;, 
-  html =&gt; &quot;The value the field defined above changed to during that time.&quot; },   
-] %]
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultsearchsearchpluginxmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/search/search-plugin.xml.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/search/search-plugin.xml.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/search/search-plugin.xml.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -19,6 +19,10 @@
</span><span class="cx"> &lt;ShortName&gt;[% terms.Bugzilla %]&lt;/ShortName&gt;
</span><span class="cx"> &lt;Description&gt;[% terms.Bugzilla %] Quick Search&lt;/Description&gt;
</span><span class="cx"> &lt;InputEncoding&gt;UTF-8&lt;/InputEncoding&gt;
</span><del>-&lt;Image width=&quot;16&quot; height=&quot;16&quot;&gt;data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABGdBTUEAAK%2FINwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAALBSURBVHjaYnxckcEAA3%2F%2B%2FT%2F17LUcH%2Fevf%2F8U%2BHmYGBkZMABAALEgc%2B68%2F3T227cf2tJKKhJLt59n%2FfmbnYnZV1KEhYkJrgYggBghNrz78fPIi3d8uvKBIdb%2FOaWPnzitLc97%2Bc5rFXnhnVO3%2BslLwjUABBDIhnsfPl%2Fj53VO91FX4Gfgkjxw%2Fd%2F6Q49%2FWStqyAj%2B%2B88gZqn%2B9u5rYU52iAaAAGL69%2F%2F%2F2d9%2FYiMclGT4fv76%2BZ9DbO%2FeA39%2BfJHVcvj5l%2Bnh03e%2FWThOvnwLtwEgAAAxAM7%2FBPj8%2FRYkHQYHAf3%2F%2Fv%2F%2B%2Fv8BAVNTUPX18yorLNHE2S8mB%2FT2%2Bq7a4dvu8iUSDgAAAAKICRgUv3%2F8ZGKGeIvpz6eXBvq61lZWLMwMv%2F5zMP7%2FqSAjVFyZ%2FNvZftuT10DnAAQAMQDO%2FwQIBAPz5Or6%2Ff0CBQEAAgT99ubq38z2%2BwT18%2FAM%2F%2BkNDAv6%2FQMCAA1GVVrhMze5h4kCCORpkd9%2F3n74KiHO%2B%2BffX8b%2Ff7m%2BXWP985%2Bf5R%2BPLNdfoK%2F%2F%2Ffv39%2BePj2%2FkZYR0fe0BAgikQZGX%2B9b9FzLS%2FH%2F%2B%2FGVgYGRlZWNlA7nv7z9QuDP8%2B8nw%2FRXjn68Mv4Gu%2FAwQQCCni3FxPLn7
 nIGZGegfNhYmNjYWZnBMASOakZER6Eumf9%2FYGT4y%2FHx%2F%2BfBFgAAC2cDGzPT99WeGvwzvv%2Fx89vrr%2F39%2FJER4pcT5Gf4z%2FP37D2jtj9%2B%2FL918fmzrKSsWNoAAgiaN%2Fz9%2Fff%2F6S4CP8%2BWbz9vWHfv54aukpAAz0Og%2Ff%2F7%2F%2Bs36668cO3ugED9QJUAAQTUArf7%2F8x87D9vRjcejhPiZhAUYcACAAGI5%2FOHH9ddvXzAxmjz%2B8P8lw4fXn5l4eRlwA4AAYmaTkBFg%2FKvJwfbkwZuXN57y%2Fv%2F34stXGR4uRmxpGwgAAgwA4%2FkfrfCWvLQAAAAASUVORK5CYII%3D&lt;/Image&gt;
</del><ins>+[% IF favicon %]
+  &lt;Image width=&quot;16&quot; height=&quot;16&quot;&gt;data:image/x-icon;base64,[% favicon FILTER base64 %]&lt;/Image&gt;
+[% ELSE %]
+  &lt;Image width=&quot;16&quot; height=&quot;16&quot;&gt;data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABGdBTUEAAK%2FINwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAALBSURBVHjaYnxckcEAA3%2F%2B%2FT%2F17LUcH%2Fevf%2F8U%2BHmYGBkZMABAALEgc%2B68%2F3T227cf2tJKKhJLt59n%2FfmbnYnZV1KEhYkJrgYggBghNrz78fPIi3d8uvKBIdb%2FOaWPnzitLc97%2Bc5rFXnhnVO3%2BslLwjUABBDIhnsfPl%2Fj53VO91FX4Gfgkjxw%2Fd%2F6Q49%2FWStqyAj%2B%2B88gZqn%2B9u5rYU52iAaAAGL69%2F%2F%2F2d9%2FYiMclGT4fv76%2BZ9DbO%2FeA39%2BfJHVcvj5l%2Bnh03e%2FWThOvnwLtwEgAAAxAM7%2FBPj8%2FRYkHQYHAf3%2F%2Fv%2F%2B%2Fv8BAVNTUPX18yorLNHE2S8mB%2FT2%2Bq7a4dvu8iUSDgAAAAKICRgUv3%2F8ZGKGeIvpz6eXBvq61lZWLMwMv%2F5zMP7%2FqSAjVFyZ%2FNvZftuT10DnAAQAMQDO%2FwQIBAPz5Or6%2Ff0CBQEAAgT99ubq38z2%2BwT18%2FAM%2F%2BkNDAv6%2FQMCAA1GVVrhMze5h4kCCORpkd9%2F3n74KiHO%2B%2BffX8b%2Ff7m%2BXWP985%2Bf5R%2BPLNdfoK%2F%2F%2Ffv39%2BePj2%2FkZYR0fe0BAgikQZGX%2B9b9FzLS%2FH%2F%2B%2FGVgYGRlZWNlA7nv7z9QuDP8%2B8nw%2FRXjn68Mv4Gu%2FAwQQCCni3FxPLn7nIGZGegfNh
 YmNjYWZnBMASOakZER6Eumf9%2FYGT4y%2FHx%2F%2BfBFgAAC2cDGzPT99WeGvwzvv%2Fx89vrr%2F39%2FJER4pcT5Gf4z%2FP37D2jtj9%2B%2FL918fmzrKSsWNoAAgiaN%2Fz9%2Fff%2F6S4CP8%2BWbz9vWHfv54aukpAAz0Og%2Ff%2F7%2F%2Bs36668cO3ugED9QJUAAQTUArf7%2F8x87D9vRjcejhPiZhAUYcACAAGI5%2FOHH9ddvXzAxmjz%2B8P8lw4fXn5l4eRlwA4AAYmaTkBFg%2FKvJwfbkwZuXN57y%2Fv%2F34stXGR4uRmxpGwgAAgwA4%2FkfrfCWvLQAAAAASUVORK5CYII%3D&lt;/Image&gt;
+[% END %]
</ins><span class="cx"> &lt;Url type=&quot;text/html&quot; method=&quot;GET&quot; template=&quot;[% urlbase FILTER xml %]buglist.cgi?quicksearch={searchTerms}&quot;/&gt;
</span><span class="cx"> &lt;/OpenSearchDescription&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultsearchsearchreportgraphhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/search/search-report-graph.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/search/search-report-graph.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/search/search-report-graph.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -32,8 +32,10 @@
</span><span class="cx"> [% PROCESS global/header.html.tmpl
</span><span class="cx">   title = &quot;Generate Graphical Report&quot;
</span><span class="cx">   onload = &quot;doOnSelectProduct(0); chartTypeChanged()&quot;
</span><ins>+  yui = [ 'autocomplete', 'calendar' ]
</ins><span class="cx">   javascript = js_data
</span><del>-  javascript_urls = [ &quot;js/productform.js&quot; ]
</del><ins>+  javascript_urls = [ &quot;js/util.js&quot;, &quot;js/productform.js&quot;, &quot;js/TUI.js&quot;, &quot;js/field.js&quot; ]
+  style_urls = [ &quot;skins/standard/search_form.css&quot; ]
</ins><span class="cx">   doc_section = &quot;reporting.html#reports&quot;
</span><span class="cx"> %]
</span><span class="cx"> 
</span><span class="lines">@@ -63,7 +65,7 @@
</span><span class="cx"> 
</span><span class="cx"> [% button_name = &quot;Generate Report&quot; %]
</span><span class="cx"> 
</span><del>-&lt;form method=&quot;get&quot; action=&quot;report.cgi&quot; name=&quot;reportform&quot;&gt;
</del><ins>+&lt;form method=&quot;get&quot; action=&quot;report.cgi&quot; name=&quot;reportform&quot; id=&quot;reportform&quot;&gt;
</ins><span class="cx"> 
</span><span class="cx"> &lt;table align=&quot;center&quot;&gt;
</span><span class="cx">   &lt;tr&gt;
</span><span class="lines">@@ -128,14 +130,13 @@
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS search/form.html.tmpl %]
</span><span class="cx"> 
</span><del>-&lt;br&gt;
-&lt;input type=&quot;submit&quot; id=&quot;[% button_name FILTER css_class_quote %]&quot;
-       value=&quot;[% button_name FILTER html %]&quot;&gt;
-&lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;wrap&quot;&gt;
-&lt;hr&gt;
-
</del><span class="cx"> [% PROCESS &quot;search/boolean-charts.html.tmpl&quot; %]
</span><span class="cx"> 
</span><ins>+  &lt;div id=&quot;knob&quot;&gt;
+    &lt;input type=&quot;submit&quot; id=&quot;[% button_name FILTER css_class_quote %]&quot;
+           value=&quot;[% button_name FILTER html %]&quot;&gt;
+    &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;wrap&quot;&gt;
+  &lt;/div&gt;
</ins><span class="cx"> &lt;/form&gt;
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/footer.html.tmpl %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultsearchsearchreportselecthtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/search/search-report-select.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/search/search-report-select.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/search/search-report-select.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -26,22 +26,25 @@
</span><span class="cx"> [% PROCESS &quot;global/field-descs.none.tmpl&quot; %]
</span><span class="cx"> 
</span><span class="cx"> [% BLOCK select %]
</span><del>-  [% rep_fields = [&quot;classification&quot;, &quot;product&quot;, &quot;component&quot;, &quot;version&quot;, &quot;rep_platform&quot;,  
-                   &quot;op_sys&quot;, &quot;bug_status&quot;, &quot;resolution&quot;, &quot;bug_severity&quot;, 
-                   &quot;priority&quot;, &quot;target_milestone&quot;, &quot;assigned_to&quot;,
-                   &quot;reporter&quot;, &quot;qa_contact&quot;, &quot;votes&quot; ] %]
</del><ins>+  [% Hook.process('rep_fields', 'search/search-report-select.html.tmpl') %]
</ins><span class="cx"> 
</span><span class="cx">   &lt;select name=&quot;[% name FILTER html %]&quot;&gt;
</span><span class="cx">     &lt;option value=&quot;&quot;&gt;&amp;lt;none&amp;gt;&lt;/option&gt;
</span><span class="cx">     
</span><del>-    [% FOREACH field = rep_fields %]
</del><ins>+    [% FOREACH field = report_columns.keys.sort %]
</ins><span class="cx">       [% NEXT IF field == &quot;classification&quot; AND !Param('useclassification') %]
</span><span class="cx">       [% NEXT IF field == &quot;target_milestone&quot; AND !Param('usetargetmilestone') %]
</span><span class="cx">       [% NEXT IF field == &quot;qa_contact&quot; AND !Param('useqacontact') %]
</span><del>-      [% NEXT IF field == &quot;votes&quot; AND !Param('usevotes') %]      
</del><span class="cx">       &lt;option value=&quot;[% field FILTER html %]&quot; 
</span><span class="cx">         [% &quot; selected&quot; IF default.$name.0 == field %]&gt;
</span><span class="cx">         [% field_descs.$field || field FILTER html %]&lt;/option&gt;
</span><span class="cx">     [% END %]
</span><ins>+
+    [%# Single-select fields are also valid column names. %]
+    [% FOREACH field = custom_fields %]
+      &lt;option value=&quot;[% field.name FILTER html %]&quot;
+        [% &quot; selected&quot; IF default.$name.0 == field.name %]&gt;
+        [% field.description FILTER html %]&lt;/option&gt;
+    [% END %]
</ins><span class="cx">   &lt;/select&gt;
</span><span class="cx"> [% END %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultsearchsearchreporttablehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/search/search-report-table.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/search/search-report-table.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/search/search-report-table.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -32,8 +32,10 @@
</span><span class="cx"> [% PROCESS global/header.html.tmpl
</span><span class="cx">   title = &quot;Generate Tabular Report&quot;
</span><span class="cx">   onload = &quot;doOnSelectProduct(0)&quot;
</span><ins>+  yui = [ 'autocomplete', 'calendar' ]
</ins><span class="cx">   javascript = js_data
</span><del>-  javascript_urls = [ &quot;js/productform.js&quot; ]
</del><ins>+  javascript_urls = [ &quot;js/util.js&quot;, &quot;js/productform.js&quot;, &quot;js/TUI.js&quot;, &quot;js/field.js&quot; ]
+  style_urls = [ &quot;skins/standard/search_form.css&quot; ]
</ins><span class="cx">   doc_section = &quot;reporting.html#reports&quot;
</span><span class="cx"> %]
</span><span class="cx"> 
</span><span class="lines">@@ -46,7 +48,7 @@
</span><span class="cx"> 
</span><span class="cx"> [% button_name = &quot;Generate Report&quot; %]
</span><span class="cx"> 
</span><del>-&lt;form method=&quot;get&quot; action=&quot;report.cgi&quot; name=&quot;reportform&quot;&gt;
</del><ins>+&lt;form method=&quot;get&quot; action=&quot;report.cgi&quot; name=&quot;reportform&quot; id=&quot;reportform&quot;&gt;
</ins><span class="cx"> 
</span><span class="cx"> &lt;table align=&quot;center&quot;&gt;
</span><span class="cx">   &lt;tr&gt;
</span><span class="lines">@@ -78,17 +80,16 @@
</span><span class="cx"> 
</span><span class="cx"> &lt;hr&gt;
</span><span class="cx"> 
</span><del>-[% PROCESS search/form.html.tmpl %]
</del><ins>+  [% PROCESS search/form.html.tmpl %]
</ins><span class="cx"> 
</span><del>-&lt;br&gt;
-&lt;input type=&quot;submit&quot; id=&quot;[% button_name FILTER css_class_quote %]&quot;
-       value=&quot;[% button_name FILTER html %]&quot;&gt;
-&lt;input type=&quot;hidden&quot; name=&quot;format&quot; value=&quot;table&quot;&gt;
-&lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;wrap&quot;&gt;
-&lt;hr&gt;
</del><ins>+  [% PROCESS &quot;search/boolean-charts.html.tmpl&quot; %]
</ins><span class="cx"> 
</span><del>-[% PROCESS &quot;search/boolean-charts.html.tmpl&quot; %]
-
</del><ins>+  &lt;div id=&quot;knob&quot;&gt;
+    &lt;input type=&quot;submit&quot; id=&quot;[% button_name FILTER css_class_quote %]&quot;
+         value=&quot;[% button_name FILTER html %]&quot;&gt;
+    &lt;input type=&quot;hidden&quot; name=&quot;format&quot; value=&quot;table&quot;&gt;
+    &lt;input type=&quot;hidden&quot; name=&quot;action&quot; value=&quot;wrap&quot;&gt;
+  &lt;/div&gt;
</ins><span class="cx"> &lt;/form&gt;
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/footer.html.tmpl %]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultsearchsearchspecifichtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/search/search-specific.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/search/search-specific.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/search/search-specific.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -21,7 +21,8 @@
</span><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="cx"> 
</span><span class="cx"> [% PROCESS global/header.html.tmpl 
</span><del>-  title = &quot;Find a Specific &quot; _ terms.Bug
</del><ins>+  title = &quot;Simple Search&quot;
+  style_urls = [ &quot;skins/standard/search_form.css&quot; ]
</ins><span class="cx"> %]
</span><span class="cx"> 
</span><span class="cx"> [% WRAPPER search/tabs.html.tmpl %]
</span><span class="lines">@@ -42,11 +43,11 @@
</span><span class="cx"> &lt;input type=&quot;hidden&quot; name=&quot;query_format&quot; value=&quot;specific&quot;&gt;
</span><span class="cx"> &lt;input type=&quot;hidden&quot; name=&quot;order&quot; value=&quot;relevance desc&quot;&gt;
</span><span class="cx"> 
</span><del>-&lt;table&gt;
</del><ins>+&lt;table summary=&quot;Search fields&quot; class=&quot;bz_simple_search_form&quot;&gt;
</ins><span class="cx">   &lt;tr&gt;
</span><del>-    &lt;td align=&quot;right&quot; valign=&quot;baseline&quot;&gt;
-      &lt;b&gt;&lt;label for=&quot;bug_status&quot;&gt;Status:&lt;/label&gt;&lt;/b&gt;
-    &lt;/td&gt;
</del><ins>+    &lt;th&gt;
+      &lt;label for=&quot;bug_status&quot;&gt;[% field_descs.bug_status FILTER html %]:&lt;/label&gt;
+    &lt;/th&gt;
</ins><span class="cx">     &lt;td&gt;
</span><span class="cx">       &lt;select name=&quot;bug_status&quot; id=&quot;bug_status&quot;&gt;
</span><span class="cx">         [% statuses = [ { name = 'open', label = &quot;Open&quot; },
</span><span class="lines">@@ -62,9 +63,9 @@
</span><span class="cx">     &lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx">   &lt;tr&gt;
</span><del>-    &lt;td align=&quot;right&quot; valign=&quot;baseline&quot;&gt;
-      &lt;b&gt;&lt;label for=&quot;product&quot;&gt;Product:&lt;/label&gt;&lt;/b&gt;
-    &lt;/td&gt;
</del><ins>+    &lt;th&gt;
+      &lt;label for=&quot;product&quot;&gt;[% field_descs.product FILTER html %]:&lt;/label&gt;
+    &lt;/th&gt;
</ins><span class="cx">     &lt;td&gt;
</span><span class="cx">       &lt;select name=&quot;product&quot; id=&quot;product&quot;&gt;
</span><span class="cx">         &lt;option value=&quot;&quot;&gt;All&lt;/option&gt;
</span><span class="lines">@@ -74,7 +75,7 @@
</span><span class="cx">             [% FOREACH p = user.get_selectable_products(c.id) %]
</span><span class="cx">               [% IF p.components.size %]
</span><span class="cx">                 &lt;option value=&quot;[% p.name FILTER html %]&quot;
</span><del>-                  [% &quot; selected&quot; IF lsearch(default.product, p.name) != -1 %]&gt;
</del><ins>+                  [% &quot; selected&quot; IF default.product.contains(p.name) %]&gt;
</ins><span class="cx">                   [% p.name FILTER html %]
</span><span class="cx">                 &lt;/option&gt;
</span><span class="cx">               [% END %]
</span><span class="lines">@@ -84,7 +85,7 @@
</span><span class="cx">         [% ELSE %]
</span><span class="cx">           [% FOREACH p = product %]
</span><span class="cx">             &lt;option value=&quot;[% p.name FILTER html %]&quot;
</span><del>-              [% &quot; selected&quot; IF lsearch(default.product, p.name) != -1 %]&gt;
</del><ins>+              [% &quot; selected&quot; IF default.product.contains(p.name) %]&gt;
</ins><span class="cx">               [% p.name FILTER html %]
</span><span class="cx">             &lt;/option&gt;
</span><span class="cx">           [% END %]
</span><span class="lines">@@ -93,9 +94,9 @@
</span><span class="cx">     &lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx">   &lt;tr&gt;
</span><del>-    &lt;td align=&quot;right&quot; valign=&quot;baseline&quot;&gt;
-      &lt;b&gt;&lt;label for=&quot;content&quot;&gt;Words:&lt;/label&gt;&lt;/b&gt;
-    &lt;/td&gt;
</del><ins>+    &lt;th&gt;
+      &lt;label for=&quot;content&quot;&gt;Words:&lt;/label&gt;
+    &lt;/th&gt;
</ins><span class="cx">     &lt;td&gt;
</span><span class="cx">       &lt;input name=&quot;content&quot; size=&quot;40&quot; id=&quot;content&quot;
</span><span class="cx">              value=&quot;[% default.content.0 FILTER html %]&quot;&gt;
</span><span class="lines">@@ -109,7 +110,7 @@
</span><span class="cx">     &lt;td&gt;&lt;/td&gt;
</span><span class="cx">     &lt;td&gt;
</span><span class="cx">     
</span><del>-      [% IF Param('specific_search_allow_empty_words') %]
</del><ins>+      [% IF Param('search_allow_no_criteria') %]
</ins><span class="cx">         &lt;input type=&quot;submit&quot; id=&quot;search&quot; value=&quot;Search&quot;&gt;
</span><span class="cx">       [% ELSE %]
</span><span class="cx">         &lt;input type=&quot;submit&quot; id=&quot;search&quot; value=&quot;Search&quot;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultsearchtabshtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/search/tabs.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/search/tabs.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/search/tabs.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -24,7 +24,7 @@
</span><span class="cx">   #%]
</span><span class="cx"> 
</span><span class="cx"> [% WRAPPER global/tabs.html.tmpl
</span><del>-     tabs = [ { name =&gt; 'specific', label =&gt; &quot;Find a Specific $terms.Bug&quot;,
</del><ins>+     tabs = [ { name =&gt; 'specific', label =&gt; &quot;Simple Search&quot;,
</ins><span class="cx">                 link =&gt; &quot;query.cgi?format=specific&quot; },
</span><span class="cx">               { name =&gt; 'advanced', label =&gt; &quot;Advanced Search&quot;,
</span><span class="cx">                 link =&gt; &quot;query.cgi?format=advanced&quot; } ]
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultsearchtypeselecthtmltmpl"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/template/en/default/search/type-select.html.tmpl (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/search/type-select.html.tmpl                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/template/en/default/search/type-select.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,30 @@
</span><ins>+[%# The contents of this file are subject to the Mozilla Public
+  # License Version 1.1 (the &quot;License&quot;); you may not use this file
+  # except in compliance with the License. You may obtain a copy of
+  # the License at http://www.mozilla.org/MPL/
+  #
+  # Software distributed under the License is distributed on an &quot;AS
+  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+  # implied. See the License for the specific language governing
+  # rights and limitations under the License.
+  #
+  # The Original Code is the Bugzilla Bug Tracking System.
+  #
+  # The Initial Developer of the Original Code is the San Jose State
+  # University Foundation. Portions created by the Initial Developer are
+  # Copyright (C) 2008 the Initial Developer. All Rights Reserved.
+  #
+  # Contributor(s): 
+  #   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+  #%]
+
+[% PROCESS &quot;global/field-descs.none.tmpl&quot; %]
+  
+&lt;select name=&quot;[% name FILTER html %]&quot; title=&quot;Search type&quot;
+        class=&quot;[% class FILTER css_class_quote %]&quot;&gt;
+  [% FOREACH type = types %]
+    &lt;option value=&quot;[% type FILTER html %]&quot;
+            [%- ' selected=&quot;selected&quot;' IF type == selected %]&gt;
+        [%- search_descs.$type FILTER html %]&lt;/option&gt;
+  [% END %]
+&lt;/select&gt;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultsetupstringstxtpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/setup/strings.txt.pl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/setup/strings.txt.pl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/setup/strings.txt.pl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -28,12 +28,90 @@
</span><span class="cx"> 
</span><span class="cx"> %strings = (
</span><span class="cx">     any  =&gt; 'any',
</span><ins>+    apachectl_failed =&gt; &lt;&lt;END,
+WARNING: We could not check the configuration of Apache. This sometimes
+happens when you are not running checksetup.pl as ##root##. To see the
+problem we ran into, run: ##command##
+END
+    bad_executable =&gt; 'not a valid executable: ##bin##',
</ins><span class="cx">     blacklisted =&gt; '(blacklisted)',
</span><ins>+    bz_schema_exists_before_220 =&gt; &lt;&lt;'END',
+You are upgrading from a version before 2.20, but the bz_schema table
+already exists. This means that you restored a mysqldump into the Bugzilla
+database without first dropping the already-existing Bugzilla database,
+at some point. Whenever you restore a Bugzilla database backup, you must
+always drop the entire database first.
+
+Please drop your Bugzilla database and restore it from a backup that does
+not contain the bz_schema table. If for some reason you cannot do this, you
+can connect to your MySQL database and drop the bz_schema table, as a last
+resort.
+END
</ins><span class="cx">     checking_for =&gt; 'Checking for',
</span><span class="cx">     checking_dbd      =&gt; 'Checking available perl DBD modules...',
</span><span class="cx">     checking_optional =&gt; 'The following Perl modules are optional:',
</span><span class="cx">     checking_modules  =&gt; 'Checking perl modules...',
</span><ins>+    chmod_failed      =&gt; '##path##: Failed to change permissions: ##error##',
+    chown_failed      =&gt; '##path##: Failed to change ownership: ##error##',
+    commands_dbd      =&gt; &lt;&lt;EOT,
+YOU MUST RUN ONE OF THE FOLLOWING COMMANDS (depending on which database
+you use):
+EOT
+    commands_optional =&gt; 'COMMANDS TO INSTALL OPTIONAL MODULES:',
+    commands_required =&gt; &lt;&lt;EOT,
+COMMANDS TO INSTALL REQUIRED MODULES (You *must* run all these commands
+and then re-run checksetup.pl):
+EOT
+    continue_without_answers =&gt; &lt;&lt;'END',
+Re-run checksetup.pl in interactive mode (without an 'answers' file)
+to continue.
+END
+    cpan_bugzilla_home =&gt; 
+        &quot;WARNING: Using the Bugzilla directory as the CPAN home.&quot;,
+    db_enum_setup  =&gt; &quot;Setting up choices for standard drop-down fields:&quot;,
+    db_schema_init =&gt; &quot;Initializing bz_schema...&quot;,
+    db_table_new   =&gt; &quot;Adding new table ##table##...&quot;,
+    db_table_setup =&gt; &quot;Creating tables...&quot;,
</ins><span class="cx">     done =&gt; 'done.',
</span><ins>+    enter_or_ctrl_c =&gt; &quot;Press Enter to continue or Ctrl-C to exit...&quot;,
+    error_localconfig_read =&gt; &lt;&lt;'END',
+An error has occurred while reading the ##localconfig## file.  The text of
+the error message is:
+
+##error##
+
+Please fix the error in the localconfig file. Alternately, rename your
+localconfig file and re-run checksetup.pl to have it create a new
+localconfig file:
+
+  $ mv -f localconfig localconfig.old
+  $ ./checksetup.pl
+END
+    extension_must_return_name =&gt; &lt;&lt;END,
+##file## returned ##returned##, which is not a valid name for an extension.
+Extensions must return their name, not &lt;code&gt;1&lt;/code&gt; or a number. See
+the documentation of Bugzilla::Extension for details.
+END
+    feature_auth_ldap         =&gt; 'LDAP Authentication',
+    feature_auth_radius       =&gt; 'RADIUS Authentication',
+    feature_graphical_reports =&gt; 'Graphical Reports',
+    feature_html_desc         =&gt; 'More HTML in Product/Group Descriptions',
+    feature_inbound_email     =&gt; 'Inbound Email',
+    feature_jobqueue          =&gt; 'Mail Queueing',
+    feature_jsonrpc           =&gt; 'JSON-RPC Interface',
+    feature_jsonrpc_faster    =&gt; 'Make JSON-RPC Faster',
+    feature_new_charts        =&gt; 'New Charts',
+    feature_old_charts        =&gt; 'Old Charts',
+    feature_mod_perl          =&gt; 'mod_perl',
+    feature_moving            =&gt; 'Move Bugs Between Installations',
+    feature_patch_viewer      =&gt; 'Patch Viewer',
+    feature_smtp_auth         =&gt; 'SMTP Authentication',
+    feature_updates           =&gt; 'Automatic Update Notifications',
+    feature_xmlrpc            =&gt; 'XML-RPC Interface',
+    feature_detect_charset    =&gt; 'Automatic charset detection for text attachments',
+
+    file_remove =&gt; 'Removing ##name##...',
+    file_rename =&gt; 'Renaming ##from## to ##to##...',
</ins><span class="cx">     header =&gt; &quot;* This is Bugzilla ##bz_ver## on perl ##perl_ver##\n&quot;
</span><span class="cx">             . &quot;* Running on ##os_name## ##os_ver##&quot;,
</span><span class="cx">     install_all =&gt; &lt;&lt;EOT,
</span><span class="lines">@@ -52,18 +130,315 @@
</span><span class="cx"> 
</span><span class="cx"> EOT
</span><span class="cx">     install_module =&gt; 'Installing ##module## version ##version##...',
</span><ins>+    installation_failed =&gt; '*** Installation aborted. Read the messages above. ***',
+    install_no_compiler =&gt; &lt;&lt;END,
+ERROR: Using install-module.pl requires that you install a compiler, such as
+gcc.
+END
+    install_no_make =&gt; &lt;&lt;END,
+ERROR: Using install-module.pl requires that you install &quot;make&quot;.
+END
+    lc_new_vars =&gt; &lt;&lt;'END',
+This version of Bugzilla contains some variables that you may want to
+change and adapt to your local settings. The following variables are
+new to ##localconfig## since you last ran checksetup.pl:
+
+##new_vars##
+
+Please edit the file ##localconfig## and then re-run checksetup.pl
+to complete your installation.
+END
+    lc_old_vars =&gt; &lt;&lt;'END',
+The following variables are no longer used in ##localconfig##, and
+have been moved to ##old_file##: ##vars##
+END
+    localconfig_create_htaccess =&gt; &lt;&lt;'END',
+If you are using Apache as your web server, Bugzilla can create .htaccess
+files for you, which will keep this file (localconfig) and other
+confidential files from being read over the web.
+
+If this is set to 1, checksetup.pl will create .htaccess files if 
+they don't exist.
+
+If this is set to 0, checksetup.pl will not create .htaccess files.
+END
+    localconfig_cvsbin =&gt; &lt;&lt;'END',
+If you want to use the CVS integration of the Patch Viewer, please specify
+the full path to the &quot;cvs&quot; executable here.
+END
+    localconfig_db_check =&gt; &lt;&lt;'END',
+Should checksetup.pl try to verify that your database setup is correct?
+With some combinations of database servers/Perl modules/moonphase this
+doesn't work, and so you can try setting this to 0 to make checksetup.pl
+run.
+END
+    localconfig_db_driver =&gt; &lt;&lt;'END',
+What SQL database to use. Default is mysql. List of supported databases
+can be obtained by listing Bugzilla/DB directory - every module corresponds
+to one supported database and the name of the module (before &quot;.pm&quot;)
+corresponds to a valid value for this variable.
+END
+    localconfig_db_host =&gt; &lt;&lt;'END',
+The DNS name or IP address of the host that the database server runs on.
+END
+    localconfig_db_name =&gt; &lt;&lt;'END',
+The name of the database. For Oracle, this is the database's SID. For
+SQLite, this is a name (or path) for the DB file.
+END
+    localconfig_db_pass =&gt; &lt;&lt;'END',
+Enter your database password here. It's normally advisable to specify
+a password for your bugzilla database user.
+If you use apostrophe (') or a backslash (\) in your password, you'll
+need to escape it by preceding it with a '\' character. (\') or (\)
+(It is far simpler to just not use those characters.)
+END
+    localconfig_db_port =&gt; &lt;&lt;'END',
+Sometimes the database server is running on a non-standard port. If that's
+the case for your database server, set this to the port number that your
+database server is running on. Setting this to 0 means &quot;use the default
+port for my database server.&quot;
+END
+    localconfig_db_sock =&gt; &lt;&lt;'END',
+MySQL Only: Enter a path to the unix socket for MySQL. If this is
+blank, then MySQL's compiled-in default will be used. You probably
+want that.
+END
+    localconfig_db_user =&gt; &quot;Who we connect to the database as.&quot;,
+    localconfig_diffpath =&gt; &lt;&lt;'END',
+For the &quot;Difference Between Two Patches&quot; feature to work, we need to know
+what directory the &quot;diff&quot; bin is in. (You only need to set this if you
+are using that feature of the Patch Viewer.)
+END
+    localconfig_index_html =&gt; &lt;&lt;'END',
+Most web servers will allow you to use index.cgi as a directory
+index, and many come preconfigured that way, but if yours doesn't
+then you'll need an index.html file that provides redirection
+to index.cgi. Setting $index_html to 1 below will allow
+checksetup.pl to create an index.html for you if it doesn't exist.
+NOTE: checksetup.pl will not replace an existing file, so if you
+      wish to have checksetup.pl create one for you, you must
+      make sure that index.html doesn't already exist.
+END
+    localconfig_interdiffbin =&gt; &lt;&lt;'END',
+If you want to use the &quot;Difference Between Two Patches&quot; feature of the
+Patch Viewer, please specify the full path to the &quot;interdiff&quot; executable
+here.
+END
+    localconfig_site_wide_secret =&gt; &lt;&lt;'END',
+This secret key is used by your installation for the creation and
+validation of encrypted tokens. These tokens are used to implement
+security features in Bugzilla, to protect against certain types of attacks.
+A random string is generated by default. It's very important that this key
+is kept secret. It also must be very long.
+END
+    localconfig_use_suexec =&gt; &lt;&lt;'END',
+Set this to 1 if Bugzilla runs in an Apache SuexecUserGroup environment.
+
+If your web server runs control panel software (cPanel, Plesk or similar),
+or if your Bugzilla is to run in a shared hosting environment, then you are
+almost certainly in an Apache SuexecUserGroup environment.
+
+If this is a Windows box, ignore this setting, as it does nothing.
+
+If set to 0, checksetup.pl will set file permissions appropriately for
+a normal webserver environment.
+
+If set to 1, checksetup.pl will set file permissions so that Bugzilla
+works in a SuexecUserGroup environment. 
+END
+    localconfig_webservergroup =&gt; &lt;&lt;'END',
+The name of the group that your web server runs as. On Red Hat
+distributions, this is usually &quot;apache&quot;. On Debian/Ubuntu, it is 
+usually &quot;www-data&quot;.
+
+If you have use_suexec turned on below, then this is instead the name
+of the group that your web server switches to to run cgi files.
+
+If this is a Windows machine, ignore this setting, as it does nothing.
+
+If you do not have access to the group your scripts will run under,
+set this to &quot;&quot;. If you do set this to &quot;&quot;, then your Bugzilla installation
+will be _VERY_ insecure, because some files will be world readable/writable,
+and so anyone who can get local access to your machine can do whatever they
+want. You should only have this set to &quot;&quot; if this is a testing installation
+and you cannot set this up any other way. YOU HAVE BEEN WARNED!
+
+If you set this to anything other than &quot;&quot;, you will need to run checksetup.pl
+as ##root## or as a user who is a member of the specified group.
+END
</ins><span class="cx">     max_allowed_packet =&gt; &lt;&lt;EOT,
</span><span class="cx"> WARNING: You need to set the max_allowed_packet parameter in your MySQL
</span><span class="cx"> configuration to at least ##needed##. Currently it is set to ##current##.
</span><span class="cx"> You can set this parameter in the [mysqld] section of your MySQL
</span><span class="cx"> configuration file.
</span><span class="cx"> EOT
</span><ins>+    min_version_required =&gt; &quot;Minimum version required: &quot;,
+
+# Note: When translating these &quot;modules&quot; messages, don't change the formatting
+# if possible, because there is hardcoded formatting in 
+# Bugzilla::Install::Requirements to match the box formatting.
+    modules_message_apache =&gt; &lt;&lt;END,
+***********************************************************************
+* APACHE MODULES                                                      *
+***********************************************************************
+* Normally, when Bugzilla is upgraded, all Bugzilla users have to     *
+* clear their browser cache or Bugzilla will break. If you enable     *
+* certain modules in your Apache configuration (usually called        *
+* httpd.conf or apache2.conf) then your users will not have to clear  *
+* their caches when you upgrade Bugzilla. The modules you need to     *
+* enable are:                                                         *
+*                                                                     *
+END
+    modules_message_db =&gt; &lt;&lt;EOT,
+***********************************************************************
+* DATABASE ACCESS                                                     *
+***********************************************************************
+* In order to access your database, Bugzilla requires that the        *
+* correct &quot;DBD&quot; module be installed for the database that you are     *
+* running. See below for the correct command to run to install the    *
+* appropriate module for your database.                               *
+EOT
+    modules_message_optional =&gt; &lt;&lt;EOT,
+***********************************************************************
+* OPTIONAL MODULES                                                    *
+***********************************************************************
+* Certain Perl modules are not required by Bugzilla, but by           *
+* installing the latest version you gain access to additional         *
+* features.                                                           *
+*                                                                     *
+* The optional modules you do not have installed are listed below,    *
+* with the name of the feature they enable. Below that table are the  *
+* commands to install each module.                                    *
+EOT
+    modules_message_required =&gt; &lt;&lt;EOT,
+***********************************************************************
+* REQUIRED MODULES                                                    *
+***********************************************************************
+* Bugzilla requires you to install some Perl modules which are either *
+* missing from your system, or the version on your system is too old. *
+* See below for commands to install these modules.                    *
+EOT
+
</ins><span class="cx">     module_found =&gt; &quot;found v##ver##&quot;,
</span><span class="cx">     module_not_found =&gt; &quot;not found&quot;,
</span><span class="cx">     module_ok =&gt; 'ok',
</span><span class="cx">     module_unknown_version =&gt; &quot;found unknown version&quot;,
</span><ins>+    no_such_module =&gt; &quot;There is no Perl module on CPAN named ##module##.&quot;,
+    mysql_innodb_disabled =&gt; &lt;&lt;'END',
+InnoDB is disabled in your MySQL installation.
+Bugzilla requires InnoDB to be enabled.
+Please enable it and then re-run checksetup.pl.
+END
+    mysql_index_renaming =&gt; &lt;&lt;'END',
+We are about to rename old indexes. The estimated time to complete
+renaming is ##minutes## minutes. You cannot interrupt this action once
+it has begun. If you would like to cancel, press Ctrl-C now...
+(Waiting 45 seconds...)
+END
+    mysql_utf8_conversion =&gt; &lt;&lt;'END',
+WARNING: We are about to convert your table storage format to UTF-8. This
+         allows Bugzilla to correctly store and sort international characters.
+         However, if you have any non-UTF-8 data in your database,
+         it ***WILL BE DELETED*** by this process. So, before
+         you continue with checksetup.pl, if you have any non-UTF-8
+         data (or even if you're not sure) you should press Ctrl-C now
+         to interrupt checksetup.pl, and run contrib/recode.pl to make all
+         the data in your database into UTF-8. You should also back up your
+         database before continuing. This will affect every single table
+         in the database, even non-Bugzilla tables.
+
+         If you ever used a version of Bugzilla before 2.22, we STRONGLY
+         recommend that you stop checksetup.pl NOW and run contrib/recode.pl.
+END
+    no_checksetup_from_cgi =&gt; &lt;&lt;END,
+&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.01//EN&quot;
+          &quot;http://www.w3.org/TR/html4/strict.dtd&quot;&gt;
+&lt;html&gt;
+  &lt;head&gt;
+    &lt;title&gt;checksetup.pl cannot run from a web browser&lt;/title&gt;
+  &lt;/head&gt;
+
+  &lt;body&gt;
+    &lt;h1&gt;checksetup.pl cannot run from a web browser&lt;/h1&gt;
+    &lt;p&gt;
+      You &lt;b&gt;must not&lt;/b&gt; execute this script from your web browser.
+      To install or upgrade Bugzilla, run this script from
+      the command-line (e.g. &lt;tt&gt;bash&lt;/tt&gt; or &lt;tt&gt;ssh&lt;/tt&gt; on Linux
+      or &lt;tt&gt;cmd.exe&lt;/tt&gt; on Windows), and follow instructions given there.
+    &lt;/p&gt;
+
+    &lt;p&gt;
+      For more information on how to install Bugzilla, please
+      &lt;a href=&quot;http://www.bugzilla.org/docs/&quot;&gt;read the documentation&lt;/a&gt;
+      available on the official Bugzilla website.
+    &lt;/p&gt;
+  &lt;/body&gt;
+&lt;/html&gt;
+END
+    patchutils_missing =&gt; &lt;&lt;'END',
+OPTIONAL NOTE: If you want to be able to use the 'difference between two
+patches' feature of Bugzilla (which requires the PatchReader Perl module
+as well), you should install patchutils from:
+
+    http://cyberelk.net/tim/patchutils/
+END
+    ppm_repo_add =&gt; &lt;&lt;EOT,
+***********************************************************************
+* Note For Windows Users                                              *
+***********************************************************************
+* In order to install the modules listed below, you first have to run * 
+* the following command as an Administrator:                          *
+*                                                                     *
+*   ppm repo add theory58S ##theory_url##
+EOT
+    ppm_repo_up =&gt; &lt;&lt;EOT,
+*                                                                     *
+* Then you have to do (also as an Administrator):                     *
+*                                                                     *
+*   ppm repo up theory58S                                             *
+*                                                                     *
+* Do that last command over and over until you see &quot;theory58S&quot; at the *
+* top of the displayed list.                                          *
+EOT
</ins><span class="cx">     template_precompile   =&gt; &quot;Precompiling templates...&quot;,
</span><ins>+    template_removal_failed =&gt; &lt;&lt;END,
+WARNING: The directory '##template_cache##' could not be removed.
+         It has been moved into '##deleteme##', which should be
+         deleted manually to conserve disk space.
+END
</ins><span class="cx">     template_removing_dir =&gt; &quot;Removing existing compiled templates...&quot;,
</span><ins>+    update_cf_invalid_name =&gt; 
+        &quot;Removing custom field '##field##', because it has an invalid name...&quot;,
+    update_flags_bad_name =&gt; &lt;&lt;'END',
+&quot;##flag##&quot; is not a valid name for a flag. Rename it to not have any spaces
+or commas.
+END
+    update_nomail_bad =&gt; &lt;&lt;'END',
+WARNING: The following users were listed in ##data##/nomail, but do
+not have an account here. The unmatched entries have been moved to 
+##data##/nomail.bad:
+END
+    update_summary_truncate_comment =&gt; 
+        &quot;The original value of the Summary field was longer than 255&quot;
+        . &quot; characters, and so it was truncated during an upgrade.&quot;
+        . &quot; The original summary was:\n\n##summary##&quot;,
+    update_summary_truncated =&gt; &lt;&lt;'END',
+WARNING: Some of your bugs had summaries longer than 255 characters.
+They have had their original summary copied into a comment, and then
+the summary was truncated to 255 characters. The affected bug numbers were:
+END
+    update_quips =&gt; &lt;&lt;'END',
+Quips are now stored in the database, rather than in an external file.
+The quips previously stored in ##data##/comments have been copied into
+the database, and that file has been renamed to ##data##/comments.bak
+You may delete the renamed file once you have confirmed that all your
+quips were moved successfully.
+END
+    update_queries_to_tags =&gt; &quot;Populating the new 'tag' table:&quot;,
+    webdot_bad_htaccess =&gt; &lt;&lt;END,
+WARNING: Dependency graph images are not accessible.
+Delete ##dir##/.htaccess and re-run checksetup.pl.
+END
</ins><span class="cx"> );
</span><span class="cx"> 
</span><span class="cx"> 1;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultsidebarxultmpl"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/template/en/default/sidebar.xul.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/sidebar.xul.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/sidebar.xul.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,130 +0,0 @@
</span><del>-[%# -*- mode: sgml -*- %]
-[%# The contents of this file are subject to the Mozilla Public
-  # License Version 1.1 (the &quot;License&quot;); you may not use this file
-  # except in compliance with the License. You may obtain a copy of
-  # the License at http://www.mozilla.org/MPL/
-  #
-  # Software distributed under the License is distributed on an &quot;AS
-  # IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
-  # implied. See the License for the specific language governing
-  # rights and limitations under the License.
-  #
-  # The Original Code is the Bugzilla Bug Tracking System.
-  #
-  # The Initial Developer of the Original Code is Netscape Communications
-  # Corporation. Portions created by Netscape are
-  # Copyright (C) 1998 Netscape Communications Corporation. All
-  # Rights Reserved.
-  #
-  # Contributor(s): Jacob Steenhagen &lt;jake@bugzilla.org&gt;
-  #                 Scott Collins &lt;scc@mozilla.org&gt;
-  #                 Christopher A. Aillon &lt;christopher@aillon.com&gt;
-  #%]
-
-[% PROCESS global/variables.none.tmpl %]
-
-&lt;?xml version=&quot;1.0&quot;?&gt;
-&lt;?xml-stylesheet href=&quot;chrome://communicator/skin/&quot; type=&quot;text/css&quot;?&gt;
-&lt;?xml-stylesheet href=&quot;[% urlbase FILTER xml %]skins/standard/panel.css&quot; type=&quot;text/css&quot;?&gt;
-&lt;window
-  xmlns=&quot;http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul&quot;
-  xmlns:html=&quot;http://www.w3.org/1999/xhtml&quot;
-  orient=&quot;vertical&quot;
-  onload=&quot;document.getElementById('query-field').addEventListener('keypress', initial_keypress_handler, true)&quot;&gt;
-
-&lt;script type=&quot;application/x-javascript&quot;&gt;&lt;![CDATA[
-
-function load_absolute_url( aAbsoluteURL ) {
-    content.location = aAbsoluteURL;
-}
-
-function load_relative_url( aRelativeURL ) {
-    aRelativeURL = '[% urlbase FILTER xml %]' + aRelativeURL;
-    _content.location = aRelativeURL;
-}
-
-function initial_keypress_handler( aEvent ) {
-    this.removeAttribute(&quot;class&quot;);
-    this.addEventListener(&quot;keypress&quot;, normal_keypress_handler, true);
-    this.removeEventListener(&quot;keypress&quot;, initial_keypress_handler, true);
-}
-
-function normal_keypress_handler( aEvent ) {
-    if ( aEvent.keyCode == 13 )
-      load_relative_url('buglist.cgi?quicksearch=' + this.value);
-}
-
-]]&gt;&lt;/script&gt;
-
-  &lt;textbox id=&quot;query-field&quot; class=&quot;descriptive-content&quot; value=&quot;enter search&quot; onfocus=&quot;this.setSelectionRange(0,this.value.length)&quot;/&gt;
-
-  &lt;separator class=&quot;groove&quot;/&gt;
-
-  &lt;box autostretch=&quot;never&quot; valign=&quot;top&quot;&gt;
-    &lt;box orient=&quot;vertical&quot; flex=&quot;1&quot;&gt;
-      &lt;text class=&quot;text-link&quot; onclick=&quot;load_relative_url('query.cgi')&quot; value=&quot;new search&quot;/&gt;
-      &lt;text class=&quot;text-link&quot; onclick=&quot;load_relative_url('report.cgi')&quot; value=&quot;reports&quot;/&gt;
-      &lt;text class=&quot;text-link&quot; onclick=&quot;load_relative_url('enter_bug.cgi')&quot; value=&quot;new [% terms.bug %]&quot;/&gt;
-      &lt;separator class=&quot;thin&quot;/&gt;
-
-[% IF user.id %]
-      &lt;text class=&quot;text-link&quot; onclick=&quot;load_relative_url('userprefs.cgi')&quot; value=&quot;edit prefs&quot;/&gt;
-  [%- IF user.groups.tweakparams %]
-      &lt;text class=&quot;text-link&quot; onclick=&quot;load_relative_url('editparams.cgi')&quot; value=&quot;edit params&quot;/&gt;
-      &lt;text class=&quot;text-link&quot; onclick=&quot;load_relative_url('editsettings.cgi')&quot; value=&quot;edit default preferences&quot;/&gt;
-  [%- END %]
-  [%- IF user.groups.editusers || user.can_bless %]
-      &lt;text class=&quot;text-link&quot; onclick=&quot;load_relative_url('editusers.cgi')&quot; value=&quot;edit users&quot;/&gt;
-  [%- END %]
-  [%- IF Param('useclassification') &amp;&amp; user.groups.editclassifications %]
-      &lt;text class=&quot;text-link&quot; onclick=&quot;load_relative_url('editclassifications.cgi')&quot; value=&quot;edit classifications&quot;/&gt;
-  [%- END %]
-  [%- IF user.groups.editcomponents %]
-      &lt;text class=&quot;text-link&quot; onclick=&quot;load_relative_url('editcomponents.cgi')&quot; value=&quot;edit components&quot;/&gt;
-      &lt;text class=&quot;text-link&quot; onclick=&quot;load_relative_url('editflagtypes.cgi')&quot; value=&quot;edit flags&quot;/&gt;
-      &lt;text class=&quot;text-link&quot; onclick=&quot;load_relative_url('editvalues.cgi')&quot; value=&quot;edit field values&quot;/&gt;
-  [%- END %]
-  [%- IF user.groups.creategroups %]
-      &lt;text class=&quot;text-link&quot; onclick=&quot;load_relative_url('editgroups.cgi')&quot; value=&quot;edit groups&quot;/&gt;
-  [%- END %]
-  [%- IF user.groups.editkeywords %]
-      &lt;text class=&quot;text-link&quot; onclick=&quot;load_relative_url('editkeywords.cgi')&quot; value=&quot;edit keywords&quot;/&gt;
-  [%- END %]
-  [%- IF user.groups.bz_canusewhines %]
-      &lt;text class=&quot;text-link&quot; onclick=&quot;load_relative_url('editwhines.cgi')&quot; value=&quot;edit whining&quot;/&gt;
-  [%- END %]
-  [%- IF user.groups.editcomponents %]
-      &lt;text class=&quot;text-link&quot; onclick=&quot;load_relative_url('sanitycheck.cgi')&quot; value=&quot;sanity check&quot;/&gt;
-  [%- END %]
-  [%- IF user.authorizer.can_logout %]
-      &lt;text class=&quot;text-link&quot; onclick=&quot;load_relative_url('relogin.cgi')&quot; value=&quot;log out [% user.login FILTER html %]&quot;/&gt;
-  [%- END %]
-      &lt;separator class=&quot;thin&quot;/&gt;
-  [%- IF user.showmybugslink %]
-      [% filtered_username = user.login FILTER url_quote %]
-      &lt;text class=&quot;text-link&quot; onclick=&quot;load_relative_url('[% Param('mybugstemplate').replace('%userid%', filtered_username) FILTER js FILTER html %]')&quot; value=&quot;my [% terms.bugs %]&quot;/&gt;
-  [%- END %]
-  [%- IF Param('usevotes') %]
-      &lt;text class=&quot;text-link&quot; onclick=&quot;load_relative_url('votes.cgi?action=show_user')&quot; value=&quot;my votes&quot;/&gt;
-  [%- END %]
-
-  [%- FOREACH q = user.queries %]
-      &lt;text class=&quot;text-link&quot; onclick=&quot;load_relative_url('buglist.cgi?cmdtype=runnamed&amp;amp;namedcmd=[% q.name FILTER url_quote %]')&quot; value=&quot;[% q.name FILTER html %]&quot;/&gt;
-  [% END %]
-
-[% ELSE %]
-      &lt;text class=&quot;text-link&quot; onclick=&quot;load_relative_url('createaccount.cgi')&quot; value=&quot;new user&quot;/&gt;
-      &lt;text class=&quot;text-link&quot; onclick=&quot;load_relative_url('index.cgi?GoAheadAndLogIn=1')&quot; value=&quot;log in&quot;/&gt;
-[% END %]
-
-    &lt;/box&gt;
-  &lt;/box&gt;
-
-  &lt;spring flex=&quot;1&quot;/&gt;
-  &lt;box orient=&quot;horizontal&quot;&gt;
-    &lt;spring flex=&quot;1&quot;/&gt;
-    &lt;html align=&quot;right&quot;&gt;
-      &lt;html:a class=&quot;text-link&quot; href=&quot;[% urlbase FILTER xml %]sidebar.cgi&quot;&gt;reload&lt;/html:a&gt;
-    &lt;/html&gt;
-  &lt;/box&gt;
-&lt;/window&gt;
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultwelcomeadminhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/welcome-admin.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/welcome-admin.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/welcome-admin.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -41,31 +41,28 @@
</span><span class="cx">   parameters for this installation; among others:&lt;/p&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;ul&gt;
</span><del>-    &lt;li&gt;&lt;a href=&quot;editparams.cgi?section=core#maintainer&quot;&gt;maintainer&lt;/a&gt;, the person
-    responsible for this installation if something is running wrong.&lt;/li&gt;
-
-    &lt;li&gt;&lt;a href=&quot;editparams.cgi?section=core#urlbase&quot;&gt;urlbase&lt;/a&gt;, which is the URL
</del><ins>+    &lt;li&gt;&lt;a href=&quot;editparams.cgi?section=core#urlbase_desc&quot;&gt;urlbase&lt;/a&gt;, which is the URL
</ins><span class="cx">     pointing to this installation and which will be used in emails (which is also the
</span><span class="cx">     reason you see this page: as long as this parameter is not set, you will see this
</span><span class="cx">     page again and again).&lt;/li&gt;
</span><span class="cx"> 
</span><del>-    &lt;li&gt;&lt;a href=&quot;editparams.cgi?section=core#cookiepath&quot;&gt;cookiepath&lt;/a&gt; is important
</del><ins>+    &lt;li&gt;&lt;a href=&quot;editparams.cgi?section=core#cookiepath_desc&quot;&gt;cookiepath&lt;/a&gt; is important
</ins><span class="cx">     for your browser to manage your cookies correctly.&lt;/li&gt;
</span><span class="cx"> 
</span><del>-    &lt;li&gt;&lt;a href=&quot;editparams.cgi?section=core#utf8&quot;&gt;utf8&lt;/a&gt; will let you encode all
-    texts into UTF-8, if desired (it is strongly recommended to keep this parameter
-    turned on).&lt;/li&gt;
</del><ins>+    &lt;li&gt;&lt;a href=&quot;editparams.cgi?section=general#maintainer_desc&quot;&gt;maintainer&lt;/a&gt;,
+      the person responsible for this installation if something is
+      running wrongly.&lt;/li&gt;
</ins><span class="cx">   &lt;/ul&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;p&gt;Also important are the following parameters:&lt;/p&gt;
</span><span class="cx"> 
</span><span class="cx">   &lt;ul&gt;
</span><del>-    &lt;li&gt;&lt;a href=&quot;editparams.cgi?section=auth#requirelogin&quot;&gt;requirelogin&lt;/a&gt;, if turned
</del><ins>+    &lt;li&gt;&lt;a href=&quot;editparams.cgi?section=auth#requirelogin_desc&quot;&gt;requirelogin&lt;/a&gt;, if turned
</ins><span class="cx">     on, will protect your installation from users having no account on this installation.
</span><span class="cx">     In other words, users who are not explicitly authenticated with a valid account
</span><span class="cx">     cannot see any data. This is what you want if you want to keep your data private.&lt;/li&gt;
</span><span class="cx"> 
</span><del>-    &lt;li&gt;&lt;a href=&quot;editparams.cgi?section=auth#createemailregexp&quot;&gt;createemailregexp&lt;/a&gt;
</del><ins>+    &lt;li&gt;&lt;a href=&quot;editparams.cgi?section=auth#createemailregexp_desc&quot;&gt;createemailregexp&lt;/a&gt;
</ins><span class="cx">     defines which users are allowed to create an account on this installation. If set
</span><span class="cx">     to &quot;.*&quot; (the default), everybody is free to create his own account. If set to
</span><span class="cx">     &quot;@mycompany.com$&quot;, only users having an account @mycompany.com will be allowed to
</span><span class="lines">@@ -74,7 +71,7 @@
</span><span class="cx">     installation, you must absolutely set this parameter to something different from
</span><span class="cx">     the default.&lt;/li&gt;
</span><span class="cx"> 
</span><del>-    &lt;li&gt;&lt;a href=&quot;editparams.cgi?section=mta#mail_delivery_method&quot;&gt;mail_delivery_method&lt;/a&gt;
</del><ins>+    &lt;li&gt;&lt;a href=&quot;editparams.cgi?section=mta#mail_delivery_method_desc&quot;&gt;mail_delivery_method&lt;/a&gt;
</ins><span class="cx">     defines the method used to send emails, such as sendmail or SMTP. You have to set
</span><span class="cx">     it correctly to send emails.&lt;/li&gt;
</span><span class="cx">   &lt;/ul&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultwhinemailhtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/whine/mail.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/whine/mail.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/whine/mail.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -31,10 +31,6 @@
</span><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="cx"> [% PROCESS 'global/field-descs.none.tmpl' %]
</span><span class="cx"> 
</span><del>-[%# assignee_login_string is a literal string used for getting the 
-  # assignee's name out of the bug data %]
-[% SET assignee_login_string=&quot;map_assigned_to.login_name&quot; %]
-
</del><span class="cx"> &lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;&gt;
</span><span class="cx"> &lt;html&gt;
</span><span class="cx">   &lt;head&gt;
</span><span class="lines">@@ -44,9 +40,9 @@
</span><span class="cx">   &lt;/head&gt;
</span><span class="cx">   &lt;body bgcolor=&quot;#FFFFFF&quot;&gt;
</span><span class="cx"> 
</span><del>-    &lt;p align=&quot;left&quot;&gt;
</del><ins>+    &lt;pre&gt;
</ins><span class="cx">       [% body FILTER html %]
</span><del>-    &lt;/p&gt;
</del><ins>+    &lt;/pre&gt;
</ins><span class="cx"> 
</span><span class="cx">     &lt;p align=&quot;left&quot;&gt;
</span><span class="cx">       [% IF author.login == recipient.login %]
</span><span class="lines">@@ -57,39 +53,42 @@
</span><span class="cx">       [% END %]
</span><span class="cx">     &lt;/p&gt;
</span><span class="cx"> 
</span><ins>+[% IF queries.size %]
+  [% FOREACH query=queries %]
</ins><span class="cx"> 
</span><del>-[% FOREACH query=queries %]
</del><ins>+    &lt;h2&gt;[%+ query.title FILTER html %]&lt;/h2&gt;
</ins><span class="cx"> 
</span><del>-  &lt;h2&gt;[%+ query.title FILTER html %]&lt;/h2&gt;
-
-  &lt;table width=&quot;100%&quot;&gt;
-    &lt;tr&gt;
-      &lt;th align=&quot;left&quot;&gt;ID&lt;/th&gt;
-      &lt;th align=&quot;left&quot;&gt;Sev&lt;/th&gt;
-      &lt;th align=&quot;left&quot;&gt;Pri&lt;/th&gt;
-      &lt;th align=&quot;left&quot;&gt;Plt&lt;/th&gt;
-      &lt;th align=&quot;left&quot;&gt;Assignee&lt;/th&gt;
-      &lt;th align=&quot;left&quot;&gt;Status&lt;/th&gt;
-      &lt;th align=&quot;left&quot;&gt;Resolution&lt;/th&gt;
-      &lt;th align=&quot;left&quot;&gt;Summary&lt;/th&gt;
-    &lt;/tr&gt;
-
-    [% FOREACH bug=query.bugs %]
</del><ins>+    &lt;table width=&quot;100%&quot;&gt;
</ins><span class="cx">       &lt;tr&gt;
</span><del>-        &lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;[%+ urlbase FILTER html %]show_bug.cgi?id=
-            [%- bug.bug_id %]&quot;&gt;[% bug.bug_id %]&lt;/a&gt;&lt;/td&gt;
-        &lt;td align=&quot;left&quot;&gt;[% bug.bug_severity FILTER html %]&lt;/td&gt;
-        &lt;td align=&quot;left&quot;&gt;[% bug.priority FILTER html %]&lt;/td&gt;
-        &lt;td align=&quot;left&quot;&gt;[% bug.rep_platform FILTER html %]&lt;/td&gt;
-        &lt;td align=&quot;left&quot;&gt;[% bug.$assignee_login_string FILTER html %]&lt;/td&gt;
-        &lt;td align=&quot;left&quot;&gt;[% get_status(bug.bug_status) FILTER html %]&lt;/td&gt;
-        &lt;td align=&quot;left&quot;&gt;[% get_resolution(bug.resolution) FILTER html %]&lt;/td&gt;
-        &lt;td align=&quot;left&quot;&gt;[% bug.short_desc FILTER html %]&lt;/td&gt;
</del><ins>+        &lt;th align=&quot;left&quot;&gt;ID&lt;/th&gt;
+        &lt;th align=&quot;left&quot;&gt;Sev&lt;/th&gt;
+        &lt;th align=&quot;left&quot;&gt;Pri&lt;/th&gt; 
+        &lt;th align=&quot;left&quot;&gt;Plt&lt;/th&gt;
+        &lt;th align=&quot;left&quot;&gt;Assignee&lt;/th&gt;
+        &lt;th align=&quot;left&quot;&gt;Status&lt;/th&gt;
+        &lt;th align=&quot;left&quot;&gt;Resolution&lt;/th&gt;
+        &lt;th align=&quot;left&quot;&gt;Summary&lt;/th&gt;
</ins><span class="cx">       &lt;/tr&gt;
</span><del>-    [% END %]
-  &lt;/table&gt;
-[% END %]
</del><span class="cx"> 
</span><ins>+      [% FOREACH bug=query.bugs %]
+        &lt;tr&gt;
+          &lt;td align=&quot;left&quot;&gt;&lt;a href=&quot;[%+ urlbase FILTER html %]show_bug.cgi?id=
+              [%- bug.bug_id %]&quot;&gt;[% bug.bug_id %]&lt;/a&gt;&lt;/td&gt;
+          &lt;td align=&quot;left&quot;&gt;[% display_value(&quot;bug_severity&quot;, bug.bug_severity) FILTER html %]&lt;/td&gt;
+          &lt;td align=&quot;left&quot;&gt;[% display_value(&quot;priority&quot;, bug.priority) FILTER html %]&lt;/td&gt;
+          &lt;td align=&quot;left&quot;&gt;[% display_value(&quot;rep_platform&quot;, bug.rep_platform) FILTER html %]&lt;/td&gt;
+          &lt;td align=&quot;left&quot;&gt;[% bug.assigned_to FILTER html %]&lt;/td&gt;
+          &lt;td align=&quot;left&quot;&gt;[% display_value(&quot;bug_status&quot;, bug.bug_status) FILTER html %]&lt;/td&gt;
+          &lt;td align=&quot;left&quot;&gt;[% display_value(&quot;resolution&quot;, bug.resolution) FILTER html %]&lt;/td&gt;
+          &lt;td align=&quot;left&quot;&gt;[% bug.short_desc FILTER html %]&lt;/td&gt;
+        &lt;/tr&gt;
+      [% END %]
+    &lt;/table&gt;
+  [% END %]
+[% ELSE %]
+
+  &lt;h3&gt;No [% terms.bugs %] were found that matched the search criteria.&lt;/h3&gt;
+[% END %]
</ins><span class="cx">   &lt;/body&gt;
</span><span class="cx"> &lt;/html&gt;
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultwhinemailtxttmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/whine/mail.txt.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/whine/mail.txt.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/whine/mail.txt.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -31,10 +31,6 @@
</span><span class="cx"> [% PROCESS global/variables.none.tmpl %]
</span><span class="cx"> [% PROCESS 'global/field-descs.none.tmpl' %]
</span><span class="cx"> 
</span><del>-[%# assignee_login_string is a literal string used for getting the 
-  # assignee's name out of the bug data %]
-[% SET assignee_login_string=&quot;map_assigned_to.login_name&quot; %]
-
</del><span class="cx"> [% body %]
</span><span class="cx"> 
</span><span class="cx"> [% IF author.login == recipient.login %]
</span><span class="lines">@@ -44,26 +40,29 @@
</span><span class="cx">   This search was scheduled by [% author.login %].
</span><span class="cx"> [% END %]
</span><span class="cx"> 
</span><ins>+[% IF queries.size %]
+  [% FOREACH query=queries %]
</ins><span class="cx"> 
</span><del>-[% FOREACH query=queries %]
-
</del><span class="cx"> [%+ query.title +%]
</span><span class="cx"> [%+ &quot;-&quot; FILTER repeat(query.title.length) %]
</span><span class="cx"> 
</span><del>- [% FOREACH bug=query.bugs %]
</del><ins>+  [% FOREACH bug=query.bugs %]
</ins><span class="cx">   [% terms.Bug +%] [%+ bug.bug_id %]:
</span><span class="cx">   [%+ urlbase %]show_bug.cgi?id=[% bug.bug_id +%]
</span><del>-  Priority: [%+ bug.priority -%]
-  Severity: [%+ bug.bug_severity -%]
-  Platform: [%+ bug.rep_platform %]
-  Assignee: [%+ bug.$assignee_login_string %]
-    Status: [%+ get_status(bug.bug_status) %]
-            [%- IF bug.resolution -%] Resolution: [% get_resolution(bug.resolution) -%]
-                                [%- END %]
</del><ins>+  Priority: [%+ display_value(&quot;priority&quot;, bug.priority) -%]
+  Severity: [%+ display_value(&quot;bug_severity&quot;, bug.bug_severity) -%]
+  Platform: [%+ display_value(&quot;rep_platform&quot;, bug.rep_platform) %]
+  Assignee: [%+ bug.assigned_to %]
+    Status: [%+ display_value(&quot;bug_status&quot;, bug.bug_status) %]
+            [%- IF bug.resolution -%] Resolution: [% display_value(&quot;resolution&quot;, bug.resolution) -%]
+            [%- END %]
</ins><span class="cx">    Summary: [% bug.short_desc %]
</span><span class="cx"> 
</span><del>- [% END %]
</del><ins>+   [% END %]
</ins><span class="cx"> 
</span><ins>+  [% END %]
+[% ELSE %]
+
+  No [% terms.bugs %] were found that matched the search criteria.
</ins><span class="cx"> [% END %]
</span><span class="cx"> 
</span><del>-
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultwhinemultipartmimetxttmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/whine/multipart-mime.txt.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/whine/multipart-mime.txt.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/whine/multipart-mime.txt.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -35,6 +35,7 @@
</span><span class="cx"> Subject: [[% terms.Bugzilla %]] [% subject %]
</span><span class="cx"> MIME-Version: 1.0
</span><span class="cx"> Content-Type: multipart/alternative; boundary=&quot;[% boundary %]&quot;
</span><ins>+X-Bugzilla-Type: whine
</ins><span class="cx"> 
</span><span class="cx"> 
</span><span class="cx"> This is a MIME multipart message.  It is possible that your mail program
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtemplateendefaultwhineschedulehtmltmpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/template/en/default/whine/schedule.html.tmpl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/template/en/default/whine/schedule.html.tmpl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/template/en/default/whine/schedule.html.tmpl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -72,11 +72,7 @@
</span><span class="cx"> &lt;/p&gt;
</span><span class="cx"> 
</span><span class="cx"> &lt;p&gt;
</span><del>-  [% IF Param(&quot;timezone&quot;) %]
-    All times are server local time ([% Param(&quot;timezone&quot;) FILTER upper %]).
-  [% ELSE %]
-    All times are server local time.
-  [% END %]
</del><ins>+  All times are server local time ([% local_timezone FILTER html %]).
</ins><span class="cx"> &lt;/p&gt;
</span><span class="cx"> 
</span><span class="cx"> &lt;form method=&quot;post&quot; action=&quot;editwhines.cgi&quot;&gt;
</span><span class="lines">@@ -128,6 +124,16 @@
</span><span class="cx">     &lt;/td&gt;
</span><span class="cx">   &lt;/tr&gt;
</span><span class="cx"> 
</span><ins>+  &lt;tr&gt;
+    &lt;td valign=&quot;top&quot; align=&quot;right&quot;&gt;
+      Send a message even if there are no [% terms.bugs %] in the search result:
+    &lt;/td&gt;
+    &lt;td colspan=&quot;2&quot;&gt;
+      &lt;input type=&quot;checkbox&quot; name=&quot;event_[% event.key %]_mailifnobugs&quot;
+        [%- IF event.value.mailifnobugs == 1 %] checked [% END %]&gt;
+    &lt;/td&gt;
+  &lt;/tr&gt;
+
</ins><span class="cx">   [% IF event.value.schedule.size == 0 %]
</span><span class="cx"> 
</span><span class="cx">     &lt;tr&gt;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtestserverpl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/testserver.pl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/testserver.pl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/testserver.pl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -21,13 +21,7 @@
</span><span class="cx"> use strict;
</span><span class="cx"> use lib qw(. lib);
</span><span class="cx"> 
</span><del>-BEGIN {
-    my $envpath = $ENV{'PATH'};
-    require Bugzilla;
-    # $ENV{'PATH'} is required by the 'ps' command to run correctly.
-    $ENV{'PATH'} = $envpath;
-}
-
</del><ins>+use Bugzilla;
</ins><span class="cx"> use Bugzilla::Constants;
</span><span class="cx"> 
</span><span class="cx"> use Socket;
</span><span class="lines">@@ -48,7 +42,7 @@
</span><span class="cx"> # Try to determine the GID used by the web server.
</span><span class="cx"> my @pscmds = ('ps -eo comm,gid', 'ps -acxo command,gid', 'ps -acxo command,rgid');
</span><span class="cx"> my $sgid = 0;
</span><del>-if ($^O !~ /MSWin32/i) {
</del><ins>+if (!ON_WINDOWS) {
</ins><span class="cx">     foreach my $pscmd (@pscmds) {
</span><span class="cx">         open PH, &quot;$pscmd 2&gt;/dev/null |&quot;;
</span><span class="cx">         while (my $line = &lt;PH&gt;) {
</span><span class="lines">@@ -65,7 +59,8 @@
</span><span class="cx"> my $webservergroup = Bugzilla-&gt;localconfig-&gt;{webservergroup};
</span><span class="cx"> if ($webservergroup =~ /^(\d+)$/) {
</span><span class="cx">     $webgroupnum = $1;
</span><del>-} else {
</del><ins>+}
+else {
</ins><span class="cx">     eval { $webgroupnum = (getgrnam $webservergroup) || 0; };
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -76,30 +71,33 @@
</span><span class="cx"> &quot;WARNING \$webservergroup is set to an empty string.
</span><span class="cx"> That is a very insecure practice. Please refer to the
</span><span class="cx"> Bugzilla documentation.\n&quot;;
</span><del>-    } elsif ($webgroupnum == $sgid) {
</del><ins>+    }
+    elsif ($webgroupnum == $sgid || Bugzilla-&gt;localconfig-&gt;{use_suexec}) {
</ins><span class="cx">         print &quot;TEST-OK Webserver is running under group id in \$webservergroup.\n&quot;;
</span><del>-    } else {
</del><ins>+    }
+    else {
</ins><span class="cx">         print 
</span><span class="cx"> &quot;TEST-WARNING Webserver is running under group id not matching \$webservergroup.
</span><span class="cx"> This if the tests below fail, this is probably the problem.
</span><span class="cx"> Please refer to the web server configuration section of the Bugzilla guide. 
</span><span class="cx"> If you are using virtual hosts or suexec, this warning may not apply.\n&quot;;
</span><span class="cx">     }
</span><del>-} elsif ($^O !~ /MSWin32/i) {
</del><ins>+}
+elsif (!ON_WINDOWS) {
</ins><span class="cx">    print
</span><span class="cx"> &quot;TEST-WARNING Failed to find the GID for the 'httpd' process, unable
</span><span class="cx"> to validate webservergroup.\n&quot;;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> 
</span><del>-# Try to fetch a static file (front.png)
</del><ins>+# Try to fetch a static file (padlock.png)
</ins><span class="cx"> $ARGV[0] =~ s/\/$//;
</span><del>-my $url = $ARGV[0] . &quot;/skins/standard/index/front.png&quot;;
</del><ins>+my $url = $ARGV[0] . &quot;/images/padlock.png&quot;;
</ins><span class="cx"> if (fetch($url)) {
</span><del>-    print &quot;TEST-OK Got front picture.\n&quot;;
</del><ins>+    print &quot;TEST-OK Got padlock picture.\n&quot;;
</ins><span class="cx"> } else {
</span><span class="cx">     print 
</span><del>-&quot;TEST-FAILED Fetch of skins/standard/index/front.png failed
</del><ins>+&quot;TEST-FAILED Fetch of images/padlock.png failed
</ins><span class="cx"> Your web server could not fetch $url.
</span><span class="cx"> Check your web server configuration and try again.\n&quot;;
</span><span class="cx">     exit(1);
</span><span class="lines">@@ -140,7 +138,7 @@
</span><span class="cx"> 
</span><span class="cx">     # Ensure major versions of GD and libgd match
</span><span class="cx">     # Windows's GD module include libgd.dll, guaranteed to match
</span><del>-    if ($^O !~ /MSWin32/i) {
</del><ins>+    if (!ON_WINDOWS) {
</ins><span class="cx">         my $gdlib = `gdlib-config --version 2&gt;&amp;1` || &quot;&quot;;
</span><span class="cx">         $gdlib =~ s/\n$//;
</span><span class="cx">         if (!$gdlib) {
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgtokencgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/token.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/token.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/token.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -37,6 +37,7 @@
</span><span class="cx"> use Bugzilla::Token;
</span><span class="cx"> use Bugzilla::User;
</span><span class="cx"> 
</span><ins>+use Date::Format;
</ins><span class="cx"> use Date::Parse;
</span><span class="cx"> 
</span><span class="cx"> my $dbh = Bugzilla-&gt;dbh;
</span><span class="lines">@@ -44,6 +45,9 @@
</span><span class="cx"> local our $template = Bugzilla-&gt;template;
</span><span class="cx"> local our $vars = {};
</span><span class="cx"> 
</span><ins>+my $action = $cgi-&gt;param('a');
+my $token = $cgi-&gt;param('t');
+
</ins><span class="cx"> Bugzilla-&gt;login(LOGIN_OPTIONAL);
</span><span class="cx"> 
</span><span class="cx"> ################################################################################
</span><span class="lines">@@ -52,47 +56,40 @@
</span><span class="cx"> 
</span><span class="cx"> # Throw an error if the form does not contain an &quot;action&quot; field specifying
</span><span class="cx"> # what the user wants to do.
</span><del>-$cgi-&gt;param('a') || ThrowCodeError(&quot;unknown_action&quot;);
</del><ins>+$action || ThrowUserError('unknown_action');
</ins><span class="cx"> 
</span><del>-# Assign the action to a global variable.
-$::action = $cgi-&gt;param('a');
-
</del><span class="cx"> # If a token was submitted, make sure it is a valid token that exists in the
</span><span class="cx"> # database and is the correct type for the action being taken.
</span><del>-if ($cgi-&gt;param('t')) {
-  # Assign the token and its SQL quoted equivalent to global variables.
-  $::token = $cgi-&gt;param('t');
-  
-  # Make sure the token contains only valid characters in the right amount.
-  # validate_password will throw an error if token is invalid
-  validate_password($::token);
-
</del><ins>+if ($token) {
</ins><span class="cx">   Bugzilla::Token::CleanTokenTable();
</span><span class="cx"> 
</span><ins>+  # It's safe to detaint the token as it's used in a placeholder.
+  trick_taint($token);
+
</ins><span class="cx">   # Make sure the token exists in the database.
</span><span class="cx">   my ($tokentype) = $dbh-&gt;selectrow_array('SELECT tokentype FROM tokens
</span><del>-                                           WHERE token = ?', undef, $::token);
</del><ins>+                                           WHERE token = ?', undef, $token);
</ins><span class="cx">   $tokentype || ThrowUserError(&quot;token_does_not_exist&quot;);
</span><span class="cx"> 
</span><span class="cx">   # Make sure the token is the correct type for the action being taken.
</span><del>-  if ( grep($::action eq $_ , qw(cfmpw cxlpw chgpw)) &amp;&amp; $tokentype ne 'password' ) {
-    Bugzilla::Token::Cancel($::token, &quot;wrong_token_for_changing_passwd&quot;);
</del><ins>+  if ( grep($action eq $_ , qw(cfmpw cxlpw chgpw)) &amp;&amp; $tokentype ne 'password' ) {
+    Bugzilla::Token::Cancel($token, &quot;wrong_token_for_changing_passwd&quot;);
</ins><span class="cx">     ThrowUserError(&quot;wrong_token_for_changing_passwd&quot;);
</span><span class="cx">   }
</span><del>-  if ( ($::action eq 'cxlem') 
</del><ins>+  if ( ($action eq 'cxlem')
</ins><span class="cx">       &amp;&amp; (($tokentype ne 'emailold') &amp;&amp; ($tokentype ne 'emailnew')) ) {
</span><del>-    Bugzilla::Token::Cancel($::token, &quot;wrong_token_for_cancelling_email_change&quot;);
</del><ins>+    Bugzilla::Token::Cancel($token, &quot;wrong_token_for_cancelling_email_change&quot;);
</ins><span class="cx">     ThrowUserError(&quot;wrong_token_for_cancelling_email_change&quot;);
</span><span class="cx">   }
</span><del>-  if ( grep($::action eq $_ , qw(cfmem chgem)) 
</del><ins>+  if ( grep($action eq $_ , qw(cfmem chgem))
</ins><span class="cx">       &amp;&amp; ($tokentype ne 'emailnew') ) {
</span><del>-    Bugzilla::Token::Cancel($::token, &quot;wrong_token_for_confirming_email_change&quot;);
</del><ins>+    Bugzilla::Token::Cancel($token, &quot;wrong_token_for_confirming_email_change&quot;);
</ins><span class="cx">     ThrowUserError(&quot;wrong_token_for_confirming_email_change&quot;);
</span><span class="cx">   }
</span><del>-  if (($::action =~ /^(request|confirm|cancel)_new_account$/)
</del><ins>+  if (($action =~ /^(request|confirm|cancel)_new_account$/)
</ins><span class="cx">       &amp;&amp; ($tokentype ne 'account'))
</span><span class="cx">   {
</span><del>-      Bugzilla::Token::Cancel($::token, 'wrong_token_for_creating_account');
</del><ins>+      Bugzilla::Token::Cancel($token, 'wrong_token_for_creating_account');
</ins><span class="cx">       ThrowUserError('wrong_token_for_creating_account');
</span><span class="cx">   }
</span><span class="cx"> }
</span><span class="lines">@@ -102,7 +99,7 @@
</span><span class="cx"> # their login name and it exists in the database, and that the DB module is in
</span><span class="cx"> # the list of allowed verification methods.
</span><span class="cx"> my $user_account;
</span><del>-if ( $::action eq 'reqpw' ) {
</del><ins>+if ( $action eq 'reqpw' ) {
</ins><span class="cx">     my $login_name = $cgi-&gt;param('loginname')
</span><span class="cx">                        || ThrowUserError(&quot;login_needed_for_password_change&quot;);
</span><span class="cx"> 
</span><span class="lines">@@ -115,18 +112,26 @@
</span><span class="cx">         || ThrowUserError('illegal_email_address', {addr =&gt; $login_name});
</span><span class="cx"> 
</span><span class="cx">     $user_account = Bugzilla::User-&gt;check($login_name);
</span><ins>+
+    # Make sure the user account is active.
+    if (!$user_account-&gt;is_enabled) {
+        ThrowUserError('account_disabled',
+                       {disabled_reason =&gt; get_text('account_disabled', {account =&gt; $login_name})});
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> # If the user is changing their password, make sure they submitted a new
</span><span class="cx"> # password and that the new password is valid.
</span><span class="cx"> my $password;
</span><del>-if ( $::action eq 'chgpw' ) {
</del><ins>+if ( $action eq 'chgpw' ) {
</ins><span class="cx">     $password = $cgi-&gt;param('password');
</span><span class="cx">     defined $password
</span><span class="cx">       &amp;&amp; defined $cgi-&gt;param('matchpassword')
</span><span class="cx">       || ThrowUserError(&quot;require_new_password&quot;);
</span><span class="cx"> 
</span><span class="cx">     validate_password($password, $cgi-&gt;param('matchpassword'));
</span><ins>+    # Make sure that these never show up in the UI under any circumstances.
+    $cgi-&gt;delete('password', 'matchpassword');
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> ################################################################################
</span><span class="lines">@@ -137,31 +142,28 @@
</span><span class="cx"> # determines what the user wants to do.  The code below checks the value of
</span><span class="cx"> # that variable and runs the appropriate code.
</span><span class="cx"> 
</span><del>-if ($::action eq 'reqpw') { 
</del><ins>+if ($action eq 'reqpw') {
</ins><span class="cx">     requestChangePassword($user_account);
</span><del>-} elsif ($::action eq 'cfmpw') { 
-    confirmChangePassword(); 
-} elsif ($::action eq 'cxlpw') { 
-    cancelChangePassword(); 
-} elsif ($::action eq 'chgpw') { 
-    changePassword($password);
-} elsif ($::action eq 'cfmem') {
-    confirmChangeEmail();
-} elsif ($::action eq 'cxlem') {
-    cancelChangeEmail();
-} elsif ($::action eq 'chgem') {
-    changeEmail();
-} elsif ($::action eq 'request_new_account') {
-    request_create_account();
-} elsif ($::action eq 'confirm_new_account') {
-    confirm_create_account();
-} elsif ($::action eq 'cancel_new_account') {
-    cancel_create_account();
</del><ins>+} elsif ($action eq 'cfmpw') {
+    confirmChangePassword($token);
+} elsif ($action eq 'cxlpw') {
+    cancelChangePassword($token);
+} elsif ($action eq 'chgpw') {
+    changePassword($token, $password);
+} elsif ($action eq 'cfmem') {
+    confirmChangeEmail($token);
+} elsif ($action eq 'cxlem') {
+    cancelChangeEmail($token);
+} elsif ($action eq 'chgem') {
+    changeEmail($token);
+} elsif ($action eq 'request_new_account') {
+    request_create_account($token);
+} elsif ($action eq 'confirm_new_account') {
+    confirm_create_account($token);
+} elsif ($action eq 'cancel_new_account') {
+    cancel_create_account($token);
</ins><span class="cx"> } else { 
</span><del>-    # If the action that the user wants to take (specified in the &quot;a&quot; form field)
-    # is none of the above listed actions, display an error telling the user 
-    # that we do not understand what they would like to do.
-    ThrowCodeError(&quot;unknown_action&quot;, { action =&gt; $::action });
</del><ins>+    ThrowUserError('unknown_action', {action =&gt; $action});
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> exit;
</span><span class="lines">@@ -182,16 +184,18 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub confirmChangePassword {
</span><del>-    $vars-&gt;{'token'} = $::token;
-    
</del><ins>+    my $token = shift;
+    $vars-&gt;{'token'} = $token;
+
</ins><span class="cx">     print $cgi-&gt;header();
</span><span class="cx">     $template-&gt;process(&quot;account/password/set-forgotten-password.html.tmpl&quot;, $vars)
</span><span class="cx">       || ThrowTemplateError($template-&gt;error());
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-sub cancelChangePassword {    
</del><ins>+sub cancelChangePassword {
+    my $token = shift;
</ins><span class="cx">     $vars-&gt;{'message'} = &quot;password_change_canceled&quot;;
</span><del>-    Bugzilla::Token::Cancel($::token, $vars-&gt;{'message'});
</del><ins>+    Bugzilla::Token::Cancel($token, $vars-&gt;{'message'});
</ins><span class="cx"> 
</span><span class="cx">     print $cgi-&gt;header();
</span><span class="cx">     $template-&gt;process(&quot;global/message.html.tmpl&quot;, $vars)
</span><span class="lines">@@ -199,7 +203,7 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub changePassword {
</span><del>-    my ($password) = @_;
</del><ins>+    my ($token, $password) = @_;
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx"> 
</span><span class="cx">     # Create a crypted version of the new password
</span><span class="lines">@@ -207,7 +211,7 @@
</span><span class="cx"> 
</span><span class="cx">     # Get the user's ID from the tokens table.
</span><span class="cx">     my ($userid) = $dbh-&gt;selectrow_array('SELECT userid FROM tokens
</span><del>-                                          WHERE token = ?', undef, $::token);
</del><ins>+                                          WHERE token = ?', undef, $token);
</ins><span class="cx">     
</span><span class="cx">     # Update the user's password in the profiles table and delete the token
</span><span class="cx">     # from the tokens table.
</span><span class="lines">@@ -216,7 +220,7 @@
</span><span class="cx">                SET      cryptpassword = ?
</span><span class="cx">                WHERE    userid = ?},
</span><span class="cx">              undef, ($cryptedpassword, $userid) );
</span><del>-    $dbh-&gt;do('DELETE FROM tokens WHERE token = ?', undef, $::token);
</del><ins>+    $dbh-&gt;do('DELETE FROM tokens WHERE token = ?', undef, $token);
</ins><span class="cx">     $dbh-&gt;bz_commit_transaction();
</span><span class="cx"> 
</span><span class="cx">     Bugzilla-&gt;logout_user_by_id($userid);
</span><span class="lines">@@ -229,22 +233,22 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub confirmChangeEmail {
</span><del>-    # Return HTTP response headers.
</del><ins>+    my $token = shift;
+    $vars-&gt;{'token'} = $token;
+
</ins><span class="cx">     print $cgi-&gt;header();
</span><del>-
-    $vars-&gt;{'token'} = $::token;
-
</del><span class="cx">     $template-&gt;process(&quot;account/email/confirm.html.tmpl&quot;, $vars)
</span><span class="cx">       || ThrowTemplateError($template-&gt;error());
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub changeEmail {
</span><ins>+    my $token = shift;
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx"> 
</span><span class="cx">     # Get the user's ID from the tokens table.
</span><span class="cx">     my ($userid, $eventdata) = $dbh-&gt;selectrow_array(
</span><span class="cx">                                  q{SELECT userid, eventdata FROM tokens
</span><del>-                                   WHERE token = ?}, undef, $::token);
</del><ins>+                                   WHERE token = ?}, undef, $token);
</ins><span class="cx">     my ($old_email, $new_email) = split(/:/,$eventdata);
</span><span class="cx"> 
</span><span class="cx">     # Check the user entered the correct old email address
</span><span class="lines">@@ -255,7 +259,7 @@
</span><span class="cx">     # confirmed initially so cancel token if it is not still available
</span><span class="cx">     if (! is_available_username($new_email,$old_email)) {
</span><span class="cx">         $vars-&gt;{'email'} = $new_email; # Needed for Bugzilla::Token::Cancel's mail
</span><del>-        Bugzilla::Token::Cancel($::token, &quot;account_exists&quot;, $vars);
</del><ins>+        Bugzilla::Token::Cancel($token, &quot;account_exists&quot;, $vars);
</ins><span class="cx">         ThrowUserError(&quot;account_exists&quot;, { email =&gt; $new_email } );
</span><span class="cx">     } 
</span><span class="cx"> 
</span><span class="lines">@@ -266,15 +270,16 @@
</span><span class="cx">                SET      login_name = ?
</span><span class="cx">                WHERE    userid = ?},
</span><span class="cx">              undef, ($new_email, $userid));
</span><del>-    $dbh-&gt;do('DELETE FROM tokens WHERE token = ?', undef, $::token);
</del><ins>+    $dbh-&gt;do('DELETE FROM tokens WHERE token = ?', undef, $token);
</ins><span class="cx">     $dbh-&gt;do(q{DELETE FROM tokens WHERE userid = ?
</span><span class="cx">                AND tokentype = 'emailnew'}, undef, $userid);
</span><del>-    $dbh-&gt;bz_commit_transaction();
</del><span class="cx"> 
</span><span class="cx">     # The email address has been changed, so we need to rederive the groups
</span><span class="cx">     my $user = new Bugzilla::User($userid);
</span><span class="cx">     $user-&gt;derive_regexp_groups;
</span><span class="cx"> 
</span><ins>+    $dbh-&gt;bz_commit_transaction();
+
</ins><span class="cx">     # Return HTTP response headers.
</span><span class="cx">     print $cgi-&gt;header();
</span><span class="cx"> 
</span><span class="lines">@@ -287,12 +292,15 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub cancelChangeEmail {
</span><ins>+    my $token = shift;
</ins><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx"> 
</span><ins>+    $dbh-&gt;bz_start_transaction();
+
</ins><span class="cx">     # Get the user's ID from the tokens table.
</span><span class="cx">     my ($userid, $tokentype, $eventdata) = $dbh-&gt;selectrow_array(
</span><span class="cx">                               q{SELECT userid, tokentype, eventdata FROM tokens
</span><del>-                                WHERE token = ?}, undef, $::token);
</del><ins>+                                WHERE token = ?}, undef, $token);
</ins><span class="cx">     my ($old_email, $new_email) = split(/:/,$eventdata);
</span><span class="cx"> 
</span><span class="cx">     if($tokentype eq &quot;emailold&quot;) {
</span><span class="lines">@@ -304,16 +312,15 @@
</span><span class="cx">         
</span><span class="cx">         # check to see if it has been altered
</span><span class="cx">         if($actualemail ne $old_email) {
</span><ins>+            # XXX - This is NOT safe - if A has change to B, another profile
+            # could have grabbed A's username in the meantime.
+            # The DB constraint will catch this, though
</ins><span class="cx">             $dbh-&gt;do(q{UPDATE   profiles
</span><span class="cx">                        SET      login_name = ?
</span><span class="cx">                        WHERE    userid = ?},
</span><span class="cx">                      undef, ($old_email, $userid));
</span><span class="cx"> 
</span><span class="cx">             # email has changed, so rederive groups
</span><del>-            # Note that this is done _after_ the tables are unlocked
-            # This is sort of a race condition (given the lack of transactions)
-            # but the user had access to it just now, so it's not a security
-            # issue
</del><span class="cx"> 
</span><span class="cx">             my $user = new Bugzilla::User($userid);
</span><span class="cx">             $user-&gt;derive_regexp_groups;
</span><span class="lines">@@ -327,12 +334,14 @@
</span><span class="cx"> 
</span><span class="cx">     $vars-&gt;{'old_email'} = $old_email;
</span><span class="cx">     $vars-&gt;{'new_email'} = $new_email;
</span><del>-    Bugzilla::Token::Cancel($::token, $vars-&gt;{'message'}, $vars);
</del><ins>+    Bugzilla::Token::Cancel($token, $vars-&gt;{'message'}, $vars);
</ins><span class="cx"> 
</span><span class="cx">     $dbh-&gt;do(q{DELETE FROM tokens WHERE userid = ?
</span><span class="cx">                AND tokentype = 'emailold' OR tokentype = 'emailnew'},
</span><span class="cx">              undef, $userid);
</span><span class="cx"> 
</span><ins>+    $dbh-&gt;bz_commit_transaction();
+
</ins><span class="cx">     # Return HTTP response headers.
</span><span class="cx">     print $cgi-&gt;header();
</span><span class="cx"> 
</span><span class="lines">@@ -341,29 +350,29 @@
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub request_create_account {
</span><del>-    my (undef, $date, $login_name) = Bugzilla::Token::GetTokenData($::token);
-    $vars-&gt;{'token'} = $::token;
</del><ins>+    my $token = shift;
+
+    Bugzilla-&gt;user-&gt;check_account_creation_enabled;
+    my (undef, $date, $login_name) = Bugzilla::Token::GetTokenData($token);
+    $vars-&gt;{'token'} = $token;
</ins><span class="cx">     $vars-&gt;{'email'} = $login_name . Bugzilla-&gt;params-&gt;{'emailsuffix'};
</span><del>-    $vars-&gt;{'date'} = str2time($date);
</del><ins>+    $vars-&gt;{'expiration_ts'} = ctime(str2time($date) + MAX_TOKEN_AGE * 86400);
</ins><span class="cx"> 
</span><del>-    # When 'ssl' equals 'always' or 'authenticated sessions', 
-    # we want this form to always be over SSL.
-    if ($cgi-&gt;protocol ne 'https' &amp;&amp; Bugzilla-&gt;params-&gt;{'sslbase'} ne ''
-        &amp;&amp; Bugzilla-&gt;params-&gt;{'ssl'} ne 'never')
-    {
-        $cgi-&gt;require_https(Bugzilla-&gt;params-&gt;{'sslbase'});
-    }
</del><span class="cx">     print $cgi-&gt;header();
</span><del>-
</del><span class="cx">     $template-&gt;process('account/email/confirm-new.html.tmpl', $vars)
</span><span class="cx">       || ThrowTemplateError($template-&gt;error());
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub confirm_create_account {
</span><del>-    my (undef, undef, $login_name) = Bugzilla::Token::GetTokenData($::token);
</del><ins>+    my $token = shift;
</ins><span class="cx"> 
</span><ins>+    Bugzilla-&gt;user-&gt;check_account_creation_enabled;
+    my (undef, undef, $login_name) = Bugzilla::Token::GetTokenData($token);
+
</ins><span class="cx">     my $password = $cgi-&gt;param('passwd1') || '';
</span><span class="cx">     validate_password($password, $cgi-&gt;param('passwd2') || '');
</span><ins>+    # Make sure that these never show up anywhere in the UI.
+    $cgi-&gt;delete('passwd1', 'passwd2');
</ins><span class="cx"> 
</span><span class="cx">     my $otheruser = Bugzilla::User-&gt;create({
</span><span class="cx">         login_name =&gt; $login_name, 
</span><span class="lines">@@ -371,25 +380,31 @@
</span><span class="cx">         cryptpassword =&gt; $password});
</span><span class="cx"> 
</span><span class="cx">     # Now delete this token.
</span><del>-    delete_token($::token);
</del><ins>+    delete_token($token);
</ins><span class="cx"> 
</span><span class="cx">     # Let the user know that his user account has been successfully created.
</span><span class="cx">     $vars-&gt;{'message'} = 'account_created';
</span><span class="cx">     $vars-&gt;{'otheruser'} = $otheruser;
</span><del>-    $vars-&gt;{'login_info'} = 1;
</del><span class="cx"> 
</span><ins>+    # Log in the new user using credentials he just gave.
+    $cgi-&gt;param('Bugzilla_login', $otheruser-&gt;login);
+    $cgi-&gt;param('Bugzilla_password', $password);
+    Bugzilla-&gt;login(LOGIN_OPTIONAL);
+
</ins><span class="cx">     print $cgi-&gt;header();
</span><span class="cx"> 
</span><del>-    $template-&gt;process('global/message.html.tmpl', $vars)
</del><ins>+    $template-&gt;process('index.html.tmpl', $vars)
</ins><span class="cx">       || ThrowTemplateError($template-&gt;error());
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub cancel_create_account {
</span><del>-    my (undef, undef, $login_name) = Bugzilla::Token::GetTokenData($::token);
</del><ins>+    my $token = shift;
</ins><span class="cx"> 
</span><ins>+    my (undef, undef, $login_name) = Bugzilla::Token::GetTokenData($token);
+
</ins><span class="cx">     $vars-&gt;{'message'} = 'account_creation_canceled';
</span><span class="cx">     $vars-&gt;{'account'} = $login_name;
</span><del>-    Bugzilla::Token::Cancel($::token, $vars-&gt;{'message'});
</del><ins>+    Bugzilla::Token::Cancel($token, $vars-&gt;{'message'});
</ins><span class="cx"> 
</span><span class="cx">     print $cgi-&gt;header();
</span><span class="cx">     $template-&gt;process('global/message.html.tmpl', $vars)
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorguserprefscgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/userprefs.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/userprefs.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/userprefs.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -27,6 +27,7 @@
</span><span class="cx"> use lib qw(. lib);
</span><span class="cx"> 
</span><span class="cx"> use Bugzilla;
</span><ins>+use Bugzilla::BugMail;
</ins><span class="cx"> use Bugzilla::Constants;
</span><span class="cx"> use Bugzilla::Search;
</span><span class="cx"> use Bugzilla::Util;
</span><span class="lines">@@ -56,8 +57,9 @@
</span><span class="cx">        Bugzilla::Token::CleanTokenTable();
</span><span class="cx"> 
</span><span class="cx">         my @token = $dbh-&gt;selectrow_array(
</span><del>-            &quot;SELECT tokentype, issuedate + &quot; .
-                    $dbh-&gt;sql_interval(MAX_TOKEN_AGE, 'DAY') . &quot;, eventdata
</del><ins>+            &quot;SELECT tokentype, &quot; .
+                    $dbh-&gt;sql_date_math('issuedate', '+', MAX_TOKEN_AGE, 'DAY')
+                    . &quot;, eventdata
</ins><span class="cx">                FROM tokens
</span><span class="cx">               WHERE userid = ?
</span><span class="cx">                 AND tokentype LIKE 'email%'
</span><span class="lines">@@ -79,36 +81,26 @@
</span><span class="cx">     my $dbh = Bugzilla-&gt;dbh;
</span><span class="cx">     my $user = Bugzilla-&gt;user;
</span><span class="cx"> 
</span><ins>+    my $oldpassword = $cgi-&gt;param('old_password');
</ins><span class="cx">     my $pwd1 = $cgi-&gt;param('new_password1');
</span><span class="cx">     my $pwd2 = $cgi-&gt;param('new_password2');
</span><ins>+    my $new_login_name = trim($cgi-&gt;param('new_login_name'));
</ins><span class="cx"> 
</span><span class="cx">     if ($user-&gt;authorizer-&gt;can_change_password
</span><del>-        &amp;&amp; ($cgi-&gt;param('Bugzilla_password') ne &quot;&quot; || $pwd1 ne &quot;&quot; || $pwd2 ne &quot;&quot;))
</del><ins>+        &amp;&amp; ($oldpassword ne &quot;&quot; || $pwd1 ne &quot;&quot; || $pwd2 ne &quot;&quot;))
</ins><span class="cx">     {
</span><del>-        my ($oldcryptedpwd) = $dbh-&gt;selectrow_array(
-                        q{SELECT cryptpassword FROM profiles WHERE userid = ?},
-                        undef, $user-&gt;id);
</del><ins>+        my $oldcryptedpwd = $user-&gt;cryptpassword;
</ins><span class="cx">         $oldcryptedpwd || ThrowCodeError(&quot;unable_to_retrieve_password&quot;);
</span><span class="cx"> 
</span><del>-        my $oldpassword = $cgi-&gt;param('Bugzilla_password');
-
-        # Wide characters cause crypt to die
-        if (Bugzilla-&gt;params-&gt;{'utf8'}) {
-            utf8::encode($oldpassword) if utf8::is_utf8($oldpassword);
-        } 
-
-        if (crypt($oldpassword, $oldcryptedpwd) ne $oldcryptedpwd) 
-        {
</del><ins>+        if (bz_crypt($oldpassword, $oldcryptedpwd) ne $oldcryptedpwd) {
</ins><span class="cx">             ThrowUserError(&quot;old_password_incorrect&quot;);
</span><span class="cx">         }
</span><span class="cx"> 
</span><del>-        if ($pwd1 ne &quot;&quot; || $pwd2 ne &quot;&quot;)
-        {
-            $cgi-&gt;param('new_password1')
-              || ThrowUserError(&quot;new_password_missing&quot;);
</del><ins>+        if ($pwd1 ne &quot;&quot; || $pwd2 ne &quot;&quot;) {
+            $pwd1 || ThrowUserError(&quot;new_password_missing&quot;);
</ins><span class="cx">             validate_password($pwd1, $pwd2);
</span><span class="cx"> 
</span><del>-            if ($cgi-&gt;param('Bugzilla_password') ne $pwd1) {
</del><ins>+            if ($oldpassword ne $pwd1) {
</ins><span class="cx">                 my $cryptedpassword = bz_crypt($pwd1);
</span><span class="cx">                 $dbh-&gt;do(q{UPDATE profiles
</span><span class="cx">                               SET cryptpassword = ?
</span><span class="lines">@@ -123,16 +115,11 @@
</span><span class="cx"> 
</span><span class="cx">     if ($user-&gt;authorizer-&gt;can_change_email
</span><span class="cx">         &amp;&amp; Bugzilla-&gt;params-&gt;{&quot;allowemailchange&quot;}
</span><del>-        &amp;&amp; $cgi-&gt;param('new_login_name'))
</del><ins>+        &amp;&amp; $new_login_name)
</ins><span class="cx">     {
</span><del>-        my $old_login_name = $cgi-&gt;param('Bugzilla_login');
-        my $new_login_name = trim($cgi-&gt;param('new_login_name'));
</del><ins>+        if ($user-&gt;login ne $new_login_name) {
+            $oldpassword || ThrowUserError(&quot;old_password_required&quot;);
</ins><span class="cx"> 
</span><del>-        if($old_login_name ne $new_login_name) {
-            $cgi-&gt;param('Bugzilla_password') 
-              || ThrowUserError(&quot;old_password_required&quot;);
-
-            use Bugzilla::Token;
</del><span class="cx">             # Block multiple email changes for the same user.
</span><span class="cx">             if (Bugzilla::Token::HasEmailChangeToken($user-&gt;id)) {
</span><span class="cx">                 ThrowUserError(&quot;email_change_in_progress&quot;);
</span><span class="lines">@@ -144,8 +131,7 @@
</span><span class="cx">             is_available_username($new_login_name)
</span><span class="cx">               || ThrowUserError(&quot;account_exists&quot;, {email =&gt; $new_login_name});
</span><span class="cx"> 
</span><del>-            Bugzilla::Token::IssueEmailChangeToken($user, $old_login_name,
-                                                   $new_login_name);
</del><ins>+            Bugzilla::Token::IssueEmailChangeToken($user, $new_login_name);
</ins><span class="cx"> 
</span><span class="cx">             $vars-&gt;{'email_changes_saved'} = 1;
</span><span class="cx">         }
</span><span class="lines">@@ -188,6 +174,7 @@
</span><span class="cx">     foreach my $name (@setting_list) {
</span><span class="cx">         next if ! ($settings-&gt;{$name}-&gt;{'is_enabled'});
</span><span class="cx">         my $value = $cgi-&gt;param($name);
</span><ins>+        next unless defined $value;
</ins><span class="cx">         my $setting = new Bugzilla::User::Setting($name);
</span><span class="cx"> 
</span><span class="cx">         if ($value eq &quot;${name}-isdefault&quot; ) {
</span><span class="lines">@@ -210,43 +197,26 @@
</span><span class="cx">     ###########################################################################
</span><span class="cx">     # User watching
</span><span class="cx">     ###########################################################################
</span><del>-    if (Bugzilla-&gt;params-&gt;{&quot;supportwatchers&quot;}) {
-        my $watched_ref = $dbh-&gt;selectcol_arrayref(
-            &quot;SELECT profiles.login_name FROM watch INNER JOIN profiles&quot; .
-            &quot; ON watch.watched = profiles.userid&quot; .
-            &quot; WHERE watcher = ?&quot; .
-            &quot; ORDER BY profiles.login_name&quot;,
-            undef, $user-&gt;id);
-        $vars-&gt;{'watchedusers'} = $watched_ref;
</del><ins>+    my $watched_ref = $dbh-&gt;selectcol_arrayref(
+        &quot;SELECT profiles.login_name FROM watch INNER JOIN profiles&quot; .
+        &quot; ON watch.watched = profiles.userid&quot; .
+        &quot; WHERE watcher = ?&quot; .
+        &quot; ORDER BY profiles.login_name&quot;,
+        undef, $user-&gt;id);
+    $vars-&gt;{'watchedusers'} = $watched_ref;
</ins><span class="cx"> 
</span><del>-        my $watcher_ids = $dbh-&gt;selectcol_arrayref(
-            &quot;SELECT watcher FROM watch WHERE watched = ?&quot;,
-            undef, $user-&gt;id);
</del><ins>+    my $watcher_ids = $dbh-&gt;selectcol_arrayref(
+        &quot;SELECT watcher FROM watch WHERE watched = ?&quot;,
+        undef, $user-&gt;id);
</ins><span class="cx"> 
</span><del>-        my @watchers;
-        foreach my $watcher_id (@$watcher_ids) {
-            my $watcher = new Bugzilla::User($watcher_id);
-            push (@watchers, Bugzilla::User::identity($watcher));
-        }
-
-        @watchers = sort { lc($a) cmp lc($b) } @watchers;
-        $vars-&gt;{'watchers'} = \@watchers;
</del><ins>+    my @watchers;
+    foreach my $watcher_id (@$watcher_ids) {
+        my $watcher = new Bugzilla::User($watcher_id);
+        push(@watchers, Bugzilla::User::identity($watcher));
</ins><span class="cx">     }
</span><span class="cx"> 
</span><del>-    ###########################################################################
-    # Role-based preferences
-    ###########################################################################
-    my $sth = $dbh-&gt;prepare(&quot;SELECT relationship, event &quot; . 
-                            &quot;FROM email_setting &quot; . 
-                            &quot;WHERE user_id = ?&quot;);
-    $sth-&gt;execute($user-&gt;id);
-
-    my %mail;
-    while (my ($relationship, $event) = $sth-&gt;fetchrow_array()) {
-        $mail{$relationship}{$event} = 1;
-    }
-
-    $vars-&gt;{'mail'} = \%mail;      
</del><ins>+    @watchers = sort { lc($a) cmp lc($b) } @watchers;
+    $vars-&gt;{'watchers'} = \@watchers;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub SaveEmail {
</span><span class="lines">@@ -254,68 +224,76 @@
</span><span class="cx">     my $cgi = Bugzilla-&gt;cgi;
</span><span class="cx">     my $user = Bugzilla-&gt;user;
</span><span class="cx"> 
</span><del>-    if (Bugzilla-&gt;params-&gt;{&quot;supportwatchers&quot;}) {
-        Bugzilla::User::match_field($cgi, { 'new_watchedusers' =&gt; {'type' =&gt; 'multi'} });
-    }
</del><ins>+    Bugzilla::User::match_field({ 'new_watchedusers' =&gt; {'type' =&gt; 'multi'} });
</ins><span class="cx"> 
</span><span class="cx">     ###########################################################################
</span><span class="cx">     # Role-based preferences
</span><span class="cx">     ###########################################################################
</span><span class="cx">     $dbh-&gt;bz_start_transaction();
</span><span class="cx"> 
</span><del>-    # Delete all the user's current preferences
-    $dbh-&gt;do(&quot;DELETE FROM email_setting WHERE user_id = ?&quot;, undef, $user-&gt;id);
</del><ins>+    my $sth_insert = $dbh-&gt;prepare('INSERT INTO email_setting
+                                    (user_id, relationship, event) VALUES (?, ?, ?)');
</ins><span class="cx"> 
</span><del>-    # Repopulate the table - first, with normal events in the 
</del><ins>+    my $sth_delete = $dbh-&gt;prepare('DELETE FROM email_setting
+                                    WHERE user_id = ? AND relationship = ? AND event = ?');
+    # Load current email preferences into memory before updating them.
+    my $settings = $user-&gt;mail_settings;
+
+    # Update the table - first, with normal events in the
</ins><span class="cx">     # relationship/event matrix.
</span><del>-    # Note: the database holds only &quot;off&quot; email preferences, as can be implied 
-    # from the name of the table - profiles_nomail.
-    foreach my $rel (RELATIONSHIPS) {
</del><ins>+    my %relationships = Bugzilla::BugMail::relationships();
+    foreach my $rel (keys %relationships) {
+        next if ($rel == REL_QA &amp;&amp; !Bugzilla-&gt;params-&gt;{'useqacontact'});
</ins><span class="cx">         # Positive events: a ticked box means &quot;send me mail.&quot;
</span><span class="cx">         foreach my $event (POS_EVENTS) {
</span><del>-            if (defined($cgi-&gt;param(&quot;email-$rel-$event&quot;))
-                &amp;&amp; $cgi-&gt;param(&quot;email-$rel-$event&quot;) == 1)
-            {
-                $dbh-&gt;do(&quot;INSERT INTO email_setting &quot; . 
-                         &quot;(user_id, relationship, event) &quot; . 
-                         &quot;VALUES (?, ?, ?)&quot;,
-                         undef, ($user-&gt;id, $rel, $event));
</del><ins>+            my $is_set = $cgi-&gt;param(&quot;email-$rel-$event&quot;);
+            if ($is_set xor $settings-&gt;{$rel}{$event}) {
+                if ($is_set) {
+                    $sth_insert-&gt;execute($user-&gt;id, $rel, $event);
+                }
+                else {
+                    $sth_delete-&gt;execute($user-&gt;id, $rel, $event);
+                }
</ins><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">         
</span><span class="cx">         # Negative events: a ticked box means &quot;don't send me mail.&quot;
</span><span class="cx">         foreach my $event (NEG_EVENTS) {
</span><del>-            if (!defined($cgi-&gt;param(&quot;neg-email-$rel-$event&quot;)) ||
-                $cgi-&gt;param(&quot;neg-email-$rel-$event&quot;) != 1) 
-            {
-                $dbh-&gt;do(&quot;INSERT INTO email_setting &quot; . 
-                         &quot;(user_id, relationship, event) &quot; . 
-                         &quot;VALUES (?, ?, ?)&quot;,
-                         undef, ($user-&gt;id, $rel, $event));
</del><ins>+            my $is_set = $cgi-&gt;param(&quot;neg-email-$rel-$event&quot;);
+            if (!$is_set xor $settings-&gt;{$rel}{$event}) {
+                if (!$is_set) {
+                    $sth_insert-&gt;execute($user-&gt;id, $rel, $event);
+                }
+                else {
+                    $sth_delete-&gt;execute($user-&gt;id, $rel, $event);
+                }
</ins><span class="cx">             }
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     # Global positive events: a ticked box means &quot;send me mail.&quot;
</span><span class="cx">     foreach my $event (GLOBAL_EVENTS) {
</span><del>-        if (defined($cgi-&gt;param(&quot;email-&quot; . REL_ANY . &quot;-$event&quot;))
-            &amp;&amp; $cgi-&gt;param(&quot;email-&quot; . REL_ANY . &quot;-$event&quot;) == 1)
-        {
-            $dbh-&gt;do(&quot;INSERT INTO email_setting &quot; . 
-                     &quot;(user_id, relationship, event) &quot; . 
-                     &quot;VALUES (?, ?, ?)&quot;,
-                     undef, ($user-&gt;id, REL_ANY, $event));
</del><ins>+        my $is_set = $cgi-&gt;param(&quot;email-&quot; . REL_ANY . &quot;-$event&quot;);
+        if ($is_set xor $settings-&gt;{+REL_ANY}{$event}) {
+            if ($is_set) {
+                $sth_insert-&gt;execute($user-&gt;id, REL_ANY, $event);
+            }
+            else {
+                $sth_delete-&gt;execute($user-&gt;id, REL_ANY, $event);
+            }
</ins><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     $dbh-&gt;bz_commit_transaction();
</span><span class="cx"> 
</span><ins>+    # We have to clear the cache about email preferences.
+    delete $user-&gt;{'mail_settings'};
+
</ins><span class="cx">     ###########################################################################
</span><span class="cx">     # User watching
</span><span class="cx">     ###########################################################################
</span><del>-    if (Bugzilla-&gt;params-&gt;{&quot;supportwatchers&quot;} 
-        &amp;&amp; (defined $cgi-&gt;param('new_watchedusers')
-            || defined $cgi-&gt;param('remove_watched_users'))) 
</del><ins>+    if (defined $cgi-&gt;param('new_watchedusers')
+        || defined $cgi-&gt;param('remove_watched_users'))
</ins><span class="cx">     {
</span><span class="cx">         $dbh-&gt;bz_start_transaction();
</span><span class="cx"> 
</span><span class="lines">@@ -406,7 +384,7 @@
</span><span class="cx">         $vars-&gt;{'queryshare_groups'} =
</span><span class="cx">             Bugzilla::Group-&gt;new_from_list($user-&gt;queryshare_groups);
</span><span class="cx">     }
</span><del>-    $vars-&gt;{'bless_group_ids'} = [map {$_-&gt;{'id'}} @{$user-&gt;bless_groups}];
</del><ins>+    $vars-&gt;{'bless_group_ids'} = [map { $_-&gt;id } @{$user-&gt;bless_groups}];
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> sub SaveSavedSearches {
</span><span class="lines">@@ -507,18 +485,22 @@
</span><span class="cx"> 
</span><span class="cx"> my $cgi = Bugzilla-&gt;cgi;
</span><span class="cx"> 
</span><del>-# This script needs direct access to the username and password CGI variables,
-# so we save them before their removal in Bugzilla-&gt;login, and delete them 
-# before login in case we might be in a sudo session.
-my $bugzilla_login    = $cgi-&gt;param('Bugzilla_login');
-my $bugzilla_password = $cgi-&gt;param('Bugzilla_password');
</del><ins>+# Delete credentials before logging in in case we are in a sudo session.
</ins><span class="cx"> $cgi-&gt;delete('Bugzilla_login', 'Bugzilla_password') if ($cgi-&gt;cookie('sudo'));
</span><ins>+$cgi-&gt;delete('GoAheadAndLogIn');
</ins><span class="cx"> 
</span><ins>+# First try to get credentials from cookies.
+Bugzilla-&gt;login(LOGIN_OPTIONAL);
+
+if (!Bugzilla-&gt;user-&gt;id) {
+    # Use credentials given in the form if login cookies are not available.
+    $cgi-&gt;param('Bugzilla_login', $cgi-&gt;param('old_login'));
+    $cgi-&gt;param('Bugzilla_password', $cgi-&gt;param('old_password'));
+}
</ins><span class="cx"> Bugzilla-&gt;login(LOGIN_REQUIRED);
</span><del>-$cgi-&gt;param('Bugzilla_login', $bugzilla_login);
-$cgi-&gt;param('Bugzilla_password', $bugzilla_password);
</del><span class="cx"> 
</span><del>-$vars-&gt;{'changes_saved'} = $cgi-&gt;param('dosave');
</del><ins>+my $save_changes = $cgi-&gt;param('dosave');
+$vars-&gt;{'changes_saved'} = $save_changes;
</ins><span class="cx"> 
</span><span class="cx"> my $current_tab_name = $cgi-&gt;param('tab') || &quot;settings&quot;;
</span><span class="cx"> 
</span><span class="lines">@@ -528,22 +510,32 @@
</span><span class="cx"> $vars-&gt;{'current_tab_name'} = $current_tab_name;
</span><span class="cx"> 
</span><span class="cx"> my $token = $cgi-&gt;param('token');
</span><del>-check_token_data($token, 'edit_user_prefs') if $cgi-&gt;param('dosave');
</del><ins>+check_token_data($token, 'edit_user_prefs') if $save_changes;
</ins><span class="cx"> 
</span><span class="cx"> # Do any saving, and then display the current tab.
</span><span class="cx"> SWITCH: for ($current_tab_name) {
</span><ins>+
+    # Extensions must set it to 1 to confirm the tab is valid.
+    my $handled = 0;
+    Bugzilla::Hook::process('user_preferences',
+                            { 'vars'       =&gt; $vars,
+                              save_changes =&gt; $save_changes,
+                              current_tab  =&gt; $current_tab_name,
+                              handled      =&gt; \$handled });
+    last SWITCH if $handled;
+
</ins><span class="cx">     /^account$/ &amp;&amp; do {
</span><del>-        SaveAccount() if $cgi-&gt;param('dosave');
</del><ins>+        SaveAccount() if $save_changes;
</ins><span class="cx">         DoAccount();
</span><span class="cx">         last SWITCH;
</span><span class="cx">     };
</span><span class="cx">     /^settings$/ &amp;&amp; do {
</span><del>-        SaveSettings() if $cgi-&gt;param('dosave');
</del><ins>+        SaveSettings() if $save_changes;
</ins><span class="cx">         DoSettings();
</span><span class="cx">         last SWITCH;
</span><span class="cx">     };
</span><span class="cx">     /^email$/ &amp;&amp; do {
</span><del>-        SaveEmail() if $cgi-&gt;param('dosave');
</del><ins>+        SaveEmail() if $save_changes;
</ins><span class="cx">         DoEmail();
</span><span class="cx">         last SWITCH;
</span><span class="cx">     };
</span><span class="lines">@@ -552,15 +544,16 @@
</span><span class="cx">         last SWITCH;
</span><span class="cx">     };
</span><span class="cx">     /^saved-searches$/ &amp;&amp; do {
</span><del>-        SaveSavedSearches() if $cgi-&gt;param('dosave');
</del><ins>+        SaveSavedSearches() if $save_changes;
</ins><span class="cx">         DoSavedSearches();
</span><span class="cx">         last SWITCH;
</span><span class="cx">     };
</span><ins>+
</ins><span class="cx">     ThrowUserError(&quot;unknown_tab&quot;,
</span><span class="cx">                    { current_tab_name =&gt; $current_tab_name });
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-delete_token($token) if $cgi-&gt;param('dosave');
</del><ins>+delete_token($token) if $save_changes;
</ins><span class="cx"> if ($current_tab_name ne 'permissions') {
</span><span class="cx">     $vars-&gt;{'token'} = issue_session_token('edit_user_prefs');
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgvotescgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/votes.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/votes.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/votes.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -13,344 +13,38 @@
</span><span class="cx"> #
</span><span class="cx"> # The Original Code is the Bugzilla Bug Tracking System.
</span><span class="cx"> #
</span><del>-# The Initial Developer of the Original Code is Netscape Communications
-# Corporation. Portions created by Netscape are
-# Copyright (C) 1998 Netscape Communications Corporation. All
-# Rights Reserved.
</del><ins>+# The Initial Developer of the Original Code is Everything Solved, Inc.
+# Portions created by the Initial Developer are Copyright (C) 2010 the
+# Initial Developer. All Rights Reserved.
</ins><span class="cx"> #
</span><del>-# Contributor(s): Terry Weissman &lt;terry@mozilla.org&gt;
-#                 Stephan Niemz  &lt;st.n@gmx.net&gt;
-#                 Christopher Aillon &lt;christopher@aillon.com&gt;
-#                 Gervase Markham &lt;gerv@gerv.net&gt;
-#                 Frédéric Buclin &lt;LpSolit@gmail.com&gt;
</del><ins>+# Contributor(s):
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
</ins><span class="cx"> 
</span><ins>+# This script remains as a backwards-compatibility URL for before
+# the time that Voting was an extension.
+
</ins><span class="cx"> use strict;
</span><span class="cx"> use lib qw(. lib);
</span><del>-
</del><span class="cx"> use Bugzilla;
</span><del>-use Bugzilla::Constants;
-use Bugzilla::Util;
</del><span class="cx"> use Bugzilla::Error;
</span><del>-use Bugzilla::Bug;
-use Bugzilla::User;
-use Bugzilla::Product;
</del><span class="cx"> 
</span><del>-use List::Util qw(min);
</del><ins>+my $is_enabled = grep { $_-&gt;NAME eq 'Voting' } @{ Bugzilla-&gt;extensions };
+$is_enabled || ThrowCodeError('extension_disabled', { name =&gt; 'Voting' });
</ins><span class="cx"> 
</span><span class="cx"> my $cgi = Bugzilla-&gt;cgi;
</span><del>-local our $vars = {};
</del><ins>+my $action = $cgi-&gt;param('action') || 'show_user';
</ins><span class="cx"> 
</span><del>-# If the action is show_bug, you need a bug_id.
-# If the action is show_user, you can supply a userid to show the votes for
-# another user, otherwise you see your own.
-# If the action is vote, your votes are set to those encoded in the URL as 
-# &lt;bug_id&gt;=&lt;votes&gt;.
-#
-# If no action is defined, we default to show_bug if a bug_id is given,
-# otherwise to show_user.
-my $bug_id = $cgi-&gt;param('bug_id');
-my $action = $cgi-&gt;param('action') || ($bug_id ? &quot;show_bug&quot; : &quot;show_user&quot;);
-
-if ($action eq &quot;show_bug&quot; ||
-    ($action eq &quot;show_user&quot; &amp;&amp; defined $cgi-&gt;param('user')))
-{
-    Bugzilla-&gt;login();
-}
-else {
-    Bugzilla-&gt;login(LOGIN_REQUIRED);
-}
-
-################################################################################
-# Begin Data/Security Validation
-################################################################################
-
-# Make sure the bug ID is a positive integer representing an existing
-# bug that the user is authorized to access.
-
-ValidateBugID($bug_id) if defined $bug_id;
-
-################################################################################
-# End Data/Security Validation
-################################################################################
-
</del><span class="cx"> if ($action eq &quot;show_bug&quot;) {
</span><del>-    show_bug($bug_id);
</del><ins>+    $cgi-&gt;delete('action');
+    $cgi-&gt;param('id', 'voting/bug.html');
</ins><span class="cx"> } 
</span><del>-elsif ($action eq &quot;show_user&quot;) {
-    show_user($bug_id);
</del><ins>+elsif ($action eq &quot;show_user&quot; or $action eq 'vote') {
+    $cgi-&gt;delete('action') unless $action eq 'vote';
+    $cgi-&gt;param('id', 'voting/user.html');
</ins><span class="cx"> }
</span><del>-elsif ($action eq &quot;vote&quot;) {
-    record_votes() if Bugzilla-&gt;params-&gt;{'usevotes'};
-    show_user($bug_id);
-}
</del><span class="cx"> else {
</span><del>-    ThrowCodeError(&quot;unknown_action&quot;, {action =&gt; $action});
</del><ins>+    ThrowUserError('unknown_action', {action =&gt; $action});
</ins><span class="cx"> }
</span><span class="cx"> 
</span><ins>+print $cgi-&gt;redirect('page.cgi?' . $cgi-&gt;query_string);
</ins><span class="cx"> exit;
</span><del>-
-# Display the names of all the people voting for this one bug.
-sub show_bug {
-    my ($bug_id) = @_;
-    my $cgi = Bugzilla-&gt;cgi;
-    my $dbh = Bugzilla-&gt;dbh;
-    my $template = Bugzilla-&gt;template;
-
-    ThrowCodeError(&quot;missing_bug_id&quot;) unless defined $bug_id;
-
-    $vars-&gt;{'bug_id'} = $bug_id;
-    $vars-&gt;{'users'} =
-        $dbh-&gt;selectall_arrayref('SELECT profiles.login_name, votes.vote_count 
-                                    FROM votes
-                              INNER JOIN profiles 
-                                      ON profiles.userid = votes.who
-                                   WHERE votes.bug_id = ?',
-                                  {'Slice' =&gt; {}}, $bug_id);
-
-    print $cgi-&gt;header();
-    $template-&gt;process(&quot;bug/votes/list-for-bug.html.tmpl&quot;, $vars)
-      || ThrowTemplateError($template-&gt;error());
-}
-
-# Display all the votes for a particular user. If it's the user
-# doing the viewing, give them the option to edit them too.
-sub show_user {
-    my ($bug_id) = @_;
-    my $cgi = Bugzilla-&gt;cgi;
-    my $dbh = Bugzilla-&gt;dbh;
-    my $user = Bugzilla-&gt;user;
-    my $template = Bugzilla-&gt;template;
-
-    # If a bug_id is given, and we're editing, we'll add it to the votes list.
-    $bug_id ||= &quot;&quot;;
-
-    my $name = $cgi-&gt;param('user') || $user-&gt;login;
-    my $who = login_to_id($name, THROW_ERROR);
-    my $userid = $user-&gt;id;
-
-    my $canedit = (Bugzilla-&gt;params-&gt;{'usevotes'} &amp;&amp; $userid == $who) ? 1 : 0;
-
-    $dbh-&gt;bz_start_transaction();
-
-    if ($canedit &amp;&amp; $bug_id) {
-        # Make sure there is an entry for this bug
-        # in the vote table, just so that things display right.
-        my $has_votes = $dbh-&gt;selectrow_array('SELECT vote_count FROM votes 
-                                               WHERE bug_id = ? AND who = ?',
-                                               undef, ($bug_id, $who));
-        if (!$has_votes) {
-            $dbh-&gt;do('INSERT INTO votes (who, bug_id, vote_count) 
-                      VALUES (?, ?, 0)', undef, ($who, $bug_id));
-        }
-    }
-
-    my @all_bug_ids;
-    my @products;
-    my $products = $user-&gt;get_selectable_products;
-    # Read the votes data for this user for each product.
-    foreach my $product (@$products) {
-        next unless ($product-&gt;votes_per_user &gt; 0);
-
-        my @bugs;
-        my @bug_ids;
-        my $total = 0;
-        my $onevoteonly = 0;
-
-        my $vote_list =
-            $dbh-&gt;selectall_arrayref('SELECT votes.bug_id, votes.vote_count,
-                                             bugs.short_desc
-                                        FROM votes
-                                  INNER JOIN bugs
-                                          ON votes.bug_id = bugs.bug_id
-                                       WHERE votes.who = ?
-                                         AND bugs.product_id = ?
-                                    ORDER BY votes.bug_id',
-                                      undef, ($who, $product-&gt;id));
-
-        foreach (@$vote_list) {
-            my ($id, $count, $summary) = @$_;
-            $total += $count;
-
-            # Next if user can't see this bug. So, the totals will be correct
-            # and they can see there are votes 'missing', but not on what bug
-            # they are. This seems a reasonable compromise; the alternative is
-            # to lie in the totals.
-            next if !$user-&gt;can_see_bug($id);
-
-            push (@bugs, { id =&gt; $id, 
-                           summary =&gt; $summary,
-                           count =&gt; $count });
-            push (@bug_ids, $id);
-            push (@all_bug_ids, $id);
-        }
-
-        $onevoteonly = 1 if (min($product-&gt;votes_per_user,
-                                 $product-&gt;max_votes_per_bug) == 1);
-
-        # Only add the product for display if there are any bugs in it.
-        if ($#bugs &gt; -1) {
-            push (@products, { name =&gt; $product-&gt;name,
-                               bugs =&gt; \@bugs,
-                               bug_ids =&gt; \@bug_ids,
-                               onevoteonly =&gt; $onevoteonly,
-                               total =&gt; $total,
-                               maxvotes =&gt; $product-&gt;votes_per_user,
-                               maxperbug =&gt; $product-&gt;max_votes_per_bug });
-        }
-    }
-
-    $dbh-&gt;do('DELETE FROM votes WHERE vote_count &lt;= 0');
-    $dbh-&gt;bz_commit_transaction();
-
-    $vars-&gt;{'canedit'} = $canedit;
-    $vars-&gt;{'voting_user'} = { &quot;login&quot; =&gt; $name };
-    $vars-&gt;{'products'} = \@products;
-    $vars-&gt;{'bug_id'} = $bug_id;
-    $vars-&gt;{'all_bug_ids'} = \@all_bug_ids;
-
-    print $cgi-&gt;header();
-    $template-&gt;process(&quot;bug/votes/list-for-user.html.tmpl&quot;, $vars)
-      || ThrowTemplateError($template-&gt;error());
-}
-
-# Update the user's votes in the database.
-sub record_votes {
-    ############################################################################
-    # Begin Data/Security Validation
-    ############################################################################
-
-    my $cgi = Bugzilla-&gt;cgi;
-    my $dbh = Bugzilla-&gt;dbh;
-    my $template = Bugzilla-&gt;template;
-
-    # Build a list of bug IDs for which votes have been submitted.  Votes
-    # are submitted in form fields in which the field names are the bug 
-    # IDs and the field values are the number of votes.
-
-    my @buglist = grep {/^[1-9][0-9]*$/} $cgi-&gt;param();
-
-    # If no bugs are in the buglist, let's make sure the user gets notified
-    # that their votes will get nuked if they continue.
-    if (scalar(@buglist) == 0) {
-        if (!defined $cgi-&gt;param('delete_all_votes')) {
-            print $cgi-&gt;header();
-            $template-&gt;process(&quot;bug/votes/delete-all.html.tmpl&quot;, $vars)
-              || ThrowTemplateError($template-&gt;error());
-            exit();
-        }
-        elsif ($cgi-&gt;param('delete_all_votes') == 0) {
-            print $cgi-&gt;redirect(&quot;votes.cgi&quot;);
-            exit();
-        }
-    }
-
-    # Call ValidateBugID on each bug ID to make sure it is a positive
-    # integer representing an existing bug that the user is authorized 
-    # to access, and make sure the number of votes submitted is also
-    # a non-negative integer (a series of digits not preceded by a
-    # minus sign).
-    my %votes;
-    foreach my $id (@buglist) {
-      ValidateBugID($id);
-      $votes{$id} = $cgi-&gt;param($id);
-      detaint_natural($votes{$id}) 
-        || ThrowUserError(&quot;votes_must_be_nonnegative&quot;);
-    }
-
-    ############################################################################
-    # End Data/Security Validation
-    ############################################################################
-    my $who = Bugzilla-&gt;user-&gt;id;
-
-    # If the user is voting for bugs, make sure they aren't overstuffing
-    # the ballot box.
-    if (scalar(@buglist)) {
-        my %prodcount;
-        my %products;
-        # XXX - We really need a $bug-&gt;product() method.
-        foreach my $bug_id (@buglist) {
-            my $bug = new Bugzilla::Bug($bug_id);
-            my $prod = $bug-&gt;product;
-            $products{$prod} ||= new Bugzilla::Product({name =&gt; $prod});
-            $prodcount{$prod} ||= 0;
-            $prodcount{$prod} += $votes{$bug_id};
-
-            # Make sure we haven't broken the votes-per-bug limit
-            ($votes{$bug_id} &lt;= $products{$prod}-&gt;max_votes_per_bug)
-              || ThrowUserError(&quot;too_many_votes_for_bug&quot;,
-                                {max =&gt; $products{$prod}-&gt;max_votes_per_bug,
-                                 product =&gt; $prod,
-                                 votes =&gt; $votes{$bug_id}});
-        }
-
-        # Make sure we haven't broken the votes-per-product limit
-        foreach my $prod (keys(%prodcount)) {
-            ($prodcount{$prod} &lt;= $products{$prod}-&gt;votes_per_user)
-              || ThrowUserError(&quot;too_many_votes_for_product&quot;,
-                                {max =&gt; $products{$prod}-&gt;votes_per_user,
-                                 product =&gt; $prod,
-                                 votes =&gt; $prodcount{$prod}});
-        }
-    }
-
-    # Update the user's votes in the database.  If the user did not submit 
-    # any votes, they may be using a form with checkboxes to remove all their
-    # votes (checkboxes are not submitted along with other form data when
-    # they are not checked, and Bugzilla uses them to represent single votes
-    # for products that only allow one vote per bug).  In that case, we still
-    # need to clear the user's votes from the database.
-    my %affected;
-    $dbh-&gt;bz_start_transaction();
-    
-    # Take note of, and delete the user's old votes from the database.
-    my $bug_list = $dbh-&gt;selectcol_arrayref('SELECT bug_id FROM votes
-                                             WHERE who = ?', undef, $who);
-
-    foreach my $id (@$bug_list) {
-        $affected{$id} = 1;
-    }
-    $dbh-&gt;do('DELETE FROM votes WHERE who = ?', undef, $who);
-
-    my $sth_insertVotes = $dbh-&gt;prepare('INSERT INTO votes (who, bug_id, vote_count)
-                                         VALUES (?, ?, ?)');
-    # Insert the new values in their place
-    foreach my $id (@buglist) {
-        if ($votes{$id} &gt; 0) {
-            $sth_insertVotes-&gt;execute($who, $id, $votes{$id});
-        }
-        $affected{$id} = 1;
-    }
-
-    # Update the cached values in the bugs table
-    print $cgi-&gt;header();
-    my @updated_bugs = ();
-
-    my $sth_getVotes = $dbh-&gt;prepare(&quot;SELECT SUM(vote_count) FROM votes
-                                      WHERE bug_id = ?&quot;);
-
-    my $sth_updateVotes = $dbh-&gt;prepare(&quot;UPDATE bugs SET votes = ?
-                                         WHERE bug_id = ?&quot;);
-
-    foreach my $id (keys %affected) {
-        $sth_getVotes-&gt;execute($id);
-        my $v = $sth_getVotes-&gt;fetchrow_array || 0;
-        $sth_updateVotes-&gt;execute($v, $id);
-
-        my $confirmed = CheckIfVotedConfirmed($id, $who);
-        push (@updated_bugs, $id) if $confirmed;
-    }
-    $dbh-&gt;bz_commit_transaction();
-
-    $vars-&gt;{'type'} = &quot;votes&quot;;
-    $vars-&gt;{'mailrecipients'} = { 'changer' =&gt; Bugzilla-&gt;user-&gt;login };
-    $vars-&gt;{'title_tag'} = 'change_votes';
-
-    foreach my $bug_id (@updated_bugs) {
-        $vars-&gt;{'id'} = $bug_id;
-        $template-&gt;process(&quot;bug/process/results.html.tmpl&quot;, $vars)
-          || ThrowTemplateError($template-&gt;error());
-        # Set header_done to 1 only after the first bug.
-        $vars-&gt;{'header_done'} = 1;
-    }
-    $vars-&gt;{'votes_recorded'} = 1;
-}
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgwhinepl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/whine.pl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/whine.pl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/whine.pl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -34,6 +34,7 @@
</span><span class="cx"> use Bugzilla::User;
</span><span class="cx"> use Bugzilla::Mailer;
</span><span class="cx"> use Bugzilla::Util;
</span><ins>+use Bugzilla::Group;
</ins><span class="cx"> 
</span><span class="cx"> # create some handles that we'll need
</span><span class="cx"> my $template = Bugzilla-&gt;template;
</span><span class="lines">@@ -64,7 +65,8 @@
</span><span class="cx">     &quot; whine_schedules.eventid, &quot; .
</span><span class="cx">     &quot; whine_events.owner_userid, &quot; .
</span><span class="cx">     &quot; whine_events.subject, &quot; .
</span><del>-    &quot; whine_events.body &quot; .
</del><ins>+    &quot; whine_events.body, &quot; .
+    &quot; whine_events.mailifnobugs &quot; .
</ins><span class="cx">     &quot;FROM whine_schedules &quot; .
</span><span class="cx">     &quot;LEFT JOIN whine_events &quot; .
</span><span class="cx">     &quot; ON whine_events.id = whine_schedules.eventid &quot; .
</span><span class="lines">@@ -148,20 +150,22 @@
</span><span class="cx">         # A time greater than now means it still has to run today
</span><span class="cx">         elsif ($time &gt;= $now_hour) {
</span><span class="cx">             # set it to today + number of hours
</span><del>-            $sth = $dbh-&gt;prepare(&quot;UPDATE whine_schedules &quot; .
-                                 &quot;SET run_next = CURRENT_DATE + &quot; .
-                                 $dbh-&gt;sql_interval('?', 'HOUR') .
-                                 &quot; WHERE id = ?&quot;);
</del><ins>+            $sth = $dbh-&gt;prepare(
+                &quot;UPDATE whine_schedules &quot; .
+                   &quot;SET run_next = &quot; .
+                        $dbh-&gt;sql_date_math('CURRENT_DATE', '+', '?', 'HOUR') .
+                &quot; WHERE id = ?&quot;);
</ins><span class="cx">             $sth-&gt;execute($time, $schedule_id);
</span><span class="cx">         }
</span><span class="cx">         # the target time is less than the current time
</span><span class="cx">         else { # set it for the next applicable day
</span><span class="cx">             $day = &amp;get_next_date($day);
</span><ins>+            my $run_next = $dbh-&gt;sql_date_math('(' 
+                . $dbh-&gt;sql_date_math('CURRENT_DATE', '+', '?', 'DAY')
+                . ')', '+', '?', 'HOUR');
</ins><span class="cx">             $sth = $dbh-&gt;prepare(&quot;UPDATE whine_schedules &quot; .
</span><del>-                                 &quot;SET run_next = (CURRENT_DATE + &quot; .
-                                 $dbh-&gt;sql_interval('?', 'DAY') . &quot;) + &quot; .
-                                 $dbh-&gt;sql_interval('?', 'HOUR') .
-                                 &quot; WHERE id = ?&quot;);
</del><ins>+                                    &quot;SET run_next = $run_next
+                                   WHERE id = ?&quot;);
</ins><span class="cx">             $sth-&gt;execute($day, $time, $schedule_id);
</span><span class="cx">         }
</span><span class="cx"> 
</span><span class="lines">@@ -174,11 +178,12 @@
</span><span class="cx">         # midnight
</span><span class="cx">         my $target_time = ($time =~ /^\d+$/) ? $time : 0;
</span><span class="cx"> 
</span><ins>+       my $run_next = $dbh-&gt;sql_date_math('(' 
+            . $dbh-&gt;sql_date_math('CURRENT_DATE', '+', '?', 'DAY') 
+            . ')', '+', '?', 'HOUR');
</ins><span class="cx">         $sth = $dbh-&gt;prepare(&quot;UPDATE whine_schedules &quot; .
</span><del>-                             &quot;SET run_next = (CURRENT_DATE + &quot; .
-                             $dbh-&gt;sql_interval('?', 'DAY') . &quot;) + &quot; .
-                             $dbh-&gt;sql_interval('?', 'HOUR') .
-                             &quot; WHERE id = ?&quot;);
</del><ins>+                                &quot;SET run_next = $run_next
+                               WHERE id = ?&quot;);
</ins><span class="cx">         $sth-&gt;execute($target_date, $target_time, $schedule_id);
</span><span class="cx">     }
</span><span class="cx"> }
</span><span class="lines">@@ -199,6 +204,7 @@
</span><span class="cx"> #   users   - array of user objects for recipients
</span><span class="cx"> #   subject - Subject line for the email
</span><span class="cx"> #   body    - the text inserted above the bug lists
</span><ins>+#   mailifnobugs - send message even if there are no query or query results
</ins><span class="cx"> 
</span><span class="cx"> sub get_next_event {
</span><span class="cx">     my $event = {};
</span><span class="lines">@@ -213,7 +219,7 @@
</span><span class="cx">         my $fetched = $sth_next_scheduled_event-&gt;fetch;
</span><span class="cx">         $sth_next_scheduled_event-&gt;finish;
</span><span class="cx">         return undef unless $fetched;
</span><del>-        my ($eventid, $owner_id, $subject, $body) = @{$fetched};
</del><ins>+        my ($eventid, $owner_id, $subject, $body, $mailifnobugs) = @{$fetched};
</ins><span class="cx"> 
</span><span class="cx">         my $owner = Bugzilla::User-&gt;new($owner_id);
</span><span class="cx"> 
</span><span class="lines">@@ -250,7 +256,7 @@
</span><span class="cx">                         $groupname, $owner);
</span><span class="cx">                     if ($group_id) {
</span><span class="cx">                         my $glist = join(',',
</span><del>-                            @{Bugzilla::User-&gt;flatten_group_membership(
</del><ins>+                            @{Bugzilla::Group-&gt;flatten_group_membership(
</ins><span class="cx">                             $group_id)});
</span><span class="cx">                         $sth = $dbh-&gt;prepare(&quot;SELECT user_id FROM &quot; .
</span><span class="cx">                                              &quot;user_group_map &quot; .
</span><span class="lines">@@ -281,6 +287,7 @@
</span><span class="cx">                     'mailto'  =&gt; \@users,
</span><span class="cx">                     'subject' =&gt; $subject,
</span><span class="cx">                     'body'    =&gt; $body,
</span><ins>+                    'mailifnobugs' =&gt; $mailifnobugs,
</ins><span class="cx">             };
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="lines">@@ -295,6 +302,7 @@
</span><span class="cx"> #   mailto  (array of user objects for mail targets)
</span><span class="cx"> #   subject (subject line for message)
</span><span class="cx"> #   body    (text blurb at top of message)
</span><ins>+#   mailifnobugs (send message even if there are no query or query results)
</ins><span class="cx"> while (my $event = get_next_event) {
</span><span class="cx"> 
</span><span class="cx">     my $eventid = $event-&gt;{'eventid'};
</span><span class="lines">@@ -315,12 +323,14 @@
</span><span class="cx">         # run the queries for this schedule
</span><span class="cx">         my $queries = run_queries($args);
</span><span class="cx"> 
</span><del>-        # check to make sure there is something to output
-        my $there_are_bugs = 0;
-        for my $query (@{$queries}) {
-            $there_are_bugs = 1 if scalar @{$query-&gt;{'bugs'}};
</del><ins>+        # If mailifnobugs is false, make sure there is something to output
+        if (!$event-&gt;{'mailifnobugs'}) {
+            my $there_are_bugs = 0;
+            for my $query (@{$queries}) {
+                $there_are_bugs = 1 if scalar @{$query-&gt;{'bugs'}};
+            }
+            next unless $there_are_bugs;
</ins><span class="cx">         }
</span><del>-        next unless $there_are_bugs;
</del><span class="cx"> 
</span><span class="cx">         $args-&gt;{'queries'} = $queries;
</span><span class="cx"> 
</span><span class="lines">@@ -357,7 +367,7 @@
</span><span class="cx">     # Don't send mail to someone whose bugmail notification is disabled.
</span><span class="cx">     return if $addressee-&gt;email_disabled;
</span><span class="cx"> 
</span><del>-    my $template = Bugzilla-&gt;template_inner($addressee-&gt;settings-&gt;{'lang'}-&gt;{'value'});
</del><ins>+    my $template = Bugzilla-&gt;template_inner($addressee-&gt;setting('lang'));
</ins><span class="cx">     my $msg = ''; # it's a temporary variable to hold the template output
</span><span class="cx">     $args-&gt;{'alternatives'} ||= [];
</span><span class="cx"> 
</span><span class="lines">@@ -388,7 +398,6 @@
</span><span class="cx">     $template-&gt;process(&quot;whine/multipart-mime.txt.tmpl&quot;, $args, \$msg)
</span><span class="cx">         or die($template-&gt;error());
</span><span class="cx"> 
</span><del>-    Bugzilla-&gt;template_inner(&quot;&quot;);
</del><span class="cx">     MessageToMTA($msg);
</span><span class="cx"> 
</span><span class="cx">     delete $args-&gt;{'boundary'};
</span><span class="lines">@@ -424,16 +433,15 @@
</span><span class="cx">         next unless $savedquery;    # silently ignore missing queries
</span><span class="cx"> 
</span><span class="cx">         # Execute the saved query
</span><del>-        my @searchfields = (
-            'bugs.bug_id',
-            'bugs.bug_severity',
-            'bugs.priority',
-            'bugs.rep_platform',
-            'bugs.assigned_to',
-            'bugs.bug_status',
-            'bugs.resolution',
-            'bugs.short_desc',
-            'map_assigned_to.login_name',
</del><ins>+        my @searchfields = qw(
+            bug_id
+            bug_severity
+            priority
+            rep_platform
+            assigned_to
+            bug_status
+            resolution
+            short_desc
</ins><span class="cx">         );
</span><span class="cx">         # A new Bugzilla::CGI object needs to be created to allow
</span><span class="cx">         # Bugzilla::Search to execute a saved query.  It's exceedingly weird,
</span><span class="lines">@@ -441,10 +449,18 @@
</span><span class="cx">         my $searchparams = new Bugzilla::CGI($savedquery);
</span><span class="cx">         my $search = new Bugzilla::Search(
</span><span class="cx">             'fields' =&gt; \@searchfields,
</span><del>-            'params' =&gt; $searchparams,
</del><ins>+            'params' =&gt; scalar $searchparams-&gt;Vars,
</ins><span class="cx">             'user'   =&gt; $args-&gt;{'recipient'}, # the search runs as the recipient
</span><span class="cx">         );
</span><del>-        my $sqlquery = $search-&gt;getSQL();
</del><ins>+        # If a query fails for whatever reason, it shouldn't kill the script.
+        my $sqlquery = eval { $search-&gt;sql };
+        if ($@) {
+            print STDERR get_text('whine_query_failed', { query_name =&gt; $thisquery-&gt;{'name'},
+                                                          author =&gt; $args-&gt;{'author'},
+                                                          reason =&gt; $@ }) . &quot;\n&quot;;
+            next;
+        }
+
</ins><span class="cx">         $sth = $dbh-&gt;prepare($sqlquery);
</span><span class="cx">         $sth-&gt;execute;
</span><span class="cx"> 
</span><span class="lines">@@ -579,21 +595,22 @@
</span><span class="cx">         my $target_time = ($run_time =~ /^\d+$/) ? $run_time : 0;
</span><span class="cx"> 
</span><span class="cx">         my $nextdate = &amp;get_next_date($run_day);
</span><del>-
</del><ins>+        my $run_next = $dbh-&gt;sql_date_math('('
+            . $dbh-&gt;sql_date_math('CURRENT_DATE', '+', '?', 'DAY')
+            . ')', '+', '?', 'HOUR');
</ins><span class="cx">         $sth = $dbh-&gt;prepare(&quot;UPDATE whine_schedules &quot; .
</span><del>-                             &quot;SET run_next = (CURRENT_DATE + &quot; .
-                             $dbh-&gt;sql_interval('?', 'DAY') . &quot;) + &quot; .
-                             $dbh-&gt;sql_interval('?', 'HOUR') .
-                             &quot; WHERE id = ?&quot;);
</del><ins>+                                &quot;SET run_next = $run_next
+                               WHERE id = ?&quot;);
</ins><span class="cx">         $sth-&gt;execute($nextdate, $target_time, $schedule_id);
</span><span class="cx">         return;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     if ($minute_offset &gt; 0) {
</span><span class="cx">         # Scheduling is done in terms of whole minutes.
</span><del>-        my $next_run = $dbh-&gt;selectrow_array('SELECT NOW() + ' .
-                                             $dbh-&gt;sql_interval('?', 'MINUTE'),
-                                             undef, $minute_offset);
</del><ins>+        
+        my $next_run = $dbh-&gt;selectrow_array(
+            'SELECT ' . $dbh-&gt;sql_date_math('NOW()', '+', '?', 'MINUTE'),
+            undef, $minute_offset);
</ins><span class="cx">         $next_run = format_time($next_run, &quot;%Y-%m-%d %R&quot;);
</span><span class="cx"> 
</span><span class="cx">         $sth = $dbh-&gt;prepare(&quot;UPDATE whine_schedules &quot; .
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgwhineatnewspl"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/whineatnews.pl (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/whineatnews.pl        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/whineatnews.pl        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -25,8 +25,10 @@
</span><span class="cx"> 
</span><span class="cx"> # This is a script suitable for running once a day from a cron job.  It 
</span><span class="cx"> # looks at all the bugs, and sends whiny mail to anyone who has a bug 
</span><del>-# assigned to them that has status NEW or REOPENED that has not been 
-# touched for more than the number of days specified in the whinedays param.
</del><ins>+# assigned to them that has status CONFIRMED, NEW, or REOPENED that has not
+# been touched for more than the number of days specified in the whinedays
+# param. (We have NEW and REOPENED in there to keep compatibility with old
+# Bugzillas.)
</ins><span class="cx"> 
</span><span class="cx"> use strict;
</span><span class="cx"> use lib qw(. lib);
</span><span class="lines">@@ -44,7 +46,7 @@
</span><span class="cx">                 FROM bugs
</span><span class="cx">           INNER JOIN profiles
</span><span class="cx">                   ON userid = assigned_to
</span><del>-               WHERE (bug_status = ? OR bug_status = ?)
</del><ins>+               WHERE bug_status IN (?,?,?)
</ins><span class="cx">                  AND disable_mail = 0
</span><span class="cx">                  AND } . $dbh-&gt;sql_to_days('NOW()') . &quot; - &quot; .
</span><span class="cx">                        $dbh-&gt;sql_to_days('delta_ts') . &quot; &gt; &quot; .
</span><span class="lines">@@ -54,7 +56,8 @@
</span><span class="cx"> my %bugs;
</span><span class="cx"> my %desc;
</span><span class="cx"> 
</span><del>-my $slt_bugs = $dbh-&gt;selectall_arrayref($query, undef, 'NEW', 'REOPENED');
</del><ins>+my $slt_bugs = $dbh-&gt;selectall_arrayref($query, undef, 'CONFIRMED', 'NEW',
+                                                       'REOPENED');
</ins><span class="cx"> 
</span><span class="cx"> foreach my $bug (@$slt_bugs) {
</span><span class="cx">     my ($id, $desc, $email) = @$bug;
</span><span class="lines">@@ -85,11 +88,10 @@
</span><span class="cx">     $vars-&gt;{'bugs'} = \@bugs;
</span><span class="cx"> 
</span><span class="cx">     my $msg;
</span><del>-    my $template = Bugzilla-&gt;template_inner($user-&gt;settings-&gt;{'lang'}-&gt;{'value'});
</del><ins>+    my $template = Bugzilla-&gt;template_inner($user-&gt;setting('lang'));
</ins><span class="cx">     $template-&gt;process(&quot;email/whine.txt.tmpl&quot;, $vars, \$msg)
</span><span class="cx">       or die($template-&gt;error());
</span><span class="cx"> 
</span><del>-    Bugzilla-&gt;template_inner(&quot;&quot;);
</del><span class="cx">     MessageToMTA($msg);
</span><span class="cx"> 
</span><span class="cx">     print &quot;$email      &quot; . join(&quot; &quot;, @{$bugs{$email}}) . &quot;\n&quot;;
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgxmlcgi"></a>
<div class="delfile"><h4>Deleted: trunk/Websites/bugs.webkit.org/xml.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/xml.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/xml.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -1,41 +0,0 @@
</span><del>-#!/usr/bin/env perl -wT
-# -*- Mode: perl; indent-tabs-mode: nil -*-
-#
-# The contents of this file are subject to the Mozilla Public
-# License Version 1.1 (the &quot;License&quot;); you may not use this file
-# except in compliance with the License. You may obtain a copy of
-# the License at http://www.mozilla.org/MPL/
-#
-# Software distributed under the License is distributed on an &quot;AS
-# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
-# implied. See the License for the specific language governing
-# rights and limitations under the License.
-#
-# The Original Code is the Bugzilla Bug Tracking System.
-#
-# The Initial Developer of the Original Code is Netscape Communications
-# Corporation. Portions created by Netscape are
-# Copyright (C) 1998 Netscape Communications Corporation. All
-# Rights Reserved.
-#
-# Contributor(s): Dawn Endico    &lt;endico@mozilla.org&gt;
-#                 Terry Weissman &lt;terry@mozilla.org&gt;
-#                 Gervase Markham &lt;gerv@gerv.net&gt;
-
-use strict;
-
-use lib qw(. lib);
-use Bugzilla;
-
-my $cgi = Bugzilla-&gt;cgi;
-
-# Convert comma/space separated elements into separate params
-my @ids = ();
-
-if (defined $cgi-&gt;param('id')) {
-    @ids = split (/[, ]+/, $cgi-&gt;param('id'));
-}
-
-my $ids = join('', map { $_ = &quot;&amp;id=&quot; . $_ } @ids);
-
-print $cgi-&gt;redirect(&quot;show_bug.cgi?ctype=xml$ids&quot;);
</del></span></pre></div>
<a id="trunkWebsitesbugswebkitorgxmlrpccgi"></a>
<div class="modfile"><h4>Modified: trunk/Websites/bugs.webkit.org/xmlrpc.cgi (174763 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/xmlrpc.cgi        2014-10-16 15:26:14 UTC (rev 174763)
+++ trunk/Websites/bugs.webkit.org/xmlrpc.cgi        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -21,16 +21,17 @@
</span><span class="cx"> use Bugzilla;
</span><span class="cx"> use Bugzilla::Constants;
</span><span class="cx"> use Bugzilla::Error;
</span><del>-use Bugzilla::Hook;
</del><span class="cx"> use Bugzilla::WebService::Constants;
</span><ins>+BEGIN {
+    if (!Bugzilla-&gt;feature('xmlrpc')) {
+        ThrowCodeError('feature_disabled', { feature =&gt; 'xmlrpc' });
+    }
+}
+use Bugzilla::WebService::Server::XMLRPC;
</ins><span class="cx"> 
</span><del>-# Use an eval here so that runtests.pl accepts this script even if SOAP-Lite
-# is not installed.
-eval 'use XMLRPC::Transport::HTTP;
-      use Bugzilla::WebService;';
-$@ &amp;&amp; ThrowCodeError('soap_not_installed');
</del><ins>+Bugzilla-&gt;usage_mode(USAGE_MODE_XMLRPC);
</ins><span class="cx"> 
</span><del>-Bugzilla-&gt;usage_mode(Bugzilla::Constants::USAGE_MODE_WEBSERVICE);
</del><ins>+# Fix the error code that SOAP::Lite uses for Perl errors.
</ins><span class="cx"> local $SOAP::Constants::FAULT_SERVER;
</span><span class="cx"> $SOAP::Constants::FAULT_SERVER = ERROR_UNKNOWN_FATAL;
</span><span class="cx"> # The line above is used, this one is ignored, but SOAP::Lite
</span><span class="lines">@@ -38,27 +39,10 @@
</span><span class="cx"> local $XMLRPC::Constants::FAULT_SERVER;
</span><span class="cx"> $XMLRPC::Constants::FAULT_SERVER = ERROR_UNKNOWN_FATAL;
</span><span class="cx"> 
</span><del>-my %hook_dispatch;
-Bugzilla::Hook::process('webservice', { dispatch =&gt; \%hook_dispatch });
</del><span class="cx"> local @INC = (bz_locations()-&gt;{extensionsdir}, @INC);
</span><del>-
-my $dispatch = {
-    'Bugzilla' =&gt; 'Bugzilla::WebService::Bugzilla',
-    'Bug'      =&gt; 'Bugzilla::WebService::Bug',
-    'User'     =&gt; 'Bugzilla::WebService::User',
-    'Product'  =&gt; 'Bugzilla::WebService::Product',
-    %hook_dispatch
-};
-
-# The on_action sub needs to be wrapped so that we can work out which
-# class to use; when the XMLRPC module calls it theres no indication
-# of which dispatch class will be handling it.
-# Note that using this to get code thats called before the actual routine
-# is a bit of a hack; its meant to be for modifying the SOAPAction
-# headers, which XMLRPC doesn't use; it relies on the XMLRPC modules
-# using SOAP::Lite internally....
-
-my $response = Bugzilla::WebService::XMLRPC::Transport::HTTP::CGI
-    -&gt;dispatch_with($dispatch)
-    -&gt;on_action(sub { Bugzilla::WebService::handle_login($dispatch, @_) } )
-    -&gt;handle;
</del><ins>+my $server = new Bugzilla::WebService::Server::XMLRPC;
+# We use a sub for on_action because that gets us the info about what 
+# class is being called. Note that this is a hack--this is technically 
+# for setting SOAPAction, which isn't used by XML-RPC.
+$server-&gt;on_action(sub { $server-&gt;handle_login(WS_DISPATCH, @_) })
+       -&gt;handle();
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgxtREADME"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/xt/README (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/xt/README                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/xt/README        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,18 @@
</span><ins>+The tests in this directory require a working database, as opposed
+to the tests in t/, which simply test the code without a working
+installation.
+
+Some of the tests may modify your current working installation, even
+if only temporarily. To run the tests that modify your database,
+set the environment variable BZ_WRITE_TESTS to 1.
+
+Some tests also take additional, optional arguments. You can pass arguments
+to tests like:
+
+  prove xt/search.t :: --long --operators=equals,notequals
+
+Note the &quot;::&quot;--that is necessary to note that the arguments are going to
+the test, not to &quot;prove&quot;.
+
+See the perldoc of the individual tests to see what options they support,
+or do &quot;perl xt/search.t --help&quot;.
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgxtlibBugzillaTestSearchAndTestpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/AndTest.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/AndTest.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/AndTest.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,66 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Everything Solved, Inc.
+# Portions created by the Initial Developer are Copyright (C) 2010 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+# This test combines two field/operator combinations using AND in
+# a single boolean chart.
+package Bugzilla::Test::Search::AndTest;
+use base qw(Bugzilla::Test::Search::OrTest);
+
+use Bugzilla::Test::Search::Constants;
+use List::MoreUtils qw(all);
+
+use constant type =&gt; 'AND';
+
+#############
+# Accessors #
+#############
+
+# In an AND test, bugs ARE supposed to be contained only if they are contained
+# by ALL tests.
+sub bug_is_contained {
+    my ($self, $number) = @_;
+    return all { $_-&gt;bug_is_contained($number) } $self-&gt;field_tests;
+}
+
+sub _bug_will_actually_be_contained {
+    my ($self, $number) = @_;
+    return all { $_-&gt;will_actually_contain_bug($number) } $self-&gt;field_tests;
+}
+
+##############################
+# Bugzilla::Search arguments #
+##############################
+
+sub search_params {
+    my ($self) = @_;
+    my @all_params = map { $_-&gt;search_params } $self-&gt;field_tests;
+    my %params;
+    my $chart = 0;
+    foreach my $item (@all_params) {
+        $params{&quot;field0-$chart-0&quot;} = $item-&gt;{'field0-0-0'};
+        $params{&quot;type0-$chart-0&quot;}  = $item-&gt;{'type0-0-0'};
+        $params{&quot;value0-$chart-0&quot;} = $item-&gt;{'value0-0-0'};
+        $chart++;
+    }
+    return \%params;
+}
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgxtlibBugzillaTestSearchConstantspm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/Constants.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/Constants.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/Constants.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,1130 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Everything Solved, Inc.
+# Portions created by the Initial Developer are Copyright (C) 2010 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+
+# These are constants used by Bugzilla::Test::Search.
+# See the comment at the top of that package for a general overview
+# of how the search test works, and how the constants are used.
+# More detailed information on each constant is available in the comments
+# in this file.
+package Bugzilla::Test::Search::Constants;
+use base qw(Exporter);
+use Bugzilla::Constants;
+use Bugzilla::Util qw(generate_random_password);
+
+our @EXPORT = qw(
+    ATTACHMENT_FIELDS
+    BROKEN_NOT
+    COLUMN_TRANSLATION
+    COMMENT_FIELDS
+    CUSTOM_FIELDS
+    CUSTOM_SEARCH_TESTS
+    FIELD_SIZE
+    FIELD_SUBSTR_SIZE
+    FLAG_FIELDS
+    INJECTION_BROKEN_FIELD
+    INJECTION_BROKEN_OPERATOR
+    INJECTION_TESTS
+    KNOWN_BROKEN
+    NUM_BUGS
+    NUM_SEARCH_TESTS
+    SKIP_FIELDS
+    SPECIAL_PARAM_TESTS
+    SUBSTR_NO_FIELD_ADD
+    SUBSTR_SIZE
+    TESTS
+    TESTS_PER_RUN
+    USER_FIELDS
+);
+
+# Bug 1 is designed to be found by all the &quot;equals&quot; tests. It has
+# multiple values for several fields where other fields only have
+# one value.
+#
+# Bug 2 and 3 have a dependency relationship with Bug 1,
+# but show up in &quot;not equals&quot; tests. We do use bug 2 in multiple-value
+# tests.
+#
+# Bug 4 should never show up in any equals test, and has no relationship
+# with any other bug. However, it does have all its fields set.
+#
+# Bug 5 only has values set for mandatory fields, to expose problems
+# that happen with &quot;not equals&quot; tests failing to catch bugs that don't
+# have a value set at all.
+#
+# Bug 6 is a clone of Bug 1, but is in a group that the searcher isn't
+# in.
+use constant NUM_BUGS =&gt; 6;
+
+# How many tests there are for each operator/field combination other
+# than the &quot;contains&quot; tests.
+use constant NUM_SEARCH_TESTS =&gt; 3;
+# This is how many tests get run for each field/operator.
+use constant TESTS_PER_RUN =&gt; NUM_SEARCH_TESTS + NUM_BUGS;
+
+# This is how many random characters we generate for most fields' names.
+# (Some fields can't be this long, though, so they have custom lengths
+# in Bugzilla::Test::Search).
+use constant FIELD_SIZE =&gt; 30;
+
+# These are the custom fields that are created if the BZ_MODIFY_DATABASE_TESTS
+# environment variable is set.
+use constant CUSTOM_FIELDS =&gt; {
+    FIELD_TYPE_FREETEXT,  'cf_freetext',
+    FIELD_TYPE_SINGLE_SELECT, 'cf_single_select',
+    FIELD_TYPE_MULTI_SELECT, 'cf_multi_select',
+    FIELD_TYPE_TEXTAREA, 'cf_textarea',
+    FIELD_TYPE_DATETIME, 'cf_datetime',
+    FIELD_TYPE_BUG_ID, 'cf_bugid',
+};
+
+# This translates fielddefs names into Search column names.
+use constant COLUMN_TRANSLATION =&gt; {
+    creation_ts =&gt; 'opendate',
+    delta_ts    =&gt; 'changeddate',
+    work_time =&gt; 'actual_time',
+};
+
+# Make comment field names to their Bugzilla::Comment accessor.
+use constant COMMENT_FIELDS =&gt; {
+    longdesc  =&gt; 'body',
+    commenter =&gt; 'author',
+    'longdescs.isprivate' =&gt; 'is_private',
+};
+
+# Same as above, for Bugzilla::Attachment.
+use constant ATTACHMENT_FIELDS =&gt; {
+    mimetype =&gt; 'contenttype',
+    submitter =&gt; 'attacher',
+    thedata   =&gt; 'data',
+};
+
+# Same, for Bugzilla::Flag.
+use constant FLAG_FIELDS =&gt; {
+    'flagtypes.name' =&gt; 'name',
+    'setters.login_name' =&gt; 'setter',
+    'requestees.login_name' =&gt; 'requestee',
+};
+
+# These are fields that we don't test. Test::More will mark these
+# &quot;TODO &amp; SKIP&quot;, and not run tests for them at all.
+#
+# We don't support days_elapsed or owner_idle_time yet.
+use constant SKIP_FIELDS =&gt; qw(
+    owner_idle_time
+    days_elapsed
+);
+
+# All the fields that represent users.
+use constant USER_FIELDS =&gt; qw(
+    assigned_to
+    cc
+    reporter
+    qa_contact
+    commenter
+    attachments.submitter
+    setters.login_name
+    requestees.login_name
+);
+
+# For the &quot;substr&quot;-type searches, how short of a substring should
+# we use? The goal is to be shorter than the full string, but
+# long enough to still be globally unique.
+use constant SUBSTR_SIZE =&gt; 20;
+# However, for some fields, we use a different size.
+use constant FIELD_SUBSTR_SIZE =&gt; {
+    alias =&gt; 11,
+    # Just the month and day.
+    deadline =&gt; -5,
+    creation_ts =&gt; -8,
+    delta_ts =&gt; -8,
+    percentage_complete =&gt; 1,
+    work_time =&gt; 3,
+    remaining_time =&gt; 3,
+    target_milestone =&gt; 15,
+    longdesc =&gt; 25,
+    # Just the hour and minute.
+    FIELD_TYPE_DATETIME, -5,
+};
+
+# For most fields, we add the length of the name of the field plus
+# the SUBSTR_SIZE specified above to determine how large of a substring
+# we're going to use. However, for some fields, it doesn't make sense to
+# add in their field name this way.
+use constant SUBSTR_NO_FIELD_ADD =&gt; FIELD_TYPE_DATETIME, qw(
+    target_milestone remaining_time percentage_complete work_time
+    attachments.mimetype attachments.submitter attachments.filename
+    attachments.description flagtypes.name
+);
+
+################
+# Known Broken #
+################
+
+# See the KNOWN_BROKEN constant for a general description of these
+# &quot;_BROKEN&quot; constants.
+
+# Shared between greaterthan and greaterthaneq.
+#
+# As with other fields, longdescs greaterthan matches if any comment
+# matches (which might be OK).
+#
+# Same for keywords, and cc. Logically, all of these might
+# be OK, but it makes the operation not the logical reverse of
+# lessthaneq. What we're really saying here by marking these broken
+# is that there ought to be some way of searching &quot;all ccs&quot; vs &quot;any cc&quot;
+# (and same for the other fields).
+use constant GREATERTHAN_BROKEN =&gt; (
+    cc        =&gt; { contains =&gt; [1] },
+);
+
+# allwords and allwordssubstr have these broken tests in common.
+#
+# allwordssubstr on cc fields matches against a single cc,
+# instead of matching against all ccs on a bug.
+use constant ALLWORDS_BROKEN =&gt; (
+    cc        =&gt; { contains =&gt; [1] },
+);
+
+# Fields that don't generally work at all with changed* searches, but
+# probably should.
+use constant CHANGED_BROKEN =&gt; (
+    classification =&gt; { contains =&gt; [1] },
+    commenter =&gt; { contains =&gt; [1] },
+    percentage_complete     =&gt; { contains =&gt; [1] },
+    'requestees.login_name' =&gt; { contains =&gt; [1] },
+    'setters.login_name'    =&gt; { contains =&gt; [1] },
+    delta_ts                =&gt; { contains =&gt; [1] },
+);
+
+# These are additional broken tests that changedfrom and changedto
+# have in common.
+use constant CHANGED_VALUE_BROKEN =&gt; (
+    bug_group        =&gt; { contains =&gt; [1] },
+    cc               =&gt; { contains =&gt; [1] },
+    estimated_time   =&gt; { contains =&gt; [1] },
+    'flagtypes.name' =&gt; { contains =&gt; [1] },
+    keywords  =&gt; { contains =&gt; [1] },
+    'longdescs.count' =&gt; { search =&gt; 1 },
+    FIELD_TYPE_MULTI_SELECT, { contains =&gt; [1] },
+);
+
+
+# Any test listed in KNOWN_BROKEN gets marked TODO by Test::More
+# (using some complex code in Bugzilla::Test::Seach::FieldTest).
+# This means that if you run the test under &quot;prove -v&quot;, these tests will
+# still show up as &quot;not ok&quot;, but the test suite results won't show them
+# as a failure.
+#
+# This constant contains operators as keys, which point to hashes. The hashes
+# have field names as keys. Each field name points to a hash describing
+# how that field/operator combination is broken. The &quot;contains&quot;
+# array specifies that that particular &quot;contains&quot; test is expected
+# to fail. If &quot;search&quot; is set to 1, then we expect the creation of the
+# Bugzilla::Search object to fail.
+#
+# To allow handling custom fields, you can also use the field type as a key
+# instead of the field name. Specifying explicit field names always overrides
+# specifying a field type.
+#
+# Sometimes the operators have multiple tests, and one of them works
+# while the other fails. In this case, we have a special override for
+# &quot;operator-value&quot;, which uniquely identifies tests.
+use constant KNOWN_BROKEN =&gt; {
+    &quot;equals-%group.&lt;1-bug_group&gt;%&quot; =&gt; {
+        commenter =&gt; { contains =&gt; [1,2,3,4,5] },
+    },
+
+    greaterthan   =&gt; { GREATERTHAN_BROKEN },
+    greaterthaneq =&gt; { GREATERTHAN_BROKEN },
+
+    'allwordssubstr-&lt;1&gt;' =&gt; { ALLWORDS_BROKEN },
+    'allwords-&lt;1&gt;' =&gt; {
+        ALLWORDS_BROKEN,
+    },
+
+    # setters.login_name and requestees.login name aren't tracked individually
+    # in bugs_activity, so can't be searched using this method.
+    #
+    # percentage_complete isn't tracked in bugs_activity (and it would be
+    # really hard to track). However, it adds a 0=0 term instead of using
+    # the changed* charts or simply denying them.
+    #
+    # delta_ts changedbefore/after should probably search for bugs based
+    # on their delta_ts.
+    #
+    # creation_ts changedbefore/after should search for bug creation dates.
+    #
+    # The commenter field changedbefore/after should search for comment
+    # creation dates.
+    #
+    # classification isn't being tracked properly in bugs_activity, I think.
+    #
+    # attach_data.thedata should search when attachments were created and
+    # who they were created by.
+    'changedbefore' =&gt; {
+        CHANGED_BROKEN,
+        'attach_data.thedata' =&gt; { contains =&gt; [1] },
+    },
+    'changedafter' =&gt; {
+        'attach_data.thedata' =&gt; { contains =&gt; [2,3,4] },
+        classification =&gt; { contains =&gt; [2,3,4] },
+        commenter   =&gt; { contains =&gt; [2,3,4] },
+        delta_ts    =&gt; { contains =&gt; [2,3,4] },
+        percentage_complete =&gt; { contains =&gt; [2,3,4] },
+        'requestees.login_name' =&gt; { contains =&gt; [2,3,4] },
+        'setters.login_name'    =&gt; { contains =&gt; [2,3,4] },
+    },
+    changedfrom =&gt; {
+        CHANGED_BROKEN,
+        CHANGED_VALUE_BROKEN,
+        # All fields should have a way to search for &quot;changing
+        # from a blank value&quot; probably.
+        blocked   =&gt; { contains =&gt; [3,4,5], no_criteria =&gt; 1 },
+        dependson =&gt; { contains =&gt; [2,4,5], no_criteria =&gt; 1 },
+        work_time =&gt; { contains =&gt; [1] },
+        FIELD_TYPE_BUG_ID, { contains =&gt; [5], no_criteria =&gt; 1 },
+    },
+    # changeto doesn't find remaining_time changes (possibly due to us not
+    # tracking that data properly).
+    #
+    # multi-valued fields are stored as comma-separated strings, so you
+    # can't do changedfrom/to on them.
+    #
+    # Perhaps commenter can either tell you who the last commenter was,
+    # or if somebody commented at a given time (combined with other
+    # charts).
+    #
+    # longdesc changedto/from doesn't do anything; maybe it should.
+    # Same for attach_data.thedata.
+    changedto =&gt; {
+        CHANGED_BROKEN,
+        CHANGED_VALUE_BROKEN,
+        'attach_data.thedata' =&gt; { contains =&gt; [1] },
+        longdesc         =&gt; { contains =&gt; [1] },
+        remaining_time   =&gt; { contains =&gt; [1] },
+    },
+    changedby =&gt; {
+        CHANGED_BROKEN,
+        # This should probably search the attacher or anybody who changed
+        # anything about an attachment at all.
+        'attach_data.thedata' =&gt; { contains =&gt; [1] },
+        # This should probably search the reporter.
+        creation_ts =&gt; { contains =&gt; [1] },
+    },
+};
+
+###################
+# Broken NotTests #
+###################
+
+# Common BROKEN_NOT values for the changed* fields.
+use constant CHANGED_BROKEN_NOT =&gt; (
+    &quot;attach_data.thedata&quot;   =&gt; { contains =&gt; [1] },
+    &quot;classification&quot;        =&gt; { contains =&gt; [1] },
+    &quot;commenter&quot;             =&gt; { contains =&gt; [1] },
+    &quot;delta_ts&quot;              =&gt; { contains =&gt; [1] },
+    percentage_complete     =&gt; { contains =&gt; [1] },
+    &quot;requestees.login_name&quot; =&gt; { contains =&gt; [1] },
+    &quot;setters.login_name&quot;    =&gt; { contains =&gt; [1] },
+);
+
+# For changedfrom and changedto.
+use constant CHANGED_FROM_TO_BROKEN_NOT =&gt; (
+    'longdescs.count' =&gt; { search =&gt; 1 },
+    &quot;bug_group&quot; =&gt; { contains =&gt; [1] },
+    &quot;cc&quot; =&gt; { contains =&gt; [1] },
+    &quot;estimated_time&quot; =&gt; { contains =&gt; [1] },
+    &quot;flagtypes.name&quot; =&gt; { contains =&gt; [1] },
+    &quot;keywords&quot; =&gt; { contains =&gt; [1] },    
+    FIELD_TYPE_MULTI_SELECT, { contains =&gt; [1] },
+);
+
+# These are field/operator combinations that are broken when run under NOT().
+use constant BROKEN_NOT =&gt; {
+    allwords       =&gt; {
+        cc =&gt; { contains =&gt; [1] },
+    },
+    'allwords-&lt;1&gt; &lt;2&gt;' =&gt; {
+        cc =&gt; { },
+    },
+    allwordssubstr =&gt; {
+        cc =&gt; { contains =&gt; [1] },
+    },
+    'allwordssubstr-&lt;1&gt;,&lt;2&gt;' =&gt; {
+        cc =&gt; { },
+    },
+    changedafter =&gt; {
+        &quot;attach_data.thedata&quot;   =&gt; { contains =&gt; [2, 3, 4] },
+        &quot;classification&quot;        =&gt; { contains =&gt; [2, 3, 4] },
+        &quot;commenter&quot;             =&gt; { contains =&gt; [2, 3, 4] },
+        percentage_complete     =&gt; { contains =&gt; [2, 3, 4] },
+        &quot;delta_ts&quot;              =&gt; { contains =&gt; [2, 3, 4] },
+        &quot;requestees.login_name&quot; =&gt; { contains =&gt; [2, 3, 4] },
+        &quot;setters.login_name&quot;    =&gt; { contains =&gt; [2, 3, 4] },
+    },
+    changedbefore =&gt; {
+        CHANGED_BROKEN_NOT,
+    },
+    changedby =&gt; {
+        CHANGED_BROKEN_NOT,
+        creation_ts =&gt; { contains =&gt; [1] },
+        work_time   =&gt; { contains =&gt; [1] },
+    },
+    changedfrom =&gt; {
+        CHANGED_BROKEN_NOT,
+        CHANGED_FROM_TO_BROKEN_NOT,
+        'attach_data.thedata' =&gt; { },
+        blocked         =&gt; { contains =&gt; [1, 2] },
+        dependson       =&gt; { contains =&gt; [1, 3] },
+        work_time       =&gt; { contains =&gt; [1] },
+        FIELD_TYPE_BUG_ID, { contains =&gt; [1 .. 4] },
+        
+    },
+    changedto =&gt; {
+        CHANGED_BROKEN_NOT,
+        CHANGED_FROM_TO_BROKEN_NOT,
+        longdesc =&gt; { contains =&gt; [1] },
+        &quot;remaining_time&quot; =&gt; { contains =&gt; [1] },
+    },
+    greaterthan =&gt; {
+        cc        =&gt; { contains =&gt; [1] },
+    },
+    greaterthaneq =&gt; {
+        cc               =&gt; { contains =&gt; [1] },
+    },
+};
+
+#############
+# Overrides #
+#############
+
+# These overrides are used in the TESTS constant, below.
+
+# Regex tests need unique test values for certain fields.
+use constant REGEX_OVERRIDE =&gt; {
+    'attachments.mimetype'  =&gt; { value =&gt; '^text/x-1-' },
+    bug_file_loc =&gt; { value =&gt; '^http://1-' },
+    see_also  =&gt; { value =&gt; '^http://1-' },
+    blocked   =&gt; { value =&gt; '^&lt;1&gt;$' },
+    dependson =&gt; { value =&gt; '^&lt;1&gt;$' },
+    bug_id    =&gt; { value =&gt; '^&lt;1&gt;$' },
+    'attachments.isobsolete' =&gt; { value =&gt; '^1'},
+    'attachments.ispatch'    =&gt; { value =&gt; '^1'},
+    'attachments.isprivate'  =&gt; { value =&gt; '^1' },
+    cclist_accessible        =&gt; { value =&gt; '^1' },
+    reporter_accessible      =&gt; { value =&gt; '^1' },
+    everconfirmed            =&gt; { value =&gt; '^1' },
+    'longdescs.count'        =&gt; { value =&gt; '^3' },
+    'longdescs.isprivate'    =&gt; { value =&gt; '^1' },
+    creation_ts =&gt; { value =&gt; '^2037-01-01' },
+    delta_ts    =&gt; { value =&gt; '^2037-01-01' },
+    deadline    =&gt; { value =&gt; '^2037-02-01' },
+    estimated_time =&gt; { value =&gt; '^1.0' },
+    remaining_time =&gt; { value =&gt; '^9.0' },
+    work_time      =&gt; { value =&gt; '^1.0' },
+    longdesc       =&gt; { value =&gt; '^1-' },
+    percentage_complete =&gt; { value =&gt; '^10' },
+    FIELD_TYPE_BUG_ID, { value =&gt; '^&lt;1&gt;$' },
+    FIELD_TYPE_DATETIME, { value =&gt; '^2037-03-01' }
+};
+
+# Common overrides between lessthan and lessthaneq.
+use constant LESSTHAN_OVERRIDE =&gt; (
+    alias             =&gt; { contains =&gt; [1,5] },
+    estimated_time    =&gt; { contains =&gt; [1,5] },
+    qa_contact        =&gt; { contains =&gt; [1,5] },
+    resolution        =&gt; { contains =&gt; [1,5] },
+    status_whiteboard =&gt; { contains =&gt; [1,5] },
+    FIELD_TYPE_TEXTAREA, { contains =&gt; [1,5] },
+    FIELD_TYPE_FREETEXT, { contains =&gt; [1,5] },
+);
+
+# The mandatorily-set fields have values higher than &lt;1&gt;,
+# so bug 5 shows up.
+use constant GREATERTHAN_OVERRIDE =&gt; (
+    classification =&gt; { contains =&gt; [2,3,4,5] },
+    assigned_to  =&gt; { contains =&gt; [2,3,4,5] },
+    bug_id       =&gt; { contains =&gt; [2,3,4,5] },
+    bug_group    =&gt; { contains =&gt; [1,2,3,4] },
+    bug_severity =&gt; { contains =&gt; [2,3,4,5] },
+    bug_status   =&gt; { contains =&gt; [2,3,4,5] },
+    component    =&gt; { contains =&gt; [2,3,4,5] },
+    commenter    =&gt; { contains =&gt; [2,3,4,5] },
+    # keywords matches if *any* keyword matches
+    keywords     =&gt; { contains =&gt; [1,2,3,4] },
+    longdesc     =&gt; { contains =&gt; [1,2,3,4] },
+    op_sys       =&gt; { contains =&gt; [2,3,4,5] },
+    priority     =&gt; { contains =&gt; [2,3,4,5] },
+    product      =&gt; { contains =&gt; [2,3,4,5] },
+    reporter     =&gt; { contains =&gt; [2,3,4,5] },
+    rep_platform =&gt; { contains =&gt; [2,3,4,5] },
+    short_desc   =&gt; { contains =&gt; [2,3,4,5] },
+    version      =&gt; { contains =&gt; [2,3,4,5] },
+    tag          =&gt; { contains =&gt; [1,2,3,4] },
+    target_milestone =&gt; { contains =&gt; [2,3,4,5] },
+    # Bug 2 is the only bug besides 1 that has a Requestee set.
+    'requestees.login_name'  =&gt; { contains =&gt; [2] },
+    FIELD_TYPE_SINGLE_SELECT, { contains =&gt; [2,3,4,5] },
+    # Override SINGLE_SELECT for resolution.
+    resolution =&gt; { contains =&gt; [2,3,4] },
+    # MULTI_SELECTs match if *any* value matches
+    FIELD_TYPE_MULTI_SELECT, { contains =&gt; [1,2,3,4] },
+);
+
+# For all positive multi-value types.
+use constant MULTI_BOOLEAN_OVERRIDE =&gt; (
+    'attachments.ispatch'    =&gt; { value =&gt; '1,1', contains =&gt; [1] },
+    'attachments.isobsolete' =&gt; { value =&gt; '1,1', contains =&gt; [1] },
+    'attachments.isprivate'  =&gt; { value =&gt; '1,1', contains =&gt; [1] },
+    cclist_accessible        =&gt; { value =&gt; '1,1', contains =&gt; [1] },
+    reporter_accessible      =&gt; { value =&gt; '1,1', contains =&gt; [1] },
+    'longdescs.isprivate'    =&gt; { value =&gt; '1,1', contains =&gt; [1] },
+    everconfirmed            =&gt; { value =&gt; '1,1', contains =&gt; [1] },
+);
+
+# Same as above, for negative multi-value types.
+use constant NEGATIVE_MULTI_BOOLEAN_OVERRIDE =&gt; (
+    'attachments.ispatch'    =&gt; { value =&gt; '1,1', contains =&gt; [2,3,4,5] },
+    'attachments.isobsolete' =&gt; { value =&gt; '1,1', contains =&gt; [2,3,4,5] },
+    'attachments.isprivate'  =&gt; { value =&gt; '1,1', contains =&gt; [2,3,4,5] },
+    cclist_accessible        =&gt; { value =&gt; '1,1', contains =&gt; [2,3,4,5] },
+    reporter_accessible      =&gt; { value =&gt; '1,1', contains =&gt; [2,3,4,5] },
+    'longdescs.isprivate'    =&gt; { value =&gt; '1,1', contains =&gt; [2,3,4,5] },
+    everconfirmed            =&gt; { value =&gt; '1,1', contains =&gt; [2,3,4,5] },
+);
+
+# For anyexact and anywordssubstr
+use constant ANY_OVERRIDE =&gt; (
+    'longdescs.count' =&gt; { contains =&gt; [1,2,3,4] },
+    'work_time' =&gt; { value =&gt; '1.0,2.0' },
+    dependson =&gt; { value =&gt; '&lt;1&gt;,&lt;3&gt;', contains =&gt; [1,3] },
+    MULTI_BOOLEAN_OVERRIDE,
+);
+
+# For all the changed* searches. The ones that have empty contains
+# are fields that never change in value, or will never be rationally
+# tracked in bugs_activity.
+use constant CHANGED_OVERRIDE =&gt; (
+    'attachments.submitter' =&gt; { contains =&gt; [] },
+    bug_id    =&gt; { contains =&gt; [] },
+    reporter  =&gt; { contains =&gt; [] },
+    tag       =&gt; { contains =&gt; [] },
+);
+
+#########
+# Tests #
+#########
+
+# The basic format of this is a hashref, where the keys are operators,
+# and each operator has an arrayref of tests that it runs. The tests
+# are hashrefs, with the following possible keys:
+#
+# contains: This is a list of bug numbers that the search is expected
+#           to contain. (This is bug numbers, like 1,2,3, not the bug
+#           ids. For a description of each bug number, see NUM_BUGS.)
+#           Any bug not listed in &quot;contains&quot; must *not* show up in the
+#           search result.
+# value: The value that you're searching for. There are certain special
+#        codes that will be replaced with bug values when the tests are
+#        run. In these examples below, &quot;#&quot; indicates a bug number:
+#
+#        &lt;#&gt; - The field value for this bug.
+#
+#              For any operator that has the string &quot;word&quot; in it, this is
+#              *all* the values for the current field from the numbered bug,
+#              joined by a space.
+#
+#              If the operator has the string &quot;substr&quot; in it, then we
+#              take a substring of the value (for single-value searches)
+#              or we take a substring of each value and join them (for
+#              multi-value &quot;word&quot; searches). The length of the substring
+#              is determined by the SUBSTR_SIZE constants above.)
+#
+#              For other operators, this just becomes the first value from
+#              the field for the numbered bug.
+#
+#              So, if we were running the &quot;equals&quot; test and checking the
+#              cc field, &lt;1&gt; would become the login name of the first cc on
+#              Bug 1. If we did an &quot;anywords&quot; search test, it would become
+#              a space-separated string of the login names of all the ccs
+#              on Bug 1. If we did an &quot;anywordssubstr&quot; search test, it would
+#              become a space-separated string of the first few characters
+#              of each CC's login name on Bug 1.
+#              
+#        &lt;#-id&gt; - The bug id of the numbered bug.
+#        &lt;#-reporter&gt; - The login name of the numbered bug's reporter.
+#        &lt;#-delta&gt; - The delta_ts of the numbered bug.
+#
+# escape: If true, we will call quotemeta() on the value immediately
+#         before passing it to Search.pm.
+#
+# transform: A function to call on any field value before inserting
+#            it for a &lt;#&gt; replacement. The transformation function
+#            gets all of the bug's values for the field as its arguments.
+# if_equal: This allows you to override &quot;contains&quot; for the case where
+#           the transformed value (from calling the &quot;transform&quot; function)
+#           is equal to the original value.
+#
+# override: This allows you to override &quot;contains&quot; and &quot;values&quot; for
+#           certain fields.
+use constant TESTS =&gt; {
+    equals =&gt; [
+        { contains =&gt; [1], value =&gt; '&lt;1&gt;' },
+    ],
+    notequals =&gt; [
+        { contains =&gt; [2,3,4,5], value =&gt; '&lt;1&gt;' },
+    ],
+    substring =&gt; [
+        { contains =&gt; [1], value =&gt; '&lt;1&gt;',
+          override =&gt; {
+              percentage_complete =&gt; { contains =&gt; [1,2,3] },
+          }
+        },
+    ],
+    casesubstring =&gt; [
+        { contains =&gt; [1], value =&gt; '&lt;1&gt;',
+          override =&gt; {
+              percentage_complete =&gt; { contains =&gt; [1,2,3] },
+          }
+        },
+        { contains =&gt; [], value =&gt; '&lt;1&gt;', transform =&gt; sub { lc($_[0]) },
+          extra_name =&gt; 'lc', if_equal =&gt; { contains =&gt; [1] },
+          override =&gt; {
+              percentage_complete =&gt; { contains =&gt; [1,2,3] },
+          }
+        },
+    ],
+    notsubstring =&gt; [
+        { contains =&gt; [2,3,4,5], value =&gt; '&lt;1&gt;',
+          override =&gt; {
+              percentage_complete =&gt; { contains =&gt; [4,5] },
+          },
+        }
+    ],
+    regexp =&gt; [
+        { contains =&gt; [1], value =&gt; '&lt;1&gt;', escape =&gt; 1,
+          override =&gt; {
+              percentage_complete =&gt; { value =&gt; '^10' },
+          }
+        },
+        { contains =&gt; [1], value =&gt; '^1-', override =&gt; REGEX_OVERRIDE },
+    ],
+    notregexp =&gt; [
+        { contains =&gt; [2,3,4,5], value =&gt; '&lt;1&gt;', escape =&gt; 1,
+          override =&gt; {
+              percentage_complete =&gt; { value =&gt; '^10' },
+          }
+        },
+        { contains =&gt; [2,3,4,5], value =&gt; '^1-', override =&gt; REGEX_OVERRIDE },
+    ],
+    lessthan =&gt; [
+        { contains =&gt; [1], value =&gt; 2, 
+          override =&gt; {
+              # A lot of these contain bug 5 because an empty value is validly
+              # less than the specified value.
+              bug_file_loc =&gt; { value =&gt; 'http://2-', contains =&gt; [1,5] },
+              see_also     =&gt; { value =&gt; 'http://2-' },
+              'attachments.mimetype' =&gt; { value =&gt; 'text/x-2-' },
+              blocked   =&gt; { value =&gt; '&lt;4-id&gt;', contains =&gt; [1,2] },
+              dependson =&gt; { value =&gt; '&lt;3-id&gt;', contains =&gt; [1,3] },
+              bug_id    =&gt; { value =&gt; '&lt;2-id&gt;' },
+              'attachments.isprivate'  =&gt; { value =&gt; 1, contains =&gt; [2,3,4] },
+              'attachments.isobsolete' =&gt; { value =&gt; 1, contains =&gt; [2,3,4] },
+              'attachments.ispatch'    =&gt; { value =&gt; 1, contains =&gt; [2,3,4] },
+              cclist_accessible        =&gt; { value =&gt; 1, contains =&gt; [2,3,4,5] },
+              reporter_accessible      =&gt; { value =&gt; 1, contains =&gt; [2,3,4,5] },
+              'longdescs.count'        =&gt; { value =&gt; 3, contains =&gt; [2,3,4,5] },
+              'longdescs.isprivate'    =&gt; { value =&gt; 1, contains =&gt; [1,2,3,4,5] },
+              everconfirmed            =&gt; { value =&gt; 1, contains =&gt; [2,3,4,5] },
+              creation_ts =&gt; { value =&gt; '2037-01-02', contains =&gt; [1,5] },
+              delta_ts    =&gt; { value =&gt; '2037-01-02', contains =&gt; [1,5] },
+              deadline    =&gt; { value =&gt; '2037-02-02', contains =&gt; [1,5] },
+              remaining_time =&gt; { value =&gt; 10, contains =&gt; [1,5] },
+              percentage_complete =&gt; { value =&gt; 11, contains =&gt; [1,5] },
+              longdesc =&gt; { value =&gt; '2-', contains =&gt; [1,5] },
+              work_time =&gt; { value =&gt; 1, contains =&gt; [5] },
+              FIELD_TYPE_BUG_ID, { value =&gt; '&lt;2&gt;', contains =&gt; [1,5] },
+              FIELD_TYPE_DATETIME, { value =&gt; '2037-03-02', contains =&gt; [1,5] },
+              LESSTHAN_OVERRIDE,
+          }
+        },
+    ],
+    lessthaneq =&gt; [
+        { contains =&gt; [1], value =&gt; '&lt;1&gt;',
+          override =&gt; {
+              'attachments.isobsolete' =&gt; { value =&gt; 0, contains =&gt; [2,3,4] },
+              'attachments.ispatch'    =&gt; { value =&gt; 0, contains =&gt; [2,3,4] },
+              'attachments.isprivate'  =&gt; { value =&gt; 0, contains =&gt; [2,3,4] },
+              cclist_accessible        =&gt; { value =&gt; 0, contains =&gt; [2,3,4,5] },
+              reporter_accessible      =&gt; { value =&gt; 0, contains =&gt; [2,3,4,5] },
+              'longdescs.count'        =&gt; { value =&gt; 2, contains =&gt; [2,3,4,5] },
+              'longdescs.isprivate'    =&gt; { value =&gt; -1, contains =&gt; [] },
+              everconfirmed            =&gt; { value =&gt; 0, contains =&gt; [2,3,4,5] },
+              bug_file_loc   =&gt; { contains =&gt; [1,5] },
+              blocked        =&gt; { contains =&gt; [1,2] },
+              deadline       =&gt; { contains =&gt; [1,5] },
+              dependson      =&gt; { contains =&gt; [1,3] },
+              creation_ts    =&gt; { contains =&gt; [1,5] },
+              delta_ts       =&gt; { contains =&gt; [1,5] },
+              remaining_time =&gt; { contains =&gt; [1,5] },
+              longdesc       =&gt; { contains =&gt; [1,5] },
+              percentage_complete =&gt; { contains =&gt; [1,5] },
+              work_time =&gt; { value =&gt; 1, contains =&gt; [1,5] },
+              FIELD_TYPE_BUG_ID, { contains =&gt; [1,5] },
+              FIELD_TYPE_DATETIME, { contains =&gt; [1,5] },
+              LESSTHAN_OVERRIDE,
+          },
+        },
+    ],
+    greaterthan =&gt; [
+        { contains =&gt; [2,3,4], value =&gt; '&lt;1&gt;',
+          override =&gt; {
+              dependson =&gt; { contains =&gt; [3] },
+              blocked   =&gt; { contains =&gt; [2] },
+              'attachments.ispatch'    =&gt; { value =&gt; 0, contains =&gt; [1] },
+              'attachments.isobsolete' =&gt; { value =&gt; 0, contains =&gt; [1] },
+              'attachments.isprivate'  =&gt; { value =&gt; 0, contains =&gt; [1] },
+              cclist_accessible        =&gt; { value =&gt; 0, contains =&gt; [1] },
+              reporter_accessible      =&gt; { value =&gt; 0, contains =&gt; [1] },
+              'longdescs.count'        =&gt; { value =&gt; 2, contains =&gt; [1] },
+              'longdescs.isprivate'    =&gt; { value =&gt; 0, contains =&gt; [1] },
+              everconfirmed            =&gt; { value =&gt; 0, contains =&gt; [1] },
+              'flagtypes.name'         =&gt; { value =&gt; 2, contains =&gt; [2,3,4] },
+              GREATERTHAN_OVERRIDE,
+          },
+        },
+    ],
+    greaterthaneq =&gt; [
+        { contains =&gt; [2,3,4], value =&gt; '&lt;2&gt;',
+          override =&gt; {
+              'attachments.ispatch'    =&gt; { value =&gt; 1, contains =&gt; [1] },
+              'attachments.isobsolete' =&gt; { value =&gt; 1, contains =&gt; [1] },
+              'attachments.isprivate'  =&gt; { value =&gt; 1, contains =&gt; [1] },
+              cclist_accessible        =&gt; { value =&gt; 1, contains =&gt; [1] },
+              reporter_accessible      =&gt; { value =&gt; 1, contains =&gt; [1] },
+              'longdescs.count'        =&gt; { value =&gt; 3, contains =&gt; [1] },
+              'longdescs.isprivate'    =&gt; { value =&gt; 1, contains =&gt; [1] },
+              everconfirmed            =&gt; { value =&gt; 1, contains =&gt; [1] },
+              dependson =&gt; { value =&gt; '&lt;3&gt;', contains =&gt; [1,3] },
+              blocked   =&gt; { contains =&gt; [1,2] },
+              GREATERTHAN_OVERRIDE,
+          }
+        },
+    ],
+    matches =&gt; [
+        { contains =&gt; [1], value =&gt; '&lt;1&gt;' },
+    ],
+    notmatches =&gt; [
+        { contains =&gt; [2,3,4,5], value =&gt; '&lt;1&gt;' },
+    ],
+    anyexact =&gt; [
+        { contains =&gt; [1,2], value =&gt; '&lt;1&gt;, &lt;2&gt;', 
+          override =&gt; { ANY_OVERRIDE } },
+    ],
+    anywordssubstr =&gt; [
+        { contains =&gt; [1,2], value =&gt; '&lt;1&gt; &lt;2&gt;', 
+          override =&gt; {
+              ANY_OVERRIDE,
+              percentage_complete =&gt; { contains =&gt; [1,2,3] },
+          }
+        },
+    ],
+    allwordssubstr =&gt; [
+        { contains =&gt; [1], value =&gt; '&lt;1&gt;',
+          override =&gt; {
+              MULTI_BOOLEAN_OVERRIDE,
+              # We search just the number &quot;1&quot; for percentage_complete,
+              # which matches a lot of bugs.
+              percentage_complete =&gt; { contains =&gt; [1,2,3] },
+          },
+        },
+        { contains =&gt; [], value =&gt; '&lt;1&gt;,&lt;2&gt;',
+          override =&gt; {
+              dependson =&gt; { value =&gt; '&lt;1-id&gt; &lt;3-id&gt;', contains =&gt; [] },
+              # bug 3 has the value &quot;21&quot; here, so matches &quot;2,1&quot;
+              percentage_complete =&gt; { value =&gt; '&lt;2&gt;,&lt;3&gt;', contains =&gt; [3] },
+              # 1 0 matches bug 1, which has both public and private comments.
+             'longdescs.isprivate' =&gt; { contains =&gt; [1] },              
+          }
+        },
+    ],
+    nowordssubstr =&gt; [
+        { contains =&gt; [2,3,4,5], value =&gt; '&lt;1&gt;',
+          override =&gt; {
+              # longdescs.isprivate translates to &quot;1 0&quot;, so no bugs should
+              # show up.
+              'longdescs.isprivate' =&gt; { contains =&gt; [] },
+              percentage_complete =&gt; { contains =&gt; [4,5] },
+              work_time =&gt; { contains =&gt; [2,3,4,5] },
+          }
+        },
+    ],
+    anywords =&gt; [
+        { contains =&gt; [1], value =&gt; '&lt;1&gt;',
+          override =&gt; {
+              MULTI_BOOLEAN_OVERRIDE,
+          }
+        },
+        { contains =&gt; [1,2], value =&gt; '&lt;1&gt; &lt;2&gt;',
+          override =&gt; {
+              MULTI_BOOLEAN_OVERRIDE,
+              dependson =&gt; { value =&gt; '&lt;1&gt; &lt;3&gt;', contains =&gt; [1,3] },
+              'longdescs.count' =&gt; { contains =&gt; [1,2,3,4] },              
+          },
+        },
+    ],
+    allwords =&gt; [
+        { contains =&gt; [1], value =&gt; '&lt;1&gt;',
+          override =&gt; { MULTI_BOOLEAN_OVERRIDE } },
+        { contains =&gt; [], value =&gt; '&lt;1&gt; &lt;2&gt;',
+          override =&gt; {
+            dependson =&gt; { contains =&gt; [], value =&gt; '&lt;2-id&gt; &lt;3-id&gt;' },
+            # 1 0 matches bug 1, which has both public and private comments.
+            'longdescs.isprivate' =&gt; { contains =&gt; [1] },
+          }
+        },
+    ],
+    nowords =&gt; [
+        { contains =&gt; [2,3,4,5], value =&gt; '&lt;1&gt;',
+          override =&gt; {
+              # longdescs.isprivate translates to &quot;1 0&quot;, so no bugs should
+              # show up.
+              'longdescs.isprivate' =&gt; { contains =&gt; [] },
+              work_time =&gt; { contains =&gt; [2,3,4,5] },
+          }
+        },
+    ],
+
+    changedbefore =&gt; [
+        { contains =&gt; [1], value =&gt; '&lt;1-delta&gt;',
+          override =&gt; {
+              CHANGED_OVERRIDE,
+              creation_ts =&gt; { contains =&gt; [1,5] },
+              blocked   =&gt; { contains =&gt; [1,2] },
+              dependson =&gt; { contains =&gt; [1,3] },
+              longdesc =&gt; { contains =&gt; [1,5] },
+              'longdescs.count' =&gt; { contains =&gt; [1,5] },
+          }
+        },
+    ],
+    changedafter =&gt; [
+        { contains =&gt; [2,3,4], value =&gt; '&lt;2-delta&gt;',
+          override =&gt; { 
+              CHANGED_OVERRIDE,
+              creation_ts =&gt; { contains =&gt; [3,4] },
+              # We only change this for one bug, and it doesn't match.
+              'longdescs.isprivate' =&gt; { contains =&gt; [] },
+              # Same for everconfirmed.
+              'everconfirmed' =&gt; { contains =&gt; [] },
+              # For blocked and dependson, they have the delta_ts of bug1
+              # in the bugs_activity table, so they won't ever match.
+              blocked   =&gt; { contains =&gt; [] },
+              dependson =&gt; { contains =&gt; [] },
+          }
+        },
+    ],
+    changedfrom =&gt; [
+        { contains =&gt; [1], value =&gt; '&lt;1&gt;',
+          override =&gt; {
+              CHANGED_OVERRIDE,
+              # The test never changes an already-set dependency field, but
+              # we *can* attempt to test searching against an empty value,
+              # which should get us some bugs.
+              blocked   =&gt; { value =&gt; '', contains =&gt; [1,2] },
+              dependson =&gt; { value =&gt; '', contains =&gt; [1,3] },
+              FIELD_TYPE_BUG_ID, { value =&gt; '', contains =&gt; [1,2,3,4] },
+              # longdesc changedfrom doesn't make any sense.
+              longdesc =&gt; { contains =&gt; [] },
+              # Nor does creation_ts changedfrom.
+              creation_ts =&gt; { contains =&gt; [] },
+              'attach_data.thedata' =&gt; { contains =&gt; [] },
+              bug_id =&gt; { value =&gt; '&lt;1-id&gt;', contains =&gt; [] },
+          },
+        },
+    ],
+    changedto =&gt; [
+        { contains =&gt; [1], value =&gt; '&lt;1&gt;',
+          override =&gt; {
+              CHANGED_OVERRIDE,
+              # I can't imagine any use for creation_ts changedto.
+              creation_ts =&gt; { contains =&gt; [] },
+          }
+        },
+    ],
+    changedby =&gt; [
+        { contains =&gt; [1], value =&gt; '&lt;1-reporter&gt;',
+          override =&gt; {
+              CHANGED_OVERRIDE,
+              blocked   =&gt; { contains =&gt; [1,2] },
+              dependson =&gt; { contains =&gt; [1,3] },
+          },
+        },
+    ],
+};
+
+# Fields that do not behave as we expect, for InjectionTest.
+# search =&gt; 1 means the Bugzilla::Search creation fails.
+# sql_error is a regex that specifies a SQL error that's OK for us to throw.
+# operator_ok overrides the &quot;brokenness&quot; of certain operators, so that they
+# are always OK for that field/operator combination.
+use constant INJECTION_BROKEN_FIELD =&gt; {
+    # Pg can't run injection tests against integer or date fields. See bug 577557.
+    'attachments.isobsolete' =&gt; { db_skip =&gt; ['Pg'] },
+    'attachments.ispatch'    =&gt; { db_skip =&gt; ['Pg'] },
+    'attachments.isprivate'  =&gt; { db_skip =&gt; ['Pg'] },
+    blocked                  =&gt; { db_skip =&gt; ['Pg'] },
+    bug_id                   =&gt; { db_skip =&gt; ['Pg'] },
+    cclist_accessible        =&gt; { db_skip =&gt; ['Pg'] },
+    creation_ts              =&gt; { db_skip =&gt; ['Pg'] },
+    days_elapsed             =&gt; { db_skip =&gt; ['Pg'] },
+    dependson                =&gt; { db_skip =&gt; ['Pg'] },
+    deadline                 =&gt; { db_skip =&gt; ['Pg'] },
+    delta_ts                 =&gt; { db_skip =&gt; ['Pg'] },
+    estimated_time           =&gt; { db_skip =&gt; ['Pg'] },
+    everconfirmed            =&gt; { db_skip =&gt; ['Pg'] },
+    'longdescs.isprivate'    =&gt; { db_skip =&gt; ['Pg'] },
+    percentage_complete      =&gt; { db_skip =&gt; ['Pg'] },
+    remaining_time           =&gt; { db_skip =&gt; ['Pg'] },
+    reporter_accessible      =&gt; { db_skip =&gt; ['Pg'] },
+    work_time                =&gt; { db_skip =&gt; ['Pg'] },
+    FIELD_TYPE_BUG_ID,          { db_skip =&gt; ['Pg'] },
+    FIELD_TYPE_DATETIME,        { db_skip =&gt; ['Pg'] },
+    owner_idle_time =&gt; { search =&gt; 1 },
+    'longdescs.count' =&gt; {
+        search =&gt; 1,
+        db_skip =&gt; ['Pg'],
+        operator_ok =&gt; [qw(allwords allwordssubstr anywordssubstr casesubstring
+                           changedbefore changedafter greaterthan greaterthaneq
+                           lessthan lessthaneq notregexp notsubstring
+                           nowordssubstr regexp substring anywords
+                           notequals nowords equals anyexact)],
+    },
+};
+
+# Operators that do not behave as we expect, for InjectionTest.
+# search =&gt; 1 means the Bugzilla::Search creation fails, but
+# field_ok contains fields that it does actually succeed for.
+use constant INJECTION_BROKEN_OPERATOR =&gt; {
+    changedafter  =&gt; { search =&gt; 1, field_ok =&gt; ['creation_ts'] },
+    changedbefore =&gt; { search =&gt; 1, field_ok =&gt; ['creation_ts'] },
+    changedby     =&gt; { search =&gt; 1 },
+};
+
+# Tests run by Bugzilla::Test::Search::InjectionTest.
+# We have to make sure the values are all one word or they'll be split
+# up by the multi-word tests.
+use constant INJECTION_TESTS =&gt; (
+    { value =&gt; ';SEMICOLON_TEST' },
+    { value =&gt; '--COMMENT_TEST'  },
+    { value =&gt; &quot;'QUOTE_TEST&quot; },
+    { value =&gt; &quot;';QUOTE_SEMICOLON_TEST&quot; },
+    { value =&gt; '/*STAR_COMMENT_TEST' }
+);
+
+#################
+# Special Tests #
+#################
+
+use constant SPECIAL_PARAM_TESTS =&gt; (
+    { field =&gt; 'bug_status', operator =&gt; 'anyexact', value =&gt; '__open__',
+      contains =&gt; [5] },
+    { field =&gt; 'bug_status', operator =&gt; 'anyexact', value =&gt; '__closed__',
+      contains =&gt; [1,2,3,4] },
+    { field =&gt; 'bug_status', operator =&gt; 'anyexact', value =&gt; '__all__',
+      contains =&gt; [1,2,3,4,5] },
+    
+    { field =&gt; 'resolution', operator =&gt; 'anyexact', value =&gt; '---',
+      contains =&gt; [5] },
+    
+    # email* query parameters.
+    { field =&gt; 'assigned_to', operator =&gt; 'anyexact',
+      value =&gt; '&lt;1&gt;, &lt;2-reporter&gt;', contains =&gt; [1,2],
+      extra_params =&gt; { emailreporter1 =&gt; 1 } },
+    { field =&gt; 'assigned_to', operator =&gt; 'equals',
+      value =&gt; '&lt;1&gt;', extra_name =&gt; 'email2', contains =&gt; [],
+      extra_params =&gt; {
+          email2 =&gt; generate_random_password(100), emaillongdesc2 =&gt; 1,
+      },
+    },
+    
+    # standard pronouns
+    { field =&gt; 'assigned_to', operator =&gt; 'equals', value =&gt; '%assignee%',
+      contains =&gt; [1,2,3,4,5] },
+    { field =&gt; 'reporter', operator =&gt; 'equals', value =&gt; '%reporter%',
+      contains =&gt; [1,2,3,4,5] },
+    { field =&gt; 'qa_contact', operator =&gt; 'equals', value =&gt; '%qacontact%',
+      contains =&gt; [1,2,3,4,5] },
+    { field =&gt; 'cc', operator =&gt; 'equals', value =&gt; '%user%',
+      contains =&gt; [1] },
+    # group pronouns
+    { field =&gt; 'reporter', operator =&gt; 'equals',
+      value =&gt; '%group.&lt;1-bug_group&gt;%', contains =&gt; [1,2,3,4,5] },
+    { field =&gt; 'assigned_to', operator =&gt; 'equals',
+      value =&gt; '%group.&lt;1-bug_group&gt;%', contains =&gt; [1,2,3,4,5] },
+    { field =&gt; 'qa_contact', operator =&gt; 'equals',
+      value =&gt; '%group.&lt;1-bug_group&gt;%', contains =&gt; [1,2,3,4] },
+    { field =&gt; 'cc', operator =&gt; 'equals',
+      value =&gt; '%group.&lt;1-bug_group&gt;%', contains =&gt; [1,2,3,4] },
+    { field =&gt; 'commenter', operator =&gt; 'equals',
+      value =&gt; '%group.&lt;1-bug_group&gt;%', contains =&gt; [1,2,3,4,5] },
+);
+
+use constant CUSTOM_SEARCH_TESTS =&gt; (
+    { name =&gt; 'OP without CP', contains =&gt; [1],
+      params =&gt; [
+          { f =&gt; 'OP' },
+          { f =&gt; 'bug_id', o =&gt; 'equals', v =&gt; '&lt;1&gt;' },
+      ]
+    },
+
+    { name =&gt; 'Empty OP/CP pair before criteria', contains =&gt; [1],
+      params =&gt; [
+          { f =&gt; 'OP' }, { f =&gt; 'CP' },
+          { f =&gt; 'bug_id', o =&gt; 'equals', v =&gt; '&lt;1&gt;' },
+      ]
+    },
+
+    { name =&gt; 'Empty OP/CP pair after criteria', contains =&gt; [1],
+      params =&gt; [
+          { f =&gt; 'bug_id', o =&gt; 'equals', v =&gt; '&lt;1&gt;' },
+          { f =&gt; 'OP' }, { f =&gt; 'CP' },
+      ]
+    },
+
+    { name  =&gt; 'empty OP/CP mid criteria', contains =&gt; [1],
+      columns =&gt; ['assigned_to'],
+      params =&gt; [
+          { f =&gt; 'bug_id', o =&gt; 'equals', v =&gt; '&lt;1&gt;' },
+          { f =&gt; 'OP' }, { f =&gt; 'CP' },
+          { f =&gt; 'assigned_to', o =&gt; 'substr', v =&gt; '@' },
+      ]
+    },
+
+    { name  =&gt; 'bug_id = 1 AND assigned_to contains @', contains =&gt; [1],
+      columns =&gt; ['assigned_to'],
+      params =&gt; [
+          { f =&gt; 'bug_id',      o =&gt; 'equals', v =&gt; '&lt;1&gt;' },
+          { f =&gt; 'assigned_to', o =&gt; 'substr', v =&gt; '@' },
+      ]
+    },
+
+    { name  =&gt; 'NOT(bug_id = 1) AND NOT(assigned_to = 2)',
+      contains =&gt; [3,4,5],
+      columns =&gt; ['assigned_to'],
+      params =&gt; [
+          { n =&gt; 1, f =&gt; 'bug_id',      o =&gt; 'equals', v =&gt; '&lt;1&gt;' },
+          { n =&gt; 1, f =&gt; 'assigned_to', o =&gt; 'equals', v =&gt; '&lt;2&gt;' },
+      ]
+    },
+
+    { name  =&gt; 'bug_id = 1 OR assigned_to = 2', contains =&gt; [1,2],
+      columns =&gt; ['assigned_to'], top_params =&gt; { j_top =&gt; 'OR' },
+      params =&gt; [
+          { f =&gt; 'bug_id',      o =&gt; 'equals', v =&gt; '&lt;1&gt;' },
+          { f =&gt; 'assigned_to', o =&gt; 'equals', v =&gt; '&lt;2&gt;' },
+      ]
+    },
+
+    { name =&gt; 'NOT(bug_id = 1 AND assigned_to = 1)', contains =&gt; [2,3,4,5],
+      columns =&gt; ['assigned_to'],
+      params =&gt; [
+          { f =&gt; 'OP', n =&gt; 1 },
+            { f =&gt; 'bug_id',      o =&gt; 'equals', v =&gt; '&lt;1&gt;' },
+            { f =&gt; 'assigned_to', o =&gt; 'equals', v =&gt; '&lt;1&gt;' },
+          { f =&gt; 'CP' },
+      ]
+    },
+
+
+    { name  =&gt; '(bug_id = 1 AND assigned_to contains @) '
+               . ' OR (bug_id = 2 AND assigned_to contains @)',
+      contains =&gt; [1,2], columns =&gt; ['assigned_to'],
+      top_params =&gt; { j_top =&gt; 'OR' },
+      params =&gt; [
+          { f =&gt; 'OP' },
+            { f =&gt; 'bug_id',      o =&gt; 'equals', v =&gt; '&lt;1&gt;' },
+            { f =&gt; 'assigned_to', o =&gt; 'substr', v =&gt; '@' },
+          { f =&gt; 'CP' },
+          { f =&gt; 'OP' },
+            { f =&gt; 'bug_id',      o =&gt; 'equals', v =&gt; '&lt;2&gt;' },
+            { f =&gt; 'assigned_to', o =&gt; 'substr', v =&gt; '@' },
+          { f =&gt; 'CP' },
+      ]
+    },
+
+    { name  =&gt; '(bug_id = 1 OR assigned_to = 2) '
+               . ' AND (bug_id = 2 OR assigned_to = 1)',
+      contains =&gt; [1,2], columns =&gt; ['assigned_to'],
+      params =&gt; [
+          { f =&gt; 'OP', j =&gt; 'OR' },
+            { f =&gt; 'bug_id',      o =&gt; 'equals', v =&gt; '&lt;1&gt;' },
+            { f =&gt; 'assigned_to', o =&gt; 'equals', v =&gt; '&lt;2&gt;' },
+          { f =&gt; 'CP' },
+          { f =&gt; 'OP', j =&gt; 'OR' },
+            { f =&gt; 'bug_id',      o =&gt; 'equals', v =&gt; '&lt;2&gt;' },
+            { f =&gt; 'assigned_to', o =&gt; 'equals', v =&gt; '&lt;1&gt;' },
+          { f =&gt; 'CP' },
+      ]
+    },
+
+    { name  =&gt; 'bug_id = 3 OR ( (bug_id = 1 OR assigned_to = 2) '
+               . ' AND (bug_id = 2 OR assigned_to = 1) )',
+      contains =&gt; [1,2,3], columns =&gt; ['assigned_to'],
+      top_params =&gt; { j_top =&gt; 'OR' },
+      params =&gt; [
+          { f =&gt; 'bug_id', o =&gt; 'equals', v =&gt; '&lt;3&gt;' },
+          { f =&gt; 'OP' },
+            { f =&gt; 'OP', j =&gt; 'OR' },
+              { f =&gt; 'bug_id',      o =&gt; 'equals', v =&gt; '&lt;1&gt;' },
+              { f =&gt; 'assigned_to', o =&gt; 'equals', v =&gt; '&lt;2&gt;' },
+            { f =&gt; 'CP' },
+            { f =&gt; 'OP', j =&gt; 'OR' },
+              { f =&gt; 'bug_id',      o =&gt; 'equals', v =&gt; '&lt;2&gt;' },
+              { f =&gt; 'assigned_to', o =&gt; 'equals', v =&gt; '&lt;1&gt;' },
+            { f =&gt; 'CP' },
+          { f =&gt; 'CP' },
+      ]
+    },
+
+    { name  =&gt; 'bug_id = 3 OR ( (bug_id = 1 OR assigned_to = 2) '
+               . ' AND (bug_id = 2 OR assigned_to = 1) ) OR bug_id = 4',
+      contains =&gt; [1,2,3,4], columns =&gt; ['assigned_to'],
+      top_params =&gt; { j_top =&gt; 'OR' },
+      params =&gt; [
+          { f =&gt; 'bug_id', o =&gt; 'equals', v =&gt; '&lt;3&gt;' },
+          { f =&gt; 'OP' },
+            { f =&gt; 'OP', j =&gt; 'OR' },
+              { f =&gt; 'bug_id',      o =&gt; 'equals', v =&gt; '&lt;1&gt;' },
+              { f =&gt; 'assigned_to', o =&gt; 'equals', v =&gt; '&lt;2&gt;' },
+            { f =&gt; 'CP' },
+            { f =&gt; 'OP', j =&gt; 'OR' },
+              { f =&gt; 'bug_id',      o =&gt; 'equals', v =&gt; '&lt;2&gt;' },
+              { f =&gt; 'assigned_to', o =&gt; 'equals', v =&gt; '&lt;1&gt;' },
+            { f =&gt; 'CP' },
+          { f =&gt; 'CP' },
+          { f =&gt; 'bug_id', o =&gt; 'equals', v =&gt; '&lt;4&gt;' },
+      ]
+    },
+
+);
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgxtlibBugzillaTestSearchCustomTestpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/CustomTest.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/CustomTest.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/CustomTest.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,115 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Google, Inc.
+# Portions created by the Initial Developer are Copyright (C) 2011 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+# This module represents a test with custom URL parameters.
+# Tests like this are specified in CUSTOM_SEARCH_TESTS in
+# Bugzilla::Test::Search::Constants.
+package Bugzilla::Test::Search::CustomTest;
+use base qw(Bugzilla::Test::Search::FieldTest);
+use strict;
+use warnings;
+
+use Bugzilla::Test::Search::FieldTest;
+use Bugzilla::Test::Search::OperatorTest;
+
+use Storable qw(dclone);
+
+###############
+# Constructor #
+###############
+
+sub new {
+  my ($class, $test, $search_test) = @_;
+  bless { raw_test =&gt; dclone($test), search_test =&gt; $search_test }, $class;
+}
+
+#############
+# Accessors #
+#############
+
+sub search_test { return $_[0]-&gt;{search_test} }
+sub name { return 'Custom: ' . $_[0]-&gt;test-&gt;{name} }
+sub test { return $_[0]-&gt;{raw_test} }
+
+sub operator_test { die &quot;unimplemented&quot; }
+sub field_object { die &quot;unimplemented&quot; }
+sub main_value { die &quot;unimplenmented&quot; }
+sub test_value { die &quot;unimplemented&quot; }
+# Custom tests don't use transforms.
+sub transformed_value_was_equal { 0 }
+sub debug_value {
+    my ($self) = @_;
+    my $string = '';
+    my $params = $self-&gt;search_params;
+    foreach my $param (keys %$params) {
+        $string .= $param . &quot;=&quot; . $params-&gt;{$param} . '&amp;';
+    }
+    chop($string);
+    return $string;
+}
+
+# The tests we know are broken for this operator/field combination.
+sub _known_broken { return {} }
+sub contains_known_broken { return undef }
+sub search_known_broken { return undef }
+sub field_not_yet_implemented { return undef }
+sub invalid_field_operator_combination { return undef }
+
+#########################################
+# Accessors: Bugzilla::Search Arguments #
+#########################################
+
+# Converts the f, o, v rows into f0, o0, v0, etc. and translates
+# the values appropriately.
+sub search_params {
+    my ($self) = @_;
+
+    my %params = %{ $self-&gt;test-&gt;{top_params} || {} };
+    my $counter = 0;
+    foreach my $row (@{ $self-&gt;test-&gt;{params} }) {
+        $row-&gt;{v} = $self-&gt;translate_value($row) if exists $row-&gt;{v};
+        foreach my $key (keys %$row) {
+            $params{&quot;${key}$counter&quot;} = $row-&gt;{$key};
+        }
+        $counter++;
+    }
+
+    return \%params;
+}
+
+sub translate_value {
+    my ($self, $row) = @_;
+    my $as_test = { field =&gt; $row-&gt;{f}, operator =&gt; $row-&gt;{o},
+                    value =&gt; $row-&gt;{v} };
+    my $operator_test = new Bugzilla::Test::Search::OperatorTest($row-&gt;{o},
+        $self-&gt;search_test);
+    my $field = Bugzilla::Field-&gt;check($row-&gt;{f});
+    my $field_test = new Bugzilla::Test::Search::FieldTest($operator_test,
+      $field, $as_test);
+    return $field_test-&gt;translated_value;
+}
+
+sub search_columns {
+    my ($self) = @_;
+    return ['bug_id', @{ $self-&gt;test-&gt;{columns} || [] }];
+}
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgxtlibBugzillaTestSearchFieldTestpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/FieldTest.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/FieldTest.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/FieldTest.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,614 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Everything Solved, Inc.
+# Portions created by the Initial Developer are Copyright (C) 2010 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+# This module represents the tests that get run on a single
+# operator/field combination for Bugzilla::Test::Search.
+# This is where all the actual testing happens.
+package Bugzilla::Test::Search::FieldTest;
+
+use strict;
+use warnings;
+use Bugzilla::Search;
+use Bugzilla::Test::Search::Constants;
+
+use Data::Dumper;
+use Scalar::Util qw(blessed);
+use Test::More;
+use Test::Exception;
+
+###############
+# Constructor #
+###############
+
+sub new {
+    my ($class, $operator_test, $field, $test) = @_;
+    return bless { operator_test =&gt; $operator_test,
+                   field_object =&gt; $field,
+                   raw_test     =&gt; $test }, $class;
+}
+
+#############
+# Accessors #
+#############
+
+sub num_tests { return TESTS_PER_RUN }
+
+# The Bugzilla::Test::Search::OperatorTest that this is a child of.
+sub operator_test { return $_[0]-&gt;{operator_test} }
+# The Bugzilla::Field being tested.
+sub field_object { return $_[0]-&gt;{field_object} }
+# The name of the field being tested, which we need much more often
+# than we need the object.
+sub field {
+    my ($self) = @_;
+    $self-&gt;{field_name} ||= $self-&gt;field_object-&gt;name;
+    return $self-&gt;{field_name};
+}
+# The Bugzilla::Test::Search object that this is a child of.
+sub search_test { return $_[0]-&gt;operator_test-&gt;search_test }
+# The operator being tested
+sub operator { return $_[0]-&gt;operator_test-&gt;operator }
+# The bugs currently being tested by Bugzilla::Test::Search.
+sub bugs { return $_[0]-&gt;search_test-&gt;bugs }
+sub bug {
+    my $self = shift;
+    return $self-&gt;search_test-&gt;bug(@_);
+}
+
+# The name displayed for this test by Test::More. Used in test descriptions.
+sub name {
+    my ($self) = @_;
+    my $field = $self-&gt;field;
+    my $operator = $self-&gt;operator;
+    my $value = $self-&gt;main_value;
+    
+    my $name = &quot;$field-$operator-$value&quot;;
+    if (my $extra_name = $self-&gt;test-&gt;{extra_name}) {
+        $name .= &quot;-$extra_name&quot;;
+    }
+    return $name;
+}
+
+# The appropriate value from the TESTS constant for this test, taking
+# into account overrides.
+sub test {
+    my $self = shift;
+    return $self-&gt;{test} if $self-&gt;{test};
+    
+    my %test = %{ $self-&gt;{raw_test} };
+    
+    # We have field name overrides...
+    my $override = $test{override}-&gt;{$self-&gt;field};
+    # And also field type overrides.
+    if (!$override) {
+        $override = $test{override}-&gt;{$self-&gt;field_object-&gt;type} || {};
+    }
+    
+    foreach my $key (%$override) {
+        $test{$key} = $override-&gt;{$key};
+    }
+    
+    $self-&gt;{test} = \%test;
+    return $self-&gt;{test};
+}
+
+# All the values for all the bugs for this field.
+sub _field_values {
+    my ($self) = @_;
+    return $self-&gt;{field_values} if $self-&gt;{field_values};
+    
+    my %field_values;
+    foreach my $number (1..NUM_BUGS) {
+        $field_values{$number} = $self-&gt;_field_values_for_bug($number);
+    }
+    $self-&gt;{field_values} = \%field_values;
+    return $self-&gt;{field_values};
+}
+# The values for this field for the numbered bug.
+sub bug_values {
+    my ($self, $number) = @_;
+    return @{ $self-&gt;_field_values-&gt;{$number} };
+}
+
+# The untranslated, non-overriden value--used in the name of the test
+# and other places.
+sub main_value { return $_[0]-&gt;{raw_test}-&gt;{value} }
+# The untranslated test value, taking into account overrides.
+sub test_value { return $_[0]-&gt;test-&gt;{value} };
+# The value translated appropriately for passing to Bugzilla::Search.
+sub translated_value {
+    my $self = shift;
+    if (!exists $self-&gt;{translated_value}) {
+        my $value = $self-&gt;search_test-&gt;value_translation_cache($self);
+        if (!defined $value) {
+            $value = $self-&gt;_translate_value();
+            $self-&gt;search_test-&gt;value_translation_cache($self, $value);
+        }
+        $self-&gt;{translated_value} = $value;
+    }
+    return $self-&gt;{translated_value};
+}
+# Used in failure diagnostic messages.
+sub debug_value {
+    my ($self) = @_;
+    return &quot;Value: '&quot; . $self-&gt;translated_value . &quot;'&quot;;
+}
+
+# True for a bug if we ran the &quot;transform&quot; function on it and the
+# result was equal to its first value.
+sub transformed_value_was_equal {
+    my ($self, $number, $value) = @_;
+    if (@_ &gt; 2) {
+        $self-&gt;{transformed_value_was_equal}-&gt;{$number} = $value;
+        $self-&gt;search_test-&gt;was_equal_cache($self, $number, $value);
+    }
+    my $cached = $self-&gt;search_test-&gt;was_equal_cache($self, $number);
+    return $cached if defined $cached;
+    return $self-&gt;{transformed_value_was_equal}-&gt;{$number};
+}
+
+# True if this test is supposed to contain the numbered bug.
+sub bug_is_contained {
+    my ($self, $number) = @_;
+    my $contains = $self-&gt;test-&gt;{contains};
+    if ($self-&gt;transformed_value_was_equal($number)
+        and !$self-&gt;test-&gt;{override}-&gt;{$self-&gt;field}-&gt;{contains})
+    {
+        $contains = $self-&gt;test-&gt;{if_equal}-&gt;{contains};
+    }
+    return grep($_ == $number, @$contains) ? 1 : 0;
+}
+
+###################################################
+# Accessors: Ways of doing SKIP and TODO on tests #
+###################################################
+
+# The tests we know are broken for this operator/field combination.
+sub _known_broken {
+    my ($self, $constant, $skip_pg_check) = @_;
+    $constant ||= KNOWN_BROKEN;
+    my $field = $self-&gt;field;
+    my $type = $self-&gt;field_object-&gt;type;
+    my $operator = $self-&gt;operator;
+    my $value = $self-&gt;main_value;
+    my $value_name = &quot;$operator-$value&quot;;
+    if (my $extra_name = $self-&gt;test-&gt;{extra_name}) {
+        $value_name .= &quot;-$extra_name&quot;;
+    }    
+    
+    my $value_broken = $constant-&gt;{$value_name}-&gt;{$field};
+    $value_broken ||= $constant-&gt;{$value_name}-&gt;{$type};
+    return $value_broken if $value_broken;
+    my $operator_broken = $constant-&gt;{$operator}-&gt;{$field};
+    $operator_broken ||= $constant-&gt;{$operator}-&gt;{$type};
+    return $operator_broken if $operator_broken;
+    return {};
+}
+
+# True if the &quot;contains&quot; search for the numbered bug is broken.
+# That is, either the result is supposed to contain it and doesn't,
+# or the result is not supposed to contain it and does.
+sub contains_known_broken {
+    my ($self, $number) = @_;
+    my $field = $self-&gt;field;
+    my $operator = $self-&gt;operator;
+
+    my $contains_broken = $self-&gt;_known_broken-&gt;{contains} || [];
+    if (grep($_ == $number, @$contains_broken)) {
+        return &quot;$field $operator contains $number is known to be broken&quot;;
+    }
+    return undef;
+}
+
+# Used by subclasses. Checks both bug_is_contained and contains_known_broken
+# to tell you whether or not the bug will *actually* be found by the test.
+sub will_actually_contain_bug {
+    my ($self, $number) = @_;
+    my $is_contained = $self-&gt;bug_is_contained($number) ? 1 : 0;
+    my $is_broken = $self-&gt;contains_known_broken($number) ? 1 : 0;
+
+    # If the test is supposed to contain the bug and *isn't* broken,
+    # then the test will contain the bug.
+    return 1 if ($is_contained and !$is_broken);
+    # If this test is *not* supposed to contain the bug, but that test is
+    # broken, then this test *will* contain the bug.
+    return 1 if (!$is_contained and $is_broken);
+
+    return 0;
+}
+
+# Returns a string if creating a Bugzilla::Search object throws an error,
+# with this field/operator/value combination.
+sub search_known_broken {
+    my ($self) = @_;
+    my $field = $self-&gt;field;
+    my $operator = $self-&gt;operator;
+    if ($self-&gt;_known_broken-&gt;{search}) {
+        return &quot;Bugzilla::Search for $field $operator is known to be broken&quot;;
+    }
+    return undef;
+}
+    
+# Returns a string if we haven't yet implemented the tests for this field,
+# but we plan to in the future.
+sub field_not_yet_implemented {
+    my ($self) = @_;
+    my $skip_this_field = grep { $_ eq $self-&gt;field } SKIP_FIELDS;
+    if ($skip_this_field) {
+        my $field = $self-&gt;field;
+        return &quot;$field testing not yet implemented&quot;;
+    }
+    return undef;
+}
+
+# Returns a message if this field/operator combination can't ever be run.
+# At no time in the future will this field/operator combination ever work.
+sub invalid_field_operator_combination {
+    my ($self) = @_;
+    my $field = $self-&gt;field;
+    my $operator = $self-&gt;operator;
+    
+    if ($field eq 'content' &amp;&amp; $operator !~ /matches/) {
+        return &quot;content field does not support $operator&quot;;
+    }
+    elsif ($operator =~ /matches/ &amp;&amp; $field ne 'content') {
+        return &quot;matches operator does not support fields other than content&quot;;
+    }
+    return undef;
+}
+
+# True if this field is broken in an OR combination.
+sub join_broken {
+    my ($self, $or_broken_map) = @_;
+    my $or_broken = $or_broken_map-&gt;{$self-&gt;field . '-' . $self-&gt;operator};
+    if (!$or_broken) {
+        # See if this is a comment field, and in that case, if there's
+        # a generic entry for all comment fields.
+        my $is_comment_field = COMMENT_FIELDS-&gt;{$self-&gt;field};
+        if ($is_comment_field) {
+            $or_broken = $or_broken_map-&gt;{'longdescs.-' . $self-&gt;operator};
+        }
+    }
+    return $or_broken;
+}
+
+#########################################
+# Accessors: Bugzilla::Search Arguments #
+#########################################
+
+# The data that will get passed to Bugzilla::Search as its arguments.
+sub search_params {
+    my ($self) = @_;
+    return $self-&gt;{search_params} if $self-&gt;{search_params};
+
+    my %params = (
+        &quot;field0-0-0&quot; =&gt; $self-&gt;field,
+        &quot;type0-0-0&quot;  =&gt; $self-&gt;operator,
+        &quot;value0-0-0&quot;  =&gt; $self-&gt;translated_value,
+    );
+    
+    $self-&gt;{search_params} = \%params;
+    return $self-&gt;{search_params};
+}
+
+sub search_columns {
+    my ($self) = @_;
+    my $field = $self-&gt;field;
+    my @search_fields = qw(bug_id);
+    if ($self-&gt;field_object-&gt;buglist) {
+        my $col_name = COLUMN_TRANSLATION-&gt;{$field} || $field;
+        push(@search_fields, $col_name);
+    }
+    return \@search_fields;
+}
+
+
+################
+# Field Values #
+################
+
+sub _field_values_for_bug {
+    my ($self, $number) = @_;
+    my $field = $self-&gt;field;
+
+    my @values;
+
+    if ($field =~ /^attach.+\.(.+)$/ ) {
+        my $attach_field = $1;
+        $attach_field = ATTACHMENT_FIELDS-&gt;{$attach_field} || $attach_field;
+        @values = $self-&gt;_values_for($number, 'attachments', $attach_field);
+    }
+    elsif (my $flag_field = FLAG_FIELDS-&gt;{$field}) {
+        @values = $self-&gt;_values_for($number, 'flags', $flag_field);
+    }
+    elsif (my $translation = COMMENT_FIELDS-&gt;{$field}) {
+        @values = $self-&gt;_values_for($number, 'comments', $translation);
+        # We want the last value to come first, so that single-value
+        # searches use the last comment.
+        @values = reverse @values;
+    }
+    elsif ($field eq 'longdescs.count') {
+        @values = scalar(@{ $self-&gt;bug($number)-&gt;comments });
+    }
+    elsif ($field eq 'work_time') {
+        @values = $self-&gt;_values_for($number, 'actual_time');
+    }
+    elsif ($field eq 'bug_group') {
+        @values = $self-&gt;_values_for($number, 'groups_in', 'name');
+    }
+    elsif ($field eq 'keywords') {
+        @values = $self-&gt;_values_for($number, 'keyword_objects', 'name'); 
+    }
+    elsif ($field eq 'content') {
+        @values = $self-&gt;_values_for($number, 'short_desc');
+    }
+    elsif ($field eq 'see_also') {
+        @values = $self-&gt;_values_for($number, 'see_also', 'name');
+    }
+    elsif ($field eq 'tag') {
+        @values = $self-&gt;_values_for($number, 'tags');
+    }
+    # Bugzilla::Bug truncates creation_ts, but we need the full value
+    # from the database. This has no special value for changedfrom,
+    # because it never changes.
+    elsif ($field eq 'creation_ts') {
+        my $bug = $self-&gt;bug($number);
+        my $creation_ts = Bugzilla-&gt;dbh-&gt;selectrow_array(
+            'SELECT creation_ts FROM bugs WHERE bug_id = ?',
+            undef, $bug-&gt;id);
+        @values = ($creation_ts);
+    }
+    else {
+        @values = $self-&gt;_values_for($number, $field);
+    }
+
+    # We convert user objects to their login name, here, all in one
+    # block for simplicity.
+    if (grep { $_ eq $field } USER_FIELDS) {
+        # requestees.login_name is empty for most bugs (but checking
+        # blessed(undef) handles that.
+        # Values that come from %original_values aren't User objects.
+        @values = map { blessed($_) ? $_-&gt;login : $_ } @values;
+        @values = grep { defined $_ } @values;
+    }
+    
+    return \@values;
+}
+
+sub _values_for {
+    my ($self, $number, $bug_field, $item_field) = @_;
+
+    my $item;
+    if ($self-&gt;operator eq 'changedfrom') {
+        $item = $self-&gt;search_test-&gt;bug_create_value($number, $bug_field);
+    }
+    else {
+        my $bug = $self-&gt;bug($number);
+        $item = $bug-&gt;$bug_field;
+    }
+
+    if ($item_field) {
+        if ($bug_field eq 'flags' and $item_field eq 'name') {
+            return (map { $_-&gt;name . $_-&gt;status } @$item);
+        }
+        return (map { $self-&gt;_get_item($_, $item_field) } @$item);
+    }
+
+    return @$item if ref($item) eq 'ARRAY';
+    return $item if defined $item;
+    return ();
+}
+
+sub _get_item {
+    my ($self, $from, $field) = @_;
+    if (blessed($from)) {
+        return $from-&gt;$field;
+    }
+    return $from-&gt;{$field};
+}
+
+#####################
+# Value Translation #
+#####################
+
+# This function translates the &quot;value&quot; specified in TESTS into an actual
+# search value to pass to Search.pm. This means that we get the value
+# from the current bug (or, in the case of changedfrom, from %original_values)
+# and then we insert it as required into the &quot;value&quot; from TESTS. (For example,
+# &lt;1&gt; becomes the value for the field from bug 1.)
+sub _translate_value {
+    my $self = shift;
+    my $value = $self-&gt;test_value;
+    foreach my $number (1..NUM_BUGS) {
+        $value = $self-&gt;_translate_value_for_bug($number, $value);
+    }
+    # Sanity check to make sure that none of the &lt;&gt; stuff was left in.
+    if ($value =~ /&lt;\d/) {
+        die $self-&gt;name . &quot;: value untranslated: $value\n&quot;;
+    }
+    return $value;
+}
+
+sub _translate_value_for_bug {
+    my ($self, $number, $value) = @_;
+    
+    my $bug = $self-&gt;bug($number);
+    
+    my $bug_id = $bug-&gt;id;
+    $value =~ s/&lt;$number-id&gt;/$bug_id/g;
+    my $bug_delta = $bug-&gt;delta_ts;
+    $value =~ s/&lt;$number-delta&gt;/$bug_delta/g;
+    my $reporter = $bug-&gt;reporter-&gt;login;
+    $value =~ s/&lt;$number-reporter&gt;/$reporter/g;
+    if ($value =~ /&lt;$number-bug_group&gt;/) {
+        my @bug_groups = map { $_-&gt;name } @{ $bug-&gt;groups_in };
+        @bug_groups = grep { $_ =~ /^\d+-group-/ } @bug_groups;
+        my $group = $bug_groups[0];
+        $value =~ s/&lt;$number-bug_group&gt;/$group/g;
+    }
+    
+    my @bug_values = $self-&gt;bug_values($number);    
+    return $value if !@bug_values;
+    
+    if ($self-&gt;operator =~ /substr/) {
+        @bug_values = map { $self-&gt;_substr_value($_) } @bug_values;
+    }
+
+    my $string_value = $bug_values[0];
+    if ($self-&gt;operator =~ /word/) {
+        $string_value = join(' ', @bug_values);
+    }
+    if (my $func = $self-&gt;test-&gt;{transform}) {
+        my $transformed = $func-&gt;(@bug_values);
+        my $is_equal = $transformed eq $bug_values[0] ? 1 : 0;
+        $self-&gt;transformed_value_was_equal($number, $is_equal);
+        $string_value = $transformed;
+    }
+
+    if ($self-&gt;test-&gt;{escape}) {
+        $string_value = quotemeta($string_value);
+    }
+    $value =~ s/&lt;$number&gt;/$string_value/g;
+    
+    return $value;
+}
+
+sub _substr_value {
+    my ($self, $value) = @_;
+    my $field = $self-&gt;field;
+    my $type  = $self-&gt;field_object-&gt;type;
+    my $substr_size = SUBSTR_SIZE;
+    if (exists FIELD_SUBSTR_SIZE-&gt;{$field}) {
+        $substr_size = FIELD_SUBSTR_SIZE-&gt;{$field};
+    }
+    elsif (exists FIELD_SUBSTR_SIZE-&gt;{$type}) {
+        $substr_size = FIELD_SUBSTR_SIZE-&gt;{$type};
+    }
+    if ($substr_size &gt; 0) {
+        # The field name is included in every field value, and if it's
+        # long, it might take up the whole substring, and we don't want that.
+        if (!grep { $_ eq $field or $_ eq $type } SUBSTR_NO_FIELD_ADD) {
+            $substr_size += length($field);
+        }
+        my $string = substr($value, 0, $substr_size);
+        return $string;
+    }
+    return substr($value, $substr_size);
+}
+
+#####################
+# Main Test Methods #
+#####################
+
+sub run {
+    my ($self) = @_;
+    
+    my $invalid_combination = $self-&gt;invalid_field_operator_combination;
+    my $field_not_implemented = $self-&gt;field_not_yet_implemented;
+
+    SKIP: {    
+        skip($invalid_combination, $self-&gt;num_tests) if $invalid_combination;
+        TODO: {
+            todo_skip ($field_not_implemented, $self-&gt;num_tests) if $field_not_implemented;
+            $self-&gt;do_tests();
+        }
+    }
+}
+
+sub do_tests {
+    my ($self) = @_;
+    my $name = $self-&gt;name;
+
+    my $search_broken = $self-&gt;search_known_broken;
+    
+    my $search = $self-&gt;_test_search_object_creation();
+
+    my $sql;
+    TODO: {
+        local $TODO = $search_broken if $search_broken;
+        lives_ok { $sql = $search-&gt;sql } &quot;$name: generate SQL&quot;;
+    }
+    
+    my $results;
+    SKIP: {
+        skip &quot;Can't run SQL without any SQL&quot;, 1 if !defined $sql;
+        $results = $self-&gt;_test_sql($sql);
+    }
+
+    $self-&gt;_test_content($results, $sql);
+}
+
+sub _test_search_object_creation {
+    my ($self) = @_;
+    my $name = $self-&gt;name;
+    my @args = (fields =&gt; $self-&gt;search_columns, params =&gt; $self-&gt;search_params);
+    my $search;
+    lives_ok { $search = new Bugzilla::Search(@args) }
+             &quot;$name: create search object&quot;;
+    return $search;
+}
+
+sub _test_sql {
+    my ($self, $sql) = @_;
+    my $dbh = Bugzilla-&gt;dbh;
+    my $name = $self-&gt;name;
+    my $results;
+    lives_ok { $results = $dbh-&gt;selectall_arrayref($sql) } &quot;$name: Run SQL Query&quot;
+        or diag($sql);
+    return $results;
+}
+
+sub _test_content {
+    my ($self, $results, $sql) = @_;
+
+    SKIP: {
+        skip &quot;Without results we can't test them&quot;, NUM_BUGS if !$results;
+        foreach my $number (1..NUM_BUGS) {
+            $self-&gt;_test_content_for_bug($number, $results, $sql);
+        }
+    }
+}
+
+sub _test_content_for_bug {
+    my ($self, $number, $results, $sql) = @_;
+    my $name = $self-&gt;name;
+    
+    my $contains_known_broken = $self-&gt;contains_known_broken($number);
+    
+    my %result_ids = map { $_-&gt;[0] =&gt; 1 } @$results;
+    my $bug_id = $self-&gt;bug($number)-&gt;id;
+    
+    TODO: {
+        local $TODO = $contains_known_broken if $contains_known_broken;
+        if ($self-&gt;bug_is_contained($number)) {
+            ok($result_ids{$bug_id},
+               &quot;$name: contains bug $number ($bug_id)&quot;)
+                or diag Dumper($results) . $self-&gt;debug_value . &quot;\n\nSQL: $sql&quot;;
+        }
+        else {
+            ok(!$result_ids{$bug_id},
+               &quot;$name: does not contain bug $number ($bug_id)&quot;)
+                or diag Dumper($results) . $self-&gt;debug_value . &quot;\n\nSQL: $sql&quot;;
+        }
+    }
+}
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgxtlibBugzillaTestSearchFieldTestNormalpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/FieldTestNormal.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/FieldTestNormal.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/FieldTestNormal.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,118 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Everything Solved, Inc.
+# Portions created by the Initial Developer are Copyright (C) 2010 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+# This is the same as a FieldTest, except that it uses normal URL
+# parameters instead of Boolean Charts.
+package Bugzilla::Test::Search::FieldTestNormal;
+use strict;
+use warnings;
+use base qw(Bugzilla::Test::Search::FieldTest);
+
+use Scalar::Util qw(blessed);
+
+use constant CH_OPERATOR =&gt; {
+    changedafter  =&gt; 'chfieldfrom',
+    changedbefore =&gt; 'chfieldto',
+    changedto     =&gt; 'chfieldvalue',
+};
+
+use constant EMAIL_FIELDS =&gt; qw(assigned_to qa_contact cc reporter commenter);
+
+# Normally, we just clone a FieldTest because that's the best for performance,
+# overall--that way we don't have to translate the value again. However,
+# sometimes (like in Bugzilla::Test::Search's direct code) we just want
+# to create a FieldTestNormal.
+sub new {
+    my $class = shift;
+    my ($first_arg) = @_;
+    if (blessed $first_arg
+        and $first_arg-&gt;isa('Bugzilla::Test::Search::FieldTest'))
+    {
+        my $self = { %$first_arg };
+        return bless $self, $class;
+    }
+    return $class-&gt;SUPER::new(@_);
+}
+
+sub name {
+    my $self = shift;
+    my $name = $self-&gt;SUPER::name(@_);
+    return &quot;$name (Normal Params)&quot;;
+}
+
+sub search_columns {
+    my $self = shift;
+    my $field = $self-&gt;field;
+    # For the assigned_to, qa_contact, and reporter fields, have the
+    # &quot;Normal Params&quot; test check that the _realname columns work
+    # all by themselves.
+    if (grep($_ eq $field, EMAIL_FIELDS) &amp;&amp; $self-&gt;field_object-&gt;buglist) {
+        return ['bug_id', &quot;${field}_realname&quot;]
+    }
+    return $self-&gt;SUPER::search_columns(@_);
+}
+
+sub search_params {
+    my ($self) = @_;
+    my $field = $self-&gt;field;
+    my $operator = $self-&gt;operator;
+    my $value = $self-&gt;translated_value;
+    if ($operator eq 'anyexact') {
+        $value = [split ',', $value];
+    }
+    
+    if (my $ch_param = CH_OPERATOR-&gt;{$operator}) {
+        if ($field eq 'creation_ts') {
+            $field = '[Bug creation]';
+        }
+        return { chfield =&gt; $field, $ch_param =&gt; $value };
+    }
+    
+    if ($field eq 'delta_ts' and $operator eq 'greaterthaneq') {
+        return { chfieldfrom =&gt; $value };
+    }
+    if ($field eq 'delta_ts' and $operator eq 'lessthaneq') {
+        return { chfieldto =&gt; $value };
+    }
+    
+    if ($field eq 'deadline' and $operator eq 'greaterthaneq') {
+        return { deadlinefrom =&gt; $value };
+    }
+    if ($field eq 'deadline' and $operator eq 'lessthaneq') {
+        return { deadlineto =&gt; $value };
+    }
+    
+    if (grep { $_ eq $field } EMAIL_FIELDS) {
+        $field = 'longdesc' if $field eq 'commenter';
+        return {
+            email1           =&gt; $value,
+            &quot;email${field}1&quot; =&gt; 1,
+            emailtype1       =&gt; $operator,
+            # Used to do extra tests on special sorts of email* combinations.
+            %{ $self-&gt;test-&gt;{extra_params} || {} },
+        };
+    }
+
+    $field =~ s/\./_/g;
+    return { $field =&gt; $value, &quot;${field}_type&quot; =&gt; $operator };
+}
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgxtlibBugzillaTestSearchInjectionTestpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/InjectionTest.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/InjectionTest.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/InjectionTest.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,91 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Everything Solved, Inc.
+# Portions created by the Initial Developer are Copyright (C) 2010 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+# This module represents the SQL Injection tests that get run on a single
+# operator/field combination for Bugzilla::Test::Search.
+package Bugzilla::Test::Search::InjectionTest;
+use base qw(Bugzilla::Test::Search::FieldTest);
+
+use strict;
+use warnings;
+use Bugzilla::Test::Search::Constants;
+use Test::Exception;
+
+sub num_tests { return NUM_SEARCH_TESTS }
+
+sub _known_broken {
+    my ($self) = @_;
+    my $operator_broken = INJECTION_BROKEN_OPERATOR-&gt;{$self-&gt;operator};
+    # We don't want to auto-vivify $operator_broken and thus make it true.
+    my @field_ok = $operator_broken ? @{ $operator_broken-&gt;{field_ok} || [] }
+                                    : ();
+    $operator_broken = undef if grep { $_ eq $self-&gt;field } @field_ok;
+
+    my $field_broken = INJECTION_BROKEN_FIELD-&gt;{$self-&gt;field}
+                       || INJECTION_BROKEN_FIELD-&gt;{$self-&gt;field_object-&gt;type};
+    # We don't want to auto-vivify $field_broken and thus make it true.
+    my @operator_ok = $field_broken ? @{ $field_broken-&gt;{operator_ok} || [] }
+                                    : ();
+    $field_broken = undef if grep { $_ eq $self-&gt;operator } @operator_ok;
+
+    return $operator_broken || $field_broken || {};
+}
+
+sub sql_error_ok { return $_[0]-&gt;_known_broken-&gt;{sql_error} }
+
+# Injection tests only skip fields on certain dbs.
+sub field_not_yet_implemented {
+    my ($self) = @_;
+    # We use the constant directly because we don't want operator_ok
+    # or field_ok to stop us.
+    my $broken = INJECTION_BROKEN_FIELD-&gt;{$self-&gt;field}
+                 || INJECTION_BROKEN_FIELD-&gt;{$self-&gt;field_object-&gt;type};
+    my $skip_for_dbs = $broken-&gt;{db_skip};
+    return undef if !$skip_for_dbs;
+    my $dbh = Bugzilla-&gt;dbh;
+    if (my ($skip) = grep { $dbh-&gt;isa(&quot;Bugzilla::DB::$_&quot;) } @$skip_for_dbs) {
+        my $field = $self-&gt;field;
+        return &quot;$field injection testing is not supported with $skip&quot;;
+    }
+    return undef;
+}
+# Injection tests don't do translation.
+sub translated_value { $_[0]-&gt;test_value }
+
+sub name { return &quot;injection-&quot; . $_[0]-&gt;SUPER::name; }
+
+# Injection tests don't check content.
+sub _test_content {}
+
+sub _test_sql {
+    my $self = shift;
+    my ($sql) = @_;
+    my $dbh = Bugzilla-&gt;dbh;
+    my $name = $self-&gt;name;
+    if (my $error_ok = $self-&gt;sql_error_ok) {
+        throws_ok { $dbh-&gt;selectall_arrayref($sql) } $error_ok,
+                  &quot;$name: SQL query dies, as we expect&quot;;
+        return;
+    }
+    return $self-&gt;SUPER::_test_sql(@_);
+}
+
+1;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgxtlibBugzillaTestSearchNotTestpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/NotTest.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/NotTest.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/NotTest.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,75 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Everything Solved, Inc.
+# Portions created by the Initial Developer are Copyright (C) 2010 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+# This module runs tests just like a normal FieldTest, AndTest,
+# or OrTest, but in a NOT chart instead of a normal chart.
+#
+# Logically this should be a mixin of some sort so that we can apply
+# it to OrTest and AndTest, but without Moose there isn't much of an
+# easy way to do that.
+package Bugzilla::Test::Search::NotTest;
+use base qw(Bugzilla::Test::Search::FieldTest);
+use strict;
+use warnings;
+use Bugzilla::Test::Search::Constants;
+
+# We just clone a FieldTest because that's the best for performance,
+# overall--that way we don't have to translate the value again.
+sub new {
+    my ($class, $field_test) = @_;
+    my $self = { %$field_test };
+    return bless $self, $class;
+}
+
+#############
+# Accessors #
+#############
+
+sub name {
+    my ($self) = @_;
+    return &quot;NOT(&quot; . $self-&gt;SUPER::name . &quot;)&quot;;
+}
+
+# True if this test is supposed to contain the numbered bug. Reversed for
+# NOT tests.
+sub bug_is_contained {
+    my $self = shift;
+    my ($number) = @_;
+    # No search ever returns bug 6, because it's protected by security groups
+    # that the searcher isn't a member of.
+    return 0 if $number == 6;
+    return $self-&gt;SUPER::bug_is_contained(@_) ? 0 : 1;
+}
+
+# NOT tests have their own constant for tracking broken-ness.
+sub _known_broken {
+    my ($self) = @_;
+    return $self-&gt;SUPER::_known_broken(BROKEN_NOT, 'skip pg check');
+}
+
+sub search_params {
+    my ($self) = @_;
+    my %params = %{ $self-&gt;SUPER::search_params() };
+    $params{negate0} = 1;
+    return \%params;
+}
+
+1;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgxtlibBugzillaTestSearchOperatorTestpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/OperatorTest.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/OperatorTest.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/OperatorTest.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,117 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Everything Solved, Inc.
+# Portions created by the Initial Developer are Copyright (C) 2010 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+# This module represents the tests that get run on a single operator
+# from the TESTS constant in Bugzilla::Search::Test::Constants.
+package Bugzilla::Test::Search::OperatorTest;
+
+use strict;
+use warnings;
+use Bugzilla::Test::Search::Constants;
+use Bugzilla::Test::Search::FieldTest;
+use Bugzilla::Test::Search::FieldTestNormal;
+use Bugzilla::Test::Search::InjectionTest;
+use Bugzilla::Test::Search::OrTest;
+use Bugzilla::Test::Search::AndTest;
+use Bugzilla::Test::Search::NotTest;
+
+###############
+# Constructor #
+###############
+
+sub new {
+    my ($invocant, $operator, $search_test) = @_;
+    $search_test ||= $invocant-&gt;search_test;
+    my $class = ref($invocant) || $invocant;
+    return bless { search_test =&gt; $search_test, operator =&gt; $operator }, $class;
+}
+
+#############
+# Accessors #
+#############
+
+# The Bugzilla::Test::Search object that this is a child of.
+sub search_test { return $_[0]-&gt;{search_test} }
+# The operator being tested
+sub operator { return $_[0]-&gt;{operator} }
+# The tests that we're going to run on this operator.
+sub tests { return @{ TESTS-&gt;{$_[0]-&gt;operator } } }
+# The fields we're going to test for this operator.
+sub test_fields { return $_[0]-&gt;search_test-&gt;all_fields }
+
+sub run {
+    my ($self) = @_;
+
+    foreach my $field ($self-&gt;test_fields) {
+        foreach my $test ($self-&gt;tests) {
+            my $field_test =
+                new Bugzilla::Test::Search::FieldTest($self, $field, $test);
+            $field_test-&gt;run();
+            my $normal_test =
+                new Bugzilla::Test::Search::FieldTestNormal($field_test);
+            $normal_test-&gt;run();
+            my $not_test = new Bugzilla::Test::Search::NotTest($field_test);
+            $not_test-&gt;run();
+            
+            next if !$self-&gt;search_test-&gt;option('long');
+
+            # Run the OR tests. This tests every other operator (including
+            # this operator itself) in combination with every other field,
+            # in an OR with this operator and field.
+            foreach my $other_operator ($self-&gt;search_test-&gt;all_operators) {
+                $self-&gt;run_join_tests($field_test, $other_operator);
+            }
+        }
+        foreach my $test (INJECTION_TESTS) {
+            my $injection_test =
+                new Bugzilla::Test::Search::InjectionTest($self, $field, $test);
+            $injection_test-&gt;run();
+        }
+    }
+}
+
+sub run_join_tests {
+    my ($self, $field_test, $other_operator) = @_;
+
+    my $other_operator_test = $self-&gt;new($other_operator);
+    foreach my $other_test ($other_operator_test-&gt;tests) {
+        foreach my $other_field ($self-&gt;test_fields) {
+            $self-&gt;_run_one_join_test($field_test, $other_operator_test,
+                                      $other_field, $other_test);
+            $self-&gt;search_test-&gt;clean_test_history();
+        }
+    }
+}
+
+sub _run_one_join_test {
+    my ($self, $field_test, $other_operator_test, $other_field, $other_test) = @_;
+    my $other_field_test =
+        new Bugzilla::Test::Search::FieldTest($other_operator_test,
+                                              $other_field, $other_test);
+    my $or_test = new Bugzilla::Test::Search::OrTest($field_test,
+                                                     $other_field_test);
+    $or_test-&gt;run();
+    my $and_test = new Bugzilla::Test::Search::AndTest($field_test,
+                                                       $other_field_test);
+    $and_test-&gt;run();
+}
+
+1;
</ins><span class="cx">\ No newline at end of file
</span></span></pre></div>
<a id="trunkWebsitesbugswebkitorgxtlibBugzillaTestSearchOrTestpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/OrTest.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/OrTest.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search/OrTest.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,155 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Everything Solved, Inc.
+# Portions created by the Initial Developer are Copyright (C) 2010 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+# This test combines two field/operator combinations using OR in
+# a single boolean chart.
+package Bugzilla::Test::Search::OrTest;
+use base qw(Bugzilla::Test::Search::FieldTest);
+
+use Bugzilla::Test::Search::Constants;
+use List::MoreUtils qw(all any uniq);
+
+use constant type =&gt; 'OR';
+
+###############
+# Constructor #
+###############
+
+sub new {
+    my $class = shift;
+    my $self = { field_tests =&gt; [@_] };
+    return bless $self, $class;
+}
+
+#############
+# Accessors #
+#############
+
+sub field_tests { return @{ $_[0]-&gt;{field_tests} } }
+sub search_test { ($_[0]-&gt;field_tests)[0]-&gt;search_test }
+
+sub name {
+    my ($self) = @_;
+    my @names = map { $_-&gt;name } $self-&gt;field_tests;
+    return join('-' . $self-&gt;type . '-', @names);
+}
+
+# In an OR test, bugs ARE supposed to be contained if they are contained
+# by ANY test.
+sub bug_is_contained {
+    my ($self, $number) = @_;
+    return any { $_-&gt;bug_is_contained($number) } $self-&gt;field_tests;
+}
+
+# Needed only for failure messages
+sub debug_value {
+    my ($self) = @_;
+    my @values = map { $_-&gt;field . ' ' . $_-&gt;debug_value } $self-&gt;field_tests;
+    return join(' ' . $self-&gt;type . ' ', @values);
+}
+
+########################
+# SKIP &amp; TODO Messages #
+########################
+
+sub field_not_yet_implemented {
+    my ($self) = @_;
+    return $self-&gt;_join_messages('field_not_yet_implemented');
+}
+sub invalid_field_operator_combination {
+    my ($self) = @_;
+    return $self-&gt;_join_messages('invalid_field_operator_combination');
+}
+sub search_known_broken {
+    my ($self) = @_;
+    return $self-&gt;_join_messages('search_known_broken');    
+}
+
+sub _join_messages {
+    my ($self, $message_method) = @_;
+    my @messages = map { $_-&gt;$message_method } $self-&gt;field_tests;
+    @messages = grep { $_ } @messages;
+    return join(' AND ', @messages);
+}
+
+sub _bug_will_actually_be_contained {
+    my ($self, $number) = @_;
+
+    foreach my $test ($self-&gt;field_tests) {
+        # Some tests are broken in such a way that they actually
+        # generate no criteria in the SQL. In this case, the only way
+        # the test contains the bug is if *another* test contains it.
+        next if $test-&gt;_known_broken-&gt;{no_criteria};
+        return 1 if $test-&gt;will_actually_contain_bug($number);
+    }
+    return 0;
+}
+
+sub contains_known_broken {
+    my ($self, $number) = @_;
+
+    if ( ( $self-&gt;bug_is_contained($number)
+           and !$self-&gt;_bug_will_actually_be_contained($number) )
+        or ( !$self-&gt;bug_is_contained($number)
+             and $self-&gt;_bug_will_actually_be_contained($number) ) )
+    {
+        my @messages = map { $_-&gt;contains_known_broken($number) } 
+                           $self-&gt;field_tests;
+        @messages = grep { $_ } @messages;
+        # Sometimes, with things that break because of no_criteria, there won't
+        # be anything in @messages even though we need to print out a message.
+        if (!@messages) {
+            my @no_criteria = grep { $_-&gt;_known_broken-&gt;{no_criteria} }
+                                   $self-&gt;field_tests;
+            @messages = map { &quot;No criteria generated by &quot; . $_-&gt;name }
+                            @no_criteria;
+        }
+        die &quot;broken test with no message&quot; if !@messages;
+        return join(' AND ', @messages);
+    }
+    return undef;
+}
+
+##############################
+# Bugzilla::Search arguments #
+##############################
+
+sub search_columns {
+    my ($self) = @_;
+    my @columns = map { @{ $_-&gt;search_columns } } $self-&gt;field_tests;
+    return [uniq @columns];
+}
+
+sub search_params {
+    my ($self) = @_;
+    my @all_params = map { $_-&gt;search_params } $self-&gt;field_tests;
+    my %params;
+    my $chart = 0;
+    foreach my $item (@all_params) {
+        $params{&quot;field0-0-$chart&quot;} = $item-&gt;{'field0-0-0'};
+        $params{&quot;type0-0-$chart&quot;}  = $item-&gt;{'type0-0-0'};
+        $params{&quot;value0-0-$chart&quot;} = $item-&gt;{'value0-0-0'};
+        $chart++;
+    }
+    return \%params;
+}
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgxtlibBugzillaTestSearchpm"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search.pm (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search.pm                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/xt/lib/Bugzilla/Test/Search.pm        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,1002 @@
</span><ins>+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Everything Solved, Inc.
+# Portions created by the Initial Developer are Copyright (C) 2010 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+# This module tests Bugzilla/Search.pm. It uses various constants
+# that are in Bugzilla::Test::Search::Constants, in xt/lib/.
+#
+# It does this by:
+# 1) Creating a bunch of field values. Each field value is
+#    randomly named and fully unique.
+# 2) Creating a bunch of bugs that use those unique field
+#    values. Each bug has different characteristics--see
+#    the comment above the NUM_BUGS constant for a description
+#    of each bug.
+# 3) Running searches using the combination of every search operator against
+#    every field. The tests that we run are described by the TESTS constant.
+#    Some of the operator/field combinations are known to be broken--
+#    these are listed in the KNOWN_BROKEN constant.
+# 4) For each search, we make sure that certain bugs are contained in
+#    the search, and certain other bugs are not contained in the search.
+#    The code for the operator/field tests is mostly in
+#    Bugzilla::Test::Search::FieldTest.
+# 5) After testing each operator/field combination's functionality, we
+#    do additional tests to make sure that there are no SQL injections
+#    possible via any operator/field combination. The code for the
+#    SQL Injection tests is in Bugzilla::Test::Search::InjectionTest.
+#
+# Generally, the only way that you should modify the behavior of this
+# script is by modifying the constants.
+
+package Bugzilla::Test::Search;
+
+use strict;
+use warnings;
+use Bugzilla::Attachment;
+use Bugzilla::Bug ();
+use Bugzilla::Constants;
+use Bugzilla::Field;
+use Bugzilla::Field::Choice;
+use Bugzilla::FlagType;
+use Bugzilla::Group;
+use Bugzilla::Install ();
+use Bugzilla::Test::Search::Constants;
+use Bugzilla::Test::Search::CustomTest;
+use Bugzilla::Test::Search::FieldTestNormal;
+use Bugzilla::Test::Search::OperatorTest;
+use Bugzilla::User ();
+use Bugzilla::Util qw(generate_random_password);
+
+use Carp;
+use DateTime;
+use Scalar::Util qw(blessed);
+
+###############
+# Constructor #
+###############
+
+sub new {
+    my ($class, $options) = @_;
+    return bless { options =&gt; $options }, $class;
+}
+
+#############
+# Accessors #
+#############
+
+sub options { return $_[0]-&gt;{options} }
+sub option { return $_[0]-&gt;{options}-&gt;{$_[1]} }
+
+sub num_tests {
+    my ($self) = @_;
+    my @top_operators = $self-&gt;top_level_operators;
+    my @all_operators = $self-&gt;all_operators;
+    my $top_operator_tests = $self-&gt;_total_operator_tests(\@top_operators);
+    my $all_operator_tests = $self-&gt;_total_operator_tests(\@all_operators);
+
+    my @fields = $self-&gt;all_fields;
+
+    # Basically, we run TESTS_PER_RUN tests for each field/operator combination.
+    my $top_combinations = $top_operator_tests * scalar(@fields);
+    my $all_combinations = $all_operator_tests * scalar(@fields);
+    # But we also have ORs, for which we run combinations^2 tests.
+    my $join_tests = $self-&gt;option('long')
+                     ? ($top_combinations * $all_combinations) : 0;
+    # And AND tests, which means we run 2x $join_tests;
+    $join_tests = $join_tests * 2;
+    # Also, because of NOT tests and Normal tests, we run 3x $top_combinations.
+    my $basic_tests = $top_combinations * 3;
+    my $operator_field_tests = ($basic_tests + $join_tests) * TESTS_PER_RUN;
+
+    # Then we test each field/operator combination for SQL injection.
+    my @injection_values = INJECTION_TESTS;
+    my $sql_injection_tests = scalar(@fields) * scalar(@top_operators)
+                              * scalar(@injection_values) * NUM_SEARCH_TESTS;
+
+    # This @{ [] } thing is the only reasonable way to get a count out of a
+    # constant array.
+    my $special_tests = scalar(@{ [SPECIAL_PARAM_TESTS, CUSTOM_SEARCH_TESTS] }) 
+                        * TESTS_PER_RUN;
+    
+    return $operator_field_tests + $sql_injection_tests + $special_tests;
+}
+
+sub _total_operator_tests {
+    my ($self, $operators) = @_;
+    
+    # Some operators have more than one test. Find those ones and add
+    # them to the total operator tests
+    my $extra_operator_tests;
+    foreach my $operator (@$operators) {
+        my $tests = TESTS-&gt;{$operator};
+        next if !$tests;
+        my $extra_num = scalar(@$tests) - 1;
+        $extra_operator_tests += $extra_num;
+    }
+    return scalar(@$operators) + $extra_operator_tests;
+    
+}
+
+sub all_operators {
+    my ($self) = @_;
+    if (not $self-&gt;{all_operators}) {
+        
+        my @operators;
+        if (my $limit_operators = $self-&gt;option('operators')) {
+            @operators = split(',', $limit_operators);
+        }
+        else {
+            @operators = sort (keys %{ Bugzilla::Search::OPERATORS() });
+        }
+        # &quot;substr&quot; is just a backwards-compatibility operator, same as &quot;substring&quot;.
+        @operators = grep { $_ ne 'substr' } @operators;
+        $self-&gt;{all_operators} = \@operators;
+    }
+    return @{ $self-&gt;{all_operators} };
+}
+
+sub all_fields {
+    my $self = shift;
+    if (not $self-&gt;{all_fields}) {
+        $self-&gt;_create_custom_fields();
+        my @fields = @{ Bugzilla-&gt;fields };
+        @fields = sort { $a-&gt;name cmp $b-&gt;name } @fields;
+        $self-&gt;{all_fields} = \@fields;
+    }
+    return @{ $self-&gt;{all_fields} };
+}
+
+sub top_level_operators {
+    my ($self) = @_;
+    if (!$self-&gt;{top_level_operators}) {
+        my @operators;
+        my $limit_top = $self-&gt;option('top-operators');
+        if ($limit_top) {
+            @operators = split(',', $limit_top);
+        }
+        else {
+            @operators = $self-&gt;all_operators;
+        }
+        $self-&gt;{top_level_operators} = \@operators;
+    }
+    return @{ $self-&gt;{top_level_operators} };
+}
+
+sub text_fields {
+    my ($self) = @_;
+    my @text_fields = grep { $_-&gt;type == FIELD_TYPE_TEXTAREA
+                             or $_-&gt;type == FIELD_TYPE_FREETEXT } $self-&gt;all_fields;
+    @text_fields = map { $_-&gt;name } @text_fields;
+    push(@text_fields, qw(short_desc status_whiteboard bug_file_loc see_also));
+    return @text_fields;
+}
+
+sub bugs {
+    my $self = shift;
+    $self-&gt;{bugs} ||= [map { $self-&gt;_create_one_bug($_) } (1..NUM_BUGS)];
+    return @{ $self-&gt;{bugs} };
+}
+
+# Get a numbered bug.
+sub bug {
+    my ($self, $number) = @_;
+    return ($self-&gt;bugs)[$number - 1];
+}
+
+sub admin {
+    my $self = shift;
+    if (!$self-&gt;{admin_user}) {
+        my $admin = create_user(&quot;admin&quot;);
+        Bugzilla::Install::make_admin($admin);
+        $self-&gt;{admin_user} = $admin;
+    }
+    # We send back a fresh object every time, to make sure that group
+    # memberships are always up-to-date.
+    return new Bugzilla::User($self-&gt;{admin_user}-&gt;id);
+}
+
+sub nobody {
+    my $self = shift;
+    $self-&gt;{nobody} ||= Bugzilla::Group-&gt;create({ name =&gt; &quot;nobody-&quot; . random(),
+        description =&gt; &quot;Nobody&quot;, isbuggroup =&gt; 1 });
+    return $self-&gt;{nobody};
+}
+sub everybody {
+    my ($self) = @_;
+    $self-&gt;{everybody} ||= create_group('To The Limit');
+    return $self-&gt;{everybody};
+}
+
+sub bug_create_value {
+    my ($self, $number, $field) = @_;
+    $field = $field-&gt;name if blessed($field);
+    if ($number == 6 and $field ne 'alias') {
+        $number = 1;
+    }
+    my $extra_values = $self-&gt;_extra_bug_create_values-&gt;{$number};
+    if (exists $extra_values-&gt;{$field}) {
+        return $extra_values-&gt;{$field};
+    }
+    return $self-&gt;_bug_create_values-&gt;{$number}-&gt;{$field};
+}
+sub bug_update_value {
+    my ($self, $number, $field) = @_;
+    $field = $field-&gt;name if blessed($field);
+    if ($number == 6 and $field ne 'alias') {
+        $number = 1;
+    }
+    return $self-&gt;_bug_update_values-&gt;{$number}-&gt;{$field};
+}
+
+# Values used to create the bugs.
+sub _bug_create_values {
+    my $self = shift;
+    return $self-&gt;{bug_create_values} if $self-&gt;{bug_create_values};
+    my %values;
+    foreach my $number (1..NUM_BUGS) {
+        $values{$number} = $self-&gt;_create_field_values($number, 'for create');
+    }
+    $self-&gt;{bug_create_values} = \%values;
+    return $self-&gt;{bug_create_values};
+}
+# Values as they existed on the bug, at creation time. Used by the
+# changedfrom tests.
+sub _extra_bug_create_values {
+    my $self = shift;
+    $self-&gt;{extra_bug_create_values} ||= { map { $_ =&gt; {} } (1..NUM_BUGS) };
+    return $self-&gt;{extra_bug_create_values};
+}
+
+# Values used to update the bugs after they are created.
+sub _bug_update_values {
+    my $self = shift;
+    return $self-&gt;{bug_update_values} if $self-&gt;{bug_update_values};
+    my %values;
+    foreach my $number (1..NUM_BUGS) {
+        $values{$number} = $self-&gt;_create_field_values($number);
+    }
+    $self-&gt;{bug_update_values} = \%values;
+    return $self-&gt;{bug_update_values};
+}
+
+##############################
+# General Helper Subroutines #
+##############################
+
+sub random {
+    $_[0] ||= FIELD_SIZE;
+    generate_random_password(@_);
+}
+
+# We need to use a custom timestamp for each create() and update(),
+# because the database returns the same value for LOCALTIMESTAMP(0)
+# for the entire transaction, and we need each created bug to have
+# its own creation_ts and delta_ts.
+sub timestamp {
+    my ($day, $second) = @_;
+    return DateTime-&gt;new(
+        year   =&gt; 2037,
+        month  =&gt; 1,
+        day    =&gt; $day,
+        hour   =&gt; 12,
+        minute =&gt; $second,
+        second =&gt; 0,
+        # We make it floating because the timezone doesn't matter for our uses,
+        # and we want totally consistent behavior across all possible machines.
+        time_zone =&gt; 'floating',
+    );
+}
+
+sub create_keyword {
+    my ($number) = @_;
+    return Bugzilla::Keyword-&gt;create({
+        name =&gt; &quot;$number-keyword-&quot; . random(),
+        description =&gt; &quot;Keyword $number&quot; });
+}
+
+sub create_user {
+    my ($prefix) = @_;
+    my $user_name = $prefix . '-' . random(15) . &quot;@&quot; . random(12)
+                    . &quot;.&quot; . random(3);
+    my $user_realname = $prefix . '-' . random();
+    my $user = Bugzilla::User-&gt;create({
+        login_name =&gt; $user_name,
+        realname   =&gt; $user_realname,
+        cryptpassword =&gt; '*',
+    });
+    return $user;
+}
+
+sub create_group {
+    my ($prefix) = @_;
+    return Bugzilla::Group-&gt;create({
+        name =&gt; &quot;$prefix-group-&quot; . random(), description =&gt; &quot;Everybody $prefix&quot;,
+        userregexp =&gt; '.*', isbuggroup =&gt; 1 });
+}
+
+sub create_legal_value {
+    my ($field, $number) = @_;
+    my $type = Bugzilla::Field::Choice-&gt;type($field);
+    my $field_name = $field-&gt;name;
+    return $type-&gt;create({ value =&gt; &quot;$number-$field_name-&quot; . random(),
+                           is_open =&gt; 0 });
+}
+
+#########################
+# Custom Field Creation #
+#########################
+
+sub _create_custom_fields {
+    my ($self) = @_;
+    return if !$self-&gt;option('add-custom-fields');
+    
+    while (my ($type, $name) = each %{ CUSTOM_FIELDS() }) {
+        my $exists = new Bugzilla::Field({ name =&gt; $name });
+        next if $exists;
+        Bugzilla::Field-&gt;create({
+            name =&gt; $name,
+            type =&gt; $type,
+            description =&gt; &quot;Search Test Field $name&quot;,
+            enter_bug =&gt; 1,
+            custom =&gt; 1,
+            buglist =&gt; 1,
+            is_mandatory =&gt; 0,
+        });
+    }
+}
+
+########################
+# Field Value Creation #
+########################
+
+sub _create_field_values {
+    my ($self, $number, $for_create) = @_;
+    my $dbh = Bugzilla-&gt;dbh;
+    
+    Bugzilla-&gt;set_user($self-&gt;admin);
+
+    my @selects = grep { $_-&gt;is_select } $self-&gt;all_fields;
+    my %values;
+    foreach my $field (@selects) {
+        next if $field-&gt;is_abnormal;
+        $values{$field-&gt;name} = create_legal_value($field, $number)-&gt;name;
+    }
+
+    my $group = create_group($number);
+    $values{groups} = [$group-&gt;name];
+
+    $values{'keywords'} = create_keyword($number)-&gt;name;
+
+    foreach my $field (qw(assigned_to qa_contact reporter cc)) {
+        $values{$field} = create_user(&quot;$number-$field&quot;)-&gt;login;
+    }
+
+    my $classification = Bugzilla::Classification-&gt;create(
+        { name =&gt; &quot;$number-classification-&quot; . random() });
+    $classification = $classification-&gt;name;
+
+    my $version = &quot;$number-version-&quot; . random();
+    my $milestone = &quot;$number-tm-&quot; . random(15);
+    my $product = Bugzilla::Product-&gt;create({
+        name =&gt; &quot;$number-product-&quot; . random(),
+        description =&gt; 'Created by t/search.t',
+        defaultmilestone =&gt; $milestone,
+        classification =&gt; $classification,
+        version =&gt; $version,
+        allows_unconfirmed =&gt; 1,
+    });
+    foreach my $item ($group, $self-&gt;nobody) {
+        $product-&gt;set_group_controls($item,
+            { membercontrol =&gt; CONTROLMAPSHOWN,
+              othercontrol =&gt; CONTROLMAPNA });
+    }
+    # $product-&gt;update() is called lower down.
+    my $component = Bugzilla::Component-&gt;create({
+        product =&gt; $product, name =&gt; &quot;$number-component-&quot; . random(),
+        initialowner =&gt; create_user(&quot;$number-defaultowner&quot;)-&gt;login,
+        initialqacontact =&gt; create_user(&quot;$number-defaultqa&quot;)-&gt;login,
+        initial_cc =&gt; [create_user(&quot;$number-initcc&quot;)-&gt;login],
+        description =&gt; &quot;Component $number&quot; });
+    
+    $values{'product'} = $product-&gt;name;
+    $values{'component'} = $component-&gt;name;
+    $values{'target_milestone'} = $milestone;
+    $values{'version'} = $version;
+
+    foreach my $field ($self-&gt;text_fields) {
+        # We don't add a - after $field for the text fields, because
+        # if we do, fulltext searching for short_desc pulls out
+        # &quot;short_desc&quot; as a word and matches it in every bug.
+        my $value = &quot;$number-$field&quot; . random();
+        if ($field eq 'bug_file_loc' or $field eq 'see_also') {
+            $value = &quot;http://$value-&quot; . random(3)
+                     . &quot;/show_bug.cgi?id=$number&quot;;
+        }
+        $values{$field} = $value;
+    }
+    $values{'tag'} = [&quot;$number-tag-&quot; . random()];
+    
+    my @date_fields = grep { $_-&gt;type == FIELD_TYPE_DATETIME } $self-&gt;all_fields;
+    foreach my $field (@date_fields) {
+        # We use 03 as the month because that differs from our creation_ts,
+        # delta_ts, and deadline. (It's nice to have recognizable values
+        # for each field when debugging.)
+        my $second = $for_create ? $number : $number + 1;
+        $values{$field-&gt;name} = &quot;2037-03-0$number 12:34:0$second&quot;;
+    }
+
+    $values{alias} = &quot;$number-alias-&quot; . random(12);
+
+    # Prefixing the original comment with &quot;description&quot; makes the
+    # lesserthan and greaterthan tests behave predictably.
+    my $comm_prefix = $for_create ? &quot;description-&quot; : '';
+    $values{comment} = &quot;$comm_prefix$number-comment-&quot; . random()
+                               . ' ' . random();
+
+    my @flags;
+    my $setter = create_user(&quot;$number-setters.login_name&quot;);
+    my $requestee = create_user(&quot;$number-requestees.login_name&quot;);
+    $values{set_flags} = _create_flags($number, $setter, $requestee);
+
+    my $month = $for_create ? &quot;12&quot; : &quot;02&quot;;
+    $values{'deadline'} = &quot;2037-$month-0$number&quot;;
+    my $estimate_times = $for_create ? 10 : 1;
+    $values{estimated_time} = $estimate_times * $number;
+
+    $values{attachment} = _get_attach_values($number, $for_create);
+
+    # Some things only happen on the first bug.
+    if ($number == 1) {
+        # We use 6 as the prefix for the extra values, because bug 6's values
+        # don't otherwise get used (since bug 6 is created as a clone of
+        # bug 1). This also makes sure that our greaterthan/lessthan
+        # tests work properly.
+        my $extra_group = create_group(6);
+        $product-&gt;set_group_controls($extra_group,
+            { membercontrol =&gt; CONTROLMAPSHOWN,
+              othercontrol =&gt; CONTROLMAPNA });
+        $values{groups} = [$values{groups}-&gt;[0], $extra_group-&gt;name];
+        my $extra_keyword = create_keyword(6);
+        $values{keywords} = [$values{keywords}, $extra_keyword-&gt;name];
+        my $extra_cc = create_user(&quot;6-cc&quot;);
+        $values{cc} = [$values{cc}, $extra_cc-&gt;login];
+        my @multi_selects = grep { $_-&gt;type == FIELD_TYPE_MULTI_SELECT }
+                                 $self-&gt;all_fields;
+        foreach my $field (@multi_selects) {
+            my $new_value = create_legal_value($field, 6);
+            my $name = $field-&gt;name;
+            $values{$name} = [$values{$name}, $new_value-&gt;name];
+        }
+        push(@{ $values{'tag'} }, &quot;6-tag-&quot; . random());
+    }
+
+    # On bug 5, any field that *can* be left empty, *is* left empty.
+    if ($number == 5) {
+        my @set_fields = grep { $_-&gt;type == FIELD_TYPE_SINGLE_SELECT }
+                         $self-&gt;all_fields;
+        @set_fields = map { $_-&gt;name } @set_fields;
+        push(@set_fields, qw(short_desc version reporter));
+        foreach my $key (keys %values) {
+            delete $values{$key} unless grep { $_ eq $key } @set_fields;
+        }
+    }
+
+    $product-&gt;update();
+
+    return \%values;
+}
+
+# Flags
+sub _create_flags {
+    my ($number, $setter, $requestee) = @_;
+
+    my $flagtypes = _create_flagtypes($number);
+
+    my %flags;
+    foreach my $type (qw(a b)) {
+        $flags{$type} = _get_flag_values(@_, $flagtypes-&gt;{$type});
+    }
+    return \%flags;
+}
+
+sub _create_flagtypes {
+    my ($number) = @_;
+    my $dbh = Bugzilla-&gt;dbh;
+    my $name = &quot;$number-flag-&quot; . random();
+    my $desc = &quot;FlagType $number&quot;;
+
+    my %flagtypes; 
+    foreach my $target (qw(a b)) {
+         $dbh-&gt;do(&quot;INSERT INTO flagtypes
+                  (name, description, target_type, is_requestable, 
+                   is_requesteeble, is_multiplicable, cc_list)
+                   VALUES (?,?,?,1,1,1,'')&quot;,
+                   undef, $name, $desc, $target);
+         my $id = $dbh-&gt;bz_last_key('flagtypes', 'id');
+         $dbh-&gt;do('INSERT INTO flaginclusions (type_id) VALUES (?)',
+                  undef, $id);
+         my $flagtype = new Bugzilla::FlagType($id);
+         $flagtypes{$target} = $flagtype;
+    }
+    return \%flagtypes;
+}
+
+sub _get_flag_values {
+    my ($number, $setter, $requestee, $flagtype) = @_;
+
+    my @set_flags;
+    if ($number &lt;= 2) {
+        foreach my $value (qw(? - + ?)) {
+            my $flag = { type_id =&gt; $flagtype-&gt;id, status =&gt; $value,
+                         setter =&gt; $setter, flagtype =&gt; $flagtype };
+            push(@set_flags, $flag);
+        }
+        $set_flags[0]-&gt;{requestee} = $requestee-&gt;login;
+    }
+    else {
+        @set_flags = ({ type_id =&gt; $flagtype-&gt;id, status =&gt; '+',
+                        setter =&gt; $setter, flagtype =&gt; $flagtype });
+    }
+    return \@set_flags;
+}
+
+# Attachments
+sub _get_attach_values {
+    my ($number, $for_create) = @_;
+
+    my $boolean = $number == 1 ? 1 : 0;
+    if ($for_create) {
+        $boolean = !$boolean ? 1 : 0;
+    }
+    my $ispatch = $for_create ? 'ispatch' : 'is_patch';
+    my $isobsolete = $for_create ? 'isobsolete' : 'is_obsolete';
+    my $isprivate = $for_create ? 'isprivate' : 'is_private';
+    my $mimetype = $for_create ? 'mimetype' : 'content_type';
+
+    my %values = (
+        description =&gt; &quot;$number-attach_desc-&quot; . random(),
+        filename =&gt; &quot;$number-filename-&quot; . random(),
+        $ispatch =&gt; $boolean,
+        $isobsolete =&gt; $boolean,
+        $isprivate =&gt; $boolean,
+        $mimetype =&gt; &quot;text/x-$number-&quot; . random(),
+    );
+    if ($for_create) {
+        $values{data} = &quot;$number-data-&quot; . random() . random();
+    }
+    return \%values;
+}
+
+################
+# Bug Creation #
+################
+
+sub _create_one_bug {
+    my ($self, $number) = @_;
+    my $dbh = Bugzilla-&gt;dbh;
+    
+    # We need bug 6 to have a unique alias that is not a clone of bug 1's,
+    # so we get the alias separately from the other parameters.
+    my $alias = $self-&gt;bug_create_value($number, 'alias');
+    my $update_alias = $self-&gt;bug_update_value($number, 'alias');
+    
+    # Otherwise, make bug 6 a clone of bug 1.
+    my $real_number = $number;
+    $number = 1 if $number == 6;
+    
+    my $reporter = $self-&gt;bug_create_value($number, 'reporter');
+    Bugzilla-&gt;set_user(Bugzilla::User-&gt;check($reporter));
+    
+    # We create the bug with one set of values, and then we change it
+    # to have different values.
+    my %params = %{ $self-&gt;_bug_create_values-&gt;{$number} };
+    $params{alias} = $alias;
+    
+    # There are some things in bug_create_values that shouldn't go into
+    # create().
+    delete @params{qw(attachment set_flags tag)};
+    
+    my ($status, $resolution, $see_also) = 
+        delete @params{qw(bug_status resolution see_also)};
+    # All the bugs are created with everconfirmed = 0.
+    $params{bug_status} = 'UNCONFIRMED';
+    my $bug = Bugzilla::Bug-&gt;create(\%params);
+    
+    # These are necessary for the changedfrom tests.
+    my $extra_values = $self-&gt;_extra_bug_create_values-&gt;{$number};
+    foreach my $field (qw(comments remaining_time percentage_complete
+                         keyword_objects everconfirmed dependson blocked
+                         groups_in classification actual_time))
+    {
+        $extra_values-&gt;{$field} = $bug-&gt;$field;
+    }
+    $extra_values-&gt;{reporter_accessible} = $number == 1 ? 0 : 1;
+    $extra_values-&gt;{cclist_accessible}   = $number == 1 ? 0 : 1;
+    
+    if ($number == 5) {
+        # Bypass Bugzilla::Bug--we don't want any changes in bugs_activity
+        # for bug 5.
+        $dbh-&gt;do('UPDATE bugs SET qa_contact = NULL, reporter_accessible = 0,
+                                  cclist_accessible = 0 WHERE bug_id = ?',
+                 undef, $bug-&gt;id);
+        $dbh-&gt;do('DELETE FROM cc WHERE bug_id = ?', undef, $bug-&gt;id);
+        my $ts = '1970-01-01 00:00:00';
+        $dbh-&gt;do('UPDATE bugs SET creation_ts = ?, delta_ts = ?
+                   WHERE bug_id = ?', undef, $ts, $ts, $bug-&gt;id);
+        $dbh-&gt;do('UPDATE longdescs SET bug_when = ? WHERE bug_id = ?',
+                 undef, $ts, $bug-&gt;id);
+        $bug-&gt;{creation_ts} = $ts;
+        $extra_values-&gt;{see_also} = [];
+    }
+    else {
+        # Manually set the creation_ts so that each bug has a different one.
+        #
+        # Also, manually update the resolution and bug_status, because
+        # we want to see both of them change in bugs_activity, so we
+        # have to start with values for both (and as of the time when I'm
+        # writing this test, Bug-&gt;create doesn't support setting resolution).
+        #
+        # Same for see_also.
+        my $timestamp = timestamp($number, $number - 1);
+        my $creation_ts = $timestamp-&gt;ymd . ' ' . $timestamp-&gt;hms;
+        $bug-&gt;{creation_ts} = $creation_ts;
+        $dbh-&gt;do('UPDATE longdescs SET bug_when = ? WHERE bug_id = ?',
+                 undef, $creation_ts, $bug-&gt;id);
+        $dbh-&gt;do('UPDATE bugs SET creation_ts = ?, bug_status = ?,
+                  resolution = ? WHERE bug_id = ?',
+                 undef, $creation_ts, $status, $resolution, $bug-&gt;id);
+        $dbh-&gt;do('INSERT INTO bug_see_also (bug_id, value, class) VALUES (?,?,?)',
+                 undef, $bug-&gt;id, $see_also, 'Bugzilla::BugUrl::Bugzilla');
+        $extra_values-&gt;{see_also} = $bug-&gt;see_also;
+
+        # All the tags must be created as the admin user, so that the
+        # admin user can find them, later.
+        my $original_user = Bugzilla-&gt;user;
+        Bugzilla-&gt;set_user($self-&gt;admin);
+        my $tags = $self-&gt;bug_create_value($number, 'tag');
+        $bug-&gt;add_tag($_) foreach @$tags;
+        $extra_values-&gt;{tags} = $tags;
+        Bugzilla-&gt;set_user($original_user);
+
+        if ($number == 1) {
+            # Bug 1 needs to start off with reporter_accessible and
+            # cclist_accessible being 0, so that when we change them to 1,
+            # that change shows up in bugs_activity.
+            $dbh-&gt;do('UPDATE bugs SET reporter_accessible = 0,
+                      cclist_accessible = 0 WHERE bug_id = ?',
+                      undef, $bug-&gt;id);
+            # Bug 1 gets three comments, so that longdescs.count matches it
+            # uniquely. The third comment is added in the middle, so that the
+            # last comment contains all of the important data, like work_time.
+            $bug-&gt;add_comment(&quot;1-comment-&quot; . random(100));
+        }
+        
+        my %update_params = %{ $self-&gt;_bug_update_values-&gt;{$number} };
+        my %reverse_map = reverse %{ Bugzilla::Bug-&gt;FIELD_MAP };
+        foreach my $db_name (keys %reverse_map) {
+            next if $db_name eq 'comment';
+            next if $db_name eq 'status_whiteboard';
+            if (exists $update_params{$db_name}) {
+                my $update_name = $reverse_map{$db_name};
+                $update_params{$update_name} = delete $update_params{$db_name};
+            }
+        }
+        
+        my ($new_status, $new_res) = 
+            delete @update_params{qw(status resolution)};
+        # Bypass the status workflow.
+        $bug-&gt;{bug_status} = $new_status;
+        $bug-&gt;{resolution} = $new_res;
+        $bug-&gt;{everconfirmed} = 1 if $number == 1;
+        
+        # add/remove/set fields.
+        $update_params{keywords} = { set =&gt; $update_params{keywords} };
+        $update_params{groups} = { add =&gt; $update_params{groups},
+                                   remove =&gt; $bug-&gt;groups_in };
+        my @cc_remove = map { $_-&gt;login } @{ $bug-&gt;cc_users };
+        my $cc_new = $update_params{cc};
+        my @cc_add = ref($cc_new) ? @$cc_new : ($cc_new);
+        # We make the admin an explicit CC on bug 1 (but not on bug 6), so
+        # that we can test the %user% pronoun properly.
+        if ($real_number == 1) {
+            push(@cc_add, $self-&gt;admin-&gt;login);
+        }
+        $update_params{cc} = { add =&gt; \@cc_add, remove =&gt; \@cc_remove };
+        my $see_also_remove = $bug-&gt;see_also;
+        my $see_also_add = [$update_params{see_also}];
+        $update_params{see_also} = { add =&gt; $see_also_add, 
+                                     remove =&gt; $see_also_remove };
+        $update_params{comment} = { body =&gt; $update_params{comment} };
+        $update_params{work_time} = $number;
+        # Setting work_time kills the remaining_time, so we need to
+        # preserve that. We add 8 because that produces an integer
+        # percentage_complete for bug 1, which is necessary for
+        # accurate &quot;equals&quot;-type searching.
+        $update_params{remaining_time} = $number + 8;
+        $update_params{reporter_accessible} = $number == 1 ? 1 : 0;
+        $update_params{cclist_accessible} = $number == 1 ? 1 : 0;
+        $update_params{alias} = $update_alias;
+
+        $bug-&gt;set_all(\%update_params);
+        my $flags = $self-&gt;bug_create_value($number, 'set_flags')-&gt;{b};
+        $bug-&gt;set_flags([], $flags);
+        $timestamp-&gt;set(second =&gt; $number);
+        $bug-&gt;update($timestamp-&gt;ymd . ' ' . $timestamp-&gt;hms);
+        $extra_values-&gt;{flags} = $bug-&gt;flags;
+        
+        # It's not generally safe to do update() multiple times on
+        # the same Bug object.
+        $bug = new Bugzilla::Bug($bug-&gt;id);
+        my $update_flags = $self-&gt;bug_update_value($number, 'set_flags')-&gt;{b};
+        $_-&gt;{status} = 'X' foreach @{ $bug-&gt;flags };
+        $bug-&gt;set_flags($bug-&gt;flags, $update_flags);
+        if ($number == 1) {
+            my $comment_id = $bug-&gt;comments-&gt;[-1]-&gt;id;
+            $bug-&gt;set_comment_is_private({ $comment_id =&gt; 1 });
+        }
+        $bug-&gt;update($bug-&gt;delta_ts);
+        
+        my $attach_create = $self-&gt;bug_create_value($number, 'attachment');
+        my $attachment = Bugzilla::Attachment-&gt;create({
+            bug =&gt; $bug,
+            creation_ts =&gt; $creation_ts,
+            %$attach_create });
+        # Store for the changedfrom tests.
+        $extra_values-&gt;{attachments} = 
+            [new Bugzilla::Attachment($attachment-&gt;id)];
+        
+        my $attach_update = $self-&gt;bug_update_value($number, 'attachment');
+        $attachment-&gt;set_all($attach_update);
+        # In order to keep the mimetype on the ispatch attachment,
+        # we need to bypass the validator.
+        $attachment-&gt;{mimetype} = $attach_update-&gt;{content_type};
+        my $attach_flags = $self-&gt;bug_update_value($number, 'set_flags')-&gt;{a};
+        $attachment-&gt;set_flags([], $attach_flags);
+        $attachment-&gt;update($bug-&gt;delta_ts);
+    }
+    
+    # Values for changedfrom.
+    $extra_values-&gt;{creation_ts} = $bug-&gt;creation_ts;
+    $extra_values-&gt;{delta_ts}    = $bug-&gt;creation_ts;
+    
+    return new Bugzilla::Bug($bug-&gt;id);
+}
+
+###################################
+# Test::Builder Memory Efficiency #
+###################################
+
+# Test::Builder stores information for each test run, but Test::Harness
+# and TAP::Harness don't actually need this information. When we run 60
+# million tests, the history eats up all our memory. (After about
+# 1 million tests, memory usage is around 1 GB.)
+#
+# The only part of the history that Test::More actually *uses* is the &quot;ok&quot;
+# field, which we store more efficiently, in an array, and then we re-populate
+# the Test_Results in Test::Builder at the end of the test.
+sub clean_test_history {
+    my ($self) = @_;
+    return if !$self-&gt;option('long');
+    my $builder = Test::More-&gt;builder;
+    my $current_test = $builder-&gt;current_test;
+
+    # I don't use details() because I don't want to copy the array.
+    my $results = $builder-&gt;{Test_Results};
+    my $check_test = $current_test - 1;
+    while (my $result = $results-&gt;[$check_test]) {
+        last if !$result;
+        $self-&gt;test_success($check_test, $result-&gt;{ok});
+        $check_test--;
+    }
+
+    # Truncate the test history array, but retain the current test number.
+    $builder-&gt;{Test_Results} = [];
+    $builder-&gt;{Curr_Test} = $current_test;
+}
+
+sub test_success {
+    my ($self, $index, $status) = @_;
+    $self-&gt;{test_success}-&gt;[$index] = $status;
+    return $self-&gt;{test_success};
+}
+
+sub repopulate_test_results {
+    my ($self) = @_;
+    return if !$self-&gt;option('long');
+    $self-&gt;clean_test_history();
+    # We create only two hashes, for memory efficiency.
+    my %ok = ( ok =&gt; 1 );
+    my %not_ok = ( ok =&gt; 0 );
+    my @results;
+    foreach my $success (@{ $self-&gt;{test_success} }) {
+        push(@results, $success ? \%ok : \%not_ok);
+    }
+    my $builder = Test::More-&gt;builder;
+    $builder-&gt;{Test_Results} = \@results;
+}
+
+##########
+# Caches #
+##########
+
+# When doing AND and OR tests, we essentially test the same field/operator
+# combinations over and over. So, if we're going to be running those tests,
+# we cache the translated_value of the FieldTests globally so that we don't
+# have to re-run the value-translation code every time (which can be pretty
+# slow).
+sub value_translation_cache {
+    my ($self, $field_test, $value) = @_;
+    return if !$self-&gt;option('long');
+    my $test_name = $field_test-&gt;name;
+    if (@_ == 3) {
+        $self-&gt;{value_translation_cache}-&gt;{$test_name} = $value;
+    }
+    return $self-&gt;{value_translation_cache}-&gt;{$test_name};
+}
+
+# When doing AND/OR tests, the value for transformed_value_was_equal
+# (see Bugzilla::Test::Search::FieldTest) won't be recalculated
+# if we pull our values from the value_translation_cache. So we need
+# to also cache the values for transformed_value_was_equal.
+sub was_equal_cache {
+    my ($self, $field_test, $number, $value) = @_;
+    return if !$self-&gt;option('long');
+    my $test_name = $field_test-&gt;name;
+    if (@_ == 4) {
+        $self-&gt;{tvwe_cache}-&gt;{$test_name}-&gt;{$number} = $value;
+    }
+    return $self-&gt;{tvwe_cache}-&gt;{$test_name}-&gt;{$number};
+}
+
+#############
+# Main Test #
+#############
+
+sub run {
+    my ($self) = @_;
+    my $dbh = Bugzilla-&gt;dbh;
+
+    # We want backtraces on any &quot;die&quot; message or any warning.
+    # Otherwise it's hard to trace errors inside of Bugzilla::Search from
+    # reading automated test run results.
+    local $SIG{__WARN__} = \&amp;Carp::cluck;
+    local $SIG{__DIE__}  = \&amp;Carp::confess;
+
+    $dbh-&gt;bz_start_transaction();
+    
+    # Some parameters need to be set in order for the tests to function
+    # properly.
+    my $everybody = $self-&gt;everybody;
+    my $params = Bugzilla-&gt;params;
+    local $params-&gt;{'useclassification'} = 1;
+    local $params-&gt;{'useqacontact'} = 1;
+    local $params-&gt;{'usebugaliases'} = 1;
+    local $params-&gt;{'usetargetmilestone'} = 1;
+    local $params-&gt;{'mail_delivery_method'} = 'None';
+    local $params-&gt;{'timetrackinggroup'} = $everybody-&gt;name;
+    local $params-&gt;{'insidergroup'} = $everybody-&gt;name;
+
+    $self-&gt;_setup_bugs();
+    
+    # Even though _setup_bugs set us as an admin, we want to be sure at
+    # this point that we have an admin with refreshed group memberships.
+    Bugzilla-&gt;set_user($self-&gt;admin);
+    foreach my $test (CUSTOM_SEARCH_TESTS) {
+        my $custom_test = new Bugzilla::Test::Search::CustomTest($test, $self);
+        $custom_test-&gt;run();
+    }
+    foreach my $test (SPECIAL_PARAM_TESTS) {
+        my $operator_test =
+            new Bugzilla::Test::Search::OperatorTest($test-&gt;{operator}, $self);
+        my $field = Bugzilla::Field-&gt;check($test-&gt;{field});
+        my $special_test = new Bugzilla::Test::Search::FieldTestNormal(
+            $operator_test, $field, $test);
+        $special_test-&gt;run();
+    }
+    foreach my $operator ($self-&gt;top_level_operators) {
+        my $operator_test =
+            new Bugzilla::Test::Search::OperatorTest($operator, $self);
+        $operator_test-&gt;run();
+    }
+
+    # Rollbacks won't get rid of bugs_fulltext entries, so we do that ourselves.
+    my @bug_ids = map { $_-&gt;id } $self-&gt;bugs;
+    my $bug_id_string = join(',', @bug_ids);
+    $dbh-&gt;do(&quot;DELETE FROM bugs_fulltext WHERE bug_id IN ($bug_id_string)&quot;);
+    $dbh-&gt;bz_rollback_transaction();
+    $self-&gt;repopulate_test_results();
+}
+
+# This makes a few changes to the bugs after they're created--changes
+# that can only be done after all the bugs have been created.
+sub _setup_bugs {
+    my ($self) = @_;
+    $self-&gt;_setup_dependencies();
+    $self-&gt;_set_bug_id_fields();
+    $self-&gt;_protect_bug_6();
+}
+sub _setup_dependencies {
+    my ($self) = @_;
+    my $dbh = Bugzilla-&gt;dbh;
+    
+    # Set up depedency relationships between the bugs.
+    # Bug 1 + 6 depend on bug 2 and block bug 3.
+    my $bug2 = $self-&gt;bug(2);
+    my $bug3 = $self-&gt;bug(3);
+    foreach my $number (1,6) {
+        my $bug = $self-&gt;bug($number);
+        my @original_delta = ($bug2-&gt;delta_ts, $bug3-&gt;delta_ts);
+        Bugzilla-&gt;set_user($bug-&gt;reporter);
+        $bug-&gt;set_dependencies([$bug2-&gt;id], [$bug3-&gt;id]);
+        $bug-&gt;update($bug-&gt;delta_ts);
+        # Setting dependencies changed the delta_ts on bug2 and bug3, so
+        # re-set them back to what they were before. However, we leave
+        # the correct update times in bugs_activity, so that the changed*
+        # searches still work right.
+        my $set_delta = $dbh-&gt;prepare(
+            'UPDATE bugs SET delta_ts = ? WHERE bug_id = ?');
+        foreach my $row ([$original_delta[0], $bug2-&gt;id], 
+                         [$original_delta[1], $bug3-&gt;id])
+        {
+            $set_delta-&gt;execute(@$row);
+        }
+    }
+}
+
+sub _set_bug_id_fields {
+    my ($self) = @_;
+    # BUG_ID fields couldn't be set before, because before we create bug 1,
+    # we don't necessarily have any valid bug ids.)
+    my @bug_id_fields = grep { $_-&gt;type == FIELD_TYPE_BUG_ID }
+                             $self-&gt;all_fields;
+    foreach my $number (1..NUM_BUGS) {
+        my $bug = $self-&gt;bug($number);
+        $number = 1 if $number == 6;
+        next if $number == 5;
+        my $other_bug = $self-&gt;bug($number + 1);
+        Bugzilla-&gt;set_user($bug-&gt;reporter);
+        foreach my $field (@bug_id_fields) {
+            $bug-&gt;set_custom_field($field, $other_bug-&gt;id);
+            $bug-&gt;update($bug-&gt;delta_ts);
+        }
+    }
+}
+
+sub _protect_bug_6 {
+    my ($self) = @_;
+    my $dbh = Bugzilla-&gt;dbh;
+    
+    Bugzilla-&gt;set_user($self-&gt;admin);
+    
+    # Put bug6 in the nobody group.
+    my $nobody = $self-&gt;nobody;
+    # We pull it newly from the DB to be sure it's safe to call update()
+    # on.
+    my $bug6 = new Bugzilla::Bug($self-&gt;bug(6)-&gt;id);
+    $bug6-&gt;add_group($nobody);
+    $bug6-&gt;update($bug6-&gt;delta_ts);
+    
+    # Remove the admin (and everybody else) from the $nobody group.
+    $dbh-&gt;do('DELETE FROM group_group_map 
+               WHERE grantor_id = ? OR member_id = ?', undef,
+             $nobody-&gt;id, $nobody-&gt;id);
+}
+
+1;
</ins></span></pre></div>
<a id="trunkWebsitesbugswebkitorgxtsearcht"></a>
<div class="addfile"><h4>Added: trunk/Websites/bugs.webkit.org/xt/search.t (0 => 174764)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Websites/bugs.webkit.org/xt/search.t                                (rev 0)
+++ trunk/Websites/bugs.webkit.org/xt/search.t        2014-10-16 16:00:58 UTC (rev 174764)
</span><span class="lines">@@ -0,0 +1,96 @@
</span><ins>+#!/usr/bin/env perl -w
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the &quot;License&quot;); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an &quot;AS
+# IS&quot; basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Bug Tracking System.
+#
+# The Initial Developer of the Original Code is Everything Solved, Inc.
+# Portions created by the Initial Developer are Copyright (C) 2010 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#   Max Kanat-Alexander &lt;mkanat@bugzilla.org&gt;
+
+# For a description of this test, see Bugzilla::Test::Search
+# in xt/lib/.
+
+use strict;
+use warnings;
+use lib qw(. xt/lib lib);
+use Bugzilla;
+use Bugzilla::Constants;
+use Bugzilla::Test::Search;
+use Getopt::Long;
+use Pod::Usage;
+
+use Test::More;
+
+my %switches;
+GetOptions(\%switches, 'operators=s', 'top-operators=s', 'long',
+                       'add-custom-fields', 'help|h') || die $@;
+
+pod2usage(verbose =&gt; 1) if $switches{'help'};
+
+plan skip_all =&gt; &quot;BZ_WRITE_TESTS environment variable not set&quot;
+  if !$ENV{BZ_WRITE_TESTS};
+
+Bugzilla-&gt;usage_mode(USAGE_MODE_TEST);
+
+my $test = new Bugzilla::Test::Search(\%switches);
+plan tests =&gt; $test-&gt;num_tests;
+$test-&gt;run();
+
+__END__
+
+=head1 NAME
+
+search.t - Test L&lt;Bugzilla::Search&gt;
+
+=head1 DESCRIPTION
+
+This test tests L&lt;Bugzilla::Search&gt;.
+
+Note that users may be prevented from writing new bugs, products, components,
+etc. to your database while this test is running.
+
+=head1 OPTIONS
+
+=over
+
+=item --long
+
+Run AND and OR tests in addition to normal tests. Specifying
+--long without also specifying L&lt;/--top-operators&gt; is likely to
+run your system out of memory.
+
+=item --add-custom-fields
+
+This adds every type of custom field to the database, so that they can
+all be tested. Note that this B&lt;CANNOT BE REVERSED&gt;, so do not use this
+switch on a production installation.
+
+=item --operators=a,b,c
+
+Limit the test to testing only the listed operators.
+
+=item --top-operators=a,b,c
+
+Limit the top-level tested operators to the following list. This
+means that for normal tests, only the listed operators will be tested.
+However, for OR and AND tests, all other operators will be tested
+along with the operators you listed.
+
+=item --help
+
+Display this help.
+
+=back
</ins></span></pre>
</div>
</div>

</body>
</html>